├── .gitignore ├── components └── esp32-wifi-manager │ ├── src │ ├── connect │ ├── compress.bat │ ├── status │ ├── lock.png │ ├── wifi0.png │ ├── wifi1.png │ ├── wifi2.png │ ├── wifi24.png │ ├── wifi3.png │ ├── settings.png │ ├── component.mk │ ├── ap.json │ ├── json.h │ ├── nvs_sync.c │ ├── nvs_sync.h │ ├── http_app.h │ ├── json.c │ ├── dns_server.h │ ├── index.html │ ├── dns_server.c │ ├── style.css │ ├── code.js │ ├── wifi_manager.h │ └── http_app.c │ ├── component.mk │ ├── CMakeLists.txt │ ├── .gitignore │ ├── LICENSE.md │ ├── Kconfig │ ├── .travis.yml │ └── README.md ├── main ├── CMakeLists.txt ├── component.mk └── main.c ├── images ├── esp32.jpg ├── max485.jpg ├── wiring.jpg ├── grafana.jpg ├── overview.png ├── wiring.pptx ├── controller.jpg ├── controller-detail.jpg ├── esp32-wroom-pinout.jpg ├── prometheus-metrics.jpg └── esp32_pentair_controller.jpg ├── CMakeLists.txt ├── .vscode └── c_cpp_properties.json ├── README.md └── sdkconfig /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/connect: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCS "main.c") 2 | 3 | register_component() 4 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/compress.bat: -------------------------------------------------------------------------------- 1 | gzip index.html style.css --best --keep --force 2 | pause -------------------------------------------------------------------------------- /images/esp32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/esp32.jpg -------------------------------------------------------------------------------- /images/max485.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/max485.jpg -------------------------------------------------------------------------------- /images/wiring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/wiring.jpg -------------------------------------------------------------------------------- /images/grafana.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/grafana.jpg -------------------------------------------------------------------------------- /images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/overview.png -------------------------------------------------------------------------------- /images/wiring.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/wiring.pptx -------------------------------------------------------------------------------- /images/controller.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/controller.jpg -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/status: -------------------------------------------------------------------------------- 1 | {"ssid":"zodmgbbq","ip":"192.168.1.119","netmask":"255.255.255.0","gw":"192.168.1.1","urc":0} -------------------------------------------------------------------------------- /images/controller-detail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/controller-detail.jpg -------------------------------------------------------------------------------- /images/esp32-wroom-pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/esp32-wroom-pinout.jpg -------------------------------------------------------------------------------- /images/prometheus-metrics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/prometheus-metrics.jpg -------------------------------------------------------------------------------- /images/esp32_pentair_controller.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/images/esp32_pentair_controller.jpg -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/lock.png -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/wifi0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/wifi0.png -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/wifi1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/wifi1.png -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/wifi2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/wifi2.png -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/wifi24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/wifi24.png -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/wifi3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/wifi3.png -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelusner/esp32-pentair-controller/HEAD/components/esp32-wifi-manager/src/settings.png -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | set(EXTRA_COMPONENTS_DIRS components/) 3 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 4 | project(esp32_pentair_controller) 5 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS = src 2 | COMPONENT_SRCDIRS = src 3 | COMPONENT_DEPENDS = log esp_http_server 4 | COMPONENT_EMBED_FILES := src/style.css src/code.js src/index.html 5 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | idf_component_register(SRC_DIRS src 3 | REQUIRES log nvs_flash mdns wpa_supplicant lwip esp_http_server 4 | INCLUDE_DIRS src 5 | EMBED_FILES src/style.css src/code.js src/index.html) 6 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/ap.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"ssid":"Pantum-AP-A6D49F","chan":11,"rssi":-55,"auth":4}, 3 | {"ssid":"a0308","chan":1,"rssi":-56,"auth":3}, 4 | {"ssid":"dlink-D9D8","chan":11,"rssi":-82,"auth":4}, 5 | {"ssid":"Linksys06730","chan":7,"rssi":-85,"auth":3}, 6 | {"ssid":"SINGTEL-5171","chan":9,"rssi":-88,"auth":4}, 7 | {"ssid":"1126-1","chan":11,"rssi":-89,"auth":4}, 8 | {"ssid":"The Shah 5GHz-2","chan":1,"rssi":-90,"auth":3}, 9 | {"ssid":"SINGTEL-1D28 (2G)","chan":11,"rssi":-91,"auth":3}, 10 | {"ssid":"dlink-F864","chan":1,"rssi":-92,"auth":4}, 11 | {"ssid":"dlink-74F0","chan":1,"rssi":-93,"auth":4} 12 | ] -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [ 9 | "_DEBUG", 10 | "UNICODE", 11 | "_UNICODE" 12 | ], 13 | "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC/14.25.28610/bin/Hostx64/x64/cl.exe", 14 | "cStandard": "c11", 15 | "cppStandard": "c++17", 16 | "intelliSenseMode": "msvc-x64", 17 | "compileCommands": "${workspaceFolder}/build/compile_commands.json" 18 | } 19 | ], 20 | "version": 4 21 | } -------------------------------------------------------------------------------- /components/esp32-wifi-manager/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Eclipse 55 | .metadata/ 56 | RemoteSystemsTempFiles/.project 57 | .settings/ 58 | *.a 59 | *.o 60 | *.d 61 | wifi_manager/.cproject 62 | wifi_manager/.project 63 | sdkconfig 64 | sdkconfig.old 65 | **/build/ 66 | #doxygen 67 | Doxyfile 68 | wifi_manager/doc/ 69 | .project 70 | .cproject 71 | 72 | # Visual Studio Code 73 | .vscode/ 74 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2019 Tony Pottier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/json.h: -------------------------------------------------------------------------------- 1 | /* 2 | @file json.h 3 | @brief handles very basic JSON with a minimal footprint on the system 4 | 5 | This code is a lightly modified version of cJSON 1.4.7. cJSON is licensed under the MIT license: 6 | Copyright (c) 2009 Dave Gamble 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 | of the Software, and to permit persons to whom the Software is furnished to do 13 | so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 20 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 22 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | @see https://github.com/DaveGamble/cJSON 26 | */ 27 | 28 | #ifndef JSON_H_INCLUDED 29 | #define JSON_H_INCLUDED 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /** 36 | * @brief Render the cstring provided to a JSON escaped version that can be printed. 37 | * @param input the input buffer to be escaped. 38 | * @param output_buffer the output buffer to write to. You must ensure it is big enough to contain the final string. 39 | * @see cJSON equivlaent static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) 40 | */ 41 | bool json_print_string(const unsigned char *input, unsigned char *output_buffer); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif /* JSON_H_INCLUDED */ 48 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/nvs_sync.c: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2020 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file nvs_sync.c 23 | @author Tony Pottier 24 | @brief Exposes a simple API to synchronize NVS memory read and writes 25 | 26 | @see https://idyl.io 27 | @see https://github.com/tonyp7/esp32-wifi-manager 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "nvs_sync.h" 35 | 36 | 37 | static SemaphoreHandle_t nvs_sync_mutex = NULL; 38 | 39 | esp_err_t nvs_sync_create(){ 40 | if(nvs_sync_mutex == NULL){ 41 | 42 | nvs_sync_mutex = xSemaphoreCreateMutex(); 43 | 44 | if(nvs_sync_mutex){ 45 | return ESP_OK; 46 | } 47 | else{ 48 | return ESP_FAIL; 49 | } 50 | } 51 | else{ 52 | return ESP_OK; 53 | } 54 | } 55 | 56 | void nvs_sync_free(){ 57 | if(nvs_sync_mutex != NULL){ 58 | vSemaphoreDelete( nvs_sync_mutex ); 59 | nvs_sync_mutex = NULL; 60 | } 61 | } 62 | 63 | bool nvs_sync_lock(TickType_t xTicksToWait){ 64 | if(nvs_sync_mutex){ 65 | if( xSemaphoreTake( nvs_sync_mutex, xTicksToWait ) == pdTRUE ) { 66 | return true; 67 | } 68 | else{ 69 | return false; 70 | } 71 | } 72 | else{ 73 | return false; 74 | } 75 | } 76 | 77 | void nvs_sync_unlock(){ 78 | xSemaphoreGive( nvs_sync_mutex ); 79 | } -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/nvs_sync.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2020 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file nvs_sync.h 23 | @author Tony Pottier 24 | @brief Exposes a simple API to synchronize NVS memory read and writes 25 | 26 | @see https://idyl.io 27 | @see https://github.com/tonyp7/esp32-wifi-manager 28 | */ 29 | 30 | 31 | 32 | #ifndef WIFI_MANAGER_NVS_SYNC_H_INCLUDED 33 | #define WIFI_MANAGER_NVS_SYNC_H_INCLUDED 34 | 35 | #include /* for type bool */ 36 | #include /* for TickType_t */ 37 | #include /* for esp_err_t */ 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | 44 | /** 45 | * @brief Attempts to get hold of the NVS semaphore for a set amount of ticks. 46 | * @note If you are uncertain about the number of ticks to wait use portMAX_DELAY. 47 | * @return true on a succesful lock, false otherwise 48 | */ 49 | bool nvs_sync_lock(TickType_t xTicksToWait); 50 | 51 | 52 | /** 53 | * @brief Releases the NVS semaphore 54 | */ 55 | void nvs_sync_unlock(); 56 | 57 | 58 | /** 59 | * @brief Create the NVS semaphore 60 | * @return ESP_OK: success or if the semaphore already exists 61 | * ESP_FAIL: failure 62 | */ 63 | esp_err_t nvs_sync_create(); 64 | 65 | /** 66 | * @brief Frees memory associated with the NVS semaphore 67 | * @warning Do not delete a semaphore that has tasks blocked on it (tasks that are in the Blocked state waiting for the semaphore to become available). 68 | */ 69 | void nvs_sync_free(); 70 | 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #endif /* WIFI_MANAGER_NVS_SYNC_H_INCLUDED */ -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/http_app.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file http_app.h 23 | @author Tony Pottier 24 | @brief Defines all functions necessary for the HTTP server to run. 25 | 26 | Contains the freeRTOS task for the HTTP listener and all necessary support 27 | function to process requests, decode URLs, serve files, etc. etc. 28 | 29 | @note http_server task cannot run without the wifi_manager task! 30 | @see https://idyl.io 31 | @see https://github.com/tonyp7/esp32-wifi-manager 32 | */ 33 | 34 | #ifndef HTTP_APP_H_INCLUDED 35 | #define HTTP_APP_H_INCLUDED 36 | 37 | #include 38 | #include 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | 45 | /** @brief Defines the URL where the wifi manager is located 46 | * By default it is at the server root (ie "/"). If you wish to add your own webpages 47 | * you may want to relocate the wifi manager to another URL, for instance /wifimanager 48 | */ 49 | #define WEBAPP_LOCATION CONFIG_WEBAPP_LOCATION 50 | 51 | 52 | /** 53 | * @brief spawns the http server 54 | */ 55 | void http_app_start(bool lru_purge_enable); 56 | 57 | /** 58 | * @brief stops the http server 59 | */ 60 | void http_app_stop(); 61 | 62 | /** 63 | * @brief sets a hook into the wifi manager URI handlers. Setting the handler to NULL disables the hook. 64 | * @return ESP_OK in case of success, ESP_ERR_INVALID_ARG if the method is unsupported. 65 | */ 66 | esp_err_t http_app_set_handler_hook( httpd_method_t method, esp_err_t (*handler)(httpd_req_t *r) ); 67 | 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Wifi Manager Configuration" 2 | 3 | config WIFI_MANAGER_TASK_PRIORITY 4 | int "RTOS Task Priority for the wifi_manager" 5 | default 5 6 | help 7 | Tasks spawn by the manager will have a priority of WIFI_MANAGER_TASK_PRIORITY-1. For this particular reason, minimum recommended task priority is 2. 8 | 9 | config WIFI_MANAGER_RETRY_TIMER 10 | int "Time (in ms) between each retry attempt" 11 | default 5000 12 | help 13 | Defines the time to wait before an attempt to re-connect to a saved wifi is made after connection is lost or another unsuccesful attempt is made. 14 | 15 | config WIFI_MANAGER_MAX_RETRY_START_AP 16 | int "Max Retry before starting the AP" 17 | default 3 18 | help 19 | Defines the maximum number of failed retries allowed before the WiFi manager starts its own access point. 20 | 21 | config WIFI_MANAGER_SHUTDOWN_AP_TIMER 22 | int "Time (in ms) to wait before shutting down the AP" 23 | default 60000 24 | help 25 | Defines the time (in ms) to wait after a succesful connection before shutting down the access point. 26 | 27 | config WEBAPP_LOCATION 28 | string "Defines the URL where the wifi manager is located" 29 | default "/" 30 | help 31 | This parameter helps you relocate the wifimanager to another URL, for instance /wifimanager/ The trailing slash is important and should be included 32 | 33 | config DEFAULT_AP_SSID 34 | string "Access Point SSID" 35 | default "esp32" 36 | help 37 | SSID (network name) the the esp32 will broadcast. 38 | 39 | config DEFAULT_AP_PASSWORD 40 | string "Access Point Password" 41 | default "esp32pwd" 42 | help 43 | Password used for the Access Point. Leave empty and set AUTH MODE to WIFI_AUTH_OPEN for no password. 44 | 45 | config DEFAULT_AP_CHANNEL 46 | int "Access Point WiFi Channel" 47 | default 1 48 | help 49 | Be careful you might not see the access point if you use a channel not allowed in your country. 50 | 51 | config DEFAULT_AP_IP 52 | string "Access Point IP Address" 53 | default "10.10.0.1" 54 | help 55 | This is used for the redirection to the captive portal. It is recommended to leave unchanged. 56 | 57 | config DEFAULT_AP_GATEWAY 58 | string "Access Point IP Gateway" 59 | default "10.10.0.1" 60 | help 61 | This is used for the redirection to the captive portal. It is recommended to leave unchanged. 62 | 63 | config DEFAULT_AP_NETMASK 64 | string "Access Point Netmask" 65 | default "255.255.255.0" 66 | help 67 | This is used for the redirection to the captive portal. It is recommended to leave unchanged. 68 | 69 | config DEFAULT_AP_MAX_CONNECTIONS 70 | int "Access Point Max Connections" 71 | default 4 72 | help 73 | Max is 4. 74 | 75 | config DEFAULT_AP_BEACON_INTERVAL 76 | int "Access Point Beacon Interval (ms)" 77 | default 100 78 | help 79 | 100ms is the recommended default. 80 | 81 | endmenu 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 WIFI Pentair Pool Controller 2 | * Send MQTT commands to your pool to control 3 | * Pool pump 4 | * Spa 5 | * Lights 6 | * Features 7 | 8 | * Easily integrated with HomeAssistant 9 | * FreeRTOS based 10 | * Includes Prometheus metrics on ```/metrics``` URL 11 | 12 | ![image](https://github.com/michaelusner/esp32_pentair_controller/blob/master/images/overview.png?raw=true) 13 | 14 | ## Track your metrics with Prometheus and Grafana 15 | ![image](https://github.com/michaelusner/esp32_pentair_controller/blob/master/images/prometheus-metrics.jpg?raw=true) ![image](https://github.com/michaelusner/esp32_pentair_controller/blob/master/images/grafana.jpg?raw=true) 16 | 17 | ## Hardware 18 | For this project, I used the following: 19 | * ESP32-DevKitC which I bought from [Amazon](https://www.amazon.com/gp/product/B0811LGWY2/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) 20 | 21 | ![image](https://github.com/michaelusner/esp32_pentair_controller/blob/master/images/esp32.jpg?raw=true) 22 | 23 | * MAX485 Development Board also from [Amazon](https://www.amazon.com/gp/product/B014QNI0BC/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) 24 | 25 | ![image](https://github.com/michaelusner/esp32_pentair_controller/blob/master/images/max485.jpg?raw=true) 26 | 27 | ## Wiring 28 | Here's the wiring diagram: 29 | 30 | ![image](https://github.com/michaelusner/esp32_pentair_controller/blob/master/images/wiring.jpg?raw=true) 31 | 32 | MAX485 Input: 33 | A - Pentair RS485 34 | B - Pentair RS485 35 | DE - RE Jumper 36 | 37 | | ESP32 Pin | MAX485 Pin | 38 | | --------- | ---------- | 39 | | 5v | VCC | 40 | | GND | GND | 41 | | 4 | DE | 42 | | 16 | R0 | 43 | | 17 | D1 | 44 | 45 | ## Configuration 46 | This project uses the [esp32-wifi-manager](https://github.com/tonyp7/esp32-wifi-manager) to connect your ESP32 to your wifi network. 47 | Please see this project for details on connecting to wifi after flashing. 48 | 49 | ## MQTT Server 50 | This project relies on an MQTT server installed somewhere on your home network. 51 | There are several options available (I chose Mosquitto on my Synology NAS which works fine). Installation and configuration of the server will be up to you. The ESP32 will need user/password access on the same subnet. 52 | 53 | After installing and configuring MQTT, you will need to add the required hostname/ip/user/password to the ESP32 code before flashing. 54 | 55 | TODO: This will be improved by a options available via a HTTP page on the ESP32. 56 | 57 | ## Home Assistant 58 | Once you setup your MQTT server, you will need to [configure Home Assistant](https://www.home-assistant.io/integrations/mqtt/) to connect to your MQTT server. 59 | 60 | The esp32-pentair-controller uses Home Assistant MQTT auto-discovery to populate the controls. They should appear automatically following the configuration and discovery process. 61 | 62 | ## TODO 63 | Configure MQTT server settings via web interface 64 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | 3 | # when you suspects issues in cache, use the following line to disable cache. 4 | # cache: false 5 | cache: 6 | directories: 7 | - ${HOME}/distfiles 8 | - ${HOME}/.ccache 9 | - ${HOME}/.cache/pip 10 | os: 11 | - linux 12 | 13 | matrix: 14 | include: 15 | - env: 16 | - PROJECT_TARGET="esp32" 17 | - PROJECT_SDK_BRANCH="master" 18 | # - env: 19 | # - PROJECT_TARGET="esp8266" 20 | # - PROJECT_SDK_BRANCH="master" 21 | 22 | addons: 23 | apt: 24 | packages: 25 | - gcc 26 | - wget 27 | - make 28 | - libncurses-dev 29 | - flex 30 | - bison 31 | - python 32 | - python-pip 33 | - gperf 34 | - ccache 35 | 36 | before_install: 37 | # Save path to the git respository 38 | - PROJECT_PATH=$(pwd) 39 | 40 | install: 41 | - export TOOLCHAIN_DIR="${HOME}/${PROJECT_TARGET}" 42 | - | 43 | if [ ${PROJECT_TARGET} == "esp8266" ]; then 44 | export PROJECT_GCC_PREFIX="xtensa-lx106-elf" 45 | export PROJECT_TOOLCHAIN_FILE=xtensa-lx106-elf-linux64-1.22.0-92-g8facf4c-5.2.0.tar.gz 46 | export PROJECT_SDK_NAME="ESP8266_RTOS_SDK" 47 | else 48 | export PROJECT_GCC_PREFIX="xtensa-esp32-elf" 49 | export PROJECT_TOOLCHAIN_FILE=xtensa-esp32-elf-gcc8_2_0-esp32-2019r1-linux-amd64.tar.gz 50 | export PROJECT_SDK_NAME="esp-idf" 51 | fi 52 | - export PROJECT_GCC_FILE="${PROJECT_GCC_PREFIX}-gcc" 53 | - export PROJECT_DISTFILE_DIR="${HOME}/distfiles" 54 | - export IDF_PATH=${TOOLCHAIN_DIR}/${PROJECT_SDK_NAME} 55 | - export PROJECT_LOG="${HOME}/build.log" 56 | - export PROJECT_EXAMPLE_DIR="${PROJECT_PATH}/examples" 57 | # Install ESP32 toochain following steps as desribed 58 | # in http://esp-idf.readthedocs.io/en/latest/linux-setup.html 59 | 60 | # Prepare directory for the toolchain 61 | - mkdir -p ${TOOLCHAIN_DIR} ${PROJECT_DISTFILE_DIR} 62 | # Get SDK from github 63 | - git clone --branch ${PROJECT_SDK_BRANCH} --recursive https://github.com/espressif/${PROJECT_SDK_NAME}.git ${IDF_PATH} 64 | 65 | # Setup ccache to build faster 66 | # XXX when the entire build process exceeds 50 min, th job will be killed 67 | # https://docs.travis-ci.com/user/customizing-the-build/#build-timeouts 68 | - ccache --version 69 | - mkdir ${HOME}/ccache_bin 70 | - (cd ${HOME}/ccache_bin && ln -s /usr/bin/ccache ${PROJECT_GCC_FILE}) 71 | - export CCACHE_BASEDIR=$PROJECT_PATH 72 | - export CCACHE_CPP2=true 73 | 74 | # Get Python requirements 75 | - python -m pip install --user --upgrade pyOpenSSL 76 | - python -m pip install --user -r ${IDF_PATH}/requirements.txt 77 | 78 | # Download binary toolchain if it does not exist 79 | - | 80 | if [ ! -f ${PROJECT_DISTFILE_DIR}/${PROJECT_TOOLCHAIN_FILE} ]; then 81 | wget -O ${PROJECT_DISTFILE_DIR}/${PROJECT_TOOLCHAIN_FILE} https://dl.espressif.com/dl/${PROJECT_TOOLCHAIN_FILE} 82 | fi 83 | - tar -xz -C ${TOOLCHAIN_DIR} -f ${PROJECT_DISTFILE_DIR}/${PROJECT_TOOLCHAIN_FILE} 84 | 85 | # Make toolchains available for all terminal sessions 86 | - export PATH=$HOME/ccache_bin:$PATH:$HOME/${PROJECT_TARGET}/${PROJECT_GCC_PREFIX}/bin 87 | 88 | script: 89 | - rm -f ${PROJECT_LOG} 90 | # XXX surpress log output where possible. when the size exceeds 4 MB, the 91 | # job will be killed. 92 | - | 93 | IGNORE_FILE="travis-ignore" 94 | 95 | case ${PROJECT_TARGET} in 96 | esp32) 97 | ;; 98 | esp8266) 99 | IGNORE_FILE="travis-ignore-esp8266" 100 | # these drivers do not compile for ESP8266 yet 101 | export EXCLUDE_COMPONENTS="encoder max7219 mcp23x17" 102 | ;; 103 | esac 104 | 105 | cd ${PROJECT_EXAMPLE_DIR} 106 | for i in $(ls -d */); do 107 | if [ ! -e ${PROJECT_EXAMPLE_DIR}/${i}/${IGNORE_FILE} ]; then 108 | echo "Building ${i}..." 109 | cd ${PROJECT_EXAMPLE_DIR}/${i} 110 | make defconfig 111 | make -j2 >> ${PROJECT_LOG} 112 | if [ $? -ne 0 ]; then 113 | # when failed, show last 100 lines for debugging, and exit with 114 | # non-zero exit code 115 | tail -n 100 ${PROJECT_LOG} 116 | exit 1 117 | fi 118 | make clean >/dev/null 119 | # make sure the directory is clean 120 | rm -rf ${i}/sdkconfig ${i}/build 121 | fi 122 | done 123 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/json.c: -------------------------------------------------------------------------------- 1 | /* 2 | @file json.c 3 | @brief handles very basic JSON with a minimal footprint on the system 4 | 5 | This code is a lightly modified version of cJSON 1.4.7. cJSON is licensed under the MIT license: 6 | Copyright (c) 2009 Dave Gamble 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 | of the Software, and to permit persons to whom the Software is furnished to do 13 | so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 20 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 22 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | @see https://github.com/DaveGamble/cJSON 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "json.h" 33 | 34 | 35 | bool json_print_string(const unsigned char *input, unsigned char *output_buffer) 36 | { 37 | const unsigned char *input_pointer = NULL; 38 | unsigned char *output = NULL; 39 | unsigned char *output_pointer = NULL; 40 | size_t output_length = 0; 41 | /* numbers of additional characters needed for escaping */ 42 | size_t escape_characters = 0; 43 | 44 | if (output_buffer == NULL) 45 | { 46 | return false; 47 | } 48 | 49 | /* empty string */ 50 | if (input == NULL) 51 | { 52 | //output = ensure(output_buffer, sizeof("\"\""), hooks); 53 | if (output == NULL) 54 | { 55 | return false; 56 | } 57 | strcpy((char*)output, "\"\""); 58 | 59 | return true; 60 | } 61 | 62 | /* set "flag" to 1 if something needs to be escaped */ 63 | for (input_pointer = input; *input_pointer; input_pointer++) 64 | { 65 | if (strchr("\"\\\b\f\n\r\t", *input_pointer)) 66 | { 67 | /* one character escape sequence */ 68 | escape_characters++; 69 | } 70 | else if (*input_pointer < 32) 71 | { 72 | /* UTF-16 escape sequence uXXXX */ 73 | escape_characters += 5; 74 | } 75 | } 76 | output_length = (size_t)(input_pointer - input) + escape_characters; 77 | 78 | /* in the original cJSON it is possible to realloc here in case output buffer is too small. 79 | * This is overkill for an embedded system. */ 80 | output = output_buffer; 81 | 82 | /* no characters have to be escaped */ 83 | if (escape_characters == 0) 84 | { 85 | output[0] = '\"'; 86 | memcpy(output + 1, input, output_length); 87 | output[output_length + 1] = '\"'; 88 | output[output_length + 2] = '\0'; 89 | 90 | return true; 91 | } 92 | 93 | output[0] = '\"'; 94 | output_pointer = output + 1; 95 | /* copy the string */ 96 | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) 97 | { 98 | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) 99 | { 100 | /* normal character, copy */ 101 | *output_pointer = *input_pointer; 102 | } 103 | else 104 | { 105 | /* character needs to be escaped */ 106 | *output_pointer++ = '\\'; 107 | switch (*input_pointer) 108 | { 109 | case '\\': 110 | *output_pointer = '\\'; 111 | break; 112 | case '\"': 113 | *output_pointer = '\"'; 114 | break; 115 | case '\b': 116 | *output_pointer = 'b'; 117 | break; 118 | case '\f': 119 | *output_pointer = 'f'; 120 | break; 121 | case '\n': 122 | *output_pointer = 'n'; 123 | break; 124 | case '\r': 125 | *output_pointer = 'r'; 126 | break; 127 | case '\t': 128 | *output_pointer = 't'; 129 | break; 130 | default: 131 | /* escape and print as unicode codepoint */ 132 | sprintf((char*)output_pointer, "u%04x", *input_pointer); 133 | output_pointer += 4; 134 | break; 135 | } 136 | } 137 | } 138 | output[output_length + 1] = '\"'; 139 | output[output_length + 2] = '\0'; 140 | 141 | return true; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/dns_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file dns_server.h 23 | @author Tony Pottier 24 | @brief Defines an extremly basic DNS server for captive portal functionality. 25 | 26 | Contains the freeRTOS task for the DNS server that processes the requests. 27 | 28 | @see https://idyl.io 29 | @see https://github.com/tonyp7/esp32-wifi-manager 30 | @see http://www.zytrax.com/books/dns/ch15 31 | */ 32 | 33 | #ifndef MAIN_DNS_SERVER_H_ 34 | #define MAIN_DNS_SERVER_H_ 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | 41 | /** 12 byte header, 64 byte domain name, 4 byte qtype/qclass. This NOT compliant with the RFC, but it's good enough for a captive portal 42 | * if a DNS query is too big it just wont be processed. */ 43 | #define DNS_QUERY_MAX_SIZE 80 44 | 45 | /** Query + 2 byte ptr, 2 byte type, 2 byte class, 4 byte TTL, 2 byte len, 4 byte data */ 46 | #define DNS_ANSWER_MAX_SIZE (DNS_QUERY_MAX_SIZE+16) 47 | 48 | 49 | /** 50 | * @brief RCODE values used in a DNS header message 51 | */ 52 | typedef enum dns_reply_code_t { 53 | DNS_REPLY_CODE_NO_ERROR = 0, 54 | DNS_REPLY_CODE_FORM_ERROR = 1, 55 | DNS_REPLY_CODE_SERVER_FAILURE = 2, 56 | DNS_REPLY_CODE_NON_EXISTANT_DOMAIN = 3, 57 | DNS_REPLY_CODE_NOT_IMPLEMENTED = 4, 58 | DNS_REPLY_CODE_REFUSED = 5, 59 | DNS_REPLY_CODE_YXDOMAIN = 6, 60 | DNS_REPLY_CODE_YXRRSET = 7, 61 | DNS_REPLY_CODE_NXRRSET = 8 62 | }dns_reply_code_t; 63 | 64 | 65 | 66 | /** 67 | * @brief OPCODE values used in a DNS header message 68 | */ 69 | typedef enum dns_opcode_code_t { 70 | DNS_OPCODE_QUERY = 0, 71 | DNS_OPCODE_IQUERY = 1, 72 | DNS_OPCODE_STATUS = 2 73 | }dns_opcode_code_t; 74 | 75 | 76 | 77 | /** 78 | * @brief Represents a 12 byte DNS header. 79 | * __packed__ is needed to prevent potential unwanted memory alignments 80 | */ 81 | typedef struct __attribute__((__packed__)) dns_header_t{ 82 | uint16_t ID; // identification number 83 | uint8_t RD : 1; // recursion desired 84 | uint8_t TC : 1; // truncated message 85 | uint8_t AA : 1; // authoritive answer 86 | uint8_t OPCode : 4; // message_type 87 | uint8_t QR : 1; // query/response flag 88 | uint8_t RCode : 4; // response code 89 | uint8_t Z : 3; // its z! reserved 90 | uint8_t RA : 1; // recursion available 91 | uint16_t QDCount; // number of question entries 92 | uint16_t ANCount; // number of answer entries 93 | uint16_t NSCount; // number of authority entries 94 | uint16_t ARCount; // number of resource entries 95 | }dns_header_t; 96 | 97 | 98 | 99 | typedef enum dns_answer_type_t { 100 | DNS_ANSWER_TYPE_A = 1, 101 | DNS_ANSWER_TYPE_NS = 2, 102 | DNS_ANSWER_TYPE_CNAME = 5, 103 | DNS_ANSWER_TYPE_SOA = 6, 104 | DNS_ANSWER_TYPE_WKS = 11, 105 | DNS_ANSWER_TYPE_PTR = 12, 106 | DNS_ANSWER_TYPE_MX = 15, 107 | DNS_ANSWER_TYPE_SRV = 33, 108 | DNS_ANSWER_TYPE_AAAA = 28 109 | }dns_answer_type_t; 110 | 111 | typedef enum dns_answer_class_t { 112 | DNS_ANSWER_CLASS_IN = 1 113 | }dns_answer_class_t; 114 | 115 | 116 | 117 | typedef struct __attribute__((__packed__)) dns_answer_t{ 118 | uint16_t NAME; /* for the sake of simplicity only 16 bit pointers are supported */ 119 | uint16_t TYPE; /* Unsigned 16 bit value. The resource record types - determines the content of the RDATA field. */ 120 | uint16_t CLASS; /* Class of response. */ 121 | uint32_t TTL; /* The time in seconds that the record may be cached. A value of 0 indicates the record should not be cached. */ 122 | uint16_t RDLENGTH; /* Unsigned 16-bit value that defines the length in bytes of the RDATA record. */ 123 | uint32_t RDATA; /* For the sake of simplicity only ipv4 is supported, and as such it's a unsigned 32 bit */ 124 | }dns_answer_t; 125 | 126 | void dns_server(void *pvParameters); 127 | void dns_server_start(); 128 | void dns_server_stop(); 129 | 130 | 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | 136 | 137 | #endif /* MAIN_DNS_SERVER_H_ */ 138 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | esp32-wifi-manager 10 | 11 | 12 |
13 |
14 |
15 |
16 |

