Merge branch 'development' into pre-release-9.2.0

This commit is contained in:
Theo Arends 2020-12-15 16:45:59 +01:00
commit c09f966f41
14 changed files with 382 additions and 158 deletions

View File

@ -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=`

View File

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

View File

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

View File

@ -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
//

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
/*********************************************************************************************\
* 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 <LittleFS.h>
#define TASMOTA_FS LittleFS
#endif
#ifdef USE_FFAT
#include <FFat.h>
#define TASMOTA_FS FFat
#endif
#ifdef USE_SPIFFS
#include <SPIFFS.h>
#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

View File

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

View File

@ -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);
}

View File

@ -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
}

View File

@ -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,
};

View File

@ -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) {

View File

@ -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);

View File

@ -1943,7 +1943,7 @@ void ZigbeeShowMap(void) {
} else {
WSContentSend_P(PSTR(
"<script type=\"text/javascript\" src=\"https://unpkg.com/vis-network/standalone/umd/vis-network.min.js\"></script>"
"<div id=\"mynetwork\" style=\"background-color:#fff;width:800px;height:400px;border:1px solid lightgray;resize:both;\"></div>"
"<div id=\"mynetwork\" style=\"background-color:#fff;color:#000;width:800px;height:400px;border:1px solid lightgray;resize:both;\">Unable to load vis.js</div>"
"<script type=\"text/javascript\">"
"var container=document.getElementById(\"mynetwork\");"
"var options={groups:{o:{shape:\"circle\",color:\"#d55\"},r:{shape:\"box\",color:\"#fb7\"},e:{shape:\"ellipse\",color:\"#adf\"}}};"

View File

@ -430,10 +430,6 @@ void ShutterDecellerateForStop(uint8_t i)
void ShutterPowerOff(uint8_t i) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SHT: Stop Shutter %d. Switchmode %d"), i,Shutter[i].switch_mode);
ShutterDecellerateForStop(i);
if (Shutter[i].direction !=0) {
Shutter[i].direction = 0;
delay(MOTOR_STOP_TIME);
}
switch (Shutter[i].switch_mode) {
case SHT_SWITCH:
if ((1 << (Settings.shutter_startrelay[i]-1)) & TasmotaGlobal.power) {
@ -449,7 +445,7 @@ void ShutterPowerOff(uint8_t i) {
if ((SRC_PULSETIMER == TasmotaGlobal.last_source || SRC_SHUTTER == TasmotaGlobal.last_source || SRC_WEBGUI == TasmotaGlobal.last_source)) {
ExecuteCommandPowerShutter(cur_relay, 1, SRC_SHUTTER);
// switch off direction relay to make it power less
if ((1 << (Settings.shutter_startrelay[i])) & TasmotaGlobal.power) {
if (((1 << (Settings.shutter_startrelay[i])) & TasmotaGlobal.power) && Settings.shutter_startrelay[i]+1 != cur_relay) {
ExecuteCommandPowerShutter(Settings.shutter_startrelay[i]+1, 0, SRC_SHUTTER);
}
} else {
@ -465,6 +461,10 @@ void ShutterPowerOff(uint8_t i) {
ExecuteCommand(scmnd, SRC_BUTTON);
break;
}
if (Shutter[i].direction !=0) {
Shutter[i].direction = 0;
delay(MOTOR_STOP_TIME);
}
}
void ShutterUpdatePosition(void)
@ -616,7 +616,7 @@ void ShutterRelayChanged(void)
break;
default:
TasmotaGlobal.last_source = SRC_SHUTTER; // avoid switch off in the next loop
if (Shutter[i].direction != 0 ) ShutterPowerOff(i);
if (Shutter[i].direction != 0 ) Shutter[i].target_position = Shutter[i].real_position;
}
switch (ShutterGlobal.position_mode) {
// enum Shutterposition_mode {SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,};
@ -983,7 +983,7 @@ void CmndShutterStop(void)
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SHT: Stop moving %d: dir: %d"), XdrvMailbox.index, Shutter[i].direction);
int32_t temp_realpos = ShutterCalculatePosition(i);
XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i);
XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i)-Shutter[i].direction;
TasmotaGlobal.last_source = SRC_WEBGUI;
CmndShutterPosition();
} else {

View File

@ -69,7 +69,8 @@ const char HTTP_MGC_3130_SNS[] PROGMEM =
"{s}" "%s" "{m}%s{e}"
"{s}" "HwRev" "{m}%u.%u{e}"
"{s}" "loaderVer" "{m}%u.%u{e}"
"{s}" "platVer" "{m}%u{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
"{s}" "platVer" "{m}%u{e}"
"{s}" "NoisePower" "{m}%s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
@ -152,17 +153,18 @@ union MGC3130_Union{
float SDData[4]; // signal deviation
} out;
struct {
uint8_t header[3];
uint8_t header[4];
// payload
uint8_t valid;
uint8_t valid; // 0xAA is valid
uint8_t hwRev[2];
uint8_t parameterStartAddr;
uint8_t loaderVersion[2];
uint8_t loaderPlatform;
uint8_t fwStartAddr;
uint8_t fwStartAddr; // should be 0x20
char fwVersion[120];
} fw;
struct{
uint8_t header[4];
uint8_t id;
uint8_t size;
uint16_t error;
@ -180,7 +182,7 @@ int16_t MGC3130_rotValue, MGC3130_lastSentRotValue = 0;
uint16_t MGC3130_lastSentX, MGC3130_lastSentY, MGC3130_lastSentZ = 0;
uint8_t hwRev[2], loaderVersion[2], loaderPlatform = 0;
char MGC3130_firmwareInfo[20];
float MGC3130_noisePower = -1;
uint8_t MGC3130_touchTimeout = 0;
uint16_t MGC3130_touchCounter = 1; // measure how long you touch the surface in loop cycles
@ -194,6 +196,7 @@ uint8_t MGC3130_mode = 1; // 1-gesture; 2-airwheel; 3-position
uint8_t MGC3130autoCal[] = {0x10, 0x00, 0x00, 0xA2, 0x80, 0x00 , 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t MGC3130disableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
uint8_t MGC3130enableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
uint8_t MGC3130enableAll[] = {0x10, 0x00, 0x00, 0xA2, 0xA0, 0x00 , 0x00, 0x00, 0x3f, 0x18, 0x00, 0x00, 0x3f, 0x18, 0x00, 0x00};
void MGC3130_handleSensorData(){
if ( MGC_data.out.outputConfigMask.touchInfo && MGC3130_touchTimeout == 0){
@ -220,6 +223,9 @@ void MGC3130_handleSensorData(){
MqttPublishSensor();
}
}
if(MGC_data.out.systemInfo.noisePowerValid){
MGC3130_noisePower = MGC_data.out.noisePower;
}
}
void MGC3130_sendMessage(uint8_t data[], uint8_t length){
@ -394,7 +400,7 @@ void MGC3130_handleAirWheel(){
}
void MGC3130_handleSystemStatus(){
//Serial.println("Got System status");
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MGC3130: system_status: response to ID:%02x, error code: %04x"),MGC_data.status.id, MGC_data.status.error);
}
bool MGC3130_receiveMessage(){
@ -407,16 +413,15 @@ bool MGC3130_receiveMessage(){
MGC3130_handleSystemStatus();
break;
case MGC3130_FW_VERSION:
hwRev[0] = MGC_data.fw.hwRev[1];
hwRev[1] = MGC_data.fw.hwRev[0];
loaderVersion[0] = MGC_data.fw.loaderVersion[0];
loaderVersion[1] = MGC_data.fw.loaderVersion[1];
hwRev[1] = MGC_data.fw.hwRev[1];
hwRev[0] = MGC_data.fw.hwRev[0];
loaderVersion[1] = MGC_data.fw.loaderVersion[0];
loaderVersion[0] = MGC_data.fw.loaderVersion[1];
loaderPlatform = MGC_data.fw.loaderPlatform;
snprintf_P(MGC3130_firmwareInfo, sizeof(MGC3130_firmwareInfo), PSTR("FW: %s"), MGC_data.fw.fwVersion);
MGC3130_firmwareInfo[20] = '\0';
// Serial.print(MGC3130_firmwareInfo);
AddLog_P(LOG_LEVEL_INFO,PSTR("MGC3130: GestIC:%s"),MGC_data.fw.fwVersion);
break;
}
MGC_data.out.id = 0;
return true;
}
return false;
@ -424,11 +429,12 @@ bool MGC3130_receiveMessage(){
bool MGC3130_readData()
{
static uint8_t _lastCounter = 0;
bool success = false;
if (!digitalRead(MGC3130_xfer)){
pinMode(MGC3130_xfer, OUTPUT);
digitalWrite(MGC3130_xfer, LOW);
Wire.requestFrom(MGC3130_I2C_ADDR, (uint16_t)32); // request usual data output
Wire.requestFrom(MGC3130_I2C_ADDR, (uint16_t)132); // request maximal data output
MGC_data.buffer[0] = 4; // read at least header, but update after first read anyway
unsigned char i = 0;
@ -438,6 +444,14 @@ bool MGC3130_readData()
}
digitalWrite(MGC3130_xfer, HIGH);
pinMode(MGC3130_xfer, INPUT);
uint8_t _mismatch = MGC_data.out.counter - _lastCounter;
if(_mismatch != 1){
if(i>4 && MGC_data.out.id != MGC3130_FW_VERSION){
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MGC3130: missed a packet, mismatch: %u"), _mismatch - 1);
AddLogBuffer(LOG_LEVEL_DEBUG,MGC_data.buffer,i);
}
}
_lastCounter = MGC_data.out.counter;
success = true;
}
return success;
@ -537,7 +551,9 @@ void MGC3130_show(bool json)
}
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_MGC_3130_SNS, MGC3130stype, status_chr, hwRev[0], hwRev[1], loaderVersion[0], loaderVersion[1], loaderPlatform );
char _noise[FLOATSZ];
dtostrfd(MGC3130_noisePower, 2, _noise);
WSContentSend_PD(HTTP_MGC_3130_SNS, MGC3130stype, status_chr, hwRev[0], hwRev[1], loaderVersion[0], loaderVersion[1], loaderPlatform, _noise);
#endif // USE_WEBSERVER
}
}
@ -552,6 +568,7 @@ void MGC3130_show(bool json)
* Sensor36 | 1 | Gesture Mode
* Sensor36 | 2 | Airwheel Mode
* Sensor36 | 3 | Position Mode with x,y,z - z must be higher than half of the max. sensing height
* Sensor36 | 4 | Enable all data for debugging (noise level in web GUI)
\*********************************************************************************************/
bool MGC3130CommandSensor()
@ -573,8 +590,12 @@ bool MGC3130CommandSensor()
case 3: // position & touch
MGC3130_mode = 3;
MGC3130_sendMessage(MGC3130disableAirwheel,16);
break;
break;
case 4: // enable all readings for noise level for web GUI
MGC3130_sendMessage(MGC3130enableAll,16);
break;
}
Response_P(PSTR("{\"MGC3130\":{\"mode\":%d}}"), MGC3130_mode);
return serviced;
}
@ -614,4 +635,4 @@ bool Xsns36(uint8_t function)
return result;
}
#endif // USE_MGC3130
#endif // USE_I2C
#endif // USE_I2C