├── .github ├── ESP32-WebApp.gif └── front_blinker.png ├── .gitignore ├── CMakeLists.txt ├── Makefile ├── README.md ├── components └── protocol_examples_common │ ├── CMakeLists.txt │ ├── Kconfig.projbuild │ ├── addr_from_stdin.c │ ├── component.mk │ ├── connect.c │ ├── include │ ├── addr_from_stdin.h │ └── protocol_examples_common.h │ └── stdin_out.c ├── front └── web-blinker │ ├── .browserslistrc │ ├── .editorconfig │ ├── .eslintrc.js │ ├── .gitignore │ ├── babel.config.js │ ├── package.json │ ├── postcss.config.js │ ├── public │ ├── favicon.ico │ └── index.html │ ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── Blinker.vue │ │ └── Home.vue │ ├── main.js │ ├── plugins │ │ └── vuetify.js │ └── router.js │ └── vue.config.js ├── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── component.mk ├── esp_rest_main.c └── rest_server.c ├── partitions_www_2500Kb.csv ├── partitions_www_5Mb.csv ├── sdkconfig.defaults └── version.txt /.github/ESP32-WebApp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurFDLR/esp32-webapp/70ecda7290785cad5fd652d15a916793bb9d9359/.github/ESP32-WebApp.gif -------------------------------------------------------------------------------- /.github/front_blinker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurFDLR/esp32-webapp/70ecda7290785cad5fd652d15a916793bb9d9359/.github/front_blinker.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .config 2 | *.o 3 | *.pyc 4 | 5 | # ESP-IDF configuration 6 | sdkconfig 7 | sdkconfig.old 8 | 9 | # gtags 10 | GTAGS 11 | GRTAGS 12 | GPATH 13 | 14 | # emacs 15 | .dir-locals.el 16 | 17 | # emacs temp file suffixes 18 | *~ 19 | .#* 20 | \#*# 21 | 22 | # eclipse setting 23 | .settings 24 | 25 | # MacOS directory files 26 | .DS_Store 27 | 28 | # cache dir 29 | .cache/ 30 | 31 | # Components Unit Test Apps files 32 | components/**/build/ 33 | components/**/build_*_*/ 34 | components/**/sdkconfig 35 | components/**/sdkconfig.old 36 | 37 | # Example project files 38 | examples/**/build/ 39 | examples/**/build_esp*_*/ 40 | examples/**/sdkconfig 41 | examples/**/sdkconfig.old 42 | 43 | # Doc build artifacts 44 | docs/_build/ 45 | docs/doxygen_sqlite3.db 46 | 47 | # Downloaded font files 48 | docs/_static/DejaVuSans.ttf 49 | docs/_static/NotoSansSC-Regular.otf 50 | 51 | # Unit test app files 52 | tools/unit-test-app/sdkconfig 53 | tools/unit-test-app/sdkconfig.old 54 | tools/unit-test-app/build 55 | tools/unit-test-app/build_*_*/ 56 | tools/unit-test-app/output 57 | tools/unit-test-app/test_configs 58 | 59 | # Unit Test CMake compile log folder 60 | log_ut_cmake 61 | 62 | # test application build files 63 | tools/test_apps/**/build/ 64 | tools/test_apps/**/build_*_*/ 65 | tools/test_apps/**/sdkconfig 66 | tools/test_apps/**/sdkconfig.old 67 | 68 | # IDF monitor test 69 | tools/test_idf_monitor/outputs 70 | 71 | TEST_LOGS 72 | 73 | # gcov coverage reports 74 | *.gcda 75 | *.gcno 76 | coverage.info 77 | coverage_report/ 78 | 79 | test_multi_heap_host 80 | 81 | # VS Code Settings 82 | .vscode/ 83 | 84 | # VIM files 85 | *.swp 86 | *.swo 87 | 88 | # Clion IDE CMake build & config 89 | .idea/ 90 | cmake-build-*/ 91 | 92 | # Results for the checking of the Python coding style and static analysis 93 | .mypy_cache 94 | flake8_output.txt 95 | 96 | # ESP-IDF default build directory name 97 | build 98 | 99 | # lock files for examples and components 100 | dependencies.lock 101 | 102 | # managed_components for examples 103 | managed_components 104 | 105 | # pytest log 106 | pytest_embedded_log/ 107 | 108 | # User 109 | video/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 4 | project(esp32s3_webapp) 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := esp32s3_webapp 2 | 3 | EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common 4 | 5 | include $(IDF_PATH)/make/project.mk 6 | 7 | ifdef CONFIG_EXAMPLE_WEB_DEPLOY_SF 8 | WEB_SRC_DIR = $(shell pwd)/front/web-blinker 9 | ifneq ($(wildcard $(WEB_SRC_DIR)/dist/.*),) 10 | SPIFFS_IMAGE_FLASH_IN_PROJECT := 1 11 | $(eval $(call spiffs_create_partition_image,www,$(WEB_SRC_DIR)/dist)) 12 | else 13 | $(error $(WEB_SRC_DIR)/dist doesn't exist. Please run 'npm run build' in $(WEB_SRC_DIR)) 14 | endif 15 | endif 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

Demo of the application

