diff --git a/docs/source/api/wifi.rst b/docs/source/api/wifi.rst index eb32b4af53e..1fd5651f38b 100644 --- a/docs/source/api/wifi.rst +++ b/docs/source/api/wifi.rst @@ -50,6 +50,102 @@ Common API Here are the common APIs that are used for both modes, AP and STA. +onEvent (and removeEvent) +************************* + +Registers a caller-supplied function to be called when WiFi events +occur. Several forms are available. + +Function pointer callback taking the event ID: + +.. code-block:: arduino + + typedef void (*WiFiEventCb)(arduino_event_id_t); + wifi_event_id_t onEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_MAX); + +Function pointer callback taking an event-ID-and-info struct: + +.. code-block:: arduino + + typedef struct{ + arduino_event_id_t event_id; + arduino_event_info_t event_info; + } arduino_event_t; + + typedef void (*WiFiEventSysCb)(arduino_event_t *); + wifi_event_id_t onEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_MAX); + +Callback using ``std::function`` taking event ID and info separately: + +.. code-block:: arduino + + typedef std::function WiFiEventFuncCb; + wifi_event_id_t onEvent(WiFiEventFuncCb, arduino_event_id_t = ARDUINO_EVENT_MAX); + +A similar set of functions are available to remove callbacks: + +.. code-block:: arduino + + void removeEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_MAX); + void removeEvent(WiFiEventSysCb, arduino_event_id_t = ARDUINO_EVENT_MAX); + void removeEvent(wifi_event_id_t = ARDUINO_EVENT_MAX); + +In all cases, the subscribing function accepts an optional event type to +invoke the callback only for that specific event; with the default +``ARDUINO_EVENT_MAX``, the callback will be invoked for all WiFi events. + +Any callback function is given the event type in a parameter. +Some of the possible callback function formats also take an +``arduino_event_info_t`` (or use ``arduino_event_t`` which includes both +ID and info) which is a union of structs with additional information +about different event types. + +See +`WiFiGeneric.h `_ +for the list of event types and "info" substructures, and also see a full +example of event handling: `events example`_. + +.. warning:: + + Event callback functions are invoked on a separate + `thread `_ + (`FreeRTOS task `_) + independent of the main application thread that runs ``setup()`` and + ``loop()``. Callback functions must therefore be + `thread-safe `_; + they must not access shared/global variables directly without locking, + and must only call similarly thread-safe functions. + + Some core operations like ``Serial.print()`` are thread-safe but many + functions are not. Notably, ``WiFi.onEvent()`` and ``WiFi.removeEvent()`` + are not thread-safe and should never be invoked from a callback thread. + +setHostname (and getHostname) +***************************** + +Sets the name the DHCP client uses to identify itself. In a typical network +setup this will be the name that shows up in the Wi-Fi router's device list. +The hostname must be no longer than 32 characters. + +.. code-block:: arduino + + setHostname(const char *hostname); + +If the hostname is never specified, a default one will be assigned based +on the chip type and MAC address. The current hostname (default or custom) +may be retrieved: + +.. code-block:: arduino + + const char *getHostname(); + +.. warning:: + + The ``setHostname()`` function must be called BEFORE WiFi is started with + ``WiFi.begin()``, ``WiFi.softAP()``, ``WiFi.mode()``, or ``WiFi.run()``. + To change the name, reset WiFi with ``WiFi.mode(WIFI_MODE_NULL)``, + then proceed with ``WiFi.setHostname(...)`` and restart WiFi from scratch. + useStaticBuffers **************** @@ -552,6 +648,8 @@ To see how to use the ``WiFiScan``, take a look at the ``WiFiScan.ino`` example Examples -------- +`Complete list of WiFi examples `_. + .. _ap example: Wi-Fi AP Example @@ -568,5 +666,10 @@ Wi-Fi STA Example .. literalinclude:: ../../../libraries/WiFi/examples/WiFiClient/WiFiClient.ino :language: arduino -References ----------- +.. _events example: + +Wi-Fi Events Example +******************** + +.. literalinclude:: ../../../libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino + :language: arduino diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino index 862263973ee..7914e66e6ee 100644 --- a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino +++ b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino @@ -16,12 +16,14 @@ static bool eth_connected = false; -void onEvent(arduino_event_id_t event, arduino_event_info_t info) +// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)! +void WiFiEvent(WiFiEvent_t event) { switch (event) { case ARDUINO_EVENT_ETH_START: Serial.println("ETH Started"); - //set eth hostname here + // The hostname must be set after the interface is started, but needs + // to be set before DHCP, so set it from the event handler thread. ETH.setHostname("esp32-ethernet"); break; case ARDUINO_EVENT_ETH_CONNECTED: @@ -72,11 +74,10 @@ void testClient(const char * host, uint16_t port) void setup() { Serial.begin(115200); - WiFi.onEvent(onEvent); + WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. ETH.begin(); } - void loop() { if (eth_connected) { diff --git a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino index 9558889fbd2..3a685994862 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino +++ b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino @@ -5,21 +5,23 @@ #include -#define ETH_TYPE ETH_PHY_TLK110 -#define ETH_ADDR 31 -#define ETH_MDC_PIN 23 -#define ETH_MDIO_PIN 18 -#define ETH_POWER_PIN 17 -#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN +#define ETH_TYPE ETH_PHY_TLK110 +#define ETH_ADDR 31 +#define ETH_MDC_PIN 23 +#define ETH_MDIO_PIN 18 +#define ETH_POWER_PIN 17 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN static bool eth_connected = false; -void onEvent(arduino_event_id_t event, arduino_event_info_t info) +// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)! +void WiFiEvent(WiFiEvent_t event) { switch (event) { case ARDUINO_EVENT_ETH_START: Serial.println("ETH Started"); - //set eth hostname here + // The hostname must be set after the interface is started, but needs + // to be set before DHCP, so set it from the event handler thread. ETH.setHostname("esp32-ethernet"); break; case ARDUINO_EVENT_ETH_CONNECTED: @@ -70,7 +72,7 @@ void testClient(const char * host, uint16_t port) void setup() { Serial.begin(115200); - WiFi.onEvent(onEvent); + WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. ETH.begin(ETH_TYPE, ETH_ADDR, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_POWER_PIN, ETH_CLK_MODE); } diff --git a/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino b/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino index 04492039519..c7c63c51ed8 100644 --- a/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino +++ b/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino @@ -24,6 +24,7 @@ bool dimmer_state = true; // But, you can also define custom devices using the 'Device' base class object, as shown here static Device *my_device = NULL; +// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)! void sysProvEvent(arduino_event_t *sys_event) { switch (sys_event->event_id) { @@ -105,7 +106,7 @@ void setup() RMaker.start(); - WiFi.onEvent(sysProvEvent); + WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread. #if CONFIG_IDF_TARGET_ESP32S2 WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); #else diff --git a/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino b/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino index 47fdec37f62..75c2e1daf90 100644 --- a/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino +++ b/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino @@ -40,6 +40,7 @@ bool power_state = true; // But, you can also define custom devices using the 'Device' base class object, as shown here static Device *my_device = NULL; +// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)! void sysProvEvent(arduino_event_t *sys_event) { switch (sys_event->event_id) { @@ -170,7 +171,7 @@ void setup() RMaker.start(); - WiFi.onEvent(sysProvEvent); + WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread. #if CONFIG_IDF_TARGET_ESP32S2 WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); #else diff --git a/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino b/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino index 1df84e6eae2..082388dd64d 100644 --- a/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino +++ b/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino @@ -34,6 +34,7 @@ LightSwitch switch_ch2 = {gpio_switch2, false}; static Switch *my_switch1 = NULL; static Switch *my_switch2 = NULL; +// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)! void sysProvEvent(arduino_event_t *sys_event) { switch (sys_event->event_id) { @@ -160,7 +161,7 @@ void setup() Serial.printf("\nStarting ESP-RainMaker\n"); RMaker.start(); - WiFi.onEvent(sysProvEvent); + WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread. #if CONFIG_IDF_TARGET_ESP32 WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name); #else diff --git a/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino b/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino index 688feed9bf7..270612774cd 100644 --- a/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino +++ b/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino @@ -25,6 +25,7 @@ bool switch_state = true; // fan, temperaturesensor. static Switch *my_switch = NULL; +// WARNING: sysProvEvent is called from a separate FreeRTOS task (thread)! void sysProvEvent(arduino_event_t *sys_event) { switch (sys_event->event_id) { @@ -107,7 +108,7 @@ void setup() RMaker.start(); - WiFi.onEvent(sysProvEvent); + WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread. #if CONFIG_IDF_TARGET_ESP32S2 WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); diff --git a/libraries/WiFi/examples/FTM/FTM_Initiator/FTM_Initiator.ino b/libraries/WiFi/examples/FTM/FTM_Initiator/FTM_Initiator.ino index eac6563fc95..1fc5fb40a36 100644 --- a/libraries/WiFi/examples/FTM/FTM_Initiator/FTM_Initiator.ino +++ b/libraries/WiFi/examples/FTM/FTM_Initiator/FTM_Initiator.ino @@ -28,6 +28,7 @@ SemaphoreHandle_t ftmSemaphore; bool ftmSuccess = true; // FTM report handler with the calculated data from the round trip +// WARNING: This function is called from a separate FreeRTOS task (thread)! void onFtmReport(arduino_event_t *event) { const char * status_str[5] = {"SUCCESS", "UNSUPPORTED", "CONF_REJECTED", "NO_RESPONSE", "FAIL"}; wifi_event_ftm_report_t * report = &event->event_info.wifi_ftm_report; @@ -62,7 +63,7 @@ void setup() { // Create binary semaphore (initialized taken and can be taken/given from any thread/ISR) ftmSemaphore = xSemaphoreCreateBinary(); - // Listen for FTM Report events + // Will call onFtmReport() from another thread with FTM Report events. WiFi.onEvent(onFtmReport, ARDUINO_EVENT_WIFI_FTM_REPORT); // Connect to AP that has FTM Enabled diff --git a/libraries/WiFi/examples/WPS/WPS.ino b/libraries/WiFi/examples/WPS/WPS.ino index 606c7787f93..687247aa8f8 100644 --- a/libraries/WiFi/examples/WPS/WPS.ino +++ b/libraries/WiFi/examples/WPS/WPS.ino @@ -61,6 +61,7 @@ String wpspin2string(uint8_t a[]){ return (String)wps_pin; } +// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)! void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info){ switch(event){ case ARDUINO_EVENT_WIFI_STA_START: @@ -103,7 +104,7 @@ void setup(){ Serial.begin(115200); delay(10); Serial.println(); - WiFi.onEvent(WiFiEvent); + WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. WiFi.mode(WIFI_MODE_STA); Serial.println("Starting WPS"); wpsInitConfig(); diff --git a/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino b/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino index 9f56bb9f786..771a531a480 100644 --- a/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino +++ b/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino @@ -73,6 +73,7 @@ void onButton(){ delay(100); } +// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)! void WiFiEvent(WiFiEvent_t event){ switch(event) { case ARDUINO_EVENT_WIFI_AP_START: @@ -112,7 +113,7 @@ void WiFiEvent(WiFiEvent_t event){ void setup() { Serial.begin(115200); pinMode(0, INPUT_PULLUP); - WiFi.onEvent(WiFiEvent); + WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. Serial.print("ESP32 SDK: "); Serial.println(ESP.getSdkVersion()); Serial.println("Press the button to select the next mode"); diff --git a/libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino b/libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino index e705b89e171..3d00dd32690 100644 --- a/libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino +++ b/libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino @@ -41,7 +41,7 @@ const char* ssid = "your-ssid"; const char* password = "your-password"; - +// WARNING: This function is called from a separate FreeRTOS task (thread)! void WiFiEvent(WiFiEvent_t event) { Serial.printf("[WiFi-event] event: %d\n", event); @@ -132,6 +132,7 @@ void WiFiEvent(WiFiEvent_t event) default: break; }} +// WARNING: This function is called from a separate FreeRTOS task (thread)! void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { Serial.println("WiFi connected"); @@ -148,7 +149,8 @@ void setup() delay(1000); - // Examples of different ways to register wifi events + // Examples of different ways to register wifi events; + // these handlers will be called from another thread. WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); WiFiEventId_t eventID = WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){ diff --git a/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino b/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino index 6be60fc2581..3dcba56eec2 100644 --- a/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino +++ b/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino @@ -64,16 +64,15 @@ void wifiConnectedLoop(){ delay(9000); } +// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)! void WiFiEvent(WiFiEvent_t event){ switch(event) { - case ARDUINO_EVENT_WIFI_AP_START: //can set ap hostname here WiFi.softAPsetHostname(AP_SSID); //enable ap ipv6 here WiFi.softAPenableIpV6(); break; - case ARDUINO_EVENT_WIFI_STA_START: //set sta hostname here WiFi.setHostname(AP_SSID); @@ -106,7 +105,7 @@ void WiFiEvent(WiFiEvent_t event){ void setup(){ Serial.begin(115200); WiFi.disconnect(true); - WiFi.onEvent(WiFiEvent); + WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. WiFi.mode(WIFI_MODE_APSTA); WiFi.softAP(AP_SSID); WiFi.begin(STA_SSID, STA_PASS); diff --git a/libraries/WiFi/examples/WiFiUDPClient/WiFiUDPClient.ino b/libraries/WiFi/examples/WiFiUDPClient/WiFiUDPClient.ino index 6fd07caf44e..7c5ebc39196 100644 --- a/libraries/WiFi/examples/WiFiUDPClient/WiFiUDPClient.ino +++ b/libraries/WiFi/examples/WiFiUDPClient/WiFiUDPClient.ino @@ -47,7 +47,7 @@ void connectToWiFi(const char * ssid, const char * pwd){ // delete old config WiFi.disconnect(true); //register event handler - WiFi.onEvent(WiFiEvent); + WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. //Initiate connection WiFi.begin(ssid, pwd); @@ -55,7 +55,7 @@ void connectToWiFi(const char * ssid, const char * pwd){ Serial.println("Waiting for WIFI connection..."); } -//wifi event handler +// WARNING: WiFiEvent is called from a separate FreeRTOS task (thread)! void WiFiEvent(WiFiEvent_t event){ switch(event) { case ARDUINO_EVENT_WIFI_STA_GOT_IP: diff --git a/libraries/WiFiProv/examples/WiFiProv/README.md b/libraries/WiFiProv/examples/WiFiProv/README.md index 70da0052c3d..efee39fd7a5 100644 --- a/libraries/WiFiProv/examples/WiFiProv/README.md +++ b/libraries/WiFiProv/examples/WiFiProv/README.md @@ -10,7 +10,8 @@ This example allows Arduino users to choose either BLE or SOFTAP as the mode of ### WiFi.onEvent() -Using this API, users can register to receive WiFi Events and Provisioning Events. +This API can be used to register a function to be called from another +thread for WiFi Events and Provisioning Events. ### WiFi.beginProvision() diff --git a/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino b/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino index 204e6c34a5b..72c043cb74f 100644 --- a/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino +++ b/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino @@ -11,13 +11,13 @@ Note: This sketch takes up a lot of space for the app and may not be able to fla #include "WiFiProv.h" #include "WiFi.h" -// #define USE_SOFT_AP // Uncomment if you want to enforce using Soft AP method instead of BLE - -const char * pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by user in the phone app +// #define USE_SOFT_AP // Uncomment if you want to enforce using the Soft AP method instead of BLE +const char * pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by the user in the phone app const char * service_name = "PROV_123"; // Name of your device (the Espressif apps expects by default device name starting with "Prov_") const char * service_key = NULL; // Password used for SofAP method (NULL = no password needed) bool reset_provisioned = true; // When true the library will automatically delete previously provisioned data. +// WARNING: SysProvEvent is called from a separate FreeRTOS task (thread)! void SysProvEvent(arduino_event_t *sys_event) { switch (sys_event->event_id) {