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
"
"