diff --git a/CHANGELOG.md b/CHANGELOG.md index 300ef6298..2152515ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - DS18x20 support on up to four GPIOs by md5sum-as (#16833) - Berry add `bytes().setbytes()` +- Support for Shelly Pro 1/2 (#16773) - Add Zigbee router firmware for Sonoff ZBBridgePro ### Breaking Changed @@ -15,6 +16,7 @@ All notable changes to this project will be documented in this file. - DS18x20 ``DS18Alias`` to ``DS18Sens`` (#16833) - Compiling with reduced boards manifests in favour of Autoconfig (#16848) - Add NeoPool ``NPFiltration 2`` toggle cmnd (#16859) +- ESP32 NimBLE library from v1.4.0 to v1.4.1 (#16775) ### Fixed - BP5758D red channel corruption regression from v12.1.1.6 (#16850) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c377bd73d..5e85b1f00 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,10 +110,13 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo ## Changelog v12.2.0.1 ### Added - DS18x20 support on up to four GPIOs by md5sum-as [#16833](https://github.com/arendst/Tasmota/issues/16833) +- Berry add `bytes().setbytes()` [#16892](https://github.com/arendst/Tasmota/issues/16892) +- Support for Shelly Pro 1/2 [#16773](https://github.com/arendst/Tasmota/issues/16773) ### Breaking Changed ### Changed +- ESP32 NimBLE library from v1.4.0 to v1.4.1 [#16775](https://github.com/arendst/Tasmota/issues/16775) - DS18x20 ``DS18Alias`` to ``DS18Sens`` [#16833](https://github.com/arendst/Tasmota/issues/16833) - Compiling with reduced boards manifests in favour of Autoconfig [#16848](https://github.com/arendst/Tasmota/issues/16848) diff --git a/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md b/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md index 5d1d2d409..43fbc62cf 100644 --- a/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md +++ b/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. +## [1.4.1] - 2022-10-23 + +### Fixed + - Compile warning removed for esp32c3 + - NimBLEDevice::getPower incorrect value when power level is -3db. + - Failed pairing when already in progress. + +### Changed + - Revert previous change that forced writing with response when subscribing in favor of allowing the application to decide. + +### Added + - Added NimBLEHIDDevice::batteryLevel. + - Added NimBLEDevice::setDeviceName allowing for changing the device name while the BLE stack is active. + - CI build tests. + - Missing items in CHANGELOG that were not recorded correctly + ## [1.4.0] - 2022-07-10 ### Fixed @@ -11,6 +27,9 @@ All notable changes to this project will be documented in this file. ### Changed - Updated NimBLE core to use the v1.4.0 branch of esp-nimble. - AD flags are no longer set in the advertisements of non-connectable beacons, freeing up 3 bytes of advertisement room. +- Config option CONFIG_BT_NIMBLE_DEBUG replaced with CONFIG_BT_NIMBLE_LOG_LEVEL (see src/nimconfig.h for usage) +- Config option CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT renamed to CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT +- Config option CONFIG_BT_NIMBLE_TASK_STACK_SIZE renamed to CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE ### Added - Preliminary support for non-esp devices, NRF51 and NRF52 devices supported with [n-able arduino core](https://github.com/h2zero/n-able-Arduino) diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile b/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile index 54129a191..d9c430338 100644 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile +++ b/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = NimBLE-Arduino # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.0 +PROJECT_NUMBER = 1.4.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = docs +OUTPUT_DIRECTORY = doxydocs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -836,7 +836,7 @@ WARN_NO_PARAMDOC = NO # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. -WARN_AS_ERROR = FAIL_ON_WARNINGS +WARN_AS_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which diff --git a/lib/libesp32_div/NimBLE-Arduino/library.properties b/lib/libesp32_div/NimBLE-Arduino/library.properties index 16ddf82b5..d1b32b9cf 100644 --- a/lib/libesp32_div/NimBLE-Arduino/library.properties +++ b/lib/libesp32_div/NimBLE-Arduino/library.properties @@ -1,5 +1,5 @@ name=NimBLE-Arduino -version=1.4.0 +version=1.4.1 author=h2zero maintainer=h2zero sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE. diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp index d923e6a0a..a83e23b4a 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp @@ -336,6 +336,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) * @return True on success. */ bool NimBLEClient::secureConnection() { + NIMBLE_LOGD(LOG_TAG, ">> secureConnection()"); TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); ble_task_data_t taskData = {this, cur_task, 0, nullptr}; @@ -345,7 +346,7 @@ bool NimBLEClient::secureConnection() { m_pTaskData = &taskData; int rc = NimBLEDevice::startSecurity(m_conn_id); - if(rc != 0){ + if(rc != 0 && rc != BLE_HS_EALREADY){ m_lastErr = rc; m_pTaskData = nullptr; return false; @@ -360,9 +361,11 @@ bool NimBLEClient::secureConnection() { if(taskData.rc != 0){ m_lastErr = taskData.rc; + NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc); return false; } + NIMBLE_LOGD(LOG_TAG, "<< secureConnection: success"); return true; } // secureConnection diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp index 6ae9a7745..43ba21909 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp @@ -971,6 +971,15 @@ void NimBLEDevice::deinit(bool clearAll) { } } // deinit +/** + * @brief Set the BLEDevice's name + * @param [in] deviceName The device name of the device. + */ +/* STATIC */ +void NimBLEDevice::setDeviceName(const std::string &deviceName) { + ble_svc_gap_device_name_set(deviceName.c_str()); +} // setDeviceName + /** * @brief Check if the initialization is complete. diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h index b7e804b8f..8d4d849e4 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h @@ -97,6 +97,7 @@ class NimBLEDevice { public: static void init(const std::string &deviceName); static void deinit(bool clearAll = false); + static void setDeviceName(const std::string &deviceName); static bool getInitialized(); static NimBLEAddress getAddress(); static std::string toString(); @@ -150,7 +151,8 @@ public: int max_events = 0); static bool stopAdvertising(uint8_t inst_id); static bool stopAdvertising(); -# else +# endif +# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) static NimBLEAdvertising* getAdvertising(); static bool startAdvertising(); static bool stopAdvertising(); diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp index 29150ce63..a2310eb9e 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp @@ -203,12 +203,12 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level) { /* * @brief Returns battery level characteristic * @ return battery level characteristic - *//* -BLECharacteristic* BLEHIDDevice::batteryLevel() { + */ +NimBLECharacteristic* NimBLEHIDDevice::batteryLevel() { return m_batteryLevelCharacteristic; } - +/* BLECharacteristic* BLEHIDDevice::reportMap() { return m_reportMapCharacteristic; diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h index ef2ed7395..0e8b2828a 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h @@ -55,7 +55,7 @@ public: void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version); //NimBLECharacteristic* hidInfo(); void hidInfo(uint8_t country, uint8_t flags); - //NimBLECharacteristic* batteryLevel(); + NimBLECharacteristic* batteryLevel(); void setBatteryLevel(uint8_t level); diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp index 68982f89e..6cca615db 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp @@ -616,7 +616,6 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC NIMBLE_LOGD(LOG_TAG, "<< setNotify()"); - response = true; // Always write with response as per Bluetooth core specification. return desc->writeValue((uint8_t *)&val, 2, response); } // setNotify diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h index 7042b19bf..353d83221 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h @@ -73,8 +73,8 @@ public: bool subscribe(bool notifications = true, notify_callback notifyCallback = nullptr, - bool response = true); - bool unsubscribe(bool response = true); + bool response = false); + bool unsubscribe(bool response = false); bool registerForNotify(notify_callback notifyCallback, bool notifications = true, bool response = true) diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h index 19fecfdde..54bbb9ab1 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h @@ -58,7 +58,8 @@ public: int duration = 0, int max_events = 0); bool stopAdvertising(uint8_t inst_id); -#else +#endif +#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) NimBLEAdvertising* getAdvertising(); bool startAdvertising(); #endif diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 5383ba276..3dee90dad 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -382,7 +382,7 @@ enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_I2C_INIT, FUNC_ FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_WEB_COL_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, - FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, + FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, FUNC_LED_LINK, FUNC_ENERGY_EVERY_SECOND, FUNC_ENERGY_RESET, FUNC_RULES_PROCESS, FUNC_TELEPERIOD_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_BUTTON_PRESSED, FUNC_BUTTON_MULTI_PRESSED, FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_CONSOLE_BUTTON, FUNC_WEB_ADD_MANAGEMENT_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index d6a691003..b252a2275 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -642,6 +642,7 @@ //#define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k code) //#define USE_MCP2515 // Add support for can bus using MCP2515 (+7k code) //#define USE_CANSNIFFER // Add support for can bus sniffer using MCP2515 (+5k code) +#define USE_SHELLY_PRO // Add support for Shelly Pro #define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) #define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index d37ffd6a3..869e92a8c 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -208,7 +208,7 @@ enum ProgramSelectablePins { GPIO_USER, // User configurable needs to be 2047 GPIO_MAX }; -#define MAX_OPTIONS_A 6 // Increase if more bits are used from GpioOptionABits +#define MAX_OPTIONS_A 7 // Increase if more bits are used from GpioOptionABits typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption @@ -219,7 +219,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t enable_ccloader : 1; // bit 3 (v9.4.0.5) - Option_A4 - (Zigbee) Enable CCLoader using Zigbee Rx/Tx/Rst Gpios uint32_t rotary_mi_desk : 1; // bit 4 (v9.5.0.5) - Option_A5 - (Rotary) Enable Mi Desk emulation uint32_t linkind_support : 1; // bit 5 (v10.1.0.4) - Option_A6 - (Light) LinkInd support - uint32_t spare06 : 1; // bit 6 + uint32_t shelly_pro : 1; // bit 6 (v12.2.0.1) - Option_A7 - (Device) Shelly Pro uint32_t spare07 : 1; // bit 7 uint32_t spare08 : 1; // bit 8 uint32_t spare09 : 1; // bit 9 diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino index bdfad5330..b12ef5714 100644 --- a/tasmota/tasmota_support/support_button_v3.ino +++ b/tasmota/tasmota_support/support_button_v3.ino @@ -473,6 +473,11 @@ void ButtonHandler(void) { valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); } #endif // ESP8266 +#ifdef USE_SHELLY_PRO + if (TasmotaGlobal.gpio_optiona.shelly_pro) { + valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); + } +#endif // USE_SHELLY_PRO if ((Button.press_counter[button_index] > 1) && valid_relay && (Button.press_counter[button_index] <= MAX_RELAY_BUTTON1)) { ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally // AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1)); diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 77163871e..b51856b4b 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -517,8 +517,13 @@ void SetLedPowerAll(uint32_t state) } } -void SetLedLink(uint32_t state) -{ +void SetLedLink(uint32_t state) { +#ifdef ESP32 + uint32_t index = XdrvMailbox.index; + XdrvMailbox.index = state; + XdrvCall(FUNC_LED_LINK); + XdrvMailbox.index = index; +#endif // ESP32 int led_pin = Pin(GPIO_LEDLNK); uint32_t led_inv = TasmotaGlobal.ledlnk_inverted; if (-1 == led_pin) { // Legacy - LED1 is status diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino new file mode 100644 index 000000000..d7ffd8caa --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -0,0 +1,123 @@ +/* + xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota + + Copyright (C) 2022 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 +#ifdef USE_SPI +#ifdef USE_SHELLY_PRO +/*********************************************************************************************\ + * Shelly Pro support + * + * {"NAME":"Shelly Pro 1","GPIO":[0,0,0,0,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,0,0,160,0],"FLAG":0,"BASE":1} + * {"NAME":"Shelly Pro 2","GPIO":[0,0,0,0,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,0,0,160,161],"FLAG":0,"BASE":1} + * + * Shelly Pro uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring + * + * Testset + * {"NAME":"Shelly Pro 2PM (POC)","GPIO":[1,0,1,0,768,1,0,0,672,704,736,1,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,1,32,1,1,160,161],"FLAG":0,"BASE":1} +\*********************************************************************************************/ + +#define XDRV_88 88 + +struct SPro { + uint8_t pin_shift595_rclk; + uint8_t ledlink; + uint8_t power; + bool detected; +} SPro; + +void ShellyProUpdate(void) { + // Shelly Pro 595 register + // bit 0 = relay/led 1 + // bit 1 = relay/led 2 + // bit 2 = wifi led blue + // bit 3 = wifi led green + // bit 4 = wifi led red + // bit 5 - 7 = nc + uint32_t val = SPro.power | SPro.ledlink; + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + SPI.transfer(val); // Write 74HC595 shift register + SPI.endTransaction(); + + digitalWrite(SPro.pin_shift595_rclk, 1); + delayMicroseconds(200); // Shelly 10mS + digitalWrite(SPro.pin_shift595_rclk, 0); +} + +void ShellyProPreInit(void) { + if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && + PinUsed(GPIO_SPI_CS) && + TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 + + if (PinUsed(GPIO_SWT1)) { + TasmotaGlobal.devices_present++; // Shelly Pro 1 + if (PinUsed(GPIO_SWT1, 1)) { + TasmotaGlobal.devices_present++; // Shelly Pro 2 + } + + SPro.pin_shift595_rclk = Pin(GPIO_SPI_CS); + pinMode(SPro.pin_shift595_rclk, OUTPUT); + digitalWrite(SPro.pin_shift595_rclk, 0); + // Does nothing if SPI is already initiated (by ADE7953) so no harm done + SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); + + SPro.power = TasmotaGlobal.power &3; // Restore power + SPro.ledlink = 0x1C; // All leds off + ShellyProUpdate(); + + SPro.detected = true; + } + } +} + +void ShellyProPower(void) { + SPro.power = XdrvMailbox.index &3; + ShellyProUpdate(); +} + +void ShellyProLedLink(void) { + // bit 2 = blue, 3 = green, 4 = red + SPro.ledlink = (XdrvMailbox.index) ? 0x18 : 0x1C; // Blue on (wifi link) or all off + ShellyProUpdate(); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv88(uint8_t function) { + bool result = false; + + if (FUNC_PRE_INIT == function) { + ShellyProPreInit(); + } else if (SPro.detected) { + switch (function) { + case FUNC_SET_POWER: + ShellyProPower(); + break; + case FUNC_LED_LINK: + ShellyProLedLink(); + break; + } + } + return result; +} + +#endif // USE_SHELLY_PRO +#endif // USE_SPI +#endif // ESP32