3 | [**See full video demonstration here**](https://youtu.be/Ou1GtHqjWwc) 4 | 5 | # ESP32 Web Application Example: ESP-IDF RESTful & Vue 2 Frontend 6 | 7 | This repository is a refresher of the [ESP-IDF example](https://github.com/espressif/esp-idf/tree/master/examples/protocols/http_server/restful_server) to use Vue 2, and its UI library Vuetify. 8 | 9 | It has been tested and developed on an [ESP32-S3 custom board with 8Mb of flash memory](https://github.com/ArthurFDLR/esp32-s3-darlington-array), but any ESP32 with at least 4Mb of memory should handle this application. 10 | 11 | - [ESP32 Web Application Example: ESP-IDF RESTful & Vue 2 Frontend](#esp32-web-application-example-esp-idf-restful--vue-2-frontend) 12 | - [Overview](#overview) 13 | - [About mDNS](#about-mdns) 14 | - [About deploy mode](#about-deploy-mode) 15 | - [About frontend framework](#about-frontend-framework) 16 | - [How to use example](#how-to-use-example) 17 | - [Hardware Required](#hardware-required) 18 | - [Configure the project](#configure-the-project) 19 | - [Build and Flash](#build-and-flash) 20 | - [Extra steps to do for deploying website by semihost](#extra-steps-to-do-for-deploying-website-by-semihost) 21 | - [Troubleshooting](#troubleshooting) 22 | 23 | ## Overview 24 | 25 | This example mainly introduces how to implement a RESTful API server and HTTP server on ESP32, with a frontend browser UI. 26 | 27 | This example designs several APIs to fetch resources as follows: 28 | 29 | | API | Method | Resource Example | Description | Page URL | 30 | | -------------------------- | ------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------- | 31 | | `/api/v1/system/info` | `GET` | {
version:"v4.0-dev",
cores:2
} | Used for clients to get system information like IDF version, ESP32 cores, etc | `/` | 32 | | `/api/v1/blinker/duration` | `POST` | {
"duration_ms":1000
} | Used for clients to get raw temperature data read from sensor | `/blinker` | 33 | | `/api/v1/blinker/state` | `POST` | {
"state":true
} | Used for clients to upload control values to ESP32 in order to control LED’s brightness | `/blinker` | 34 | 35 | **Page URL** is the URL of the webpage which will send a request to the API. 36 | 37 | ### About mDNS 38 | 39 | The IP address of an IoT device may vary from time to time, so it’s impracticable to hard code the IP address in the webpage. By default, we use the `mDNS` to parse the domain name `esp-blinker.local`, so that we can always get access to the web server by this URL no matter what the real IP address behind it. See [here](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/protocols/mdns.html) for more information about mDNS. 40 | 41 | **Notes: mDNS is installed by default on most operating systems or is available as separate package.** 42 | 43 | ### About deploy mode 44 | 45 | In development mode, it would be awful to flash the whole webpages every time we update the html, js or css files. So it is highly recommended to deploy the webpage to host PC via `semihost` technology. Whenever the browser fetch the webpage, ESP32 can forward the required files located on host PC. By this mean, it will save a lot of time when designing new pages. 46 | 47 | After developing, the pages should be deployed to one of the following destinations: 48 | 49 | * SPI Flash - which is recommended when the website after built is small (e.g. less than 2MB). 50 | * SD Card - which would be an option when the website after built is very large that the SPI Flash have not enough space to hold (e.g. larger than 2MB). 51 | 52 | ### About frontend framework 53 | 54 | Many famous frontend frameworks (e.g. Vue, React, Angular) can be used in this example. Here we just take [Vue](https://vuejs.org/) as example and adopt the [vuetify](https://vuetifyjs.com/) as the UI library. 55 | 56 | ## How to use example 57 | 58 | ### Hardware Required 59 | 60 | To run this example, you need an ESP32 dev board (e.g. ESP32-WROVER Kit, ESP32-Ethernet-Kit) or ESP32 core board (e.g. ESP32-DevKitC). An extra JTAG adapter might also needed if you choose to deploy the website by semihosting. For more information about supported JTAG adapter, please refer to [select JTAG adapter](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter). Or if you choose to deploy the website to SD card, an extra SD slot board is needed. 61 | 62 | **Pin Assignment:** 63 | 64 | Only if you deploy the website to SD card, then the following pin connection is used in this example. 65 | 66 | | ESP32 | SD Card | 67 | | ------ | ------- | 68 | | GPIO2 | D0 | 69 | | GPIO4 | D1 | 70 | | GPIO12 | D2 | 71 | | GPIO13 | D3 | 72 | | GPIO14 | CLK | 73 | | GPIO15 | CMD | 74 | 75 | 76 | ### Configure the project 77 | 78 | Open the project configuration menu (`idf.py menuconfig`). 79 | 80 | In the `Example Connection Configuration` menu: 81 | 82 | * Choose the network interface in `Connect using` option based on your board. Currently we support both Wi-Fi and Ethernet. 83 | * If you select the Wi-Fi interface, you also have to set: 84 | * Wi-Fi SSID and Wi-Fi password that your esp32 will connect to. 85 | * If you select the Ethernet interface, you also have to set: 86 | * PHY model in `Ethernet PHY` option, e.g. IP101. 87 | * PHY address in `PHY Address` option, which should be determined by your board schematic. 88 | * EMAC Clock mode, GPIO used by SMI. 89 | 90 | In the `Example Configuration` menu: 91 | 92 | * Set the pin of the build-in LED (or any pin which has something blinkable connected) in `Blink GPIO number`. 93 | * Set the domain name in `mDNS Host Name` option. 94 | * Choose the deploy mode in `Website deploy mode`, currently we support deploy website to host PC, SD card and SPI Nor flash. 95 | * If we choose to `Deploy website to host (JTAG is needed)`, then we also need to specify the full path of the website in `Host path to mount (e.g. absolute path to web dist directory)`. 96 | * Set the mount point of the website in `Website mount point in VFS` option, the default value is `/www`. 97 | 98 | ### Build and Flash 99 | 100 | After the webpage design work has been finished, you should compile them by running following commands: 101 | 102 | ```bash 103 | cd ./front/web-blinker 104 | npm install 105 | npm run build 106 | ``` 107 | 108 | After a while, you will see a `dist` directory which contains all the website files (e.g. html, js, css, images). 109 | 110 | Run `idf.py -p PORT flash monitor` to build and flash the project.. 111 | 112 | (To exit the serial monitor, type ``Ctrl-]``.) 113 | 114 | See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. 115 | 116 | ### Extra steps to do for deploying website by semihost 117 | 118 | We need to run the latest version of OpenOCD which should support semihost feature when we test this deploy mode: 119 | 120 | ```bash 121 | openocd-esp32/bin/openocd -s openocd-esp32/share/openocd/scripts -f board/esp32-wrover-kit-3.3v.cfg 122 | ``` 123 | 124 | ## Troubleshooting 125 | 126 | 1. Error occurred when building example: `...front/web-demo/dist doesn't exit. Please run 'npm run build' in ...front/web-demo`. 127 | * When you choose to deploy website to SPI flash, make sure the `dist` directory has been generated before you building this example. 128 | 129 | (For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) 130 | -------------------------------------------------------------------------------- /components/protocol_examples_common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "connect.c" "stdin_out.c" "addr_from_stdin.c" 2 | INCLUDE_DIRS "include" 3 | PRIV_REQUIRES esp_netif 4 | ) 5 | -------------------------------------------------------------------------------- /components/protocol_examples_common/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Example Connection Configuration" 2 | 3 | config EXAMPLE_GPIO_RANGE_MIN 4 | int 5 | default 0 6 | 7 | config EXAMPLE_GPIO_RANGE_MAX 8 | int 9 | default 33 if IDF_TARGET_ESP32 10 | default 46 if IDF_TARGET_ESP32S2 11 | default 19 if IDF_TARGET_ESP32C3 12 | default 48 if IDF_TARGET_ESP32S3 13 | 14 | config EXAMPLE_CONNECT_WIFI 15 | bool "connect using WiFi interface" 16 | default y 17 | help 18 | Protocol examples can use Wi-Fi and/or Ethernet to connect to the network. 19 | Choose this option to connect with WiFi 20 | 21 | if EXAMPLE_CONNECT_WIFI 22 | config EXAMPLE_WIFI_SSID 23 | string "WiFi SSID" 24 | default "myssid" 25 | help 26 | SSID (network name) for the example to connect to. 27 | 28 | config EXAMPLE_WIFI_PASSWORD 29 | string "WiFi Password" 30 | default "mypassword" 31 | help 32 | WiFi password (WPA or WPA2) for the example to use. 33 | Can be left blank if the network has no security set. 34 | 35 | choice EXAMPLE_WIFI_SCAN_METHOD 36 | prompt "WiFi Scan Method" 37 | default EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL 38 | help 39 | WiFi scan method: 40 | 41 | If "Fast" is selected, scan will end after find SSID match AP. 42 | 43 | If "All Channel" is selected, scan will end after scan all the channel. 44 | 45 | config EXAMPLE_WIFI_SCAN_METHOD_FAST 46 | bool "Fast" 47 | config EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL 48 | bool "All Channel" 49 | endchoice 50 | 51 | menu "WiFi Scan threshold" 52 | config EXAMPLE_WIFI_SCAN_RSSI_THRESHOLD 53 | int "WiFi minimum rssi" 54 | range -127 0 55 | 56 | default -127 57 | help 58 | The minimum rssi to accept in the scan mode. 59 | 60 | choice EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD 61 | prompt "WiFi Scan auth mode threshold" 62 | default EXAMPLE_WIFI_AUTH_OPEN 63 | help 64 | The weakest authmode to accept in the scan mode. 65 | 66 | config EXAMPLE_WIFI_AUTH_OPEN 67 | bool "OPEN" 68 | config EXAMPLE_WIFI_AUTH_WEP 69 | bool "WEP" 70 | config EXAMPLE_WIFI_AUTH_WPA_PSK 71 | bool "WPA PSK" 72 | config EXAMPLE_WIFI_AUTH_WPA2_PSK 73 | bool "WPA2 PSK" 74 | config EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK 75 | bool "WPA WPA2 PSK" 76 | config EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE 77 | bool "WPA2 ENTERPRISE" 78 | config EXAMPLE_WIFI_AUTH_WPA3_PSK 79 | bool "WPA3 PSK" 80 | config EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK 81 | bool "WPA2 WPA3 PSK" 82 | config EXAMPLE_WIFI_AUTH_WAPI_PSK 83 | bool "WAPI PSK" 84 | endchoice 85 | endmenu 86 | 87 | choice EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD 88 | prompt "WiFi Connect AP Sort Method" 89 | default EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL 90 | help 91 | WiFi connect AP sort method: 92 | 93 | If "Signal" is selected, Sort matched APs in scan list by RSSI. 94 | 95 | If "Security" is selected, Sort matched APs in scan list by security mode. 96 | 97 | config EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL 98 | bool "Signal" 99 | config EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY 100 | bool "Security" 101 | endchoice 102 | endif 103 | 104 | config EXAMPLE_CONNECT_ETHERNET 105 | bool "connect using Ethernet interface" 106 | default n 107 | help 108 | Protocol examples can use Wi-Fi and/or Ethernet to connect to the network. 109 | Choose this option to connect with Ethernet 110 | 111 | if EXAMPLE_CONNECT_ETHERNET 112 | config EXAMPLE_USE_SPI_ETHERNET 113 | bool 114 | 115 | choice EXAMPLE_ETHERNET_TYPE 116 | prompt "Ethernet Type" 117 | default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 118 | default EXAMPLE_USE_W5500 119 | help 120 | Select which kind of Ethernet will be used in the example. 121 | 122 | config EXAMPLE_USE_INTERNAL_ETHERNET 123 | depends on IDF_TARGET_ESP32 124 | select ETH_USE_ESP32_EMAC 125 | bool "Internal EMAC" 126 | help 127 | Select internal Ethernet MAC controller. 128 | 129 | config EXAMPLE_USE_DM9051 130 | bool "DM9051 Module" 131 | select EXAMPLE_USE_SPI_ETHERNET 132 | select ETH_USE_SPI_ETHERNET 133 | select ETH_SPI_ETHERNET_DM9051 134 | help 135 | Select external SPI-Ethernet module. 136 | 137 | config EXAMPLE_USE_W5500 138 | bool "W5500 Module" 139 | select EXAMPLE_USE_SPI_ETHERNET 140 | select ETH_USE_SPI_ETHERNET 141 | select ETH_SPI_ETHERNET_W5500 142 | help 143 | Select external SPI-Ethernet module (W5500). 144 | 145 | config EXAMPLE_USE_OPENETH 146 | bool "OpenCores Ethernet MAC (EXPERIMENTAL)" 147 | select ETH_USE_OPENETH 148 | help 149 | When this option is enabled, the example is built with support for 150 | OpenCores Ethernet MAC, which allows testing the example in QEMU. 151 | Note that this option is used for internal testing purposes, and 152 | not officially supported. Examples built with this option enabled 153 | will not run on a real ESP32 chip. 154 | 155 | endchoice # EXAMPLE_ETHERNET_TYPE 156 | 157 | if EXAMPLE_USE_INTERNAL_ETHERNET 158 | choice EXAMPLE_ETH_PHY_MODEL 159 | prompt "Ethernet PHY Device" 160 | default EXAMPLE_ETH_PHY_IP101 161 | help 162 | Select the Ethernet PHY device to use in the example. 163 | 164 | config EXAMPLE_ETH_PHY_IP101 165 | bool "IP101" 166 | help 167 | IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. 168 | Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. 169 | 170 | config EXAMPLE_ETH_PHY_RTL8201 171 | bool "RTL8201/SR8201" 172 | help 173 | RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. 174 | Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. 175 | 176 | config EXAMPLE_ETH_PHY_LAN87XX 177 | bool "LAN87xx" 178 | help 179 | Below chips are supported: 180 | LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and 181 | flexPWR® Technology. 182 | LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. 183 | LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver 184 | with HP Auto-MDIX and flexPWR® Technology. 185 | LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and 186 | flexPWR® Technology. 187 | Goto https://www.microchip.com for more information about them. 188 | 189 | config EXAMPLE_ETH_PHY_DP83848 190 | bool "DP83848" 191 | help 192 | DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. 193 | Goto http://www.ti.com/product/DP83848J for more information about it. 194 | endchoice 195 | 196 | config EXAMPLE_ETH_MDC_GPIO 197 | int "SMI MDC GPIO number" 198 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 199 | default 23 200 | help 201 | Set the GPIO number used by SMI MDC. 202 | 203 | config EXAMPLE_ETH_MDIO_GPIO 204 | int "SMI MDIO GPIO number" 205 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 206 | default 18 207 | help 208 | Set the GPIO number used by SMI MDIO. 209 | endif 210 | 211 | if EXAMPLE_USE_SPI_ETHERNET 212 | config EXAMPLE_ETH_SPI_HOST 213 | int "SPI Host Number" 214 | range 0 2 215 | default 1 216 | help 217 | Set the SPI host used to communicate with the SPI Ethernet Controller. 218 | 219 | config EXAMPLE_ETH_SPI_SCLK_GPIO 220 | int "SPI SCLK GPIO number" 221 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 222 | default 14 223 | help 224 | Set the GPIO number used by SPI SCLK. 225 | 226 | config EXAMPLE_ETH_SPI_MOSI_GPIO 227 | int "SPI MOSI GPIO number" 228 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 229 | default 13 230 | help 231 | Set the GPIO number used by SPI MOSI. 232 | 233 | config EXAMPLE_ETH_SPI_MISO_GPIO 234 | int "SPI MISO GPIO number" 235 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 236 | default 12 237 | help 238 | Set the GPIO number used by SPI MISO. 239 | 240 | config EXAMPLE_ETH_SPI_CS_GPIO 241 | int "SPI CS GPIO number" 242 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 243 | default 15 244 | help 245 | Set the GPIO number used by SPI CS. 246 | 247 | config EXAMPLE_ETH_SPI_CLOCK_MHZ 248 | int "SPI clock speed (MHz)" 249 | range 5 80 250 | default 36 251 | help 252 | Set the clock speed (MHz) of SPI interface. 253 | 254 | config EXAMPLE_ETH_SPI_INT_GPIO 255 | int "Interrupt GPIO number" 256 | range EXAMPLE_GPIO_RANGE_MIN EXAMPLE_GPIO_RANGE_MAX 257 | default 4 258 | help 259 | Set the GPIO number used by the SPI Ethernet module interrupt line. 260 | endif # EXAMPLE_USE_SPI_ETHERNET 261 | 262 | config EXAMPLE_ETH_PHY_RST_GPIO 263 | int "PHY Reset GPIO number" 264 | range -1 EXAMPLE_GPIO_RANGE_MAX 265 | default 5 266 | help 267 | Set the GPIO number used to reset PHY chip. 268 | Set to -1 to disable PHY chip hardware reset. 269 | 270 | config EXAMPLE_ETH_PHY_ADDR 271 | int "PHY Address" 272 | range 0 31 if EXAMPLE_USE_INTERNAL_ETHERNET 273 | default 1 274 | help 275 | Set PHY address according your board schematic. 276 | endif # EXAMPLE_CONNECT_ETHERNET 277 | 278 | config EXAMPLE_CONNECT_IPV6 279 | bool "Obtain IPv6 address" 280 | default y 281 | depends on EXAMPLE_CONNECT_WIFI || EXAMPLE_CONNECT_ETHERNET 282 | select LWIP_IPV6 283 | help 284 | By default, examples will wait until IPv4 and IPv6 local link addresses are obtained. 285 | Disable this option if the network does not support IPv6. 286 | Choose the preferred IPv6 address type if the connection code should wait until other than 287 | the local link address gets assigned. 288 | Consider enabling IPv6 stateless address autoconfiguration (SLAAC) in the LWIP component. 289 | 290 | if EXAMPLE_CONNECT_IPV6 291 | choice EXAMPLE_CONNECT_PREFERRED_IPV6 292 | prompt "Preferred IPv6 Type" 293 | default EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK 294 | help 295 | Select which kind of IPv6 address the connect logic waits for. 296 | 297 | config EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK 298 | bool "Local Link Address" 299 | help 300 | Blocks until Local link address assigned. 301 | 302 | config EXAMPLE_CONNECT_IPV6_PREF_GLOBAL 303 | bool "Global Address" 304 | help 305 | Blocks until Global address assigned. 306 | 307 | config EXAMPLE_CONNECT_IPV6_PREF_SITE_LOCAL 308 | bool "Site Local Address" 309 | help 310 | Blocks until Site link address assigned. 311 | 312 | config EXAMPLE_CONNECT_IPV6_PREF_UNIQUE_LOCAL 313 | bool "Unique Local Link Address" 314 | help 315 | Blocks until Unique local address assigned. 316 | 317 | endchoice 318 | 319 | endif 320 | 321 | 322 | endmenu 323 | -------------------------------------------------------------------------------- /components/protocol_examples_common/addr_from_stdin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "esp_system.h" 3 | #include "esp_log.h" 4 | #include "esp_netif.h" 5 | #include "protocol_examples_common.h" 6 | 7 | #include "lwip/sockets.h" 8 | #include 9 | #include 10 | 11 | #define HOST_IP_SIZE 128 12 | 13 | esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *addr_family, struct sockaddr_storage *dest_addr) 14 | { 15 | char host_ip[HOST_IP_SIZE]; 16 | int len; 17 | static bool already_init = false; 18 | 19 | // this function could be called multiple times -> make sure UART init runs only once 20 | if (!already_init) { 21 | example_configure_stdin_stdout(); 22 | already_init = true; 23 | } 24 | 25 | // ignore empty or LF only string (could receive from DUT class) 26 | do { 27 | fgets(host_ip, HOST_IP_SIZE, stdin); 28 | len = strlen(host_ip); 29 | } while (len<=1 && host_ip[0] == '\n'); 30 | host_ip[len - 1] = '\0'; 31 | 32 | struct addrinfo hints, *addr_list, *cur; 33 | memset( &hints, 0, sizeof( hints ) ); 34 | 35 | // run getaddrinfo() to decide on the IP protocol 36 | hints.ai_family = AF_UNSPEC; 37 | hints.ai_socktype = sock_type; 38 | hints.ai_protocol = IPPROTO_TCP; 39 | if( getaddrinfo( host_ip, NULL, &hints, &addr_list ) != 0 ) { 40 | return ESP_FAIL; 41 | } 42 | for( cur = addr_list; cur != NULL; cur = cur->ai_next ) { 43 | memcpy(dest_addr, cur->ai_addr, sizeof(*dest_addr)); 44 | if (cur->ai_family == AF_INET) { 45 | *ip_protocol = IPPROTO_IP; 46 | *addr_family = AF_INET; 47 | // add port number and return on first IPv4 match 48 | ((struct sockaddr_in*)dest_addr)->sin_port = htons(port); 49 | freeaddrinfo( addr_list ); 50 | return ESP_OK; 51 | 52 | } 53 | #if CONFIG_LWIP_IPV6 54 | else if (cur->ai_family == AF_INET6) { 55 | *ip_protocol = IPPROTO_IPV6; 56 | *addr_family = AF_INET6; 57 | // add port and interface number and return on first IPv6 match 58 | ((struct sockaddr_in6*)dest_addr)->sin6_port = htons(port); 59 | ((struct sockaddr_in6*)dest_addr)->sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE); 60 | freeaddrinfo( addr_list ); 61 | return ESP_OK; 62 | } 63 | #endif 64 | } 65 | // no match found 66 | freeaddrinfo( addr_list ); 67 | return ESP_FAIL; 68 | } 69 | -------------------------------------------------------------------------------- /components/protocol_examples_common/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurFDLR/esp32-webapp/70ecda7290785cad5fd652d15a916793bb9d9359/components/protocol_examples_common/component.mk -------------------------------------------------------------------------------- /components/protocol_examples_common/connect.c: -------------------------------------------------------------------------------- 1 | /* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection. 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | 10 | #include 11 | #include "protocol_examples_common.h" 12 | #include "sdkconfig.h" 13 | #include "esp_event.h" 14 | #include "esp_wifi.h" 15 | #include "esp_wifi_default.h" 16 | #if CONFIG_EXAMPLE_CONNECT_ETHERNET 17 | #include "esp_eth.h" 18 | #if CONFIG_ETH_USE_SPI_ETHERNET 19 | #include "driver/spi_master.h" 20 | #endif // CONFIG_ETH_USE_SPI_ETHERNET 21 | #endif // CONFIG_EXAMPLE_CONNECT_ETHERNET 22 | #include "esp_log.h" 23 | #include "esp_netif.h" 24 | #include "driver/gpio.h" 25 | #include "freertos/FreeRTOS.h" 26 | #include "freertos/task.h" 27 | #include "freertos/event_groups.h" 28 | #include "lwip/err.h" 29 | #include "lwip/sys.h" 30 | 31 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 32 | #define MAX_IP6_ADDRS_PER_NETIF (5) 33 | #define NR_OF_IP_ADDRESSES_TO_WAIT_FOR (s_active_interfaces*2) 34 | 35 | #if defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK) 36 | #define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_LINK_LOCAL 37 | #elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_GLOBAL) 38 | #define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_GLOBAL 39 | #elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_SITE_LOCAL) 40 | #define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_SITE_LOCAL 41 | #elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_UNIQUE_LOCAL) 42 | #define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_UNIQUE_LOCAL 43 | #endif // if-elif CONFIG_EXAMPLE_CONNECT_IPV6_PREF_... 44 | 45 | #else 46 | #define NR_OF_IP_ADDRESSES_TO_WAIT_FOR (s_active_interfaces) 47 | #endif 48 | 49 | #define EXAMPLE_DO_CONNECT CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET 50 | 51 | #if CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST 52 | #define EXAMPLE_WIFI_SCAN_METHOD WIFI_FAST_SCAN 53 | #elif CONFIG_EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL 54 | #define EXAMPLE_WIFI_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN 55 | #endif 56 | 57 | #if CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL 58 | #define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL 59 | #elif CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY 60 | #define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY 61 | #endif 62 | 63 | #if CONFIG_EXAMPLE_WIFI_AUTH_OPEN 64 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN 65 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WEP 66 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP 67 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_PSK 68 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK 69 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_PSK 70 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK 71 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK 72 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK 73 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE 74 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_ENTERPRISE 75 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WPA3_PSK 76 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK 77 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK 78 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK 79 | #elif CONFIG_EXAMPLE_WIFI_AUTH_WAPI_PSK 80 | #define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK 81 | #endif 82 | 83 | static int s_active_interfaces = 0; 84 | static xSemaphoreHandle s_semph_get_ip_addrs; 85 | static esp_netif_t *s_example_esp_netif = NULL; 86 | 87 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 88 | static esp_ip6_addr_t s_ipv6_addr; 89 | 90 | /* types of ipv6 addresses to be displayed on ipv6 events */ 91 | static const char *s_ipv6_addr_types[] = { 92 | "ESP_IP6_ADDR_IS_UNKNOWN", 93 | "ESP_IP6_ADDR_IS_GLOBAL", 94 | "ESP_IP6_ADDR_IS_LINK_LOCAL", 95 | "ESP_IP6_ADDR_IS_SITE_LOCAL", 96 | "ESP_IP6_ADDR_IS_UNIQUE_LOCAL", 97 | "ESP_IP6_ADDR_IS_IPV4_MAPPED_IPV6" 98 | }; 99 | #endif 100 | 101 | static const char *TAG = "example_connect"; 102 | 103 | #if CONFIG_EXAMPLE_CONNECT_WIFI 104 | static esp_netif_t *wifi_start(void); 105 | static void wifi_stop(void); 106 | #endif 107 | #if CONFIG_EXAMPLE_CONNECT_ETHERNET 108 | static esp_netif_t *eth_start(void); 109 | static void eth_stop(void); 110 | #endif 111 | 112 | /** 113 | * @brief Checks the netif description if it contains specified prefix. 114 | * All netifs created withing common connect component are prefixed with the module TAG, 115 | * so it returns true if the specified netif is owned by this module 116 | */ 117 | static bool is_our_netif(const char *prefix, esp_netif_t *netif) 118 | { 119 | return strncmp(prefix, esp_netif_get_desc(netif), strlen(prefix) - 1) == 0; 120 | } 121 | 122 | /* set up connection, Wi-Fi and/or Ethernet */ 123 | static void start(void) 124 | { 125 | 126 | #if CONFIG_EXAMPLE_CONNECT_WIFI 127 | s_example_esp_netif = wifi_start(); 128 | s_active_interfaces++; 129 | #endif 130 | 131 | #if CONFIG_EXAMPLE_CONNECT_ETHERNET 132 | s_example_esp_netif = eth_start(); 133 | s_active_interfaces++; 134 | #endif 135 | 136 | #if CONFIG_EXAMPLE_CONNECT_WIFI && CONFIG_EXAMPLE_CONNECT_ETHERNET 137 | /* if both intefaces at once, clear out to indicate that multiple netifs are active */ 138 | s_example_esp_netif = NULL; 139 | #endif 140 | 141 | #if EXAMPLE_DO_CONNECT 142 | /* create semaphore if at least one interface is active */ 143 | s_semph_get_ip_addrs = xSemaphoreCreateCounting(NR_OF_IP_ADDRESSES_TO_WAIT_FOR, 0); 144 | #endif 145 | 146 | } 147 | 148 | /* tear down connection, release resources */ 149 | static void stop(void) 150 | { 151 | #if CONFIG_EXAMPLE_CONNECT_WIFI 152 | wifi_stop(); 153 | s_active_interfaces--; 154 | #endif 155 | 156 | #if CONFIG_EXAMPLE_CONNECT_ETHERNET 157 | eth_stop(); 158 | s_active_interfaces--; 159 | #endif 160 | } 161 | 162 | #if EXAMPLE_DO_CONNECT 163 | static esp_ip4_addr_t s_ip_addr; 164 | 165 | static void on_got_ip(void *arg, esp_event_base_t event_base, 166 | int32_t event_id, void *event_data) 167 | { 168 | ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; 169 | if (!is_our_netif(TAG, event->esp_netif)) { 170 | ESP_LOGW(TAG, "Got IPv4 from another interface \"%s\": ignored", esp_netif_get_desc(event->esp_netif)); 171 | return; 172 | } 173 | ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip)); 174 | memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr)); 175 | xSemaphoreGive(s_semph_get_ip_addrs); 176 | } 177 | #endif 178 | 179 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 180 | 181 | static void on_got_ipv6(void *arg, esp_event_base_t event_base, 182 | int32_t event_id, void *event_data) 183 | { 184 | ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; 185 | if (!is_our_netif(TAG, event->esp_netif)) { 186 | ESP_LOGW(TAG, "Got IPv6 from another netif: ignored"); 187 | return; 188 | } 189 | esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip); 190 | ESP_LOGI(TAG, "Got IPv6 event: Interface \"%s\" address: " IPV6STR ", type: %s", esp_netif_get_desc(event->esp_netif), 191 | IPV62STR(event->ip6_info.ip), s_ipv6_addr_types[ipv6_type]); 192 | if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) { 193 | memcpy(&s_ipv6_addr, &event->ip6_info.ip, sizeof(s_ipv6_addr)); 194 | xSemaphoreGive(s_semph_get_ip_addrs); 195 | } 196 | } 197 | 198 | #endif // CONFIG_EXAMPLE_CONNECT_IPV6 199 | 200 | esp_err_t example_connect(void) 201 | { 202 | #if EXAMPLE_DO_CONNECT 203 | if (s_semph_get_ip_addrs != NULL) { 204 | return ESP_ERR_INVALID_STATE; 205 | } 206 | #endif 207 | start(); 208 | ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop)); 209 | ESP_LOGI(TAG, "Waiting for IP(s)"); 210 | for (int i = 0; i < NR_OF_IP_ADDRESSES_TO_WAIT_FOR; ++i) { 211 | xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY); 212 | } 213 | // iterate over active interfaces, and print out IPs of "our" netifs 214 | esp_netif_t *netif = NULL; 215 | esp_netif_ip_info_t ip; 216 | for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) { 217 | netif = esp_netif_next(netif); 218 | if (is_our_netif(TAG, netif)) { 219 | ESP_LOGI(TAG, "Connected to %s", esp_netif_get_desc(netif)); 220 | ESP_ERROR_CHECK(esp_netif_get_ip_info(netif, &ip)); 221 | 222 | ESP_LOGI(TAG, "- IPv4 address: " IPSTR, IP2STR(&ip.ip)); 223 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 224 | esp_ip6_addr_t ip6[MAX_IP6_ADDRS_PER_NETIF]; 225 | int ip6_addrs = esp_netif_get_all_ip6(netif, ip6); 226 | for (int j = 0; j < ip6_addrs; ++j) { 227 | esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j])); 228 | ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(ip6[j]), s_ipv6_addr_types[ipv6_type]); 229 | } 230 | #endif 231 | 232 | } 233 | } 234 | return ESP_OK; 235 | } 236 | 237 | esp_err_t example_disconnect(void) 238 | { 239 | if (s_semph_get_ip_addrs == NULL) { 240 | return ESP_ERR_INVALID_STATE; 241 | } 242 | vSemaphoreDelete(s_semph_get_ip_addrs); 243 | s_semph_get_ip_addrs = NULL; 244 | stop(); 245 | ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&stop)); 246 | return ESP_OK; 247 | } 248 | 249 | #ifdef CONFIG_EXAMPLE_CONNECT_WIFI 250 | 251 | static void on_wifi_disconnect(void *arg, esp_event_base_t event_base, 252 | int32_t event_id, void *event_data) 253 | { 254 | ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect..."); 255 | esp_err_t err = esp_wifi_connect(); 256 | if (err == ESP_ERR_WIFI_NOT_STARTED) { 257 | return; 258 | } 259 | ESP_ERROR_CHECK(err); 260 | } 261 | 262 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 263 | 264 | static void on_wifi_connect(void *esp_netif, esp_event_base_t event_base, 265 | int32_t event_id, void *event_data) 266 | { 267 | esp_netif_create_ip6_linklocal(esp_netif); 268 | } 269 | 270 | #endif // CONFIG_EXAMPLE_CONNECT_IPV6 271 | 272 | static esp_netif_t *wifi_start(void) 273 | { 274 | char *desc; 275 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 276 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 277 | 278 | esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA(); 279 | // Prefix the interface description with the module TAG 280 | // Warning: the interface desc is used in tests to capture actual connection details (IP, gw, mask) 281 | asprintf(&desc, "%s: %s", TAG, esp_netif_config.if_desc); 282 | esp_netif_config.if_desc = desc; 283 | esp_netif_config.route_prio = 128; 284 | esp_netif_t *netif = esp_netif_create_wifi(WIFI_IF_STA, &esp_netif_config); 285 | free(desc); 286 | esp_wifi_set_default_wifi_sta_handlers(); 287 | 288 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, NULL)); 289 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip, NULL)); 290 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 291 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &on_wifi_connect, netif)); 292 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL)); 293 | #endif 294 | 295 | ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); 296 | wifi_config_t wifi_config = { 297 | .sta = { 298 | .ssid = CONFIG_EXAMPLE_WIFI_SSID, 299 | .password = CONFIG_EXAMPLE_WIFI_PASSWORD, 300 | .scan_method = EXAMPLE_WIFI_SCAN_METHOD, 301 | .sort_method = EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD, 302 | .threshold.rssi = CONFIG_EXAMPLE_WIFI_SCAN_RSSI_THRESHOLD, 303 | .threshold.authmode = EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD, 304 | }, 305 | }; 306 | ESP_LOGI(TAG, "Connecting to %s...", wifi_config.sta.ssid); 307 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); 308 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); 309 | ESP_ERROR_CHECK(esp_wifi_start()); 310 | esp_wifi_connect(); 311 | return netif; 312 | } 313 | 314 | static void wifi_stop(void) 315 | { 316 | esp_netif_t *wifi_netif = get_example_netif_from_desc("sta"); 317 | ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect)); 318 | ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip)); 319 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 320 | ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6)); 321 | ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &on_wifi_connect)); 322 | #endif 323 | esp_err_t err = esp_wifi_stop(); 324 | if (err == ESP_ERR_WIFI_NOT_INIT) { 325 | return; 326 | } 327 | ESP_ERROR_CHECK(err); 328 | ESP_ERROR_CHECK(esp_wifi_deinit()); 329 | ESP_ERROR_CHECK(esp_wifi_clear_default_wifi_driver_and_handlers(wifi_netif)); 330 | esp_netif_destroy(wifi_netif); 331 | s_example_esp_netif = NULL; 332 | } 333 | #endif // CONFIG_EXAMPLE_CONNECT_WIFI 334 | 335 | #ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET 336 | 337 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 338 | 339 | /** Event handler for Ethernet events */ 340 | static void on_eth_event(void *esp_netif, esp_event_base_t event_base, 341 | int32_t event_id, void *event_data) 342 | { 343 | switch (event_id) { 344 | case ETHERNET_EVENT_CONNECTED: 345 | ESP_LOGI(TAG, "Ethernet Link Up"); 346 | ESP_ERROR_CHECK(esp_netif_create_ip6_linklocal(esp_netif)); 347 | break; 348 | default: 349 | break; 350 | } 351 | } 352 | 353 | #endif // CONFIG_EXAMPLE_CONNECT_IPV6 354 | 355 | static esp_eth_handle_t s_eth_handle = NULL; 356 | static esp_eth_mac_t *s_mac = NULL; 357 | static esp_eth_phy_t *s_phy = NULL; 358 | static esp_eth_netif_glue_handle_t s_eth_glue = NULL; 359 | 360 | static esp_netif_t *eth_start(void) 361 | { 362 | char *desc; 363 | esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); 364 | // Prefix the interface description with the module TAG 365 | // Warning: the interface desc is used in tests to capture actual connection details (IP, gw, mask) 366 | asprintf(&desc, "%s: %s", TAG, esp_netif_config.if_desc); 367 | esp_netif_config.if_desc = desc; 368 | esp_netif_config.route_prio = 64; 369 | esp_netif_config_t netif_config = { 370 | .base = &esp_netif_config, 371 | .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH 372 | }; 373 | esp_netif_t *netif = esp_netif_new(&netif_config); 374 | assert(netif); 375 | free(desc); 376 | 377 | eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); 378 | eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); 379 | phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; 380 | phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; 381 | #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET 382 | mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; 383 | mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; 384 | s_mac = esp_eth_mac_new_esp32(&mac_config); 385 | #if CONFIG_EXAMPLE_ETH_PHY_IP101 386 | s_phy = esp_eth_phy_new_ip101(&phy_config); 387 | #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201 388 | s_phy = esp_eth_phy_new_rtl8201(&phy_config); 389 | #elif CONFIG_EXAMPLE_ETH_PHY_LAN87XX 390 | s_phy = esp_eth_phy_new_lan87xx(&phy_config); 391 | #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 392 | s_phy = esp_eth_phy_new_dp83848(&phy_config); 393 | #endif 394 | #elif CONFIG_EXAMPLE_USE_SPI_ETHERNET 395 | gpio_install_isr_service(0); 396 | spi_device_handle_t spi_handle = NULL; 397 | spi_bus_config_t buscfg = { 398 | .miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO, 399 | .mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO, 400 | .sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO, 401 | .quadwp_io_num = -1, 402 | .quadhd_io_num = -1, 403 | }; 404 | ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); 405 | #if CONFIG_EXAMPLE_USE_DM9051 406 | spi_device_interface_config_t devcfg = { 407 | .command_bits = 1, 408 | .address_bits = 7, 409 | .mode = 0, 410 | .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, 411 | .spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO, 412 | .queue_size = 20 413 | }; 414 | ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); 415 | /* dm9051 ethernet driver is based on spi driver */ 416 | eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); 417 | dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO; 418 | s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); 419 | s_phy = esp_eth_phy_new_dm9051(&phy_config); 420 | #elif CONFIG_EXAMPLE_USE_W5500 421 | spi_device_interface_config_t devcfg = { 422 | .command_bits = 16, // Actually it's the address phase in W5500 SPI frame 423 | .address_bits = 8, // Actually it's the control phase in W5500 SPI frame 424 | .mode = 0, 425 | .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, 426 | .spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO, 427 | .queue_size = 20 428 | }; 429 | ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); 430 | /* w5500 ethernet driver is based on spi driver */ 431 | eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); 432 | w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO; 433 | s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); 434 | s_phy = esp_eth_phy_new_w5500(&phy_config); 435 | #endif 436 | #elif CONFIG_EXAMPLE_USE_OPENETH 437 | phy_config.autonego_timeout_ms = 100; 438 | s_mac = esp_eth_mac_new_openeth(&mac_config); 439 | s_phy = esp_eth_phy_new_dp83848(&phy_config); 440 | #endif 441 | 442 | // Install Ethernet driver 443 | esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); 444 | ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); 445 | #if !CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET 446 | /* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually. 447 | 02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control. 448 | */ 449 | ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) { 450 | 0x02, 0x00, 0x00, 0x12, 0x34, 0x56 451 | })); 452 | #endif 453 | // combine driver with netif 454 | s_eth_glue = esp_eth_new_netif_glue(s_eth_handle); 455 | esp_netif_attach(netif, s_eth_glue); 456 | 457 | // Register user defined event handers 458 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL)); 459 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 460 | ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event, netif)); 461 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL)); 462 | #endif 463 | 464 | esp_eth_start(s_eth_handle); 465 | return netif; 466 | } 467 | 468 | static void eth_stop(void) 469 | { 470 | esp_netif_t *eth_netif = get_example_netif_from_desc("eth"); 471 | ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip)); 472 | #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 473 | ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6)); 474 | ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event)); 475 | #endif 476 | ESP_ERROR_CHECK(esp_eth_stop(s_eth_handle)); 477 | ESP_ERROR_CHECK(esp_eth_del_netif_glue(s_eth_glue)); 478 | ESP_ERROR_CHECK(esp_eth_driver_uninstall(s_eth_handle)); 479 | ESP_ERROR_CHECK(s_phy->del(s_phy)); 480 | ESP_ERROR_CHECK(s_mac->del(s_mac)); 481 | 482 | esp_netif_destroy(eth_netif); 483 | s_example_esp_netif = NULL; 484 | } 485 | 486 | #endif // CONFIG_EXAMPLE_CONNECT_ETHERNET 487 | 488 | esp_netif_t *get_example_netif(void) 489 | { 490 | return s_example_esp_netif; 491 | } 492 | 493 | esp_netif_t *get_example_netif_from_desc(const char *desc) 494 | { 495 | esp_netif_t *netif = NULL; 496 | char *expected_desc; 497 | asprintf(&expected_desc, "%s: %s", TAG, desc); 498 | while ((netif = esp_netif_next(netif)) != NULL) { 499 | if (strcmp(esp_netif_get_desc(netif), expected_desc) == 0) { 500 | free(expected_desc); 501 | return netif; 502 | } 503 | } 504 | free(expected_desc); 505 | return netif; 506 | } 507 | -------------------------------------------------------------------------------- /components/protocol_examples_common/include/addr_from_stdin.h: -------------------------------------------------------------------------------- 1 | /* Common utilities for socket address input interface: 2 | The API get_addr_from_stdin() is mainly used by socket client examples which read IP address from stdin (if configured). 3 | This option is typically used in the CI, but could be enabled in the project configuration. 4 | In that case this component is used to receive a string that is evaluated and processed to output 5 | socket structures to open a connectio 6 | This example code is in the Public Domain (or CC0 licensed, at your option.) 7 | 8 | Unless required by applicable law or agreed to in writing, this 9 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | CONDITIONS OF ANY KIND, either express or implied. 11 | */ 12 | 13 | #pragma once 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #include "lwip/sys.h" 20 | #include 21 | #include 22 | 23 | /** 24 | * @brief Read and evaluate IP address from stdin 25 | * 26 | * This API reads stdin and parses the input address using getaddrinfo() 27 | * to fill in struct sockaddr_storage (for both IPv4 and IPv6) used to open 28 | * a socket. IP protocol is guessed from the IP address string. 29 | * 30 | * @param[in] port port number of expected connection 31 | * @param[in] sock_type expected protocol: SOCK_STREAM or SOCK_DGRAM 32 | * @param[out] ip_protocol resultant IP protocol: IPPROTO_IP or IPPROTO_IP6 33 | * @param[out] addr_family resultant address family: AF_INET or AF_INET6 34 | * @param[out] dest_addr sockaddr_storage structure (for both IPv4 and IPv6) 35 | * @return ESP_OK on success, ESP_FAIL otherwise 36 | */ 37 | esp_err_t get_addr_from_stdin(int port, int sock_type, 38 | int *ip_protocol, 39 | int *addr_family, 40 | struct sockaddr_storage *dest_addr); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /components/protocol_examples_common/include/protocol_examples_common.h: -------------------------------------------------------------------------------- 1 | /* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection. 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | 10 | #pragma once 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include "esp_err.h" 17 | #include "esp_netif.h" 18 | 19 | #ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET 20 | #define EXAMPLE_INTERFACE get_example_netif() 21 | #endif 22 | 23 | #ifdef CONFIG_EXAMPLE_CONNECT_WIFI 24 | #define EXAMPLE_INTERFACE get_example_netif() 25 | #endif 26 | 27 | #if !defined (CONFIG_EXAMPLE_CONNECT_ETHERNET) && !defined (CONFIG_EXAMPLE_CONNECT_WIFI) 28 | // This is useful for some tests which do not need a network connection 29 | #define EXAMPLE_INTERFACE NULL 30 | #endif 31 | 32 | /** 33 | * @brief Configure Wi-Fi or Ethernet, connect, wait for IP 34 | * 35 | * This all-in-one helper function is used in protocols examples to 36 | * reduce the amount of boilerplate in the example. 37 | * 38 | * It is not intended to be used in real world applications. 39 | * See examples under examples/wifi/getting_started/ and examples/ethernet/ 40 | * for more complete Wi-Fi or Ethernet initialization code. 41 | * 42 | * Read "Establishing Wi-Fi or Ethernet Connection" section in 43 | * examples/protocols/README.md for more information about this function. 44 | * 45 | * @return ESP_OK on successful connection 46 | */ 47 | esp_err_t example_connect(void); 48 | 49 | /** 50 | * Counterpart to example_connect, de-initializes Wi-Fi or Ethernet 51 | */ 52 | esp_err_t example_disconnect(void); 53 | 54 | /** 55 | * @brief Configure stdin and stdout to use blocking I/O 56 | * 57 | * This helper function is used in ASIO examples. It wraps installing the 58 | * UART driver and configuring VFS layer to use UART driver for console I/O. 59 | */ 60 | esp_err_t example_configure_stdin_stdout(void); 61 | 62 | /** 63 | * @brief Returns esp-netif pointer created by example_connect() 64 | * 65 | * @note If multiple interfaces active at once, this API return NULL 66 | * In that case the get_example_netif_from_desc() should be used 67 | * to get esp-netif pointer based on interface description 68 | */ 69 | esp_netif_t *get_example_netif(void); 70 | 71 | /** 72 | * @brief Returns esp-netif pointer created by example_connect() described by 73 | * the supplied desc field 74 | * 75 | * @param desc Textual interface of created network interface, for example "sta" 76 | * indicate default WiFi station, "eth" default Ethernet interface. 77 | * 78 | */ 79 | esp_netif_t *get_example_netif_from_desc(const char *desc); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | -------------------------------------------------------------------------------- /components/protocol_examples_common/stdin_out.c: -------------------------------------------------------------------------------- 1 | /* Common functions for protocol examples, to configure stdin and stdout. 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | 10 | #include "protocol_examples_common.h" 11 | #include "esp_err.h" 12 | #include "esp_vfs_dev.h" 13 | #include "driver/uart.h" 14 | #include "sdkconfig.h" 15 | 16 | esp_err_t example_configure_stdin_stdout(void) 17 | { 18 | // Initialize VFS & UART so we can use std::cout/cin 19 | setvbuf(stdin, NULL, _IONBF, 0); 20 | /* Install UART driver for interrupt-driven reads and writes */ 21 | ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_ESP_CONSOLE_UART_NUM, 22 | 256, 0, 0, NULL, 0) ); 23 | /* Tell VFS to use UART driver */ 24 | esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); 25 | esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); 26 | /* Move the caret to the beginning of the next line on '\n' */ 27 | esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); 28 | return ESP_OK; 29 | } 30 | -------------------------------------------------------------------------------- /front/web-blinker/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /front/web-blinker/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /front/web-blinker/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /front/web-blinker/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | 23 | # APIs used in this example is simple and stable enough. 24 | # There shouldn't be risk of compatibility unless the major version of some library changed. 25 | # To compress the package size, just exclude the package-lock.json file. 26 | package-lock.json 27 | -------------------------------------------------------------------------------- /front/web-blinker/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /front/web-blinker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-blinker", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@nuxtjs/vuetify": "^2.0.0-beta.2", 12 | "axios": "^0.21.4", 13 | "core-js": "^2.6.12", 14 | "vue": "^2.7.10", 15 | "vue-router": "^3.6.4", 16 | "vuetify": "^2.6.9", 17 | "vuex": "^3.6.2" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "^3.12.1", 21 | "@vue/cli-plugin-eslint": "^3.12.1", 22 | "@vue/cli-service": "^3.12.1", 23 | "@vue/eslint-config-standard": "^4.0.0", 24 | "babel-eslint": "^10.1.0", 25 | "eslint": "^5.16.0", 26 | "eslint-plugin-vue": "^5.2.3", 27 | "stylus": "^0.54.8", 28 | "stylus-loader": "^3.0.2", 29 | "vue-cli-plugin-vuetify": "^0.5.0", 30 | "vue-template-compiler": "^2.7.10", 31 | "vuetify-loader": "^1.9.2", 32 | "webpack-bundle-analyzer": "^4.6.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /front/web-blinker/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /front/web-blinker/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurFDLR/esp32-webapp/70ecda7290785cad5fd652d15a916793bb9d9359/front/web-blinker/public/favicon.ico -------------------------------------------------------------------------------- /front/web-blinker/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ESP-Blinker 9 | 10 | 11 | 12 | 13 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /front/web-blinker/src/App.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 59 | -------------------------------------------------------------------------------- /front/web-blinker/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurFDLR/esp32-webapp/70ecda7290785cad5fd652d15a916793bb9d9359/front/web-blinker/src/assets/logo.png -------------------------------------------------------------------------------- /front/web-blinker/src/components/Blinker.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 144 | 145 | 161 | -------------------------------------------------------------------------------- /front/web-blinker/src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 41 | -------------------------------------------------------------------------------- /front/web-blinker/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import vuetify from './plugins/vuetify' 4 | 5 | import router from './router' 6 | import axios from 'axios' 7 | 8 | Vue.config.productionTip = false 9 | 10 | Vue.prototype.$ajax = axios 11 | 12 | new Vue({ 13 | vuetify, 14 | router, 15 | render: h => h(App) 16 | }).$mount('#app') 17 | -------------------------------------------------------------------------------- /front/web-blinker/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuetify from 'vuetify/lib' 3 | 4 | Vue.use(Vuetify) 5 | 6 | export default new Vuetify({ 7 | icons: { 8 | iconfont: 'md' 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /front/web-blinker/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from './components/Home.vue' 4 | import Blinker from './components/Blinker.vue' 5 | 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | mode: 'history', 10 | base: process.env.BASE_URL, 11 | routes: [ 12 | { 13 | path: '/', 14 | name: 'home', 15 | component: Home 16 | }, 17 | { 18 | path: '/blinker', 19 | name: 'blinker', 20 | component: Blinker 21 | } 22 | ] 23 | }) 24 | -------------------------------------------------------------------------------- /front/web-blinker/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | devServer: { 3 | proxy: { 4 | '/api': { 5 | target: 'http://web-blinker.local:80', 6 | changeOrigin: true, 7 | ws: true 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "esp_rest_main.c" 2 | "rest_server.c" 3 | INCLUDE_DIRS ".") 4 | 5 | if(CONFIG_EXAMPLE_WEB_DEPLOY_SF) 6 | set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../front/web-blinker") 7 | if(EXISTS ${WEB_SRC_DIR}/dist) 8 | spiffs_create_partition_image(www ${WEB_SRC_DIR}/dist FLASH_IN_PROJECT) 9 | else() 10 | message(FATAL_ERROR "${WEB_SRC_DIR}/dist doesn't exit. Please run 'npm run build' in ${WEB_SRC_DIR}") 11 | endif() 12 | endif() 13 | -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Example Configuration" 2 | 3 | config BLINK_GPIO 4 | int "Blink GPIO number" 5 | range 0 48 6 | default 21 7 | help 8 | GPIO number (IOxx) to blink on and off. 9 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. 10 | 11 | config EXAMPLE_MDNS_HOST_NAME 12 | string "mDNS Host Name" 13 | default "esp-blinker" 14 | help 15 | Specify the domain name used in the mDNS service. 16 | Note that webpage also take it as a part of URL where it will send GET/POST requests to. 17 | 18 | choice EXAMPLE_WEB_DEPLOY_MODE 19 | prompt "Website deploy mode" 20 | default EXAMPLE_WEB_DEPLOY_SF 21 | help 22 | Select website deploy mode. 23 | You can deploy website to host, and ESP32 will retrieve them in a semihost way (JTAG is needed). 24 | You can deploy website to SD card or SPI flash, and ESP32 will retrieve them via SDIO/SPI interface. 25 | Detailed operation steps are listed in the example README file. 26 | config EXAMPLE_WEB_DEPLOY_SEMIHOST 27 | bool "Deploy website to host (JTAG is needed)" 28 | help 29 | Deploy website to host. 30 | It is recommended to choose this mode during developing. 31 | config EXAMPLE_WEB_DEPLOY_SD 32 | depends on IDF_TARGET_ESP32 33 | bool "Deploy website to SD card" 34 | help 35 | Deploy website to SD card. 36 | Choose this production mode if the size of website is too large (bigger than 2MB). 37 | config EXAMPLE_WEB_DEPLOY_SF 38 | bool "Deploy website to SPI Nor Flash" 39 | help 40 | Deploy website to SPI Nor Flash. 41 | Choose this production mode if the size of website is small (less than 2MB). 42 | endchoice 43 | 44 | if EXAMPLE_WEB_DEPLOY_SEMIHOST 45 | config EXAMPLE_HOST_PATH_TO_MOUNT 46 | string "Host path to mount (e.g. absolute path to web dist directory)" 47 | default "PATH-TO-WEB-DIST_DIR" 48 | help 49 | When using semihost in ESP32, you should specify the host path which will be mounted to VFS. 50 | Note that only absolute path is acceptable. 51 | endif 52 | 53 | config EXAMPLE_WEB_MOUNT_POINT 54 | string "Website mount point in VFS" 55 | default "/www" 56 | help 57 | Specify the mount point in VFS. 58 | 59 | endmenu 60 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurFDLR/esp32-webapp/70ecda7290785cad5fd652d15a916793bb9d9359/main/component.mk -------------------------------------------------------------------------------- /main/esp_rest_main.c: -------------------------------------------------------------------------------- 1 | /* HTTP Restful API Server Example 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | #include "sdkconfig.h" 10 | #include "driver/gpio.h" 11 | #include "esp_vfs_semihost.h" 12 | #include "esp_vfs_fat.h" 13 | #include "esp_spiffs.h" 14 | #include "sdmmc_cmd.h" 15 | #include "nvs_flash.h" 16 | #include "esp_netif.h" 17 | #include "esp_event.h" 18 | #include "esp_log.h" 19 | #include "mdns.h" 20 | #include "lwip/apps/netbiosns.h" 21 | #include "stdatomic.h" 22 | #include "protocol_examples_common.h" 23 | #if CONFIG_EXAMPLE_WEB_DEPLOY_SD 24 | #include "driver/sdmmc_host.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #define MDNS_INSTANCE "esp home web server" 32 | 33 | static const char *TAG = "example"; 34 | static const char *BLINK_TAG = "blinker"; 35 | 36 | esp_err_t start_rest_server(const char *base_path); 37 | 38 | static void initialise_mdns(void) 39 | { 40 | mdns_init(); 41 | mdns_hostname_set(CONFIG_EXAMPLE_MDNS_HOST_NAME); 42 | mdns_instance_name_set(MDNS_INSTANCE); 43 | 44 | mdns_txt_item_t serviceTxtData[] = { 45 | {"board", "esp32"}, 46 | {"path", "/"} 47 | }; 48 | 49 | ESP_ERROR_CHECK(mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 50 | sizeof(serviceTxtData) / sizeof(serviceTxtData[0]))); 51 | ESP_LOGE(TAG, "MDNS Hostname set to %s", CONFIG_EXAMPLE_MDNS_HOST_NAME); 52 | } 53 | 54 | #if CONFIG_EXAMPLE_WEB_DEPLOY_SEMIHOST 55 | esp_err_t init_fs(void) 56 | { 57 | esp_err_t ret = esp_vfs_semihost_register(CONFIG_EXAMPLE_WEB_MOUNT_POINT); 58 | if (ret != ESP_OK) { 59 | ESP_LOGE(TAG, "Failed to register semihost driver (%s)!", esp_err_to_name(ret)); 60 | return ESP_FAIL; 61 | } 62 | return ESP_OK; 63 | } 64 | #endif 65 | 66 | #if CONFIG_EXAMPLE_WEB_DEPLOY_SD 67 | esp_err_t init_fs(void) 68 | { 69 | sdmmc_host_t host = SDMMC_HOST_DEFAULT(); 70 | sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); 71 | 72 | gpio_set_pull_mode(15, GPIO_PULLUP_ONLY); // CMD 73 | gpio_set_pull_mode(2, GPIO_PULLUP_ONLY); // D0 74 | gpio_set_pull_mode(4, GPIO_PULLUP_ONLY); // D1 75 | gpio_set_pull_mode(12, GPIO_PULLUP_ONLY); // D2 76 | gpio_set_pull_mode(13, GPIO_PULLUP_ONLY); // D3 77 | 78 | esp_vfs_fat_sdmmc_mount_config_t mount_config = { 79 | .format_if_mount_failed = true, 80 | .max_files = 4, 81 | .allocation_unit_size = 16 * 1024 82 | }; 83 | 84 | sdmmc_card_t *card; 85 | esp_err_t ret = esp_vfs_fat_sdmmc_mount(CONFIG_EXAMPLE_WEB_MOUNT_POINT, &host, &slot_config, &mount_config, &card); 86 | if (ret != ESP_OK) { 87 | if (ret == ESP_FAIL) { 88 | ESP_LOGE(TAG, "Failed to mount filesystem."); 89 | } else { 90 | ESP_LOGE(TAG, "Failed to initialize the card (%s)", esp_err_to_name(ret)); 91 | } 92 | return ESP_FAIL; 93 | } 94 | /* print card info if mount successfully */ 95 | sdmmc_card_print_info(stdout, card); 96 | return ESP_OK; 97 | } 98 | #endif 99 | 100 | #if CONFIG_EXAMPLE_WEB_DEPLOY_SF 101 | esp_err_t init_fs(void) 102 | { 103 | esp_vfs_spiffs_conf_t conf = { 104 | .base_path = CONFIG_EXAMPLE_WEB_MOUNT_POINT, 105 | .partition_label = NULL, 106 | .max_files = 5, 107 | .format_if_mount_failed = false 108 | }; 109 | esp_err_t ret = esp_vfs_spiffs_register(&conf); 110 | 111 | if (ret != ESP_OK) { 112 | if (ret == ESP_FAIL) { 113 | ESP_LOGE(TAG, "Failed to mount or format filesystem"); 114 | } else if (ret == ESP_ERR_NOT_FOUND) { 115 | ESP_LOGE(TAG, "Failed to find SPIFFS partition"); 116 | } else { 117 | ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); 118 | } 119 | return ESP_FAIL; 120 | } 121 | 122 | size_t total = 0, used = 0; 123 | ret = esp_spiffs_info(NULL, &total, &used); 124 | if (ret != ESP_OK) { 125 | ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); 126 | } else { 127 | ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); 128 | } 129 | return ESP_OK; 130 | } 131 | #endif 132 | 133 | // From rest_server.c 134 | extern atomic_int blinker_duration_ms_atomic; 135 | extern atomic_bool blinker_state_atomic; 136 | 137 | void led_blinker(void *pvParams) { 138 | gpio_reset_pin(CONFIG_BLINK_GPIO); 139 | gpio_set_direction(CONFIG_BLINK_GPIO, GPIO_MODE_OUTPUT); 140 | 141 | uint8_t s_led_state = 0; 142 | while (true) { 143 | if (blinker_state_atomic) 144 | { 145 | s_led_state = !s_led_state; 146 | } else 147 | { 148 | s_led_state = 0; 149 | } 150 | gpio_set_level(CONFIG_BLINK_GPIO,s_led_state); 151 | vTaskDelay((blinker_duration_ms_atomic / 2) / portTICK_PERIOD_MS); 152 | } 153 | } 154 | 155 | void start_led_blinker( void ) 156 | { 157 | static uint8_t ucParameterToPass; 158 | TaskHandle_t xHandle = NULL; 159 | 160 | // Create the task, storing the handle. Note that the passed parameter ucParameterToPass 161 | // must exist for the lifetime of the task, so in this case is declared static. If it was just an 162 | // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time 163 | // the new task attempts to access it. 164 | ESP_LOGI(BLINK_TAG, "Create LED_BLINKER task on GPIO %d", CONFIG_BLINK_GPIO); 165 | xTaskCreate( led_blinker, "LED_BLINKER", 4096, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle ); 166 | configASSERT( xHandle ); 167 | 168 | // Use the handle to delete the task. 169 | // if( xHandle != NULL ) 170 | // { 171 | // ESP_LOGI(BLINK_TAG, "Delete LED_BLINKER task"); 172 | // vTaskDelete( xHandle ); 173 | // } 174 | } 175 | 176 | void app_main(void) 177 | { 178 | ESP_ERROR_CHECK(nvs_flash_init()); 179 | ESP_ERROR_CHECK(esp_netif_init()); 180 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 181 | initialise_mdns(); 182 | netbiosns_init(); 183 | netbiosns_set_name(CONFIG_EXAMPLE_MDNS_HOST_NAME); 184 | 185 | ESP_ERROR_CHECK(example_connect()); 186 | ESP_ERROR_CHECK(init_fs()); 187 | ESP_ERROR_CHECK(start_rest_server(CONFIG_EXAMPLE_WEB_MOUNT_POINT)); 188 | 189 | start_led_blinker(); 190 | } 191 | -------------------------------------------------------------------------------- /main/rest_server.c: -------------------------------------------------------------------------------- 1 | /* HTTP Restful API Server 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | #include 10 | #include 11 | #include "esp_http_server.h" 12 | #include "esp_system.h" 13 | #include "esp_log.h" 14 | #include "esp_vfs.h" 15 | #include "cJSON.h" 16 | #include "stdatomic.h" 17 | 18 | static const char *REST_TAG = "esp-rest"; 19 | #define REST_CHECK(a, str, goto_tag, ...) \ 20 | do \ 21 | { \ 22 | if (!(a)) \ 23 | { \ 24 | ESP_LOGE(REST_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 25 | goto goto_tag; \ 26 | } \ 27 | } while (0) 28 | 29 | #define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128) 30 | #define SCRATCH_BUFSIZE (10240) 31 | 32 | typedef struct rest_server_context { 33 | char base_path[ESP_VFS_PATH_MAX + 1]; 34 | char scratch[SCRATCH_BUFSIZE]; 35 | } rest_server_context_t; 36 | 37 | #define CHECK_FILE_EXTENSION(filename, ext) (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0) 38 | 39 | /* Set HTTP response content type according to file extension */ 40 | static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath) 41 | { 42 | const char *type = "text/plain"; 43 | if (CHECK_FILE_EXTENSION(filepath, ".html")) { 44 | type = "text/html"; 45 | } else if (CHECK_FILE_EXTENSION(filepath, ".js")) { 46 | type = "application/javascript"; 47 | } else if (CHECK_FILE_EXTENSION(filepath, ".css")) { 48 | type = "text/css"; 49 | } else if (CHECK_FILE_EXTENSION(filepath, ".png")) { 50 | type = "image/png"; 51 | } else if (CHECK_FILE_EXTENSION(filepath, ".ico")) { 52 | type = "image/x-icon"; 53 | } else if (CHECK_FILE_EXTENSION(filepath, ".svg")) { 54 | type = "text/xml"; 55 | } 56 | return httpd_resp_set_type(req, type); 57 | } 58 | 59 | /* Send HTTP response with the contents of the requested file */ 60 | static esp_err_t rest_common_get_handler(httpd_req_t *req) 61 | { 62 | char filepath[FILE_PATH_MAX]; 63 | 64 | rest_server_context_t *rest_context = (rest_server_context_t *)req->user_ctx; 65 | strlcpy(filepath, rest_context->base_path, sizeof(filepath)); 66 | if (req->uri[strlen(req->uri) - 1] == '/') { 67 | strlcat(filepath, "/index.html", sizeof(filepath)); 68 | } else { 69 | strlcat(filepath, req->uri, sizeof(filepath)); 70 | } 71 | int fd = open(filepath, O_RDONLY, 0); 72 | if (fd == -1) { 73 | ESP_LOGE(REST_TAG, "Failed to open file : %s", filepath); 74 | /* Respond with 500 Internal Server Error */ 75 | httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file"); 76 | return ESP_FAIL; 77 | } 78 | 79 | set_content_type_from_file(req, filepath); 80 | 81 | char *chunk = rest_context->scratch; 82 | ssize_t read_bytes; 83 | do { 84 | /* Read file in chunks into the scratch buffer */ 85 | read_bytes = read(fd, chunk, SCRATCH_BUFSIZE); 86 | if (read_bytes == -1) { 87 | ESP_LOGE(REST_TAG, "Failed to read file : %s", filepath); 88 | } else if (read_bytes > 0) { 89 | /* Send the buffer contents as HTTP response chunk */ 90 | if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) { 91 | close(fd); 92 | ESP_LOGE(REST_TAG, "File sending failed!"); 93 | /* Abort sending file */ 94 | httpd_resp_sendstr_chunk(req, NULL); 95 | /* Respond with 500 Internal Server Error */ 96 | httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file"); 97 | return ESP_FAIL; 98 | } 99 | } 100 | } while (read_bytes > 0); 101 | /* Close file after sending complete */ 102 | close(fd); 103 | ESP_LOGI(REST_TAG, "File sending complete"); 104 | /* Respond with an empty chunk to signal HTTP response completion */ 105 | httpd_resp_send_chunk(req, NULL, 0); 106 | return ESP_OK; 107 | } 108 | 109 | atomic_int blinker_duration_ms_atomic = 500; 110 | 111 | /* Simple handler for blinker duration control */ 112 | static esp_err_t blinker_duration_post_handler(httpd_req_t *req) 113 | { 114 | int total_len = req->content_len; 115 | int cur_len = 0; 116 | char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; 117 | int received = 0; 118 | if (total_len >= SCRATCH_BUFSIZE) { 119 | /* Respond with 500 Internal Server Error */ 120 | httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); 121 | return ESP_FAIL; 122 | } 123 | while (cur_len < total_len) { 124 | received = httpd_req_recv(req, buf + cur_len, total_len); 125 | if (received <= 0) { 126 | /* Respond with 500 Internal Server Error */ 127 | httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value"); 128 | return ESP_FAIL; 129 | } 130 | cur_len += received; 131 | } 132 | buf[total_len] = '\0'; 133 | 134 | cJSON *root = cJSON_Parse(buf); 135 | blinker_duration_ms_atomic = cJSON_GetObjectItem(root, "duration_ms")->valueint; 136 | ESP_LOGI(REST_TAG, "Blinker control: duration_ms = %d", blinker_duration_ms_atomic); 137 | cJSON_Delete(root); 138 | httpd_resp_sendstr(req, "Post control value successfully"); 139 | return ESP_OK; 140 | } 141 | 142 | atomic_bool blinker_state_atomic = false; 143 | 144 | /* Simple handler for blinker state control */ 145 | static esp_err_t blinker_state_post_handler(httpd_req_t *req) 146 | { 147 | int total_len = req->content_len; 148 | int cur_len = 0; 149 | char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; 150 | int received = 0; 151 | if (total_len >= SCRATCH_BUFSIZE) { 152 | /* Respond with 500 Internal Server Error */ 153 | httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); 154 | return ESP_FAIL; 155 | } 156 | while (cur_len < total_len) { 157 | received = httpd_req_recv(req, buf + cur_len, total_len); 158 | if (received <= 0) { 159 | /* Respond with 500 Internal Server Error */ 160 | httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value"); 161 | return ESP_FAIL; 162 | } 163 | cur_len += received; 164 | } 165 | buf[total_len] = '\0'; 166 | 167 | cJSON *root = cJSON_Parse(buf); 168 | blinker_state_atomic = cJSON_IsTrue(cJSON_GetObjectItem(root, "state")); 169 | ESP_LOGI(REST_TAG, "Blinker control: state = %d", blinker_state_atomic); 170 | cJSON_Delete(root); 171 | httpd_resp_sendstr(req, "Post control value successfully"); 172 | return ESP_OK; 173 | } 174 | 175 | /* Simple handler for getting system handler */ 176 | static esp_err_t system_info_get_handler(httpd_req_t *req) 177 | { 178 | httpd_resp_set_type(req, "application/json"); 179 | cJSON *root = cJSON_CreateObject(); 180 | esp_chip_info_t chip_info; 181 | esp_chip_info(&chip_info); 182 | cJSON_AddStringToObject(root, "version", IDF_VER); 183 | cJSON_AddNumberToObject(root, "cores", chip_info.cores); 184 | const char *sys_info = cJSON_Print(root); 185 | httpd_resp_sendstr(req, sys_info); 186 | free((void *)sys_info); 187 | cJSON_Delete(root); 188 | return ESP_OK; 189 | } 190 | 191 | 192 | esp_err_t start_rest_server(const char *base_path) 193 | { 194 | REST_CHECK(base_path, "wrong base path", err); 195 | rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t)); 196 | REST_CHECK(rest_context, "No memory for rest context", err); 197 | strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path)); 198 | 199 | httpd_handle_t server = NULL; 200 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); 201 | config.uri_match_fn = httpd_uri_match_wildcard; 202 | 203 | ESP_LOGI(REST_TAG, "Starting HTTP Server"); 204 | REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start); 205 | 206 | /* URI handler for fetching system info */ 207 | httpd_uri_t system_info_get_uri = { 208 | .uri = "/api/v1/system/info", 209 | .method = HTTP_GET, 210 | .handler = system_info_get_handler, 211 | .user_ctx = rest_context 212 | }; 213 | httpd_register_uri_handler(server, &system_info_get_uri); 214 | 215 | /* URI handler for light blinking duration control */ 216 | httpd_uri_t blinker_duration_post_uri = { 217 | .uri = "/api/v1/blinker/duration", 218 | .method = HTTP_POST, 219 | .handler = blinker_duration_post_handler, 220 | .user_ctx = rest_context 221 | }; 222 | httpd_register_uri_handler(server, &blinker_duration_post_uri); 223 | 224 | /* URI handler for blinker blinking state control */ 225 | httpd_uri_t blinker_state_post_uri = { 226 | .uri = "/api/v1/blinker/state", 227 | .method = HTTP_POST, 228 | .handler = blinker_state_post_handler, 229 | .user_ctx = rest_context 230 | }; 231 | httpd_register_uri_handler(server, &blinker_state_post_uri); 232 | 233 | /* URI handler for getting web server files */ 234 | httpd_uri_t common_get_uri = { 235 | .uri = "/*", 236 | .method = HTTP_GET, 237 | .handler = rest_common_get_handler, 238 | .user_ctx = rest_context 239 | }; 240 | httpd_register_uri_handler(server, &common_get_uri); 241 | 242 | return ESP_OK; 243 | err_start: 244 | free(rest_context); 245 | err: 246 | return ESP_FAIL; 247 | } 248 | -------------------------------------------------------------------------------- /partitions_www_2500Kb.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap 3 | nvs, data, nvs, 0x9000, 24K, 4 | phy_init, data, phy, 0xf000, 4K, 5 | factory, app, factory, 0x10000, 1M, 6 | www, data, spiffs, , 2500K, 7 | -------------------------------------------------------------------------------- /partitions_www_5Mb.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap 3 | nvs, data, nvs, 0x9000, 24K, 4 | phy_init, data, phy, 0xf000, 4K, 5 | factory, app, factory, 0x10000, 2M, 6 | www, data, spiffs, , 5M, 7 | -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 2 | CONFIG_SPIFFS_OBJ_NAME_LEN=64 3 | CONFIG_FATFS_LONG_FILENAME=y 4 | CONFIG_FATFS_LFN_HEAP=y 5 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 6 | CONFIG_PARTITION_TABLE_CUSTOM=y 7 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_www_5Mb.csv" 8 | CONFIG_PARTITION_TABLE_FILENAME="partitions_www_5Mb.csv" 9 | CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y 10 | CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240 -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 0.1.0 --------------------------------------------------------------------------------