Wi-Fi

17 |
18 |
19 |

Connected to:

20 |
21 |
22 |
23 |
24 |

Manual connect

25 |
26 |
ADD (HIDDEN) SSID
27 |
28 |

or choose a network...

29 |
30 |
31 |
Powered by esp32-wifi-manager.
32 |
33 |
34 |
35 |

Enter Details

36 |
37 |

Manual Connection

38 |
39 | 40 | 41 |
42 |
43 | 44 | 45 |
46 |
47 |
48 |
49 |

Enter Password

50 |
51 |

Password for

52 |
53 | 54 |
55 |
56 | 57 | 58 |
59 |
60 |
61 |
62 |

Please wait...

63 |
64 |

Connecting to

65 |
66 |
67 |
68 |

You may lose wifi access while the esp32 recalibrates its radio. Please wait until your device automatically reconnects. This can take up to 30s.

69 |
70 |
71 |

Success!

72 |
73 |
74 |

Connection failed

75 |

Please double-check wifi password if any and make sure the access point has good signal.

76 |
77 |
78 |
79 | 80 |
81 |
82 |
83 |
84 |
85 |

86 |
87 |

88 |
89 |
90 | 91 |
92 |
93 |

IP Address

94 |
95 |
IP Address:
96 |
Subnet Mask:
97 |
Default Gateway:
98 |
99 |
100 | 101 |
102 |
103 |
104 |
105 |

Are you sure you would like to disconnect from this wifi?

106 |
107 | 108 | 109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |

About this app...

118 |
119 |

120 |
121 |

esp32-wifi-manager, © 2017-2020, Tony Pottier
Licended under the MIT License.

122 |

123 | This app would not be possible without the following libraries: 124 |

125 |
    126 |
  • SpinKit, © 2015, Tobias Ahlin. Licensed under the MIT License.
  • 127 |
  • jQuery, The jQuery Foundation. Licensed under the MIT License.
  • 128 |
  • cJSON, © 2009-2017, Dave Gamble and cJSON contributors. Licensed under the MIT License.
  • 129 |
