From f3ae2a65e24c7fd7ad5cf07485cd0ac2aa5d8a6c Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Fri, 30 May 2025 15:18:57 +0300 Subject: [PATCH 01/20] IDF release/v5.4 (#11406) * fix(build): Update APB frequency set routine * IDF release/v5.4 aed8bdc8 --- cores/esp32/esp32-hal-cpu.c | 10 ++++ package/package_esp32_index.template.json | 68 +++++++++++------------ 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/cores/esp32/esp32-hal-cpu.c b/cores/esp32/esp32-hal-cpu.c index 1ffde860792..b80e24c2b0f 100644 --- a/cores/esp32/esp32-hal-cpu.c +++ b/cores/esp32/esp32-hal-cpu.c @@ -26,6 +26,8 @@ #include "soc/efuse_reg.h" #include "esp32-hal.h" #include "esp32-hal-cpu.h" +#include "hal/timer_ll.h" +#include "esp_private/systimer.h" #include "esp_system.h" #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ @@ -173,7 +175,9 @@ static uint32_t calculateApb(rtc_cpu_freq_config_t *conf) { #endif } +#if defined(CONFIG_IDF_TARGET_ESP32) && !defined(LACT_MODULE) && !defined(LACT_TICKS_PER_US) void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF +#endif bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { rtc_cpu_freq_config_t conf, cconf; @@ -246,7 +250,13 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { //Update APB Freq REG rtc_clk_apb_freq_update(apb); //Update esp_timer divisor +#if CONFIG_IDF_TARGET_ESP32 +#if defined(LACT_MODULE) && defined(LACT_TICKS_PER_US) + timer_ll_set_lact_clock_prescale(TIMER_LL_GET_HW(LACT_MODULE), apb / MHZ / LACT_TICKS_PER_US); +#else esp_timer_impl_update_apb_freq(apb / MHZ); +#endif +#endif } #endif //Update FreeRTOS Tick Divisor diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index ba63dd3beb5..14aa8e9b4cf 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -51,7 +51,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.4-fe753553-v1" + "version": "idf-release_v5.4-aed8bdc8-v1" }, { "packager": "esp32", @@ -104,63 +104,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.4-fe753553-v1", + "version": "idf-release_v5.4-aed8bdc8-v1", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-fe753553-v1.zip", - "checksum": "SHA-256:79abe0d17524dc64eccdab97bf4407127d8249e99c9b929357c10d24fe47a703", - "size": "353685379" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.4-aed8bdc8-v1.zip", + "checksum": "SHA-256:448691c3171f79b2136e4ab8006e9c78bd1627156dab1365fff8f8867a6a7e5b", + "size": "353758763" } ] }, From 6f56df2a09a17213823e2edda3cdff3db32cadaf Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:19:44 -0300 Subject: [PATCH 02/20] feat(codeowners): Initial CODEOWNERS setup (#11397) * feat(codeowners): Initial CODEOWNERS setup * fix(comment): Improve comment * fix(codeowners): Add teams * fix(codeowners): Apply suggestions * fix(codeowners): Add missing libraries --- .github/CODEOWNERS | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..75a2b46d619 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,79 @@ +# CODEOWNERS for ESP32 Arduino Core + +# This file is used to specify the code owners for the ESP32 Arduino Core. +# Read more about CODEOWNERS: +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# Note that order matters. The last matching pattern will be used. + +# The default owners are the active developers of the ESP32 Arduino Core. +# Refrain from using @espressif/arduino-esp32 to avoid spamming non-developers with review requests. +* @espressif/arduino-devs + +# CI +/.github/ @lucasssvaz @me-no-dev @P-R-O-C-H-Y +/tests/ @lucasssvaz @P-R-O-C-H-Y + +# Tools +/tools/ @me-no-dev +/tools/pre-commit/ @lucasssvaz +/tools/add_lib.sh @P-R-O-C-H-Y + +# Pre-commit +/.* @lucasssvaz # Files in root directory that start with a dot. + +# Git Files +/.gitignore @espressif/arduino-devs +/.gitmodules @espressif/arduino-devs + +# Documentation +/docs/ @pedrominatel +/.github/ISSUE_TEMPLATE/ @pedrominatel +/.github/PULL_REQUEST_TEMPLATE.md @pedrominatel +/.readthedocs.yaml @pedrominatel +/*.md @pedrominatel + +# Boards +/variants/ @P-R-O-C-H-Y +/boards.txt @P-R-O-C-H-Y + +# Arduino as Component +/idf_component_examples/ @SuGlider +/idf_component.yml @SuGlider @me-no-dev +/CMakeLists.txt @SuGlider @me-no-dev +/Kconfig.projbuild @SuGlider @me-no-dev + +# Build System +/package.json @me-no-dev +/platform.txt @me-no-dev +/programmers.txt @me-no-dev +/package/ @me-no-dev + +# Libraries +/libraries/ArduinoOTA/ @me-no-dev +/libraries/AsyncUDP/ @me-no-dev +/libraries/BLE/ @lucasssvaz @SuGlider +/libraries/ESP_I2S/ @me-no-dev +/libraries/ESP_NOW/ @P-R-O-C-H-Y @lucasssvaz +/libraries/ESP_SR/ @me-no-dev +/libraries/ESPmDNS/ @me-no-dev +/libraries/Ethernet/ @me-no-dev +/libraries/Matter/ @SuGlider +/libraries/NetBIOS/ @me-no-dev +/libraries/Network/ @me-no-dev +/libraries/OpenThread/ @SuGlider +/libraries/PPP/ @me-no-dev +/libraries/SPI/ @me-no-dev +/libraries/Update/ @me-no-dev +/libraries/USB/ @SuGlider @me-no-dev +/libraries/WiFi/ @me-no-dev +/libraries/WiFiProv/ @me-no-dev +/libraries/Wire/ @me-no-dev +/libraries/Zigbee/ @P-R-O-C-H-Y + +# CI JSON +# Keep this after other libraries and tests to avoid being overridden. +**/ci.json @lucasssvaz + +# The CODEOWNERS file should be owned by the developers of the ESP32 Arduino Core. +# Leave this entry as the last one to avoid being overridden. +/.github/CODEOWNERS @espressif/arduino-devs From b5c5655cf004858ed56f3488f006ebad3690c303 Mon Sep 17 00:00:00 2001 From: Kevin Sidwar Date: Wed, 4 Jun 2025 08:39:19 -0600 Subject: [PATCH 03/20] Support HTTP 204 (#11408) HTTP 204 is a successful return code which indicates No Content. While it's appropriate to return a 304 if the server has content for a device but it hasn't change, it is more accurate for a server to return a 204 if it simply doesn't have any firmware files for a particular device. Co-authored-by: Me No Dev --- libraries/HTTPUpdate/src/HTTPUpdate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/HTTPUpdate/src/HTTPUpdate.cpp b/libraries/HTTPUpdate/src/HTTPUpdate.cpp index 1eda0a4f7e5..b463ffe2e83 100644 --- a/libraries/HTTPUpdate/src/HTTPUpdate.cpp +++ b/libraries/HTTPUpdate/src/HTTPUpdate.cpp @@ -356,6 +356,7 @@ HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient &http, const String ¤ log_e("Content-Length was 0 or wasn't set by Server?!\n"); } break; + case HTTP_CODE_NO_CONTENT: case HTTP_CODE_NOT_MODIFIED: ///< Not Modified (No updates) ret = HTTP_UPDATE_NO_UPDATES; From a2880a4c17038b4ff3dfa083e7af7c7bbdba914a Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 4 Jun 2025 17:39:34 +0300 Subject: [PATCH 04/20] feat(ap): Add support for DHCP Captive Portal (opt 114) (#11412) * feat(ap): Add support for DHCP Captive Portal (opt 114) * feat(ap): No need to guard the function * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../examples/CaptivePortal/CaptivePortal.ino | 5 ++- libraries/WiFi/src/AP.cpp | 39 +++++++++++++++++++ libraries/WiFi/src/WiFiAP.h | 1 + 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino b/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino index d956dc14ad3..7759aa09a1c 100644 --- a/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino +++ b/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino @@ -34,8 +34,9 @@ void handleNotFound() { void setup() { Serial.begin(115200); - WiFi.mode(WIFI_AP); - WiFi.softAP("ESP32-DNSServer"); + WiFi.AP.begin(); + WiFi.AP.create("ESP32-DNSServer"); + WiFi.AP.enableDhcpCaptivePortal(); // by default DNSServer is started serving any "*" domain name. It will reply // AccessPoint's IP to all DNS request (this is required for Captive Portal detection) diff --git a/libraries/WiFi/src/AP.cpp b/libraries/WiFi/src/AP.cpp index 0e7839764ea..a649c3898cb 100644 --- a/libraries/WiFi/src/AP.cpp +++ b/libraries/WiFi/src/AP.cpp @@ -305,6 +305,45 @@ bool APClass::enableNAPT(bool enable) { return true; } +bool APClass::enableDhcpCaptivePortal() { + esp_err_t err = ESP_OK; + static char captiveportal_uri[32] = { + 0, + }; + + if (!started()) { + log_e("AP must be first started to enable DHCP Captive Portal"); + return false; + } + + // Create Captive Portal URL: http://192.168.0.4 + strcpy(captiveportal_uri, "http://"); + strcat(captiveportal_uri, String(localIP()).c_str()); + + // Stop DHCPS + err = esp_netif_dhcps_stop(_esp_netif); + if (err && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { + log_e("DHCPS Stop Failed! 0x%04x: %s", err, esp_err_to_name(err)); + return false; + } + + // Enable DHCP Captive Portal + err = esp_netif_dhcps_option(_esp_netif, ESP_NETIF_OP_SET, ESP_NETIF_CAPTIVEPORTAL_URI, captiveportal_uri, strlen(captiveportal_uri)); + if (err) { + log_e("Could not set enable DHCP Captive Portal! 0x%x: %s", err, esp_err_to_name(err)); + return false; + } + + // Start DHCPS + err = esp_netif_dhcps_start(_esp_netif); + if (err) { + log_e("DHCPS Start Failed! 0x%04x: %s", err, esp_err_to_name(err)); + return false; + } + + return true; +} + String APClass::SSID(void) const { if (!started()) { return String(); diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h index 540ec87f44f..2b7ce469801 100644 --- a/libraries/WiFi/src/WiFiAP.h +++ b/libraries/WiFi/src/WiFiAP.h @@ -53,6 +53,7 @@ class APClass : public NetworkInterface { bool bandwidth(wifi_bandwidth_t bandwidth); bool enableNAPT(bool enable = true); + bool enableDhcpCaptivePortal(); String SSID(void) const; uint8_t stationCount(); From 460b89201b0be121c4345549551bcf102c26f165 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:39:54 +0200 Subject: [PATCH 05/20] make BT core code execution conditional from include esp_bt.h (#11413) * make code execution conditional from include esp_bt.h.h * only one if * Update esp32-hal-bt.c --- cores/esp32/esp32-hal-bt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-bt.c b/cores/esp32/esp32-hal-bt.c index 1e5f73e324c..5d512d448a3 100644 --- a/cores/esp32/esp32-hal-bt.c +++ b/cores/esp32/esp32-hal-bt.c @@ -15,7 +15,7 @@ #include "esp32-hal-bt.h" #if SOC_BT_SUPPORTED -#ifdef CONFIG_BT_BLUEDROID_ENABLED +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && __has_include("esp_bt.h") #if CONFIG_IDF_TARGET_ESP32 bool btInUse() { From 375f2c002de0d5ace08bac59a4e42134be1af22e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:40:12 +0200 Subject: [PATCH 06/20] C2: Disable network provisioning (#11423) --- idf_component.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/idf_component.yml b/idf_component.yml index 967c4ecf0f6..7f090cb26a0 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -68,6 +68,8 @@ dependencies: # RainMaker Start (Fixed versions, because Matter supports only Insights 1.0.1) espressif/network_provisioning: version: "1.0.2" + rules: + - if: "target != esp32c2" espressif/esp_rainmaker: version: "1.5.2" rules: From cae66e65a30d5a3d7c15b85ffa4130fa74e01b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:40:28 +0200 Subject: [PATCH 07/20] feat(zigbee): Add endpoint identification in read handlers + command structures fix (#11425) * feat(zigbee): Add endpoint identification in read handlers * fix(zigbee): initialize Zigbee command structures with zeros * fix(zigbee): Spelling correction * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../Zigbee_Thermostat/Zigbee_Thermostat.ino | 56 +++- libraries/Zigbee/keywords.txt | 3 +- libraries/Zigbee/src/ZigbeeEP.cpp | 20 +- libraries/Zigbee/src/ZigbeeEP.h | 4 +- libraries/Zigbee/src/ZigbeeHandlers.cpp | 8 +- .../Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp | 48 +-- libraries/Zigbee/src/ep/ZigbeeSwitch.cpp | 32 +- libraries/Zigbee/src/ep/ZigbeeThermostat.cpp | 279 +++++++++++++++++- libraries/Zigbee/src/ep/ZigbeeThermostat.h | 29 +- 9 files changed, 390 insertions(+), 89 deletions(-) diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino index 7cdf45ef711..6f5934f791d 100644 --- a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino @@ -34,7 +34,8 @@ #include "Zigbee.h" /* Zigbee thermostat configuration */ -#define THERMOSTAT_ENDPOINT_NUMBER 5 +#define THERMOSTAT_ENDPOINT_NUMBER 1 +#define USE_RECEIVE_TEMP_WITH_SOURCE 1 uint8_t button = BOOT_PIN; ZigbeeThermostat zbThermostat = ZigbeeThermostat(THERMOSTAT_ENDPOINT_NUMBER); @@ -48,13 +49,28 @@ float sensor_tolerance; struct tm timeinfo = {}; // Time structure for Time cluster /****************** Temperature sensor handling *******************/ -void recieveSensorTemp(float temperature) { +#if USE_RECEIVE_TEMP_WITH_SOURCE == 0 +void receiveSensorTemp(float temperature) { Serial.printf("Temperature sensor value: %.2f°C\n", temperature); sensor_temp = temperature; } +#else +void receiveSensorTempWithSource(float temperature, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) { + if (src_address.addr_type == ESP_ZB_ZCL_ADDR_TYPE_SHORT) { + Serial.printf("Temperature sensor value: %.2f°C from endpoint %d, address 0x%04x\n", temperature, src_endpoint, src_address.u.short_addr); + } else { + Serial.printf( + "Temperature sensor value: %.2f°C from endpoint %d, address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", temperature, src_endpoint, + src_address.u.ieee_addr[7], src_address.u.ieee_addr[6], src_address.u.ieee_addr[5], src_address.u.ieee_addr[4], src_address.u.ieee_addr[3], + src_address.u.ieee_addr[2], src_address.u.ieee_addr[1], src_address.u.ieee_addr[0] + ); + } + sensor_temp = temperature; +} +#endif -void recieveSensorConfig(float min_temp, float max_temp, float tolerance) { - Serial.printf("Temperature sensor settings: min %.2f°C, max %.2f°C, tolerance %.2f°C\n", min_temp, max_temp, tolerance); +void receiveSensorConfig(float min_temp, float max_temp, float tolerance) { + Serial.printf("Temperature sensor config: min %.2f°C, max %.2f°C, tolerance %.2f°C\n", min_temp, max_temp, tolerance); sensor_min_temp = min_temp; sensor_max_temp = max_temp; sensor_tolerance = tolerance; @@ -66,9 +82,15 @@ void setup() { // Init button switch pinMode(button, INPUT_PULLUP); - // Set callback functions for temperature and configuration receive - zbThermostat.onTempRecieve(recieveSensorTemp); - zbThermostat.onConfigRecieve(recieveSensorConfig); +// Set callback function for receiving temperature from sensor - Use only one option +#if USE_RECEIVE_TEMP_WITH_SOURCE == 0 + zbThermostat.onTempReceive(receiveSensorTemp); // If you bound only one sensor or you don't need to know the source of the temperature +#else + zbThermostat.onTempReceiveWithSource(receiveSensorTempWithSource); +#endif + + // Set callback function for receiving sensor configuration + zbThermostat.onConfigReceive(receiveSensorConfig); //Optional: set Zigbee device name and model zbThermostat.setManufacturerAndModel("Espressif", "ZigbeeThermostat"); @@ -107,19 +129,30 @@ void setup() { Serial.println(); - // Get temperature sensor configuration - zbThermostat.getSensorSettings(); + // Get temperature sensor configuration for all bound sensors by endpoint number and address + std::list boundSensors = zbThermostat.getBoundDevices(); + for (const auto &device : boundSensors) { + Serial.println("--------------------------------"); + if (device->short_addr == 0x0000 || device->short_addr == 0xFFFF) { //End devices never have 0x0000 short address or 0xFFFF group address + Serial.printf( + "Device on endpoint %d, IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->endpoint, device->ieee_addr[7], device->ieee_addr[6], + device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0] + ); + zbThermostat.getSensorSettings(device->endpoint, device->ieee_addr); + } else { + Serial.printf("Device on endpoint %d, short address: 0x%x\r\n", device->endpoint, device->short_addr); + zbThermostat.getSensorSettings(device->endpoint, device->short_addr); + } + } } void loop() { // Handle button switch in loop() if (digitalRead(button) == LOW) { // Push button pressed - // Key debounce handling while (digitalRead(button) == LOW) { delay(50); } - // Set reporting interval for temperature sensor zbThermostat.setTemperatureReporting(0, 10, 2); } @@ -130,5 +163,6 @@ void loop() { last_print = millis(); int temp_percent = (int)((sensor_temp - sensor_min_temp) / (sensor_max_temp - sensor_min_temp) * 100); Serial.printf("Loop temperature info: %.2f°C (%d %%)\n", sensor_temp, temp_percent); + zbThermostat.printBoundDevices(Serial); } } diff --git a/libraries/Zigbee/keywords.txt b/libraries/Zigbee/keywords.txt index 4d4cd7d0606..5ce1e8f6f51 100644 --- a/libraries/Zigbee/keywords.txt +++ b/libraries/Zigbee/keywords.txt @@ -107,6 +107,7 @@ setLightColor KEYWORD2 # ZigbeeThermostat onTempRecieve KEYWORD2 onConfigRecieve KEYWORD2 +onTempReceiveWithSource KEYWORD2 getTemperature KEYWORD2 getSensorSettings KEYWORD2 setTemperatureReporting KEYWORD2 @@ -191,4 +192,4 @@ ZIGBEE_DEFAULT_COORDINATOR_CONFIG LITERAL1 ZIGBEE_DEFAULT_RADIO_CONFIG LITERAL1 ZIGBEE_DEFAULT_UART_RCP_RADIO_CONFIG LITERAL1 ZIGBEE_DEFAULT_HOST_CONFIG LITERAL1 -ZB_ARRAY_LENTH LITERAL1 +ZB_ARRAY_LENGHT LITERAL1 diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp index 1d3df126ce8..efddbdd0368 100644 --- a/libraries/Zigbee/src/ZigbeeEP.cpp +++ b/libraries/Zigbee/src/ZigbeeEP.cpp @@ -145,7 +145,7 @@ bool ZigbeeEP::setBatteryVoltage(uint8_t voltage) { bool ZigbeeEP::reportBatteryPercentage() { /* Send report attributes command */ - esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + esp_zb_zcl_report_attr_cmd_t report_attr_cmd = {0}; report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID; report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; @@ -166,7 +166,7 @@ bool ZigbeeEP::reportBatteryPercentage() { char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) { /* Read peer Manufacture Name & Model Identifier */ - esp_zb_zcl_read_attr_cmd_t read_req; + esp_zb_zcl_read_attr_cmd_t read_req = {0}; if (short_addr != 0) { read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; @@ -183,7 +183,7 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_i uint16_t attributes[] = { ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, }; - read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); read_req.attr_field = attributes; if (_read_manufacturer != NULL) { @@ -204,7 +204,7 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_i char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) { /* Read peer Manufacture Name & Model Identifier */ - esp_zb_zcl_read_attr_cmd_t read_req; + esp_zb_zcl_read_attr_cmd_t read_req = {0}; if (short_addr != 0) { read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; @@ -221,7 +221,7 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_add uint16_t attributes[] = { ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, }; - read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); read_req.attr_field = attributes; if (_read_model != NULL) { @@ -375,7 +375,7 @@ bool ZigbeeEP::setTimezone(int32_t gmt_offset) { tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) { /* Read peer time */ - esp_zb_zcl_read_attr_cmd_t read_req; + esp_zb_zcl_read_attr_cmd_t read_req = {0}; if (short_addr >= 0) { read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; @@ -386,7 +386,7 @@ tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ie } uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_TIME_ID}; - read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); read_req.attr_field = attributes; read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME; @@ -427,7 +427,7 @@ tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ie int32_t ZigbeeEP::getTimezone(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) { /* Read peer timezone */ - esp_zb_zcl_read_attr_cmd_t read_req; + esp_zb_zcl_read_attr_cmd_t read_req = {0}; if (short_addr >= 0) { read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; @@ -438,7 +438,7 @@ int32_t ZigbeeEP::getTimezone(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_ } uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID}; - read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); read_req.attr_field = attributes; read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME; @@ -543,7 +543,7 @@ static void findOTAServer(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t } void ZigbeeEP::requestOTAUpdate() { - esp_zb_zdo_match_desc_req_param_t req; + esp_zb_zdo_match_desc_req_param_t req = {0}; uint16_t cluster_list[] = {ESP_ZB_ZCL_CLUSTER_ID_OTA_UPGRADE}; /* Match the OTA server of coordinator */ diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h index fe22f31faaf..a3217cbd066 100644 --- a/libraries/Zigbee/src/ZigbeeEP.h +++ b/libraries/Zigbee/src/ZigbeeEP.h @@ -12,7 +12,7 @@ #define ZB_CMD_TIMEOUT 10000 // 10 seconds #define OTA_UPGRADE_QUERY_INTERVAL (1 * 60) // 1 hour = 60 minutes -#define ZB_ARRAY_LENTH(arr) (sizeof(arr) / sizeof(arr[0])) +#define ZB_ARRAY_LENGHT(arr) (sizeof(arr) / sizeof(arr[0])) #define RGB_TO_XYZ(r, g, b, X, Y, Z) \ { \ @@ -131,7 +131,7 @@ class ZigbeeEP { // list of all handlers function calls, to be override by EPs implementation virtual void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {}; - virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {}; + virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {}; virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented virtual void zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message); virtual void zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) {}; diff --git a/libraries/Zigbee/src/ZigbeeHandlers.cpp b/libraries/Zigbee/src/ZigbeeHandlers.cpp index eeeb1e8013a..5d54e459058 100644 --- a/libraries/Zigbee/src/ZigbeeHandlers.cpp +++ b/libraries/Zigbee/src/ZigbeeHandlers.cpp @@ -108,7 +108,9 @@ static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_mes // List through all Zigbee EPs and call the callback function, with the message for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { if (message->dst_endpoint == (*it)->getEndpoint()) { - (*it)->zbAttributeRead(message->cluster, &message->attribute); //method zbAttributeRead must be implemented in specific EP class + (*it)->zbAttributeRead( + message->cluster, &message->attribute, message->src_endpoint, message->src_address + ); //method zbAttributeRead must be implemented in specific EP class } } return ESP_OK; @@ -142,7 +144,9 @@ static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_re } else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_TIME) { (*it)->zbReadTimeCluster(&variable->attribute); //method zbReadTimeCluster implemented in the common EP class } else { - (*it)->zbAttributeRead(message->info.cluster, &variable->attribute); //method zbAttributeRead must be implemented in specific EP class + (*it)->zbAttributeRead( + message->info.cluster, &variable->attribute, message->info.src_endpoint, message->info.src_address + ); //method zbAttributeRead must be implemented in specific EP class } } variable = variable->next; diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp index 935d638324f..f795ed1a3c8 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp @@ -53,7 +53,7 @@ void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t ad ZigbeeColorDimmerSwitch *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_d("Found light endpoint"); - esp_zb_zdo_bind_req_param_t bind_req; + esp_zb_zdo_bind_req_param_t bind_req = {0}; zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t)); light->endpoint = endpoint; light->short_addr = addr; @@ -97,7 +97,7 @@ void ZigbeeColorDimmerSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cm // Methods to control the light void ZigbeeColorDimmerSwitch::lightToggle() { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; @@ -112,7 +112,7 @@ void ZigbeeColorDimmerSwitch::lightToggle() { void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -128,7 +128,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) { void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -145,7 +145,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -165,7 +165,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t i void ZigbeeColorDimmerSwitch::lightOn() { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; @@ -180,7 +180,7 @@ void ZigbeeColorDimmerSwitch::lightOn() { void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -196,7 +196,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) { void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -213,7 +213,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -233,7 +233,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_ void ZigbeeColorDimmerSwitch::lightOff() { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; @@ -248,7 +248,7 @@ void ZigbeeColorDimmerSwitch::lightOff() { void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -264,7 +264,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) { void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -281,7 +281,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -301,7 +301,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) { if (_is_bound) { - esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req; + esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.effect_id = effect_id; @@ -317,7 +317,7 @@ void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effe void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() { if (_is_bound) { - esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req; + esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; log_v("Sending 'light on with scene recall' command"); @@ -331,7 +331,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() { void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) { if (_is_bound) { - esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req; + esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API @@ -348,7 +348,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16 void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) { if (_is_bound) { - esp_zb_zcl_move_to_level_cmd_t cmd_req; + esp_zb_zcl_move_to_level_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.level = level; @@ -364,7 +364,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) { void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_move_to_level_cmd_t cmd_req; + esp_zb_zcl_move_to_level_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -381,7 +381,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t group_addr) void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_move_to_level_cmd_t cmd_req; + esp_zb_zcl_move_to_level_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -399,7 +399,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uin void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_move_to_level_cmd_t cmd_req; + esp_zb_zcl_move_to_level_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -422,7 +422,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t if (_is_bound) { espXyColor_t xy_color = espRgbToXYColor(red, green, blue); - esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.color_x = xy_color.x; @@ -441,7 +441,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t if (_is_bound) { espXyColor_t xy_color = espRgbToXYColor(red, green, blue); - esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -461,7 +461,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t if (_is_bound) { espXyColor_t xy_color = espRgbToXYColor(red, green, blue); - esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -482,7 +482,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t if (_is_bound) { espXyColor_t xy_color = espRgbToXYColor(red, green, blue); - esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp index 38fd7d370fb..68e7a7430cc 100644 --- a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp @@ -52,7 +52,7 @@ void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t ZigbeeSwitch *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_d("Found light endpoint"); - esp_zb_zdo_bind_req_param_t bind_req; + esp_zb_zdo_bind_req_param_t bind_req = {0}; zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t)); light->endpoint = endpoint; light->short_addr = addr; @@ -94,7 +94,7 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) { // Methods to control the light void ZigbeeSwitch::lightToggle() { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; @@ -109,7 +109,7 @@ void ZigbeeSwitch::lightToggle() { void ZigbeeSwitch::lightToggle(uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -125,7 +125,7 @@ void ZigbeeSwitch::lightToggle(uint16_t group_addr) { void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -142,7 +142,7 @@ void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) { void ZigbeeSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -162,7 +162,7 @@ void ZigbeeSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { void ZigbeeSwitch::lightOn() { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; @@ -177,7 +177,7 @@ void ZigbeeSwitch::lightOn() { void ZigbeeSwitch::lightOn(uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -193,7 +193,7 @@ void ZigbeeSwitch::lightOn(uint16_t group_addr) { void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -210,7 +210,7 @@ void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { void ZigbeeSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -230,7 +230,7 @@ void ZigbeeSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { void ZigbeeSwitch::lightOff() { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; @@ -245,7 +245,7 @@ void ZigbeeSwitch::lightOff() { void ZigbeeSwitch::lightOff(uint16_t group_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; @@ -261,7 +261,7 @@ void ZigbeeSwitch::lightOff(uint16_t group_addr) { void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; @@ -278,7 +278,7 @@ void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { void ZigbeeSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { if (_is_bound) { - esp_zb_zcl_on_off_cmd_t cmd_req; + esp_zb_zcl_on_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; @@ -298,7 +298,7 @@ void ZigbeeSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) { if (_is_bound) { - esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req; + esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.effect_id = effect_id; @@ -314,7 +314,7 @@ void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) void ZigbeeSwitch::lightOnWithSceneRecall() { if (_is_bound) { - esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req; + esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; log_v("Sending 'light on with scene recall' command"); @@ -327,7 +327,7 @@ void ZigbeeSwitch::lightOnWithSceneRecall() { } void ZigbeeSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) { if (_is_bound) { - esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req; + esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req = {0}; cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp index 633a60d0ff9..f3bfd7d981b 100644 --- a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp @@ -65,7 +65,7 @@ void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uin ZigbeeThermostat *instance = static_cast(user_ctx); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { log_i("Found temperature sensor"); - esp_zb_zdo_bind_req_param_t bind_req; + esp_zb_zdo_bind_req_param_t bind_req = {0}; /* Store the information of the remote device */ zb_device_params_t *sensor = (zb_device_params_t *)malloc(sizeof(zb_device_params_t)); sensor->endpoint = endpoint; @@ -115,31 +115,38 @@ void ZigbeeThermostat::findEndpoint(esp_zb_zdo_match_desc_req_param_t *param) { esp_zb_zdo_match_cluster(param, ZigbeeThermostat::findCbWrapper, this); } -void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) { +void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) { static uint8_t read_config = 0; if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT) { if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { int16_t value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; - if (_on_temp_recieve) { - _on_temp_recieve(zb_s16_to_temperature(value)); + if (_on_temp_receive) { + _on_temp_receive(zb_s16_to_temperature(value)); + } + if (_on_temp_receive_with_source) { + _on_temp_receive_with_source(zb_s16_to_temperature(value), src_endpoint, src_address); } } if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { int16_t min_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; _min_temp = zb_s16_to_temperature(min_value); read_config++; + log_d("Received min temperature: %.2f°C from endpoint %d", _min_temp, src_endpoint); } if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { int16_t max_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; _max_temp = zb_s16_to_temperature(max_value); read_config++; + log_d("Received max temperature: %.2f°C from endpoint %d", _max_temp, src_endpoint); } if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) { uint16_t tolerance = attribute->data.value ? *(uint16_t *)attribute->data.value : 0; _tolerance = 1.0 * tolerance / 100; read_config++; + log_d("Received tolerance: %.2f°C from endpoint %d", _tolerance, src_endpoint); } if (read_config == 3) { + log_d("All config attributes processed"); read_config = 0; xSemaphoreGive(lock); } @@ -147,14 +154,14 @@ void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_att } void ZigbeeThermostat::getTemperature() { - /* Send "read attributes" command to the bound sensor */ - esp_zb_zcl_read_attr_cmd_t read_req; + /* Send "read attributes" command to all bound sensors */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; read_req.zcl_basic_cmd.src_endpoint = _endpoint; read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID}; - read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); read_req.attr_field = attributes; log_i("Sending 'read temperature' command"); @@ -163,9 +170,68 @@ void ZigbeeThermostat::getTemperature() { esp_zb_lock_release(); } +void ZigbeeThermostat::getTemperature(uint16_t group_addr) { + /* Send "read attributes" command to the group */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID}; + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); + read_req.attr_field = attributes; + + log_i("Sending 'read temperature' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); +} + +void ZigbeeThermostat::getTemperature(uint8_t endpoint, uint16_t short_addr) { + /* Send "read attributes" command to specific endpoint */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_endpoint = endpoint; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID}; + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); + read_req.attr_field = attributes; + + log_i("Sending 'read temperature' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); +} + +void ZigbeeThermostat::getTemperature(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { + /* Send "read attributes" command to specific endpoint */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_endpoint = endpoint; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + + uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID}; + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); + read_req.attr_field = attributes; + + log_i( + "Sending 'read temperature' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], + ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); +} + void ZigbeeThermostat::getSensorSettings() { - /* Send "read attributes" command to the bound sensor */ - esp_zb_zcl_read_attr_cmd_t read_req; + /* Send "read attributes" command to all bound sensors */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; read_req.zcl_basic_cmd.src_endpoint = _endpoint; read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; @@ -173,10 +239,102 @@ void ZigbeeThermostat::getSensorSettings() { uint16_t attributes[] = { ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID }; - read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); read_req.attr_field = attributes; - log_i("Sending 'read temperature' command"); + log_i("Sending 'read sensor settings' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); + + //Take semaphore to wait for response of all attributes + if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) { + log_e("Error while reading attributes"); + return; + } else { + //Call the callback function when all attributes are read + _on_config_receive(_min_temp, _max_temp, _tolerance); + } +} + +void ZigbeeThermostat::getSensorSettings(uint16_t group_addr) { + /* Send "read attributes" command to the group */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + uint16_t attributes[] = { + ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID + }; + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); + read_req.attr_field = attributes; + + log_i("Sending 'read sensor settings' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); + + //Take semaphore to wait for response of all attributes + if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) { + log_e("Error while reading attributes"); + return; + } else { + //Call the callback function when all attributes are read + _on_config_receive(_min_temp, _max_temp, _tolerance); + } +} + +void ZigbeeThermostat::getSensorSettings(uint8_t endpoint, uint16_t short_addr) { + /* Send "read attributes" command to specific endpoint */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_endpoint = endpoint; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + uint16_t attributes[] = { + ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID + }; + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); + read_req.attr_field = attributes; + + log_i("Sending 'read sensor settings' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); + + //Take semaphore to wait for response of all attributes + if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) { + log_e("Error while reading attributes"); + return; + } else { + //Call the callback function when all attributes are read + _on_config_receive(_min_temp, _max_temp, _tolerance); + } +} + +void ZigbeeThermostat::getSensorSettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) { + /* Send "read attributes" command to specific endpoint */ + esp_zb_zcl_read_attr_cmd_t read_req = {0}; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_endpoint = endpoint; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + + uint16_t attributes[] = { + ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID + }; + read_req.attr_number = ZB_ARRAY_LENGHT(attributes); + read_req.attr_field = attributes; + + log_i( + "Sending 'read sensor settings' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], + ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_read_attr_cmd_req(&read_req); esp_zb_lock_release(); @@ -187,13 +345,13 @@ void ZigbeeThermostat::getSensorSettings() { return; } else { //Call the callback function when all attributes are read - _on_config_recieve(_min_temp, _max_temp, _tolerance); + _on_config_receive(_min_temp, _max_temp, _tolerance); } } void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta) { - /* Send "configure report attribute" command to the bound sensor */ - esp_zb_zcl_config_report_cmd_t report_cmd; + /* Send "configure report attribute" command to all bound sensors */ + esp_zb_zcl_config_report_cmd_t report_cmd = {0}; report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; report_cmd.zcl_basic_cmd.src_endpoint = _endpoint; report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; @@ -206,10 +364,10 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, .min_interval = min_interval, .max_interval = max_interval, - .reportable_change = &report_change, + .reportable_change = (void *)&report_change, }, }; - report_cmd.record_number = ZB_ARRAY_LENTH(records); + report_cmd.record_number = ZB_ARRAY_LENGHT(records); report_cmd.record_field = records; log_i("Sending 'configure reporting' command"); @@ -218,4 +376,93 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m esp_zb_lock_release(); } +void ZigbeeThermostat::setTemperatureReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta) { + /* Send "configure report attribute" command to the group */ + esp_zb_zcl_config_report_cmd_t report_cmd = {0}; + report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + report_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_cmd.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + int16_t report_change = (int16_t)delta * 100; + esp_zb_zcl_config_report_record_t records[] = { + { + .direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND, + .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, + .min_interval = min_interval, + .max_interval = max_interval, + .reportable_change = (void *)&report_change, + }, + }; + report_cmd.record_number = ZB_ARRAY_LENGHT(records); + report_cmd.record_field = records; + + log_i("Sending 'configure reporting' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_config_report_cmd_req(&report_cmd); + esp_zb_lock_release(); +} + +void ZigbeeThermostat::setTemperatureReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta) { + /* Send "configure report attribute" command to specific endpoint */ + esp_zb_zcl_config_report_cmd_t report_cmd = {0}; + report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + report_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_cmd.zcl_basic_cmd.dst_endpoint = endpoint; + report_cmd.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + int16_t report_change = (int16_t)delta * 100; + esp_zb_zcl_config_report_record_t records[] = { + { + .direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND, + .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, + .min_interval = min_interval, + .max_interval = max_interval, + .reportable_change = (void *)&report_change, + }, + }; + report_cmd.record_number = ZB_ARRAY_LENGHT(records); + report_cmd.record_field = records; + + log_i("Sending 'configure reporting' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_config_report_cmd_req(&report_cmd); + esp_zb_lock_release(); +} + +void ZigbeeThermostat::setTemperatureReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta) { + /* Send "configure report attribute" command to specific endpoint */ + esp_zb_zcl_config_report_cmd_t report_cmd = {0}; + report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + report_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_cmd.zcl_basic_cmd.dst_endpoint = endpoint; + report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + memcpy(report_cmd.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + + int16_t report_change = (int16_t)delta * 100; + esp_zb_zcl_config_report_record_t records[] = { + { + .direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND, + .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, + .min_interval = min_interval, + .max_interval = max_interval, + .reportable_change = (void *)&report_change, + }, + }; + report_cmd.record_number = ZB_ARRAY_LENGHT(records); + report_cmd.record_field = records; + + log_i( + "Sending 'configure reporting' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], + ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_config_report_cmd_req(&report_cmd); + esp_zb_lock_release(); +} + #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.h b/libraries/Zigbee/src/ep/ZigbeeThermostat.h index acdcd68e512..c10a9d7f974 100644 --- a/libraries/Zigbee/src/ep/ZigbeeThermostat.h +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.h @@ -34,24 +34,39 @@ class ZigbeeThermostat : public ZigbeeEP { ZigbeeThermostat(uint8_t endpoint); ~ZigbeeThermostat() {} - void onTempRecieve(void (*callback)(float)) { - _on_temp_recieve = callback; + void onTempReceive(void (*callback)(float)) { + _on_temp_receive = callback; } - void onConfigRecieve(void (*callback)(float, float, float)) { - _on_config_recieve = callback; + void onTempReceiveWithSource(void (*callback)(float, uint8_t, esp_zb_zcl_addr_t)) { + _on_temp_receive_with_source = callback; + } + void onConfigReceive(void (*callback)(float, float, float)) { + _on_config_receive = callback; } void getTemperature(); + void getTemperature(uint16_t group_addr); + void getTemperature(uint8_t endpoint, uint16_t short_addr); + void getTemperature(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); + void getSensorSettings(); + void getSensorSettings(uint16_t group_addr); + void getSensorSettings(uint8_t endpoint, uint16_t short_addr); + void getSensorSettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); + void setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta); + void setTemperatureReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta); + void setTemperatureReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta); + void setTemperatureReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta); private: // save instance of the class in order to use it in static functions static ZigbeeThermostat *_instance; zb_device_params_t *_device; - void (*_on_temp_recieve)(float); - void (*_on_config_recieve)(float, float, float); + void (*_on_temp_receive)(float); + void (*_on_temp_receive_with_source)(float, uint8_t, esp_zb_zcl_addr_t); + void (*_on_config_receive)(float, float, float); float _min_temp; float _max_temp; float _tolerance; @@ -62,7 +77,7 @@ class ZigbeeThermostat : public ZigbeeEP { static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx); static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); - void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override; + void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) override; }; #endif // CONFIG_ZB_ENABLED From e3018b67191ec621cbd28b872f99c259de83a7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:40:52 +0200 Subject: [PATCH 08/20] feat(zigbee): Add method to set/get/report analog output (#11431) * feat(zigbee): Add methot to set,get,report analog output * fix(ci): Update json file for example * fix(zigbee): Add missing keywords * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../Zigbee_Analog_Input_Output.ino | 12 +++-- .../Zigbee_Analog_Input_Output/ci.json | 3 +- libraries/Zigbee/keywords.txt | 11 ++++- libraries/Zigbee/src/ep/ZigbeeAnalog.cpp | 49 +++++++++++++++++-- libraries/Zigbee/src/ep/ZigbeeAnalog.h | 14 ++++-- 5 files changed, 74 insertions(+), 15 deletions(-) diff --git a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino index db8a62b091e..59c4b514db1 100644 --- a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino +++ b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino @@ -26,8 +26,8 @@ * Modified by Pat Clay */ -#ifndef ZIGBEE_MODE_ED -#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator/router device mode is not selected in Tools->Zigbee mode" #endif #include "Zigbee.h" @@ -70,6 +70,7 @@ void setup() { zbAnalogDevice.addAnalogOutput(); zbAnalogDevice.setAnalogOutputApplication(ESP_ZB_ZCL_AI_RPM_OTHER); zbAnalogDevice.setAnalogOutputDescription("Fan Speed (RPM)"); + zbAnalogDevice.setAnalogOutputResolution(1); // If analog output cluster is added, set callback function for analog output change zbAnalogDevice.onAnalogOutputChange(onAnalogOutputChange); @@ -99,8 +100,8 @@ void setup() { Zigbee.addEndpoint(&zbAnalogPercent); Serial.println("Starting Zigbee..."); - // When all EPs are registered, start Zigbee in End Device mode - if (!Zigbee.begin()) { + // When all EPs are registered, start Zigbee in Router Device mode + if (!Zigbee.begin(ZIGBEE_ROUTER)) { Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); ESP.restart(); @@ -151,6 +152,9 @@ void loop() { Zigbee.factoryReset(); } } + // For demonstration purposes, increment the analog output value by 100 + zbAnalogDevice.setAnalogOutput(zbAnalogDevice.getAnalogOutput() + 100); + zbAnalogDevice.reportAnalogOutput(); } delay(100); } diff --git a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/ci.json b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/ci.json index ceacc367801..15d6190e4ae 100644 --- a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/ci.json @@ -1,7 +1,6 @@ { - "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", "requires": [ - "CONFIG_SOC_IEEE802154_SUPPORTED=y", "CONFIG_ZB_ENABLED=y" ] } diff --git a/libraries/Zigbee/keywords.txt b/libraries/Zigbee/keywords.txt index 5ce1e8f6f51..556b6408ea2 100644 --- a/libraries/Zigbee/keywords.txt +++ b/libraries/Zigbee/keywords.txt @@ -143,14 +143,21 @@ setSensorType KEYWORD2 setCarbonDioxide KEYWORD2 # ZigbeeAnalog -addAnalogValue KEYWORD2 addAnalogInput KEYWORD2 addAnalogOutput KEYWORD2 onAnalogOutputChange KEYWORD2 -setAnalogValue KEYWORD2 setAnalogInput KEYWORD2 +setAnalogOutput KEYWORD2 +getAnalogOutput KEYWORD2 reportAnalogInput KEYWORD2 +reportAnalogOutput KEYWORD2 setAnalogInputReporting KEYWORD2 +setAnalogInputApplication KEYWORD2 +setAnalogInputDescription KEYWORD2 +setAnalogInputResolution KEYWORD2 +setAnalogOutputApplication KEYWORD2 +setAnalogOutputDescription KEYWORD2 +setAnalogOutputResolution KEYWORD2 # ZigbeeCarbonDioxideSensor setCarbonDioxide KEYWORD2 diff --git a/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp b/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp index 6e073c345bc..893a9854ecc 100644 --- a/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp @@ -129,8 +129,8 @@ bool ZigbeeAnalog::setAnalogOutputApplication(uint32_t application_type) { void ZigbeeAnalog::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) { if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT) { if (message->attribute.id == ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_PRESENT_VALUE_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_SINGLE) { - float analog_output = *(float *)message->attribute.data.value; - analogOutputChanged(analog_output); + _output_state = *(float *)message->attribute.data.value; + analogOutputChanged(); } else { log_w("Received message ignored. Attribute ID: %d not supported for Analog Output", message->attribute.id); } @@ -139,9 +139,9 @@ void ZigbeeAnalog::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *mes } } -void ZigbeeAnalog::analogOutputChanged(float analog_output) { +void ZigbeeAnalog::analogOutputChanged() { if (_on_analog_output_change) { - _on_analog_output_change(analog_output); + _on_analog_output_change(_output_state); } else { log_w("No callback function set for analog output change"); } @@ -166,6 +166,26 @@ bool ZigbeeAnalog::setAnalogInput(float analog) { return true; } +bool ZigbeeAnalog::setAnalogOutput(float analog) { + esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS; + _output_state = analog; + analogOutputChanged(); + + log_v("Updating analog output to %.2f", analog); + /* Update analog output */ + esp_zb_lock_acquire(portMAX_DELAY); + ret = esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_PRESENT_VALUE_ID, &_output_state, false + ); + esp_zb_lock_release(); + + if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Failed to set analog output: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); + return false; + } + return true; +} + bool ZigbeeAnalog::reportAnalogInput() { /* Send report attributes command */ esp_zb_zcl_report_attr_cmd_t report_attr_cmd; @@ -187,6 +207,27 @@ bool ZigbeeAnalog::reportAnalogInput() { return true; } +bool ZigbeeAnalog::reportAnalogOutput() { + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_PRESENT_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + if (ret != ESP_OK) { + log_e("Failed to send Analog Output report: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + log_v("Analog Output report sent"); + return true; +} + bool ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta) { esp_zb_zcl_reporting_info_t reporting_info; memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t)); diff --git a/libraries/Zigbee/src/ep/ZigbeeAnalog.h b/libraries/Zigbee/src/ep/ZigbeeAnalog.h index e0c3fc11c5a..bbc5f6d6fc2 100644 --- a/libraries/Zigbee/src/ep/ZigbeeAnalog.h +++ b/libraries/Zigbee/src/ep/ZigbeeAnalog.h @@ -46,11 +46,18 @@ class ZigbeeAnalog : public ZigbeeEP { _on_analog_output_change = callback; } - // Set the analog input value + // Set the Analog Input/Output value bool setAnalogInput(float analog); + bool setAnalogOutput(float analog); - // Report Analog Input value + // Get the Analog Output value + float getAnalogOutput() { + return _output_state; + } + + // Report Analog Input/Output bool reportAnalogInput(); + bool reportAnalogOutput(); // Set reporting for Analog Input bool setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta); @@ -59,9 +66,10 @@ class ZigbeeAnalog : public ZigbeeEP { void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; void (*_on_analog_output_change)(float); - void analogOutputChanged(float analog_output); + void analogOutputChanged(); uint8_t _analog_clusters; + float _output_state; }; #endif // CONFIG_ZB_ENABLED From 31d22e6ed05a26a7fd7765b9ae42fd292559690f Mon Sep 17 00:00:00 2001 From: SooD <45733639+syong0921@users.noreply.github.com> Date: Thu, 5 Jun 2025 00:49:09 +0900 Subject: [PATCH 09/20] fix: change geekble nano board setting (#11432) add PSRAM Setting --- boards.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards.txt b/boards.txt index d92f057a78f..7e86af52a4f 100644 --- a/boards.txt +++ b/boards.txt @@ -41778,6 +41778,13 @@ Geekble_Nano_ESP32S3.menu.PartitionScheme.custom=Custom Geekble_Nano_ESP32S3.menu.PartitionScheme.custom.build.partitions= Geekble_Nano_ESP32S3.menu.PartitionScheme.custom.upload.maximum_size=16777216 +Geekble_Nano_ESP32S3.menu.PSRAM.disabled=Disabled +Geekble_Nano_ESP32S3.menu.PSRAM.disabled.build.defines= +Geekble_Nano_ESP32S3.menu.PSRAM.disabled.build.psram_type=qspi +Geekble_Nano_ESP32S3.menu.PSRAM.enabled=Enabled +Geekble_Nano_ESP32S3.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +Geekble_Nano_ESP32S3.menu.PSRAM.enabled.build.psram_type=qspi + Geekble_Nano_ESP32S3.menu.DebugLevel.none=None Geekble_Nano_ESP32S3.menu.DebugLevel.none.build.code_debug=0 Geekble_Nano_ESP32S3.menu.DebugLevel.error=Error From 1bac8de384c6e27abde8901b4fb3ca712d11cf1b Mon Sep 17 00:00:00 2001 From: SooD <45733639+syong0921@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:29:11 +0900 Subject: [PATCH 10/20] fix: Updated the tools options for Geekble Mini (#11437) fix: Updated the tools options for Geekble Mini --- boards.txt | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/boards.txt b/boards.txt index 7e86af52a4f..49a4d9a737d 100644 --- a/boards.txt +++ b/boards.txt @@ -41589,11 +41589,6 @@ Geekble_ESP32C3.build.boot=qio Geekble_ESP32C3.build.partitions=default Geekble_ESP32C3.build.defines= -Geekble_ESP32C3.menu.CDCOnBoot.default=Enabled -Geekble_ESP32C3.menu.CDCOnBoot.default.build.cdc_on_boot=1 -Geekble_ESP32C3.menu.CDCOnBoot.cdc=Disabled -Geekble_ESP32C3.menu.CDCOnBoot.cdc.build.cdc_on_boot=0 - Geekble_ESP32C3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) Geekble_ESP32C3.menu.PartitionScheme.default.build.partitions=default Geekble_ESP32C3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -41614,39 +41609,6 @@ Geekble_ESP32C3.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) Geekble_ESP32C3.menu.PartitionScheme.huge_app.build.partitions=huge_app Geekble_ESP32C3.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 -Geekble_ESP32C3.menu.CPUFreq.160=160MHz (WiFi) (Default) -Geekble_ESP32C3.menu.CPUFreq.160.build.f_cpu=160000000L -Geekble_ESP32C3.menu.CPUFreq.80=80MHz (WiFi) -Geekble_ESP32C3.menu.CPUFreq.80.build.f_cpu=80000000L -Geekble_ESP32C3.menu.CPUFreq.40=40MHz -Geekble_ESP32C3.menu.CPUFreq.40.build.f_cpu=40000000L -Geekble_ESP32C3.menu.CPUFreq.20=20MHz -Geekble_ESP32C3.menu.CPUFreq.20.build.f_cpu=20000000L -Geekble_ESP32C3.menu.CPUFreq.10=10MHz -Geekble_ESP32C3.menu.CPUFreq.10.build.f_cpu=10000000L - -Geekble_ESP32C3.menu.FlashMode.qio=QIO (Default) -Geekble_ESP32C3.menu.FlashMode.qio.build.flash_mode=dio -Geekble_ESP32C3.menu.FlashMode.qio.build.boot=qio -Geekble_ESP32C3.menu.FlashMode.dio=DIO -Geekble_ESP32C3.menu.FlashMode.dio.build.flash_mode=dio -Geekble_ESP32C3.menu.FlashMode.dio.build.boot=dio -Geekble_ESP32C3.menu.FlashMode.qout=QOUT -Geekble_ESP32C3.menu.FlashMode.qout.build.flash_mode=dout -Geekble_ESP32C3.menu.FlashMode.qout.build.boot=qout -Geekble_ESP32C3.menu.FlashMode.dout=DOUT -Geekble_ESP32C3.menu.FlashMode.dout.build.flash_mode=dout - -Geekble_ESP32C3.menu.FlashFreq.80=80MHz (Default) -Geekble_ESP32C3.menu.FlashFreq.80.build.flash_freq=80m -Geekble_ESP32C3.menu.FlashFreq.40=40MHz -Geekble_ESP32C3.menu.FlashFreq.40.build.flash_freq=40m - -Geekble_ESP32C3.menu.FlashSize.4M=4MB (Default) -Geekble_ESP32C3.menu.FlashSize.4M.build.flash_size=4MB -Geekble_ESP32C3.menu.FlashSize.2M=2MB -Geekble_ESP32C3.menu.FlashSize.2M.build.flash_size=2MB - Geekble_ESP32C3.menu.UploadSpeed.921600=921600 (Default) Geekble_ESP32C3.menu.UploadSpeed.921600.upload.speed=921600 Geekble_ESP32C3.menu.UploadSpeed.115200=115200 From 610d951f9d1ddf690b786600bccddb515f1f0b5b Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:29:29 +0200 Subject: [PATCH 11/20] include "esp_bt.h" only when existing (#11438) --- cores/esp32/esp32-hal-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 594acd38153..aadd08ceffc 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -25,7 +25,7 @@ #include "esp_ota_ops.h" #endif //CONFIG_APP_ROLLBACK_ENABLE #include "esp_private/startup_internal.h" -#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED && __has_include("esp_bt.h") #include "esp_bt.h" #endif //CONFIG_BT_BLUEDROID_ENABLED #include From ee347baa7dca0cbe87dbd579465bbe00924f9b03 Mon Sep 17 00:00:00 2001 From: i3water <121024123@qq.com> Date: Tue, 10 Jun 2025 15:29:46 +0800 Subject: [PATCH 12/20] feat(boards): update wifiduinov2&wifiduino32s3 boards setting (#11440) * update wifiduinov2&wifiduino32s3 boards setting * fix wifiduinov2&wifiduino32s3 build board error. * fix wifiduinov2(esp32c3) board setting * fix wifiduinov2(esp32c3) cdc on boot default setting. * fix wifiduino32s3 spi pin set * change wifiduino32s3 spi pin to spi1 * remove 32Mb flash size * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 46 +++++++++---------- variants/wifiduino32s3/pins_arduino.h | 66 ++++++++++++++++----------- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/boards.txt b/boards.txt index 49a4d9a737d..fefc6cdfb71 100644 --- a/boards.txt +++ b/boards.txt @@ -31513,16 +31513,16 @@ wifiduino32c3.build.target=esp wifiduino32c3.build.mcu=esp32c3 wifiduino32c3.build.core=esp32 wifiduino32c3.build.variant=wifiduinov2 -wifiduino32c3.build.board=WiFiduinoV2 +wifiduino32c3.build.board=WIFIDUINOV2 wifiduino32c3.build.bootloader_addr=0x0 wifiduino32c3.build.cdc_on_boot=0 wifiduino32c3.build.f_cpu=160000000L wifiduino32c3.build.flash_size=4MB wifiduino32c3.build.flash_freq=80m -wifiduino32c3.build.flash_mode=qio -wifiduino32c3.build.boot=qio -wifiduino32c3.build.partitions=default +wifiduino32c3.build.flash_mode=dio +wifiduino32c3.build.boot=dio +wifiduino32c3.build.partitions=no_ota wifiduino32c3.build.defines= wifiduino32c3.menu.CDCOnBoot.default=Disabled @@ -31530,6 +31530,9 @@ wifiduino32c3.menu.CDCOnBoot.default.build.cdc_on_boot=0 wifiduino32c3.menu.CDCOnBoot.cdc=Enabled wifiduino32c3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +wifiduino32c3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +wifiduino32c3.menu.PartitionScheme.no_ota.build.partitions=no_ota +wifiduino32c3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 wifiduino32c3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) wifiduino32c3.menu.PartitionScheme.default.build.partitions=default wifiduino32c3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -31539,9 +31542,6 @@ wifiduino32c3.menu.PartitionScheme.default_8MB.build.partitions=default_8MB wifiduino32c3.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 wifiduino32c3.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) wifiduino32c3.menu.PartitionScheme.minimal.build.partitions=minimal -wifiduino32c3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) -wifiduino32c3.menu.PartitionScheme.no_ota.build.partitions=no_ota -wifiduino32c3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 wifiduino32c3.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) wifiduino32c3.menu.PartitionScheme.noota_3g.build.partitions=noota_3g wifiduino32c3.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 @@ -31584,12 +31584,12 @@ wifiduino32c3.menu.CPUFreq.20.build.f_cpu=20000000L wifiduino32c3.menu.CPUFreq.10=10MHz wifiduino32c3.menu.CPUFreq.10.build.f_cpu=10000000L -wifiduino32c3.menu.FlashMode.qio=QIO -wifiduino32c3.menu.FlashMode.qio.build.flash_mode=dio -wifiduino32c3.menu.FlashMode.qio.build.boot=qio wifiduino32c3.menu.FlashMode.dio=DIO wifiduino32c3.menu.FlashMode.dio.build.flash_mode=dio wifiduino32c3.menu.FlashMode.dio.build.boot=dio +wifiduino32c3.menu.FlashMode.qio=QIO +wifiduino32c3.menu.FlashMode.qio.build.flash_mode=dio +wifiduino32c3.menu.FlashMode.qio.build.boot=qio wifiduino32c3.menu.FlashFreq.80=80MHz wifiduino32c3.menu.FlashFreq.80.build.flash_freq=80m @@ -31665,34 +31665,34 @@ wifiduino32s3.build.target=esp32s3 wifiduino32s3.build.mcu=esp32s3 wifiduino32s3.build.core=esp32 wifiduino32s3.build.variant=wifiduino32s3 -wifiduino32s3.build.board=WiFiduino32S3 +wifiduino32s3.build.board=WIFIDUINO32S3 wifiduino32s3.build.usb_mode=1 wifiduino32s3.build.cdc_on_boot=0 wifiduino32s3.build.msc_on_boot=0 wifiduino32s3.build.dfu_on_boot=0 wifiduino32s3.build.f_cpu=240000000L -wifiduino32s3.build.flash_size=4MB +wifiduino32s3.build.flash_size=16MB wifiduino32s3.build.flash_freq=80m wifiduino32s3.build.flash_mode=dio wifiduino32s3.build.boot=qio wifiduino32s3.build.boot_freq=80m -wifiduino32s3.build.partitions=default +wifiduino32s3.build.partitions=app3M_fat9M_16MB wifiduino32s3.build.defines= wifiduino32s3.build.loop_core= wifiduino32s3.build.event_core= -wifiduino32s3.build.psram_type=qspi +wifiduino32s3.build.psram_type=opi wifiduino32s3.build.memory_type={build.boot}_{build.psram_type} +wifiduino32s3.menu.PSRAM.opi=OPI PSRAM +wifiduino32s3.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM +wifiduino32s3.menu.PSRAM.opi.build.psram_type=opi wifiduino32s3.menu.PSRAM.disabled=Disabled wifiduino32s3.menu.PSRAM.disabled.build.defines= wifiduino32s3.menu.PSRAM.disabled.build.psram_type=qspi wifiduino32s3.menu.PSRAM.enabled=QSPI PSRAM wifiduino32s3.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM wifiduino32s3.menu.PSRAM.enabled.build.psram_type=qspi -wifiduino32s3.menu.PSRAM.opi=OPI PSRAM -wifiduino32s3.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM -wifiduino32s3.menu.PSRAM.opi.build.psram_type=opi wifiduino32s3.menu.FlashMode.qio=QIO 80MHz wifiduino32s3.menu.FlashMode.qio.build.flash_mode=dio @@ -31715,12 +31715,10 @@ wifiduino32s3.menu.FlashMode.opi.build.boot=opi wifiduino32s3.menu.FlashMode.opi.build.boot_freq=80m wifiduino32s3.menu.FlashMode.opi.build.flash_freq=80m -wifiduino32s3.menu.FlashSize.4M=4MB (32Mb) -wifiduino32s3.menu.FlashSize.4M.build.flash_size=4MB -wifiduino32s3.menu.FlashSize.8M=8MB (64Mb) -wifiduino32s3.menu.FlashSize.8M.build.flash_size=8MB wifiduino32s3.menu.FlashSize.16M=16MB (128Mb) wifiduino32s3.menu.FlashSize.16M.build.flash_size=16MB +wifiduino32s3.menu.FlashSize.8M=8MB (64Mb) +wifiduino32s3.menu.FlashSize.8M.build.flash_size=8MB #wifiduino32s3.menu.FlashSize.32M=32MB (256Mb) #wifiduino32s3.menu.FlashSize.32M.build.flash_size=32MB @@ -31761,6 +31759,9 @@ wifiduino32s3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) wifiduino32s3.menu.UploadMode.cdc.upload.use_1200bps_touch=true wifiduino32s3.menu.UploadMode.cdc.upload.wait_for_upload_port=true +wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 wifiduino32s3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) wifiduino32s3.menu.PartitionScheme.default.build.partitions=default wifiduino32s3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) @@ -31791,9 +31792,6 @@ wifiduino32s3.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 wifiduino32s3.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) wifiduino32s3.menu.PartitionScheme.fatflash.build.partitions=ffat wifiduino32s3.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 -wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) -wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB -wifiduino32s3.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 wifiduino32s3.menu.PartitionScheme.rainmaker=RainMaker 4MB wifiduino32s3.menu.PartitionScheme.rainmaker.build.partitions=rainmaker wifiduino32s3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 diff --git a/variants/wifiduino32s3/pins_arduino.h b/variants/wifiduino32s3/pins_arduino.h index d26e415910e..4fc08139c0e 100644 --- a/variants/wifiduino32s3/pins_arduino.h +++ b/variants/wifiduino32s3/pins_arduino.h @@ -2,43 +2,57 @@ #define Pins_Arduino_h #include - -#define USB_VID 0x303a -#define USB_PID 0x1001 - -// No USER LED or NeoLED - -static const uint8_t TX = 45; +#include "soc/soc_caps.h" + +#define USB_VID 0x303a +#define USB_PID 0x1001 +#define USB_MANUFACTURER "openjumper" +#define USB_PRODUCT "Wifiduino32-S3" +#define USB_SERIAL "" // Empty string for MAC address + +// Some boards have too low voltage on this pin (board design bug) +// Use different pin with 3V and connect with 48 +// and change this setup for the chosen pin (for example 38) +#define PIN_RGB_LED 48 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGB_BRIGHTNESS 64 + +static const uint8_t TX = 43; static const uint8_t RX = 44; static const uint8_t SDA = 4; static const uint8_t SCL = 5; -static const uint8_t SS = 46; -static const uint8_t MOSI = 3; -static const uint8_t MISO = 20; -static const uint8_t SCK = 19; +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 13; +static const uint8_t SCK = 12; -static const uint8_t A0 = 7; -static const uint8_t A1 = 6; +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; static const uint8_t A2 = 2; -static const uint8_t A3 = 1; +static const uint8_t A3 = 3; static const uint8_t A4 = 4; static const uint8_t A5 = 5; static const uint8_t D0 = 44; -static const uint8_t D1 = 45; -static const uint8_t D2 = 42; -static const uint8_t D3 = 41; -static const uint8_t D4 = 0; -static const uint8_t D5 = 45; -static const uint8_t D6 = 48; -static const uint8_t D7 = 47; +static const uint8_t D1 = 43; +static const uint8_t D2 = 45; +static const uint8_t D3 = 46; +static const uint8_t D4 = 47; +static const uint8_t D5 = 48; +static const uint8_t D6 = 18; +static const uint8_t D7 = 17; static const uint8_t D8 = 21; -static const uint8_t D9 = 14; -static const uint8_t D10 = 46; -static const uint8_t D11 = 3; -static const uint8_t D12 = 20; -static const uint8_t D13 = 19; +static const uint8_t D9 = 42; +static const uint8_t D10 = 41; +static const uint8_t D11 = 40; +static const uint8_t D12 = 38; +static const uint8_t D13 = 39; #endif /* Pins_Arduino_h */ From af47bd30089bee71849b634b97dd329e6564a10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:59:56 +0200 Subject: [PATCH 13/20] fix(ci): Process only needed files in publish sizes (#11439) --- .github/workflows/publishsizes.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publishsizes.yml b/.github/workflows/publishsizes.yml index 69c18cf1835..8ff591e052b 100644 --- a/.github/workflows/publishsizes.yml +++ b/.github/workflows/publishsizes.yml @@ -44,16 +44,17 @@ jobs: gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact do IFS=$'\t' read name url <<< "$artifact" - gh api $url > "$name.zip" - unzip -j "$name.zip" -d "temp_$name" - if [[ "$name" == "pr_number" ]]; then - mv "temp_$name"/* sizes-report - elif [[ "$name" == "pr_cli"* ]]; then - mv "temp_$name"/* sizes-report/pr - else - mv "temp_$name"/* sizes-report + # Only process pr_number and pr_cli_compile artifacts + if [[ "$name" == "pr_number" || "$name" =~ ^pr_cli_compile_[0-9]+$ ]]; then + gh api $url > "$name.zip" + unzip -o -j "$name.zip" -d "temp_$name" + if [[ "$name" == "pr_number" ]]; then + mv "temp_$name"/* sizes-report + elif [[ "$name" =~ ^pr_cli_compile_[0-9]+$ ]]; then + mv "temp_$name"/* sizes-report/pr + fi + rm -r "temp_$name" fi - rm -r "temp_$name" done echo "Contents of parent directory:" ls -R .. From 0007815a1148c7a3d24a3f6986739bc2b26eb5c7 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 10 Jun 2025 11:00:20 +0300 Subject: [PATCH 14/20] feat(p4): Add 32MB Flash Partitions to ESP32-P4 (#11453) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(p4): Add 32MB Flash Partitions to ESP32-P4 * feat(p4): Add 32MB flash size option --------- Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com> --- boards.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boards.txt b/boards.txt index fefc6cdfb71..15a75eaad8b 100644 --- a/boards.txt +++ b/boards.txt @@ -282,6 +282,15 @@ esp32p4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 esp32p4.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +esp32p4.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) +esp32p4.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB +esp32p4.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 +esp32p4.menu.PartitionScheme.app5M_little24M_32MB=32M Flash (4.8MB APP/22MB LittleFS) +esp32p4.menu.PartitionScheme.app5M_little24M_32MB.build.partitions=large_littlefs_32MB +esp32p4.menu.PartitionScheme.app5M_little24M_32MB.upload.maximum_size=4718592 +esp32p4.menu.PartitionScheme.app13M_data7M_32MB=32M Flash (13MB APP/6.75MB SPIFFS) +esp32p4.menu.PartitionScheme.app13M_data7M_32MB.build.partitions=default_32MB +esp32p4.menu.PartitionScheme.app13M_data7M_32MB.upload.maximum_size=13107200 esp32p4.menu.PartitionScheme.custom=Custom esp32p4.menu.PartitionScheme.custom.build.partitions= esp32p4.menu.PartitionScheme.custom.upload.maximum_size=16777216 @@ -314,6 +323,8 @@ esp32p4.menu.FlashSize.2M.build.flash_size=2MB esp32p4.menu.FlashSize.2M.build.partitions=minimal esp32p4.menu.FlashSize.16M=16MB (128Mb) esp32p4.menu.FlashSize.16M.build.flash_size=16MB +esp32p4.menu.FlashSize.32M=32MB (256Mb) +esp32p4.menu.FlashSize.32M.build.flash_size=32MB esp32p4.menu.UploadSpeed.921600=921600 esp32p4.menu.UploadSpeed.921600.upload.speed=921600 From 0aada091e1afb56bb4e2103297233b17a9463bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:31:17 +0200 Subject: [PATCH 15/20] feat(zigbee): Support min/max setting for Analog EP (#11451) * feat(zigbee): Support min max for Analog EP * feat(zigbee): Use cfloat FLT_MAX * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../Zigbee_Analog_Input_Output.ino | 3 + libraries/Zigbee/src/ep/ZigbeeAnalog.cpp | 84 +++++++++++++++++++ libraries/Zigbee/src/ep/ZigbeeAnalog.h | 4 + 3 files changed, 91 insertions(+) diff --git a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino index 59c4b514db1..f1cc54bda64 100644 --- a/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino +++ b/libraries/Zigbee/examples/Zigbee_Analog_Input_Output/Zigbee_Analog_Input_Output.ino @@ -72,6 +72,9 @@ void setup() { zbAnalogDevice.setAnalogOutputDescription("Fan Speed (RPM)"); zbAnalogDevice.setAnalogOutputResolution(1); + // Set the min and max values for the analog output which is used by HA to limit the range of the analog output + zbAnalogDevice.setAnalogOutputMinMax(-10000, 10000); //-10000 to 10000 RPM + // If analog output cluster is added, set callback function for analog output change zbAnalogDevice.onAnalogOutputChange(onAnalogOutputChange); diff --git a/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp b/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp index 893a9854ecc..309739d54c9 100644 --- a/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeAnalog.cpp @@ -1,5 +1,6 @@ #include "ZigbeeAnalog.h" #if CONFIG_ZB_ENABLED +#include ZigbeeAnalog::ZigbeeAnalog(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; @@ -20,6 +21,8 @@ bool ZigbeeAnalog::addAnalogInput() { "Analog Input"; uint32_t application_type = 0x00000000 | (ESP_ZB_ZCL_AI_GROUP_ID << 24); float resolution = 0.1; // Default resolution of 0.1 + float min = -FLT_MAX; // Default min value for float + float max = FLT_MAX; // Default max value for float esp_err_t ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_DESCRIPTION_ID, (void *)default_description); if (ret != ESP_OK) { @@ -39,11 +42,24 @@ bool ZigbeeAnalog::addAnalogInput() { return false; } + ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MIN_PRESENT_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_analog_input_cluster_add_attr(esp_zb_analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MAX_PRESENT_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_list_add_analog_input_cluster(_cluster_list, esp_zb_analog_input_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); if (ret != ESP_OK) { log_e("Failed to add Analog Input cluster: 0x%x: %s", ret, esp_err_to_name(ret)); return false; } + _analog_clusters |= ANALOG_INPUT; return true; } @@ -76,6 +92,8 @@ bool ZigbeeAnalog::addAnalogOutput() { "Analog Output"; uint32_t application_type = 0x00000000 | (ESP_ZB_ZCL_AO_GROUP_ID << 24); float resolution = 1; // Default resolution of 1 + float min = -FLT_MAX; // Default min value for float + float max = FLT_MAX; // Default max value for float esp_err_t ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_DESCRIPTION_ID, (void *)default_description); @@ -96,6 +114,18 @@ bool ZigbeeAnalog::addAnalogOutput() { return false; } + ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MIN_PRESENT_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_analog_output_cluster_add_attr(esp_zb_analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MAX_PRESENT_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + ret = esp_zb_cluster_list_add_analog_output_cluster(_cluster_list, esp_zb_analog_output_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); if (ret != ESP_OK) { log_e("Failed to add Analog Output cluster: 0x%x: %s", ret, esp_err_to_name(ret)); @@ -376,4 +406,58 @@ bool ZigbeeAnalog::setAnalogOutputResolution(float resolution) { return true; } +bool ZigbeeAnalog::setAnalogOutputMinMax(float min, float max) { + if (!(_analog_clusters & ANALOG_OUTPUT)) { + log_e("Analog Output cluster not added"); + return false; + } + + esp_zb_attribute_list_t *analog_output_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_OUTPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (analog_output_cluster == nullptr) { + log_e("Failed to get analog output cluster"); + return false; + } + + esp_err_t ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MIN_PRESENT_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_cluster_update_attr(analog_output_cluster, ESP_ZB_ZCL_ATTR_ANALOG_OUTPUT_MAX_PRESENT_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + +bool ZigbeeAnalog::setAnalogInputMinMax(float min, float max) { + if (!(_analog_clusters & ANALOG_INPUT)) { + log_e("Analog Input cluster not added"); + return false; + } + + esp_zb_attribute_list_t *analog_input_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + if (analog_input_cluster == nullptr) { + log_e("Failed to get analog input cluster"); + return false; + } + + esp_err_t ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MIN_PRESENT_VALUE_ID, (void *)&min); + if (ret != ESP_OK) { + log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + + ret = esp_zb_cluster_update_attr(analog_input_cluster, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_MAX_PRESENT_VALUE_ID, (void *)&max); + if (ret != ESP_OK) { + log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + #endif // CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeAnalog.h b/libraries/Zigbee/src/ep/ZigbeeAnalog.h index bbc5f6d6fc2..5218a0b7d60 100644 --- a/libraries/Zigbee/src/ep/ZigbeeAnalog.h +++ b/libraries/Zigbee/src/ep/ZigbeeAnalog.h @@ -41,6 +41,10 @@ class ZigbeeAnalog : public ZigbeeEP { bool setAnalogOutputDescription(const char *description); bool setAnalogOutputResolution(float resolution); + // Set the min and max values for the analog Input/Output + bool setAnalogOutputMinMax(float min, float max); + bool setAnalogInputMinMax(float min, float max); + // Use to set a cb function to be called on analog output change void onAnalogOutputChange(void (*callback)(float analog)) { _on_analog_output_change = callback; From d6a76da0a5134bce8dfd4961af7e9c828bf21328 Mon Sep 17 00:00:00 2001 From: Niki Waibel Date: Tue, 10 Jun 2025 10:55:43 +0200 Subject: [PATCH 16/20] fix(libraries/asyncudp): IPv4 ONLY listenMulticast() (#11444) AsyncUDP::listenMulticast() properly receives packets sent to IPv4 multicast addresses like 239.1.2.3, but it is not receiving packets sent to IPv6 multicast addresses like ff12::6ood:cafe. The root cause is a bit hidden: listen(NULL, port) would match AsyncUDP::listen(const ip_addr_t *addr, uint16_t port), which calls _udp_bind(_pcb, addr, port), which uses the lwIP API to call udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) at the end. If lwIP has LWIP_IPV4 enabled, it checks if ipaddr == NULL and sets it to IP4_ADDR_ANY. So an IPv6 address is never bound. This fix checks the IP address passed to AsyncUDP::listenMulticast(). If it is an IPv6 address, it constructs and passes the IPv6 any address (::); otherwise (IPv4), it constructs and passes the IPv4 any address (0.0.0.0). --- libraries/AsyncUDP/src/AsyncUDP.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libraries/AsyncUDP/src/AsyncUDP.cpp b/libraries/AsyncUDP/src/AsyncUDP.cpp index f44cc839c97..cab9c951921 100644 --- a/libraries/AsyncUDP/src/AsyncUDP.cpp +++ b/libraries/AsyncUDP/src/AsyncUDP.cpp @@ -682,6 +682,8 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap } bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) { + ip_addr_t bind_addr; + if (!ip_addr_ismulticast(addr)) { return false; } @@ -690,7 +692,18 @@ bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl return false; } - if (!listen(NULL, port)) { +#if CONFIG_LWIP_IPV6 + if (IP_IS_V6(addr)) { + IP_SET_TYPE(&bind_addr, IPADDR_TYPE_V6); + ip6_addr_set_any(&bind_addr.u_addr.ip6); + } else { +#endif + IP_SET_TYPE(&bind_addr, IPADDR_TYPE_V4); + ip4_addr_set_any(&bind_addr.u_addr.ip4); +#if CONFIG_LWIP_IPV6 + } +#endif + if (!listen(&bind_addr, port)) { return false; } From cbdaee6f52b78fa747693dbb718c2cafe99015b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:57:07 +0200 Subject: [PATCH 17/20] feat(ledc): Improve timer management with frequency/resolution matching (#11452) * feat(ledc): Improve timer management with frequency/resolution matching * fix(ci): Fix uninitialized timer variable warning * Update cores/esp32/esp32-hal-ledc.c Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/esp32-hal-ledc.c | 124 +++++++++++++++++++++++++++++++---- cores/esp32/esp32-hal-ledc.h | 2 + 2 files changed, 115 insertions(+), 11 deletions(-) diff --git a/cores/esp32/esp32-hal-ledc.c b/cores/esp32/esp32-hal-ledc.c index 039fa1312f1..764c2803b4b 100644 --- a/cores/esp32/esp32-hal-ledc.c +++ b/cores/esp32/esp32-hal-ledc.c @@ -45,6 +45,93 @@ typedef struct { ledc_periph_t ledc_handle = {0}; +// Helper function to find a timer with matching frequency and resolution +static bool find_matching_timer(uint8_t speed_mode, uint32_t freq, uint8_t resolution, uint8_t *timer_num) { + log_d("Searching for timer with freq=%u, resolution=%u", freq, resolution); + // Check all channels to find one with matching frequency and resolution + for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) { + if (!perimanPinIsValid(i)) { + continue; + } + peripheral_bus_type_t type = perimanGetPinBusType(i); + if (type == ESP32_BUS_TYPE_LEDC) { + ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC); + if (bus != NULL && (bus->channel / 8) == speed_mode && bus->freq_hz == freq && bus->channel_resolution == resolution) { + log_d("Found matching timer %u for freq=%u, resolution=%u", bus->timer_num, freq, resolution); + *timer_num = bus->timer_num; + return true; + } + } + } + log_d("No matching timer found for freq=%u, resolution=%u", freq, resolution); + return false; +} + +// Helper function to find an unused timer +static bool find_free_timer(uint8_t speed_mode, uint8_t *timer_num) { + // Check which timers are in use + uint8_t used_timers = 0; + for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) { + if (!perimanPinIsValid(i)) { + continue; + } + peripheral_bus_type_t type = perimanGetPinBusType(i); + if (type == ESP32_BUS_TYPE_LEDC) { + ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC); + if (bus != NULL && (bus->channel / 8) == speed_mode) { + log_d("Timer %u is in use by channel %u", bus->timer_num, bus->channel); + used_timers |= (1 << bus->timer_num); + } + } + } + + // Find first unused timer + for (uint8_t i = 0; i < SOC_LEDC_TIMER_NUM; i++) { + if (!(used_timers & (1 << i))) { + log_d("Found free timer %u", i); + *timer_num = i; + return true; + } + } + log_e("No free timers available"); + return false; +} + +// Helper function to remove a channel from a timer and clear timer if no channels are using it +static void remove_channel_from_timer(uint8_t speed_mode, uint8_t timer_num, uint8_t channel) { + log_d("Removing channel %u from timer %u in speed_mode %u", channel, timer_num, speed_mode); + + // Check if any other channels are using this timer + bool timer_in_use = false; + for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) { + if (!perimanPinIsValid(i)) { + continue; + } + peripheral_bus_type_t type = perimanGetPinBusType(i); + if (type == ESP32_BUS_TYPE_LEDC) { + ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC); + if (bus != NULL && (bus->channel / 8) == speed_mode && bus->timer_num == timer_num && bus->channel != channel) { + log_d("Timer %u is still in use by channel %u", timer_num, bus->channel); + timer_in_use = true; + break; + } + } + } + + if (!timer_in_use) { + log_d("No other channels using timer %u, deconfiguring timer", timer_num); + // Stop the timer + ledc_timer_pause(speed_mode, timer_num); + // Deconfigure the timer + ledc_timer_config_t ledc_timer; + memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t)); + ledc_timer.speed_mode = speed_mode; + ledc_timer.timer_num = timer_num; + ledc_timer.deconfigure = true; + ledc_timer_config(&ledc_timer); + } +} + static bool fade_initialized = false; static ledc_clk_cfg_t clock_source = LEDC_DEFAULT_CLK; @@ -81,6 +168,8 @@ static bool ledcDetachBus(void *bus) { } pinMatrixOutDetach(handle->pin, false, false); if (!channel_found) { + uint8_t group = (handle->channel / 8); + remove_channel_from_timer(group, handle->timer_num, handle->channel % 8); ledc_handle.used_channels &= ~(1UL << handle->channel); } free(handle); @@ -117,8 +206,10 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c return false; } - uint8_t group = (channel / 8), timer = ((channel / 2) % 4); + uint8_t group = (channel / 8); + uint8_t timer = 0; bool channel_used = ledc_handle.used_channels & (1UL << channel); + if (channel_used) { log_i("Channel %u is already set up, given frequency and resolution will be ignored", channel); if (ledc_set_pin(pin, group, channel % 8) != ESP_OK) { @@ -126,17 +217,26 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c return false; } } else { - ledc_timer_config_t ledc_timer; - memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t)); - ledc_timer.speed_mode = group; - ledc_timer.timer_num = timer; - ledc_timer.duty_resolution = resolution; - ledc_timer.freq_hz = freq; - ledc_timer.clk_cfg = clock_source; + // Find a timer with matching frequency and resolution, or a free timer + if (!find_matching_timer(group, freq, resolution, &timer)) { + if (!find_free_timer(group, &timer)) { + log_e("No free timers available for speed mode %u", group); + return false; + } - if (ledc_timer_config(&ledc_timer) != ESP_OK) { - log_e("ledc setup failed!"); - return false; + // Configure the timer if we're using a new one + ledc_timer_config_t ledc_timer; + memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t)); + ledc_timer.speed_mode = group; + ledc_timer.timer_num = timer; + ledc_timer.duty_resolution = resolution; + ledc_timer.freq_hz = freq; + ledc_timer.clk_cfg = clock_source; + + if (ledc_timer_config(&ledc_timer) != ESP_OK) { + log_e("ledc setup failed!"); + return false; + } } uint32_t duty = ledc_get_duty(group, (channel % 8)); @@ -157,6 +257,8 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c ledc_channel_handle_t *handle = (ledc_channel_handle_t *)malloc(sizeof(ledc_channel_handle_t)); handle->pin = pin; handle->channel = channel; + handle->timer_num = timer; + handle->freq_hz = freq; #ifndef SOC_LEDC_SUPPORT_FADE_STOP handle->lock = NULL; #endif diff --git a/cores/esp32/esp32-hal-ledc.h b/cores/esp32/esp32-hal-ledc.h index 5b44aaad452..f1a27dd4f7a 100644 --- a/cores/esp32/esp32-hal-ledc.h +++ b/cores/esp32/esp32-hal-ledc.h @@ -51,6 +51,8 @@ typedef struct { uint8_t pin; // Pin assigned to channel uint8_t channel; // Channel number uint8_t channel_resolution; // Resolution of channel + uint8_t timer_num; // Timer number used by this channel + uint32_t freq_hz; // Frequency configured for this channel voidFuncPtr fn; void *arg; #ifndef SOC_LEDC_SUPPORT_FADE_STOP From c21ef70a156aa0071f00ee6d7a00e0be2d0aa17e Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Tue, 10 Jun 2025 07:09:27 -0300 Subject: [PATCH 18/20] fix(release): Replace all assets with chinese mirrors (#11323) * fix(release): Replace all assets with chinese mirrors * feat(release): Add script to append "-cn" to versions * docs(install): Add instructions for users in China --- .github/scripts/on-release.sh | 10 +++-- .github/scripts/release_append_cn.py | 56 ++++++++++++++++++++++++++++ docs/en/installing.rst | 2 + 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100755 .github/scripts/release_append_cn.py diff --git a/.github/scripts/on-release.sh b/.github/scripts/on-release.sh index dafbf3d6a1c..275c74f8ea5 100755 --- a/.github/scripts/on-release.sh +++ b/.github/scripts/on-release.sh @@ -342,12 +342,14 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \ echo "Generating $PACKAGE_JSON_DEV ..." cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV" # On MacOS the sed command won't skip the first match. Use gsed instead. -sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN" +sed '0,/github\.com\//!s|github\.com/|dl.espressif.cn/github_assets/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN" +python "$SCRIPTS_DIR/release_append_cn.py" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN" if [ "$RELEASE_PRE" == "false" ]; then echo "Generating $PACKAGE_JSON_REL ..." cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL" # On MacOS the sed command won't skip the first match. Use gsed instead. - sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN" + sed '0,/github\.com\//!s|github\.com/|dl.espressif.cn/github_assets/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN" + python "$SCRIPTS_DIR/release_append_cn.py" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN" fi # Figure out the last release or pre-release @@ -456,14 +458,14 @@ echo "Uploading $PACKAGE_JSON_DEV ..." echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV")" echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV")" echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")" -echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")" +echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV_CN" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")" echo if [ "$RELEASE_PRE" == "false" ]; then echo "Uploading $PACKAGE_JSON_REL ..." echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL")" echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL")" echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")" - echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")" + echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL_CN" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")" echo fi diff --git a/.github/scripts/release_append_cn.py b/.github/scripts/release_append_cn.py new file mode 100755 index 00000000000..b29fe0c31ba --- /dev/null +++ b/.github/scripts/release_append_cn.py @@ -0,0 +1,56 @@ + +#!/usr/bin/env python3 + +# Arduino IDE provides by default a package file for the ESP32. This causes version conflicts +# when the user tries to use the JSON file with the Chinese mirrors. +# +# The downside is that the Arduino IDE will always warn the user that updates are available as it +# will consider the version from the Chinese mirrors as a pre-release version. +# +# This script is used to append "-cn" to all versions in the package_esp32_index_cn.json file so that +# the user can select the Chinese mirrors without conflicts. +# +# If Arduino ever stops providing the package_esp32_index.json file by default, +# this script can be removed and the tags reverted. + +import json + +def append_cn_to_versions(obj): + if isinstance(obj, dict): + # dfu-util comes from arduino.cc and not from the Chinese mirrors, so we skip it + if obj.get("name") == "dfu-util": + return + + for key, value in obj.items(): + if key == "version" and isinstance(value, str): + if not value.endswith("-cn"): + obj[key] = value + "-cn" + else: + append_cn_to_versions(value) + + elif isinstance(obj, list): + for item in obj: + append_cn_to_versions(item) + +def process_json_file(input_path, output_path=None): + with open(input_path, "r", encoding="utf-8") as f: + data = json.load(f) + + append_cn_to_versions(data) + + if output_path is None: + output_path = input_path + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2) + + print(f"Updated JSON written to {output_path}") + +if __name__ == "__main__": + import sys + if len(sys.argv) < 2: + print("Usage: python release_append_cn.py input.json [output.json]") + else: + input_file = sys.argv[1] + output_file = sys.argv[2] if len(sys.argv) > 2 else None + process_json_file(input_file, output_file) diff --git a/docs/en/installing.rst b/docs/en/installing.rst index 35342020864..3ca0881c398 100644 --- a/docs/en/installing.rst +++ b/docs/en/installing.rst @@ -70,6 +70,8 @@ To start the installation process using the Boards Manager, follow these steps: :figclass: align-center - Open Boards Manager from Tools > Board menu and install *esp32* platform (and do not forget to select your ESP32 board from Tools > Board menu after installation). + Users in China must select the package version with the "-cn" suffix and perform updates manually. + Automatic updates are not supported in this region, as they target the default package without the "-cn" suffix, resulting in download failures. .. figure:: ../_static/install_guide_boards_manager_esp32.png :align: center From d71135e2ca72cef49ea417d00ae821b35cf95da3 Mon Sep 17 00:00:00 2001 From: whatsABetterNick Date: Tue, 10 Jun 2025 18:27:47 +0800 Subject: [PATCH 19/20] Fix(I2S example): make fix to the ESP32 I2S simple tone example (#10954) * made some fix to the ESP32 I2S simple tone example * edit the I2S - simple tone example * edit the I2S - simple tone example * some edit * edit comment * edit * edit * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../examples/Simple_tone/Simple_tone.ino | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/ESP_I2S/examples/Simple_tone/Simple_tone.ino b/libraries/ESP_I2S/examples/Simple_tone/Simple_tone.ino index 935aa4bc50f..bba7d4f4d9d 100644 --- a/libraries/ESP_I2S/examples/Simple_tone/Simple_tone.ino +++ b/libraries/ESP_I2S/examples/Simple_tone/Simple_tone.ino @@ -24,10 +24,17 @@ 2nd September 2021 Lucas Saavedra Vaz (lucasssvaz) 22nd December 2023 + anon + 10nd February 2025 */ #include +// The GPIO pins are not fixed, most other pins could be used for the I2S function. +#define I2S_LRC 25 +#define I2S_BCLK 5 +#define I2S_DIN 26 + const int frequency = 440; // frequency of square wave in Hz const int amplitude = 500; // amplitude of square wave const int sampleRate = 8000; // sample rate in Hz @@ -36,10 +43,10 @@ i2s_data_bit_width_t bps = I2S_DATA_BIT_WIDTH_16BIT; i2s_mode_t mode = I2S_MODE_STD; i2s_slot_mode_t slot = I2S_SLOT_MODE_STEREO; -const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave +const unsigned int halfWavelength = sampleRate / frequency / 2; // half wavelength of square wave int32_t sample = amplitude; // current sample value -int count = 0; +unsigned int count = 0; I2SClass i2s; @@ -47,6 +54,8 @@ void setup() { Serial.begin(115200); Serial.println("I2S simple tone"); + i2s.setPins(I2S_BCLK, I2S_LRC, I2S_DIN); + // start I2S at the sample rate with 16-bits per sample if (!i2s.begin(mode, sampleRate, bps, slot)) { Serial.println("Failed to initialize I2S!"); @@ -60,8 +69,13 @@ void loop() { sample = -1 * sample; } - i2s.write(sample); // Right channel - i2s.write(sample); // Left channel + // Left channel, the low 8 bits then high 8 bits + i2s.write(sample); + i2s.write(sample >> 8); + + // Right channel, the low 8 bits then high 8 bits + i2s.write(sample); + i2s.write(sample >> 8); // increment the counter for the next sample count++; From 422e52684b824a3fde85989ea90abf6624f2b0eb Mon Sep 17 00:00:00 2001 From: Paula Scharf <48286621+PaulaScharf@users.noreply.github.com> Date: Tue, 10 Jun 2025 13:29:27 +0200 Subject: [PATCH 20/20] fix(msc): remove weak function declaration of tud_msc_is_writable_cb (#11353) Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- cores/esp32/esp32-hal-tinyusb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index 0991e08d27f..30a827baa01 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -466,9 +466,6 @@ __attribute__((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint __attribute__((weak)) int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) { return -1; } -__attribute__((weak)) bool tud_msc_is_writable_cb(uint8_t lun) { - return false; -} #endif #if CFG_TUD_NCM __attribute__((weak)) bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {