diff --git a/CHANGELOG.md b/CHANGELOG.md index cfd01e080..ad1a2401b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ All notable changes to this project will be documented in this file. - Support for SPI connected MFRC522 13.56MHz rfid card reader (#9916) - Letsencrypt R3 in addition to X3 CA (#10086) - Zigbee add visual map of network +- Command ``SetOption117 1`` for light fading to be fixed duration instead of fixed slew rate (#10109) +- ESP32 SPIFFS support ### Breaking Changed - KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888) @@ -44,6 +46,8 @@ All notable changes to this project will be documented in this file. - Backlog timing wraparound (#9995) - First LED in addressable string does not fade when using scheme (#10088) - Improved Opentherm error handling (#10055) +- Shutter motordelay stop issue (#10033) +- ESP32 CC2530 heap corruption (#10121) ### Removed - PN532 define USE_PN532_CAUSE_EVENTS replaced by generic rule trigger `on pn532#uid=` diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 44e6125f6..ec017703b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -60,6 +60,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ### Added - Command ``SetOption115 1`` to enable ESP32 MiBle - Command ``SetOption116 1`` to disable auto-query of zigbee light devices (avoids network storms with large groups) +- Command ``SetOption117 1`` for light fading to be fixed duration instead of fixed slew rate (#10109) - Command ``RfProtocol`` to control RcSwitch receive protocols by BBBits (#10063) - Commands ``TuyaRGB``, ``TuyaEnum`` and ``TuyaEnumList`` (#9769) - Zigbee command ``ZbInfo`` and prepare support for EEPROM @@ -68,6 +69,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Zigbee alarm persistence (#9785) - Zigbee persistence of device/sensor data in EEPROM (only ZBBridge) - Zigbee better support for Tuya Protocol (#10074) +- Zigbee visual map of network - TyuaMcu update 2/3 by Federico Leoni (#10004) - Support for additional EZO sensors by Christopher Tremblay - Support for AS608 optical and R503 capacitive fingerprint sensor @@ -79,6 +81,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Fallback NTP server from x.pool.ntp.org if no ntpservers are configured - Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970) - Letsencrypt R3 in addition to X3 CA (#10086) +- ESP32 SPIFFS support ### Breaking Changed - KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888) @@ -105,6 +108,8 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Backlog timing wraparound (#9995) - First LED in addressable string does not fade when using scheme (#10088) - Improved Opentherm error handling (#10055) +- Shutter motordelay stop issue (#10033) +- ESP32 CC2530 heap corruption (#10121) ### Removed - Version compatibility check diff --git a/tasmota/settings.h b/tasmota/settings.h index d55fcc76f..72d0477ce 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -142,7 +142,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t mqtt_switches : 1; // bit 0 (v9.0.0.3) - SetOption114 - (Switch) Detach Switches from relays and enable MQTT action state for all the SwitchModes (1) uint32_t mi32_enable : 1; // bit 1 (v9.1.0.1) - SetOption115 - (ESP32 BLE) Enable ESP32 MI32 BLE (1) uint32_t zb_disable_autoquery : 1; // bit 2 (v9.1.0.1) - SetOption116 - (Zigbee) Disable auto-query of zigbee lights and devices (1) - uint32_t spare03 : 1; // bit 3 + uint32_t fade_fixed_duration : 1; // bit 3 (v9.1.0.2) - SetOption117 - (Light) run fading at fixed duration instead of fixed slew rate uint32_t spare04 : 1; // bit 4 uint32_t spare05 : 1; // bit 5 uint32_t spare06 : 1; // bit 6 diff --git a/tasmota/support_esp32.ino b/tasmota/support_esp32.ino index a46809e26..806175505 100644 --- a/tasmota/support_esp32.ino +++ b/tasmota/support_esp32.ino @@ -167,10 +167,19 @@ void SettingsErase(uint8_t type) { } void SettingsRead(void *data, size_t size) { +#ifdef USE_TFS +// if (!TfsLoadFile("/settings", (uint8_t*)data, size)) { + NvmLoad("main", "Settings", data, size); +// } +#else NvmLoad("main", "Settings", data, size); +#endif } void SettingsWrite(const void *pSettings, unsigned nSettingsLen) { +#ifdef USE_TFS +// TfsSaveFile("/settings", (const uint8_t*)pSettings, nSettingsLen); +#endif NvmSave("main", "Settings", pSettings, nSettingsLen); } @@ -182,18 +191,6 @@ void QPCWrite(const void *pSettings, unsigned nSettingsLen) { NvmSave("qpc", "pcreg", pSettings, nSettingsLen); } -void ZigbeeErase(void) { - NvmErase("zb"); -} - -void ZigbeeRead(void *pSettings, unsigned nSettingsLen) { - NvmLoad("zb", "zigbee", pSettings, nSettingsLen); -} - -void ZigbeeWrite(const void *pSettings, unsigned nSettingsLen) { - NvmSave("zb", "zigbee", pSettings, nSettingsLen); -} - void NvsInfo(void) { nvs_stats_t nvs_stats; nvs_get_stats(NULL, &nvs_stats); @@ -201,6 +198,28 @@ void NvsInfo(void) { nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries, nvs_stats.namespace_count); } +void ZigbeeErase(unsigned nSettingsLen) { +// NvmErase("zb"); +#ifdef USE_TFS + TfsEraseFile("/zb", nSettingsLen); +#endif +} + +void ZigbeeRead(uint8_t *pSettings, unsigned nSettingsLen) { +// NvmLoad("zb", "zigbee", pSettings, nSettingsLen); +#ifdef USE_TFS + TfsLoadFile("/zb", pSettings, nSettingsLen); +#endif +} + +void ZigbeeWrite(const uint8_t *pSettings, unsigned nSettingsLen) { +// NvmSave("zb", "zigbee", pSettings, nSettingsLen); +#ifdef USE_TFS + TfsSaveFile("/zb", pSettings, nSettingsLen); +#endif +} + + // // Flash memory mapping // diff --git a/tasmota/support_filesystem.ino b/tasmota/support_filesystem.ino new file mode 100644 index 000000000..6eef715f4 --- /dev/null +++ b/tasmota/support_filesystem.ino @@ -0,0 +1,153 @@ +/* + support_filesystem.ino - Filesystem support for Tasmota + + Copyright (C) 2020 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 . +*/ + +/*********************************************************************************************\ + * ESP32 Filesystem Support +\*********************************************************************************************/ + +#ifdef ESP32 + +#define USE_TFS + +#ifdef USE_SCRIPT +#undef USE_TFS +#endif // USE_SCRIPT + +#ifdef USE_TFS + +//#define USE_LITTLEFS // LittleFS not tested yet +//#define USE_FFAT // FFat minimal 983k partition (4096 sector size) - tested +#define USE_SPIFFS // SPIFFS - tested + +#ifdef USE_LITTLEFS + #include + #define TASMOTA_FS LittleFS +#endif +#ifdef USE_FFAT + #include + #define TASMOTA_FS FFat +#endif +#ifdef USE_SPIFFS + #include + #define TASMOTA_FS SPIFFS +#endif + +bool TfsInit(void) { + static uint8_t FsMounted = 0; + + if (FsMounted) { return FsMounted -1; } + + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Mounting...")); + if (!TASMOTA_FS.begin()) { + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Formatting...")); + TASMOTA_FS.format(); + if (!TASMOTA_FS.begin()) { + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Failed")); + FsMounted = 1; // false + return false; + } + } + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Mounted")); +// TfsInfo(); + FsMounted = 2; // true + return true; +} + +bool TfsFileExists(const char *fname){ + if (!TfsInit()) { return false; } + + bool yes = false; + File file = TASMOTA_FS.open(fname, "r"); + if (!file.isDirectory()) { + yes = true; + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File not found")); + } + file.close(); + return yes; +} + +bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) { + if (!TfsInit()) { return false; } + + File file = TASMOTA_FS.open(fname, "w"); + if (!file) { + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Save failed")); + return false; + } + + file.write(buf, len); + file.close(); + return true; +} + +bool TfsEraseFile(const char *fname, uint32_t len) { + if (!TfsInit()) { return false; } + + File file = TASMOTA_FS.open(fname, "w"); + if (!file) { + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Erase failed")); + return false; + } + + uint8_t init_value = 0xff; + for (uint32_t i = 0; i < len; i++) { + file.write(&init_value, 1); + } + file.close(); + return true; +} + +bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) { + if (!TfsInit()) { return false; } + if (!TfsFileExists(fname)) { return false; } + + File file = TASMOTA_FS.open(fname, "r"); + if (!file) { + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File not found")); + return false; + } + + file.read(buf, len); + file.close(); + return true; +} + +void TfsInfo(void) { +#ifdef USE_SPIFFS + uint32_t used_bytes = TASMOTA_FS.usedBytes(); +#endif // USE_SPIFFS + uint32_t total_bytes = TASMOTA_FS.totalBytes(); +#ifdef USE_FFAT + uint32_t used_bytes = total_bytes - TASMOTA_FS.freeBytes(); +#endif // USE_FFAT + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Used %d/%d bytes"), used_bytes, total_bytes); + + File root = TASMOTA_FS.open("/"); + File file = root.openNextFile(); + while (file) { + String filename = file.name(); + size_t filesize = file.size(); + AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File %s, size %d"), filename.c_str(), filesize); + file = root.openNextFile(); + } +} + +#endif // USE_TFS +#endif // ESP32 diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index c12fc8b95..9af684987 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -2137,7 +2137,10 @@ bool LightApplyFade(void) { // did the value chanegd and needs to be applied // compute the duration of the animation // Note: Settings.light_speed is the number of half-seconds for a 100% fade, // i.e. light_speed=1 means 1024 steps in 500ms - Light.fade_duration = (distance * Settings.light_speed * 500) / 1023; + Light.fade_duration = Settings.light_speed * 500; + if (!Settings.flag5.fade_fixed_duration) { + Light.fade_duration = (distance * Light.fade_duration) / 1023; // time is proportional to distance, except with SO117 + } if (Settings.save_data) { // Also postpone the save_data for the duration of the Fade (in seconds) uint32_t delay_seconds = 1 + (Light.fade_duration + 999) / 1000; // add one more second diff --git a/tasmota/xdrv_16_tuyamcu.ino b/tasmota/xdrv_16_tuyamcu.ino index 6eab26f08..033fd3380 100644 --- a/tasmota/xdrv_16_tuyamcu.ino +++ b/tasmota/xdrv_16_tuyamcu.ino @@ -1214,6 +1214,13 @@ void TuyaSetTime(void) { uint16_t payload_len = 8; uint8_t payload_buffer[8]; + uint8_t tuya_day_of_week; + if (RtcTime.day_of_week == 1) { + tuya_day_of_week = 7; + } else { + tuya_day_of_week = RtcTime.day_of_week-1; + } + payload_buffer[0] = 0x01; payload_buffer[1] = RtcTime.year %100; payload_buffer[2] = RtcTime.month; @@ -1221,7 +1228,7 @@ void TuyaSetTime(void) { payload_buffer[4] = RtcTime.hour; payload_buffer[5] = RtcTime.minute; payload_buffer[6] = RtcTime.second; - payload_buffer[7] = RtcTime.day_of_week; + payload_buffer[7] = tuya_day_of_week; //1 for Monday in TUYA Doc TuyaSendCmd(TUYA_CMD_SET_TIME, payload_buffer, payload_len); } diff --git a/tasmota/xdrv_23_zigbee_4_persistence.ino b/tasmota/xdrv_23_zigbee_4_persistence.ino index d15a50ef9..046077771 100644 --- a/tasmota/xdrv_23_zigbee_4_persistence.ino +++ b/tasmota/xdrv_23_zigbee_4_persistence.ino @@ -304,7 +304,7 @@ void loadZigbeeDevices(bool dump_only = false) { AddLog_P(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Cannot allocate 4KB buffer")); return; } - ZigbeeRead(&spi_buffer, z_spi_len); + ZigbeeRead(spi_buffer, z_spi_len); z_dev_start = spi_buffer; #endif // ESP32 Z_Flashentry flashdata; @@ -367,7 +367,7 @@ void saveZigbeeDevices(void) { ESP.flashRead(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); #endif // ESP8266 #ifdef ESP32 - ZigbeeRead(&spi_buffer, z_spi_len); + ZigbeeRead(spi_buffer, z_spi_len); #endif // ESP32 Z_Flashentry *flashdata = (Z_Flashentry*)(spi_buffer + z_block_offset); @@ -385,7 +385,7 @@ void saveZigbeeDevices(void) { AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data store in Flash (0x%08X - %d bytes)"), z_dev_start, buf_len); #endif // ESP8266 #ifdef ESP32 - ZigbeeWrite(&spi_buffer, z_spi_len); + ZigbeeWrite(spi_buffer, z_spi_len); AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data saved in %s (%d bytes)"), PSTR("Flash"), buf_len); #endif // ESP32 free(spi_buffer); @@ -419,7 +419,7 @@ void eraseZigbeeDevices(void) { AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data erased in %s"), PSTR("Flash")); #endif // ESP8266 #ifdef ESP32 - ZigbeeErase(); + ZigbeeErase(z_block_len); AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data erased (%d bytes)"), z_block_len); #endif // ESP32 } diff --git a/tasmota/xdrv_23_zigbee_5__constants.ino b/tasmota/xdrv_23_zigbee_5__constants.ino index 09595a93f..5cc62720c 100644 --- a/tasmota/xdrv_23_zigbee_5__constants.ino +++ b/tasmota/xdrv_23_zigbee_5__constants.ino @@ -130,12 +130,13 @@ const char Z_strings[] PROGMEM = "AnalogInMaxValue" "\x00" "AnalogInMinValue" "\x00" "AnalogInOutOfService" "\x00" - "AqaraRotate" "\x00" + "AnalogValue" "\x00" "AnalogInReliability" "\x00" "AnalogInResolution" "\x00" "AnalogInStatusFlags" "\x00" "AnalogInEngineeringUnits" "\x00" "AnalogInApplicationType" "\x00" + "AqaraRotate" "\x00" "Aqara_FF05" "\x00" "AnalogOutDescription" "\x00" "AnalogOutMaxValue" "\x00" @@ -150,7 +151,6 @@ const char Z_strings[] PROGMEM = "AnalogOutApplicationType" "\x00" "AnalogDescription" "\x00" "AnalogOutOfService" "\x00" - "AnalogValue" "\x00" "AnalogPriorityArray" "\x00" "AnalogReliability" "\x00" "AnalogRelinquishDefault" "\x00" @@ -395,6 +395,7 @@ const char Z_strings[] PROGMEM = "TuyaFanMode" "\x00" "TuyaForceMode" "\x00" "TuyaWeekSelect" "\x00" + "OppleMode" "\x00" "TerncyDuration" "\x00" "TerncyRotate" "\x00" "Identify" "\x00" @@ -545,27 +546,27 @@ enum Z_offsets { Zo_AnalogInMaxValue = 676, Zo_AnalogInMinValue = 693, Zo_AnalogInOutOfService = 710, - Zo_AqaraRotate = 731, + Zo_AnalogValue = 731, Zo_AnalogInReliability = 743, Zo_AnalogInResolution = 763, Zo_AnalogInStatusFlags = 782, Zo_AnalogInEngineeringUnits = 802, Zo_AnalogInApplicationType = 827, - Zo_Aqara_FF05 = 851, - Zo_AnalogOutDescription = 862, - Zo_AnalogOutMaxValue = 883, - Zo_AnalogOutMinValue = 901, - Zo_AnalogOutOutOfService = 919, - Zo_AnalogOutValue = 941, - Zo_AnalogOutReliability = 956, - Zo_AnalogOutRelinquishDefault = 977, - Zo_AnalogOutResolution = 1004, - Zo_AnalogOutStatusFlags = 1024, - Zo_AnalogOutEngineeringUnits = 1045, - Zo_AnalogOutApplicationType = 1071, - Zo_AnalogDescription = 1096, - Zo_AnalogOutOfService = 1114, - Zo_AnalogValue = 1133, + Zo_AqaraRotate = 851, + Zo_Aqara_FF05 = 863, + Zo_AnalogOutDescription = 874, + Zo_AnalogOutMaxValue = 895, + Zo_AnalogOutMinValue = 913, + Zo_AnalogOutOutOfService = 931, + Zo_AnalogOutValue = 953, + Zo_AnalogOutReliability = 968, + Zo_AnalogOutRelinquishDefault = 989, + Zo_AnalogOutResolution = 1016, + Zo_AnalogOutStatusFlags = 1036, + Zo_AnalogOutEngineeringUnits = 1057, + Zo_AnalogOutApplicationType = 1083, + Zo_AnalogDescription = 1108, + Zo_AnalogOutOfService = 1126, Zo_AnalogPriorityArray = 1145, Zo_AnalogReliability = 1165, Zo_AnalogRelinquishDefault = 1183, @@ -810,97 +811,98 @@ enum Z_offsets { Zo_TuyaFanMode = 5203, Zo_TuyaForceMode = 5215, Zo_TuyaWeekSelect = 5229, - Zo_TerncyDuration = 5244, - Zo_TerncyRotate = 5259, - Zo_Identify = 5272, - Zo_xxxx = 5281, - Zo_IdentifyQuery = 5286, - Zo_AddGroup = 5300, - Zo_xxxx00 = 5309, - Zo_ViewGroup = 5316, - Zo_GetGroup = 5326, - Zo_01xxxx = 5335, - Zo_GetAllGroups = 5342, - Zo_00 = 5355, - Zo_RemoveGroup = 5358, - Zo_RemoveAllGroups = 5370, - Zo_ViewScene = 5386, - Zo_xxxxyy = 5396, - Zo_RemoveScene = 5403, - Zo_RemoveAllScenes = 5415, - Zo_RecallScene = 5431, - Zo_GetSceneMembership = 5443, - Zo_PowerOffEffect = 5462, - Zo_xxyy = 5477, - Zo_PowerOnRecall = 5482, - Zo_PowerOnTimer = 5496, - Zo_xxyyyyzzzz = 5509, - Zo_xx0A00 = 5520, - Zo_DimmerUp = 5527, - Zo_00190200 = 5536, - Zo_DimmerDown = 5545, - Zo_01190200 = 5556, - Zo_DimmerStop = 5565, - Zo_ResetAlarm = 5576, - Zo_xxyyyy = 5587, - Zo_ResetAllAlarms = 5594, - Zo_xx000A00 = 5609, - Zo_HueSat = 5618, - Zo_xxyy0A00 = 5625, - Zo_Color = 5634, - Zo_xxxxyyyy0A00 = 5640, - Zo_xxxx0A00 = 5653, - Zo_ShutterOpen = 5662, - Zo_ShutterClose = 5674, - Zo_ShutterStop = 5687, - Zo_ShutterLift = 5699, - Zo_xx = 5711, - Zo_ShutterTilt = 5714, - Zo_Shutter = 5726, - Zo_DimmerMove = 5734, - Zo_xx0A = 5745, - Zo_DimmerStepUp = 5750, - Zo_00xx0A00 = 5763, - Zo_DimmerStepDown = 5772, - Zo_01xx0A00 = 5787, - Zo_DimmerStep = 5796, - Zo_xx190A00 = 5807, - Zo_01 = 5816, - Zo_HueMove = 5819, - Zo_xx19 = 5827, - Zo_HueStepUp = 5832, - Zo_HueStepDown = 5842, - Zo_03xx0A00 = 5854, - Zo_HueStep = 5863, - Zo_SatMove = 5871, - Zo_SatStep = 5879, - Zo_xx190A = 5887, - Zo_ColorMove = 5894, - Zo_xxxxyyyy = 5904, - Zo_ColorStep = 5913, - Zo_ColorTempMoveUp = 5923, - Zo_01xxxx000000000000 = 5939, - Zo_ColorTempMoveDown = 5958, - Zo_03xxxx000000000000 = 5976, - Zo_ColorTempMoveStop = 5995, - Zo_00xxxx000000000000 = 6013, - Zo_ColorTempMove = 6032, - Zo_xxyyyy000000000000 = 6046, - Zo_ColorTempStepUp = 6065, - Zo_01xxxx0A0000000000 = 6081, - Zo_ColorTempStepDown = 6100, - Zo_03xxxx0A0000000000 = 6118, - Zo_ColorTempStep = 6137, - Zo_xxyyyy0A0000000000 = 6151, - Zo_ArrowClick = 6170, - Zo_ArrowHold = 6181, - Zo_ArrowRelease = 6191, - Zo_ZoneStatusChange = 6204, - Zo_xxxxyyzz = 6221, - Zo_xxyyzzzz = 6230, - Zo_AddScene = 6239, - Zo_xxyyyyzz = 6248, - Zo_StoreScene = 6257, + Zo_OppleMode = 5244, + Zo_TerncyDuration = 5254, + Zo_TerncyRotate = 5269, + Zo_Identify = 5282, + Zo_xxxx = 5291, + Zo_IdentifyQuery = 5296, + Zo_AddGroup = 5310, + Zo_xxxx00 = 5319, + Zo_ViewGroup = 5326, + Zo_GetGroup = 5336, + Zo_01xxxx = 5345, + Zo_GetAllGroups = 5352, + Zo_00 = 5365, + Zo_RemoveGroup = 5368, + Zo_RemoveAllGroups = 5380, + Zo_ViewScene = 5396, + Zo_xxxxyy = 5406, + Zo_RemoveScene = 5413, + Zo_RemoveAllScenes = 5425, + Zo_RecallScene = 5441, + Zo_GetSceneMembership = 5453, + Zo_PowerOffEffect = 5472, + Zo_xxyy = 5487, + Zo_PowerOnRecall = 5492, + Zo_PowerOnTimer = 5506, + Zo_xxyyyyzzzz = 5519, + Zo_xx0A00 = 5530, + Zo_DimmerUp = 5537, + Zo_00190200 = 5546, + Zo_DimmerDown = 5555, + Zo_01190200 = 5566, + Zo_DimmerStop = 5575, + Zo_ResetAlarm = 5586, + Zo_xxyyyy = 5597, + Zo_ResetAllAlarms = 5604, + Zo_xx000A00 = 5619, + Zo_HueSat = 5628, + Zo_xxyy0A00 = 5635, + Zo_Color = 5644, + Zo_xxxxyyyy0A00 = 5650, + Zo_xxxx0A00 = 5663, + Zo_ShutterOpen = 5672, + Zo_ShutterClose = 5684, + Zo_ShutterStop = 5697, + Zo_ShutterLift = 5709, + Zo_xx = 5721, + Zo_ShutterTilt = 5724, + Zo_Shutter = 5736, + Zo_DimmerMove = 5744, + Zo_xx0A = 5755, + Zo_DimmerStepUp = 5760, + Zo_00xx0A00 = 5773, + Zo_DimmerStepDown = 5782, + Zo_01xx0A00 = 5797, + Zo_DimmerStep = 5806, + Zo_xx190A00 = 5817, + Zo_01 = 5826, + Zo_HueMove = 5829, + Zo_xx19 = 5837, + Zo_HueStepUp = 5842, + Zo_HueStepDown = 5852, + Zo_03xx0A00 = 5864, + Zo_HueStep = 5873, + Zo_SatMove = 5881, + Zo_SatStep = 5889, + Zo_xx190A = 5897, + Zo_ColorMove = 5904, + Zo_xxxxyyyy = 5914, + Zo_ColorStep = 5923, + Zo_ColorTempMoveUp = 5933, + Zo_01xxxx000000000000 = 5949, + Zo_ColorTempMoveDown = 5968, + Zo_03xxxx000000000000 = 5986, + Zo_ColorTempMoveStop = 6005, + Zo_00xxxx000000000000 = 6023, + Zo_ColorTempMove = 6042, + Zo_xxyyyy000000000000 = 6056, + Zo_ColorTempStepUp = 6075, + Zo_01xxxx0A0000000000 = 6091, + Zo_ColorTempStepDown = 6110, + Zo_03xxxx0A0000000000 = 6128, + Zo_ColorTempStep = 6147, + Zo_xxyyyy0A0000000000 = 6161, + Zo_ArrowClick = 6180, + Zo_ArrowHold = 6191, + Zo_ArrowRelease = 6201, + Zo_ZoneStatusChange = 6214, + Zo_xxxxyyzz = 6231, + Zo_xxyyzzzz = 6240, + Zo_AddScene = 6249, + Zo_xxyyyyzz = 6258, + Zo_StoreScene = 6267, }; diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index acc4105d8..d18ff3547 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -127,7 +127,7 @@ enum Cx_cluster_short { Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0100, Cx0101, Cx0102, Cx0201, Cx0300, Cx0400, Cx0401, Cx0402, Cx0403, Cx0404, Cx0405, Cx0406, Cx0500, Cx0702, Cx0B01, Cx0B04, Cx0B05, - CxEF00, CxFCCC, + CxEF00, CxFCC0, CxFCCC, }; const uint16_t Cx_cluster[] PROGMEM = { @@ -136,7 +136,7 @@ const uint16_t Cx_cluster[] PROGMEM = { 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0100, 0x0101, 0x0102, 0x0201, 0x0300, 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0500, 0x0702, 0x0B01, 0x0B04, 0x0B05, - 0xEF00, 0xFCCC, + 0xEF00, 0xFCC0, 0xFCCC, }; uint16_t CxToCluster(uint8_t cx) { @@ -634,6 +634,9 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = { { Ztuya4, CxEF00, 0x046A, Z_(TuyaForceMode), Cm1, 0 }, { Ztuya4, CxEF00, 0x046F, Z_(TuyaWeekSelect), Cm1, 0 }, + // Aqara Opple spacific + { Zbool, CxFCC0, 0x0009, Z_(OppleMode), Cm1, 0 }, + // Terncy specific - 0xFCCC { Zuint16, CxFCCC, 0x001A, Z_(TerncyDuration), Cm1, 0 }, { Zint16, CxFCCC, 0x001B, Z_(TerncyRotate), Cm1, 0 }, @@ -1583,6 +1586,9 @@ void ZCLFrame::syntheticAnalogValue(Z_attribute_list &attr_list, class Z_attribu if (modelId.startsWith(F("lumi.plug"))) { attr.setKeyId(0x0702, 0x0000); // change to EnergyTotal } + if (modelId.startsWith(F("lumi.ctrl"))) { + attr.setKeyId(0x0B04, 0x050B); // change to ActivePower + } } @@ -1637,9 +1643,9 @@ void ZCLFrame::syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribu } else if (0x66 == attrid) { attr_list.addAttribute(0x0403, 0x0000).setUInt((ival32 + 50) / 100); // Pressure } - } else if (modelId.startsWith(F("lumi.plug"))) { + } else if (modelId.startsWith(F("lumi.plug")) || modelId.startsWith(F("lumi.ctrl"))) { if (0x64 == attrid) { - attr_list.addAttribute(0x0600, 0x0000).setInt(uval32); // Power (on/off) + attr_list.addAttribute(0x0006, 0x0000).setInt(uval32); // Power (on/off) } else if (0x98 == attrid) { attr_list.addAttribute(0x0B04, 0x050B).setInt(ival32); // Active Power } else if (0x95 == attrid) { diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index d97aa8335..172c85181 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -1059,6 +1059,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi) // device is reachable zigbee_devices.deviceWasReached(shortaddr); + bool non_empty = false; // check whether the response contains relevant information const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); @@ -1089,6 +1090,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi) uint8_t m_lqi = buf.get8(idx + 21); idx += 22; + non_empty = true; if (i > 0) { ResponseAppend_P(PSTR(",")); } @@ -1161,6 +1163,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi) break; // abort for any other value since we don't know the length of the field } + non_empty = true; if (i > 0) { ResponseAppend_P(PSTR(",")); } @@ -1180,7 +1183,8 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi) MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_MAP)); // Check if there are more values waiting, if so re-send a new request to get other values - if (start + len < total) { + // Only send a new request if the current was non-empty. This avoids an infinite loop if the device announces more slots that it actually has. + if ((non_empty) && (start + len < total)) { // there are more values to read #ifdef USE_ZIGBEE_ZNP Z_Send_State_or_Map(shortaddr, start + len, lqi ? ZDO_MGMT_LQI_REQ : ZDO_MGMT_BIND_REQ); diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index f7d6fbdc7..9e35decee 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -1943,7 +1943,7 @@ void ZigbeeShowMap(void) { } else { WSContentSend_P(PSTR( "" - "
" + "
Unable to load vis.js
" "