130 |
131 |
132 | 133 |
134 |
135 | 136 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/dns_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file dns_server.c 23 | @author Tony Pottier 24 | @brief Defines an extremely basic DNS server for captive portal functionality. 25 | It's basically a DNS hijack that replies to the esp's address no matter which 26 | request is sent to it. 27 | 28 | Contains the freeRTOS task for the DNS server that processes the requests. 29 | 30 | @see https://idyl.io 31 | @see https://github.com/tonyp7/esp32-wifi-manager 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "wifi_manager.h" 54 | #include "dns_server.h" 55 | 56 | static const char TAG[] = "dns_server"; 57 | static TaskHandle_t task_dns_server = NULL; 58 | int socket_fd; 59 | 60 | void dns_server_start() { 61 | if(task_dns_server == NULL){ 62 | xTaskCreate(&dns_server, "dns_server", 3072, NULL, WIFI_MANAGER_TASK_PRIORITY-1, &task_dns_server); 63 | } 64 | } 65 | 66 | void dns_server_stop(){ 67 | if(task_dns_server){ 68 | vTaskDelete(task_dns_server); 69 | close(socket_fd); 70 | task_dns_server = NULL; 71 | } 72 | 73 | } 74 | 75 | 76 | 77 | void dns_server(void *pvParameters) { 78 | 79 | 80 | 81 | struct sockaddr_in ra; 82 | 83 | /* Set redirection DNS hijack to the access point IP */ 84 | ip4_addr_t ip_resolved; 85 | inet_pton(AF_INET, DEFAULT_AP_IP, &ip_resolved); 86 | 87 | 88 | /* Create UDP socket */ 89 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 90 | if (socket_fd < 0){ 91 | ESP_LOGE(TAG, "Failed to create socket"); 92 | exit(0); 93 | } 94 | 95 | /* Bind to port 53 (typical DNS Server port) */ 96 | esp_netif_ip_info_t ip; 97 | esp_netif_t* netif_sta = wifi_manager_get_esp_netif_sta(); 98 | ESP_ERROR_CHECK(esp_netif_get_ip_info(netif_sta, &ip)); 99 | ra.sin_family = AF_INET; 100 | ra.sin_addr.s_addr = ip.ip.addr; 101 | ra.sin_port = htons(53); 102 | if (bind(socket_fd, (struct sockaddr *)&ra, sizeof(struct sockaddr_in)) == -1) { 103 | ESP_LOGE(TAG, "Failed to bind to 53/udp"); 104 | close(socket_fd); 105 | exit(1); 106 | } 107 | 108 | struct sockaddr_in client; 109 | socklen_t client_len; 110 | client_len = sizeof(client); 111 | int length; 112 | uint8_t data[DNS_QUERY_MAX_SIZE]; /* dns query buffer */ 113 | uint8_t response[DNS_ANSWER_MAX_SIZE]; /* dns response buffer */ 114 | char ip_address[INET_ADDRSTRLEN]; /* buffer to store IPs as text. This is only used for debug and serves no other purpose */ 115 | char *domain; /* This is only used for debug and serves no other purpose */ 116 | int err; 117 | 118 | ESP_LOGI(TAG, "DNS Server listening on 53/udp"); 119 | 120 | /* Start loop to process DNS requests */ 121 | for(;;) { 122 | 123 | memset(data, 0x00, sizeof(data)); /* reset buffer */ 124 | length = recvfrom(socket_fd, data, sizeof(data), 0, (struct sockaddr *)&client, &client_len); /* read udp request */ 125 | 126 | /*if the query is bigger than the buffer size we simply ignore it. This case should only happen in case of multiple 127 | * queries within the same DNS packet and is not supported by this simple DNS hijack. */ 128 | if ( length > 0 && ((length + sizeof(dns_answer_t)-1) < DNS_ANSWER_MAX_SIZE) ) { 129 | 130 | data[length] = '\0'; /*in case there's a bogus domain name that isn't null terminated */ 131 | 132 | /* Generate header message */ 133 | memcpy(response, data, sizeof(dns_header_t)); 134 | dns_header_t *dns_header = (dns_header_t*)response; 135 | dns_header->QR = 1; /*response bit */ 136 | dns_header->OPCode = DNS_OPCODE_QUERY; /* no support for other type of response */ 137 | dns_header->AA = 1; /*authoritative answer */ 138 | dns_header->RCode = DNS_REPLY_CODE_NO_ERROR; /* no error */ 139 | dns_header->TC = 0; /*no truncation */ 140 | dns_header->RD = 0; /*no recursion */ 141 | dns_header->ANCount = dns_header->QDCount; /* set answer count = question count -- duhh! */ 142 | dns_header->NSCount = 0x0000; /* name server resource records = 0 */ 143 | dns_header->ARCount = 0x0000; /* resource records = 0 */ 144 | 145 | 146 | /* copy the rest of the query in the response */ 147 | memcpy(response + sizeof(dns_header_t), data + sizeof(dns_header_t), length - sizeof(dns_header_t)); 148 | 149 | 150 | /* extract domain name and request IP for debug */ 151 | inet_ntop(AF_INET, &(client.sin_addr), ip_address, INET_ADDRSTRLEN); 152 | domain = (char*) &data[sizeof(dns_header_t) + 1]; 153 | for(char* c=domain; *c != '\0'; c++){ 154 | if(*c < ' ' || *c > 'z') *c = '.'; /* technically we should test if the first two bits are 00 (e.g. if( (*c & 0xC0) == 0x00) *c = '.') but this makes the code a lot more readable */ 155 | } 156 | ESP_LOGI(TAG, "Replying to DNS request for %s from %s", domain, ip_address); 157 | 158 | 159 | /* create DNS answer at the end of the query*/ 160 | dns_answer_t *dns_answer = (dns_answer_t*)&response[length]; 161 | dns_answer->NAME = __bswap_16(0xC00C); /* This is a pointer to the beginning of the question. As per DNS standard, first two bits must be set to 11 for some odd reason hence 0xC0 */ 162 | dns_answer->TYPE = __bswap_16(DNS_ANSWER_TYPE_A); 163 | dns_answer->CLASS = __bswap_16(DNS_ANSWER_CLASS_IN); 164 | dns_answer->TTL = (uint32_t)0x00000000; /* no caching. Avoids DNS poisoning since this is a DNS hijack */ 165 | dns_answer->RDLENGTH = __bswap_16(0x0004); /* 4 byte => size of an ipv4 address */ 166 | dns_answer->RDATA = ip_resolved.addr; 167 | 168 | err = sendto(socket_fd, response, length+sizeof(dns_answer_t), 0, (struct sockaddr *)&client, client_len); 169 | if (err < 0) { 170 | ESP_LOGE(TAG, "UDP sendto failed: %d", err); 171 | } 172 | } 173 | 174 | taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. DNS daemon should not be taxing on the system */ 175 | 176 | } 177 | close(socket_fd); 178 | 179 | vTaskDelete ( NULL ); 180 | } 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #eee; 3 | border: 0; 4 | margin: 0; 5 | font: 1.1em tahoma, arial, sans-serif; 6 | } 7 | a { 8 | color: darkblue; 9 | transition: color .2s ease-out; 10 | text-decoration: none 11 | } 12 | a:hover { 13 | color: red; 14 | } 15 | input { 16 | display: none; 17 | font: 1.1em tahoma, arial, sans-serif; 18 | } 19 | input:focus, 20 | select:focus, 21 | textarea:focus, 22 | button:focus { 23 | outline: none; 24 | } 25 | input[type="button"] { 26 | width: 100px; 27 | padding: 5px; 28 | text-align: center; 29 | display: block; 30 | } 31 | p { 32 | padding: 10px; 33 | } 34 | #credits { 35 | display: none; 36 | } 37 | #app {} #app-wrap {} #disconnect { 38 | width: 150px; 39 | } 40 | .diag-box { 41 | position: absolute; 42 | top: 0; 43 | left: 0; 44 | bottom: 0; 45 | right: 0; 46 | height: 100%; 47 | width: 100%; 48 | display: none; 49 | } 50 | .diag-box-win { 51 | position: absolute; 52 | left: 10%; 53 | width: 80%; 54 | text-align: center; 55 | border: 2px outset #888; 56 | background-color: #fff; 57 | border-radius: 10px; 58 | top: 20%; 59 | } 60 | .blur { 61 | -webkit-filter: blur(2px); 62 | -moz-filter: blur(2px); 63 | -ms-filter: blur(2px); 64 | -o-filter: blur(2px); 65 | filter: blur(2px); 66 | } 67 | .ape { 68 | margin-left: 20px; 69 | padding: 10px 0px 10px 10px; 70 | } 71 | .ape:hover { 72 | cursor: pointer; 73 | } 74 | .brdb { 75 | border-bottom: 1px solid #888; 76 | } 77 | header { 78 | background-color: #fff; 79 | border-bottom: 1px solid #888; 80 | } 81 | section { 82 | background-color: #fff; 83 | border-bottom: 1px solid #888; 84 | border-top: 1px solid #888; 85 | } 86 | h1 { 87 | display: block; 88 | text-align: center; 89 | margin: 0; 90 | padding: 15px; 91 | font-size: 1.4em 92 | } 93 | h2 { 94 | margin: 0; 95 | margin-top: 20px; 96 | padding: 10px; 97 | text-transform: uppercase; 98 | color: #888; 99 | font-size: 1.0em 100 | } 101 | h3 { 102 | margin: 0; 103 | text-align: center; 104 | padding: 20px 0px 20px 0px; 105 | } 106 | .gr { 107 | color: green; 108 | } 109 | .rd { 110 | color: red; 111 | } 112 | #wifi-status { 113 | display: none; 114 | } 115 | #connect { 116 | display: none; 117 | } 118 | #connect_manual { 119 | display: none; 120 | } 121 | #manual_ssid { 122 | border: none; 123 | width: 80%; 124 | margin-left: 35px; 125 | padding: 10px 0px 10px 10px; 126 | display: block 127 | } 128 | #manual_pwd { 129 | border: none; 130 | width: 80%; 131 | margin-left: 35px; 132 | padding: 10px 0px 10px 10px; 133 | display: block 134 | } 135 | #pwd { 136 | border: none; 137 | width: 80%; 138 | margin-left: 35px; 139 | padding: 10px 0px 10px 10px; 140 | display: block 141 | } 142 | .buttons { 143 | padding: 15px; 144 | } 145 | #join { 146 | float: right; 147 | } 148 | #manual_join { 149 | float: right; 150 | } 151 | #yes-disconnect { 152 | display: inline-block; 153 | margin-left: 20px; 154 | } 155 | #no-disconnect { 156 | display: inline-block; 157 | } 158 | .ctr { 159 | margin: 0 auto; 160 | } 161 | .tctr { 162 | text-align: center; 163 | } 164 | #connect-wait { 165 | display: none; 166 | } 167 | #connect-success { 168 | display: none; 169 | } 170 | #connect-fail { 171 | display: none; 172 | } 173 | #connect-details { 174 | display: none; 175 | } 176 | .fr { 177 | float: right; 178 | margin-right: 20px; 179 | } 180 | .w0 { 181 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTJDBGvsAAABzUlEQVRIS+WUTShEURTH3zyRhjQ+8hWxmCJMoSzEwsbCgi1LZRYW9pONptiwka9iI81CWFpYaEqNMkVKmpWN1IhYKN9ZDL/z3p3mxZh5g9X4168799xz/vPefedeLeuVC+3gdTgc07CsmCQ2DI2gg21Jci30wSpGt/CeghickTsHPVACDkgqp67rPgpO4E0ZZMIj7OHhxSvPtEyomcVDeFXJv+EZNvEsNa01rZfAuSUhThR2wU+ObJkbyhRNMMDaDIThBqy1MdZ3wAPawqfFC2Lj0Ab5kpBGxdAJs9TeW72ITUhCPZMjFYwwbwXpnkwlDzOIx50yXwP5c0MeggHGanNqSDqqBqQ7/Kxvg2zHAfMN8IE8uZhYO6eBnBXGKnOakLWfaQZ9jMRjSPXhZUuC5A9JjVFpKkeNSVVA0Tq8KJN0yFl4gilqbW2tm+SQKoybXIG8jcT34RSsh1Byt6iVg2ZLlRCg6JpROqEDpFheXZ5S9rcLFsl5YJwHad+MVA5y13w5lRY5oRsKjdm/Vz/7LR86zG+5wr+9NX+iOowjEO+aELEic+lv1ILppeUPosRst6QduTANgnE2mC+BnYswI1VwfYzCCL9dZij7pWkf6UeSTYAuE/QAAAAASUVORK5CYII=') no-repeat right top; 182 | height: 24px; 183 | margin-right: 20px; 184 | } 185 | .w1 { 186 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEQAACxEBf2RfkQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNkRpr/UAAAHiSURBVEhL5dRPKINxHMfxPVskpA35F3FYEVasHBYHFwcHrhyVZ8vBfblIceEi/4qLtINwdHCQUpQVKcnJRYqIg/J3OYz399nv0YPNtuzEt149+31/v+/n4fGYLVHpup4Rnyregd+K27TIghe63+8fx7wySqsPdbAj3qzha0MOV6ETiwTd4u0HUZxydgrtKISGj0xreG4gEAgycIRXFZCOR2yTQZSebeaa4Q1s7iOiDv/GM1bJLDJv0EHjzHLAdIFNjHBGHpkbxUo9utmbQBg3sM5G2d+AR24w82XznN4QmpGjXrCExRkXfJhk9t6aRW9YDtSwOFDNE9ZNyFLzKRczOegh406FL8ElG8JDM8S1Qtaq7KhEO0Y0TVtHGHusVxCEDy5oMLNqyVrgWm5kqaYw3mdVdmqQsENE8JbAPbY43yszMqiyHOr66QayL5XH0DJeVEgyUTxhjNmPR/vtBpZyc3hHDZohV5DfRvq7OMYtrDdZY7YwFpG8yhBi6JrrMFogww7IT1mOVsxy5oHrNIqRVpWgDtnGKn7log35xurfVxfPW/7QYT57Ybz7mapqgk9gvjU79ApiW5mpRkIvLTe4oJfyK5lKOQndgvG/wXoOSb8I061Svj4G0M9nZ6z198tmeweYtIrMYP17VAAAAABJRU5ErkJggg==') no-repeat right top; 187 | height: 24px; 188 | margin-right: 20px; 189 | } 190 | .w2 { 191 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEQAACxEBf2RfkQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNkRpr/UAAAHkSURBVEhL3dRLKERRGMDxuSPSkLzyilgo8iiUhVjYWFiwZancmSzsZSPFho28io1kISwtLKQURZGSrGykiFgo7yyG/zdzznRm5iK5Sk79uvd85/u++5hzx2Pb9q9yDLrJMWhIRB1sv98/ghlliFAXyuGFU21IbECSi9CKORrd4O0TQZyQO45mZMJCpKfZ3BcIBPooOMSravAdD9ikB63sJN1XN69kcQ8vKvknnrBMzyx9gRYCp0aCdo51DJIjr6wU2UoF2lkbxS6uYdYGWV9DtVxgMmbxjFg/apEM/ZQfyUADxqi9M3sRG5CEEib7KnjMvAaye2IbfUVupoMet6r5PDL0YjXBBY4Fai5kRxVCdscg66uQ17HDfAl9kDuXJzB3Thk5sxzzZa6DumHknN3QS+IBPvvh5ZVskN8ZU5+gz3XAlELRIp5Vk6/It/CIYWrjXm3URCkleUsV6iaXkKeR+DaOYH6EkrtCrXxoUf2iJoY8LFB0xXEA9ZBieXS5S3m/jZgi557jBGT7xvWKCxhyIP81ka/SgQ9NSDViURyDbvpTo82yrAPscl4HKxR1aRTT+BhvyhaxtPCSO6OKphfGBc6JZYaX3BnpNN1AUC7AfBrJoRUXR67X6+1BN+fp4dD/Hx7PO4o9VGuAapKIAAAAAElFTkSuQmCC') no-repeat right top; 192 | height: 24px; 193 | margin-right: 20px; 194 | } 195 | .w3 { 196 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAACAElEQVRIS7XUP0gbYRjH8VSpiBZJWvEflXYQKtqACg6ig4uDg651LPQSHLpLlyDoUhdpVdBFxEG0YwcHCQgRFJSCFKcuUohY6iC0VYtD9PuE9w3vXZ74h16HD3fv733e53KX9y7ied5/pYZhUkPHQ3TBSyQS7zFvTBC9RivKoK3NCwZS3IxBLNLoBFc3yOEbtR/Qj8d4gEJPt3lVMpkcY8E+Lk2D+/iDTXrQyquwfW3zdiZ38dcU/4tzrNHzib3AAMGhU2BlsYFxauSRtaDWaMMwc1PYwU+4a3PMryMuF5gJTH4ne4dOVMLeZSkx9GCatb/cXmQpKXjOYM+EB4w7ILsn2Og28mNe0ePUNF9CzE7GCZc5NpmxkB31FLI7xpn/DHkc24xXMQb55XIH7s55Qc0Cx0YZ29A2LJyzG95S+AU3/fHySNLUjwTWl9tzG7iqWbSCC9PkNvIunGGStUWP1jcwWijOmIW2yTHkbiTfwle4L6HUfmKtvGi+fr6BowHLLPrBMYVuyGK5dfmV8nx7MUvNb44fIdu3qFdR4KiDfGsKb6WiCn145GQ+ahgmNQyTGpYwxPOWP3qHc/mE+76apaih4hmND2B3TYasJlCjUkPFS5oeORfIkhVtSY0aKqI0TSP/bjCew10+hPf6D+r5fIziDefRwFxJahgmNQyPF7kGEsc1es+A2E4AAAAASUVORK5CYII=') no-repeat right top; 197 | height: 24px; 198 | margin-right: 20px; 199 | } 200 | .pw { 201 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTJDBGvsAAABIUlEQVRIS+3VsU7CUBTGcYhBJCwqwcmEJ2DkCQgzb8ADmLgYWXTzMVjcGNjYGEAXgoSRhTg5OroYIyFY/h+hWGwvtzQ0LpzkF8i5l/uRQ2kTjuPEKrC5T79vzHWJO4wxwzeGuMY5AitsQBFvmEObvNQboQBfhQk4gQ5wD+zgBrcYrHrSwzE2KkxAHVrQWB6QgiqJLB7xA+2pYaNsAWm8QAsa0Sn+1gU+oT1NHGFdtoAcJtBCSw1DuaPqQiNdly0gj1doQaMwleavPc+IJUDffKeADO7Rxxe08A4dEOQD2qPXJ1xh+VuYAirQVaNGFFPov2MM0OXm/UAUZRwCtjoEWP1vQBXuLTgKPYRKMAacoY0oIboDNLB8+PgC4hLY3B8nsQCQEf56jLJoQAAAAABJRU5ErkJggg==') no-repeat right top; 202 | height: 24px; 203 | margin-right: 20px; 204 | height: 24px; 205 | margin-right: 30px; 206 | } 207 | /* SpinKit is licensed under the MIT License. Copyright (c) 2015 Tobias Ahlin */ 208 | 209 | .spinner { 210 | width: 40px; 211 | height: 40px; 212 | position: relative; 213 | margin: 100px auto; 214 | } 215 | .double-bounce1, 216 | .double-bounce2 { 217 | width: 100%; 218 | height: 100%; 219 | border-radius: 50%; 220 | background-color: #333; 221 | opacity: 0.6; 222 | position: absolute; 223 | top: 0; 224 | left: 0; 225 | -webkit-animation: sk-bounce 2.0s infinite ease-in-out; 226 | animation: sk-bounce 2.0s infinite ease-in-out; 227 | } 228 | .double-bounce2 { 229 | -webkit-animation-delay: -1.0s; 230 | animation-delay: -1.0s; 231 | } 232 | @-webkit-keyframes sk-bounce { 233 | 0%, 100% { 234 | -webkit-transform: scale(0.0) 235 | } 236 | 50% { 237 | -webkit-transform: scale(1.0) 238 | } 239 | } 240 | @keyframes sk-bounce { 241 | 0%, 100% { 242 | transform: scale(0.0); 243 | -webkit-transform: scale(0.0); 244 | } 245 | 50% { 246 | transform: scale(1.0); 247 | -webkit-transform: scale(1.0); 248 | } 249 | } 250 | /* end of SpinKit */ -------------------------------------------------------------------------------- /components/esp32-wifi-manager/README.md: -------------------------------------------------------------------------------- 1 | # What is esp32-wifi-manager? 2 | 3 | ### Build status [![Build Status](https://travis-ci.com/tonyp7/esp32-wifi-manager.svg?branch=master)](https://travis-ci.com/tonyp7/esp32-wifi-manager) 4 | 5 | *esp32-wifi-manager* is a pure C esp-idf component for ESP32 that enables easy management of wifi networks through a web portal. 6 | 7 | *esp32-wifi-manager* is is an all in one wifi scanner, http server & dns daemon living in the least amount of RAM possible. 8 | 9 | *esp32-wifi-manager* will automatically attempt to re-connect to a previously saved network on boot, and if it cannot find a saved wifi it will start its own access point through which you can manage and connect to wifi networks. Upon a succesful connection, the software will shutdown the access point automatically after some time (1 minute by default). 10 | 11 | *esp32-wifi-manager* compiles with esp-idf 4.2 and above. See [Getting Started](#getting-started) to guide you through your first setup. 12 | 13 | # Content 14 | - [Demo](#demo) 15 | - [Look And Feel](#look-and-feel) 16 | - [Getting Started](#getting-started) 17 | - [Requirements](#requirements) 18 | - [Hello World](#hello-world) 19 | - [Configuring the Wifi Manager](#configuring-the-wifi-manager) 20 | - [Adding esp32-wifi-manager to your code](#adding-esp32-wifi-manager-to-your-code) 21 | - [Interacting with the manager](#interacting-with-the-manager) 22 | - [Interacting with the http server](#interacting-with-the-http-server) 23 | - [Thread safety and access to NVS](#thread-safety-and-access-to-nvs) 24 | - [License](#license) 25 | 26 | 27 | # Demo 28 | [![esp32-wifi-manager demo](http://img.youtube.com/vi/hxlZi15bym4/0.jpg)](http://www.youtube.com/watch?v=hxlZi15bym4) 29 | 30 | # Look and Feel 31 | ![esp32-wifi-manager on an mobile device](https://idyl.io/wp-content/uploads/2017/11/esp32-wifi-manager-password.png "esp32-wifi-manager") ![esp32-wifi-manager on an mobile device](https://idyl.io/wp-content/uploads/2017/11/esp32-wifi-manager-connected-to.png "esp32-wifi-manager") 32 | 33 | # Getting Started 34 | 35 | ## Requirements 36 | 37 | To get you started, esp32-wifi-manager needs: 38 | 39 | - esp-idf **4.2 and up** 40 | - esp32 or esp32-s2 41 | 42 | There are breaking changes and new features in esp-idf 4.1 and 4.2 which makes esp32-wifi-manager incompatible with anything lower than 4.2. This includes esp_netif (introduced in 4.1) and esp_event_handler_instance_t (introduced in 4.2). It is recommended to compile esp32-wifi-manager with the master tree to avoid any compatibility issue. 43 | 44 | ## Hello World 45 | 46 | Clone the repository where you want it to be. If you are unfamiliar with Git, you can use Github Desktop on Windows: 47 | 48 | ```bash 49 | git clone https://github.com/tonyp7/esp32-wifi-manager.git 50 | ``` 51 | 52 | Navigate under the included example: 53 | 54 | ```bash 55 | cd esp32-wifi-manager/examples/default_demo 56 | ``` 57 | 58 | Compile the code and load it on your esp32: 59 | 60 | ```bash 61 | idf.py build flash monitor 62 | ``` 63 | 64 | _Note: while it is encouraged to use the newer build system with idf.py and cmake, esp32-wifi-manager still supports the legacy build system. If you are using make on Linux or make using MSYS2 on Windows, you can still use "make build flash monitor" if you prefer_ 65 | 66 | Now, using any wifi capable device, you will see a new wifi access point named *esp32*. Connect to it using the default password *esp32pwd*. If the captive portal does not pop up on your device, you can access the wifi manager at its default IP address: http://10.10.0.1. 67 | 68 | ## Configuring the Wifi Manager 69 | 70 | esp32-wifi-manager can be configured without touching its code. At the project level use: 71 | 72 | ```bash 73 | idf.py menuconfig 74 | ``` 75 | 76 | Navigate in "Component config" then pick "Wifi Manager Configuration". You will be greeted by the following screen: 77 | 78 | ![esp32-wifi-manager-menuconfig](https://idyl.io/wp-content/uploads/2020/08/wifi-manager-menuconfig-800px.png "menuconfig screen") 79 | 80 | You can change the ssid and password of the access point at your convenience, but it is highly recommended to keep default values. Your password should be between 8 and 63 characters long, to comply with the WPA2 standard. If the password is set to an empty value or is less than 8 characters long, esp32-wifi-manager will create its access point as an open wifi network. 81 | 82 | You can also change the values for various timers, for instance how long it takes for the access point to shutdown once a connection is established (default: 60000). While it could be tempting to set this timer to 0, just be warned that in that case the user will never get the feedback that a connection is succesful. Shutting down the AP will instantly kill the current navigating session on the captive portal. 83 | 84 | Finally, you can choose to relocate esp32-wifi-manager to a different URL by changing the default value of "/" to something else, for instance "/wifimanager/". Please note that the trailing slash does matter. This feature is particularly useful in case you want your own webapp to co-exist with esp32-wifi-manager's own web pages. 85 | 86 | # Adding esp32-wifi-manager to your code 87 | 88 | In order to use esp32-wifi-manager effectively in your esp-idf projects, copy the whole esp32-wifi-manager repository (or git clone) into a components subfolder. 89 | 90 | Your project should look like this: 91 | 92 | - project_folder 93 | - build 94 | - components 95 | - esp32-wifi-manager 96 | - main 97 | - main.c 98 | 99 | Under eclipse, this is what a typical project looks like: 100 | 101 | ![eclipse project with esp32-wifi-manager](https://idyl.io/wp-content/uploads/2020/07/eclipse-idf-project.png "eclipse project with esp32-wifi-manager") 102 | 103 | Once this is done, you need to edit the CMakeLists.txt file at the root of your project to register the components folder. This is done by adding the following line: 104 | 105 | ```cmake 106 | set(EXTRA_COMPONENTS_DIRS components/) 107 | ``` 108 | 109 | A typical CmakeLists.txt file should look like this: 110 | 111 | ```cmake 112 | cmake_minimum_required(VERSION 3.5) 113 | set(EXTRA_COMPONENT_DIRS components/) 114 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 115 | project(name_of_your_project) 116 | ``` 117 | 118 | If you are using the old build system with make instead, you should edit the Makefile instead such as: 119 | 120 | ```make 121 | PROJECT_NAME := name_of_your_project 122 | EXTRA_COMPONENT_DIRS := components/ 123 | include $(IDF_PATH)/make/project.mk 124 | ``` 125 | 126 | Once this is done, you can now in your user code add the header: 127 | 128 | ```c 129 | #include "wifi_manager.h" 130 | ``` 131 | 132 | All you need to do now is to call wifi_manager_start(); in your code. See [examples/default_demo](examples/default_demo) if you are uncertain. 133 | 134 | 135 | ## Interacting with the manager 136 | 137 | Ther are effectively three different ways you can embed esp32-wifi-manager with your code: 138 | * Just forget about it and poll in your code for wifi connectivity status 139 | * Use event callbacks 140 | * Modify esp32-wifi-manager code directly to fit your needs 141 | 142 | **Event callbacks** are the cleanest way to use the wifi manager and that's the recommended way to do it. A typical use-case would be to get notified when wifi manager finally gets a connection to an access point. In order to do this you can simply define a callback function: 143 | 144 | ```c 145 | void cb_connection_ok(void *pvParameter){ 146 | ESP_LOGI(TAG, "I have a connection!"); 147 | } 148 | ``` 149 | 150 | Then just register it by calling: 151 | 152 | ```c 153 | wifi_manager_set_callback(WM_EVENT_STA_GOT_IP, &cb_connection_ok); 154 | ``` 155 | 156 | That's it! Now everytime the event is triggered it will call this function. The [examples/default_demo](examples/default_demo) contains sample code using callbacks. 157 | 158 | ### List of events 159 | 160 | The list of possible events you can add a callback to are defined by message_code_t in wifi_manager.h. They are as following: 161 | 162 | * WM_ORDER_START_HTTP_SERVER 163 | * WM_ORDER_STOP_HTTP_SERVER 164 | * WM_ORDER_START_DNS_SERVICE 165 | * WM_ORDER_STOP_DNS_SERVICE 166 | * WM_ORDER_START_WIFI_SCAN 167 | * WM_ORDER_LOAD_AND_RESTORE_STA 168 | * WM_ORDER_CONNECT_STA 169 | * WM_ORDER_DISCONNECT_STA 170 | * WM_ORDER_START_AP 171 | * WM_EVENT_STA_DISCONNECTED 172 | * WM_EVENT_SCAN_DONE 173 | * WM_EVENT_STA_GOT_IP 174 | * WM_ORDER_STOP_AP 175 | 176 | In practice, keeping track of WM_EVENT_STA_GOT_IP and WM_EVENT_STA_DISCONNECTED is key to know whether or not your esp32 has a connection. The other messages can mostly be ignored in a typical application using esp32-wifi-manager. 177 | 178 | ### Events parameters 179 | 180 | Callback signature includes a void* pointer. For most events, this additional parameter is empty and sent as a NULL value. A few select events have additional data which can be leveraged by user code. They are listed below: 181 | 182 | * WM_EVENT_SCAN_DONE is sent with a wifi_event_sta_scan_done_t* object. 183 | * WM_EVENT_STA_DISCONNECTED is sent with a wifi_event_sta_disconnected_t* object. 184 | * WM_EVENT_STA_GOT_IP is sent with a ip_event_got_ip_t* object. 185 | 186 | These objects are standard esp-idf structures, and are documented as such in the [official pages](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html). 187 | 188 | The [examples/default_demo](examples/default_demo) demonstrates how you can read a ip_event_got_ip_t object to access the IP address assigned to the esp32. 189 | 190 | ## Interacting with the http server 191 | 192 | Because esp32-wifi-manager spawns its own http server, you might want to extend this server to serve your own pages in your application. It is possible to do so by registering your own URL handler using the standard esp_http_server signature: 193 | 194 | ```c 195 | esp_err_t my_custom_handler(httpd_req_t *req){ 196 | ``` 197 | 198 | And then registering the handler by doing 199 | 200 | ```c 201 | http_app_set_handler_hook(HTTP_GET, &my_custom_handler); 202 | ``` 203 | 204 | The [examples/http_hook](examples/http_hook) contains an example where a web page is registered at /helloworld 205 | 206 | ## Thread safety and access to NVS 207 | 208 | esp32-wifi-manager accesses the non-volatile storage to store and loads its configuration into a dedicated namespace "espwifimgr". If you want to make sure there will never be a conflict with concurrent access to the NVS, you can include nvs_sync.h and use calls to nvs_sync_lock and nvs_sync_unlock. 209 | 210 | ```c 211 | nvs_handle handle; 212 | 213 | if(nvs_sync_lock( portMAX_DELAY )){ 214 | if(nvs_open(wifi_manager_nvs_namespace, NVS_READWRITE, &handle) == ESP_OK){ 215 | /* do something with NVS */ 216 | nvs_close(handle); 217 | } 218 | nvs_sync_unlock(); 219 | } 220 | ``` 221 | nvs_sync_lock waits for the number of ticks sent to it as a parameter to acquire a mutex. It is recommended to use portMAX_DELAY. In practice, nvs_sync_lock will almost never wait. 222 | 223 | 224 | # License 225 | *esp32-wifi-manager* is MIT licensed. As such, it can be included in any project, commercial or not, as long as you retain original copyright. Please make sure to read the license file. 226 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/code.js: -------------------------------------------------------------------------------- 1 | // save some bytes 2 | const gel = (e) => document.getElementById(e); 3 | 4 | const wifi_div = gel("wifi"); 5 | const connect_div = gel("connect"); 6 | const connect_manual_div = gel("connect_manual"); 7 | const connect_wait_div = gel("connect-wait"); 8 | const connect_details_div = gel("connect-details"); 9 | 10 | function docReady(fn) { 11 | // see if DOM is already available 12 | if ( 13 | document.readyState === "complete" || 14 | document.readyState === "interactive" 15 | ) { 16 | // call on next available tick 17 | setTimeout(fn, 1); 18 | } else { 19 | document.addEventListener("DOMContentLoaded", fn); 20 | } 21 | } 22 | 23 | var selectedSSID = ""; 24 | var refreshAPInterval = null; 25 | var checkStatusInterval = null; 26 | 27 | function stopCheckStatusInterval() { 28 | if (checkStatusInterval != null) { 29 | clearInterval(checkStatusInterval); 30 | checkStatusInterval = null; 31 | } 32 | } 33 | 34 | function stopRefreshAPInterval() { 35 | if (refreshAPInterval != null) { 36 | clearInterval(refreshAPInterval); 37 | refreshAPInterval = null; 38 | } 39 | } 40 | 41 | function startCheckStatusInterval() { 42 | checkStatusInterval = setInterval(checkStatus, 950); 43 | } 44 | 45 | function startRefreshAPInterval() { 46 | refreshAPInterval = setInterval(refreshAP, 3800); 47 | } 48 | 49 | docReady(async function () { 50 | gel("wifi-status").addEventListener( 51 | "click", 52 | () => { 53 | wifi_div.style.display = "none"; 54 | document.getElementById("connect-details").style.display = "block"; 55 | }, 56 | false 57 | ); 58 | 59 | gel("manual_add").addEventListener( 60 | "click", 61 | (e) => { 62 | selectedSSID = e.target.innerText; 63 | 64 | gel("ssid-pwd").textContent = selectedSSID; 65 | wifi_div.style.display = "none"; 66 | connect_manual_div.style.display = "block"; 67 | connect_div.style.display = "none"; 68 | 69 | gel("connect-success").display = "none"; 70 | gel("connect-fail").display = "none"; 71 | }, 72 | false 73 | ); 74 | 75 | gel("wifi-list").addEventListener( 76 | "click", 77 | (e) => { 78 | selectedSSID = e.target.innerText; 79 | gel("ssid-pwd").textContent = selectedSSID; 80 | connect_div.style.display = "block"; 81 | wifi_div.style.display = "none"; 82 | // init_cancel(); 83 | }, 84 | false 85 | ); 86 | 87 | function cancel() { 88 | selectedSSID = ""; 89 | connect_div.style.display = "none"; 90 | connect_manual_div.style.display = "none"; 91 | wifi_div.style.display = "block"; 92 | } 93 | 94 | gel("cancel").addEventListener("click", cancel, false); 95 | 96 | gel("manual_cancel").addEventListener("click", cancel, false); 97 | 98 | gel("join").addEventListener("click", performConnect, false); 99 | 100 | gel("manual_join").addEventListener( 101 | "click", 102 | (e) => { 103 | performConnect("manual"); 104 | }, 105 | false 106 | ); 107 | 108 | gel("ok-details").addEventListener( 109 | "click", 110 | () => { 111 | connect_details_div.style.display = "none"; 112 | wifi_div.style.display = "block"; 113 | }, 114 | false 115 | ); 116 | 117 | gel("ok-credits").addEventListener( 118 | "click", 119 | () => { 120 | gel("credits").style.display = "none"; 121 | gel("app").style.display = "block"; 122 | }, 123 | false 124 | ); 125 | 126 | gel("acredits").addEventListener( 127 | "click", 128 | () => { 129 | event.preventDefault(); 130 | gel("app").style.display = "none"; 131 | gel("credits").style.display = "block"; 132 | }, 133 | false 134 | ); 135 | 136 | gel("ok-connect").addEventListener( 137 | "click", 138 | () => { 139 | connect_wait_div.style.display = "none"; 140 | wifi_div.style.display = "block"; 141 | }, 142 | false 143 | ); 144 | 145 | gel("disconnect").addEventListener( 146 | "click", 147 | () => { 148 | gel("diag-disconnect").style.display = "block"; 149 | gel("connect-details-wrap").classList.add("blur"); 150 | }, 151 | false 152 | ); 153 | 154 | gel("no-disconnect").addEventListener( 155 | "click", 156 | () => { 157 | gel("diag-disconnect").style.display = "none"; 158 | gel("connect-details-wrap").classList.remove("blur"); 159 | }, 160 | false 161 | ); 162 | 163 | gel("yes-disconnect").addEventListener("click", async () => { 164 | stopCheckStatusInterval(); 165 | selectedSSID = ""; 166 | 167 | document.getElementById("diag-disconnect").style.display = "none"; 168 | gel("connect-details-wrap").classList.remove("blur"); 169 | 170 | await fetch("connect.json", { 171 | method: "DELETE", 172 | headers: { 173 | "Content-Type": "application/json", 174 | }, 175 | body: { timestamp: Date.now() }, 176 | }); 177 | 178 | startCheckStatusInterval(); 179 | 180 | connect_details_div.style.display = "none"; 181 | wifi_div.style.display = "block"; 182 | }); 183 | 184 | //first time the page loads: attempt get the connection status and start the wifi scan 185 | await refreshAP(); 186 | startCheckStatusInterval(); 187 | startRefreshAPInterval(); 188 | }); 189 | 190 | async function performConnect(conntype) { 191 | //stop the status refresh. This prevents a race condition where a status 192 | //request would be refreshed with wrong ip info from a previous connection 193 | //and the request would automatically shows as succesful. 194 | stopCheckStatusInterval(); 195 | 196 | //stop refreshing wifi list 197 | stopRefreshAPInterval(); 198 | 199 | var pwd; 200 | if (conntype == "manual") { 201 | //Grab the manual SSID and PWD 202 | selectedSSID = gel("manual_ssid").value; 203 | pwd = gel("manual_pwd").value; 204 | } else { 205 | pwd = gel("pwd").value; 206 | } 207 | //reset connection 208 | gel("loading").style.display = "block"; 209 | gel("connect-success").style.display = "none"; 210 | gel("connect-fail").style.display = "none"; 211 | 212 | gel("ok-connect").disabled = true; 213 | gel("ssid-wait").textContent = selectedSSID; 214 | connect_div.style.display = "none"; 215 | connect_manual_div.style.display = "none"; 216 | connect_wait_div.style.display = "block"; 217 | 218 | await fetch("connect.json", { 219 | method: "POST", 220 | headers: { 221 | "Content-Type": "application/json", 222 | "X-Custom-ssid": selectedSSID, 223 | "X-Custom-pwd": pwd, 224 | }, 225 | body: { timestamp: Date.now() }, 226 | }); 227 | 228 | //now we can re-set the intervals regardless of result 229 | startCheckStatusInterval(); 230 | startRefreshAPInterval(); 231 | } 232 | 233 | function rssiToIcon(rssi) { 234 | if (rssi >= -60) { 235 | return "w0"; 236 | } else if (rssi >= -67) { 237 | return "w1"; 238 | } else if (rssi >= -75) { 239 | return "w2"; 240 | } else { 241 | return "w3"; 242 | } 243 | } 244 | 245 | async function refreshAP(url = "ap.json") { 246 | try { 247 | var res = await fetch(url); 248 | var access_points = await res.json(); 249 | if (access_points.length > 0) { 250 | //sort by signal strength 251 | access_points.sort((a, b) => { 252 | var x = a["rssi"]; 253 | var y = b["rssi"]; 254 | return x < y ? 1 : x > y ? -1 : 0; 255 | }); 256 | refreshAPHTML(access_points); 257 | } 258 | } catch (e) { 259 | console.info("Access points returned empty from /ap.json!"); 260 | } 261 | } 262 | 263 | function refreshAPHTML(data) { 264 | var h = ""; 265 | data.forEach(function (e, idx, array) { 266 | let ap_class = idx === array.length - 1 ? "" : " brdb"; 267 | let rssicon = rssiToIcon(e.rssi); 268 | let auth = e.auth == 0 ? "" : "pw"; 269 | h += `
${e.ssid}
\n`; 270 | }); 271 | 272 | gel("wifi-list").innerHTML = h; 273 | } 274 | 275 | async function checkStatus(url = "status.json") { 276 | try { 277 | var response = await fetch(url); 278 | var data = await response.json(); 279 | if (data && data.hasOwnProperty("ssid") && data["ssid"] != "") { 280 | if (data["ssid"] === selectedSSID) { 281 | // Attempting connection 282 | switch (data["urc"]) { 283 | case 0: 284 | console.info("Got connection!"); 285 | document.querySelector( 286 | "#connected-to div div div span" 287 | ).textContent = data["ssid"]; 288 | document.querySelector("#connect-details h1").textContent = 289 | data["ssid"]; 290 | gel("ip").textContent = data["ip"]; 291 | gel("netmask").textContent = data["netmask"]; 292 | gel("gw").textContent = data["gw"]; 293 | gel("wifi-status").style.display = "block"; 294 | 295 | //unlock the wait screen if needed 296 | gel("ok-connect").disabled = false; 297 | 298 | //update wait screen 299 | gel("loading").style.display = "none"; 300 | gel("connect-success").style.display = "block"; 301 | gel("connect-fail").style.display = "none"; 302 | break; 303 | case 1: 304 | console.info("Connection attempt failed!"); 305 | document.querySelector( 306 | "#connected-to div div div span" 307 | ).textContent = data["ssid"]; 308 | document.querySelector("#connect-details h1").textContent = 309 | data["ssid"]; 310 | gel("ip").textContent = "0.0.0.0"; 311 | gel("netmask").textContent = "0.0.0.0"; 312 | gel("gw").textContent = "0.0.0.0"; 313 | 314 | //don't show any connection 315 | gel("wifi-status").display = "none"; 316 | 317 | //unlock the wait screen 318 | gel("ok-connect").disabled = false; 319 | 320 | //update wait screen 321 | gel("loading").display = "none"; 322 | gel("connect-fail").style.display = "block"; 323 | gel("connect-success").style.display = "none"; 324 | break; 325 | } 326 | } else if (data.hasOwnProperty("urc") && data["urc"] === 0) { 327 | console.info("Connection established"); 328 | //ESP32 is already connected to a wifi without having the user do anything 329 | if ( 330 | gel("wifi-status").style.display == "" || 331 | gel("wifi-status").style.display == "none" 332 | ) { 333 | document.querySelector("#connected-to div div div span").textContent = 334 | data["ssid"]; 335 | document.querySelector("#connect-details h1").textContent = 336 | data["ssid"]; 337 | gel("ip").textContent = data["ip"]; 338 | gel("netmask").textContent = data["netmask"]; 339 | gel("gw").textContent = data["gw"]; 340 | gel("wifi-status").style.display = "block"; 341 | } 342 | } 343 | } else if (data.hasOwnProperty("urc") && data["urc"] === 2) { 344 | console.log("Manual disconnect requested..."); 345 | if (gel("wifi-status").style.display == "block") { 346 | gel("wifi-status").style.display = "none"; 347 | } 348 | } 349 | } catch (e) { 350 | console.info("Was not able to fetch /status.json"); 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/wifi_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file wifi_manager.h 23 | @author Tony Pottier 24 | @brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis 25 | 26 | Contains the freeRTOS task and all necessary support 27 | 28 | @see https://idyl.io 29 | @see https://github.com/tonyp7/esp32-wifi-manager 30 | */ 31 | 32 | #ifndef WIFI_MANAGER_H_INCLUDED 33 | #define WIFI_MANAGER_H_INCLUDED 34 | 35 | #include 36 | 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | 43 | /** 44 | * @brief Defines the maximum size of a SSID name. 32 is IEEE standard. 45 | * @warning limit is also hard coded in wifi_config_t. Never extend this value. 46 | */ 47 | #define MAX_SSID_SIZE 32 48 | 49 | /** 50 | * @brief Defines the maximum size of a WPA2 passkey. 64 is IEEE standard. 51 | * @warning limit is also hard coded in wifi_config_t. Never extend this value. 52 | */ 53 | #define MAX_PASSWORD_SIZE 64 54 | 55 | 56 | /** 57 | * @brief Defines the maximum number of access points that can be scanned. 58 | * 59 | * To save memory and avoid nasty out of memory errors, 60 | * we can limit the number of APs detected in a wifi scan. 61 | */ 62 | #define MAX_AP_NUM 15 63 | 64 | 65 | /** 66 | * @brief Defines the maximum number of failed retries allowed before the WiFi manager starts its own access point. 67 | * Setting it to 2 for instance means there will be 3 attempts in total (original request + 2 retries) 68 | */ 69 | #define WIFI_MANAGER_MAX_RETRY_START_AP CONFIG_WIFI_MANAGER_MAX_RETRY_START_AP 70 | 71 | /** 72 | * @brief Time (in ms) between each retry attempt 73 | * Defines the time to wait before an attempt to re-connect to a saved wifi is made after connection is lost or another unsuccesful attempt is made. 74 | */ 75 | #define WIFI_MANAGER_RETRY_TIMER CONFIG_WIFI_MANAGER_RETRY_TIMER 76 | 77 | 78 | /** 79 | * @brief Time (in ms) to wait before shutting down the AP 80 | * Defines the time (in ms) to wait after a succesful connection before shutting down the access point. 81 | */ 82 | #define WIFI_MANAGER_SHUTDOWN_AP_TIMER CONFIG_WIFI_MANAGER_SHUTDOWN_AP_TIMER 83 | 84 | 85 | /** @brief Defines the task priority of the wifi_manager. 86 | * 87 | * Tasks spawn by the manager will have a priority of WIFI_MANAGER_TASK_PRIORITY-1. 88 | * For this particular reason, minimum task priority is 1. It it highly not recommended to set 89 | * it to 1 though as the sub-tasks will now have a priority of 0 which is the priority 90 | * of freeRTOS' idle task. 91 | */ 92 | #define WIFI_MANAGER_TASK_PRIORITY CONFIG_WIFI_MANAGER_TASK_PRIORITY 93 | 94 | /** @brief Defines the auth mode as an access point 95 | * Value must be of type wifi_auth_mode_t 96 | * @see esp_wifi_types.h 97 | * @warning if set to WIFI_AUTH_OPEN, passowrd me be empty. See DEFAULT_AP_PASSWORD. 98 | */ 99 | #define AP_AUTHMODE WIFI_AUTH_WPA2_PSK 100 | 101 | /** @brief Defines visibility of the access point. 0: visible AP. 1: hidden */ 102 | #define DEFAULT_AP_SSID_HIDDEN 0 103 | 104 | /** @brief Defines access point's name. Default value: esp32. Run 'make menuconfig' to setup your own value or replace here by a string */ 105 | #define DEFAULT_AP_SSID CONFIG_DEFAULT_AP_SSID 106 | 107 | /** @brief Defines access point's password. 108 | * @warning In the case of an open access point, the password must be a null string "" or "\0" if you want to be verbose but waste one byte. 109 | * In addition, the AP_AUTHMODE must be WIFI_AUTH_OPEN 110 | */ 111 | #define DEFAULT_AP_PASSWORD CONFIG_DEFAULT_AP_PASSWORD 112 | 113 | /** @brief Defines the hostname broadcasted by mDNS */ 114 | #define DEFAULT_HOSTNAME "esp32" 115 | 116 | /** @brief Defines access point's bandwidth. 117 | * Value: WIFI_BW_HT20 for 20 MHz or WIFI_BW_HT40 for 40 MHz 118 | * 20 MHz minimize channel interference but is not suitable for 119 | * applications with high data speeds 120 | */ 121 | #define DEFAULT_AP_BANDWIDTH WIFI_BW_HT20 122 | 123 | /** @brief Defines access point's channel. 124 | * Channel selection is only effective when not connected to another AP. 125 | * Good practice for minimal channel interference to use 126 | * For 20 MHz: 1, 6 or 11 in USA and 1, 5, 9 or 13 in most parts of the world 127 | * For 40 MHz: 3 in USA and 3 or 11 in most parts of the world 128 | */ 129 | #define DEFAULT_AP_CHANNEL CONFIG_DEFAULT_AP_CHANNEL 130 | 131 | 132 | 133 | /** @brief Defines the access point's default IP address. Default: "10.10.0.1 */ 134 | #define DEFAULT_AP_IP CONFIG_DEFAULT_AP_IP 135 | 136 | /** @brief Defines the access point's gateway. This should be the same as your IP. Default: "10.10.0.1" */ 137 | #define DEFAULT_AP_GATEWAY CONFIG_DEFAULT_AP_GATEWAY 138 | 139 | /** @brief Defines the access point's netmask. Default: "255.255.255.0" */ 140 | #define DEFAULT_AP_NETMASK CONFIG_DEFAULT_AP_NETMASK 141 | 142 | /** @brief Defines access point's maximum number of clients. Default: 4 */ 143 | #define DEFAULT_AP_MAX_CONNECTIONS CONFIG_DEFAULT_AP_MAX_CONNECTIONS 144 | 145 | /** @brief Defines access point's beacon interval. 100ms is the recommended default. */ 146 | #define DEFAULT_AP_BEACON_INTERVAL CONFIG_DEFAULT_AP_BEACON_INTERVAL 147 | 148 | /** @brief Defines if esp32 shall run both AP + STA when connected to another AP. 149 | * Value: 0 will have the own AP always on (APSTA mode) 150 | * Value: 1 will turn off own AP when connected to another AP (STA only mode when connected) 151 | * Turning off own AP when connected to another AP minimize channel interference and increase throughput 152 | */ 153 | #define DEFAULT_STA_ONLY 1 154 | 155 | /** @brief Defines if wifi power save shall be enabled. 156 | * Value: WIFI_PS_NONE for full power (wifi modem always on) 157 | * Value: WIFI_PS_MODEM for power save (wifi modem sleep periodically) 158 | * Note: Power save is only effective when in STA only mode 159 | */ 160 | #define DEFAULT_STA_POWER_SAVE WIFI_PS_NONE 161 | 162 | /** 163 | * @brief Defines the maximum length in bytes of a JSON representation of an access point. 164 | * 165 | * maximum ap string length with full 32 char ssid: 75 + \\n + \0 = 77\n 166 | * example: {"ssid":"abcdefghijklmnopqrstuvwxyz012345","chan":12,"rssi":-100,"auth":4},\n 167 | * BUT: we need to escape JSON. Imagine a ssid full of \" ? so it's 32 more bytes hence 77 + 32 = 99.\n 168 | * this is an edge case but I don't think we should crash in a catastrophic manner just because 169 | * someone decided to have a funny wifi name. 170 | */ 171 | #define JSON_ONE_APP_SIZE 99 172 | 173 | /** 174 | * @brief Defines the maximum length in bytes of a JSON representation of the IP information 175 | * assuming all ips are 4*3 digits, and all characters in the ssid require to be escaped. 176 | * example: {"ssid":"abcdefghijklmnopqrstuvwxyz012345","ip":"192.168.1.119","netmask":"255.255.255.0","gw":"192.168.1.1","urc":99} 177 | * Run this JS (browser console is easiest) to come to the conclusion that 159 is the worst case. 178 | * ``` 179 | * var a = {"ssid":"abcdefghijklmnopqrstuvwxyz012345","ip":"255.255.255.255","netmask":"255.255.255.255","gw":"255.255.255.255","urc":99}; 180 | * // Replace all ssid characters with a double quote which will have to be escaped 181 | * a.ssid = a.ssid.split('').map(() => '"').join(''); 182 | * console.log(JSON.stringify(a).length); // => 158 +1 for null 183 | * console.log(JSON.stringify(a)); // print it 184 | * ``` 185 | */ 186 | #define JSON_IP_INFO_SIZE 159 187 | 188 | 189 | /** 190 | * @brief defines the minimum length of an access point password running on WPA2 191 | */ 192 | #define WPA2_MINIMUM_PASSWORD_LENGTH 8 193 | 194 | 195 | /** 196 | * @brief Defines the complete list of all messages that the wifi_manager can process. 197 | * 198 | * Some of these message are events ("EVENT"), and some of them are action ("ORDER") 199 | * Each of these messages can trigger a callback function and each callback function is stored 200 | * in a function pointer array for convenience. Because of this behavior, it is extremely important 201 | * to maintain a strict sequence and the top level special element 'MESSAGE_CODE_COUNT' 202 | * 203 | * @see wifi_manager_set_callback 204 | */ 205 | typedef enum message_code_t { 206 | NONE = 0, 207 | WM_ORDER_START_HTTP_SERVER = 1, 208 | WM_ORDER_STOP_HTTP_SERVER = 2, 209 | WM_ORDER_START_DNS_SERVICE = 3, 210 | WM_ORDER_STOP_DNS_SERVICE = 4, 211 | WM_ORDER_START_WIFI_SCAN = 5, 212 | WM_ORDER_LOAD_AND_RESTORE_STA = 6, 213 | WM_ORDER_CONNECT_STA = 7, 214 | WM_ORDER_DISCONNECT_STA = 8, 215 | WM_ORDER_START_AP = 9, 216 | WM_EVENT_STA_DISCONNECTED = 10, 217 | WM_EVENT_SCAN_DONE = 11, 218 | WM_EVENT_STA_GOT_IP = 12, 219 | WM_ORDER_STOP_AP = 13, 220 | WM_MESSAGE_CODE_COUNT = 14 /* important for the callback array */ 221 | 222 | }message_code_t; 223 | 224 | /** 225 | * @brief simplified reason codes for a lost connection. 226 | * 227 | * esp-idf maintains a big list of reason codes which in practice are useless for most typical application. 228 | */ 229 | typedef enum update_reason_code_t { 230 | UPDATE_CONNECTION_OK = 0, 231 | UPDATE_FAILED_ATTEMPT = 1, 232 | UPDATE_USER_DISCONNECT = 2, 233 | UPDATE_LOST_CONNECTION = 3 234 | }update_reason_code_t; 235 | 236 | typedef enum connection_request_made_by_code_t{ 237 | CONNECTION_REQUEST_NONE = 0, 238 | CONNECTION_REQUEST_USER = 1, 239 | CONNECTION_REQUEST_AUTO_RECONNECT = 2, 240 | CONNECTION_REQUEST_RESTORE_CONNECTION = 3, 241 | CONNECTION_REQUEST_MAX = 0x7fffffff /*force the creation of this enum as a 32 bit int */ 242 | }connection_request_made_by_code_t; 243 | 244 | /** 245 | * The actual WiFi settings in use 246 | */ 247 | struct wifi_settings_t{ 248 | uint8_t ap_ssid[MAX_SSID_SIZE]; 249 | uint8_t ap_pwd[MAX_PASSWORD_SIZE]; 250 | uint8_t ap_channel; 251 | uint8_t ap_ssid_hidden; 252 | wifi_bandwidth_t ap_bandwidth; 253 | bool sta_only; 254 | wifi_ps_type_t sta_power_save; 255 | bool sta_static_ip; 256 | esp_netif_ip_info_t sta_static_ip_config; 257 | }; 258 | extern struct wifi_settings_t wifi_settings; 259 | 260 | 261 | /** 262 | * @brief Structure used to store one message in the queue. 263 | */ 264 | typedef struct{ 265 | message_code_t code; 266 | void *param; 267 | } queue_message; 268 | 269 | 270 | /** 271 | * @brief returns the current esp_netif object for the STAtion 272 | */ 273 | esp_netif_t* wifi_manager_get_esp_netif_sta(); 274 | 275 | /** 276 | * @brief returns the current esp_netif object for the Access Point 277 | */ 278 | esp_netif_t* wifi_manager_get_esp_netif_ap(); 279 | 280 | 281 | /** 282 | * Allocate heap memory for the wifi manager and start the wifi_manager RTOS task 283 | */ 284 | void wifi_manager_start(); 285 | 286 | /** 287 | * Frees up all memory allocated by the wifi_manager and kill the task. 288 | */ 289 | void wifi_manager_destroy(); 290 | 291 | /** 292 | * Filters the AP scan list to unique SSIDs 293 | */ 294 | void filter_unique( wifi_ap_record_t * aplist, uint16_t * ap_num); 295 | 296 | /** 297 | * Main task for the wifi_manager 298 | */ 299 | void wifi_manager( void * pvParameters ); 300 | 301 | 302 | char* wifi_manager_get_ap_list_json(); 303 | char* wifi_manager_get_ip_info_json(); 304 | 305 | 306 | void wifi_manager_scan_async(); 307 | 308 | 309 | /** 310 | * @brief saves the current STA wifi config to flash ram storage. 311 | */ 312 | esp_err_t wifi_manager_save_sta_config(); 313 | 314 | /** 315 | * @brief fetch a previously STA wifi config in the flash ram storage. 316 | * @return true if a previously saved config was found, false otherwise. 317 | */ 318 | bool wifi_manager_fetch_wifi_sta_config(); 319 | 320 | wifi_config_t* wifi_manager_get_wifi_sta_config(); 321 | 322 | 323 | /** 324 | * @brief requests a connection to an access point that will be process in the main task thread. 325 | */ 326 | void wifi_manager_connect_async(); 327 | 328 | /** 329 | * @brief requests a wifi scan 330 | */ 331 | void wifi_manager_scan_awifi_manager_send_messagesync(); 332 | 333 | /** 334 | * @brief requests to disconnect and forget about the access point. 335 | */ 336 | void wifi_manager_disconnect_async(); 337 | 338 | /** 339 | * @brief Tries to get access to json buffer mutex. 340 | * 341 | * The HTTP server can try to access the json to serve clients while the wifi manager thread can try 342 | * to update it. These two tasks are synchronized through a mutex. 343 | * 344 | * The mutex is used by both the access point list json and the connection status json.\n 345 | * These two resources should technically have their own mutex but we lose some flexibility to save 346 | * on memory. 347 | * 348 | * This is a simple wrapper around freeRTOS function xSemaphoreTake. 349 | * 350 | * @param xTicksToWait The time in ticks to wait for the semaphore to become available. 351 | * @return true in success, false otherwise. 352 | */ 353 | bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait); 354 | 355 | /** 356 | * @brief Releases the json buffer mutex. 357 | */ 358 | void wifi_manager_unlock_json_buffer(); 359 | 360 | /** 361 | * @brief Generates the connection status json: ssid and IP addresses. 362 | * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. 363 | */ 364 | void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code); 365 | /** 366 | * @brief Clears the connection status json. 367 | * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. 368 | */ 369 | void wifi_manager_clear_ip_info_json(); 370 | 371 | /** 372 | * @brief Generates the list of access points after a wifi scan. 373 | * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. 374 | */ 375 | void wifi_manager_generate_acess_points_json(); 376 | 377 | /** 378 | * @brief Clear the list of access points. 379 | * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. 380 | */ 381 | void wifi_manager_clear_access_points_json(); 382 | 383 | 384 | /** 385 | * @brief Start the mDNS service 386 | */ 387 | void wifi_manager_initialise_mdns(); 388 | 389 | 390 | bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait); 391 | void wifi_manager_unlock_sta_ip_string(); 392 | 393 | /** 394 | * @brief gets the string representation of the STA IP address, e.g.: "192.168.1.69" 395 | */ 396 | char* wifi_manager_get_sta_ip_string(); 397 | 398 | /** 399 | * @brief thread safe char representation of the STA IP update 400 | */ 401 | void wifi_manager_safe_update_sta_ip_string(uint32_t ip); 402 | 403 | 404 | /** 405 | * @brief Register a callback to a custom function when specific event message_code happens. 406 | */ 407 | void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*) ); 408 | 409 | 410 | BaseType_t wifi_manager_send_message(message_code_t code, void *param); 411 | BaseType_t wifi_manager_send_message_to_front(message_code_t code, void *param); 412 | 413 | #ifdef __cplusplus 414 | } 415 | #endif 416 | 417 | #endif /* WIFI_MANAGER_H_INCLUDED */ 418 | -------------------------------------------------------------------------------- /components/esp32-wifi-manager/src/http_app.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 Tony Pottier 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | @file http_app.c 23 | @author Tony Pottier 24 | @brief Defines all functions necessary for the HTTP server to run. 25 | 26 | Contains the freeRTOS task for the HTTP listener and all necessary support 27 | function to process requests, decode URLs, serve files, etc. etc. 28 | 29 | @note http_server task cannot run without the wifi_manager task! 30 | @see https://idyl.io 31 | @see https://github.com/tonyp7/esp32-wifi-manager 32 | */ 33 | 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include "esp_netif.h" 44 | #include 45 | 46 | #include "wifi_manager.h" 47 | #include "http_app.h" 48 | 49 | 50 | /* @brief tag used for ESP serial console messages */ 51 | static const char TAG[] = "http_server"; 52 | 53 | /* @brief the HTTP server handle */ 54 | static httpd_handle_t httpd_handle = NULL; 55 | 56 | /* function pointers to URI handlers that can be user made */ 57 | esp_err_t (*custom_get_httpd_uri_handler)(httpd_req_t *r) = NULL; 58 | esp_err_t (*custom_post_httpd_uri_handler)(httpd_req_t *r) = NULL; 59 | 60 | /* strings holding the URLs of the wifi manager */ 61 | static char* http_root_url = NULL; 62 | static char* http_redirect_url = NULL; 63 | static char* http_js_url = NULL; 64 | static char* http_css_url = NULL; 65 | static char* http_connect_url = NULL; 66 | static char* http_ap_url = NULL; 67 | static char* http_status_url = NULL; 68 | 69 | /** 70 | * @brief embedded binary data. 71 | * @see file "component.mk" 72 | * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data 73 | */ 74 | extern const uint8_t style_css_start[] asm("_binary_style_css_start"); 75 | extern const uint8_t style_css_end[] asm("_binary_style_css_end"); 76 | extern const uint8_t code_js_start[] asm("_binary_code_js_start"); 77 | extern const uint8_t code_js_end[] asm("_binary_code_js_end"); 78 | extern const uint8_t index_html_start[] asm("_binary_index_html_start"); 79 | extern const uint8_t index_html_end[] asm("_binary_index_html_end"); 80 | 81 | 82 | /* const httpd related values stored in ROM */ 83 | const static char http_200_hdr[] = "200 OK"; 84 | const static char http_302_hdr[] = "302 Found"; 85 | const static char http_400_hdr[] = "400 Bad Request"; 86 | const static char http_404_hdr[] = "404 Not Found"; 87 | const static char http_503_hdr[] = "503 Service Unavailable"; 88 | const static char http_location_hdr[] = "Location"; 89 | const static char http_content_type_html[] = "text/html"; 90 | const static char http_content_type_js[] = "text/javascript"; 91 | const static char http_content_type_css[] = "text/css"; 92 | const static char http_content_type_json[] = "application/json"; 93 | const static char http_cache_control_hdr[] = "Cache-Control"; 94 | const static char http_cache_control_no_cache[] = "no-store, no-cache, must-revalidate, max-age=0"; 95 | const static char http_cache_control_cache[] = "public, max-age=31536000"; 96 | const static char http_pragma_hdr[] = "Pragma"; 97 | const static char http_pragma_no_cache[] = "no-cache"; 98 | 99 | 100 | 101 | esp_err_t http_app_set_handler_hook( httpd_method_t method, esp_err_t (*handler)(httpd_req_t *r) ){ 102 | 103 | if(method == HTTP_GET){ 104 | custom_get_httpd_uri_handler = handler; 105 | return ESP_OK; 106 | } 107 | else if(method == HTTP_POST){ 108 | custom_post_httpd_uri_handler = handler; 109 | return ESP_OK; 110 | } 111 | else{ 112 | return ESP_ERR_INVALID_ARG; 113 | } 114 | 115 | } 116 | 117 | 118 | static esp_err_t http_server_delete_handler(httpd_req_t *req){ 119 | 120 | ESP_LOGI(TAG, "DELETE %s", req->uri); 121 | 122 | /* DELETE /connect.json */ 123 | if(strcmp(req->uri, http_connect_url) == 0){ 124 | wifi_manager_disconnect_async(); 125 | 126 | httpd_resp_set_status(req, http_200_hdr); 127 | httpd_resp_set_type(req, http_content_type_json); 128 | httpd_resp_set_hdr(req, http_cache_control_hdr, http_cache_control_no_cache); 129 | httpd_resp_set_hdr(req, http_pragma_hdr, http_pragma_no_cache); 130 | httpd_resp_send(req, NULL, 0); 131 | } 132 | else{ 133 | httpd_resp_set_status(req, http_404_hdr); 134 | httpd_resp_send(req, NULL, 0); 135 | } 136 | 137 | return ESP_OK; 138 | } 139 | 140 | 141 | static esp_err_t http_server_post_handler(httpd_req_t *req){ 142 | 143 | 144 | esp_err_t ret = ESP_OK; 145 | 146 | ESP_LOGI(TAG, "POST %s", req->uri); 147 | 148 | /* POST /connect.json */ 149 | if(strcmp(req->uri, http_connect_url) == 0){ 150 | 151 | 152 | /* buffers for the headers */ 153 | size_t ssid_len = 0, password_len = 0; 154 | char *ssid = NULL, *password = NULL; 155 | 156 | /* len of values provided */ 157 | ssid_len = httpd_req_get_hdr_value_len(req, "X-Custom-ssid"); 158 | password_len = httpd_req_get_hdr_value_len(req, "X-Custom-pwd"); 159 | 160 | 161 | if(ssid_len && ssid_len <= MAX_SSID_SIZE && password_len && password_len <= MAX_PASSWORD_SIZE){ 162 | 163 | /* get the actual value of the headers */ 164 | ssid = malloc(sizeof(char) * (ssid_len + 1)); 165 | password = malloc(sizeof(char) * (password_len + 1)); 166 | httpd_req_get_hdr_value_str(req, "X-Custom-ssid", ssid, ssid_len+1); 167 | httpd_req_get_hdr_value_str(req, "X-Custom-pwd", password, password_len+1); 168 | 169 | wifi_config_t* config = wifi_manager_get_wifi_sta_config(); 170 | memset(config, 0x00, sizeof(wifi_config_t)); 171 | memcpy(config->sta.ssid, ssid, ssid_len); 172 | memcpy(config->sta.password, password, password_len); 173 | ESP_LOGI(TAG, "ssid: %s, password: %s", ssid, password); 174 | ESP_LOGD(TAG, "http_server_post_handler: wifi_manager_connect_async() call"); 175 | wifi_manager_connect_async(); 176 | 177 | /* free memory */ 178 | free(ssid); 179 | free(password); 180 | 181 | httpd_resp_set_status(req, http_200_hdr); 182 | httpd_resp_set_type(req, http_content_type_json); 183 | httpd_resp_set_hdr(req, http_cache_control_hdr, http_cache_control_no_cache); 184 | httpd_resp_set_hdr(req, http_pragma_hdr, http_pragma_no_cache); 185 | httpd_resp_send(req, NULL, 0); 186 | 187 | } 188 | else{ 189 | /* bad request the authentification header is not complete/not the correct format */ 190 | httpd_resp_set_status(req, http_400_hdr); 191 | httpd_resp_send(req, NULL, 0); 192 | } 193 | 194 | } 195 | else{ 196 | 197 | if(custom_post_httpd_uri_handler == NULL){ 198 | httpd_resp_set_status(req, http_404_hdr); 199 | httpd_resp_send(req, NULL, 0); 200 | } 201 | else{ 202 | 203 | /* if there's a hook, run it */ 204 | ret = (*custom_post_httpd_uri_handler)(req); 205 | } 206 | } 207 | 208 | return ret; 209 | } 210 | 211 | 212 | static esp_err_t http_server_get_handler(httpd_req_t *req){ 213 | 214 | char* host = NULL; 215 | size_t buf_len; 216 | esp_err_t ret = ESP_OK; 217 | 218 | ESP_LOGD(TAG, "GET %s", req->uri); 219 | 220 | /* Get header value string length and allocate memory for length + 1, 221 | * extra byte for null termination */ 222 | buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1; 223 | if (buf_len > 1) { 224 | host = malloc(buf_len); 225 | if(httpd_req_get_hdr_value_str(req, "Host", host, buf_len) != ESP_OK){ 226 | /* if something is wrong we just 0 the whole memory */ 227 | memset(host, 0x00, buf_len); 228 | } 229 | } 230 | 231 | /* determine if Host is from the STA IP address */ 232 | wifi_manager_lock_sta_ip_string(portMAX_DELAY); 233 | bool access_from_sta_ip = host != NULL?strstr(host, wifi_manager_get_sta_ip_string()):false; 234 | wifi_manager_unlock_sta_ip_string(); 235 | 236 | 237 | if (host != NULL && !strstr(host, DEFAULT_AP_IP) && !access_from_sta_ip) { 238 | 239 | /* Captive Portal functionality */ 240 | /* 302 Redirect to IP of the access point */ 241 | httpd_resp_set_status(req, http_302_hdr); 242 | httpd_resp_set_hdr(req, http_location_hdr, http_redirect_url); 243 | httpd_resp_send(req, NULL, 0); 244 | 245 | } 246 | else{ 247 | 248 | /* GET / */ 249 | if(strcmp(req->uri, http_root_url) == 0){ 250 | httpd_resp_set_status(req, http_200_hdr); 251 | httpd_resp_set_type(req, http_content_type_html); 252 | httpd_resp_send(req, (char*)index_html_start, index_html_end - index_html_start); 253 | } 254 | /* GET /code.js */ 255 | else if(strcmp(req->uri, http_js_url) == 0){ 256 | httpd_resp_set_status(req, http_200_hdr); 257 | httpd_resp_set_type(req, http_content_type_js); 258 | httpd_resp_send(req, (char*)code_js_start, code_js_end - code_js_start); 259 | } 260 | /* GET /style.css */ 261 | else if(strcmp(req->uri, http_css_url) == 0){ 262 | httpd_resp_set_status(req, http_200_hdr); 263 | httpd_resp_set_type(req, http_content_type_css); 264 | httpd_resp_set_hdr(req, http_cache_control_hdr, http_cache_control_cache); 265 | httpd_resp_send(req, (char*)style_css_start, style_css_end - style_css_start); 266 | } 267 | /* GET /ap.json */ 268 | else if(strcmp(req->uri, http_ap_url) == 0){ 269 | 270 | /* if we can get the mutex, write the last version of the AP list */ 271 | if(wifi_manager_lock_json_buffer(( TickType_t ) 10)){ 272 | 273 | httpd_resp_set_status(req, http_200_hdr); 274 | httpd_resp_set_type(req, http_content_type_json); 275 | httpd_resp_set_hdr(req, http_cache_control_hdr, http_cache_control_no_cache); 276 | httpd_resp_set_hdr(req, http_pragma_hdr, http_pragma_no_cache); 277 | char* ap_buf = wifi_manager_get_ap_list_json(); 278 | httpd_resp_send(req, ap_buf, strlen(ap_buf)); 279 | wifi_manager_unlock_json_buffer(); 280 | } 281 | else{ 282 | httpd_resp_set_status(req, http_503_hdr); 283 | httpd_resp_send(req, NULL, 0); 284 | ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); 285 | } 286 | 287 | /* request a wifi scan */ 288 | wifi_manager_scan_async(); 289 | } 290 | /* GET /status.json */ 291 | else if(strcmp(req->uri, http_status_url) == 0){ 292 | 293 | if(wifi_manager_lock_json_buffer(( TickType_t ) 10)){ 294 | char *buff = wifi_manager_get_ip_info_json(); 295 | if(buff){ 296 | httpd_resp_set_status(req, http_200_hdr); 297 | httpd_resp_set_type(req, http_content_type_json); 298 | httpd_resp_set_hdr(req, http_cache_control_hdr, http_cache_control_no_cache); 299 | httpd_resp_set_hdr(req, http_pragma_hdr, http_pragma_no_cache); 300 | httpd_resp_send(req, buff, strlen(buff)); 301 | wifi_manager_unlock_json_buffer(); 302 | } 303 | else{ 304 | httpd_resp_set_status(req, http_503_hdr); 305 | httpd_resp_send(req, NULL, 0); 306 | } 307 | } 308 | else{ 309 | httpd_resp_set_status(req, http_503_hdr); 310 | httpd_resp_send(req, NULL, 0); 311 | ESP_LOGE(TAG, "http_server_netconn_serve: GET /status.json failed to obtain mutex"); 312 | } 313 | } 314 | else{ 315 | 316 | if(custom_get_httpd_uri_handler == NULL){ 317 | httpd_resp_set_status(req, http_404_hdr); 318 | httpd_resp_send(req, NULL, 0); 319 | } 320 | else{ 321 | 322 | /* if there's a hook, run it */ 323 | ret = (*custom_get_httpd_uri_handler)(req); 324 | } 325 | } 326 | 327 | } 328 | 329 | /* memory clean up */ 330 | if(host != NULL){ 331 | free(host); 332 | } 333 | 334 | return ret; 335 | 336 | } 337 | 338 | /* URI wild card for any GET request */ 339 | static const httpd_uri_t http_server_get_request = { 340 | .uri = "*", 341 | .method = HTTP_GET, 342 | .handler = http_server_get_handler 343 | }; 344 | 345 | static const httpd_uri_t http_server_post_request = { 346 | .uri = "*", 347 | .method = HTTP_POST, 348 | .handler = http_server_post_handler 349 | }; 350 | 351 | static const httpd_uri_t http_server_delete_request = { 352 | .uri = "*", 353 | .method = HTTP_DELETE, 354 | .handler = http_server_delete_handler 355 | }; 356 | 357 | 358 | void http_app_stop(){ 359 | 360 | if(httpd_handle != NULL){ 361 | 362 | 363 | /* dealloc URLs */ 364 | if(http_root_url) { 365 | free(http_root_url); 366 | http_root_url = NULL; 367 | } 368 | if(http_redirect_url){ 369 | free(http_redirect_url); 370 | http_redirect_url = NULL; 371 | } 372 | if(http_js_url){ 373 | free(http_js_url); 374 | http_js_url = NULL; 375 | } 376 | if(http_css_url){ 377 | free(http_css_url); 378 | http_css_url = NULL; 379 | } 380 | if(http_connect_url){ 381 | free(http_connect_url); 382 | http_connect_url = NULL; 383 | } 384 | if(http_ap_url){ 385 | free(http_ap_url); 386 | http_ap_url = NULL; 387 | } 388 | if(http_status_url){ 389 | free(http_status_url); 390 | http_status_url = NULL; 391 | } 392 | 393 | /* stop server */ 394 | httpd_stop(httpd_handle); 395 | httpd_handle = NULL; 396 | } 397 | } 398 | 399 | 400 | /** 401 | * @brief helper to generate URLs of the wifi manager 402 | */ 403 | static char* http_app_generate_url(const char* page){ 404 | 405 | char* ret; 406 | 407 | int root_len = strlen(WEBAPP_LOCATION); 408 | const size_t url_sz = sizeof(char) * ( (root_len+1) + ( strlen(page) + 1) ); 409 | 410 | ret = malloc(url_sz); 411 | memset(ret, 0x00, url_sz); 412 | strcpy(ret, WEBAPP_LOCATION); 413 | ret = strcat(ret, page); 414 | 415 | return ret; 416 | } 417 | 418 | void http_app_start(bool lru_purge_enable){ 419 | 420 | esp_err_t err; 421 | 422 | if(httpd_handle == NULL){ 423 | 424 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); 425 | 426 | /* this is an important option that isn't set up by default. 427 | * We could register all URLs one by one, but this would not work while the fake DNS is active */ 428 | config.uri_match_fn = httpd_uri_match_wildcard; 429 | config.lru_purge_enable = lru_purge_enable; 430 | 431 | /* generate the URLs */ 432 | if(http_root_url == NULL){ 433 | int root_len = strlen(WEBAPP_LOCATION); 434 | 435 | /* all the pages */ 436 | const char page_js[] = "code.js"; 437 | const char page_css[] = "style.css"; 438 | const char page_connect[] = "connect.json"; 439 | const char page_ap[] = "ap.json"; 440 | const char page_status[] = "status.json"; 441 | 442 | /* root url, eg "/" */ 443 | const size_t http_root_url_sz = sizeof(char) * (root_len+1); 444 | http_root_url = malloc(http_root_url_sz); 445 | memset(http_root_url, 0x00, http_root_url_sz); 446 | strcpy(http_root_url, WEBAPP_LOCATION); 447 | 448 | /* redirect url */ 449 | size_t redirect_sz = 22 + root_len + 1; /* strlen(http://255.255.255.255) + strlen("/") + 1 for \0 */ 450 | http_redirect_url = malloc(sizeof(char) * redirect_sz); 451 | *http_redirect_url = '\0'; 452 | 453 | if(root_len == 1){ 454 | snprintf(http_redirect_url, redirect_sz, "http://%s", DEFAULT_AP_IP); 455 | } 456 | else{ 457 | snprintf(http_redirect_url, redirect_sz, "http://%s%s", DEFAULT_AP_IP, WEBAPP_LOCATION); 458 | } 459 | 460 | /* generate the other pages URLs*/ 461 | http_js_url = http_app_generate_url(page_js); 462 | http_css_url = http_app_generate_url(page_css); 463 | http_connect_url = http_app_generate_url(page_connect); 464 | http_ap_url = http_app_generate_url(page_ap); 465 | http_status_url = http_app_generate_url(page_status); 466 | 467 | } 468 | 469 | err = httpd_start(&httpd_handle, &config); 470 | 471 | if (err == ESP_OK) { 472 | ESP_LOGI(TAG, "Registering URI handlers"); 473 | httpd_register_uri_handler(httpd_handle, &http_server_get_request); 474 | httpd_register_uri_handler(httpd_handle, &http_server_post_request); 475 | httpd_register_uri_handler(httpd_handle, &http_server_delete_request); 476 | } 477 | } 478 | 479 | } 480 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "driver/uart.h" 5 | #include "freertos/FreeRTOS.h" 6 | #include "freertos/task.h" 7 | #include "freertos/queue.h" 8 | #include "esp_system.h" 9 | #include "esp_log.h" 10 | #include "driver/gpio.h" 11 | #include "wifi_manager.h" 12 | #include "http_app.h" 13 | 14 | #include "mqtt_client.h" 15 | 16 | const esp_mqtt_client_config_t mqtt_cfg = { 17 | .uri = "mqtt://192.168.1.24:1883", 18 | .username = "hauser", 19 | .password = "l3mm3IN", 20 | .lwt_topic = "homeassistant/switch/pool/active", 21 | .lwt_msg = "offline", 22 | .lwt_msg_len = 7, 23 | .lwt_qos = 0, 24 | .lwt_retain = true}; 25 | esp_mqtt_client_handle_t client; 26 | 27 | #define COMMAND_BLINK_GPIO 5 28 | #define MQTT_BLINK_GPIO 18 29 | #define HTTP_BLINK_GPIO 19 30 | 31 | #define MQTT_LOOP_STACK_SIZE (2048) 32 | #define MQTT_LOOP_PRIO (11) 33 | 34 | #define COMMAND(X) X "/set" 35 | #define CONFIG(X) X "/config" 36 | #define STATE(X) X "/state" 37 | #define STATUS(X) X "/status" 38 | 39 | #define MQTT_QOS 0 40 | #define MQTT_RETAIN 0 41 | #define MQTT_HA_DISCOVERY_QOS 0 42 | #define MQTT_HA_DISCOVERY_RETAIN 1 43 | #define MQTT_HASSIO_STATUS_TOPIC "homeassistant/status" 44 | #define MQTT_POOL_TEMPERATURE_TOPIC "homeassistant/sensor/pool/pool_temperature" 45 | #define MQTT_AIR_TEMPERATURE_TOPIC "homeassistant/sensor/pool/air_temperature" 46 | #define MQTT_SPA_TOPIC "homeassistant/switch/pool/spa" 47 | #define MQTT_POOL_CLEANER_TOPIC "homeassistant/switch/pool/cleaner" 48 | #define MQTT_AIR_BLOWER_TOPIC "homeassistant/switch/pool/air_blower" 49 | #define MQTT_SPA_LIGHT_TOPIC "homeassistant/switch/pool/spa_light" 50 | #define MQTT_POOL_LIGHT_TOPIC "homeassistant/switch/pool/pool_light" 51 | #define MQTT_POOL_TOPIC "homeassistant/switch/pool/pool" 52 | #define MQTT_WATER_FEATURE1_TOPIC "homeassistant/switch/pool/water_feature1" 53 | #define MQTT_SPILLWAY_TOPIC "homeassistant/switch/pool/spillway" 54 | 55 | #define SPA_STATE(x) (x >> 0) & 1 56 | #define CLEANER_STATE(x) (x >> 1) & 1 57 | #define AIR_BLOWER_STATE(x) (x >> 2) & 1 58 | #define SPA_LIGHT_STATE(x) (x >> 3) & 1 59 | #define POOL_LIGHT_STATE(x) (x >> 4) & 1 60 | #define PUMP1_STATE(x) (x >> 5) & 1 61 | #define WATER_FEATURE1_STATE(x) (x >> 6) & 1 62 | #define SPILLWAY_STATE(x) (x >> 7) & 1 63 | 64 | // Note: UART2 default pins IO16, IO17 do not work on ESP32-WROVER module 65 | // because these pins connected to PSRAM 66 | #define ECHO_TEST_TXD (17) 67 | #define ECHO_TEST_RXD (16) 68 | 69 | // RTS for RS485 Half-Duplex Mode manages DE/~RE 70 | #define ECHO_TEST_RTS (4) 71 | 72 | // CTS is not used in RS485 Half-Duplex Mode 73 | #define ECHO_TEST_CTS UART_PIN_NO_CHANGE 74 | 75 | #define BUF_SIZE (127) 76 | #define BAUD_RATE (9600) 77 | 78 | // Read packet timeout 79 | #define PACKET_READ_TICS (100 / portTICK_RATE_MS) 80 | #define READ_RS485_STACK_SIZE (2048) 81 | #define READ_RS485_PRIO (10) 82 | #define ECHO_UART_PORT (UART_NUM_2) 83 | 84 | static const char *TAG = "RS485_PENTAIR_CONTROLLER"; 85 | 86 | const uint8_t packet_header = 0xA5; 87 | const int uart_num = ECHO_UART_PORT; 88 | 89 | SemaphoreHandle_t semMainStatus = NULL; 90 | 91 | typedef struct 92 | { 93 | uint8_t hour; // 6 94 | uint8_t minute; // 7 95 | uint8_t equip1; // 8 96 | uint8_t equip2; // 9 97 | uint8_t equip3; // 10 98 | uint8_t reserved1; // 11 99 | uint8_t reserved2; // 12 100 | uint8_t reserved3; // 13 101 | uint8_t reserved4; // 14 102 | uint8_t uom; // 15 - 0 == Fahrenheit, 4 == celsius 103 | uint8_t valve; // 16 104 | uint8_t reserved5; // 17 105 | uint8_t delay; // 18 - 64==??; 65-135 (for 50 circuits) is the circuit that is currently delayed. 106 | uint8_t unknown; // 19 - Something to do with heat. 107 | uint8_t pool_temp; // 20 108 | uint8_t spa_temp; // 21 109 | uint8_t heater_active; // 22 - 0=off. 32=on. More here? 110 | uint8_t reserved6; // 23 111 | uint8_t air_temp; // 24 112 | uint8_t solar_temp; // 25 113 | uint8_t reserved7; // 26 114 | uint8_t reserved8; // 27 115 | uint8_t heater_mode; // 28 116 | uint8_t reserved9; // 29 117 | uint8_t reserved10; // 30 118 | uint8_t reserved11; // 31 119 | uint8_t misc2; // 32 - 0=do not automatically adjust DST, 1=automatically adjust DST 120 | } MAIN_STATUS_PACKET; 121 | 122 | typedef struct __attribute__((packed, scalar_storage_order("big-endian"))) 123 | { 124 | uint8_t started; // 6 125 | uint8_t feature1; // 7 126 | uint8_t drive_state; // 8 127 | uint16_t watts; // 9 128 | uint16_t rpm; // 11 129 | uint8_t gpm; // 12 130 | uint8_t percent; // 13 131 | uint8_t unknown1; // 14 132 | uint8_t err; // 15 133 | uint8_t unknown2; //16 134 | uint8_t timer; // 17 135 | uint16_t clk; // 18 136 | } PUMP_STATUS_PACKET; 137 | 138 | typedef enum 139 | { 140 | CHLORINATOR = 0x02, 141 | BROADCAST = 0x0f, 142 | MAIN = 0x10, 143 | SECONDARY = 0x11, 144 | REMOTE = 0x20, 145 | PUMP1 = 0x60, 146 | PUMP2 = 0x61, 147 | PUMP3 = 0x62, 148 | PUMP4 = 0x63 149 | } DEVICE; 150 | 151 | typedef enum 152 | { 153 | UNKNOWN = 0, 154 | SPA = 1, 155 | CLEANER = 2, 156 | AIR_BLOWER = 3, 157 | SPA_LIGHT = 4, 158 | POOL_LIGHT = 5, 159 | POOL = 6, 160 | WATER_FEATURE = 7, 161 | SPILLWAY = 8, 162 | AUX = 9 163 | } FEATURE; 164 | 165 | // define the Pentair RS485 packet struct 166 | typedef struct 167 | { 168 | uint8_t leading_byte; 169 | uint8_t unknown; 170 | DEVICE dest; 171 | DEVICE src; 172 | uint8_t command; 173 | uint8_t length; 174 | uint8_t *data; 175 | uint16_t checksum; 176 | } Packet; 177 | 178 | typedef enum 179 | { 180 | SET_COLOR = 96, 181 | SET_CIRCUIT = 134 182 | } COMMAND; 183 | 184 | char *getDeviceName(DEVICE device) 185 | { 186 | switch (device) 187 | { 188 | case CHLORINATOR: 189 | return "Chlorinator"; 190 | case BROADCAST: 191 | return "Broadcast"; 192 | case MAIN: 193 | return "Main"; 194 | case SECONDARY: 195 | return "Secondary"; 196 | case REMOTE: 197 | return "Remote"; 198 | case PUMP1: 199 | return "Pump1"; 200 | case PUMP2: 201 | return "Pump2"; 202 | case PUMP3: 203 | return "Pump3"; 204 | case PUMP4: 205 | return "Pump4"; 206 | default: 207 | return "Unknown"; 208 | } 209 | } 210 | 211 | MAIN_STATUS_PACKET *main_status; 212 | PUMP_STATUS_PACKET *pump_status; 213 | bool mqtt_connected = false; 214 | 215 | // Get a string state status from an int 216 | static char *str_state(int state) 217 | { 218 | return state ? "on" : "off"; 219 | } 220 | 221 | // The prometheus /metrics handler 222 | static esp_err_t http_get_handler(httpd_req_t *req) 223 | { 224 | char response[700]; 225 | ESP_LOGI(TAG, "GET %s\n", req->uri); 226 | gpio_set_level(HTTP_BLINK_GPIO, 1); 227 | if (strcmp(req->uri, "/metrics") == 0) 228 | { 229 | // take the packet semaphore 230 | xSemaphoreTake(semMainStatus, portMAX_DELAY); 231 | if (main_status == NULL) 232 | { 233 | gpio_set_level(HTTP_BLINK_GPIO, 0); 234 | httpd_resp_send_500(req); 235 | } 236 | else 237 | { 238 | ESP_LOGI(TAG, "Serving page /metrics"); 239 | sprintf(response, "# HELP pool_air_temperature (F)\n" 240 | "# TYPE pool_air_temperature gauge\n" 241 | "pool_air_temperature %d\n" 242 | "# HELP pool_water_temperature (F)\n" 243 | "# TYPE pool_water_temperature gauge\n" 244 | "pool_water_temperature %d\n" 245 | "# HELP pool_pool_status\n" 246 | "# TYPE pool_pool_status gauge\n" 247 | "pool_pool_status %d\n" 248 | "# HELP pool_spa_status\n" 249 | "# TYPE pool_spa_status gauge\n" 250 | "pool_spa_status %d\n" 251 | "# HELP pool_cleaner_status\n" 252 | "# TYPE pool_cleaner_status gauge\n" 253 | "pool_cleaner_status %d\n" 254 | "# HELP pool_air_blower_status\n" 255 | "# TYPE pool_air_blower_status gauge\n" 256 | "pool_air_blower_status %d\n" 257 | "# HELP pool_spa_light_status\n" 258 | "# TYPE pool_spa_light_status gauge\n" 259 | "pool_spa_light_status %d\n" 260 | "# HELP pool_light_status\n" 261 | "# TYPE pool_light_status gauge\n" 262 | "pool_light_status %d\n", 263 | main_status->air_temp, 264 | main_status->pool_temp, 265 | PUMP1_STATE(main_status->equip1), 266 | SPA_STATE(main_status->equip1), 267 | CLEANER_STATE(main_status->equip1), 268 | AIR_BLOWER_STATE(main_status->equip1), 269 | SPA_LIGHT_STATE(main_status->equip1), 270 | POOL_LIGHT_STATE(main_status->equip1)); 271 | 272 | httpd_resp_set_status(req, "200 OK"); 273 | httpd_resp_set_type(req, "text/plain"); 274 | gpio_set_level(HTTP_BLINK_GPIO, 0); 275 | httpd_resp_send(req, response, strlen(response)); 276 | } 277 | xSemaphoreGive(semMainStatus); 278 | } 279 | else 280 | { 281 | gpio_set_level(HTTP_BLINK_GPIO, 0); 282 | /* send a 404 otherwise */ 283 | httpd_resp_send_404(req); 284 | } 285 | 286 | return ESP_OK; 287 | } 288 | 289 | static void sendCommand(DEVICE from, DEVICE to, COMMAND command, uint8_t feature, uint8_t state) 290 | { 291 | int res; 292 | gpio_set_level(COMMAND_BLINK_GPIO, 1); 293 | ESP_LOGI(TAG, "Sending command from=%02x to=%02x command=%02x feature=%02x state=%02x", from, to, command, feature, state); 294 | uint8_t cmd_packet[12] = {0x00, 0xFF, 0xA5, 0x1F, to, from, command, 2, feature, state}; 295 | uint16_t checksum = 0; 296 | for (int i = 2; i < 12; i++) 297 | checksum += cmd_packet[i]; 298 | cmd_packet[10] = checksum / 256; 299 | cmd_packet[11] = checksum % 256; 300 | for (int i = 0; i < 12; i++) 301 | { 302 | printf("%02x ", cmd_packet[i]); 303 | } 304 | res = uart_write_bytes(uart_num, (char *)&cmd_packet, 12); 305 | vTaskDelay(50); 306 | ESP_LOGI(TAG, "%d", res); 307 | gpio_set_level(COMMAND_BLINK_GPIO, 0); 308 | } 309 | 310 | static void readRS485() 311 | { 312 | Packet packet; 313 | uart_config_t uart_config = { 314 | .baud_rate = BAUD_RATE, 315 | .data_bits = UART_DATA_8_BITS, 316 | .parity = UART_PARITY_DISABLE, 317 | .stop_bits = UART_STOP_BITS_1, 318 | .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, 319 | .rx_flow_ctrl_thresh = 122, 320 | }; 321 | 322 | // Set UART log level 323 | esp_log_level_set(TAG, ESP_LOG_DEBUG); 324 | 325 | ESP_LOGI(TAG, "Start RS485 application and configure UART."); 326 | 327 | // Configure UART parameters 328 | uart_param_config(uart_num, &uart_config); 329 | 330 | ESP_LOGI(TAG, "UART set pins, mode and install driver."); 331 | // Set UART1 pins(TX: IO23, RX: I022, RTS: IO18, CTS: IO19) 332 | uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS); 333 | 334 | // Install UART driver (we don't need an event queue here) 335 | // In this example we don't even use a buffer for sending data. 336 | uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0); 337 | 338 | // Set RS485 half duplex mode 339 | uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX); 340 | 341 | // Allocate buffers for UART 342 | uint8_t *data = (uint8_t *)malloc(BUF_SIZE); 343 | char mqtt_data[20]; 344 | uint16_t checksum; 345 | int start; 346 | 347 | ESP_LOGI(TAG, "UART start recieve loop.\r\n"); 348 | while (1) 349 | { 350 | int len = uart_read_bytes(uart_num, data, BUF_SIZE, pdMS_TO_TICKS(100)); 351 | if (len > 0) 352 | { 353 | gpio_set_level(MQTT_BLINK_GPIO, 1); 354 | ESP_LOGI(TAG, "Received %u bytes:", len); 355 | for (int i = 0; i < len; i++) 356 | { 357 | if (data[i] == 0xFF && data[i + 1] == 0x00 && data[i + 2] == 0xFF && data[i + 3] == 0xA5) 358 | { 359 | ESP_LOGI(TAG, "Found header start at offset %d", i); 360 | start = i + 3; 361 | i = len; // make sure we're done with the loop 362 | memset(&packet, 0, sizeof(packet)); 363 | packet.leading_byte = data[start]; 364 | packet.unknown = data[start + 1]; 365 | packet.dest = data[start + 2]; 366 | packet.src = data[start + 3]; 367 | packet.command = data[start + 4]; 368 | packet.length = data[start + 5]; 369 | packet.data = &data[start + 6]; 370 | packet.checksum = (data[start + 6 + packet.length] << 8) + data[start + 7 + packet.length]; 371 | // calculate the checksum 372 | checksum = 0; 373 | for (int j = start; j < start + packet.length + 6; j++) 374 | { 375 | checksum = checksum + data[j]; 376 | } 377 | if (checksum != packet.checksum) 378 | ESP_LOGI(TAG, "\nCHECKSUM MISMATCH - got %d, expected %d\n", checksum, packet.checksum); 379 | else 380 | { // checksum is good - decode the packet 381 | ESP_LOGI(TAG, "Source : (0x%02x) %s", packet.src, getDeviceName(packet.src)); 382 | ESP_LOGI(TAG, "Dest : (0x%02x) %s", packet.dest, getDeviceName(packet.dest)); 383 | ESP_LOGI(TAG, "Command : (0x%02x) %d\n", packet.command, packet.command); 384 | 385 | if (packet.src == MAIN && packet.dest == BROADCAST && packet.command == 0x02) 386 | { 387 | xSemaphoreTake(semMainStatus, portMAX_DELAY); 388 | memcpy(main_status, packet.data, sizeof(MAIN_STATUS_PACKET)); 389 | xSemaphoreGive(semMainStatus); 390 | //main_status = (MAIN_STATUS_PACKET *)packet.data; 391 | ESP_LOGI(TAG, "Time: %d:%d", main_status->hour, main_status->minute); 392 | ESP_LOGI(TAG, "Pump1: %s", str_state(PUMP1_STATE(main_status->equip1))); 393 | ESP_LOGI(TAG, "Cleaner: %s", str_state(CLEANER_STATE(main_status->equip1))); 394 | ESP_LOGI(TAG, "Air Blower: %s", str_state(AIR_BLOWER_STATE(main_status->equip1))); 395 | ESP_LOGI(TAG, "Pool temp: %d", main_status->pool_temp); 396 | ESP_LOGI(TAG, "Spa temp: %d", main_status->spa_temp); 397 | ESP_LOGI(TAG, "Air temp: %d", main_status->air_temp); 398 | ESP_LOGI(TAG, "Heater: %d", main_status->heater_active); 399 | ESP_LOGI(TAG, "Heater mode: %d", main_status->heater_mode); 400 | ESP_LOGI(TAG, "Unknown: %d", main_status->unknown); 401 | ESP_LOGI(TAG, "Spa: %s", str_state(SPA_STATE(main_status->equip1))); 402 | ESP_LOGI(TAG, "Pool light: %s", str_state(POOL_LIGHT_STATE(main_status->equip1))); 403 | ESP_LOGI(TAG, "Spa light: %s\n", str_state(SPA_LIGHT_STATE(main_status->equip1))); 404 | 405 | // send the info to the mqtt broker 406 | if (mqtt_connected) 407 | { 408 | // TODO - don't send updates if values haven't changed 409 | sprintf(mqtt_data, "%d", main_status->pool_temp); 410 | esp_mqtt_client_publish(client, STATE(MQTT_POOL_TEMPERATURE_TOPIC), mqtt_data, 0, MQTT_QOS, MQTT_RETAIN); 411 | sprintf(mqtt_data, "%d", main_status->air_temp); 412 | esp_mqtt_client_publish(client, STATE(MQTT_AIR_TEMPERATURE_TOPIC), mqtt_data, 0, MQTT_QOS, MQTT_RETAIN); 413 | esp_mqtt_client_publish(client, STATE(MQTT_SPA_TOPIC), str_state(SPA_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 414 | esp_mqtt_client_publish(client, STATE(MQTT_POOL_CLEANER_TOPIC), str_state(CLEANER_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 415 | esp_mqtt_client_publish(client, STATE(MQTT_AIR_BLOWER_TOPIC), str_state(AIR_BLOWER_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 416 | esp_mqtt_client_publish(client, STATE(MQTT_SPA_TOPIC), str_state(SPA_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 417 | esp_mqtt_client_publish(client, STATE(MQTT_POOL_LIGHT_TOPIC), str_state(POOL_LIGHT_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 418 | esp_mqtt_client_publish(client, STATE(MQTT_SPA_LIGHT_TOPIC), str_state(SPA_LIGHT_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 419 | esp_mqtt_client_publish(client, STATE(MQTT_POOL_TOPIC), str_state(PUMP1_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 420 | esp_mqtt_client_publish(client, STATE(MQTT_WATER_FEATURE1_TOPIC), str_state(WATER_FEATURE1_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 421 | esp_mqtt_client_publish(client, STATE(MQTT_SPILLWAY_TOPIC), str_state(SPILLWAY_STATE(main_status->equip1)), 0, MQTT_QOS, MQTT_RETAIN); 422 | } 423 | } 424 | else if ((packet.src == PUMP1 || packet.src == PUMP2 || packet.src == PUMP3 || packet.src == PUMP4) && packet.dest == MAIN) 425 | { 426 | // we have a pump status packet 427 | // TODO - add this info to mqtt 428 | pump_status = (PUMP_STATUS_PACKET *)packet.data; 429 | ESP_LOGI(TAG, "Watts: %d", pump_status->watts); 430 | ESP_LOGI(TAG, "RPMs: %d", pump_status->rpm); 431 | } 432 | break; 433 | } 434 | i = i + packet.length; 435 | } 436 | } 437 | } 438 | gpio_set_level(MQTT_BLINK_GPIO, 0); 439 | vTaskDelay(pdMS_TO_TICKS(250)); 440 | } 441 | } 442 | 443 | static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) 444 | { 445 | esp_mqtt_client_handle_t client = event->client; 446 | uint8_t feature; 447 | switch (event->event_id) 448 | { 449 | case MQTT_EVENT_CONNECTED: 450 | ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); 451 | // configure the state subscription topics 452 | esp_mqtt_client_subscribe(client, MQTT_HASSIO_STATUS_TOPIC, 0); 453 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_POOL_TOPIC), 0); 454 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_SPA_TOPIC), 0); 455 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_POOL_CLEANER_TOPIC), 0); 456 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_POOL_LIGHT_TOPIC), 0); 457 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_SPA_LIGHT_TOPIC), 0); 458 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_AIR_BLOWER_TOPIC), 0); 459 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_WATER_FEATURE1_TOPIC), 0); 460 | esp_mqtt_client_subscribe(client, COMMAND(MQTT_SPILLWAY_TOPIC), 0); 461 | 462 | // configure the discovery topics 463 | esp_mqtt_client_publish(client, CONFIG(MQTT_POOL_TOPIC), "{\"unique_id\": \"pool_pool\", \"name\": \"Pool: Pool\", \"state_topic\": \"homeassistant/switch/pool/pool/state\", \"command_topic\": \"homeassistant/switch/pool/pool/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 464 | esp_mqtt_client_publish(client, CONFIG(MQTT_SPA_TOPIC), "{\"unique_id\": \"pool_spa\", \"name\": \"Pool: Spa\", \"state_topic\": \"homeassistant/switch/pool/spa/state\", \"command_topic\": \"homeassistant/switch/pool/spa/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 465 | esp_mqtt_client_publish(client, CONFIG(MQTT_POOL_LIGHT_TOPIC), "{\"unique_id\": \"pool_pool_light\", \"name\": \"Pool: Pool Light\", \"state_topic\": \"homeassistant/switch/pool/pool_light/state\", \"command_topic\": \"homeassistant/switch/pool/pool_light/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 466 | esp_mqtt_client_publish(client, CONFIG(MQTT_SPA_LIGHT_TOPIC), "{\"unique_id\": \"pool_spa_light\", \"name\": \"Pool: Spa Light\", \"state_topic\": \"homeassistant/switch/pool/spa_light/state\", \"command_topic\": \"homeassistant/switch/pool/spa_light/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 467 | esp_mqtt_client_publish(client, CONFIG(MQTT_AIR_BLOWER_TOPIC), "{\"unique_id\": \"pool_spa_air_blower\", \"name\": \"Pool: Air Blower\", \"state_topic\": \"homeassistant/switch/pool/air_blower/state\", \"command_topic\": \"homeassistant/switch/pool/air_blower/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 468 | esp_mqtt_client_publish(client, CONFIG(MQTT_POOL_CLEANER_TOPIC), "{\"unique_id\": \"pool_cleaner\", \"name\": \"Pool: Pool Cleaner\", \"state_topic\": \"homeassistant/switch/pool/cleaner/state\", \"command_topic\": \"homeassistant/switch/pool/cleaner/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 469 | esp_mqtt_client_publish(client, CONFIG(MQTT_WATER_FEATURE1_TOPIC), "{\"unique_id\": \"pool_water_feature1\", \"name\": \"Pool: Water Feature 1\", \"state_topic\": \"homeassistant/switch/pool/water_feature1/state\", \"command_topic\": \"homeassistant/switch/pool/water_feature1/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 470 | esp_mqtt_client_publish(client, CONFIG(MQTT_SPILLWAY_TOPIC), "{\"unique_id\": \"pool_spillway\", \"name\": \"Pool: Spillway\", \"state_topic\": \"homeassistant/switch/pool/spillway/state\", \"command_topic\": \"homeassistant/switch/pool/spillway/set\", \"state_on\": \"on\", \"state_off\": \"off\", \"payload_on\": \"on\", \"payload_off\": \"off\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 471 | esp_mqtt_client_publish(client, CONFIG(MQTT_POOL_TEMPERATURE_TOPIC), "{\"unique_id\": \"pool_pool_temperature\", \"name\": \"Pool: Pool Temperature\", \"device_class\": \"temperature\", \"state_topic\": \"homeassistant/sensor/pool/pool_temperature/state\", \"unit_of_measurement\": \"°F\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 472 | esp_mqtt_client_publish(client, CONFIG(MQTT_AIR_TEMPERATURE_TOPIC), "{\"unique_id\": \"pool_air_temperature\", \"name\": \"Pool: Air Temperature\", \"device_class\": \"temperature\", \"state_topic\": \"homeassistant/sensor/pool/air_temperature/state\", \"unit_of_measurement\": \"°F\"}", 0, MQTT_HA_DISCOVERY_QOS, MQTT_HA_DISCOVERY_RETAIN); 473 | mqtt_connected = true; 474 | break; 475 | 476 | case MQTT_EVENT_DISCONNECTED: 477 | ESP_LOGD(TAG, "MQTT_EVENT_DISCONNECTED"); 478 | mqtt_connected = false; 479 | break; 480 | 481 | case MQTT_EVENT_SUBSCRIBED: 482 | ESP_LOGD(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); 483 | break; 484 | 485 | case MQTT_EVENT_UNSUBSCRIBED: 486 | ESP_LOGD(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); 487 | break; 488 | 489 | case MQTT_EVENT_PUBLISHED: 490 | ESP_LOGD(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); 491 | break; 492 | 493 | case MQTT_EVENT_DATA: 494 | if (!mqtt_connected) 495 | break; 496 | ESP_LOGI(TAG, "MQTT_EVENT_DATA"); 497 | ESP_LOGI(TAG, "TOPIC='%.*s'\r\n", event->topic_len, event->topic); 498 | ESP_LOGI(TAG, "DATA='%.*s'\r\n", event->data_len, event->data); 499 | feature = UNKNOWN; 500 | if (strncmp(event->topic, COMMAND(MQTT_POOL_TOPIC), event->topic_len) == 0) 501 | feature = POOL; 502 | else if (strncmp(event->topic, COMMAND(MQTT_SPA_TOPIC), event->topic_len) == 0) 503 | feature = SPA; 504 | else if (strncmp(event->topic, COMMAND(MQTT_POOL_LIGHT_TOPIC), event->topic_len) == 0) 505 | feature = POOL_LIGHT; 506 | else if (strncmp(event->topic, COMMAND(MQTT_SPA_LIGHT_TOPIC), event->topic_len) == 0) 507 | feature = SPA_LIGHT; 508 | else if (strncmp(event->topic, COMMAND(MQTT_POOL_CLEANER_TOPIC), event->topic_len) == 0) 509 | feature = CLEANER; 510 | else if (strncmp(event->topic, COMMAND(MQTT_AIR_BLOWER_TOPIC), event->topic_len) == 0) 511 | feature = AIR_BLOWER; 512 | else if (strncmp(event->topic, COMMAND(MQTT_WATER_FEATURE1_TOPIC), event->topic_len) == 0) 513 | feature = WATER_FEATURE; 514 | else if (strncmp(event->topic, COMMAND(MQTT_SPILLWAY_TOPIC), event->topic_len) == 0) 515 | feature = SPILLWAY; 516 | else 517 | { 518 | ESP_LOGE(TAG, "Unknown feature topic %s", event->topic); 519 | break; 520 | } 521 | 522 | if (strncmp(event->data, "on", event->data_len) == 0) 523 | { 524 | ESP_LOGI(TAG, "Switching feature %02x ON **********************", feature); 525 | sendCommand(REMOTE, MAIN, SET_CIRCUIT, feature, 1); 526 | } 527 | else if (strncmp(event->data, "off", event->data_len) == 0) 528 | { 529 | ESP_LOGI(TAG, "Switching feature %02x OFF *********************", feature); 530 | sendCommand(REMOTE, MAIN, SET_CIRCUIT, feature, 0); 531 | } 532 | 533 | break; 534 | case MQTT_EVENT_ERROR: 535 | ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); 536 | break; 537 | default: 538 | ESP_LOGI(TAG, "Other event id:%d", event->event_id); 539 | break; 540 | } 541 | return ESP_OK; 542 | } 543 | 544 | static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) 545 | { 546 | mqtt_event_handler_cb(event_data); 547 | } 548 | 549 | static void mqttLoop() 550 | { 551 | const TickType_t xDelay = 500 / portTICK_PERIOD_MS; 552 | // init mqtt 553 | client = esp_mqtt_client_init(&mqtt_cfg); 554 | esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client); 555 | esp_mqtt_client_start(client); 556 | while (1) 557 | { 558 | vTaskDelay(xDelay); 559 | } 560 | } 561 | 562 | void app_main() 563 | { 564 | main_status = malloc(sizeof(MAIN_STATUS_PACKET)); 565 | semMainStatus = xSemaphoreCreateMutex(); 566 | gpio_reset_pin(MQTT_BLINK_GPIO); 567 | gpio_set_direction(MQTT_BLINK_GPIO, GPIO_MODE_OUTPUT); 568 | gpio_reset_pin(COMMAND_BLINK_GPIO); 569 | gpio_set_direction(COMMAND_BLINK_GPIO, GPIO_MODE_OUTPUT); 570 | gpio_reset_pin(HTTP_BLINK_GPIO); 571 | gpio_set_direction(HTTP_BLINK_GPIO, GPIO_MODE_OUTPUT); 572 | 573 | /* start the wifi manager */ 574 | wifi_manager_start(); 575 | 576 | // set /metrics handler for prometheus stats 577 | http_app_set_handler_hook(HTTP_GET, &http_get_handler); 578 | 579 | //create the rs485 reader task 580 | xTaskCreate(readRS485, "readRS485", READ_RS485_STACK_SIZE, NULL, READ_RS485_PRIO, NULL); 581 | 582 | // create the mqtt reader/writer task 583 | xTaskCreate(mqttLoop, "mqttLoop", MQTT_LOOP_STACK_SIZE, NULL, MQTT_LOOP_PRIO, NULL); 584 | } 585 | -------------------------------------------------------------------------------- /sdkconfig: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file. DO NOT EDIT. 3 | # Espressif IoT Development Framework (ESP-IDF) Project Configuration 4 | # 5 | CONFIG_IDF_CMAKE=y 6 | CONFIG_IDF_TARGET="esp32" 7 | CONFIG_IDF_TARGET_ESP32=y 8 | CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 9 | 10 | # 11 | # SDK tool configuration 12 | # 13 | CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-" 14 | # CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set 15 | # end of SDK tool configuration 16 | 17 | # 18 | # Build type 19 | # 20 | CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y 21 | # CONFIG_APP_BUILD_TYPE_ELF_RAM is not set 22 | CONFIG_APP_BUILD_GENERATE_BINARIES=y 23 | CONFIG_APP_BUILD_BOOTLOADER=y 24 | CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y 25 | # end of Build type 26 | 27 | # 28 | # Application manager 29 | # 30 | CONFIG_APP_COMPILE_TIME_DATE=y 31 | # CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set 32 | # CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set 33 | # CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set 34 | CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 35 | # end of Application manager 36 | 37 | # 38 | # Bootloader config 39 | # 40 | CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y 41 | # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set 42 | # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set 43 | # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set 44 | # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set 45 | # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set 46 | # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set 47 | CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y 48 | # CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set 49 | # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set 50 | CONFIG_BOOTLOADER_LOG_LEVEL=3 51 | # CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set 52 | CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y 53 | # CONFIG_BOOTLOADER_FACTORY_RESET is not set 54 | # CONFIG_BOOTLOADER_APP_TEST is not set 55 | CONFIG_BOOTLOADER_WDT_ENABLE=y 56 | # CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set 57 | CONFIG_BOOTLOADER_WDT_TIME_MS=9000 58 | # CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set 59 | # CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set 60 | CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 61 | # CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set 62 | # end of Bootloader config 63 | 64 | # 65 | # Security features 66 | # 67 | # CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set 68 | # CONFIG_SECURE_BOOT is not set 69 | # CONFIG_SECURE_FLASH_ENC_ENABLED is not set 70 | # end of Security features 71 | 72 | # 73 | # Serial flasher config 74 | # 75 | CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 76 | CONFIG_ESPTOOLPY_WITH_STUB=y 77 | # CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set 78 | # CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set 79 | CONFIG_ESPTOOLPY_FLASHMODE_DIO=y 80 | # CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set 81 | CONFIG_ESPTOOLPY_FLASHMODE="dio" 82 | # CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set 83 | CONFIG_ESPTOOLPY_FLASHFREQ_40M=y 84 | # CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set 85 | # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set 86 | CONFIG_ESPTOOLPY_FLASHFREQ="40m" 87 | # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set 88 | CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y 89 | # CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set 90 | # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set 91 | # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set 92 | CONFIG_ESPTOOLPY_FLASHSIZE="2MB" 93 | CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y 94 | CONFIG_ESPTOOLPY_BEFORE_RESET=y 95 | # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set 96 | CONFIG_ESPTOOLPY_BEFORE="default_reset" 97 | CONFIG_ESPTOOLPY_AFTER_RESET=y 98 | # CONFIG_ESPTOOLPY_AFTER_NORESET is not set 99 | CONFIG_ESPTOOLPY_AFTER="hard_reset" 100 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set 101 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set 102 | CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y 103 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set 104 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set 105 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set 106 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set 107 | CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 108 | CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 109 | # end of Serial flasher config 110 | 111 | # 112 | # Partition Table 113 | # 114 | CONFIG_PARTITION_TABLE_SINGLE_APP=y 115 | # CONFIG_PARTITION_TABLE_TWO_OTA is not set 116 | # CONFIG_PARTITION_TABLE_CUSTOM is not set 117 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" 118 | CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" 119 | CONFIG_PARTITION_TABLE_OFFSET=0x8000 120 | CONFIG_PARTITION_TABLE_MD5=y 121 | # end of Partition Table 122 | 123 | # 124 | # Compiler options 125 | # 126 | CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y 127 | # CONFIG_COMPILER_OPTIMIZATION_SIZE is not set 128 | # CONFIG_COMPILER_OPTIMIZATION_PERF is not set 129 | # CONFIG_COMPILER_OPTIMIZATION_NONE is not set 130 | CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y 131 | # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set 132 | # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set 133 | # CONFIG_COMPILER_CXX_EXCEPTIONS is not set 134 | # CONFIG_COMPILER_CXX_RTTI is not set 135 | CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y 136 | # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set 137 | # CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set 138 | # CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set 139 | # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set 140 | # CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set 141 | # end of Compiler options 142 | 143 | # 144 | # Component config 145 | # 146 | 147 | # 148 | # Application Level Tracing 149 | # 150 | # CONFIG_APPTRACE_DEST_TRAX is not set 151 | CONFIG_APPTRACE_DEST_NONE=y 152 | CONFIG_APPTRACE_LOCK_ENABLE=y 153 | # end of Application Level Tracing 154 | 155 | # 156 | # Bluetooth 157 | # 158 | # CONFIG_BT_ENABLED is not set 159 | CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0 160 | CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 161 | CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 162 | CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 163 | CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0 164 | CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 165 | CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 166 | CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 167 | CONFIG_BT_RESERVE_DRAM=0 168 | # end of Bluetooth 169 | 170 | # 171 | # CoAP Configuration 172 | # 173 | CONFIG_COAP_MBEDTLS_PSK=y 174 | # CONFIG_COAP_MBEDTLS_PKI is not set 175 | # CONFIG_COAP_MBEDTLS_DEBUG is not set 176 | CONFIG_COAP_LOG_DEFAULT_LEVEL=0 177 | # end of CoAP Configuration 178 | 179 | # 180 | # Driver configurations 181 | # 182 | 183 | # 184 | # ADC configuration 185 | # 186 | # CONFIG_ADC_FORCE_XPD_FSM is not set 187 | CONFIG_ADC_DISABLE_DAC=y 188 | # end of ADC configuration 189 | 190 | # 191 | # SPI configuration 192 | # 193 | # CONFIG_SPI_MASTER_IN_IRAM is not set 194 | CONFIG_SPI_MASTER_ISR_IN_IRAM=y 195 | # CONFIG_SPI_SLAVE_IN_IRAM is not set 196 | CONFIG_SPI_SLAVE_ISR_IN_IRAM=y 197 | # end of SPI configuration 198 | 199 | # 200 | # UART configuration 201 | # 202 | # CONFIG_UART_ISR_IN_IRAM is not set 203 | # end of UART configuration 204 | 205 | # 206 | # RTCIO configuration 207 | # 208 | # CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC is not set 209 | # end of RTCIO configuration 210 | # end of Driver configurations 211 | 212 | # 213 | # eFuse Bit Manager 214 | # 215 | # CONFIG_EFUSE_CUSTOM_TABLE is not set 216 | # CONFIG_EFUSE_VIRTUAL is not set 217 | # CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set 218 | CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y 219 | # CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set 220 | CONFIG_EFUSE_MAX_BLK_LEN=192 221 | # end of eFuse Bit Manager 222 | 223 | # 224 | # ESP-TLS 225 | # 226 | CONFIG_ESP_TLS_USING_MBEDTLS=y 227 | # CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set 228 | # CONFIG_ESP_TLS_SERVER is not set 229 | # CONFIG_ESP_TLS_PSK_VERIFICATION is not set 230 | # end of ESP-TLS 231 | 232 | # 233 | # ESP32-specific 234 | # 235 | CONFIG_ESP32_REV_MIN_0=y 236 | # CONFIG_ESP32_REV_MIN_1 is not set 237 | # CONFIG_ESP32_REV_MIN_2 is not set 238 | # CONFIG_ESP32_REV_MIN_3 is not set 239 | CONFIG_ESP32_REV_MIN=0 240 | CONFIG_ESP32_DPORT_WORKAROUND=y 241 | # CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set 242 | CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y 243 | # CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set 244 | CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160 245 | # CONFIG_ESP32_SPIRAM_SUPPORT is not set 246 | # CONFIG_ESP32_TRAX is not set 247 | CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 248 | # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set 249 | CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y 250 | CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 251 | # CONFIG_ESP32_ULP_COPROC_ENABLED is not set 252 | CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 253 | CONFIG_ESP32_DEBUG_OCDAWARE=y 254 | CONFIG_ESP32_BROWNOUT_DET=y 255 | CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y 256 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set 257 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set 258 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set 259 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set 260 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set 261 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set 262 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set 263 | CONFIG_ESP32_BROWNOUT_DET_LVL=0 264 | CONFIG_ESP32_REDUCE_PHY_TX_POWER=y 265 | CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y 266 | # CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set 267 | # CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set 268 | # CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set 269 | CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y 270 | # CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set 271 | # CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set 272 | # CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set 273 | CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 274 | CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 275 | CONFIG_ESP32_XTAL_FREQ_40=y 276 | # CONFIG_ESP32_XTAL_FREQ_26 is not set 277 | # CONFIG_ESP32_XTAL_FREQ_AUTO is not set 278 | CONFIG_ESP32_XTAL_FREQ=40 279 | # CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set 280 | # CONFIG_ESP32_NO_BLOBS is not set 281 | # CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set 282 | # CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set 283 | CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5 284 | # end of ESP32-specific 285 | 286 | # 287 | # Power Management 288 | # 289 | # CONFIG_PM_ENABLE is not set 290 | # end of Power Management 291 | 292 | # 293 | # ADC-Calibration 294 | # 295 | CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y 296 | CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y 297 | CONFIG_ADC_CAL_LUT_ENABLE=y 298 | # end of ADC-Calibration 299 | 300 | # 301 | # Common ESP-related 302 | # 303 | CONFIG_ESP_ERR_TO_NAME_LOOKUP=y 304 | CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 305 | CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 306 | CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 307 | CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 308 | CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y 309 | CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 310 | CONFIG_ESP_CONSOLE_UART_DEFAULT=y 311 | # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set 312 | # CONFIG_ESP_CONSOLE_UART_NONE is not set 313 | CONFIG_ESP_CONSOLE_UART_NUM=0 314 | CONFIG_ESP_CONSOLE_UART_TX_GPIO=1 315 | CONFIG_ESP_CONSOLE_UART_RX_GPIO=3 316 | CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 317 | CONFIG_ESP_INT_WDT=y 318 | CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 319 | CONFIG_ESP_INT_WDT_CHECK_CPU1=y 320 | CONFIG_ESP_TASK_WDT=y 321 | # CONFIG_ESP_TASK_WDT_PANIC is not set 322 | CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 323 | CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y 324 | CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y 325 | # CONFIG_ESP_PANIC_HANDLER_IRAM is not set 326 | CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y 327 | CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y 328 | CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y 329 | CONFIG_ESP_MAC_ADDR_UNIVERSE_BT_OFFSET=2 330 | CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y 331 | # end of Common ESP-related 332 | 333 | # 334 | # Ethernet 335 | # 336 | CONFIG_ETH_ENABLED=y 337 | CONFIG_ETH_USE_ESP32_EMAC=y 338 | CONFIG_ETH_PHY_INTERFACE_RMII=y 339 | # CONFIG_ETH_PHY_INTERFACE_MII is not set 340 | CONFIG_ETH_RMII_CLK_INPUT=y 341 | # CONFIG_ETH_RMII_CLK_OUTPUT is not set 342 | CONFIG_ETH_RMII_CLK_IN_GPIO=0 343 | CONFIG_ETH_DMA_BUFFER_SIZE=512 344 | CONFIG_ETH_DMA_RX_BUFFER_NUM=10 345 | CONFIG_ETH_DMA_TX_BUFFER_NUM=10 346 | CONFIG_ETH_USE_SPI_ETHERNET=y 347 | # CONFIG_ETH_SPI_ETHERNET_DM9051 is not set 348 | # CONFIG_ETH_USE_OPENETH is not set 349 | # end of Ethernet 350 | 351 | # 352 | # Event Loop Library 353 | # 354 | # CONFIG_ESP_EVENT_LOOP_PROFILING is not set 355 | CONFIG_ESP_EVENT_POST_FROM_ISR=y 356 | CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y 357 | # end of Event Loop Library 358 | 359 | # 360 | # GDB Stub 361 | # 362 | # end of GDB Stub 363 | 364 | # 365 | # ESP HTTP client 366 | # 367 | CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y 368 | # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set 369 | # end of ESP HTTP client 370 | 371 | # 372 | # HTTP Server 373 | # 374 | CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 375 | CONFIG_HTTPD_MAX_URI_LEN=512 376 | CONFIG_HTTPD_ERR_RESP_NO_DELAY=y 377 | CONFIG_HTTPD_PURGE_BUF_LEN=32 378 | # CONFIG_HTTPD_LOG_PURGE_DATA is not set 379 | # CONFIG_HTTPD_WS_SUPPORT is not set 380 | # end of HTTP Server 381 | 382 | # 383 | # ESP HTTPS OTA 384 | # 385 | # CONFIG_OTA_ALLOW_HTTP is not set 386 | # end of ESP HTTPS OTA 387 | 388 | # 389 | # ESP HTTPS server 390 | # 391 | # CONFIG_ESP_HTTPS_SERVER_ENABLE is not set 392 | # end of ESP HTTPS server 393 | 394 | # 395 | # ESP NETIF Adapter 396 | # 397 | CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 398 | CONFIG_ESP_NETIF_TCPIP_LWIP=y 399 | # CONFIG_ESP_NETIF_LOOPBACK is not set 400 | CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y 401 | # end of ESP NETIF Adapter 402 | 403 | # 404 | # ESP System Settings 405 | # 406 | # CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set 407 | CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y 408 | # CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set 409 | # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set 410 | # end of ESP System Settings 411 | 412 | # 413 | # High resolution timer (esp_timer) 414 | # 415 | # CONFIG_ESP_TIMER_PROFILING is not set 416 | CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 417 | # CONFIG_ESP_TIMER_IMPL_FRC2 is not set 418 | CONFIG_ESP_TIMER_IMPL_TG0_LAC=y 419 | # end of High resolution timer (esp_timer) 420 | 421 | # 422 | # Wi-Fi 423 | # 424 | CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 425 | CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 426 | # CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set 427 | CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y 428 | CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 429 | CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 430 | # CONFIG_ESP32_WIFI_CSI_ENABLED is not set 431 | CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y 432 | CONFIG_ESP32_WIFI_TX_BA_WIN=6 433 | CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y 434 | CONFIG_ESP32_WIFI_RX_BA_WIN=6 435 | CONFIG_ESP32_WIFI_NVS_ENABLED=y 436 | CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y 437 | # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set 438 | CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 439 | CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 440 | # CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set 441 | CONFIG_ESP32_WIFI_IRAM_OPT=y 442 | CONFIG_ESP32_WIFI_RX_IRAM_OPT=y 443 | CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y 444 | # end of Wi-Fi 445 | 446 | # 447 | # PHY 448 | # 449 | CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y 450 | # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set 451 | CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 452 | CONFIG_ESP32_PHY_MAX_TX_POWER=20 453 | # end of PHY 454 | 455 | # 456 | # Core dump 457 | # 458 | # CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set 459 | # CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set 460 | CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y 461 | # end of Core dump 462 | 463 | # 464 | # FAT Filesystem support 465 | # 466 | # CONFIG_FATFS_CODEPAGE_DYNAMIC is not set 467 | CONFIG_FATFS_CODEPAGE_437=y 468 | # CONFIG_FATFS_CODEPAGE_720 is not set 469 | # CONFIG_FATFS_CODEPAGE_737 is not set 470 | # CONFIG_FATFS_CODEPAGE_771 is not set 471 | # CONFIG_FATFS_CODEPAGE_775 is not set 472 | # CONFIG_FATFS_CODEPAGE_850 is not set 473 | # CONFIG_FATFS_CODEPAGE_852 is not set 474 | # CONFIG_FATFS_CODEPAGE_855 is not set 475 | # CONFIG_FATFS_CODEPAGE_857 is not set 476 | # CONFIG_FATFS_CODEPAGE_860 is not set 477 | # CONFIG_FATFS_CODEPAGE_861 is not set 478 | # CONFIG_FATFS_CODEPAGE_862 is not set 479 | # CONFIG_FATFS_CODEPAGE_863 is not set 480 | # CONFIG_FATFS_CODEPAGE_864 is not set 481 | # CONFIG_FATFS_CODEPAGE_865 is not set 482 | # CONFIG_FATFS_CODEPAGE_866 is not set 483 | # CONFIG_FATFS_CODEPAGE_869 is not set 484 | # CONFIG_FATFS_CODEPAGE_932 is not set 485 | # CONFIG_FATFS_CODEPAGE_936 is not set 486 | # CONFIG_FATFS_CODEPAGE_949 is not set 487 | # CONFIG_FATFS_CODEPAGE_950 is not set 488 | CONFIG_FATFS_CODEPAGE=437 489 | CONFIG_FATFS_LFN_NONE=y 490 | # CONFIG_FATFS_LFN_HEAP is not set 491 | # CONFIG_FATFS_LFN_STACK is not set 492 | CONFIG_FATFS_FS_LOCK=0 493 | CONFIG_FATFS_TIMEOUT_MS=10000 494 | CONFIG_FATFS_PER_FILE_CACHE=y 495 | # end of FAT Filesystem support 496 | 497 | # 498 | # Modbus configuration 499 | # 500 | CONFIG_FMB_COMM_MODE_RTU_EN=y 501 | CONFIG_FMB_COMM_MODE_ASCII_EN=y 502 | CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 503 | CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 504 | CONFIG_FMB_QUEUE_LENGTH=20 505 | CONFIG_FMB_SERIAL_TASK_STACK_SIZE=2048 506 | CONFIG_FMB_SERIAL_BUF_SIZE=256 507 | CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 508 | CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 509 | CONFIG_FMB_SERIAL_TASK_PRIO=10 510 | # CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set 511 | CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 512 | CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 513 | CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 514 | CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 515 | CONFIG_FMB_TIMER_PORT_ENABLED=y 516 | CONFIG_FMB_TIMER_GROUP=0 517 | CONFIG_FMB_TIMER_INDEX=0 518 | # CONFIG_FMB_TIMER_ISR_IN_IRAM is not set 519 | # end of Modbus configuration 520 | 521 | # 522 | # FreeRTOS 523 | # 524 | # CONFIG_FREERTOS_UNICORE is not set 525 | CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF 526 | CONFIG_FREERTOS_CORETIMER_0=y 527 | # CONFIG_FREERTOS_CORETIMER_1 is not set 528 | CONFIG_FREERTOS_HZ=100 529 | CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y 530 | # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set 531 | # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set 532 | CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y 533 | # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set 534 | CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y 535 | CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 536 | CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y 537 | # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set 538 | # CONFIG_FREERTOS_ASSERT_DISABLE is not set 539 | CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 540 | CONFIG_FREERTOS_ISR_STACKSIZE=1536 541 | # CONFIG_FREERTOS_LEGACY_HOOKS is not set 542 | CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 543 | # CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION is not set 544 | CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 545 | CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 546 | CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 547 | CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 548 | # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set 549 | # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set 550 | CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y 551 | CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y 552 | # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set 553 | CONFIG_FREERTOS_DEBUG_OCDAWARE=y 554 | # CONFIG_FREERTOS_FPU_IN_ISR is not set 555 | # end of FreeRTOS 556 | 557 | # 558 | # Heap memory debugging 559 | # 560 | CONFIG_HEAP_POISONING_DISABLED=y 561 | # CONFIG_HEAP_POISONING_LIGHT is not set 562 | # CONFIG_HEAP_POISONING_COMPREHENSIVE is not set 563 | CONFIG_HEAP_TRACING_OFF=y 564 | # CONFIG_HEAP_TRACING_STANDALONE is not set 565 | # CONFIG_HEAP_TRACING_TOHOST is not set 566 | # CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set 567 | # end of Heap memory debugging 568 | 569 | # 570 | # jsmn 571 | # 572 | # CONFIG_JSMN_PARENT_LINKS is not set 573 | # CONFIG_JSMN_STRICT is not set 574 | # end of jsmn 575 | 576 | # 577 | # libsodium 578 | # 579 | # end of libsodium 580 | 581 | # 582 | # Log output 583 | # 584 | # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set 585 | # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set 586 | # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set 587 | CONFIG_LOG_DEFAULT_LEVEL_INFO=y 588 | # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set 589 | # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set 590 | CONFIG_LOG_DEFAULT_LEVEL=3 591 | CONFIG_LOG_COLORS=y 592 | CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y 593 | # CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set 594 | # end of Log output 595 | 596 | # 597 | # LWIP 598 | # 599 | CONFIG_LWIP_LOCAL_HOSTNAME="espressif" 600 | CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y 601 | # CONFIG_LWIP_L2_TO_L3_COPY is not set 602 | # CONFIG_LWIP_IRAM_OPTIMIZATION is not set 603 | CONFIG_LWIP_TIMERS_ONDEMAND=y 604 | CONFIG_LWIP_MAX_SOCKETS=10 605 | # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set 606 | # CONFIG_LWIP_SO_LINGER is not set 607 | CONFIG_LWIP_SO_REUSE=y 608 | CONFIG_LWIP_SO_REUSE_RXTOALL=y 609 | # CONFIG_LWIP_SO_RCVBUF is not set 610 | # CONFIG_LWIP_NETBUF_RECVINFO is not set 611 | CONFIG_LWIP_IP4_FRAG=y 612 | CONFIG_LWIP_IP6_FRAG=y 613 | # CONFIG_LWIP_IP4_REASSEMBLY is not set 614 | # CONFIG_LWIP_IP6_REASSEMBLY is not set 615 | # CONFIG_LWIP_IP_FORWARD is not set 616 | # CONFIG_LWIP_STATS is not set 617 | # CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set 618 | CONFIG_LWIP_ESP_GRATUITOUS_ARP=y 619 | CONFIG_LWIP_GARP_TMR_INTERVAL=60 620 | CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 621 | CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y 622 | # CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set 623 | 624 | # 625 | # DHCP server 626 | # 627 | CONFIG_LWIP_DHCPS_LEASE_UNIT=60 628 | CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 629 | # end of DHCP server 630 | 631 | # CONFIG_LWIP_AUTOIP is not set 632 | # CONFIG_LWIP_IPV6_AUTOCONFIG is not set 633 | CONFIG_LWIP_NETIF_LOOPBACK=y 634 | CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 635 | 636 | # 637 | # TCP 638 | # 639 | CONFIG_LWIP_MAX_ACTIVE_TCP=16 640 | CONFIG_LWIP_MAX_LISTENING_TCP=16 641 | CONFIG_LWIP_TCP_MAXRTX=12 642 | CONFIG_LWIP_TCP_SYNMAXRTX=6 643 | CONFIG_LWIP_TCP_MSS=1440 644 | CONFIG_LWIP_TCP_TMR_INTERVAL=250 645 | CONFIG_LWIP_TCP_MSL=60000 646 | CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 647 | CONFIG_LWIP_TCP_WND_DEFAULT=5744 648 | CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 649 | CONFIG_LWIP_TCP_QUEUE_OOSEQ=y 650 | # CONFIG_LWIP_TCP_SACK_OUT is not set 651 | # CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set 652 | CONFIG_LWIP_TCP_OVERSIZE_MSS=y 653 | # CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set 654 | # CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set 655 | CONFIG_LWIP_TCP_RTO_TIME=3000 656 | # end of TCP 657 | 658 | # 659 | # UDP 660 | # 661 | CONFIG_LWIP_MAX_UDP_PCBS=16 662 | CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 663 | # end of UDP 664 | 665 | CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 666 | CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y 667 | # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set 668 | # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set 669 | CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF 670 | # CONFIG_LWIP_PPP_SUPPORT is not set 671 | 672 | # 673 | # ICMP 674 | # 675 | # CONFIG_LWIP_MULTICAST_PING is not set 676 | # CONFIG_LWIP_BROADCAST_PING is not set 677 | # end of ICMP 678 | 679 | # 680 | # LWIP RAW API 681 | # 682 | CONFIG_LWIP_MAX_RAW_PCBS=16 683 | # end of LWIP RAW API 684 | 685 | # 686 | # SNTP 687 | # 688 | CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 689 | CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 690 | # end of SNTP 691 | 692 | CONFIG_LWIP_ESP_LWIP_ASSERT=y 693 | # end of LWIP 694 | 695 | # 696 | # mbedTLS 697 | # 698 | CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y 699 | # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set 700 | # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set 701 | CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y 702 | CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 703 | CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 704 | # CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set 705 | # CONFIG_MBEDTLS_DEBUG is not set 706 | 707 | # 708 | # Certificate Bundle 709 | # 710 | CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y 711 | CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y 712 | # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set 713 | # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set 714 | # CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set 715 | # end of Certificate Bundle 716 | 717 | # CONFIG_MBEDTLS_ECP_RESTARTABLE is not set 718 | # CONFIG_MBEDTLS_CMAC_C is not set 719 | CONFIG_MBEDTLS_HARDWARE_AES=y 720 | CONFIG_MBEDTLS_HARDWARE_MPI=y 721 | CONFIG_MBEDTLS_HARDWARE_SHA=y 722 | # CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set 723 | # CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set 724 | CONFIG_MBEDTLS_HAVE_TIME=y 725 | # CONFIG_MBEDTLS_HAVE_TIME_DATE is not set 726 | CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y 727 | CONFIG_MBEDTLS_SHA512_C=y 728 | CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y 729 | # CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set 730 | # CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set 731 | # CONFIG_MBEDTLS_TLS_DISABLED is not set 732 | CONFIG_MBEDTLS_TLS_SERVER=y 733 | CONFIG_MBEDTLS_TLS_CLIENT=y 734 | CONFIG_MBEDTLS_TLS_ENABLED=y 735 | 736 | # 737 | # TLS Key Exchange Methods 738 | # 739 | # CONFIG_MBEDTLS_PSK_MODES is not set 740 | CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y 741 | CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y 742 | CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y 743 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y 744 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y 745 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y 746 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y 747 | # end of TLS Key Exchange Methods 748 | 749 | CONFIG_MBEDTLS_SSL_RENEGOTIATION=y 750 | # CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set 751 | CONFIG_MBEDTLS_SSL_PROTO_TLS1=y 752 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y 753 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y 754 | # CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set 755 | CONFIG_MBEDTLS_SSL_ALPN=y 756 | CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y 757 | CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y 758 | 759 | # 760 | # Symmetric Ciphers 761 | # 762 | CONFIG_MBEDTLS_AES_C=y 763 | # CONFIG_MBEDTLS_CAMELLIA_C is not set 764 | # CONFIG_MBEDTLS_DES_C is not set 765 | CONFIG_MBEDTLS_RC4_DISABLED=y 766 | # CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set 767 | # CONFIG_MBEDTLS_RC4_ENABLED is not set 768 | # CONFIG_MBEDTLS_BLOWFISH_C is not set 769 | # CONFIG_MBEDTLS_XTEA_C is not set 770 | CONFIG_MBEDTLS_CCM_C=y 771 | CONFIG_MBEDTLS_GCM_C=y 772 | # end of Symmetric Ciphers 773 | 774 | # CONFIG_MBEDTLS_RIPEMD160_C is not set 775 | 776 | # 777 | # Certificates 778 | # 779 | CONFIG_MBEDTLS_PEM_PARSE_C=y 780 | CONFIG_MBEDTLS_PEM_WRITE_C=y 781 | CONFIG_MBEDTLS_X509_CRL_PARSE_C=y 782 | CONFIG_MBEDTLS_X509_CSR_PARSE_C=y 783 | # end of Certificates 784 | 785 | CONFIG_MBEDTLS_ECP_C=y 786 | CONFIG_MBEDTLS_ECDH_C=y 787 | CONFIG_MBEDTLS_ECDSA_C=y 788 | # CONFIG_MBEDTLS_ECJPAKE_C is not set 789 | CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y 790 | CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y 791 | CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y 792 | CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y 793 | CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y 794 | CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y 795 | CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y 796 | CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y 797 | CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y 798 | CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y 799 | CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y 800 | CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y 801 | CONFIG_MBEDTLS_ECP_NIST_OPTIM=y 802 | # CONFIG_MBEDTLS_POLY1305_C is not set 803 | # CONFIG_MBEDTLS_CHACHA20_C is not set 804 | # CONFIG_MBEDTLS_HKDF_C is not set 805 | # CONFIG_MBEDTLS_THREADING_C is not set 806 | # CONFIG_MBEDTLS_SECURITY_RISKS is not set 807 | # end of mbedTLS 808 | 809 | # 810 | # mDNS 811 | # 812 | CONFIG_MDNS_MAX_SERVICES=10 813 | CONFIG_MDNS_TASK_PRIORITY=1 814 | CONFIG_MDNS_TASK_STACK_SIZE=4096 815 | # CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set 816 | CONFIG_MDNS_TASK_AFFINITY_CPU0=y 817 | # CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set 818 | CONFIG_MDNS_TASK_AFFINITY=0x0 819 | CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 820 | CONFIG_MDNS_TIMER_PERIOD_MS=100 821 | # end of mDNS 822 | 823 | # 824 | # ESP-MQTT Configurations 825 | # 826 | CONFIG_MQTT_PROTOCOL_311=y 827 | CONFIG_MQTT_TRANSPORT_SSL=y 828 | CONFIG_MQTT_TRANSPORT_WEBSOCKET=y 829 | CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y 830 | # CONFIG_MQTT_USE_CUSTOM_CONFIG is not set 831 | # CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set 832 | # CONFIG_MQTT_CUSTOM_OUTBOX is not set 833 | # end of ESP-MQTT Configurations 834 | 835 | # 836 | # Newlib 837 | # 838 | CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y 839 | # CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set 840 | # CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set 841 | # CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set 842 | # CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set 843 | CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y 844 | # CONFIG_NEWLIB_NANO_FORMAT is not set 845 | # end of Newlib 846 | 847 | # 848 | # NVS 849 | # 850 | # end of NVS 851 | 852 | # 853 | # OpenSSL 854 | # 855 | # CONFIG_OPENSSL_DEBUG is not set 856 | # CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set 857 | CONFIG_OPENSSL_ASSERT_EXIT=y 858 | # end of OpenSSL 859 | 860 | # 861 | # PThreads 862 | # 863 | CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 864 | CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 865 | CONFIG_PTHREAD_STACK_MIN=768 866 | CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y 867 | # CONFIG_PTHREAD_DEFAULT_CORE_0 is not set 868 | # CONFIG_PTHREAD_DEFAULT_CORE_1 is not set 869 | CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 870 | CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" 871 | # end of PThreads 872 | 873 | # 874 | # SPI Flash driver 875 | # 876 | # CONFIG_SPI_FLASH_VERIFY_WRITE is not set 877 | # CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set 878 | CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y 879 | CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y 880 | # CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set 881 | # CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set 882 | # CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set 883 | # CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set 884 | # CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set 885 | CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y 886 | CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 887 | CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 888 | 889 | # 890 | # Auto-detect flash chips 891 | # 892 | CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y 893 | CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y 894 | CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y 895 | # end of Auto-detect flash chips 896 | # end of SPI Flash driver 897 | 898 | # 899 | # SPIFFS Configuration 900 | # 901 | CONFIG_SPIFFS_MAX_PARTITIONS=3 902 | 903 | # 904 | # SPIFFS Cache Configuration 905 | # 906 | CONFIG_SPIFFS_CACHE=y 907 | CONFIG_SPIFFS_CACHE_WR=y 908 | # CONFIG_SPIFFS_CACHE_STATS is not set 909 | # end of SPIFFS Cache Configuration 910 | 911 | CONFIG_SPIFFS_PAGE_CHECK=y 912 | CONFIG_SPIFFS_GC_MAX_RUNS=10 913 | # CONFIG_SPIFFS_GC_STATS is not set 914 | CONFIG_SPIFFS_PAGE_SIZE=256 915 | CONFIG_SPIFFS_OBJ_NAME_LEN=32 916 | # CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set 917 | CONFIG_SPIFFS_USE_MAGIC=y 918 | CONFIG_SPIFFS_USE_MAGIC_LENGTH=y 919 | CONFIG_SPIFFS_META_LENGTH=4 920 | CONFIG_SPIFFS_USE_MTIME=y 921 | 922 | # 923 | # Debug Configuration 924 | # 925 | # CONFIG_SPIFFS_DBG is not set 926 | # CONFIG_SPIFFS_API_DBG is not set 927 | # CONFIG_SPIFFS_GC_DBG is not set 928 | # CONFIG_SPIFFS_CACHE_DBG is not set 929 | # CONFIG_SPIFFS_CHECK_DBG is not set 930 | # CONFIG_SPIFFS_TEST_VISUALISATION is not set 931 | # end of Debug Configuration 932 | # end of SPIFFS Configuration 933 | 934 | # 935 | # TinyUSB 936 | # 937 | 938 | # 939 | # Descriptor configuration 940 | # 941 | CONFIG_USB_DESC_CUSTOM_VID=0x1234 942 | CONFIG_USB_DESC_CUSTOM_PID=0x5678 943 | # end of Descriptor configuration 944 | # end of TinyUSB 945 | 946 | # 947 | # Unity unit testing library 948 | # 949 | CONFIG_UNITY_ENABLE_FLOAT=y 950 | CONFIG_UNITY_ENABLE_DOUBLE=y 951 | # CONFIG_UNITY_ENABLE_COLOR is not set 952 | CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y 953 | # CONFIG_UNITY_ENABLE_FIXTURE is not set 954 | # CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set 955 | # end of Unity unit testing library 956 | 957 | # 958 | # Virtual file system 959 | # 960 | CONFIG_VFS_SUPPORT_IO=y 961 | CONFIG_VFS_SUPPORT_DIR=y 962 | CONFIG_VFS_SUPPORT_SELECT=y 963 | CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y 964 | CONFIG_VFS_SUPPORT_TERMIOS=y 965 | 966 | # 967 | # Host File System I/O (Semihosting) 968 | # 969 | CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 970 | CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 971 | # end of Host File System I/O (Semihosting) 972 | # end of Virtual file system 973 | 974 | # 975 | # Wear Levelling 976 | # 977 | # CONFIG_WL_SECTOR_SIZE_512 is not set 978 | CONFIG_WL_SECTOR_SIZE_4096=y 979 | CONFIG_WL_SECTOR_SIZE=4096 980 | # end of Wear Levelling 981 | 982 | # 983 | # Wi-Fi Provisioning Manager 984 | # 985 | CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 986 | CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 987 | # end of Wi-Fi Provisioning Manager 988 | 989 | # 990 | # Supplicant 991 | # 992 | CONFIG_WPA_MBEDTLS_CRYPTO=y 993 | # CONFIG_WPA_DEBUG_PRINT is not set 994 | # CONFIG_WPA_TESTING_OPTIONS is not set 995 | # CONFIG_WPA_WPS_WARS is not set 996 | # end of Supplicant 997 | 998 | # 999 | # Wifi Manager Configuration 1000 | # 1001 | CONFIG_WIFI_MANAGER_TASK_PRIORITY=5 1002 | CONFIG_WIFI_MANAGER_RETRY_TIMER=5000 1003 | CONFIG_WIFI_MANAGER_MAX_RETRY_START_AP=3 1004 | CONFIG_WIFI_MANAGER_SHUTDOWN_AP_TIMER=60000 1005 | CONFIG_WEBAPP_LOCATION="/" 1006 | CONFIG_DEFAULT_AP_SSID="esp32" 1007 | CONFIG_DEFAULT_AP_PASSWORD="esp32pwd" 1008 | CONFIG_DEFAULT_AP_CHANNEL=1 1009 | CONFIG_DEFAULT_AP_IP="10.10.0.1" 1010 | CONFIG_DEFAULT_AP_GATEWAY="10.10.0.1" 1011 | CONFIG_DEFAULT_AP_NETMASK="255.255.255.0" 1012 | CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4 1013 | CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 1014 | # end of Wifi Manager Configuration 1015 | # end of Component config 1016 | 1017 | # 1018 | # Compatibility options 1019 | # 1020 | # CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set 1021 | # end of Compatibility options 1022 | 1023 | # Deprecated options for backward compatibility 1024 | CONFIG_TOOLPREFIX="xtensa-esp32-elf-" 1025 | # CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set 1026 | # CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set 1027 | # CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set 1028 | CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y 1029 | # CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set 1030 | # CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set 1031 | CONFIG_LOG_BOOTLOADER_LEVEL=3 1032 | # CONFIG_APP_ROLLBACK_ENABLE is not set 1033 | # CONFIG_FLASH_ENCRYPTION_ENABLED is not set 1034 | # CONFIG_FLASHMODE_QIO is not set 1035 | # CONFIG_FLASHMODE_QOUT is not set 1036 | CONFIG_FLASHMODE_DIO=y 1037 | # CONFIG_FLASHMODE_DOUT is not set 1038 | # CONFIG_MONITOR_BAUD_9600B is not set 1039 | # CONFIG_MONITOR_BAUD_57600B is not set 1040 | CONFIG_MONITOR_BAUD_115200B=y 1041 | # CONFIG_MONITOR_BAUD_230400B is not set 1042 | # CONFIG_MONITOR_BAUD_921600B is not set 1043 | # CONFIG_MONITOR_BAUD_2MB is not set 1044 | # CONFIG_MONITOR_BAUD_OTHER is not set 1045 | CONFIG_MONITOR_BAUD_OTHER_VAL=115200 1046 | CONFIG_MONITOR_BAUD=115200 1047 | CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y 1048 | # CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set 1049 | CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y 1050 | # CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set 1051 | # CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set 1052 | # CONFIG_CXX_EXCEPTIONS is not set 1053 | CONFIG_STACK_CHECK_NONE=y 1054 | # CONFIG_STACK_CHECK_NORM is not set 1055 | # CONFIG_STACK_CHECK_STRONG is not set 1056 | # CONFIG_STACK_CHECK_ALL is not set 1057 | # CONFIG_WARN_WRITE_STRINGS is not set 1058 | # CONFIG_DISABLE_GCC8_WARNINGS is not set 1059 | # CONFIG_ESP32_APPTRACE_DEST_TRAX is not set 1060 | CONFIG_ESP32_APPTRACE_DEST_NONE=y 1061 | CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y 1062 | CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0 1063 | CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0 1064 | CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 1065 | CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 1066 | CONFIG_ADC2_DISABLE_DAC=y 1067 | # CONFIG_SPIRAM_SUPPORT is not set 1068 | CONFIG_TRACEMEM_RESERVE_DRAM=0x0 1069 | # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set 1070 | CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y 1071 | CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 1072 | # CONFIG_ULP_COPROC_ENABLED is not set 1073 | CONFIG_ULP_COPROC_RESERVE_MEM=0 1074 | CONFIG_BROWNOUT_DET=y 1075 | CONFIG_BROWNOUT_DET_LVL_SEL_0=y 1076 | # CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set 1077 | # CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set 1078 | # CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set 1079 | # CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set 1080 | # CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set 1081 | # CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set 1082 | # CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set 1083 | CONFIG_BROWNOUT_DET_LVL=0 1084 | CONFIG_REDUCE_PHY_TX_POWER=y 1085 | CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y 1086 | # CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set 1087 | # CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set 1088 | # CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set 1089 | # CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set 1090 | # CONFIG_NO_BLOBS is not set 1091 | # CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set 1092 | CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 1093 | CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 1094 | CONFIG_MAIN_TASK_STACK_SIZE=3584 1095 | CONFIG_IPC_TASK_STACK_SIZE=1024 1096 | CONFIG_CONSOLE_UART_DEFAULT=y 1097 | # CONFIG_CONSOLE_UART_CUSTOM is not set 1098 | # CONFIG_CONSOLE_UART_NONE is not set 1099 | CONFIG_CONSOLE_UART_NUM=0 1100 | CONFIG_CONSOLE_UART_TX_GPIO=1 1101 | CONFIG_CONSOLE_UART_RX_GPIO=3 1102 | CONFIG_CONSOLE_UART_BAUDRATE=115200 1103 | CONFIG_INT_WDT=y 1104 | CONFIG_INT_WDT_TIMEOUT_MS=300 1105 | CONFIG_INT_WDT_CHECK_CPU1=y 1106 | CONFIG_TASK_WDT=y 1107 | # CONFIG_TASK_WDT_PANIC is not set 1108 | CONFIG_TASK_WDT_TIMEOUT_S=5 1109 | CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y 1110 | CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y 1111 | # CONFIG_EVENT_LOOP_PROFILING is not set 1112 | CONFIG_POST_EVENTS_FROM_ISR=y 1113 | CONFIG_POST_EVENTS_FROM_IRAM_ISR=y 1114 | # CONFIG_ESP32S2_PANIC_PRINT_HALT is not set 1115 | CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y 1116 | # CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set 1117 | # CONFIG_ESP32S2_PANIC_GDBSTUB is not set 1118 | CONFIG_TIMER_TASK_STACK_SIZE=3584 1119 | CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 1120 | CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 1121 | CONFIG_MB_QUEUE_LENGTH=20 1122 | CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048 1123 | CONFIG_MB_SERIAL_BUF_SIZE=256 1124 | CONFIG_MB_SERIAL_TASK_PRIO=10 1125 | # CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set 1126 | CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20 1127 | CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 1128 | CONFIG_MB_CONTROLLER_STACK_SIZE=4096 1129 | CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 1130 | CONFIG_MB_TIMER_PORT_ENABLED=y 1131 | CONFIG_MB_TIMER_GROUP=0 1132 | CONFIG_MB_TIMER_INDEX=0 1133 | # CONFIG_SUPPORT_STATIC_ALLOCATION is not set 1134 | CONFIG_TIMER_TASK_PRIORITY=1 1135 | CONFIG_TIMER_TASK_STACK_DEPTH=2048 1136 | CONFIG_TIMER_QUEUE_LENGTH=10 1137 | # CONFIG_L2_TO_L3_COPY is not set 1138 | # CONFIG_USE_ONLY_LWIP_SELECT is not set 1139 | CONFIG_ESP_GRATUITOUS_ARP=y 1140 | CONFIG_GARP_TMR_INTERVAL=60 1141 | CONFIG_TCPIP_RECVMBOX_SIZE=32 1142 | CONFIG_TCP_MAXRTX=12 1143 | CONFIG_TCP_SYNMAXRTX=6 1144 | CONFIG_TCP_MSS=1440 1145 | CONFIG_TCP_MSL=60000 1146 | CONFIG_TCP_SND_BUF_DEFAULT=5744 1147 | CONFIG_TCP_WND_DEFAULT=5744 1148 | CONFIG_TCP_RECVMBOX_SIZE=6 1149 | CONFIG_TCP_QUEUE_OOSEQ=y 1150 | # CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set 1151 | CONFIG_TCP_OVERSIZE_MSS=y 1152 | # CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set 1153 | # CONFIG_TCP_OVERSIZE_DISABLE is not set 1154 | CONFIG_UDP_RECVMBOX_SIZE=6 1155 | CONFIG_TCPIP_TASK_STACK_SIZE=3072 1156 | CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y 1157 | # CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set 1158 | # CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set 1159 | CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF 1160 | # CONFIG_PPP_SUPPORT is not set 1161 | CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 1162 | CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 1163 | CONFIG_ESP32_PTHREAD_STACK_MIN=768 1164 | CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y 1165 | # CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set 1166 | # CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set 1167 | CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 1168 | CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" 1169 | CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y 1170 | # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set 1171 | # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set 1172 | CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y 1173 | CONFIG_SUPPORT_TERMIOS=y 1174 | CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 1175 | CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 1176 | # End of deprecated options 1177 | --------------------------------------------------------------------------------