From b4bc001a2adcdf74fcb7b66d23e9d2a7dcd31e44 Mon Sep 17 00:00:00 2001 From: Xavier MULLER <33861984+localhost61@users.noreply.github.com> Date: Wed, 2 Sep 2020 01:03:56 +0200 Subject: [PATCH 01/38] Update fr_FR.h v8.4.0.3 2nd attempt, I made 2 typos, sorry :-/ --- tasmota/language/fr_FR.h | 134 ++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 73 deletions(-) diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 434dd07b8..28310cc52 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -1,18 +1,14 @@ /* fr-FR.h - localization for French - France for Tasmota - Copyright (C) 2020 Olivier Francais - 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 . */ @@ -28,7 +24,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v8.1.0.1 + * Updated until v8.4.0.3 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -84,7 +80,7 @@ #define D_DISABLED "Désactivé" #define D_DISTANCE "Distance" #define D_DNS_SERVER "Serveur DNS" -#define D_DONE "Fait" +#define D_DONE "Terminé" #define D_DST_TIME "DST" #define D_ECO2 "eCO₂" #define D_EMULATION "Émulation" @@ -99,8 +95,8 @@ #define D_FILE "Fichier" #define D_FLOW_RATE "Débit" #define D_FREE_MEMORY "Mémoire libre" -#define D_PSR_MAX_MEMORY "PS-RAM Memory" -#define D_PSR_FREE_MEMORY "PS-RAM free Memory" +#define D_PSR_MAX_MEMORY "Mémoire PS-RAM" +#define D_PSR_FREE_MEMORY "Mémoire PS-RAM libre" #define D_FREQUENCY "Fréquence" #define D_GAS "Gaz" #define D_GATEWAY "Passerelle" @@ -304,7 +300,7 @@ #define D_OTHER_PARAMETERS "Autres paramètres" #define D_TEMPLATE "Modèle" #define D_ACTIVATE "Activer" -#define D_DEVICE_NAME "Device Name" +#define D_DEVICE_NAME "Nom de l'appareil" #define D_WEB_ADMIN_PASSWORD "Mot de passe Web Admin" #define D_MQTT_ENABLE "MQTT activé" #define D_MQTT_TLS_ENABLE "MQTT TLS" @@ -351,8 +347,8 @@ #define D_UPLOAD_STARTED "Téléchargement lancé" #define D_UPGRADE_STARTED "Mise à jour lancée" #define D_UPLOAD_DONE "Téléchargement terminé" -#define D_UPLOAD_TRANSFER "Upload transfer" -#define D_TRANSFER_STARTED "Transfer started" +#define D_UPLOAD_TRANSFER "Transfert ZigBee" +#define D_TRANSFER_STARTED "Transfert lancé" #define D_UPLOAD_ERR_1 "Aucun fichier sélectionné" #define D_UPLOAD_ERR_2 "Espace insuffisant" #define D_UPLOAD_ERR_3 "L'octet magique n'est pas 0xE9" @@ -486,7 +482,7 @@ // xsns_07_sht1x.ino #define D_SENSOR_DID_NOT_ACK_COMMAND "Le capteur n'a pas acquitté la commande" -#define D_SHT1X_FOUND "SHT1X found" +#define D_SHT1X_FOUND "SHT1X trouvé" // xsns_18_pms5003.ino #define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter @@ -533,24 +529,24 @@ #define D_TX20_WEST "O" // xsns_53_sml.ino -#define D_TPWRIN "Energy Total-In" -#define D_TPWROUT "Energy Total-Out" -#define D_TPWRCURR "Active Power-In/Out" -#define D_TPWRCURR1 "Active Power-In p1" -#define D_TPWRCURR2 "Active Power-In p2" -#define D_TPWRCURR3 "Active Power-In p3" -#define D_Strom_L1 "Current L1" -#define D_Strom_L2 "Current L2" -#define D_Strom_L3 "Current L3" -#define D_Spannung_L1 "Voltage L1" -#define D_Spannung_L2 "Voltage L2" -#define D_Spannung_L3 "Voltage L3" -#define D_METERNR "Meter_number" +#define D_TPWRIN "Energie totale Entrée" +#define D_TPWROUT "Energie totale Sortie" +#define D_TPWRCURR "Puissance active E/S" +#define D_TPWRCURR1 "Puissance active Ent Ph1" +#define D_TPWRCURR2 "Puissance active Ent Ph2" +#define D_TPWRCURR3 "Puissance active Ent Ph3" +#define D_Strom_L1 "Courant Ph1" +#define D_Strom_L2 "Courant Ph2" +#define D_Strom_L3 "Courant Ph3" +#define D_Spannung_L1 "Tension Ph1" +#define D_Spannung_L2 "Tension Ph2" +#define D_Spannung_L3 "Tension Ph3" +#define D_METERNR "Numéro compteur" #define D_METERSID "Service ID" -#define D_GasIN "Compteur" -#define D_H2oIN "Compteur" -#define D_StL1L2L3 "Current L1+L2+L3" -#define D_SpL1L2L3 "Voltage L1+L2+L3/3" +#define D_GasIN "Compteur Gaz" +#define D_H2oIN "Compteur Eau" +#define D_StL1L2L3 "Courant Ph1+Ph2+Ph3" +#define D_SpL1L2L3 "Tension (Ph1+Ph2+Ph3)/3" // tasmota_template.h - keep them as short as possible to be able to fit them in GUI drop down box #define D_SENSOR_NONE "Aucun" @@ -689,17 +685,17 @@ #define D_SENSOR_DYP_RX "DYP Rx" #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" -#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_WINDMETER_SPEED "Anémomètre" #define D_SENSOR_TELEINFO_RX "TInfo Rx" -#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" -#define D_SENSOR_LMT01_PULSE "LMT01 Pulse" -#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_TELEINFO_ENABLE "TInfo En" +#define D_SENSOR_LMT01_PULSE "LMT01 Impulsion" +#define D_SENSOR_ADC_INPUT "ADC Entrée" #define D_SENSOR_ADC_TEMP "ADC Temp" -#define D_SENSOR_ADC_LIGHT "ADC Light" -#define D_SENSOR_ADC_BUTTON "ADC Button" -#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_LIGHT "ADC Lumière" +#define D_SENSOR_ADC_BUTTON "ADC Bouton" +#define D_SENSOR_ADC_RANGE "ADC Distance" #define D_SENSOR_ADC_CT_POWER "ADC CT Power" -#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" +#define D_SENSOR_ADC_JOYSTICK "ADC Manette" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" @@ -719,7 +715,6 @@ #define D_SENSOR_TCP_RXD "TCP Rx" #define D_SENSOR_IEM3000_TX "iEM3000 TX" #define D_SENSOR_IEM3000_RX "iEM3000 RX" - // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CELSIUS "C" @@ -759,7 +754,6 @@ #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" #define D_UNIT_WATT_METER_QUADRAT "W/m²" - //SDM220, SDM120, LE01MR #define D_PHASE_ANGLE "Angle de phase" #define D_IMPORT_ACTIVE "Énergie act conso" @@ -770,7 +764,6 @@ #define D_UNIT_KWARH "kVArh" #define D_UNIT_ANGLE "°" #define D_TOTAL_ACTIVE "Total Active" - //SOLAXX1 #define D_PV1_VOLTAGE "Tension PV1" #define D_PV1_CURRENT "Courant PV1" @@ -794,47 +787,43 @@ #define D_SOLAX_ERROR_6 "Défaut Surchauffe" #define D_SOLAX_ERROR_7 "Défaut Ventilateur" #define D_SOLAX_ERROR_8 "Défaut Autre équipement" - //xdrv_10_scripter.ino -#define D_CONFIGURE_SCRIPT "Edit script" -#define D_SCRIPT "edit script" -#define D_SDCARD_UPLOAD "file upload" -#define D_SDCARD_DIR "sd card directory" -#define D_UPL_DONE "Done" -#define D_SCRIPT_CHARS_LEFT "chars left" -#define D_SCRIPT_CHARS_NO_MORE "no more chars" +#define D_CONFIGURE_SCRIPT "Éditer le script" +#define D_SCRIPT "édition du script" +#define D_SDCARD_UPLOAD "Envoi du fichier" +#define D_SDCARD_DIR "Dossier carte SD" +#define D_UPL_DONE "Terminé" +#define D_SCRIPT_CHARS_LEFT "car. restant" +#define D_SCRIPT_CHARS_NO_MORE "plus de car." #define D_SCRIPT_DOWNLOAD "Download" -#define D_SCRIPT_ENABLE "script enable" -#define D_SCRIPT_UPLOAD "Upload" -#define D_SCRIPT_UPLOAD_FILES "Upload files" - +#define D_SCRIPT_ENABLE "script actif" +#define D_SCRIPT_UPLOAD "Envoi" +#define D_SCRIPT_UPLOAD_FILES "Envoi de fichiers" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" -#define D_AS3935_ENERGY "energy:" +#define D_AS3935_ENERGY "energie:" #define D_AS3935_DISTANCE "distance:" -#define D_AS3935_DISTURBER "disturber:" +#define D_AS3935_DISTURBER "interférence:" #define D_AS3935_VRMS "µVrms:" -#define D_AS3935_APRX "aprx.:" -#define D_AS3935_AWAY "away" -#define D_AS3935_LIGHT "lightning" -#define D_AS3935_OUT "lightning out of range" -#define D_AS3935_NOT "distance not determined" -#define D_AS3935_ABOVE "lightning overhead" -#define D_AS3935_NOISE "noise detected" -#define D_AS3935_DISTDET "disturber detected" -#define D_AS3935_INTNOEV "Interrupt with no Event!" -#define D_AS3935_NOMESS "listening..." -#define D_AS3935_ON "On" -#define D_AS3935_OFF "Off" -#define D_AS3935_INDOORS "Indoors" -#define D_AS3935_OUTDOORS "Outdoors" -#define D_AS3935_CAL_FAIL "calibration failed" -#define D_AS3935_CAL_OK "calibration set to:" - +#define D_AS3935_APRX "approx.:" +#define D_AS3935_AWAY "de distance" +#define D_AS3935_LIGHT "éclair" +#define D_AS3935_OUT "éclair éloigné" +#define D_AS3935_NOT "distance indéterminée" +#define D_AS3935_ABOVE "éclair trop intense" +#define D_AS3935_NOISE "bruit détecté" +#define D_AS3935_DISTDET "interférence détectée" +#define D_AS3935_INTNOEV "Interruption sans évenement!" +#define D_AS3935_NOMESS "en écoute..." +#define D_AS3935_ON "Actif" +#define D_AS3935_OFF "Inactif" +#define D_AS3935_INDOORS "Intérieur" +#define D_AS3935_OUTDOORS "Extérieur" +#define D_AS3935_CAL_FAIL "défaut de calibration" +#define D_AS3935_CAL_OK "calibration établie à :" //xsns_68_opentherm.ino #define D_SENSOR_BOILER_OT_RX "OpenTherm RX" #define D_SENSOR_BOILER_OT_TX "OpenTherm TX" - // xnrg_15_teleinfo Denky (Teleinfo) #define D_CONTRACT "Type contrat" #define D_POWER_LOAD "Charge actuelle" @@ -843,5 +832,4 @@ #define D_OVERLOAD "ADPS" #define D_MAX_POWER "Puissance max" #define D_MAX_CURRENT "Courant max" - #endif // _LANGUAGE_FR_FR_H_ From 79c52ce1ef0e3c5e15a85fedbbcacc8c0dcd0691 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 2 Sep 2020 11:45:17 +0200 Subject: [PATCH 02/38] Refactor zigbee transfer --- tasmota/xdrv_23_zigbee_9a_upload.ino | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index 05b20fdab..fc7defb15 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -491,28 +491,25 @@ const char HTTP_SCRIPT_XFER_STATE[] PROGMEM = "if(x.readyState==4&&x.status==200){" "var s=x.responseText;" "if(s!=7){" // ZBU_UPLOAD - "location.href='/u3';" + "location.href='/u3';" // Load page HandleUploadDone() "}" "}" "};" - "x.open('GET','" WEB_HANDLE_ZIGBEE_XFER "?m=1',true);" // ?m related to Webserver->hasArg("m") + "x.open('GET','" WEB_HANDLE_ZIGBEE_XFER "?z=1',true);" // ?z related to Webserver->hasArg("z") "x.send();" - "if(pc==1){" - "lt=setTimeout(z9,950);" // Poll every 0.95 second - "}" + "lt=setTimeout(z9,950);" // Poll every 0.95 second "}" - "pc=1;" - "wl(z9);"; + "wl(z9);"; // Execute z9() on page load void HandleZigbeeXfer(void) { if (!HttpCheckPriviledgedAccess()) { return; } - if (Webserver->hasArg("m")) { // Status refresh requested + if (Webserver->hasArg("z")) { // Status refresh requested WSContentBegin(200, CT_PLAIN); WSContentSend_P(PSTR("%d"), ZbUpload.state); WSContentEnd(); if (ZBU_ERROR == ZbUpload.state) { - Web.upload_error = 7; // Upload aborted (failed) + Web.upload_error = 7; // Upload aborted (xmodem transfer failed) } return; } @@ -522,7 +519,7 @@ void HandleZigbeeXfer(void) { WSContentStart_P(S_INFORMATION); WSContentSend_P(HTTP_SCRIPT_XFER_STATE); WSContentSendStyle(); - WSContentSend_P(PSTR("
" D_UPLOAD_TRANSFER "...
")); + WSContentSend_P(PSTR("
" D_UPLOAD_TRANSFER " ...
")); WSContentSpaceButton(BUTTON_MAIN); WSContentStop(); } From a5bb8b640c2f0dd8e216ca6816d7ac9509f52168 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Wed, 2 Sep 2020 21:53:39 +0200 Subject: [PATCH 03/38] Update Italian language --- tasmota/language/it_IT.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 34f5a1696..747ec1560 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -1,7 +1,7 @@ /* it-IT.h - localization for Italian - Italy for Tasmota - Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 19.08.2020 + Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 02.09.2020 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 @@ -351,8 +351,8 @@ #define D_UPLOAD_STARTED "Caricamento..." #define D_UPGRADE_STARTED "Aggiornamento..." #define D_UPLOAD_DONE "Caricamento completato" -#define D_UPLOAD_TRANSFER "Upload transfer" -#define D_TRANSFER_STARTED "Transfer started" +#define D_UPLOAD_TRANSFER "Trasferimento caricamento" +#define D_TRANSFER_STARTED "Trasferimento avviato" #define D_UPLOAD_ERR_1 "Nessun file selezionato" #define D_UPLOAD_ERR_2 "Spazio insufficiente" #define D_UPLOAD_ERR_3 "Magic byte non corrispondente a 0xE9" From 994081430c3fa7bd4346b60b233259b24d771567 Mon Sep 17 00:00:00 2001 From: device111 <48546979+device111@users.noreply.github.com> Date: Thu, 3 Sep 2020 09:37:10 +0200 Subject: [PATCH 04/38] AS3935 Refactor - Fix Autodisturber - Fix Event IRQ Flicker when calibrating and on Start up - Add command `power` on/off - Add command `noirqevent` (suppress IRQ with no event) - Add Info Log when no Pin defined - Add Info Log when SCO and TCO Calibration Fails - optimize Autotune Caps - new init procedure (Reset before Start) - save 128 Bytes of Ram - update language files --- tasmota/language/bg_BG.h | 2 + tasmota/language/cs_CZ.h | 2 + tasmota/language/de_DE.h | 4 +- tasmota/language/el_GR.h | 2 + tasmota/language/en_GB.h | 2 + tasmota/language/es_ES.h | 2 + tasmota/language/fr_FR.h | 2 + tasmota/language/he_HE.h | 2 + tasmota/language/hu_HU.h | 2 + tasmota/language/it_IT.h | 2 + tasmota/language/ko_KO.h | 2 + tasmota/language/nl_NL.h | 2 + tasmota/language/pl_PL.h | 2 + tasmota/language/pt_BR.h | 2 + tasmota/language/pt_PT.h | 2 + tasmota/language/ro_RO.h | 2 + tasmota/language/ru_RU.h | 2 + tasmota/language/sk_SK.h | 2 + tasmota/language/sv_SE.h | 2 + tasmota/language/tr_TR.h | 2 + tasmota/language/uk_UA.h | 2 + tasmota/language/zh_CN.h | 2 + tasmota/language/zh_TW.h | 2 + tasmota/my_user_config.h | 2 +- tasmota/settings.h | 4 +- tasmota/tasmota_template.h | 4 +- tasmota/tasmota_template_ESP32.h | 4 +- tasmota/xsns_67_as3935.ino | 674 ++++++++++++++++--------------- 28 files changed, 413 insertions(+), 323 deletions(-) diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index ec637b220..e0543019c 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "открит шум" #define D_AS3935_DISTDET "открито смущение" #define D_AS3935_INTNOEV "Прекъсване без Събитие!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "слушане..." #define D_AS3935_ON "Вкл." #define D_AS3935_OFF "Изкл." diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 1d591b610..1200ceab5 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 4798c625e..abef862c9 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -812,7 +812,7 @@ #define D_AS3935_GAIN "Rauschpegel:" #define D_AS3935_ENERGY "Energie:" #define D_AS3935_DISTANCE "Entfernung:" -#define D_AS3935_DISTURBER "Störsingal:" +#define D_AS3935_DISTURBER "Enstörer:" #define D_AS3935_VRMS "µVrms:" #define D_AS3935_APRX "ca.:" #define D_AS3935_AWAY "entfernt" @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "Rauschen entdeckt" #define D_AS3935_DISTDET "Störer entdeckt" #define D_AS3935_INTNOEV "Interrupt ohne Grund!" +#define D_AS3935_FLICKER "IRQ Pin flackerd!" +#define D_AS3935_POWEROFF "Ausgeschaltet" #define D_AS3935_NOMESS "lausche..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 8e3653957..74a7b625f 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index c077dcb81..18d655ce3 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ Pin flicker!" +#define D_AS3935_POWEROFF "Powerd Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 10c0b1ac4..674b38eab 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "Ruido detectado" #define D_AS3935_DISTDET "Perturbancia detectada" #define D_AS3935_INTNOEV "Interrupción sin evento!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "Escuchando..." #define D_AS3935_ON "Encendido" #define D_AS3935_OFF "Apagado" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 28310cc52..be1fd4f93 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -814,6 +814,8 @@ #define D_AS3935_NOISE "bruit détecté" #define D_AS3935_DISTDET "interférence détectée" #define D_AS3935_INTNOEV "Interruption sans évenement!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "en écoute..." #define D_AS3935_ON "Actif" #define D_AS3935_OFF "Inactif" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index dd0f2fbee..0de84e609 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 79d7c40aa..23a7be121 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 34f5a1696..60792b77f 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "rilevato rumore" #define D_AS3935_DISTDET "rilevato disturbatore" #define D_AS3935_INTNOEV "Interrupt senza evento!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "in ascolto..." #define D_AS3935_ON "ON" #define D_AS3935_OFF "OFF" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index ef1f781b2..d08aea216 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index a3a5821fd..6a40607c9 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 929774738..7e9d25e5c 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 990b308cb..88f1d0c86 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index a976811c3..83bbbc778 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index c4cba2ee3..00ab45bcf 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index f9e576f70..13068198f 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 072caa53d..911581ee7 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 1ba0b0b7e..73ecd4bab 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 928ad30b6..e2b496d1e 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 8ce7ee877..388aecc9a 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index b1b58b4c4..220f866e9 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "noise detected" #define D_AS3935_DISTDET "disturber detected" #define D_AS3935_INTNOEV "Interrupt with no Event!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "listening..." #define D_AS3935_ON "On" #define D_AS3935_OFF "Off" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index fc9606a90..aca69ad6b 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -823,6 +823,8 @@ #define D_AS3935_NOISE "偵測到雜訊" #define D_AS3935_DISTDET "偵測到干擾物" #define D_AS3935_INTNOEV "沒有任何事件觸發中斷!" +#define D_AS3935_FLICKER "IRQ flicker!" +#define D_AS3935_POWEROFF "Power Off" #define D_AS3935_NOMESS "聽取中..." #define D_AS3935_ON "開啟" #define D_AS3935_OFF "關閉" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 5f94c5fc0..067490f14 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -552,7 +552,7 @@ // #define WEMOS_MOTOR_V1_FREQ 1000 // Default frequency // #define USE_HDC1080 // [I2cDriver45] Enable HDC1080 temperature/humidity sensor (I2C address 0x40) (+1k5 code) // #define USE_IAQ // [I2cDriver46] Enable iAQ-core air quality sensor (I2C address 0x5a) (+0k6 code) -// #define USE_AS3935 // [I2cDriver48] Enable AS3935 Franklin Lightning Sensor (I2C address 0x03) (+5k4 code) + #define USE_AS3935 // [I2cDriver48] Enable AS3935 Franklin Lightning Sensor (I2C address 0x03) (+5k4 code) // #define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code) // #define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code) // #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code) diff --git a/tasmota/settings.h b/tasmota/settings.h index d7a526d41..60c837364 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -282,9 +282,9 @@ typedef union { struct { uint8_t nf_autotune : 1; // Autotune the NF Noise Level uint8_t dist_autotune : 1; // Autotune Disturber on/off - uint8_t nf_autotune_both : 1; // Autotune over both Areas: INDOORS/OUDOORS + uint8_t nf_autotune_both : 1; // Autotune over both Areas: INDOORS/OUDOORS uint8_t mqtt_only_Light_Event : 1; // mqtt only if lightning Irq - uint8_t spare4 : 1; + uint8_t suppress_irq_no_Event : 1; // suppress mqtt "IRQ with no Event". (Chip Bug) uint8_t spare5 : 1; uint8_t spare6 : 1; uint8_t spare7 : 1; diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index f6d28e63d..32a914f8f 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -228,7 +228,7 @@ enum UserSelectablePins { GPIO_CC1101_GDO2, // CC1101 pin for RX GPIO_HRXL_RX, // Data from MaxBotix HRXL sonar range sensor GPIO_ELECTRIQ_MOODL_TX, // ElectriQ iQ-wifiMOODL Serial TX - GPIO_AS3935, + GPIO_AS3935, // Franklin Lightning Sensor GPIO_PMS5003_TX, // Plantower PMS5003 Serial interface GPIO_BOILER_OT_RX, // OpenTherm Boiler RX pin GPIO_BOILER_OT_TX, // OpenTherm Boiler TX pin @@ -710,7 +710,7 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_DYP_RX, #endif #ifdef USE_AS3935 - GPIO_AS3935, + GPIO_AS3935, // AS3935 IRQ Pin #endif #ifdef USE_TELEINFO GPIO_TELEINFO_RX, diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index 75e8e5a70..f0f59b488 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -111,7 +111,7 @@ enum UserSelectablePins { GPIO_CC1101_GDO0, GPIO_CC1101_GDO2, // CC1101 Serial interface GPIO_HRXL_RX, // Data from MaxBotix HRXL sonar range sensor GPIO_ELECTRIQ_MOODL_TX, // ElectriQ iQ-wifiMOODL Serial TX - GPIO_AS3935, + GPIO_AS3935, // Franklin Lightning Sensor GPIO_ADC_INPUT, // Analog input GPIO_ADC_TEMP, // Analog Thermistor GPIO_ADC_LIGHT, // Analog Light sensor @@ -557,7 +557,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_DYP_RX), #endif #ifdef USE_AS3935 - AGPIO(GPIO_AS3935), + AGPIO(GPIO_AS3935), // AS3935 IRQ Pin #endif #ifdef USE_TELEINFO AGPIO(GPIO_TELEINFO_RX), diff --git a/tasmota/xsns_67_as3935.ino b/tasmota/xsns_67_as3935.ino index 3723079b4..540b59ce0 100644 --- a/tasmota/xsns_67_as3935.ino +++ b/tasmota/xsns_67_as3935.ino @@ -31,15 +31,8 @@ #define D_NAME_AS3935 "AS3935" #define AS3935_ADDR 0x03 -// Reg mask shift -#define IRQ_TBL 0x03, 0x0F, 0 -#define ENERGY_RAW_1 0x04, 0xFF, 0 -#define ENERGY_RAW_2 0x05, 0xFF, 0 -#define ENERGY_RAW_3 0x06, 0x1F, 0 -#define LGHT_DIST 0x07, 0x3F, 0 -#define DISP_TRCO 0x08, 0x20, 5 -#define DISP_LCO 0x08, 0x80, 7 -#define TUNE_CAPS 0x08, 0x0F, 0 +// I2C Registers Reg mask shift +#define PWR_REG 0x00, 0x01, 0 #define AFE_GB 0x00, 0x3E, 0 #define WDTH 0x01, 0x0F, 0 #define NF_LEVEL 0x01, 0x70, 4 @@ -47,12 +40,32 @@ #define MIN_NUM_LIGH 0x02, 0x30, 4 #define DISTURBER 0x03, 0x20, 5 #define LCO_FDIV 0x03, 0xC0, 6 +#define IRQ_TBL 0x03, 0x0F, 0 +#define ENERGY_RAW_1 0x04, 0xFF, 0 +#define ENERGY_RAW_2 0x05, 0xFF, 0 +#define ENERGY_RAW_3 0x06, 0x1F, 0 +#define LGHT_DIST 0x07, 0x3F, 0 +#define DISP_TRCO 0x08, 0x20, 5 // should 31.250 kHz with devide 16 +#define DISP_SRCO 0x08, 0x40, 6 // 1,1 MHz +#define DISP_LCO 0x08, 0x80, 7 // 32.768 kHz +#define TUNE_CAPS 0x08, 0x0F, 0 +#define CAL_TRCO_NOK 0x3A, 0x40, 6 // 1 = NOK +#define CAL_TRCO_DONE 0x3A, 0x80, 7 // 0 = OK +#define CAL_SRCO_NOK 0x3B, 0x40, 6 +#define CAL_SRCO_DONE 0x3B, 0x80, 7 +// I2C Commands +#define RESET_DEFAULT 0x3C, 0x96 +#define CALIBATE_RCO 0x3D, 0x96 + +// NF-Level #define INDOORS 0x24 #define OUTDOORS 0x1C -// Global -const char HTTP_SNS_UNIT_KILOMETER[] PROGMEM = D_UNIT_KILOMETER; +// Load Settings Mask +#define SETREG00MASK 0x3E // For Power On +#define SETREG03MASK 0xF0 // For LCO and Disturber + // Http const char HTTP_SNS_AS3935_ENERGY[] PROGMEM = "{s}" D_NAME_AS3935 " " D_AS3935_ENERGY " {m}%d{e}"; const char HTTP_SNS_AS3935_DISTANZ[] PROGMEM = "{s}" D_NAME_AS3935 " " D_AS3935_DISTANCE " {m}%u " D_UNIT_KILOMETER "{e}"; @@ -66,15 +79,18 @@ const char HTTP_SNS_AS3935_DIST_ON[] PROGMEM = "{s}%s " D_AS3935_DISTURBER " {m} const char HTTP_SNS_AS3935_DIST_OFF[] PROGMEM = "{s}%s " D_AS3935_DISTURBER " {m}" D_AS3935_OFF " {e}"; const char* const HTTP_SNS_AS3935_DISTURBER[] PROGMEM = {HTTP_SNS_AS3935_DIST_OFF, HTTP_SNS_AS3935_DIST_ON}; // http Messages -const char HTTP_SNS_AS3935_EMPTY[] PROGMEM = "{s}%s: " D_AS3935_NOMESS "{e}"; -const char HTTP_SNS_AS3935_OUT[] PROGMEM = "{s}%s: " D_AS3935_OUT "{e}"; -const char HTTP_SNS_AS3935_NOT[] PROGMEM = "{s}%s: " D_AS3935_NOT "{e}"; -const char HTTP_SNS_AS3935_ABOVE[] PROGMEM = "{s}%s: " D_AS3935_ABOVE "{e}"; -const char HTTP_SNS_AS3935_NOISE[] PROGMEM = "{s}%s: " D_AS3935_NOISE "{e}"; -const char HTTP_SNS_AS3935_DISTURB[] PROGMEM = "{s}%s: " D_AS3935_DISTDET "{e}"; -const char HTTP_SNS_AS3935_INTNOEV[] PROGMEM = "{s}%s: " D_AS3935_INTNOEV "{e}"; -const char HTTP_SNS_AS3935_MSG[] PROGMEM = "{s}%s: " D_AS3935_LIGHT " " D_AS3935_APRX " %d " D_UNIT_KILOMETER " " D_AS3935_AWAY "{e}"; -const char* const HTTP_SNS_AS3935_TABLE_1[] PROGMEM = { HTTP_SNS_AS3935_EMPTY, HTTP_SNS_AS3935_MSG, HTTP_SNS_AS3935_OUT, HTTP_SNS_AS3935_NOT, HTTP_SNS_AS3935_ABOVE, HTTP_SNS_AS3935_NOISE, HTTP_SNS_AS3935_DISTURB, HTTP_SNS_AS3935_INTNOEV }; +const char HTTP_SNS_AS3935_EMPTY[] PROGMEM = "{s}%s " D_AS3935_NOMESS "{e}"; +const char HTTP_SNS_AS3935_OUT[] PROGMEM = "{s}%s " D_AS3935_OUT "{e}"; +const char HTTP_SNS_AS3935_NOT[] PROGMEM = "{s}%s " D_AS3935_NOT "{e}"; +const char HTTP_SNS_AS3935_ABOVE[] PROGMEM = "{s}%s " D_AS3935_ABOVE "{e}"; +const char HTTP_SNS_AS3935_NOISE[] PROGMEM = "{s}%s " D_AS3935_NOISE "{e}"; +const char HTTP_SNS_AS3935_DISTURB[] PROGMEM = "{s}%s " D_AS3935_DISTDET "{e}"; +const char HTTP_SNS_AS3935_INTNOEV[] PROGMEM = "{s}%s " D_AS3935_INTNOEV "{e}"; +const char HTTP_SNS_AS3935_FLICKER[] PROGMEM = "{s}%s " D_AS3935_FLICKER "{e}"; +const char HTTP_SNS_AS3935_POWEROFF[] PROGMEM = "{s}%s " D_AS3935_POWEROFF "{e}"; + +const char HTTP_SNS_AS3935_MSG[] PROGMEM = "{s}%s " D_AS3935_LIGHT " " D_AS3935_APRX " %d " D_UNIT_KILOMETER " " D_AS3935_AWAY "{e}"; +const char* const HTTP_SNS_AS3935_TABLE_1[] PROGMEM = { HTTP_SNS_AS3935_EMPTY, HTTP_SNS_AS3935_MSG, HTTP_SNS_AS3935_OUT, HTTP_SNS_AS3935_NOT, HTTP_SNS_AS3935_ABOVE, HTTP_SNS_AS3935_NOISE, HTTP_SNS_AS3935_DISTURB, HTTP_SNS_AS3935_INTNOEV, HTTP_SNS_AS3935_FLICKER, HTTP_SNS_AS3935_POWEROFF }; // Json const char JSON_SNS_AS3935_EVENTS[] PROGMEM = ",\"%s\":{\"" D_JSON_EVENT "\":%d,\"" D_JSON_DISTANCE "\":%d,\"" D_JSON_ENERGY "\":%u,\"" D_JSON_STAGE "\":%d}"; // Json Command @@ -84,13 +100,17 @@ const char* const S_JSON_AS3935_COMMAND_CAL[] PROGMEM = {"" D_AS3935_CAL_FAIL "" const char S_JSON_AS3935_COMMAND_STRING[] PROGMEM = "{\"" D_NAME_AS3935 "\":{\"%s\":%s}}"; const char S_JSON_AS3935_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_AS3935 "\":{\"%s\":%d}}"; -const char S_JSON_AS3935_COMMAND_SETTINGS[] PROGMEM = "{\"" D_NAME_AS3935 "\":{\"Gain\":%s,\"NFfloor\":%d,\"uVrms\":%d,\"Tunecaps\":%d,\"MinNumLight\":%d,\"Rejektion\":%d,\"Wdthreshold\":%d,\"MinNFstage\":%d,\"NFAutoTime\":%d,\"DisturberAutoTime\":%d,\"Disturber\":%s,\"NFauto\":%s,\"Disturberauto\":%s,\"NFautomax\":%s,\"Mqttlightevent\":%s}}"; +const char S_JSON_AS3935_COMMAND_SETTINGS[] PROGMEM = "{\"AS3935_Settings\":{\"Gain\":%s,\"NFfloor\":%d,\"uVrms\":%d,\"Tunecaps\":%d,\"MinNumLight\":%d,\"Rejektion\":%d,\"Wdthreshold\":%d,\"MinNFstage\":%d,\"NFAutoTime\":%d,\"DisturberAutoTime\":%d,\"Disturber\":%s,\"NFauto\":%s,\"Disturberauto\":%s,\"NFautomax\":%s,\"Mqttlightevent\":%s,\"Mqttnoirqevent\":%s}}"; -const char kAS3935_Commands[] PROGMEM = "setnf|setminstage|setml|default|setgain|settunecaps|setrej|setwdth|disttime|nftime|disturber|autonf|autodisturber|autonfmax|mqttevent|settings|calibrate"; +const char kAS3935_Commands[] PROGMEM = "power|setnf|setminstage|setml|default|setgain|settunecaps|setrej|setwdth|disttime|nftime|disturber|autonf|autodisturber|autonfmax|lightevent|noirqevent|settings|calibrate"; + +const uint8_t AS3935_VrmsIndoor[] PROGMEM = { 28, 45, 62, 78, 95, 112, 130, 146 }; +const uint16_t AS3935_VrmsOutdoor[] PROGMEM = { 390, 630, 860, 1100, 1140, 1570, 1800, 2000 }; enum AS3935_Commands { // commands for Console + CMND_AS3935_POWER, // Power on/off the device (1 Bit) CMND_AS3935_SET_NF, // Noise Floor Level, value from 0-7 (3 Bit) - CMND_AS3935_SET_MINNF, // Set Min Noise Floor Level when Autotune is active Value von 0-15 + CMND_AS3935_SET_MINNF, // Set Min Noise Floor Level when Autotune is active Value from 0-15 CMND_AS3935_SET_MINLIGHT, // Minimum number of lightning 0=1/1=5/2=9/3=16 Lightnings CMND_AS3935_SET_DEF, // set default for Sensor and Settings CMND_AS3935_SET_GAIN, // Set Inddoor/Outdoor @@ -104,24 +124,25 @@ enum AS3935_Commands { // commands for Console CMND_AS3935_DIST_AUTOTUNE, // Autotune Disturber on/off CMND_AS3935_NF_ATUNE_BOTH, // Autotune over both Areas: INDOORS/OUDOORS CMND_AS3935_MQTT_LIGHT_EVT, // mqtt only if lightning Irq + CMND_AS3935_MQTT_NO_IRQ_EVT, // suppress mqtt "IRQ with no Event" CMND_AS3935_SETTINGS, // Json output of all settings CMND_AS3935_CALIBRATE // caps autocalibrate - }; +}; -struct AS3935STRUCT -{ - bool autodist_activ = false; +struct { + bool active = false; + bool http_count_start = false; + bool poweroff = false; volatile bool detected = false; - volatile bool dispLCO = 0; - uint8_t icount = 0; + volatile bool dispLCO = false; + volatile uint8_t icount = 0; uint8_t irq = 0; - uint8_t mqtt_irq = 0; - uint8_t http_irq = 0; - uint8_t http_count_start = 0; + uint8_t mqtt_event = 0; + uint8_t http_event = 0; + uint8_t http_time = 0; + uint8_t http_count = 0; int16_t http_distance = 0; int16_t distance = 0; - uint16_t http_timer = 0; - uint16_t http_count = 0; uint16_t nftimer = 0; uint16_t disttimer = 0; uint32_t intensity = 0; @@ -129,16 +150,16 @@ struct AS3935STRUCT volatile uint32_t pulse = 0; } as3935_sensor; -uint8_t as3935_active = 0; - -void ICACHE_RAM_ATTR AS3935Isr() { +void ICACHE_RAM_ATTR AS3935Isr(void) { as3935_sensor.detected = true; + as3935_sensor.icount++; } +// we have to store 5 Bytes in the eeprom. Register 8 is mapped to Byte 4 uint8_t AS3935ReadRegister(uint8_t reg, uint8_t mask, uint8_t shift) { uint8_t data = I2cRead8(AS3935_ADDR, reg); if (reg == 0x08) Settings.as3935_sensor_cfg[4] = data; - if (reg < 0x04) Settings.as3935_sensor_cfg[reg] = data; + if (reg <= 0x03) Settings.as3935_sensor_cfg[reg] = data; return ((data & mask) >> shift); } @@ -150,12 +171,12 @@ void AS3935WriteRegister(uint8_t reg, uint8_t mask, uint8_t shift, uint8_t data) data |= currentReg; I2cWrite8(AS3935_ADDR, reg, data); if (reg == 0x08) Settings.as3935_sensor_cfg[4] = I2cRead8(AS3935_ADDR, reg); - if (reg < 0x04) Settings.as3935_sensor_cfg[reg] = I2cRead8(AS3935_ADDR, reg); + if (reg <= 0x03) Settings.as3935_sensor_cfg[reg] = I2cRead8(AS3935_ADDR, reg); } /********************************************************************************************/ // Autotune Caps -void ICACHE_RAM_ATTR AS3935CountFreq() { +void ICACHE_RAM_ATTR AS3935CountFreq(void) { if (as3935_sensor.dispLCO) as3935_sensor.pulse++; } @@ -163,52 +184,161 @@ void ICACHE_RAM_ATTR AS3935CountFreq() { bool AS3935AutoTuneCaps(uint8_t irqpin) { int32_t maxtune = 17500; // there max 3.5 % tol uint8_t besttune; + uint8_t oldvalue = AS3935GetTuneCaps(); AS3935WriteRegister(LCO_FDIV, 0); // Fdiv 16 delay(2); for (uint8_t tune = 0; tune < 16; tune++) { AS3935WriteRegister(TUNE_CAPS, tune); delay(2); - AS3935WriteRegister(DISP_LCO,1); + AS3935WriteRegister(DISP_LCO, 1); delay(1); as3935_sensor.dispLCO = true; as3935_sensor.pulse = 0; attachInterrupt(digitalPinToInterrupt(irqpin), AS3935CountFreq, RISING); - delay(200); // 100ms callback not work accurat for fequ. measure + delay(50); as3935_sensor.dispLCO = false; detachInterrupt(irqpin); - AS3935WriteRegister(DISP_LCO,0); - int32_t currentfreq = 500000 - ((as3935_sensor.pulse * 5) * 16); + AS3935WriteRegister(DISP_LCO, 0); + int32_t currentfreq = 500000 - ((as3935_sensor.pulse * 20) * 16); if(currentfreq < 0) currentfreq = -currentfreq; if(maxtune > currentfreq) { maxtune = currentfreq; besttune = tune; } } - if (maxtune >= 17500) // max. 3.5% + if (maxtune >= 17500) { // max. 3.5% + AS3935SetTuneCaps(oldvalue); return false; + } AS3935SetTuneCaps(besttune); return true; } /********************************************************************************************/ // functions -void AS3935CalibrateRCO() { - I2cWrite8(AS3935_ADDR, 0x3D, 0x96); - AS3935WriteRegister(DISP_TRCO, 1); +bool AS3935CalRCOResult(void) { + if(AS3935ReadRegister(CAL_SRCO_NOK) || AS3935ReadRegister(CAL_TRCO_NOK)) { + AddLog_P2(LOG_LEVEL_INFO, PSTR("I2C: AS3935 Fatal Failure of TRCO or SRCO calibration")); + return false; + } + return true; +} + +bool AS3935CalibrateRCO(void) { + detachInterrupt(Pin(GPIO_AS3935)); // Prevent AS3935Isr from RCO Calibration + I2cWrite8(AS3935_ADDR, CALIBATE_RCO); // Cal TRCO & SRCO + AS3935WriteRegister(DISP_TRCO, 1); // need for Power up delay(2); AS3935WriteRegister(DISP_TRCO, 0); + if(!AS3935CalRCOResult()) + return false; + attachInterrupt(digitalPinToInterrupt(Pin(GPIO_AS3935)), AS3935Isr, RISING); + return true; +} + +void AS3935Reset(void) { + I2cWrite8(AS3935_ADDR, RESET_DEFAULT); + delay(2); +} + +void AS3935PwrDown(void) { + AS3935WriteRegister(PWR_REG ,1); + detachInterrupt(Pin(GPIO_AS3935)); + as3935_sensor.poweroff = true; + as3935_sensor.mqtt_event = 9; + as3935_sensor.http_event = 9; + as3935_sensor.intensity = 0; + as3935_sensor.distance = 0; +} + +void AS3935PwrUp(void) { + AS3935WriteRegister(PWR_REG ,0); + AS3935CalibrateRCO(); + as3935_sensor.poweroff = false; + as3935_sensor.mqtt_event = 0; + as3935_sensor.http_event = 0; +} + +uint8_t AS3935GetPwrStat(void) { + if (AS3935ReadRegister(PWR_REG)) + return 0; + return 1; +} + +uint8_t AS3935GetIRQ(void) { + delay(2); + return AS3935ReadRegister(IRQ_TBL); +} + +uint8_t AS3935TranslIrq(uint8_t irq, uint8_t distance) { + switch(irq) { + case 0: return 7; // Interrupt with no IRQ + case 1: return 5; // Noise level too high + case 4: return 6; // Disturber detected + case 8: + if (distance == -1) return 2; // Lightning out of Distance + else if (distance == 0) return 3; // Distance cannot be determined + else if (distance == 1) return 4; // Storm is Overhead + else return 1; // Lightning with Distance detected + } + return 0; // Fix GCC 10.1 warning +} + +uint8_t AS3935GetDistance(void) { + return AS3935ReadRegister(LGHT_DIST); +} + +int16_t AS3935CalcDistance(void) { + uint8_t dist = AS3935GetDistance(); + switch (dist) { + case 0x3F: return -1; // Out of Range + case 0x00: return 0; // Distance cannot be determined + case 0x01: return 1; // Storm is Overhead + default: + if (40 < dist) return 40; // limited because higher is not accurate + return dist; + } +} + +uint32_t AS3935GetIntensity(void) { + uint32_t energy_raw = (AS3935ReadRegister(ENERGY_RAW_3) << 8); + energy_raw |= AS3935ReadRegister(ENERGY_RAW_2); + energy_raw <<= 8; + energy_raw |= AS3935ReadRegister(ENERGY_RAW_1); + return energy_raw; +} + +uint8_t AS3935GetTuneCaps(void) { + return AS3935ReadRegister(TUNE_CAPS); +} + +void AS3935SetTuneCaps(uint8_t tune) { + AS3935WriteRegister(TUNE_CAPS, tune); + delay(2); + AS3935CalibrateRCO(); +} + +uint8_t AS3935GetDisturber(void) { + return AS3935ReadRegister(DISTURBER); +} + +void AS3935SetDisturber(uint8_t stat) { + AS3935WriteRegister(DISTURBER, stat); +} + +uint8_t AS3935GetMinLights(void) { + return AS3935ReadRegister(MIN_NUM_LIGH); +} + +void AS3935SetMinLights(uint8_t stat) { + AS3935WriteRegister(MIN_NUM_LIGH, stat); } uint8_t AS3935TransMinLights(uint8_t min_lights) { - if (5 > min_lights) { - return 0; - } else if (9 > min_lights) { - return 1; - } else if (16 > min_lights) { - return 2; - } else { - return 3; - } + if (5 > min_lights) return 0; + else if (9 > min_lights) return 1; + else if (16 > min_lights) return 2; + else return 3; } uint8_t AS3935TranslMinLightsInt(uint8_t min_lights) { @@ -221,146 +351,7 @@ uint8_t AS3935TranslMinLightsInt(uint8_t min_lights) { return 0; // Fix GCC 10.1 warning } -uint8_t AS3935TranslIrq(uint8_t irq, uint8_t distance) { - switch(irq) { - case 0: return 7; // Interrupt with no IRQ - case 1: return 5; // Noise level too high - case 4: return 6; // Disturber detected - case 8: - if (distance == -1) return 2; // Lightning out of Distance - else if (distance == 0) return 3; // Distance cannot be determined - else if (distance == 1) return 4; // Storm is Overhead - else return 1; // Lightning with Distance detected - } - return 0; // Fix GCC 10.1 warning -} - -void AS3935CalcVrmsLevel(uint16_t &vrms, uint8_t &stage) -{ - uint8_t room = AS3935GetGain(); - uint8_t nflev = AS3935GetNoiseFloor(); - if (room == 0x24) - { - switch (nflev){ - case 0x00: - vrms = 28; - break; - case 0x01: - vrms = 45; - break; - case 0x02: - vrms = 62; - break; - case 0x03: - vrms = 78; - break; - case 0x04: - vrms = 95; - break; - case 0x05: - vrms = 112; - break; - case 0x06: - vrms = 130; - break; - case 0x07: - vrms = 146; - break; - } - stage = nflev; - } - else - { - switch (nflev) - { - case 0x00: - vrms = 390; - break; - case 0x01: - vrms = 630; - break; - case 0x02: - vrms = 860; - break; - case 0x03: - vrms = 1100; - break; - case 0x04: - vrms = 1140; - break; - case 0x05: - vrms = 1570; - break; - case 0x06: - vrms = 1800; - break; - case 0x07: - vrms = 2000; - break; - } - stage = nflev + 8; - } -} - -/********************************************************************************************/ -uint8_t AS3935GetIRQ() { - delay(2); - return AS3935ReadRegister(IRQ_TBL); -} - -uint8_t AS3935GetDistance() { - return AS3935ReadRegister(LGHT_DIST); -} - -int16_t AS3935CalcDistance() { - uint8_t dist = AS3935GetDistance(); - switch (dist) { - case 0x3F: return -1; // Out of Range - case 0x01: return 1; // Storm is Overhead - case 0x00: return 0; // Distance cannot be determined - default: - if (40 < dist){ - return 40;// limited because higher is not accurate - } - return dist; - } -} - -uint32_t AS3935GetIntensity() { - uint32_t nrgy_raw = (AS3935ReadRegister(ENERGY_RAW_3) << 8); - nrgy_raw |= AS3935ReadRegister(ENERGY_RAW_2); - nrgy_raw <<= 8; - nrgy_raw |= AS3935ReadRegister(ENERGY_RAW_1); - return nrgy_raw; -} - -uint8_t AS3935GetTuneCaps() { - return AS3935ReadRegister(TUNE_CAPS); -} - -void AS3935SetTuneCaps(uint8_t tune) { - AS3935WriteRegister(TUNE_CAPS, tune); - delay(2); - AS3935CalibrateRCO(); -} - -uint8_t AS3935GetDisturber() { - return AS3935ReadRegister(DISTURBER); -} - -void AS3935SetDisturber(uint8_t stat) { - AS3935WriteRegister(DISTURBER, stat); -} - -uint8_t AS3935GetMinLights() { - return AS3935ReadRegister(MIN_NUM_LIGH); -} - -void AS3935SetMinLights(uint8_t stat) { - AS3935WriteRegister(MIN_NUM_LIGH, stat); -} - -uint8_t AS3935GetNoiseFloor() { +uint8_t AS3935GetNoiseFloor(void) { return AS3935ReadRegister(NF_LEVEL); } @@ -368,7 +359,7 @@ void AS3935SetNoiseFloor(uint8_t noise) { AS3935WriteRegister(NF_LEVEL , noise); } -uint8_t AS3935GetGain() { +uint8_t AS3935GetGain(void) { if (AS3935ReadRegister(AFE_GB) == OUTDOORS) return OUTDOORS; return INDOORS; @@ -378,13 +369,25 @@ void AS3935SetGain(uint8_t room) { AS3935WriteRegister(AFE_GB, room); } -uint8_t AS3935GetGainInt() { +uint8_t AS3935GetGainInt(void) { if (AS3935ReadRegister(AFE_GB) == OUTDOORS) - return 1; -return 0; + return 1; + return 0; } -uint8_t AS3935GetSpikeRejection() { +void AS3935CalcVrmsLevel(uint16_t &vrms, uint8_t &stage) { + uint8_t room = AS3935GetGain(); + uint8_t nflev = AS3935GetNoiseFloor(); + if (room == INDOORS) { + vrms = pgm_read_byte(AS3935_VrmsIndoor + nflev); + stage = nflev; + } else { + vrms = pgm_read_word(AS3935_VrmsOutdoor + nflev); + stage = nflev + 8; + } +} + +uint8_t AS3935GetSpikeRejection(void) { return AS3935ReadRegister(SPIKE_REJECT); } @@ -392,7 +395,7 @@ void AS3935SetSpikeRejection(uint8_t rej) { AS3935WriteRegister(SPIKE_REJECT, rej); } -uint8_t AS3935GetWdth() { +uint8_t AS3935GetWdth(void) { return AS3935ReadRegister(WDTH); } @@ -400,17 +403,15 @@ void AS3935SetWdth(uint8_t wdth) { AS3935WriteRegister(WDTH, wdth); } -bool AS3935AutoTune(){ +bool AS3935AutoTune(void) { detachInterrupt(Pin(GPIO_AS3935)); bool result = AS3935AutoTuneCaps(Pin(GPIO_AS3935)); - attachInterrupt(digitalPinToInterrupt(Pin(GPIO_AS3935)), AS3935Isr, RISING); return result; } /********************************************************************************************/ // Noise Floor autofunctions -bool AS3935LowerNoiseFloor() { - uint8_t noise = AS3935GetNoiseFloor(); +bool AS3935LowerNoiseFloor(void) { uint16_t vrms; uint8_t stage; AS3935CalcVrmsLevel(vrms, stage); @@ -421,6 +422,7 @@ bool AS3935LowerNoiseFloor() { return true; } } + uint8_t noise = AS3935GetNoiseFloor(); if (0 < noise && stage > Settings.as3935_parameter.nf_autotune_min) { noise--; AS3935SetNoiseFloor(noise); @@ -429,7 +431,7 @@ bool AS3935LowerNoiseFloor() { return false; } -bool AS3935RaiseNoiseFloor() { +bool AS3935RaiseNoiseFloor(void) { uint8_t noise = AS3935GetNoiseFloor(); uint8_t room = AS3935GetGain(); if (Settings.as3935_functions.nf_autotune_both) { @@ -449,22 +451,25 @@ bool AS3935RaiseNoiseFloor() { /********************************************************************************************/ // init functions -bool AS3935SetDefault() { - I2cWrite8(AS3935_ADDR, 0x3C, 0x96); // Set default - delay(2); +bool AS3935SetDefault(void) { + AS3935Reset(); + AS3935SetDisturber(1); // Disturber on by default + AS3935SetNoiseFloor(7); // NF High on by default Settings.as3935_sensor_cfg[0] = I2cRead8(AS3935_ADDR, 0x00); Settings.as3935_sensor_cfg[1] = I2cRead8(AS3935_ADDR, 0x01); Settings.as3935_sensor_cfg[2] = I2cRead8(AS3935_ADDR, 0x02); Settings.as3935_sensor_cfg[3] = I2cRead8(AS3935_ADDR, 0x03); Settings.as3935_sensor_cfg[4] = I2cRead8(AS3935_ADDR, 0x08); + // set all eeprom functions and values to default + Settings.as3935_functions.data = 0x00; Settings.as3935_parameter.nf_autotune_min = 0x00; Settings.as3935_parameter.nf_autotune_time = 4; Settings.as3935_parameter.dist_autotune_time = 1; return true; } -void AS3935InitSettings() { - if(Settings.as3935_functions.nf_autotune){ +void AS3935InitSettings(void) { + if(Settings.as3935_functions.nf_autotune) { if(Settings.as3935_parameter.nf_autotune_min) { if (Settings.as3935_parameter.nf_autotune_min > 7) { AS3935SetGain(OUTDOORS); @@ -475,114 +480,137 @@ void AS3935InitSettings() { } } } - I2cWrite8(AS3935_ADDR, 0x00, Settings.as3935_sensor_cfg[0]); + I2cWrite8(AS3935_ADDR, 0x00, Settings.as3935_sensor_cfg[0] & SETREG00MASK); I2cWrite8(AS3935_ADDR, 0x01, Settings.as3935_sensor_cfg[1]); I2cWrite8(AS3935_ADDR, 0x02, Settings.as3935_sensor_cfg[2]); - I2cWrite8(AS3935_ADDR, 0x03, Settings.as3935_sensor_cfg[3]); + I2cWrite8(AS3935_ADDR, 0x03, Settings.as3935_sensor_cfg[3] & SETREG03MASK); I2cWrite8(AS3935_ADDR, 0x08, Settings.as3935_sensor_cfg[4]); delay(2); } -void AS3935Setup(void) { +bool AS3935Setup(void) { if (Settings.as3935_sensor_cfg[0] == 0x00) { AS3935SetDefault(); } else { AS3935InitSettings(); } - AS3935CalibrateRCO(); + return AS3935CalibrateRCO(); } -bool AS3935init() { - uint8_t ret = I2cRead8(AS3935_ADDR, 0x00); - if(INDOORS == ret || OUTDOORS == ret) // 0x24 +bool AS3935init(void) { + AS3935Reset(); + uint8_t afe_gb = I2cRead8(AS3935_ADDR, 0x00) & SETREG00MASK; + if(INDOORS == afe_gb) return true; return false; } void AS3935Detect(void) { - if (I2cActive(AS3935_ADDR)) return; - if (AS3935init()) - { + if (!I2cSetDevice(AS3935_ADDR)) return; + if (AS3935init()) { I2cSetActiveFound(AS3935_ADDR, D_NAME_AS3935); - pinMode(Pin(GPIO_AS3935), INPUT); - attachInterrupt(digitalPinToInterrupt(Pin(GPIO_AS3935)), AS3935Isr, RISING); - AS3935Setup(); - as3935_active = 1; + if (PinUsed(GPIO_AS3935)) { + pinMode(Pin(GPIO_AS3935), INPUT); + if (!AS3935Setup()) return; + as3935_sensor.active = true; + } else { + AddLog_P2(LOG_LEVEL_INFO, PSTR("I2C: AS3935 GPIO Pin not defined!")); + } } } -void AS3935EverySecond() { - if (as3935_sensor.detected) { - as3935_sensor.irq = AS3935GetIRQ(); // 1 =Noise, 4 = Disturber, 8 = storm - switch (as3935_sensor.irq) { - case 1: - if (Settings.as3935_functions.nf_autotune) { - if (AS3935RaiseNoiseFloor()) as3935_sensor.nftimer = 0; +void AS3935EverySecond(void) { + if (!as3935_sensor.poweroff) { // Power Off + if (as3935_sensor.detected) { + as3935_sensor.detected = false; + as3935_sensor.irq = AS3935GetIRQ(); // 1 = Noise, 4 = Disturber, 8 = storm + + if (10 > as3935_sensor.icount) { + switch (as3935_sensor.irq) { + case 1: + if (Settings.as3935_functions.nf_autotune) { + if (AS3935RaiseNoiseFloor()) + as3935_sensor.nftimer = 0; + } + break; + case 4: + if (Settings.as3935_functions.dist_autotune) { + AS3935SetDisturber(1); + } + break; + case 8: + as3935_sensor.intensity = AS3935GetIntensity(); + as3935_sensor.distance = AS3935CalcDistance(); + as3935_sensor.http_intensity = as3935_sensor.intensity; + as3935_sensor.http_distance = as3935_sensor.distance; + break; } - break; - case 4: - if (Settings.as3935_functions.dist_autotune) { - AS3935SetDisturber(1); - as3935_sensor.autodist_activ = true; - } - break; - case 8: - as3935_sensor.intensity = AS3935GetIntensity(); - as3935_sensor.distance = AS3935CalcDistance(); - as3935_sensor.http_intensity = as3935_sensor.intensity; - as3935_sensor.http_distance = as3935_sensor.distance; - break; - } - // http show - as3935_sensor.http_irq = AS3935TranslIrq(as3935_sensor.irq, as3935_sensor.distance); - // mqtt publish - as3935_sensor.mqtt_irq = as3935_sensor.http_irq; - switch (as3935_sensor.mqtt_irq) { + // http show + as3935_sensor.http_event = AS3935TranslIrq(as3935_sensor.irq, as3935_sensor.distance); + } else { + as3935_sensor.http_event = 8; // flicker detected + } + + // mqtt publish + as3935_sensor.mqtt_event = as3935_sensor.http_event; + + switch (as3935_sensor.mqtt_event) { case 5: case 6: - if (!Settings.as3935_functions.mqtt_only_Light_Event) { + if (!Settings.as3935_functions.mqtt_only_Light_Event) { MqttPublishSensor(); - as3935_sensor.http_timer = 10; - } - break; - default: - as3935_sensor.http_timer = 60; + as3935_sensor.http_time = 10; + } + break; + case 7: + if (!Settings.as3935_functions.suppress_irq_no_Event) { + MqttPublishSensor(); + as3935_sensor.http_time = 10; + } + break; + default: + as3935_sensor.http_time = 30; MqttPublishSensor(); - } - // clear mqtt events for Teleperiod - as3935_sensor.intensity = 0; - as3935_sensor.distance = 0; - as3935_sensor.mqtt_irq = 0; - // start http times - as3935_sensor.http_count_start = 1; - as3935_sensor.http_count = 0; - as3935_sensor.icount++; // Int counter - as3935_sensor.detected = false; - } + } - if (as3935_sensor.http_count_start) as3935_sensor.http_count++; - // clear Http - if (as3935_sensor.http_count > as3935_sensor.http_timer) { - as3935_sensor.http_count_start = 0; - as3935_sensor.http_intensity = 0; - as3935_sensor.http_distance = 0; - as3935_sensor.http_irq = 0; - } - // Noise Floor Autotune function - if (Settings.as3935_functions.nf_autotune) { - as3935_sensor.nftimer++; - if (as3935_sensor.nftimer > Settings.as3935_parameter.nf_autotune_time * 60) { - AS3935LowerNoiseFloor(); - as3935_sensor.nftimer = 0; + as3935_sensor.irq = 0; + // clear mqtt events for Teleperiod + as3935_sensor.intensity = 0; + as3935_sensor.distance = 0; + as3935_sensor.mqtt_event = 0; + // start http times + as3935_sensor.http_count_start = true; + as3935_sensor.http_count = 0; } - } - // Disturber auto function - if (Settings.as3935_functions.dist_autotune) { - if (as3935_sensor.autodist_activ) as3935_sensor.disttimer++; - if (as3935_sensor.disttimer >= Settings.as3935_parameter.dist_autotune_time * 60) { - AS3935SetDisturber(0); - as3935_sensor.disttimer = 0; - as3935_sensor.autodist_activ = false; + as3935_sensor.icount = 0; + + // count http times + if (as3935_sensor.http_count_start) + as3935_sensor.http_count++; + // clear Http Event + if (as3935_sensor.http_count > as3935_sensor.http_time) { + as3935_sensor.http_count_start = false; + as3935_sensor.http_intensity = 0; + as3935_sensor.http_distance = 0; + as3935_sensor.http_event = 0; + } + // Noise Floor Autotune function + if (Settings.as3935_functions.nf_autotune) { + as3935_sensor.nftimer++; + if (as3935_sensor.nftimer > Settings.as3935_parameter.nf_autotune_time * 60) { + AS3935LowerNoiseFloor(); + as3935_sensor.nftimer = 0; + } + } + // Disturber auto function + if (Settings.as3935_functions.dist_autotune) { + if (AS3935GetDisturber()) { + as3935_sensor.disttimer++; + } + if (as3935_sensor.disttimer >= Settings.as3935_parameter.dist_autotune_time * 60) { + AS3935SetDisturber(0); + as3935_sensor.disttimer = 0; + } } } } @@ -593,6 +621,16 @@ bool AS3935Cmd(void) { if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_NAME_AS3935), name_len)) { uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + name_len, kAS3935_Commands); switch (command_code) { + case CMND_AS3935_POWER: + if (XdrvMailbox.data_len) { + if (!XdrvMailbox.payload) { + AS3935PwrDown(); + } else { + AS3935PwrUp(); + } + } + Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[AS3935GetPwrStat()]); + break; case CMND_AS3935_SET_NF: if (XdrvMailbox.data_len) { if (15 >= XdrvMailbox.payload) { @@ -712,6 +750,14 @@ bool AS3935Cmd(void) { } Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[Settings.as3935_functions.mqtt_only_Light_Event]); break; + case CMND_AS3935_MQTT_NO_IRQ_EVT: + if (XdrvMailbox.data_len) { + if (2 > XdrvMailbox.payload) { + Settings.as3935_functions.suppress_irq_no_Event = XdrvMailbox.payload; + } + } + Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[Settings.as3935_functions.suppress_irq_no_Event]); + break; case CMND_AS3935_SETTINGS: { if (!XdrvMailbox.data_len) { uint8_t gain = AS3935GetGainInt(); @@ -719,30 +765,31 @@ bool AS3935Cmd(void) { uint8_t stage; AS3935CalcVrmsLevel(vrms, stage); uint8_t nf_floor = AS3935GetNoiseFloor(); - uint8_t min_nf = Settings.as3935_parameter.nf_autotune_min; uint8_t tunecaps = AS3935GetTuneCaps(); uint8_t minnumlight = AS3935TranslMinLightsInt(AS3935GetMinLights()); uint8_t disturber = AS3935GetDisturber(); uint8_t reinj = AS3935GetSpikeRejection(); uint8_t wdth = AS3935GetWdth(); + uint8_t min_nf = Settings.as3935_parameter.nf_autotune_min; + uint8_t nf_time = Settings.as3935_parameter.nf_autotune_time; uint8_t nfauto = Settings.as3935_functions.nf_autotune; - uint8_t distauto = Settings.as3935_functions.dist_autotune; uint8_t nfautomax = Settings.as3935_functions.nf_autotune_both; + uint8_t distauto = Settings.as3935_functions.dist_autotune; uint8_t jsonlight = Settings.as3935_functions.mqtt_only_Light_Event; - uint8_t nf_time = Settings.as3935_parameter.nf_autotune_time; - uint8_t dist_time =Settings.as3935_parameter.dist_autotune_time; - Response_P(S_JSON_AS3935_COMMAND_SETTINGS, S_JSON_AS3935_COMMAND_GAIN[gain], nf_floor, vrms, tunecaps, minnumlight, reinj, wdth, min_nf, nf_time, dist_time, S_JSON_AS3935_COMMAND_ONOFF[disturber], S_JSON_AS3935_COMMAND_ONOFF[nfauto], S_JSON_AS3935_COMMAND_ONOFF[distauto], S_JSON_AS3935_COMMAND_ONOFF[nfautomax], S_JSON_AS3935_COMMAND_ONOFF[jsonlight]); + uint8_t jsonirq = Settings.as3935_functions.suppress_irq_no_Event; + uint8_t dist_time = Settings.as3935_parameter.dist_autotune_time; + Response_P(S_JSON_AS3935_COMMAND_SETTINGS, S_JSON_AS3935_COMMAND_GAIN[gain], nf_floor, vrms, tunecaps, minnumlight, reinj, wdth, min_nf, nf_time, dist_time, S_JSON_AS3935_COMMAND_ONOFF[disturber], S_JSON_AS3935_COMMAND_ONOFF[nfauto], S_JSON_AS3935_COMMAND_ONOFF[distauto], S_JSON_AS3935_COMMAND_ONOFF[nfautomax], S_JSON_AS3935_COMMAND_ONOFF[jsonlight], S_JSON_AS3935_COMMAND_ONOFF[jsonirq]); } } - break; - case CMND_AS3935_CALIBRATE: { - bool calreslt; - if (!XdrvMailbox.data_len) calreslt = AS3935AutoTune(); - Response_P(S_JSON_AS3935_COMMAND_NVALUE, S_JSON_AS3935_COMMAND_CAL[calreslt], AS3935GetTuneCaps()); - } - break; - default: - return false; + break; + case CMND_AS3935_CALIBRATE: { + bool calreslt; + if (!XdrvMailbox.data_len) calreslt = AS3935AutoTune(); + Response_P(S_JSON_AS3935_COMMAND_NVALUE, S_JSON_AS3935_COMMAND_CAL[calreslt], AS3935GetTuneCaps()); + } + break; + default: + return false; } return true; } else { @@ -750,13 +797,12 @@ bool AS3935Cmd(void) { } } -void AH3935Show(bool json) -{ +void AH3935Show(bool json) { if (json) { uint16_t vrms; uint8_t stage; AS3935CalcVrmsLevel(vrms, stage); - ResponseAppend_P(JSON_SNS_AS3935_EVENTS, D_SENSOR_AS3935, as3935_sensor.mqtt_irq, as3935_sensor.distance, as3935_sensor.intensity, stage); + ResponseAppend_P(JSON_SNS_AS3935_EVENTS, D_SENSOR_AS3935, as3935_sensor.mqtt_event, as3935_sensor.distance, as3935_sensor.intensity, stage); #ifdef USE_WEBSERVER } else { uint8_t gain = AS3935GetGainInt(); @@ -765,12 +811,13 @@ void AH3935Show(bool json) uint8_t stage; AS3935CalcVrmsLevel(vrms, stage); - WSContentSend_PD(HTTP_SNS_AS3935_TABLE_1[as3935_sensor.http_irq], D_NAME_AS3935, as3935_sensor.http_distance); + WSContentSend_PD(HTTP_SNS_AS3935_TABLE_1[as3935_sensor.http_event], D_NAME_AS3935, as3935_sensor.http_distance); WSContentSend_PD(HTTP_SNS_AS3935_DISTANZ, as3935_sensor.http_distance); WSContentSend_PD(HTTP_SNS_AS3935_ENERGY, as3935_sensor.http_intensity); WSContentSend_PD(HTTP_SNS_AS3935_GAIN[gain], D_NAME_AS3935); WSContentSend_PD(HTTP_SNS_AS3935_DISTURBER[disturber], D_NAME_AS3935); WSContentSend_PD(HTTP_SNS_AS3935_VRMS, vrms, stage); + #endif // USE_WEBSERVER } } @@ -779,16 +826,13 @@ void AH3935Show(bool json) * Interface \*********************************************************************************************/ -bool Xsns67(uint8_t function) -{ +bool Xsns67(uint8_t function) { if (!I2cEnabled(XI2C_48)) { return false; } - bool result = false; - if (FUNC_INIT == function) { AS3935Detect(); } - else if (as3935_active) { + else if (as3935_sensor.active) { switch (function) { case FUNC_EVERY_SECOND: AS3935EverySecond(); From 2e067977b957296a19ef4623be6e244b0b45d766 Mon Sep 17 00:00:00 2001 From: device111 <48546979+device111@users.noreply.github.com> Date: Thu, 3 Sep 2020 09:39:48 +0200 Subject: [PATCH 05/38] Update de_DE.h --- tasmota/language/de_DE.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index abef862c9..cf7271539 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -812,7 +812,7 @@ #define D_AS3935_GAIN "Rauschpegel:" #define D_AS3935_ENERGY "Energie:" #define D_AS3935_DISTANCE "Entfernung:" -#define D_AS3935_DISTURBER "Enstörer:" +#define D_AS3935_DISTURBER "Entstörer:" #define D_AS3935_VRMS "µVrms:" #define D_AS3935_APRX "ca.:" #define D_AS3935_AWAY "entfernt" From 4f4f74a545e90fa0503e9240665e94f1ae1af1b3 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 3 Sep 2020 10:48:36 +0200 Subject: [PATCH 06/38] AS3935 not enabled --- tasmota/my_user_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 067490f14..5f94c5fc0 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -552,7 +552,7 @@ // #define WEMOS_MOTOR_V1_FREQ 1000 // Default frequency // #define USE_HDC1080 // [I2cDriver45] Enable HDC1080 temperature/humidity sensor (I2C address 0x40) (+1k5 code) // #define USE_IAQ // [I2cDriver46] Enable iAQ-core air quality sensor (I2C address 0x5a) (+0k6 code) - #define USE_AS3935 // [I2cDriver48] Enable AS3935 Franklin Lightning Sensor (I2C address 0x03) (+5k4 code) +// #define USE_AS3935 // [I2cDriver48] Enable AS3935 Franklin Lightning Sensor (I2C address 0x03) (+5k4 code) // #define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code) // #define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code) // #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code) From a7fb362e1c0df4d4688bd2ffd950cbcc99d1e37f Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 3 Sep 2020 12:26:03 +0200 Subject: [PATCH 07/38] display touch interface unified --- .../Arduino_ST7789.cpp | 5 +- lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h | 2 +- lib/FT5206_Library/src/FT5206.cpp | 2 +- lib/FT5206_Library/src/FT5206.h | 2 + .../src/renderer.cpp | 1 + .../src/renderer.h | 16 +- tasmota/xdrv_10_scripter.ino | 182 +++++++++++++----- tasmota/xdrv_13_display.ino | 182 +++++++++++++++++- tasmota/xdsp_08_ILI9488.ino | 101 +++++----- tasmota/xdsp_10_RA8876.ino | 172 +++-------------- tasmota/xdsp_12_ST7789.ino | 161 +++------------- 11 files changed, 438 insertions(+), 388 deletions(-) diff --git a/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp b/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp index 344c22dad..487af20de 100755 --- a/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp +++ b/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp @@ -546,7 +546,7 @@ void Arduino_ST7789::DisplayOnff(int8_t on) { writecommand(ST7789_DISPON); //Display on if (_bp>=0) { #ifdef ST7789_DIMMER - ledcWrite(ESP32_PWM_CHANNEL,255); + ledcWrite(ESP32_PWM_CHANNEL,dimmer); #else digitalWrite(_bp,HIGH); #endif @@ -564,7 +564,8 @@ void Arduino_ST7789::DisplayOnff(int8_t on) { } // dimmer 0-100 -void Arduino_ST7789::dim(uint8_t dimmer) { +void Arduino_ST7789::dim(uint8_t dim) { + dimmer = dim; if (dimmer>15) dimmer=15; dimmer=((float)dimmer/15.0)*255.0; #ifdef ESP32 diff --git a/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h b/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h index f2571a104..2d97346e7 100755 --- a/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h +++ b/lib/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h @@ -161,7 +161,7 @@ class Arduino_ST7789 : public Renderer { boolean _hwSPI; boolean _SPI9bit; boolean _DCbit; - + uint8_t dimmer; int8_t _cs, _dc, _rst, _sid, _sclk, _bp; #if defined(USE_FAST_IO) diff --git a/lib/FT5206_Library/src/FT5206.cpp b/lib/FT5206_Library/src/FT5206.cpp index 29d4c6778..f0b106174 100755 --- a/lib/FT5206_Library/src/FT5206.cpp +++ b/lib/FT5206_Library/src/FT5206.cpp @@ -41,7 +41,7 @@ int FT5206_Class::begin(TwoWire &port, uint8_t addr) } _readByte(FT5206_CHIPID_REG, 1, &val); //Serial.printf("chip id %d\n",val ); - if ((val != FT6206_CHIPID) && (val != FT6236_CHIPID) && (val != FT6236U_CHIPID) && (val != FT5206U_CHIPID)) { + if ((val != FT6206_CHIPID) && (val != FT6236_CHIPID) && (val != FT6236U_CHIPID) && (val != FT5206U_CHIPID) && (val != FT5316_CHIPID) ) { return false; } _init = true; diff --git a/lib/FT5206_Library/src/FT5206.h b/lib/FT5206_Library/src/FT5206.h index 1a9d4d0ad..d8b6a8e3a 100755 --- a/lib/FT5206_Library/src/FT5206.h +++ b/lib/FT5206_Library/src/FT5206.h @@ -49,6 +49,8 @@ github:https://github.com/lewisxhe/FT5206_Library #define FT6236U_CHIPID 0x64 #define FT5206U_CHIPID 0x64 +#define FT5316_CHIPID 0x0a + #define DEVIDE_MODE 0x00 #define TD_STATUS 0x02 #define TOUCH1_XH 0x03 diff --git a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp index 10806220f..a8f0f9e57 100644 --- a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp +++ b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp @@ -519,4 +519,5 @@ void VButton::xdrawButton(bool inverted) { wr_redir=0; } + /* END OF FILE */ diff --git a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h index 09347ae29..27ff56efe 100644 --- a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h +++ b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h @@ -46,9 +46,23 @@ private: uint8_t font; }; +typedef union { + uint8_t data; + struct { + uint8_t spare0 : 1; + uint8_t spare1 : 1; + uint8_t spare2 : 1; + uint8_t spare3 : 1; + uint8_t disable : 1; + uint8_t on_off : 1; + uint8_t is_pushbutton : 1; + uint8_t is_virtual : 1; + }; +} TButton_State; + class VButton : public Adafruit_GFX_Button { public: - uint8_t vpower; + TButton_State vpower; void xdrawButton(bool inverted); }; diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 6353fa38a..cd5f986d2 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -300,12 +300,35 @@ struct T_INDEX { }; struct M_FILT { +#ifdef LARGE_ARRAYS + uint16_t numvals; + uint16_t index; +#else uint8_t numvals; uint8_t index; +#endif // LARGE_ARRAYS float maccu; float rbuff[1]; }; + +#ifdef LARGE_ARRAYS +#undef AND_FILT_MASK +#undef OR_FILT_MASK +#define AND_FILT_MASK 0x7fff +#define OR_FILT_MASK 0x8000 +#undef MAX_ARRAY_SIZE +#define MAX_ARRAY_SIZE 1000 +#else +#undef AND_FILT_MASK +#undef OR_FILT_MASK +#define AND_FILT_MASK 0x7f +#define OR_FILT_MASK 0x80 +#undef MAX_ARRAY_SIZE +#define MAX_ARRAY_SIZE 127 +#endif + + typedef union { uint8_t data; struct { @@ -462,6 +485,8 @@ void RulesTeleperiod(void) { #define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++; #define SCRIPT_SKIP_EOL while (*lp==SCRIPT_EOL) lp++; +float *Get_MFAddr(uint8_t index,uint16_t *len,uint16_t *ipos); + // allocates all variables and presets them int16_t Init_Scripter(void) { char *script; @@ -543,12 +568,16 @@ char *script; if ((*lp=='m' || *lp=='M') && *(lp+1)==':') { uint8_t flg=*lp; lp+=2; + if (*lp=='p' && *(lp+1)==':') { + vtypes[vars].bits.is_permanent=1; + lp+=2; + } if (flg=='M') mfilt[numflt].numvals=8; else mfilt[numflt].numvals=5; vtypes[vars].bits.is_filter=1; mfilt[numflt].index=0; if (flg=='M') { - mfilt[numflt].numvals|=0x80; + mfilt[numflt].numvals|=OR_FILT_MASK; } vtypes[vars].index=numflt; numflt++; @@ -587,9 +616,13 @@ char *script; while (*op==' ') op++; if (isdigit(*op)) { // lenght define follows - uint8_t flen=atoi(op); - mfilt[numflt-1].numvals&=0x80; - mfilt[numflt-1].numvals|=flen&0x7f; + uint16_t flen=atoi(op); + if (flen>MAX_ARRAY_SIZE) { + // limit array size + flen=MAX_ARRAY_SIZE; + } + mfilt[numflt-1].numvals&=OR_FILT_MASK; + mfilt[numflt-1].numvals|=flen&AND_FILT_MASK; } } @@ -635,11 +668,11 @@ char *script; uint16_t fsize=0; for (count=0; countnumvals=mfilt[count].numvals; - mp+=sizeof(struct M_FILT)+((mfilt[count].numvals&0x7f)-1)*sizeof(float); + mp+=sizeof(struct M_FILT)+((mfilt[count].numvals&AND_FILT_MASK)-1)*sizeof(float); } glob_script_mem.numvars=vars; @@ -760,12 +793,21 @@ char *script; for (uint8_t count=0; countnumvals&0x7f; + *len=mflp->numvals&AND_FILT_MASK; if (ipos) *ipos=mflp->index; return mflp->rbuff; } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + mp+=sizeof(struct M_FILT)+((mflp->numvals&AND_FILT_MASK)-1)*sizeof(float); } return 0; } -float Get_MFVal(uint8_t index,uint8_t bind) { +float Get_MFVal(uint8_t index,int16_t bind) { uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; for (uint8_t count=0; countnumvals&0x7f; + uint16_t maxind=mflp->numvals&AND_FILT_MASK; if (!bind) { return mflp->index; } + if (bind<0) { + return maxind; + } if (bind<1 || bind>maxind) bind=maxind; return mflp->rbuff[bind-1]; } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + mp+=sizeof(struct M_FILT)+((mflp->numvals&AND_FILT_MASK)-1)*sizeof(float); } return 0; } -void Set_MFVal(uint8_t index,uint8_t bind,float val) { +void Set_MFVal(uint8_t index,uint16_t bind,float val) { uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; for (uint8_t count=0; countnumvals&0x7f; + uint16_t maxind=mflp->numvals&AND_FILT_MASK; if (!bind) { mflp->index=val; } else { @@ -1022,7 +1067,7 @@ void Set_MFVal(uint8_t index,uint8_t bind,float val) { } return; } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + mp+=sizeof(struct M_FILT)+((mflp->numvals&AND_FILT_MASK)-1)*sizeof(float); } } @@ -1032,15 +1077,15 @@ float Get_MFilter(uint8_t index) { for (uint8_t count=0; countnumvals&0x80) { + if (mflp->numvals&OR_FILT_MASK) { // moving average - return mflp->maccu/(mflp->numvals&0x7f); + return mflp->maccu/(mflp->numvals&AND_FILT_MASK); } else { // median, sort array indices return median_array(mflp->rbuff,mflp->numvals); } } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + mp+=sizeof(struct M_FILT)+((mflp->numvals&AND_FILT_MASK)-1)*sizeof(float); } return 0; } @@ -1050,13 +1095,13 @@ void Set_MFilter(uint8_t index, float invar) { for (uint8_t count=0; countnumvals&0x80) { + if (mflp->numvals&OR_FILT_MASK) { // moving average mflp->maccu-=mflp->rbuff[mflp->index]; mflp->maccu+=invar; mflp->rbuff[mflp->index]=invar; mflp->index++; - if (mflp->index>=(mflp->numvals&0x7f)) mflp->index=0; + if (mflp->index>=(mflp->numvals&AND_FILT_MASK)) mflp->index=0; } else { // median mflp->rbuff[mflp->index]=invar; @@ -1065,7 +1110,7 @@ void Set_MFilter(uint8_t index, float invar) { } break; } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + mp+=sizeof(struct M_FILT)+((mflp->numvals&AND_FILT_MASK)-1)*sizeof(float); } } @@ -2140,7 +2185,7 @@ chknext: } } else { if (index>glob_script_mem.si_num) { - fvar=glob_script_mem.si_num; + index=glob_script_mem.si_num; } strlcpy(str,glob_script_mem.last_index_string+(index*glob_script_mem.max_ssize),glob_script_mem.max_ssize); } @@ -2691,7 +2736,7 @@ chknext: if (index<1 || index>MAXBUTTONS) index=1; index--; if (buttons[index]) { - fvar=buttons[index]->vpower&0x80; + fvar=buttons[index]->vpower.on_off; } else { fvar=-1; } @@ -2807,7 +2852,7 @@ chknext: #if defined(USE_TTGO_WATCH) && defined(USE_FT5206) if (!strncmp(vname,"wtch(",5)) { lp=GetNumericResult(lp+5,OPER_EQU,&fvar,0); - fvar=FT5206_touched(fvar); + fvar=Touch_Status(fvar); lp++; len=0; goto exit; @@ -3430,7 +3475,7 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { int16_t Run_script_sub(const char *type, int8_t tlen, JsonObject *jo) { uint8_t vtype=0,sindex,xflg,floop=0,globvindex,fromscriptcmd=0; char *lp_next; - int8_t globaindex,saindex; + int16_t globaindex,saindex; struct T_INDEX ind; uint8_t operand,lastop,numeric=1,if_state[IF_NEST],if_exe[IF_NEST],if_result[IF_NEST],and_or,ifstck=0; if_state[ifstck]=0; @@ -3762,7 +3807,7 @@ int16_t Run_script_sub(const char *type, int8_t tlen, JsonObject *jo) { if ((vtype&STYPE)==0) { // numeric result if (glob_script_mem.type[ind.index].bits.is_filter) { - uint8_t len=0; + uint16_t len=0; float *fa=Get_MFAddr(index,&len,0); //Serial.printf(">> 2 %d\n",(uint32_t)*fa); if (fa && len) ws2812_set_array(fa,len,fvar); @@ -4175,12 +4220,26 @@ void Scripter_save_pvars(void) { for (uint8_t count=0; countPMEM_SIZE) { - vtp[count].bits.is_permanent=0; - return; + if (vtp[count].bits.is_filter) { + // save array + uint16_t len=0; + float *fa=Get_MFAddr(index,&len,0); + mlen+=sizeof(float)*len; + if (mlen>glob_script_mem.script_pram_size) { + vtp[count].bits.is_permanent=0; + return; + } + while (len--) { + *fp++=*fa++; + } + } else { + mlen+=sizeof(float); + if (mlen>glob_script_mem.script_pram_size) { + vtp[count].bits.is_permanent=0; + return; + } + *fp++=glob_script_mem.fvars[index]; } - *fp++=glob_script_mem.fvars[index]; } } char *cp=(char*)fp; @@ -4190,7 +4249,7 @@ void Scripter_save_pvars(void) { char *sp=glob_script_mem.glob_snp+(index*glob_script_mem.max_ssize); uint8_t slen=strlen(sp); mlen+=slen+1; - if (mlen>PMEM_SIZE) { + if (mlen>glob_script_mem.script_pram_size) { vtp[count].bits.is_permanent=0; return; } @@ -6013,6 +6072,9 @@ const char SCRIPT_MSG_GOPT4[] PROGMEM = const char SCRIPT_MSG_GOPT5[] PROGMEM = "new Date(0,1,1,%d,%d)"; +const char SCRIPT_MSG_GOPT6[] PROGMEM = +"title:'%s',isStacked:false,vAxis:{viewWindow:{min:%d,max:%d}}%s"; + const char SCRIPT_MSG_GTE1[] PROGMEM = "'%s'"; #define GLIBS_MAIN 1<<0 @@ -6022,11 +6084,11 @@ const char SCRIPT_MSG_GTE1[] PROGMEM = "'%s'"; #define MAX_GARRAY 4 -char *gc_get_arrays(char *lp, float **arrays, uint8_t *ranum, uint8_t *rentries, uint8_t *ipos) { +char *gc_get_arrays(char *lp, float **arrays, uint8_t *ranum, uint16_t *rentries, uint16_t *ipos) { struct T_INDEX ind; uint8_t vtype; -uint8 entries=0; -uint8_t cipos=0; +uint16 entries=0; +uint16_t cipos=0; uint8_t anum=0; while (anum> 2 %d\n",(uint32_t)*fa); + //Serial.printf(">> 2 %d\n",len); if (fa && len>=entries) { if (!entries) { entries = len; @@ -6295,12 +6357,12 @@ void ScriptWebShow(char mc) { } else { if (mc=='w') { - WSContentSend_PD(PSTR("%s"),tmp); + WSContentSend_PD(PSTR("%s"),lin); } else { if (optflg) { - WSContentSend_PD(PSTR("
%s
"),tmp); + WSContentSend_PD(PSTR("
%s
"),lin); } else { - WSContentSend_PD(PSTR("{s}%s{e}"),tmp); + WSContentSend_PD(PSTR("{s}%s{e}"),lin); } } } @@ -6388,8 +6450,8 @@ exgc: float *arrays[MAX_GARRAY]; uint8_t anum=0; - uint8 entries=0; - uint8 ipos=0; + uint16_t entries=0; + uint16_t ipos=0; lp=gc_get_arrays(lp, &arrays[0], &anum, &entries, &ipos); if (anum>nanum) { @@ -6434,10 +6496,19 @@ exgc: lp=GetStringResult(lp,OPER_EQU,label,0); SCRIPT_SKIP_SPACES - int8_t todflg=-1; + int16_t divflg=1; + int16_t todflg=-1; if (!strncmp(label,"cnt",3)) { todflg=atoi(&label[3]); if (todflg>=entries) todflg=entries-1; + } else { + uint16 segments=1; + for (uint32_t cnt=0; cnt -#include Renderer *renderer; @@ -757,7 +756,28 @@ void DisplayText(void) #ifdef USE_TOUCH_BUTTONS case 'b': - { int16_t num,gxp,gyp,gxs,gys,outline,fill,textcolor,textsize; + { int16_t num,gxp,gyp,gxs,gys,outline,fill,textcolor,textsize; uint8_t dflg=1; + if (*cp=='e' || *cp=='d') { + // enable disable + uint8_t dis=0; + if (*cp=='d') dis=1; + cp++; + var=atoiv(cp,&num); + num=num%MAXBUTTONS; + cp+=var; + if (buttons[num]) { + buttons[num]->vpower.disable=dis; + if (!dis) { + if (buttons[num]->vpower.is_virtual) buttons[num]->xdrawButton(buttons[num]->vpower.on_off); + else buttons[num]->xdrawButton(bitRead(power,num)); + } + } + break; + } + if (*cp=='-') { + cp++; + dflg=0; + } var=atoiv(cp,&num); cp+=var; cp++; @@ -797,16 +817,23 @@ void DisplayText(void) if (renderer) { buttons[num]= new VButton(); if (buttons[num]) { - buttons[num]->vpower=bflags; buttons[num]->initButtonUL(renderer,gxp,gyp,gxs,gys,renderer->GetColorFromIndex(outline),\ - renderer->GetColorFromIndex(fill),renderer->GetColorFromIndex(textcolor),bbuff,textsize); + renderer->GetColorFromIndex(fill),renderer->GetColorFromIndex(textcolor),bbuff,textsize); if (!bflags) { // power button - buttons[num]->xdrawButton(bitRead(power,num)); + if (dflg) buttons[num]->xdrawButton(bitRead(power,num)); + buttons[num]->vpower.is_virtual=0; } else { // virtual button - buttons[num]->vpower&=0x7f; - buttons[num]->xdrawButton(buttons[num]->vpower&0x80); + buttons[num]->vpower.is_virtual=1; + if (bflags==2) { + // push + buttons[num]->vpower.is_pushbutton=1; + } else { + // toggle + buttons[num]->vpower.is_pushbutton=0; + } + if (dflg) buttons[num]->xdrawButton(buttons[num]->vpower.on_off); } } } @@ -2019,7 +2046,146 @@ void AddValue(uint8_t num,float fval) { } } } -#endif +#endif // USE_GRAPH + +#ifdef USE_FT5206 + +// touch panel controller +#undef FT5206_address +#define FT5206_address 0x38 + +#include +FT5206_Class *touchp; +TP_Point pLoc; + + +extern VButton *buttons[]; +bool FT5206_found; + +bool Touch_Init(TwoWire &i2c) { + FT5206_found = false; + touchp = new FT5206_Class(); + if (touchp->begin(i2c, FT5206_address)) { + I2cSetActiveFound(FT5206_address, "FT5206"); + FT5206_found = true; + } + return FT5206_found; +} + +uint32_t Touch_Status(uint32_t sel) { + if (FT5206_found) { + switch (sel) { + case 0: + return touchp->touched(); + case 1: + return pLoc.x; + case 2: + return pLoc.y; + } + return 0; + } else { + return 0; + } +} + +#ifdef USE_TOUCH_BUTTONS +void Touch_MQTT(uint8_t index, const char *cp) { + ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, buttons[index]->vpower.on_off); + MqttPublishTeleSensor(); +} + +void Touch_RDW_BUTT(uint32_t count, uint32_t pwr) { + buttons[count]->xdrawButton(pwr); + if (pwr) buttons[count]->vpower.on_off = 1; + else buttons[count]->vpower.on_off = 0; +} + +// check digitizer hit +void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) { +uint16_t temp; +uint8_t rbutt=0; +uint8_t vbutt=0; + + + if (touchp->touched()) { + // did find a hit + pLoc = touchp->getPoint(0); + + if (renderer) { + + rotconvert(&pLoc.x, &pLoc.y); + + //AddLog_P2(LOG_LEVEL_INFO, PSTR("touch %d - %d"), pLoc.x, pLoc.y); + // now must compare with defined buttons + for (uint8_t count=0; countvpower.disable) { + if (buttons[count]->contains(pLoc.x, pLoc.y)) { + // did hit + buttons[count]->press(true); + if (buttons[count]->justPressed()) { + if (!buttons[count]->vpower.is_virtual) { + uint8_t pwr=bitRead(power, rbutt); + if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { + ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); + Touch_RDW_BUTT(count, !pwr); + } + } else { + // virtual button + const char *cp; + if (!buttons[count]->vpower.is_pushbutton) { + // toggle button + buttons[count]->vpower.on_off ^= 1; + cp="TBT"; + } else { + // push button + buttons[count]->vpower.on_off = 1; + cp="PBT"; + } + buttons[count]->xdrawButton(buttons[count]->vpower.on_off); + Touch_MQTT(count,cp); + } + } + } + if (!buttons[count]->vpower.is_virtual) { + rbutt++; + } else { + vbutt++; + } + } + } + } + } else { + // no hit + for (uint8_t count=0; countpress(false); + if (buttons[count]->justReleased()) { + if (buttons[count]->vpower.is_virtual) { + if (buttons[count]->vpower.is_pushbutton) { + // push button + buttons[count]->vpower.on_off = 0; + Touch_MQTT(count,"PBT"); + buttons[count]->xdrawButton(buttons[count]->vpower.on_off); + } + } + } + if (!buttons[count]->vpower.is_virtual) { + // check if power button stage changed + uint8_t pwr = bitRead(power, rbutt); + uint8_t vpwr = buttons[count]->vpower.on_off; + if (pwr != vpwr) { + Touch_RDW_BUTT(count, pwr); + } + rbutt++; + } + } + } + pLoc.x = 0; + pLoc.y = 0; + } +} +#endif // USE_TOUCH_BUTTONS +#endif // USE_FT5206 /*********************************************************************************************\ * Interface diff --git a/tasmota/xdsp_08_ILI9488.ino b/tasmota/xdsp_08_ILI9488.ino index e49e7bffe..b1e738fd4 100644 --- a/tasmota/xdsp_08_ILI9488.ino +++ b/tasmota/xdsp_08_ILI9488.ino @@ -27,18 +27,12 @@ #define COLORED 1 #define UNCOLORED 0 -// touch panel controller -#define FT6236_address 0x38 - // using font 8 is opional (num=3) // very badly readable, but may be useful for graphs #define USE_TINY_FONT #include -#include - -TouchLocation ili9488_pLoc; uint8_t ili9488_ctouch_counter = 0; // currently fixed @@ -47,13 +41,7 @@ uint8_t ili9488_ctouch_counter = 0; extern uint8_t *buffer; extern uint8_t color_type; ILI9488 *ili9488; - -#ifdef USE_TOUCH_BUTTONS -extern VButton *buttons[]; -#endif - extern const uint16_t picture[]; -uint8_t FT6236_found; /*********************************************************************************************/ @@ -126,30 +114,52 @@ void ILI9488_InitDriver() #endif color_type = COLOR_COLOR; - // start digitizer with fixed adress - - if (I2cEnabled(XI2C_38) && I2cSetDevice(FT6236_address)) { - FT6236begin(FT6236_address); - FT6236_found=1; - I2cSetActiveFound(FT6236_address, "FT6236"); - } else { - FT6236_found=0; - } - + // start digitizer +#ifdef USE_FT5206 + Touch_Init(Wire); +#endif } } +#ifdef USE_FT5206 #ifdef USE_TOUCH_BUTTONS -void ILI9488_MQTT(uint8_t count,const char *cp) { - ResponseTime_P(PSTR(",\"RA8876\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7); - MqttPublishTeleSensor(); + +void ILI9488_RotConvert(int16_t *x, int16_t *y) { +int16_t temp; + if (renderer) { + uint8_t rot=renderer->getRotation(); + switch (rot) { + case 0: + temp=*y; + *y=renderer->height()-*x; + *x=temp; + break; + case 1: + break; + case 2: + break; + case 3: + temp=*y; + *y=*x; + *x=renderer->width()-temp; + break; + } + } } -void ILI9488_RDW_BUTT(uint32_t count,uint32_t pwr) { - buttons[count]->xdrawButton(pwr); - if (pwr) buttons[count]->vpower|=0x80; - else buttons[count]->vpower&=0x7f; +// check digitizer hit +void ILI9488_CheckTouch(void) { + ili9488_ctouch_counter++; + if (2 == ili9488_ctouch_counter) { + // every 100 ms should be enough + ili9488_ctouch_counter = 0; + Touch_Check(ILI9488_RotConvert); + } } +#endif // USE_TOUCH_BUTTONS +#endif // USE_FT5206 + +/* // check digitizer hit void FT6236Check() { uint16_t temp; @@ -181,12 +191,11 @@ if (2 == ili9488_ctouch_counter) { // now must compare with defined buttons for (uint8_t count=0; countvpower&0x7f; if (buttons[count]->contains(ili9488_pLoc.x,ili9488_pLoc.y)) { // did hit buttons[count]->press(true); if (buttons[count]->justPressed()) { - if (!bflags) { + if (!buttons[count]->vpower.is_virtual) { uint8_t pwr=bitRead(power,rbutt); if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); @@ -195,21 +204,21 @@ if (2 == ili9488_ctouch_counter) { } else { // virtual button const char *cp; - if (bflags==1) { + if (!buttons[count]->vpower.is_pushbutton) { // toggle button - buttons[count]->vpower^=0x80; + buttons[count]->vpower.on_off^=1; cp="TBT"; } else { // push button - buttons[count]->vpower|=0x80; + buttons[count]->vpower.on_off=1; cp="PBT"; } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); + buttons[count]->xdrawButton(buttons[count]->vpower.on_off); ILI9488_MQTT(count,cp); } } } - if (!bflags) { + if (!buttons[count]->vpower.is_virtual) { rbutt++; } else { vbutt++; @@ -221,23 +230,21 @@ if (2 == ili9488_ctouch_counter) { // no hit for (uint8_t count=0; countvpower&0x7f; buttons[count]->press(false); if (buttons[count]->justReleased()) { - uint8_t bflags=buttons[count]->vpower&0x7f; - if (bflags>0) { - if (bflags>1) { + if (buttons[count]->vpower.is_virtual) { + if (buttons[count]->vpower.is_pushbutton) { // push button - buttons[count]->vpower&=0x7f; + buttons[count]->vpower.on_off=0; ILI9488_MQTT(count,"PBT"); } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); + buttons[count]->xdrawButton(buttons[count]->vpower.on_off); } } - if (!bflags) { + if (!buttons[count]->vpower.is_virtual) { // check if power button stage changed uint8_t pwr=bitRead(power,rbutt); - uint8_t vpwr=(buttons[count]->vpower&0x80)>>7; + uint8_t vpwr=buttons[count]->vpower.on_off; if (pwr!=vpwr) { ILI9488_RDW_BUTT(count,pwr); } @@ -251,6 +258,8 @@ if (2 == ili9488_ctouch_counter) { } } #endif // USE_TOUCH_BUTTONS +*/ + /*********************************************************************************************/ /*********************************************************************************************\ * Interface @@ -270,7 +279,9 @@ bool Xdsp08(uint8_t function) break; case FUNC_DISPLAY_EVERY_50_MSECOND: #ifdef USE_TOUCH_BUTTONS - if (FT6236_found) FT6236Check(); + if (FT5206_found) { + ILI9488_CheckTouch(); + } #endif break; } diff --git a/tasmota/xdsp_10_RA8876.ino b/tasmota/xdsp_10_RA8876.ino index aa8e82f4d..47b909b4c 100644 --- a/tasmota/xdsp_10_RA8876.ino +++ b/tasmota/xdsp_10_RA8876.ino @@ -27,29 +27,17 @@ #define COLORED 1 #define UNCOLORED 0 -// touch panel controller -#define FT5316_address 0x38 - // using font 8 is opional (num=3) // very badly readable, but may be useful for graphs #define USE_TINY_FONT #include -#include -TouchLocation ra8876_pLoc; uint8_t ra8876_ctouch_counter = 0; - -#ifdef USE_TOUCH_BUTTONS -extern VButton *buttons[]; -#endif - extern uint8_t *buffer; extern uint8_t color_type; RA8876 *ra8876; -uint8_t FT5316_found; - /*********************************************************************************************/ void RA8876_InitDriver() { @@ -114,147 +102,41 @@ void RA8876_InitDriver() #endif color_type = COLOR_COLOR; - if (I2cEnabled(XI2C_39) && I2cSetDevice(FT5316_address)) { - FT6236begin(FT5316_address); - FT5316_found=1; - I2cSetActiveFound(FT5316_address, "FT5316"); - } else { - FT5316_found=0; - } +#ifdef USE_FT5206 + Touch_Init(Wire); +#endif } } -#ifdef USE_TOUCH_BUTTONS -void RA8876_MQTT(uint8_t count,const char *cp) { - ResponseTime_P(PSTR(",\"RA8876\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7); - MqttPublishTeleSensor(); -} -void RA8876_RDW_BUTT(uint32_t count,uint32_t pwr) { - buttons[count]->xdrawButton(pwr); - if (pwr) buttons[count]->vpower|=0x80; - else buttons[count]->vpower&=0x7f; +#ifdef USE_FT5206 +#ifdef USE_TOUCH_BUTTONS + +// no rotation support +void RA8876_RotConvert(int16_t *x, int16_t *y) { +int16_t temp; + if (renderer) { + *x=*x*renderer->width()/800; + *y=*y*renderer->height()/480; + + *x = renderer->width() - *x; + *y = renderer->height() - *y; + } } // check digitizer hit -void FT5316Check() { -uint16_t temp; -uint8_t rbutt=0,vbutt=0; -ra8876_ctouch_counter++; -if (2 == ra8876_ctouch_counter) { - // every 100 ms should be enough - ra8876_ctouch_counter=0; - // panel has 800x480 - if (FT6236readTouchLocation(&ra8876_pLoc,1)) { - ra8876_pLoc.x=ra8876_pLoc.x*RA8876_TFTWIDTH/800; - ra8876_pLoc.y=ra8876_pLoc.y*RA8876_TFTHEIGHT/480; - // did find a hit - - if (renderer) { - - // rotation not supported - ra8876_pLoc.x=RA8876_TFTWIDTH-ra8876_pLoc.x; - ra8876_pLoc.y=RA8876_TFTHEIGHT-ra8876_pLoc.y; - - /* - uint8_t rot=renderer->getRotation(); - switch (rot) { - case 0: - //temp=pLoc.y; - pLoc.x=renderer->width()-pLoc.x; - pLoc.y=renderer->height()-pLoc.y; - //pLoc.x=temp; - break; - case 1: - break; - case 2: - break; - case 3: - temp=pLoc.y; - pLoc.y=pLoc.x; - pLoc.x=renderer->width()-temp; - break; - } - */ - //AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %d,%d"),ra8876_pLoc.x,ra8876_pLoc.y); - - - //Serial.printf("loc x: %d , loc y: %d\n",pLoc.x,pLoc.y); - - // now must compare with defined buttons - for (uint8_t count=0; countvpower&0x7f; - if (buttons[count]->contains(ra8876_pLoc.x,ra8876_pLoc.y)) { - // did hit - buttons[count]->press(true); - if (buttons[count]->justPressed()) { - if (!bflags) { - // real button - uint8_t pwr=bitRead(power,rbutt); - if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { - ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); - RA8876_RDW_BUTT(count,!pwr); - } - } else { - // virtual button - const char *cp; - if (bflags==1) { - // toggle button - buttons[count]->vpower^=0x80; - cp="TBT"; - } else { - // push button - buttons[count]->vpower|=0x80; - cp="PBT"; - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - RA8876_MQTT(count,cp); - } - } - } - if (!bflags) { - rbutt++; - } else { - vbutt++; - } - } - } - } - } else { - // no hit - for (uint8_t count=0; countvpower&0x7f; - buttons[count]->press(false); - if (buttons[count]->justReleased()) { - if (bflags>0) { - if (bflags>1) { - // push button - buttons[count]->vpower&=0x7f; - RA8876_MQTT(count,"PBT"); - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - } - } - if (!bflags) { - // check if power button stage changed - uint8_t pwr=bitRead(power,rbutt); - uint8_t vpwr=(buttons[count]->vpower&0x80)>>7; - if (pwr!=vpwr) { - RA8876_RDW_BUTT(count,pwr); - } - rbutt++; - } - } - } - ra8876_pLoc.x=0; - ra8876_pLoc.y=0; +void RA8876_CheckTouch(void) { + ra8876_ctouch_counter++; + if (2 == ra8876_ctouch_counter) { + // every 100 ms should be enough + ra8876_ctouch_counter = 0; + Touch_Check(RA8876_RotConvert); } } -} -#endif // USE_TOUCH_BUTTONS +#endif // USE_TOUCH_BUTTONS +#endif // USE_FT5206 + /* void testall() { ra8876->clearScreen(0); @@ -452,8 +334,8 @@ bool Xdsp10(uint8_t function) result = true; break; case FUNC_DISPLAY_EVERY_50_MSECOND: -#ifdef USE_TOUCH_BUTTONS - if (FT5316_found) FT5316Check(); +#ifdef USE_FT5206 + if (FT5206_found) RA8876_CheckTouch(); #endif break; } diff --git a/tasmota/xdsp_12_ST7789.ino b/tasmota/xdsp_12_ST7789.ino index 3b2ef8d82..d31c55fa4 100644 --- a/tasmota/xdsp_12_ST7789.ino +++ b/tasmota/xdsp_12_ST7789.ino @@ -17,6 +17,7 @@ along with this program. If not, see . */ +//#ifdef USE_SPI #ifdef USE_SPI #ifdef USE_DISPLAY #ifdef USE_DISPLAY_ST7789 @@ -50,12 +51,6 @@ extern uint8_t color_type; Arduino_ST7789 *st7789; #ifdef USE_FT5206 -#ifdef USE_TOUCH_BUTTONS -extern VButton *buttons[]; -#endif -FT5206_Class *touchp; -uint8_t FT5206_found; -TP_Point st7789_pLoc; uint8_t st7789_ctouch_counter = 0; #endif // USE_FT5206 @@ -142,155 +137,51 @@ void ST7789_InitDriver() #define SDA_2 23 #define SCL_2 32 Wire1.begin(SDA_2, SCL_2, 400000); - touchp = new FT5206_Class(); - if (touchp->begin(Wire1, FT5206_address)) { - FT5206_found=1; - //I2cSetDevice(FT5206_address); - I2cSetActiveFound(FT5206_address, "FT5206"); - } else { - FT5206_found=0; - } + Touch_Init(Wire1); #endif // USE_FT5206 #endif // ESP32 } } - #ifdef ESP32 #ifdef USE_FT5206 #ifdef USE_TOUCH_BUTTONS -void ST7789_MQTT(uint8_t count,const char *cp) { - ResponseTime_P(PSTR(",\"ST7789\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7); - MqttPublishTeleSensor(); -} -uint32_t FT5206_touched(uint32_t sel) { - if (touchp) { - switch (sel) { +void ST7789_RotConvert(int16_t *x, int16_t *y) { +int16_t temp; + if (renderer) { + uint8_t rot=renderer->getRotation(); + switch (rot) { case 0: - return touchp->touched(); + break; case 1: - return st7789_pLoc.x; + temp=*y; + *y=renderer->height()-*x; + *x=temp; + break; case 2: - return st7789_pLoc.y; + *x=renderer->width()-*x; + *y=renderer->height()-*y; + break; + case 3: + temp=*y; + *y=*x; + *x=renderer->width()-temp; + break; } - return 0; - } else { - return 0; } } -void ST7789_RDW_BUTT(uint32_t count,uint32_t pwr) { - buttons[count]->xdrawButton(pwr); - if (pwr) buttons[count]->vpower|=0x80; - else buttons[count]->vpower&=0x7f; -} // check digitizer hit -void FT5206Check() { -uint16_t temp; -uint8_t rbutt=0,vbutt=0; +void ST7789_CheckTouch() { st7789_ctouch_counter++; -if (2 == st7789_ctouch_counter) { - // every 100 ms should be enough - st7789_ctouch_counter=0; - - if (touchp->touched()) { - // did find a hit - st7789_pLoc = touchp->getPoint(0); - if (renderer) { - uint8_t rot=renderer->getRotation(); - switch (rot) { - case 0: - break; - case 1: - temp=st7789_pLoc.y; - st7789_pLoc.y=renderer->height()-st7789_pLoc.x; - st7789_pLoc.x=temp; - break; - case 2: - st7789_pLoc.x=renderer->width()-st7789_pLoc.x; - st7789_pLoc.y=renderer->height()-st7789_pLoc.y; - break; - case 3: - temp=st7789_pLoc.y; - st7789_pLoc.y=st7789_pLoc.x; - st7789_pLoc.x=renderer->width()-temp; - break; - } - //AddLog_P2(LOG_LEVEL_INFO, PSTR("touch %d - %d"), st7789_pLoc.x, st7789_pLoc.y); - // now must compare with defined buttons - for (uint8_t count=0; countvpower&0x7f; - if (buttons[count]->contains(st7789_pLoc.x,st7789_pLoc.y)) { - // did hit - buttons[count]->press(true); - if (buttons[count]->justPressed()) { - if (!bflags) { - uint8_t pwr=bitRead(power,rbutt); - if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { - ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); - ST7789_RDW_BUTT(count,!pwr); - } - } else { - // virtual button - const char *cp; - if (bflags==1) { - // toggle button - buttons[count]->vpower^=0x80; - cp="TBT"; - } else { - // push button - buttons[count]->vpower|=0x80; - cp="PBT"; - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - ST7789_MQTT(count,cp); - } - } - } - if (!bflags) { - rbutt++; - } else { - vbutt++; - } - } - } - } - } else { - // no hit - for (uint8_t count=0; countvpower&0x7f; - buttons[count]->press(false); - if (buttons[count]->justReleased()) { - uint8_t bflags=buttons[count]->vpower&0x7f; - if (bflags>0) { - if (bflags>1) { - // push button - buttons[count]->vpower&=0x7f; - ST7789_MQTT(count,"PBT"); - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - } - } - if (!bflags) { - // check if power button stage changed - uint8_t pwr=bitRead(power,rbutt); - uint8_t vpwr=(buttons[count]->vpower&0x80)>>7; - if (pwr!=vpwr) { - ST7789_RDW_BUTT(count,pwr); - } - rbutt++; - } - } - } - st7789_pLoc.x=0; - st7789_pLoc.y=0; + if (2 == st7789_ctouch_counter) { + // every 100 ms should be enough + st7789_ctouch_counter = 0; + Touch_Check(ST7789_RotConvert); } } -} #endif // USE_TOUCH_BUTTONS #endif // USE_FT5206 #endif // ESP32 @@ -317,7 +208,7 @@ bool Xdsp12(uint8_t function) #ifdef USE_FT5206 #ifdef USE_TOUCH_BUTTONS if (FT5206_found) { - FT5206Check(); + ST7789_CheckTouch(); } #endif #endif // USE_FT5206 From 1f4b2f7ae5247bf17eda46537394e95ecd8a90b2 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 3 Sep 2020 12:27:37 +0200 Subject: [PATCH 08/38] remove obsolete lib --- lib/FT6236-gemu-1.0/FT6236.cpp | 159 --------------------------------- lib/FT6236-gemu-1.0/FT6236.h | 28 ------ 2 files changed, 187 deletions(-) delete mode 100644 lib/FT6236-gemu-1.0/FT6236.cpp delete mode 100644 lib/FT6236-gemu-1.0/FT6236.h diff --git a/lib/FT6236-gemu-1.0/FT6236.cpp b/lib/FT6236-gemu-1.0/FT6236.cpp deleted file mode 100644 index 6397190fb..000000000 --- a/lib/FT6236-gemu-1.0/FT6236.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include - -/* - * This is a static library so we need to make sure we process stuff as quick as possible - * as we do not want it to interfere with the RTOS by delaying routines unnecessarily. - * So, no delay()'s etc and opto the code as much as possible. - * ^^^ Need to be on TODO list to go through and make sure everything is as opto as - * possible - */ - -uint8_t FT6236buf[FT6236_BUFFER_SIZE]; -uint8_t FT6236_i2c_addr = 0x38; -uint8_t lenLibVersion = 0; -uint8_t firmwareId = 0; - -struct tbuttonregister { - uint16_t BUTTONID; - uint16_t xmin; - uint16_t xmax; - uint16_t ymin; - uint16_t ymax; -} buttonregister[FT6236_MAX_BUTTONS]; // we're limiting to 16 buttons for now - can reduce or increase later as needed. - -uint8_t buttoncount = 0; - -void FT6236flushbuttonregister(void) { - uint16_t bid; - for (bid=0;bid 0) { - uint16_t x = tl[0].x; - uint16_t y = tl[0].y; - for (bid=0;bid= buttonregister[bid].xmin) { - if (x <= buttonregister[bid].xmax) { - if (y >= buttonregister[bid].ymin) { - if (y <= buttonregister[bid].ymax) { - return buttonregister[bid].BUTTONID; - } - } - } - } - } - } - return 0; -} - -void FT6236begin(uint8_t i2c_addr) { - FT6236_i2c_addr=i2c_addr; - Wire.begin(); - FT6236writeTouchRegister(0,FT6236_MODE_NORMAL); - lenLibVersion = FT6236readTouchAddr(0x0a1, FT6236buf, 2 ); - firmwareId = FT6236readTouchRegister( 0xa6 ); -} - -void FT6236writeTouchRegister(uint8_t reg, uint8_t val) -{ - Wire.beginTransmission(FT6236_i2c_addr); - Wire.write(reg); // register 0 - Wire.write(val); // value - Wire.endTransmission(); -} - -uint8_t FT6236readTouchRegister(uint8_t reg) -{ - Wire.beginTransmission(FT6236_i2c_addr); - Wire.write(reg); // register 0 - uint8_t retVal = Wire.endTransmission(); - uint8_t returned = Wire.requestFrom(FT6236_i2c_addr,uint8_t(1)); // request 6 uint8_ts from slave device #2 - if (Wire.available()) - { - retVal = Wire.read(); - } - return retVal; -} - -uint8_t FT6236readTouchAddr( uint8_t regAddr, uint8_t * pBuf, uint8_t len ) -{ - Wire.beginTransmission(FT6236_i2c_addr); - Wire.write( regAddr ); // register 0 - uint8_t retVal = Wire.endTransmission(); - uint8_t returned = Wire.requestFrom(FT6236_i2c_addr, len); // request 1 bytes from slave device #2 - uint8_t i; - for (i = 0; (i < len) && Wire.available(); i++) { - pBuf[i] = Wire.read(); - } - return i; -} - -uint8_t FT6236readTouchLocation( TouchLocation * pLoc, uint8_t num ) -{ - uint8_t retVal = 0; - uint8_t i; - uint8_t k; - do - { - if (!pLoc) break; // must have a buffer - if (!num) break; // must be able to take at least one - uint8_t status = FT6236readTouchRegister(2); - static uint8_t tbuf[40]; - if ((status & 0x0f) == 0) break; // no points detected - uint8_t hitPoints = status & 0x0f; - FT6236readTouchAddr( 0x03, tbuf, hitPoints*6); - for (k=0,i = 0; (i < hitPoints*6)&&(k < num); k++, i += 6) { - pLoc[k].x = (tbuf[i+0] & 0x0f) << 8 | tbuf[i+1]; - pLoc[k].y = (tbuf[i+2] & 0x0f) << 8 | tbuf[i+3]; - } - retVal = k; - } while (0); - return retVal; -} - -uint32_t FT6236dist(const TouchLocation & loc) -{ - uint32_t retVal = 0; - uint32_t x = loc.x; - uint32_t y = loc.y; - retVal = x*x + y*y; - return retVal; -} - - -/* -uint32_t FT6236dist(const TouchLocation & loc1, const TouchLocation & loc2) -{ - uint32_t retVal = 0; - uint32_t x = loc1.x - loc2.x; - uint32_t y = loc1.y - loc2.y; - retVal = sqrt(x*x + y*y); - return retVal; -} -*/ - -bool FT6236sameLoc( const TouchLocation & loc, const TouchLocation & loc2 ) -{ - return FT6236dist(loc,loc2) < 50; -} diff --git a/lib/FT6236-gemu-1.0/FT6236.h b/lib/FT6236-gemu-1.0/FT6236.h deleted file mode 100644 index 601d9c67e..000000000 --- a/lib/FT6236-gemu-1.0/FT6236.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FT6236 -#define FT6236 - -#define FT6236_MODE_NORMAL 0x00 -#define FT6236_MODE_TEST 0x04 -#define FT6236_MODE_SYSTEM 0x01 - -#define FT6236_BUFFER_SIZE 0x1E // 30 bytes buffer -#define FT6236_MAX_BUTTONS 1 // 50 buttons should be enough for just about any page - -struct TouchLocation { - uint16_t y; // we swop x and y in position because we're using the screen in portrait mode - uint16_t x; -}; - -void FT6236flushbuttonregister(void); -void FT6236registerbutton(uint16_t buttonid,uint16_t xmin,uint16_t ymin,uint16_t xmax, uint16_t ymax); -uint16_t FT6236GetButtonMask(void); -void FT6236begin(uint8_t i2c_addr); -uint8_t FT6236readTouchRegister( uint8_t reg ); -uint8_t FT6236readTouchLocation( TouchLocation * pLoc, uint8_t num ); -uint8_t FT6236readTouchAddr( uint8_t regAddr, uint8_t * pBuf, uint8_t len ); -void FT6236writeTouchRegister( uint8_t reg, uint8_t val); -uint32_t FT6236dist(const TouchLocation & loc); -uint32_t FT6236dist(const TouchLocation & loc1, const TouchLocation & loc2); -bool FT6236sameLoc( const TouchLocation & loc, const TouchLocation & loc2 ); - -#endif From b67c0d129ca0e2dc86e52a1950b45f6530e048c9 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 3 Sep 2020 12:38:14 +0200 Subject: [PATCH 09/38] Update xdsp_08_ILI9488.ino --- tasmota/xdsp_08_ILI9488.ino | 100 ------------------------------------ 1 file changed, 100 deletions(-) diff --git a/tasmota/xdsp_08_ILI9488.ino b/tasmota/xdsp_08_ILI9488.ino index b1e738fd4..2e8abc434 100644 --- a/tasmota/xdsp_08_ILI9488.ino +++ b/tasmota/xdsp_08_ILI9488.ino @@ -159,106 +159,6 @@ void ILI9488_CheckTouch(void) { #endif // USE_TOUCH_BUTTONS #endif // USE_FT5206 -/* -// check digitizer hit -void FT6236Check() { -uint16_t temp; -uint8_t rbutt=0,vbutt=0; -ili9488_ctouch_counter++; -if (2 == ili9488_ctouch_counter) { - // every 100 ms should be enough - ili9488_ctouch_counter=0; - if (FT6236readTouchLocation(&ili9488_pLoc,1)) { - // did find a hit - if (renderer) { - uint8_t rot=renderer->getRotation(); - switch (rot) { - case 0: - temp=ili9488_pLoc.y; - ili9488_pLoc.y=renderer->height()-ili9488_pLoc.x; - ili9488_pLoc.x=temp; - break; - case 1: - break; - case 2: - break; - case 3: - temp=ili9488_pLoc.y; - ili9488_pLoc.y=ili9488_pLoc.x; - ili9488_pLoc.x=renderer->width()-temp; - break; - } - // now must compare with defined buttons - for (uint8_t count=0; countcontains(ili9488_pLoc.x,ili9488_pLoc.y)) { - // did hit - buttons[count]->press(true); - if (buttons[count]->justPressed()) { - if (!buttons[count]->vpower.is_virtual) { - uint8_t pwr=bitRead(power,rbutt); - if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { - ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); - ILI9488_RDW_BUTT(count,!pwr); - } - } else { - // virtual button - const char *cp; - if (!buttons[count]->vpower.is_pushbutton) { - // toggle button - buttons[count]->vpower.on_off^=1; - cp="TBT"; - } else { - // push button - buttons[count]->vpower.on_off=1; - cp="PBT"; - } - buttons[count]->xdrawButton(buttons[count]->vpower.on_off); - ILI9488_MQTT(count,cp); - } - } - } - if (!buttons[count]->vpower.is_virtual) { - rbutt++; - } else { - vbutt++; - } - } - } - } - } else { - // no hit - for (uint8_t count=0; countpress(false); - if (buttons[count]->justReleased()) { - if (buttons[count]->vpower.is_virtual) { - if (buttons[count]->vpower.is_pushbutton) { - // push button - buttons[count]->vpower.on_off=0; - ILI9488_MQTT(count,"PBT"); - } - buttons[count]->xdrawButton(buttons[count]->vpower.on_off); - } - } - if (!buttons[count]->vpower.is_virtual) { - // check if power button stage changed - uint8_t pwr=bitRead(power,rbutt); - uint8_t vpwr=buttons[count]->vpower.on_off; - if (pwr!=vpwr) { - ILI9488_RDW_BUTT(count,pwr); - } - rbutt++; - } - } - } - ili9488_pLoc.x=0; - ili9488_pLoc.y=0; - } -} -} -#endif // USE_TOUCH_BUTTONS -*/ /*********************************************************************************************/ /*********************************************************************************************\ From d49997fa0163126ded6ded3bd570dc98c1c6429c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 3 Sep 2020 14:29:08 +0200 Subject: [PATCH 10/38] Fix ESP32 TasmotaClient detection Fix ESP32 TasmotaClient detection (#9218) --- tasmota/xdrv_01_webserver.ino | 3 ++- tasmota/xdrv_31_tasmota_client.ino | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 72876ecf2..dc50e68e1 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -2781,9 +2781,10 @@ void HandleUploadLoop(void) } else #endif // USE_RF_FLASH #ifdef USE_TASMOTA_CLIENT - if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO CLIENT hex file + if (TasmotaClient_Available() && (upload.buf[0] == ':')) { // Check if this is a ARDUINO CLIENT hex file Update.end(); // End esp8266 update session Web.upload_file_type = UPL_TASMOTACLIENT; + Web.upload_error = TasmotaClient_UpdateInit(); // 0 if (Web.upload_error != 0) { return; } } else diff --git a/tasmota/xdrv_31_tasmota_client.ino b/tasmota/xdrv_31_tasmota_client.ino index 86121475c..89402b408 100644 --- a/tasmota/xdrv_31_tasmota_client.ino +++ b/tasmota/xdrv_31_tasmota_client.ino @@ -458,6 +458,10 @@ void TasmotaClient_Init(void) { } } +bool TasmotaClient_Available(void) { + return TClient.SerialEnabled; +} + void TasmotaClient_Show(void) { if ((TClient.type) && (TClientSettings.features.func_json_append)) { char buffer[100]; From f8f0f4f616a698ffb9a300718f7ba272e8f28906 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Thu, 3 Sep 2020 15:11:14 +0200 Subject: [PATCH 11/38] Reduce memory usage of BackLog --- tasmota/support_command.ino | 2 +- tasmota/tasmota.ino | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 379d15e0c..0cdba2969 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -323,7 +323,7 @@ void CmndBacklog(void) backlog.add(blcommand); } #else - backlog[backlog_index] = String(blcommand); + backlog[backlog_index] = blcommand; backlog_index++; if (backlog_index >= MAX_BACKLOG) backlog_index = 0; #endif diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index d257b6ddb..d3b3afd32 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -339,6 +339,7 @@ void BacklogLoop(void) { #else backlog_mutex = true; ExecuteCommand((char*)backlog[backlog_pointer].c_str(), SRC_BACKLOG); + backlog[backlog_pointer] = (const char*) nullptr; // force deallocation of the String internal memory backlog_pointer++; if (backlog_pointer >= MAX_BACKLOG) { backlog_pointer = 0; } backlog_mutex = false; From 423b4c0712fe399cfb305dcc0d702f0967a45df6 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 3 Sep 2020 20:31:31 +0200 Subject: [PATCH 12/38] Workaround compilation regression Workaround compilation regression (#9223) --- tasmota/tasmota.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index d3b3afd32..b8d3293da 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -60,9 +60,9 @@ #ifdef USE_DISCOVERY #include // MQTT, Webserver, Arduino OTA #endif // USE_DISCOVERY -#ifdef USE_I2C +//#ifdef USE_I2C #include // I2C support library -#endif // USE_I2C +//#endif // USE_I2C #ifdef USE_SPI #include // SPI support, TFT #endif // USE_SPI From 23a550cbff071867625d7517fc5ad2adfb761039 Mon Sep 17 00:00:00 2001 From: device111 <48546979+device111@users.noreply.github.com> Date: Thu, 3 Sep 2020 20:36:02 +0200 Subject: [PATCH 13/38] AS3935 update DE-language --- tasmota/language/de_DE.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index cf7271539..92601dc68 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -809,7 +809,7 @@ #define D_SCRIPT_UPLOAD_FILES "Upload Dateien" //xsns_67_as3935.ino -#define D_AS3935_GAIN "Rauschpegel:" +#define D_AS3935_GAIN "Umgebung:" #define D_AS3935_ENERGY "Energie:" #define D_AS3935_DISTANCE "Entfernung:" #define D_AS3935_DISTURBER "Entstörer:" From a9209fa170784e4a89059d58ca02813086465d61 Mon Sep 17 00:00:00 2001 From: device111 <48546979+device111@users.noreply.github.com> Date: Thu, 3 Sep 2020 20:54:04 +0200 Subject: [PATCH 14/38] Update de_DE.h --- tasmota/language/de_DE.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 92601dc68..272f67988 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -823,7 +823,7 @@ #define D_AS3935_NOISE "Rauschen entdeckt" #define D_AS3935_DISTDET "Störer entdeckt" #define D_AS3935_INTNOEV "Interrupt ohne Grund!" -#define D_AS3935_FLICKER "IRQ Pin flackerd!" +#define D_AS3935_FLICKER "IRQ Pin flackert!" #define D_AS3935_POWEROFF "Ausgeschaltet" #define D_AS3935_NOMESS "lausche..." #define D_AS3935_ON "On" From 1bae56eb66bbf0625ab722d283a626c0072f4574 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 3 Sep 2020 23:33:20 +0200 Subject: [PATCH 15/38] Revert "Revert "Use Tasmota Core 2.7.4.1 from PlatformIO registry"" --- platformio.ini | 2 +- platformio_override_sample.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index cac96ba03..e0ee7de7d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -125,6 +125,6 @@ build_flags = -DUSE_IR_REMOTE_FULL [core] ; *** Esp8266 Tasmota modified Arduino core based on core 2.7.4 platform = espressif8266@2.6.2 -platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.4.1/esp8266-2.7.4.1.zip +platform_packages = framework-arduinoespressif8266 @ jason2866/framework-arduinoespressif8266 build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index facbc450d..1131e7244 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -89,7 +89,7 @@ extra_scripts = ${scripts_defaults.extra_scripts} [tasmota_stage] ; *** Esp8266 core for Arduino version Tasmota stage platform = espressif8266@2.6.2 -platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.4.1/esp8266-2.7.4.1.zip +platform_packages = framework-arduinoespressif8266 @ jason2866/framework-arduinoespressif8266 build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From fe9339e5621ccddb5176cb433482547d8b540a92 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 3 Sep 2020 23:40:37 +0200 Subject: [PATCH 16/38] Update platformio.ini --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index e0ee7de7d..86f72211a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -125,6 +125,6 @@ build_flags = -DUSE_IR_REMOTE_FULL [core] ; *** Esp8266 Tasmota modified Arduino core based on core 2.7.4 platform = espressif8266@2.6.2 -platform_packages = framework-arduinoespressif8266 @ jason2866/framework-arduinoespressif8266 +platform_packages = jason2866/framework-arduinoespressif8266 build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From 8ee0b651553a7ea021450cf60eed8006284f890c Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 3 Sep 2020 23:41:16 +0200 Subject: [PATCH 17/38] Update platformio_override_sample.ini --- platformio_override_sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 1131e7244..be5d5f24f 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -89,7 +89,7 @@ extra_scripts = ${scripts_defaults.extra_scripts} [tasmota_stage] ; *** Esp8266 core for Arduino version Tasmota stage platform = espressif8266@2.6.2 -platform_packages = framework-arduinoespressif8266 @ jason2866/framework-arduinoespressif8266 +platform_packages = jason2866/framework-arduinoespressif8266 build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From 146eb6654d421c82a14b6ec2e0e3357be199eaf5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 4 Sep 2020 12:49:57 +0200 Subject: [PATCH 18/38] Refactor gui upload --- tasmota/xdrv_01_webserver.ino | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index dc50e68e1..ed15c9e12 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -2712,6 +2712,7 @@ void HandleUploadLoop(void) HTTPUpload& upload = Webserver->upload(); + // ***** Step1: Start upload file if (UPLOAD_FILE_START == upload.status) { restart_flag = 60; if (0 == upload.filename.c_str()[0]) { @@ -2752,7 +2753,10 @@ void HandleUploadLoop(void) } } Web.upload_progress_dot_count = 0; - } else if (!Web.upload_error && (UPLOAD_FILE_WRITE == upload.status)) { + } + + // ***** Step2: Write upload file + else if (!Web.upload_error && (UPLOAD_FILE_WRITE == upload.status)) { if (0 == upload.totalSize) { if (UPL_SETTINGS == Web.upload_file_type) { Web.config_block_count = 0; @@ -2803,6 +2807,7 @@ void HandleUploadLoop(void) // upload.buf[2] = 3; // Force DOUT - ESP8285 } } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "File type %d"), Web.upload_file_type); } } if (UPL_SETTINGS == Web.upload_file_type) { @@ -2874,7 +2879,10 @@ void HandleUploadLoop(void) if (!(Web.upload_progress_dot_count % 80)) { Serial.println(); } } } - } else if(!Web.upload_error && (UPLOAD_FILE_END == upload.status)) { + } + + // ***** Step3: Finish upload file + else if(!Web.upload_error && (UPLOAD_FILE_END == upload.status)) { if (_serialoutput && (Web.upload_progress_dot_count % 80)) { Serial.println(); } @@ -2950,9 +2958,12 @@ void HandleUploadLoop(void) } } if (!Web.upload_error) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes. " D_RESTARTING), upload.totalSize); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes"), upload.totalSize); } - } else if (UPLOAD_FILE_ABORTED == upload.status) { + } + + // ***** Step4: Abort upload file + else if (UPLOAD_FILE_ABORTED == upload.status) { restart_flag = 0; MqttRetryCounter(0); #ifdef USE_COUNTER From 1295370bf106b0ac42f2af800936073b9f9313fb Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 5 Sep 2020 14:44:31 +0200 Subject: [PATCH 19/38] Zigbee refactor of internal structures --- tasmota/support_light_list.ino | 186 +++ tasmota/support_static_buffer.ino | 15 + tasmota/xdrv_23_zigbee_1z_libs.ino | 752 ++++++++++++ tasmota/xdrv_23_zigbee_2_devices.ino | 424 +++---- tasmota/xdrv_23_zigbee_5_converters.ino | 1436 +++++++++++------------ tasmota/xdrv_23_zigbee_6_commands.ino | 162 ++- tasmota/xdrv_23_zigbee_8_parsers.ino | 170 ++- tasmota/xdrv_23_zigbee_A_impl.ino | 2 +- 8 files changed, 1923 insertions(+), 1224 deletions(-) create mode 100644 tasmota/support_light_list.ino create mode 100644 tasmota/xdrv_23_zigbee_1z_libs.ino diff --git a/tasmota/support_light_list.ino b/tasmota/support_light_list.ino new file mode 100644 index 000000000..28d2af595 --- /dev/null +++ b/tasmota/support_light_list.ino @@ -0,0 +1,186 @@ +/* + support_light_list.ino - Lightweight Linked List for simple objects - optimized for low code size and low memory + + Copyright (C) 2020 Theo Arends and Stephan Hadinger + + 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 . +*/ + +/*********************************************************************************************\ + * + * private class for Linked List element + * +\*********************************************************************************************/ +template +class LList; + +template +class LList_elt { +public: + + LList_elt() : _next(nullptr), _val() {} + + inline T & val(void) { return _val; } + inline LList_elt * next(void) { return _next; } + inline void next(LList_elt * next) { _next = next; } + + friend class LList; + +protected: + LList_elt * _next; + T _val; +}; + +/*********************************************************************************************\ + * + * Lightweight Linked List - optimized for low code size + * +\*********************************************************************************************/ +template +class LList { +public: + LList() : _head(nullptr) {} + ~LList() { reset(); } + + // remove elements + void removeHead(void); // remove first element + void reset(void); // remove all elements + void remove(const T * val); + + // read the list + inline bool isEmpty(void) const { return (_head == nullptr) ? true : false; } + size_t length(void) const; + inline T * head(void) { return _head ? &_head->_val : nullptr; } + inline const T * head(void) const { return _head ? &_head->_val : nullptr; } + const T * at(size_t index) const ; + // non-const variants + // not very academic cast but reduces code size + inline T * at(size_t index) { return (T*) ((const LList*)this)->at(index); } + + // adding elements + T & addHead(void); + T & addHead(const T &val); + T & addToLast(void); + + // iterator + // see https://stackoverflow.com/questions/8164567/how-to-make-my-custom-type-to-work-with-range-based-for-loops + class iterator { + public: + iterator(LList_elt *_cur): cur(_cur), next(nullptr) { if (cur) { next = cur->_next; } } + iterator operator++() { cur = next; if (cur) { next = cur->_next;} return *this; } + bool operator!=(const iterator & other) const { return cur != other.cur; } + T & operator*() const { return cur->_val; } + private: + LList_elt *cur; + LList_elt *next; // we need to keep next pointer in case the current attribute gets deleted + }; + iterator begin() { return iterator(this->_head); } // start with 'head' + iterator end() { return iterator(nullptr); } // end with null pointer + + // const iterator + class const_iterator { + public: + const_iterator(const LList_elt *_cur): cur(_cur), next(nullptr) { if (cur) { next = cur->_next; } } + const_iterator operator++() { cur = next; if (cur) { next = cur->_next;} return *this; } + bool operator!=(const_iterator & other) const { return cur != other.cur; } + const T & operator*() const { return cur->_val; } + private: + const LList_elt *cur; + const LList_elt *next; // we need to keep next pointer in case the current attribute gets deleted + }; + const_iterator begin() const { return const_iterator(this->_head); } // start with 'head' + const_iterator end() const { return const_iterator(nullptr); } // end with null pointer + +protected: + LList_elt * _head; +}; + +template +size_t LList::length(void) const { + size_t count = 0; + for (auto & elt : *this) {count++; } + return count; +} + + +template +const T * LList::at(size_t index) const { + size_t count = 0; + for (const auto & elt : *this) { + if (index == count++) { return &elt; } + } + return nullptr; +} + +template +void LList::reset(void) { + while (_head) { + LList_elt * next = _head->next(); + delete _head; + _head = next; + } +} + +template +void LList::removeHead(void) { + if (_head) { + LList_elt * next = _head->next(); + delete _head; + _head = next; + } +} + +template +void LList::remove(const T * val) { + if (nullptr == val) { return; } + // find element in chain and find pointer before + LList_elt **curr_ptr = &_head; + while (*curr_ptr) { + LList_elt * curr_elt = *curr_ptr; + if ( &(curr_elt->_val) == val) { + *curr_ptr = curr_elt->_next; // update previous pointer to next element + delete curr_elt; + break; // stop iteration now + } + curr_ptr = &((*curr_ptr)->_next); // move to next element + } +} + +template +T & LList::addHead(void) { + LList_elt * elt = new LList_elt(); // create element + elt->next(_head); // insert at the head + _head = elt; + return elt->_val; +} + +template +T & LList::addHead(const T &val) { + LList_elt * elt = new LList_elt(); // create element + elt->next(_head); // insert at the head + elt->_val = val; + _head = elt; + return elt->_val; +} + +template +T & LList::addToLast(void) { + LList_elt **curr_ptr = &_head; + while (*curr_ptr) { + curr_ptr = &((*curr_ptr)->_next); + } + LList_elt * elt = new LList_elt(); // create element + *curr_ptr = elt; + return elt->_val; +} \ No newline at end of file diff --git a/tasmota/support_static_buffer.ino b/tasmota/support_static_buffer.ino index ea21b2805..81deb083b 100644 --- a/tasmota/support_static_buffer.ino +++ b/tasmota/support_static_buffer.ino @@ -237,3 +237,18 @@ public: _buf = nullptr; } } PreAllocatedSBuffer; + +// nullptr accepted +bool equalsSBuffer(const class SBuffer * buf1, const class SBuffer * buf2) { + if (buf1 == buf2) { return true; } + if (!buf1 && (buf2->len() == 0)) { return true; } + if (!buf2 && (buf1->len() == 0)) { return true; } + if (!buf1 || !buf2) { return false; } // at least one buf is not empty + // we know that both buf1 and buf2 are non-null + if (buf1->len() != buf2->len()) { return false; } + size_t len = buf1->len(); + for (uint32_t i=0; iget8(i) != buf2->get8(i)) { return false; } + } + return true; +} \ No newline at end of file diff --git a/tasmota/xdrv_23_zigbee_1z_libs.ino b/tasmota/xdrv_23_zigbee_1z_libs.ino new file mode 100644 index 000000000..0590cff81 --- /dev/null +++ b/tasmota/xdrv_23_zigbee_1z_libs.ino @@ -0,0 +1,752 @@ +/* + xdrv_23_zigbee_1z_libs.ino - zigbee support for Tasmota, JSON replacement libs + + Copyright (C) 2020 Theo Arends and Stephan Hadinger + + 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 USE_ZIGBEE + +/*********************************************************************************************\ + * Replacement libs for JSON to output a list of attributes +\*********************************************************************************************/ + +// simplified version of strcmp accepting both arguments to be in PMEM, and accepting nullptr arguments +// inspired from https://code.woboq.org/userspace/glibc/string/strcmp.c.html +int strcmp_PP(const char *p1, const char *p2) { + if (p1 == p2) { return 0; } // equality + if (!p1) { return -1; } // first string is null + if (!p2) { return 1; } // second string is null + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + do { + c1 = (unsigned char) pgm_read_byte(s1); + s1++; + c2 = (unsigned char) pgm_read_byte(s2); + s2++; + if (c1 == '\0') + return c1 - c2; + } + while (c1 == c2); + return c1 - c2; +} + +/*********************************************************************************************\ + * + * Variables for Rules from last Zigbee message received + * +\*********************************************************************************************/ + +typedef struct Z_LastMessageVars { + uint16_t device; // device short address + uint16_t groupaddr; // group address + uint16_t cluster; // cluster id + uint8_t endpoint; // source endpoint +} Z_LastMessageVars; + +Z_LastMessageVars gZbLastMessage; + +uint16_t Z_GetLastDevice(void) { return gZbLastMessage.device; } +uint16_t Z_GetLastGroup(void) { return gZbLastMessage.groupaddr; } +uint16_t Z_GetLastCluster(void) { return gZbLastMessage.cluster; } +uint8_t Z_GetLastEndpoint(void) { return gZbLastMessage.endpoint; } + +/*********************************************************************************************\ + * + * Class for single attribute + * +\*********************************************************************************************/ + +enum class Za_type : uint8_t { + Za_none, // empty, translates into null in JSON + // numericals + Za_bool, // boolean, translates to true/false, uses uval32 to store + Za_uint, // unsigned 32 int, uses uval32 + Za_int, // signed 32 int, uses ival32 + Za_float, // float 32, uses fval + // non-nummericals + Za_raw, // bytes buffer, uses bval + Za_str // string, uses sval +}; + +class Z_attribute { +public: + + // attribute key, either cluster+attribute_id or plain name + union { + struct { + uint16_t cluster; + uint16_t attr_id; + } id; + char * key; + } key; + // attribute value + union { + uint32_t uval32; + int32_t ival32; + float fval; + SBuffer* bval; + char* sval; + } val; + Za_type type; // uint8_t in size, type of attribute, see above + bool key_is_str; // is the key a string? + bool key_is_pmem; // is the string in progmem, so we don't need to make a copy + bool val_str_raw; // if val is String, it is raw JSON and should not be escaped + uint8_t key_suffix; // append a suffix to key (default is 1, explicitly output if >1) + + // Constructor with all defaults + Z_attribute(): + key{ .id = { 0x0000, 0x0000 } }, + val{ .uval32 = 0x0000 }, + type(Za_type::Za_none), + key_is_str(false), + key_is_pmem(false), + val_str_raw(false), + key_suffix(1) + {}; + + Z_attribute(const Z_attribute & rhs) { + deepCopy(rhs); + } + + Z_attribute & operator = (const Z_attribute & rhs) { + freeKey(); + freeVal(); + deepCopy(rhs); + } + + // Destructor, free memory that was allocated + ~Z_attribute() { + freeKey(); + freeVal(); + } + + // free any allocated memoruy for values + void freeVal(void) { + switch (type) { + case Za_type::Za_raw: + if (val.bval) { delete val.bval; val.bval = nullptr; } + break; + case Za_type::Za_str: + if (val.sval) { delete[] val.sval; val.sval = nullptr; } + break; + } + } + // free any allocated memoruy for keys + void freeKey(void) { + if (key_is_str && key.key && !key_is_pmem) { delete[] key.key; } + key.key = nullptr; + } + + // set key name + void setKeyName(const char * _key, bool pmem = false) { + freeKey(); + key_is_str = true; + key_is_pmem = pmem; + if (pmem) { + key.key = (char*) _key; + } else { + setKeyName(_key, nullptr); + } + } + // provide two entries and concat + void setKeyName(const char * _key, const char * _key2) { + freeKey(); + key_is_str = true; + key_is_pmem = false; + if (_key) { + size_t key_len = strlen_P(_key); + if (_key2) { + key_len += strlen_P(_key2); + } + key.key = new char[key_len+1]; + strcpy_P(key.key, _key); + if (_key2) { + strcat_P(key.key, _key2); + } + } + } + + void setKeyId(uint16_t cluster, uint16_t attr_id) { + freeKey(); + key_is_str = false; + key.id.cluster = cluster; + key.id.attr_id = attr_id; + } + + // Setters + void setNone(void) { + freeVal(); // free any previously allocated memory + val.uval32 = 0; + type = Za_type::Za_none; + } + void setUInt(uint32_t _val) { + freeVal(); // free any previously allocated memory + val.uval32 = _val; + type = Za_type::Za_uint; + } + void setBool(bool _val) { + freeVal(); // free any previously allocated memory + val.uval32 = _val; + type = Za_type::Za_bool; + } + void setInt(int32_t _val) { + freeVal(); // free any previously allocated memory + val.ival32 = _val; + type = Za_type::Za_int; + } + void setFloat(float _val) { + freeVal(); // free any previously allocated memory + val.fval = _val; + type = Za_type::Za_float; + } + + void setBuf(const SBuffer &buf, size_t index, size_t len) { + freeVal(); + if (len) { + val.bval = new SBuffer(len); + val.bval->addBuffer(buf.buf(index), len); + } + type = Za_type::Za_raw; + } + + // set the string value + // PMEM argument is allowed + // string will be copied, so it can be changed later + // nullptr is allowed and considered as empty string + // Note: memory is allocated only if string is non-empty + void setStr(const char * _val) { + freeVal(); // free any previously allocated memory + val_str_raw = false; + // val.sval is always nullptr after freeVal() + if (_val) { + size_t len = strlen_P(_val); + if (len) { + val.sval = new char[len+1]; + strcpy_P(val.sval, _val); + } + } + type = Za_type::Za_str; + } + inline void setStrRaw(const char * _val) { + setStr(_val); + val_str_raw = true; + } + + inline bool isNum(void) const { return (type >= Za_type::Za_bool) && (type <= Za_type::Za_float); } + // get num values + float getFloat(void) const { + switch (type) { + case Za_type::Za_bool: + case Za_type::Za_uint: return (float) val.uval32; + case Za_type::Za_int: return (float) val.ival32; + case Za_type::Za_float: return val.fval; + default: return 0.0f; + } + } + + int32_t getInt(void) const { + switch (type) { + case Za_type::Za_bool: + case Za_type::Za_uint: return (int32_t) val.uval32; + case Za_type::Za_int: return val.ival32; + case Za_type::Za_float: return (int32_t) val.fval; + default: return 0; + } + } + + uint32_t getUInt(void) const { + switch (type) { + case Za_type::Za_bool: + case Za_type::Za_uint: return val.uval32; + case Za_type::Za_int: return (uint32_t) val.ival32; + case Za_type::Za_float: return (uint32_t) val.fval; + default: return 0; + } + } + + bool getBool(void) const { + switch (type) { + case Za_type::Za_bool: + case Za_type::Za_uint: return val.uval32 ? true : false; + case Za_type::Za_int: return val.ival32 ? true : false; + case Za_type::Za_float: return val.fval ? true : false; + default: return false; + } + } + + const SBuffer * getRaw(void) const { + if (Za_type::Za_raw == type) { return val.bval; } + return nullptr; + } + + // always return a point to a string, if not defined then empty string. + // Never returns nullptr + const char * getStr(void) const { + if (Za_type::Za_str == type) { return val.sval; } + return ""; + } + + bool equalsKey(const Z_attribute & attr2, bool ignore_key_suffix = false) const { + // check if keys are equal + if (key_is_str != attr2.key_is_str) { return false; } + if (key_is_str) { + if (strcmp_PP(key.key, attr2.key.key)) { return false; } + } else { + if ((key.id.cluster != attr2.key.id.cluster) || + (key.id.attr_id != attr2.key.id.attr_id)) { return false; } + } + if (!ignore_key_suffix) { + if (key_suffix != attr2.key_suffix) { return false; } + } + return true; + } + + bool equalsKey(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0) const { + if (!key_is_str) { + if ((key.id.cluster == cluster) && (key.id.attr_id == attr_id)) { + if (suffix) { + if (key_suffix == suffix) { return true; } + } else { + return true; + } + } + } + return false; + } + + bool equalsKey(const char * name, uint8_t suffix = 0) const { + if (key_is_str) { + if (0 == strcmp_PP(key.key, name)) { + if (suffix) { + if (key_suffix == suffix) { return true; } + } else { + return true; + } + } + } + return false; + } + + bool equalsVal(const Z_attribute & attr2) const { + if (type != attr2.type) { return false; } + if ((type >= Za_type::Za_bool) && (type <= Za_type::Za_float)) { + // numerical value + if (val.uval32 != attr2.val.uval32) { return false; } + } else if (type == Za_type::Za_raw) { + // compare 2 Static buffers + return equalsSBuffer(val.bval, attr2.val.bval); + } else if (type == Za_type::Za_str) { + // if (val_str_raw != attr2.val_str_raw) { return false; } + if (strcmp_PP(val.sval, attr2.val.sval)) { return false; } + } + return true; + } + + bool equals(const Z_attribute & attr2) const { + return equalsKey(attr2) && equalsVal(attr2); + } + + String toString(bool prefix_comma = false) const { + String res(""); + if (prefix_comma) { res += ','; } + res += '"'; + // compute the attribute name + if (key_is_str) { + if (key.key) { res += EscapeJSONString(key.key); } + else { res += F("null"); } // shouldn't happen + if (key_suffix > 1) { + res += key_suffix; + } + } else { + char attr_name[12]; + snprintf_P(attr_name, sizeof(attr_name), PSTR("%04X/%04X"), key.id.cluster, key.id.attr_id); + res += attr_name; + if (key_suffix > 1) { + res += '+'; + res += key_suffix; + } + } + res += F("\":"); + // value part + switch (type) { + case Za_type::Za_none: + res += "null"; + break; + case Za_type::Za_bool: + res += val.uval32 ? F("true") : F("false"); + break; + case Za_type::Za_uint: + res += val.uval32; + break; + case Za_type::Za_int: + res += val.ival32; + break; + case Za_type::Za_float: + { + String fstr(val.fval, 2); + size_t last = fstr.length() - 1; + // remove trailing zeros + while (fstr[last] == '0') { + fstr.remove(last--); + } + // remove trailing dot + if (fstr[last] == '.') { + fstr.remove(last); + } + res += fstr; + } + break; + case Za_type::Za_raw: + res += '"'; + if (val.bval) { + size_t blen = val.bval->len(); + // print as HEX + char hex[2*blen+1]; + ToHex_P(val.bval->getBuffer(), blen, hex, sizeof(hex)); + res += hex; + } + res += '"'; + break; + case Za_type::Za_str: + if (val_str_raw) { + if (val.sval) { res += val.sval; } + } else { + res += '"'; + if (val.sval) { + res += EscapeJSONString(val.sval); // escape JSON chars + } + res += '"'; + } + break; + } + + return res; + } + + // copy value from one attribute to another, without changing its type + void copyVal(const Z_attribute & rhs) { + freeVal(); + // copy value + val.uval32 = 0x00000000; + type = rhs.type; + if (rhs.isNum()) { + val.uval32 = rhs.val.uval32; + } else if (rhs.type == Za_type::Za_raw) { + if (rhs.val.bval) { + val.bval = new SBuffer(rhs.val.bval->len()); + val.bval->addBuffer(*(rhs.val.bval)); + } + } else if (rhs.type == Za_type::Za_str) { + if (rhs.val.sval) { + size_t s_len = strlen_P(rhs.val.sval); + val.sval = new char[s_len+1]; + strcpy_P(val.sval, rhs.val.sval); + } + } + val_str_raw = rhs.val_str_raw; + } + +protected: + void deepCopy(const Z_attribute & rhs) { + // copy key + if (!rhs.key_is_str) { + key.id.cluster = rhs.key.id.cluster; + key.id.attr_id = rhs.key.id.attr_id; + } else { + if (rhs.key_is_pmem) { + key.key = rhs.key.key; // PMEM, don't copy + } else { + key.key = nullptr; + if (rhs.key.key) { + size_t key_len = strlen_P(rhs.key.key); + if (key_len) { + key.key = new char[key_len+1]; + strcpy_P(key.key, rhs.key.key); + } + } + } + } + key_is_str = rhs.key_is_str; + key_is_pmem = rhs.key_is_pmem; + key_suffix = rhs.key_suffix; + // copy value + copyVal(rhs); + // don't touch next pointer + } +}; + +/*********************************************************************************************\ + * + * Class for attribute array of values + * This is a helper function to generate a clean list of unsigned ints + * +\*********************************************************************************************/ + +class Z_json_array { +public: + + Z_json_array(): val("[]") {} // start with empty array + void add(uint32_t uval32) { + // remove trailing ']' + val.remove(val.length()-1); + if (val.length() > 1) { // if not empty, prefix with comma + val += ','; + } + val += uval32; + val += ']'; + } + String &toString(void) { + return val; + } + +private : + String val; +}; + +/*********************************************************************************************\ + * + * Class for attribute ordered list + * +\*********************************************************************************************/ + + +// Attribute list +// Contains meta-information: +// - source endpoint (is conflicting) +// - LQI (if not conflicting) +class Z_attribute_list : public LList { +public: + uint8_t src_ep; // source endpoint, 0xFF if unknown + uint8_t lqi; // linkquality, 0xFF if unknown + uint16_t group_id; // group address OxFFFF if inknown + + Z_attribute_list(): + LList(), // call superclass constructor + src_ep(0xFF), + lqi(0xFF), + group_id(0xFFFF) + {}; + + // we don't define any destructor, the superclass destructor is automatically called + + // reset object to its initial state + // free all allocated memory + void reset(void) { + LList::reset(); + src_ep = 0xFF; + lqi = 0xFF; + group_id = 0xFFFF; + } + + inline bool isValidSrcEp(void) const { return 0xFF != src_ep; } + inline bool isValidLQI(void) const { return 0xFF != lqi; } + inline bool isValidGroupId(void) const { return 0xFFFF != group_id; } + + // the following addAttribute() compute the suffix and increments it + // Add attribute to the list, given cluster and attribute id + Z_attribute & addAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0); + + // Add attribute to the list, given name + Z_attribute & addAttribute(const char * name, bool pmem = false, uint8_t suffix = 0); + Z_attribute & addAttribute(const char * name, const char * name2, uint8_t suffix = 0); + inline Z_attribute & addAttribute(const __FlashStringHelper * name, uint8_t suffix = 0) { + return addAttribute((const char*) name, true, suffix); + } + + // Remove from list by reference, if null or not found, then do nothing + inline void removeAttribute(const Z_attribute * attr) { remove(attr); } + + // dump the entire structure as JSON, starting from head (as parameter) + // does not start not end with a comma + // do we enclosed in brackets '{' '}' + String toString(bool enclose_brackets = false) const; + + // find if attribute with same key already exists, return null if not found + const Z_attribute * findAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0) const; + const Z_attribute * findAttribute(const char * name, uint8_t suffix = 0) const; + const Z_attribute * findAttribute(const Z_attribute &attr) const; // suffis always count here + // non-const variants + inline Z_attribute * findAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0) { + return (Z_attribute*) ((const Z_attribute_list*)this)->findAttribute(cluster, attr_id, suffix); + } + inline Z_attribute * findAttribute(const char * name, uint8_t suffix = 0) { + return (Z_attribute*) (((const Z_attribute_list*)this)->findAttribute(name, suffix)); + } + inline Z_attribute * findAttribute(const Z_attribute &attr) { + return (Z_attribute*) ((const Z_attribute_list*)this)->findAttribute(attr); + } + + // count matching attributes, ignoring suffix + size_t countAttribute(uint16_t cluster, uint16_t attr_id) const ; + size_t countAttribute(const char * name) const ; + + // if suffix == 0, we don't care and find the first match + Z_attribute & findOrCreateAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0); + Z_attribute & findOrCreateAttribute(const char * name, uint8_t suffix = 0); + // always care about suffix + Z_attribute & findOrCreateAttribute(const Z_attribute &attr); + // replace attribute with new value, suffix does care + Z_attribute & replaceOrCreate(const Z_attribute &attr); + + // merge with secondary list, return true if ok, false if conflict + bool mergeList(const Z_attribute_list &list2); +}; + +// add a cluster/attr_id attribute at the end of the list +Z_attribute & Z_attribute_list::addAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix) { + Z_attribute & attr = addToLast(); + attr.key.id.cluster = cluster; + attr.key.id.attr_id = attr_id; + attr.key_is_str = false; + if (!suffix) { attr.key_suffix = countAttribute(attr.key.id.cluster, attr.key.id.attr_id); } + else { attr.key_suffix = suffix; } + return attr; +} + +// add a cluster/attr_id attribute at the end of the list +Z_attribute & Z_attribute_list::addAttribute(const char * name, bool pmem, uint8_t suffix) { + Z_attribute & attr = addToLast(); + attr.setKeyName(name, pmem); + if (!suffix) { attr.key_suffix = countAttribute(attr.key.key); } + else { attr.key_suffix = suffix; } + return attr; +} + +Z_attribute & Z_attribute_list::addAttribute(const char * name, const char * name2, uint8_t suffix) { + Z_attribute & attr = addToLast(); + attr.setKeyName(name, name2); + if (!suffix) { attr.key_suffix = countAttribute(attr.key.key); } + else { attr.key_suffix = suffix; } + return attr; +} + +String Z_attribute_list::toString(bool enclose_brackets) const { + String res = ""; + if (enclose_brackets) { res += '{'; } + bool prefix_comma = false; + for (const auto & attr : *this) { + res += attr.toString(prefix_comma); + prefix_comma = true; + } + // add source endpoint + if (0xFF != src_ep) { + if (prefix_comma) { res += ','; } + prefix_comma = true; + res += F("\"" D_CMND_ZIGBEE_ENDPOINT "\":"); + res += src_ep; + } + // add group address + if (0xFFFF != group_id) { + if (prefix_comma) { res += ','; } + prefix_comma = true; + res += F("\"" D_CMND_ZIGBEE_GROUP "\":"); + res += group_id; + } + // add lqi + if (0xFF != lqi) { + if (prefix_comma) { res += ','; } + prefix_comma = true; + res += F("\"" D_CMND_ZIGBEE_LINKQUALITY "\":"); + res += lqi; + } + if (enclose_brackets) { res += '}'; } + // done + return res; +} + +// suffis always count here +const Z_attribute * Z_attribute_list::findAttribute(const Z_attribute &attr) const { + uint8_t suffix = attr.key_suffix; + if (attr.key_is_str) { + return findAttribute(attr.key.key, suffix); + } else { + return findAttribute(attr.key.id.cluster, attr.key.id.attr_id, suffix); + } +} + +const Z_attribute * Z_attribute_list::findAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix) const { + for (const auto & attr : *this) { + if (attr.equalsKey(cluster, attr_id, suffix)) { return &attr; } + } + return nullptr; +} +size_t Z_attribute_list::countAttribute(uint16_t cluster, uint16_t attr_id) const { + size_t count = 0; + for (const auto & attr : *this) { + if (attr.equalsKey(cluster, attr_id, 0)) { count++; } + } + return count; +} + +// return the existing attribute or create a new one +Z_attribute & Z_attribute_list::findOrCreateAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix) { + Z_attribute * found = findAttribute(cluster, attr_id, suffix); + return found ? *found : addAttribute(cluster, attr_id, suffix); +} + +const Z_attribute * Z_attribute_list::findAttribute(const char * name, uint8_t suffix) const { + for (const auto & attr : *this) { + if (attr.equalsKey(name, suffix)) { return &attr; } + } + return nullptr; +} +size_t Z_attribute_list::countAttribute(const char * name) const { + size_t count = 0; + for (const auto & attr : *this) { + if (attr.equalsKey(name, 0)) { count++; } + } + return count; +} +// return the existing attribute or create a new one +Z_attribute & Z_attribute_list::findOrCreateAttribute(const char * name, uint8_t suffix) { + Z_attribute * found = findAttribute(name, suffix); + return found ? *found : addAttribute(name, suffix); +} + +// same but passing a Z_attribute as key +Z_attribute & Z_attribute_list::findOrCreateAttribute(const Z_attribute &attr) { + if (attr.key_is_str) { + return findOrCreateAttribute(attr.key.key, attr.key_suffix); + } else { + return findOrCreateAttribute(attr.key.id.cluster, attr.key.id.attr_id, attr.key_suffix); + } +} +// replace the entire content with new attribute or create +Z_attribute & Z_attribute_list::replaceOrCreate(const Z_attribute &attr) { + Z_attribute &new_attr = findOrCreateAttribute(attr); + new_attr.copyVal(attr); + return new_attr; +} + + +bool Z_attribute_list::mergeList(const Z_attribute_list &attr_list) { + // Check source endpoint + if (0xFF == src_ep) { + src_ep = attr_list.src_ep; + } else if (0xFF != attr_list.src_ep) { + if (src_ep != attr_list.src_ep) { return false; } + } + if (0xFF != attr_list.lqi) { + lqi = attr_list.lqi; + } + for (auto & attr : attr_list) { + replaceOrCreate(attr); + } + return true; +} + +#endif // USE_ZIGBEE diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index aa7ea9d2c..8ad36f861 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -19,8 +19,6 @@ #ifdef USE_ZIGBEE -#include - #ifndef ZIGBEE_SAVE_DELAY_SECONDS #define ZIGBEE_SAVE_DELAY_SECONDS 2 // wait for 2s before saving Zigbee info #endif @@ -29,25 +27,6 @@ const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait f /*********************************************************************************************\ * Structures for Rules variables related to the last received message \*********************************************************************************************/ - -typedef struct Z_LastMessageVars { - uint16_t device; // device short address - uint16_t groupaddr; // group address - uint16_t cluster; // cluster id - uint8_t endpoint; // source endpoint -} Z_LastMessageVars; - -Z_LastMessageVars gZbLastMessage; - -uint16_t Z_GetLastDevice(void) { return gZbLastMessage.device; } -uint16_t Z_GetLastGroup(void) { return gZbLastMessage.groupaddr; } -uint16_t Z_GetLastCluster(void) { return gZbLastMessage.cluster; } -uint8_t Z_GetLastEndpoint(void) { return gZbLastMessage.endpoint; } - -/*********************************************************************************************\ - * Structures for device configuration -\*********************************************************************************************/ - const size_t endpoints_max = 8; // we limit to 8 endpoints class Z_Device { @@ -58,9 +37,8 @@ public: char * modelId; char * friendlyName; uint8_t endpoints[endpoints_max]; // static array to limit memory consumption, list of endpoints until 0x00 or end of array - // json buffer used for attribute reporting - DynamicJsonBuffer *json_buffer; - JsonObject *json; + // Used for attribute reporting + Z_attribute_list attr_list; // sequence number for Zigbee frames uint16_t shortaddr; // unique key if not null, or unspecified if null uint8_t seqNumber; @@ -95,14 +73,13 @@ public: int16_t mains_power; // Active power // Constructor with all defaults - Z_Device(uint16_t _shortaddr, uint64_t _longaddr = 0x00): + Z_Device(uint16_t _shortaddr = BAD_SHORTADDR, uint64_t _longaddr = 0x00): longaddr(_longaddr), manufacturerId(nullptr), modelId(nullptr), friendlyName(nullptr), endpoints{ 0, 0, 0, 0, 0, 0, 0, 0 }, - json_buffer(nullptr), - json(nullptr), + attr_list(), shortaddr(_shortaddr), seqNumber(0), // Hue support @@ -207,7 +184,7 @@ typedef struct Z_Deferred { // - shortaddr and longaddr cannot be both null class Z_Devices { public: - Z_Devices() {}; + Z_Devices() : _deferred() {}; // Probe the existence of device keys // Results: @@ -218,12 +195,17 @@ public: uint16_t isKnownIndex(uint32_t index) const; uint16_t isKnownFriendlyName(const char * name) const; + Z_Device & findShortAddr(uint16_t shortaddr); const Z_Device & findShortAddr(uint16_t shortaddr) const; + Z_Device & findLongAddr(uint64_t longaddr); + const Z_Device & findLongAddr(uint64_t longaddr) const; Z_Device & getShortAddr(uint16_t shortaddr); // find Device from shortAddr, creates it if does not exist - const Z_Device & getShortAddrConst(uint16_t shortaddr) const ; // find Device from shortAddr, creates it if does not exist Z_Device & getLongAddr(uint64_t longaddr); // find Device from shortAddr, creates it if does not exist + // check if a device was found or if it's the fallback device + inline bool foundDevice(const Z_Device & device) const { + return (&device != &device_unk); + } - int32_t findLongAddr(uint64_t longaddr) const; int32_t findFriendlyName(const char * name) const; uint64_t getDeviceLongAddr(uint16_t shortaddr) const; @@ -281,19 +263,22 @@ public: void runTimer(void); // Append or clear attributes Json structure - void jsonClear(uint16_t shortaddr); - void jsonAppend(uint16_t shortaddr, const JsonObject &values); - const JsonObject *jsonGet(uint16_t shortaddr); + void jsonAppend(uint16_t shortaddr, const Z_attribute_list &attr_list); void jsonPublishFlush(uint16_t shortaddr); // publish the json message and clear buffer - bool jsonIsConflict(uint16_t shortaddr, const JsonObject &values); - void jsonPublishNow(uint16_t shortaddr, JsonObject &values); + bool jsonIsConflict(uint16_t shortaddr, const Z_attribute_list &attr_list) const; + void jsonPublishNow(uint16_t shortaddr, Z_attribute_list &attr_list); // Iterator size_t devicesSize(void) const { - return _devices.size(); + return _devices.length(); } - const Z_Device &devicesAt(size_t i) const { - return *(_devices.at(i)); + const Z_Device & devicesAt(size_t i) const { + const Z_Device * devp = _devices.at(i); + if (devp) { + return *devp; + } else { + return device_unk; + } } // Remove device from list @@ -308,8 +293,8 @@ public: uint16_t parseDeviceParam(const char * param, bool short_must_be_known = false) const; private: - std::vector _devices = {}; - std::vector _deferred = {}; // list of deferred calls + LList _devices; // list of devices + LList _deferred; // list of deferred calls uint32_t _saveTimer = 0; uint8_t _seqNumber = 0; // global seqNumber if device is unknown @@ -317,10 +302,7 @@ private: // Any find() function will not return Null, instead it will return this instance const Z_Device device_unk = Z_Device(BAD_SHORTADDR); - template < typename T> - static bool findInVector(const std::vector & vecOfElements, const T & element); - - int32_t findShortAddrIdx(uint16_t shortaddr) const; + //int32_t findShortAddrIdx(uint16_t shortaddr) const; // Create a new entry in the devices list - must be called if it is sure it does not already exist Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0); void freeDeviceEntry(Z_Device *device); @@ -343,31 +325,16 @@ uint16_t localShortAddr = 0; * Implementation \*********************************************************************************************/ -// https://thispointer.com/c-how-to-find-an-element-in-vector-and-get-its-index/ -template < typename T> -bool Z_Devices::findInVector(const std::vector & vecOfElements, const T & element) { - // Find given element in vector - auto it = std::find(vecOfElements.begin(), vecOfElements.end(), element); - - if (it != vecOfElements.end()) { - return true; - } else { - return false; - } -} - // // Create a new Z_Device entry in _devices. Only to be called if you are sure that no // entry with same shortaddr or longaddr exists. // Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) { if ((BAD_SHORTADDR == shortaddr) && !longaddr) { return (Z_Device&) device_unk; } // it is not legal to create this entry - Z_Device * device_alloc = new Z_Device(shortaddr, longaddr); + Z_Device device(shortaddr, longaddr); - device_alloc->json_buffer = new DynamicJsonBuffer(16); - _devices.push_back(device_alloc); dirty(); - return *(_devices.back()); + return _devices.addHead(device); } void Z_Devices::freeDeviceEntry(Z_Device *device) { @@ -383,20 +350,17 @@ void Z_Devices::freeDeviceEntry(Z_Device *device) { // In: // shortaddr (not BAD_SHORTADDR) // Out: -// index in _devices of entry, -1 if not found -// -int32_t Z_Devices::findShortAddrIdx(uint16_t shortaddr) const { - if (BAD_SHORTADDR == shortaddr) { return -1; } // does not make sense to look for BAD_SHORTADDR shortaddr (broadcast) - int32_t found = 0; - for (auto &elem : _devices) { - if (elem->shortaddr == shortaddr) { return found; } - found++; +// reference to device, or to device_unk if not found +// (use foundDevice() to check if found) +Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) { + for (auto & elem : _devices) { + if (elem.shortaddr == shortaddr) { return elem; } } - return -1; + return (Z_Device&) device_unk; } const Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) const { - for (auto &elem : _devices) { - if (elem->shortaddr == shortaddr) { return *elem; } + for (const auto & elem : _devices) { + if (elem.shortaddr == shortaddr) { return elem; } } return device_unk; } @@ -408,14 +372,19 @@ const Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) const { // Out: // index in _devices of entry, -1 if not found // -int32_t Z_Devices::findLongAddr(uint64_t longaddr) const { - if (!longaddr) { return -1; } - int32_t found = 0; +Z_Device & Z_Devices::findLongAddr(uint64_t longaddr) { + if (!longaddr) { return (Z_Device&) device_unk; } for (auto &elem : _devices) { - if (elem->longaddr == longaddr) { return found; } - found++; + if (elem.longaddr == longaddr) { return elem; } } - return -1; + return (Z_Device&) device_unk; +} +const Z_Device & Z_Devices::findLongAddr(uint64_t longaddr) const { + if (!longaddr) { return device_unk; } + for (const auto &elem : _devices) { + if (elem.longaddr == longaddr) { return elem; } + } + return device_unk; } // // Scan all devices to find a corresponding friendlyNme @@ -431,8 +400,8 @@ int32_t Z_Devices::findFriendlyName(const char * name) const { int32_t found = 0; if (name_len) { for (auto &elem : _devices) { - if (elem->friendlyName) { - if (strcasecmp(elem->friendlyName, name) == 0) { return found; } + if (elem.friendlyName) { + if (strcasecmp(elem.friendlyName, name) == 0) { return found; } } found++; } @@ -441,9 +410,8 @@ int32_t Z_Devices::findFriendlyName(const char * name) const { } uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const { - int32_t found = findLongAddr(longaddr); - if (found >= 0) { - const Z_Device & device = devicesAt(found); + const Z_Device & device = findLongAddr(longaddr); + if (foundDevice(device)) { return device.shortaddr; // can be zero, if not yet registered } else { return BAD_SHORTADDR; @@ -471,7 +439,7 @@ uint16_t Z_Devices::isKnownFriendlyName(const char * name) const { } uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const { - return getShortAddrConst(shortaddr).longaddr; // if unknown, it reverts to the Unknown device and longaddr is 0x00 + return findShortAddr(shortaddr).longaddr; // if unknown, it reverts to the Unknown device and longaddr is 0x00 } // @@ -479,38 +447,28 @@ uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const { // Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) { if (BAD_SHORTADDR == shortaddr) { return (Z_Device&) device_unk; } // this is not legal - int32_t found = findShortAddrIdx(shortaddr); - if (found >= 0) { - return *(_devices[found]); + Z_Device & device = findShortAddr(shortaddr); + if (foundDevice(device)) { + return device; } - //Serial.printf("Device entry created for shortaddr = 0x%02X, found = %d\n", shortaddr, found); return createDeviceEntry(shortaddr, 0); } -// Same version but Const -const Z_Device & Z_Devices::getShortAddrConst(uint16_t shortaddr) const { - int32_t found = findShortAddrIdx(shortaddr); - if (found >= 0) { - return *(_devices[found]); - } - return device_unk; -} // find the Device object by its longaddr (unique key if not null) Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) { if (!longaddr) { return (Z_Device&) device_unk; } - int32_t found = findLongAddr(longaddr); - if (found > 0) { - return *(_devices[found]); + Z_Device & device = findLongAddr(longaddr); + if (foundDevice(device)) { + return device; } return createDeviceEntry(0, longaddr); } // Remove device from list, return true if it was known, false if it was not recorded bool Z_Devices::removeDevice(uint16_t shortaddr) { - int32_t found = findShortAddrIdx(shortaddr); - if (found >= 0) { - freeDeviceEntry(_devices.at(found)); - _devices.erase(_devices.begin() + found); + Z_Device & device = findShortAddr(shortaddr); + if (foundDevice(device)) { + _devices.remove(&device); dirty(); return true; } @@ -523,27 +481,27 @@ bool Z_Devices::removeDevice(uint16_t shortaddr) { // shortaddr // longaddr (both can't be null at the same time) void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) { - int32_t s_found = findShortAddrIdx(shortaddr); // is there already a shortaddr entry - int32_t l_found = findLongAddr(longaddr); // is there already a longaddr entry + Z_Device * s_found = &findShortAddr(shortaddr); // is there already a shortaddr entry + Z_Device * l_found = &findLongAddr(longaddr); // is there already a longaddr entry - if ((s_found >= 0) && (l_found >= 0)) { // both shortaddr and longaddr are already registered + if (foundDevice(*s_found) && foundDevice(*l_found)) { // both shortaddr and longaddr are already registered if (s_found == l_found) { } else { // they don't match // the device with longaddr got a new shortaddr - _devices[l_found]->shortaddr = shortaddr; // update the shortaddr corresponding to the longaddr + l_found->shortaddr = shortaddr; // update the shortaddr corresponding to the longaddr // erase the previous shortaddr - freeDeviceEntry(_devices.at(s_found)); - _devices.erase(_devices.begin() + s_found); + freeDeviceEntry(s_found); + _devices.remove(s_found); dirty(); } - } else if (s_found >= 0) { + } else if (foundDevice(*s_found)) { // shortaddr already exists but longaddr not // add the longaddr to the entry - _devices[s_found]->longaddr = longaddr; + s_found->longaddr = longaddr; dirty(); - } else if (l_found >= 0) { + } else if (foundDevice(*l_found)) { // longaddr entry exists, update shortaddr - _devices[l_found]->shortaddr = shortaddr; + l_found->shortaddr = shortaddr; dirty(); } else { // neither short/lonf addr are found. @@ -588,9 +546,8 @@ void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) { // uint32_t Z_Devices::countEndpoints(uint16_t shortaddr) const { uint32_t count_ep = 0; - int32_t found = findShortAddrIdx(shortaddr); - if (found < 0) return 0; // avoid creating an entry if the device was never seen - const Z_Device &device = devicesAt(found); + const Z_Device & device =findShortAddr(shortaddr); + if (!foundDevice(device)) return 0; for (uint32_t i = 0; i < endpoints_max; i++) { if (0 != device.endpoints[i]) { @@ -666,9 +623,8 @@ void Z_Devices::setBatteryPercent(uint16_t shortaddr, uint8_t bp) { // get the next sequance number for the device, or use the global seq number if device is unknown uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) { - int32_t short_found = findShortAddrIdx(shortaddr); - if (short_found >= 0) { - Z_Device &device = getShortAddr(shortaddr); + Z_Device & device = findShortAddr(shortaddr); + if (foundDevice(device)) { device.seqNumber += 1; return device.seqNumber; } else { @@ -754,9 +710,9 @@ void Z_Devices::hideHueBulb(uint16_t shortaddr, bool hidden) { } // true if device is not knwon or not a bulb - it wouldn't make sense to publish a non-bulb bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const { - int32_t found = findShortAddrIdx(shortaddr); - if (found >= 0) { - uint8_t zb_profile = _devices[found]->zb_profile; + const Z_Device & device = findShortAddr(shortaddr); + if (foundDevice(device)) { + uint8_t zb_profile = device.zb_profile; if (0x00 == (zb_profile & 0xF0)) { // bulb type return (zb_profile & 0x08) ? true : false; @@ -769,13 +725,10 @@ bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const { // Parse for a specific category, of all deferred for a device if category == 0xFF void Z_Devices::resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category) { // iterate the list of deferred, and remove any linked to the shortaddr - for (auto it = _deferred.begin(); it != _deferred.end(); it++) { - // Notice that the iterator is decremented after it is passed - // to erase() but before erase() is executed - // see https://www.techiedelight.com/remove-elements-vector-inside-loop-cpp/ - if ((it->shortaddr == shortaddr) && (it->groupaddr == groupaddr)) { - if ((0xFF == category) || (it->category == category)) { - _deferred.erase(it--); + for (auto & defer : _deferred) { + if ((defer.shortaddr == shortaddr) && (defer.groupaddr == groupaddr)) { + if ((0xFF == category) || (defer.category == category)) { + _deferred.remove(&defer); } } } @@ -789,7 +742,8 @@ void Z_Devices::setTimer(uint16_t shortaddr, uint16_t groupaddr, uint32_t wait_m } // Now create the new timer - Z_Deferred deferred = { wait_ms + millis(), // timer + Z_Deferred & deferred = _deferred.addHead(); + deferred = { wait_ms + millis(), // timer shortaddr, groupaddr, cluster, @@ -797,20 +751,17 @@ void Z_Devices::setTimer(uint16_t shortaddr, uint16_t groupaddr, uint32_t wait_m category, value, func }; - _deferred.push_back(deferred); } // Run timer at each tick // WARNING: don't set a new timer within a running timer, this causes memory corruption void Z_Devices::runTimer(void) { // visit all timers - for (auto it = _deferred.begin(); it != _deferred.end(); it++) { - Z_Deferred &defer = *it; - + for (auto & defer : _deferred) { uint32_t timer = defer.timer; if (TimeReached(timer)) { (*defer.func)(defer.shortaddr, defer.groupaddr, defer.cluster, defer.endpoint, defer.value); - _deferred.erase(it--); // remove from list + _deferred.remove(&defer); } } @@ -821,173 +772,100 @@ void Z_Devices::runTimer(void) { } } -// Clear the JSON buffer for coalesced and deferred attributes -void Z_Devices::jsonClear(uint16_t shortaddr) { - Z_Device & device = getShortAddr(shortaddr); - device.json = nullptr; - device.json_buffer->clear(); -} - -// Copy JSON from one object to another, this helps preserving the order of attributes -void CopyJsonVariant(JsonObject &to, const String &key, const JsonVariant &val) { - // first remove the potentially existing key in the target JSON, so new adds will be at the end of the list - to.remove(key); // force remove to have metadata like LinkQuality at the end - - if (val.is()) { - const char * sval = val.as(); // using char* forces a copy, and also captures 'null' values - to.set(key, (char*) sval); - } else if (val.is()) { - JsonArray &nested_arr = to.createNestedArray(key); - CopyJsonArray(nested_arr, val.as()); // deep copy - } else if (val.is()) { - JsonObject &nested_obj = to.createNestedObject(key); - CopyJsonObject(nested_obj, val.as()); // deep copy - } else { - to.set(key, val); // general case for non array, object or string - } -} - -// Shallow copy of array, we skip any sub-array or sub-object. It may be added in the future -void CopyJsonArray(JsonArray &to, const JsonArray &arr) { - for (auto v : arr) { - if (v.is()) { - String sval = v.as(); // force a copy of the String value - to.add(sval); - } else if (v.is()) { - } else if (v.is()) { - } else { - to.add(v); - } - } -} - -// Deep copy of object -void CopyJsonObject(JsonObject &to, const JsonObject &from) { - for (auto kv : from) { - String key_string = kv.key; - JsonVariant &val = kv.value; - - CopyJsonVariant(to, key_string, val); - } -} - // does the new payload conflicts with the existing payload, i.e. values would be overwritten // true - one attribute (except LinkQuality) woudl be lost, there is conflict // false - new attributes can be safely added -bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) { - Z_Device & device = getShortAddr(shortaddr); - if (&values == nullptr) { return false; } +bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const Z_attribute_list &attr_list) const { + const Z_Device & device = findShortAddr(shortaddr); - if (nullptr == device.json) { + if (!foundDevice(device)) { return false; } + if (attr_list.isEmpty()) { return false; // if no previous value, no conflict } // compare groups - // Special case for group addresses. Group attribute is only present if the target - // address is a group address, so just comparing attributes will not work. - // Eg: if the first packet has no group attribute, and the second does, conflict would not be detected - // Here we explicitly compute the group address of both messages, and compare them. No group means group=0x0000 - // (we use the property of an missing attribute returning 0) - // (note: we use .get() here which is case-sensitive. We know however that the attribute was set with the exact syntax D_CMND_ZIGBEE_GROUP, so we don't need a case-insensitive get()) - uint16_t group1 = device.json->get(D_CMND_ZIGBEE_GROUP); - uint16_t group2 = values.get(D_CMND_ZIGBEE_GROUP); - if (group1 != group2) { - return true; // if group addresses differ, then conflict + if (device.attr_list.isValidGroupId() && attr_list.isValidGroupId()) { + if (device.attr_list.group_id != attr_list.group_id) { return true; } // groups are in conflict } - // parse all other parameters - for (auto kv : values) { - String key_string = kv.key; + // compare src_ep + if (device.attr_list.isValidSrcEp() && attr_list.isValidSrcEp()) { + if (device.attr_list.src_ep != attr_list.src_ep) { return true; } + } + + // LQI does not count as conflicting - if (0 == strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_GROUP))) { - // ignore group, it was handled already - } else if (0 == strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_ENDPOINT))) { - // attribute "Endpoint" or "Group" - if (device.json->containsKey(kv.key)) { - if (kv.value.as() != device.json->get(kv.key)) { - return true; - } - } - } else if (strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_LINKQUALITY))) { // exception = ignore duplicates for LinkQuality - if (device.json->containsKey(kv.key)) { - return true; // conflict! + // parse all other parameters + for (const auto & attr : attr_list) { + const Z_attribute * curr_attr = device.attr_list.findAttribute(attr); + if (nullptr != curr_attr) { + if (!curr_attr->equalsVal(attr)) { + return true; // the value already exists and is different - conflict! } } } return false; } -void Z_Devices::jsonAppend(uint16_t shortaddr, const JsonObject &values) { +void Z_Devices::jsonAppend(uint16_t shortaddr, const Z_attribute_list &attr_list) { Z_Device & device = getShortAddr(shortaddr); - if (&values == nullptr) { return; } - - if (nullptr == device.json) { - device.json = &(device.json_buffer->createObject()); - } - // Prepend Device, will be removed later if redundant - char sa[8]; - snprintf_P(sa, sizeof(sa), PSTR("0x%04X"), shortaddr); - device.json->set(F(D_JSON_ZIGBEE_DEVICE), sa); - // Prepend Friendly Name if it has one - const char * fname = zigbee_devices.getFriendlyName(shortaddr); - if (fname) { - device.json->set(F(D_JSON_ZIGBEE_NAME), (char*) fname); // (char*) forces ArduinoJson to make a copy of the cstring - } - - // copy all values from 'values' to 'json' - CopyJsonObject(*device.json, values); -} - -const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) { - return getShortAddr(shortaddr).json; + device.attr_list.mergeList(attr_list); } void Z_Devices::jsonPublishFlush(uint16_t shortaddr) { Z_Device & device = getShortAddr(shortaddr); if (!device.valid()) { return; } // safeguard - JsonObject & json = *device.json; - if (&json == nullptr) { return; } // abort if nothing in buffer + Z_attribute_list &attr_list = device.attr_list; - const char * fname = zigbee_devices.getFriendlyName(shortaddr); - bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname? + if (!attr_list.isEmpty()) { + const char * fname = zigbee_devices.getFriendlyName(shortaddr); + bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname? - // save parameters is global variables to be used by Rules - gZbLastMessage.device = shortaddr; // %zbdevice% - gZbLastMessage.groupaddr = json[F(D_CMND_ZIGBEE_GROUP)]; // %zbgroup% - gZbLastMessage.cluster = json[F(D_CMND_ZIGBEE_CLUSTER)]; // %zbcluster% - gZbLastMessage.endpoint = json[F(D_CMND_ZIGBEE_ENDPOINT)]; // %zbendpoint% + // save parameters is global variables to be used by Rules + gZbLastMessage.device = shortaddr; // %zbdevice% + gZbLastMessage.groupaddr = attr_list.group_id; // %zbgroup% + gZbLastMessage.endpoint = attr_list.src_ep; // %zbendpoint% - // dump json in string - String msg = ""; - json.printTo(msg); - zigbee_devices.jsonClear(shortaddr); - - if (use_fname) { - if (Settings.flag4.remove_zbreceived) { - Response_P(PSTR("{\"%s\":%s}"), fname, msg.c_str()); - } else { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":{\"%s\":%s}}"), fname, msg.c_str()); + mqtt_data[0] = 0; // clear string + // Do we prefix with `ZbReceived`? + if (!Settings.flag4.remove_zbreceived) { + Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":")); } - } else { - if (Settings.flag4.remove_zbreceived) { - Response_P(PSTR("{\"0x%04X\":%s}"), shortaddr, msg.c_str()); + // What key do we use, shortaddr or name? + if (use_fname) { + Response_P(PSTR("%s{\"%s\":{"), mqtt_data, fname); } else { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str()); + Response_P(PSTR("%s{\"0x%04X\":{"), mqtt_data, shortaddr); } + // Add "Device":"0x...." + Response_P(PSTR("%s\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\","), mqtt_data, shortaddr); + // Add "Name":"xxx" if name is present + if (fname) { + Response_P(PSTR("%s\"" D_JSON_ZIGBEE_NAME "\":\"%s\","), mqtt_data, EscapeJSONString(fname).c_str()); + } + // Add all other attributes + Response_P(PSTR("%s%s}}"), mqtt_data, attr_list.toString().c_str()); + + if (!Settings.flag4.remove_zbreceived) { + Response_P(PSTR("%s}"), mqtt_data); + } + // AddLog_P2(LOG_LEVEL_INFO, PSTR(">>> %s"), mqtt_data); // TODO + attr_list.reset(); // clear the attributes + + if (Settings.flag4.zigbee_distinct_topics) { + char subtopic[16]; + snprintf_P(subtopic, sizeof(subtopic), PSTR("%04X/" D_RSLT_SENSOR), shortaddr); + MqttPublishPrefixTopic_P(TELE, subtopic, Settings.flag.mqtt_sensor_retain); + } else { + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); + } + XdrvRulesProcess(); // apply rules } - if (Settings.flag4.zigbee_distinct_topics) { - char subtopic[16]; - snprintf_P(subtopic, sizeof(subtopic), PSTR("%04X/" D_RSLT_SENSOR), shortaddr); - MqttPublishPrefixTopic_P(TELE, subtopic, Settings.flag.mqtt_sensor_retain); - } else { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - } - XdrvRulesProcess(); // apply rules } -void Z_Devices::jsonPublishNow(uint16_t shortaddr, JsonObject & values) { +void Z_Devices::jsonPublishNow(uint16_t shortaddr, Z_attribute_list &attr_list) { jsonPublishFlush(shortaddr); // flush any previous buffer - jsonAppend(shortaddr, values); + jsonAppend(shortaddr, attr_list); jsonPublishFlush(shortaddr); // publish now } @@ -1044,9 +922,8 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const { JsonObject& json = jsonBuffer.createObject(); char hex[8]; - int32_t found = findShortAddrIdx(shortaddr); - if (found >= 0) { - const Z_Device & device = devicesAt(found); + const Z_Device & device = findShortAddr(shortaddr); + if (foundDevice(device)) { const char * fname = getFriendlyName(shortaddr); bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname? @@ -1090,8 +967,7 @@ String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const { JsonArray& json = jsonBuffer.createArray(); JsonArray& devices = json; - for (std::vector::const_iterator it = _devices.begin(); it != _devices.end(); ++it) { - const Z_Device &device = **it; + for (const auto & device : _devices) { uint16_t shortaddr = device.shortaddr; char hex[22]; diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 5f7c0786b..5655244d7 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -90,18 +90,13 @@ bool Z_isDiscreteDataType(uint8_t t) { } } -// return value: -// 0 = keep initial value -// 1 = remove initial value -typedef int32_t (*Z_AttrConverter)(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); typedef struct Z_AttributeConverter { uint8_t type; uint8_t cluster_short; uint16_t attribute; uint16_t name_offset; int8_t multiplier; // multiplier for numerical value, (if > 0 multiply by x, if <0 device by x) - uint8_t cb; // callback func from Z_ConvOperators - // Z_AttrConverter func; + // still room for a byte } Z_AttributeConverter; // Cluster numbers are store in 8 bits format to save space, @@ -129,400 +124,391 @@ uint16_t CxToCluster(uint8_t cx) { } return 0xFFFF; } - -enum Z_ConvOperators { - Z_Nop, // copy value - Z_AddPressureUnit, // add pressure unit attribute (non numerical) - Z_ManufKeep, // copy and record Manufacturer attribute - Z_ModelKeep, // copy and record ModelId attribute - Z_AqaraSensor, // decode prioprietary Aqara Sensor message - Z_AqaraSensor2, // decode prioprietary Aqara Sensor message V2 - Z_AqaraVibration, // decode Aqara vibration modes - Z_AqaraCube, // decode Aqara cube - Z_AqaraButton, // decode Aqara button - Z_BatteryPercentage, // memorize Battery Percentage in RAM -}; - // list of post-processing directives const Z_AttributeConverter Z_PostProcess[] PROGMEM = { - { Zuint8, Cx0000, 0x0000, Z_(ZCLVersion), 1, Z_Nop }, - { Zuint8, Cx0000, 0x0001, Z_(AppVersion), 1, Z_Nop }, - { Zuint8, Cx0000, 0x0002, Z_(StackVersion), 1, Z_Nop }, - { Zuint8, Cx0000, 0x0003, Z_(HWVersion), 1, Z_Nop }, - { Zstring, Cx0000, 0x0004, Z_(Manufacturer), 1, Z_ManufKeep }, // record Manufacturer - { Zstring, Cx0000, 0x0005, Z_(ModelId), 1, Z_ModelKeep }, // record Model - { Zstring, Cx0000, 0x0006, Z_(DateCode), 1, Z_Nop }, - { Zenum8, Cx0000, 0x0007, Z_(PowerSource), 1, Z_Nop }, - { Zenum8, Cx0000, 0x0008, Z_(GenericDeviceClass), 1, Z_Nop }, - { Zenum8, Cx0000, 0x0009, Z_(GenericDeviceType), 1, Z_Nop }, - { Zoctstr, Cx0000, 0x000A, Z_(ProductCode), 1, Z_Nop }, - { Zstring, Cx0000, 0x000B, Z_(ProductURL), 1, Z_Nop }, - { Zstring, Cx0000, 0x4000, Z_(SWBuildID), 1, Z_Nop }, - // { Zunk, Cx0000, 0xFFFF, nullptr, 0, Z_Nop }, // Remove all other values + { Zuint8, Cx0000, 0x0000, Z_(ZCLVersion), 1 }, + { Zuint8, Cx0000, 0x0001, Z_(AppVersion), 1 }, + { Zuint8, Cx0000, 0x0002, Z_(StackVersion), 1 }, + { Zuint8, Cx0000, 0x0003, Z_(HWVersion), 1 }, + { Zstring, Cx0000, 0x0004, Z_(Manufacturer), 1 }, // record Manufacturer + { Zstring, Cx0000, 0x0005, Z_(ModelId), 1 }, // record Model + // { Zstring, Cx0000, 0x0004, Z_(Manufacturer), 1, Z_ManufKeep }, // record Manufacturer + // { Zstring, Cx0000, 0x0005, Z_(ModelId), 1, Z_ModelKeep }, // record Model + { Zstring, Cx0000, 0x0006, Z_(DateCode), 1 }, + { Zenum8, Cx0000, 0x0007, Z_(PowerSource), 1 }, + { Zenum8, Cx0000, 0x0008, Z_(GenericDeviceClass), 1 }, + { Zenum8, Cx0000, 0x0009, Z_(GenericDeviceType), 1 }, + { Zoctstr, Cx0000, 0x000A, Z_(ProductCode), 1 }, + { Zstring, Cx0000, 0x000B, Z_(ProductURL), 1 }, + { Zstring, Cx0000, 0x4000, Z_(SWBuildID), 1 }, + // { Zunk, Cx0000, 0xFFFF, nullptr, 0 }, // Remove all other values // Cmd 0x0A - Cluster 0x0000, attribute 0xFF01 - proprietary - { Zmap8, Cx0000, 0xFF01, Z_(), 0, Z_AqaraSensor }, - { Zmap8, Cx0000, 0xFF02, Z_(), 0, Z_AqaraSensor2 }, + { Zmap8, Cx0000, 0xFF01, Z_(), 0 }, + { Zmap8, Cx0000, 0xFF02, Z_(), 0 }, + // { Zmap8, Cx0000, 0xFF01, Z_(), 0, Z_AqaraSensor }, + // { Zmap8, Cx0000, 0xFF02, Z_(), 0, Z_AqaraSensor2 }, // Power Configuration cluster - { Zuint16, Cx0001, 0x0000, Z_(MainsVoltage), 1, Z_Nop }, - { Zuint8, Cx0001, 0x0001, Z_(MainsFrequency), 1, Z_Nop }, - { Zuint8, Cx0001, 0x0020, Z_(BatteryVoltage), -10,Z_Nop }, // divide by 10 - { Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), -2, Z_BatteryPercentage }, // divide by 2 + { Zuint16, Cx0001, 0x0000, Z_(MainsVoltage), 1 }, + { Zuint8, Cx0001, 0x0001, Z_(MainsFrequency), 1 }, + { Zuint8, Cx0001, 0x0020, Z_(BatteryVoltage), -10 }, // divide by 10 + { Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), -2 }, // divide by 2 + // { Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), -2, Z_BatteryPercentage }, // divide by 2 // Device Temperature Configuration cluster - { Zint16, Cx0002, 0x0000, Z_(CurrentTemperature), 1, Z_Nop }, - { Zint16, Cx0002, 0x0001, Z_(MinTempExperienced), 1, Z_Nop }, - { Zint16, Cx0002, 0x0002, Z_(MaxTempExperienced), 1, Z_Nop }, - { Zuint16, Cx0002, 0x0003, Z_(OverTempTotalDwell), 1, Z_Nop }, + { Zint16, Cx0002, 0x0000, Z_(CurrentTemperature), 1 }, + { Zint16, Cx0002, 0x0001, Z_(MinTempExperienced), 1 }, + { Zint16, Cx0002, 0x0002, Z_(MaxTempExperienced), 1 }, + { Zuint16, Cx0002, 0x0003, Z_(OverTempTotalDwell), 1 }, // Identify cluster - { Zuint16, Cx0003, 0x0000, Z_(IdentifyTime), 1, Z_Nop }, + { Zuint16, Cx0003, 0x0000, Z_(IdentifyTime), 1 }, // Groups cluster - { Zmap8, Cx0004, 0x0000, Z_(GroupNameSupport), 1, Z_Nop }, + { Zmap8, Cx0004, 0x0000, Z_(GroupNameSupport), 1 }, // Scenes cluster - { Zuint8, Cx0005, 0x0000, Z_(SceneCount), 1, Z_Nop }, - { Zuint8, Cx0005, 0x0001, Z_(CurrentScene), 1, Z_Nop }, - { Zuint16, Cx0005, 0x0002, Z_(CurrentGroup), 1, Z_Nop }, - { Zbool, Cx0005, 0x0003, Z_(SceneValid), 1, Z_Nop }, - //{ Zmap8, Cx0005, 0x0004, (NameSupport), 1, Z_Nop }, + { Zuint8, Cx0005, 0x0000, Z_(SceneCount), 1 }, + { Zuint8, Cx0005, 0x0001, Z_(CurrentScene), 1 }, + { Zuint16, Cx0005, 0x0002, Z_(CurrentGroup), 1 }, + { Zbool, Cx0005, 0x0003, Z_(SceneValid), 1 }, + //{ Zmap8, Cx0005, 0x0004, (NameSupport), 1 }, // On/off cluster - { Zbool, Cx0006, 0x0000, Z_(Power), 1, Z_Nop }, - { Zenum8, Cx0006, 0x4003, Z_(StartUpOnOff), 1, Z_Nop }, - { Zbool, Cx0006, 0x8000, Z_(Power), 1, Z_Nop }, // See 7280 + { Zbool, Cx0006, 0x0000, Z_(Power), 1 }, + { Zenum8, Cx0006, 0x4003, Z_(StartUpOnOff), 1 }, + { Zbool, Cx0006, 0x8000, Z_(Power), 1 }, // See 7280 // On/Off Switch Configuration cluster - { Zenum8, Cx0007, 0x0000, Z_(SwitchType), 1, Z_Nop }, + { Zenum8, Cx0007, 0x0000, Z_(SwitchType), 1 }, // Level Control cluster - { Zuint8, Cx0008, 0x0000, Z_(Dimmer), 1, Z_Nop }, - { Zmap8, Cx0008, 0x000F, Z_(DimmerOptions), 1, Z_Nop }, - { Zuint16, Cx0008, 0x0001, Z_(DimmerRemainingTime), 1, Z_Nop }, - { Zuint16, Cx0008, 0x0010, Z_(OnOffTransitionTime), 1, Z_Nop }, - // { Zuint8, Cx0008, 0x0011, (OnLevel), 1, Z_Nop }, - // { Zuint16, Cx0008, 0x0012, (OnTransitionTime), 1, Z_Nop }, - // { Zuint16, Cx0008, 0x0013, (OffTransitionTime), 1, Z_Nop }, - // { Zuint16, Cx0008, 0x0014, (DefaultMoveRate), 1, Z_Nop }, + { Zuint8, Cx0008, 0x0000, Z_(Dimmer), 1 }, + { Zmap8, Cx0008, 0x000F, Z_(DimmerOptions), 1 }, + { Zuint16, Cx0008, 0x0001, Z_(DimmerRemainingTime), 1 }, + { Zuint16, Cx0008, 0x0010, Z_(OnOffTransitionTime), 1 }, + // { Zuint8, Cx0008, 0x0011, (OnLevel), 1 }, + // { Zuint16, Cx0008, 0x0012, (OnTransitionTime), 1 }, + // { Zuint16, Cx0008, 0x0013, (OffTransitionTime), 1 }, + // { Zuint16, Cx0008, 0x0014, (DefaultMoveRate), 1 }, // Alarms cluster - { Zuint16, Cx0009, 0x0000, Z_(AlarmCount), 1, Z_Nop }, + { Zuint16, Cx0009, 0x0000, Z_(AlarmCount), 1 }, // Time cluster - { ZUTC, Cx000A, 0x0000, Z_(Time), 1, Z_Nop }, - { Zmap8, Cx000A, 0x0001, Z_(TimeStatus), 1, Z_Nop }, - { Zint32, Cx000A, 0x0002, Z_(TimeZone), 1, Z_Nop }, - { Zuint32, Cx000A, 0x0003, Z_(DstStart), 1, Z_Nop }, - { Zuint32, Cx000A, 0x0004, Z_(DstEnd), 1, Z_Nop }, - { Zint32, Cx000A, 0x0005, Z_(DstShift), 1, Z_Nop }, - { Zuint32, Cx000A, 0x0006, Z_(StandardTime), 1, Z_Nop }, - { Zuint32, Cx000A, 0x0007, Z_(LocalTime), 1, Z_Nop }, - { ZUTC, Cx000A, 0x0008, Z_(LastSetTime), 1, Z_Nop }, - { ZUTC, Cx000A, 0x0009, Z_(ValidUntilTime), 1, Z_Nop }, - { ZUTC, Cx000A, 0xFF00, Z_(TimeEpoch), 1, Z_Nop }, // Tasmota specific, epoch + { ZUTC, Cx000A, 0x0000, Z_(Time), 1 }, + { Zmap8, Cx000A, 0x0001, Z_(TimeStatus), 1 }, + { Zint32, Cx000A, 0x0002, Z_(TimeZone), 1 }, + { Zuint32, Cx000A, 0x0003, Z_(DstStart), 1 }, + { Zuint32, Cx000A, 0x0004, Z_(DstEnd), 1 }, + { Zint32, Cx000A, 0x0005, Z_(DstShift), 1 }, + { Zuint32, Cx000A, 0x0006, Z_(StandardTime), 1 }, + { Zuint32, Cx000A, 0x0007, Z_(LocalTime), 1 }, + { ZUTC, Cx000A, 0x0008, Z_(LastSetTime), 1 }, + { ZUTC, Cx000A, 0x0009, Z_(ValidUntilTime), 1 }, + { ZUTC, Cx000A, 0xFF00, Z_(TimeEpoch), 1 }, // Tasmota specific, epoch // RSSI Location cluster - { Zdata8, Cx000B, 0x0000, Z_(LocationType), 1, Z_Nop }, - { Zenum8, Cx000B, 0x0001, Z_(LocationMethod), 1, Z_Nop }, - { Zuint16, Cx000B, 0x0002, Z_(LocationAge), 1, Z_Nop }, - { Zuint8, Cx000B, 0x0003, Z_(QualityMeasure), 1, Z_Nop }, - { Zuint8, Cx000B, 0x0004, Z_(NumberOfDevices), 1, Z_Nop }, + { Zdata8, Cx000B, 0x0000, Z_(LocationType), 1 }, + { Zenum8, Cx000B, 0x0001, Z_(LocationMethod), 1 }, + { Zuint16, Cx000B, 0x0002, Z_(LocationAge), 1 }, + { Zuint8, Cx000B, 0x0003, Z_(QualityMeasure), 1 }, + { Zuint8, Cx000B, 0x0004, Z_(NumberOfDevices), 1 }, // Analog Input cluster - // { 0xFF, Cx000C, 0x0004, (AnalogInActiveText), 1, Z_Nop }, - { Zstring, Cx000C, 0x001C, Z_(AnalogInDescription), 1, Z_Nop }, - // { 0xFF, Cx000C, 0x002E, (AnalogInInactiveText), 1, Z_Nop }, - { Zsingle, Cx000C, 0x0041, Z_(AnalogInMaxValue), 1, Z_Nop }, - { Zsingle, Cx000C, 0x0045, Z_(AnalogInMinValue), 1, Z_Nop }, - { Zbool, Cx000C, 0x0051, Z_(AnalogInOutOfService), 1, Z_Nop }, - { Zsingle, Cx000C, 0x0055, Z_(AqaraRotate), 1, Z_Nop }, - // { 0xFF, Cx000C, 0x0057, (AnalogInPriorityArray),1, Z_Nop }, - { Zenum8, Cx000C, 0x0067, Z_(AnalogInReliability), 1, Z_Nop }, - // { 0xFF, Cx000C, 0x0068, (AnalogInRelinquishDefault),1, Z_Nop }, - { Zsingle, Cx000C, 0x006A, Z_(AnalogInResolution), 1, Z_Nop }, - { Zmap8, Cx000C, 0x006F, Z_(AnalogInStatusFlags), 1, Z_Nop }, - { Zenum16, Cx000C, 0x0075, Z_(AnalogInEngineeringUnits),1, Z_Nop }, - { Zuint32, Cx000C, 0x0100, Z_(AnalogInApplicationType),1, Z_Nop }, - { Zuint16, Cx000C, 0xFF05, Z_(Aqara_FF05), 1, Z_Nop }, + // { 0xFF, Cx000C, 0x0004, (AnalogInActiveText), 1 }, + { Zstring, Cx000C, 0x001C, Z_(AnalogInDescription), 1 }, + // { 0xFF, Cx000C, 0x002E, (AnalogInInactiveText), 1 }, + { Zsingle, Cx000C, 0x0041, Z_(AnalogInMaxValue), 1 }, + { Zsingle, Cx000C, 0x0045, Z_(AnalogInMinValue), 1 }, + { Zbool, Cx000C, 0x0051, Z_(AnalogInOutOfService), 1 }, + { Zsingle, Cx000C, 0x0055, Z_(AqaraRotate), 1 }, + // { 0xFF, Cx000C, 0x0057, (AnalogInPriorityArray),1 }, + { Zenum8, Cx000C, 0x0067, Z_(AnalogInReliability), 1 }, + // { 0xFF, Cx000C, 0x0068, (AnalogInRelinquishDefault),1 }, + { Zsingle, Cx000C, 0x006A, Z_(AnalogInResolution), 1 }, + { Zmap8, Cx000C, 0x006F, Z_(AnalogInStatusFlags), 1 }, + { Zenum16, Cx000C, 0x0075, Z_(AnalogInEngineeringUnits),1 }, + { Zuint32, Cx000C, 0x0100, Z_(AnalogInApplicationType),1 }, + { Zuint16, Cx000C, 0xFF05, Z_(Aqara_FF05), 1 }, // Analog Output cluster - { Zstring, Cx000D, 0x001C, Z_(AnalogOutDescription), 1, Z_Nop }, - { Zsingle, Cx000D, 0x0041, Z_(AnalogOutMaxValue), 1, Z_Nop }, - { Zsingle, Cx000D, 0x0045, Z_(AnalogOutMinValue), 1, Z_Nop }, - { Zbool, Cx000D, 0x0051, Z_(AnalogOutOutOfService),1, Z_Nop }, - { Zsingle, Cx000D, 0x0055, Z_(AnalogOutValue), 1, Z_Nop }, - // { Zunk, Cx000D, 0x0057, (AnalogOutPriorityArray),1, Z_Nop }, - { Zenum8, Cx000D, 0x0067, Z_(AnalogOutReliability), 1, Z_Nop }, - { Zsingle, Cx000D, 0x0068, Z_(AnalogOutRelinquishDefault),1, Z_Nop }, - { Zsingle, Cx000D, 0x006A, Z_(AnalogOutResolution), 1, Z_Nop }, - { Zmap8, Cx000D, 0x006F, Z_(AnalogOutStatusFlags), 1, Z_Nop }, - { Zenum16, Cx000D, 0x0075, Z_(AnalogOutEngineeringUnits),1, Z_Nop }, - { Zuint32, Cx000D, 0x0100, Z_(AnalogOutApplicationType),1, Z_Nop }, + { Zstring, Cx000D, 0x001C, Z_(AnalogOutDescription), 1 }, + { Zsingle, Cx000D, 0x0041, Z_(AnalogOutMaxValue), 1 }, + { Zsingle, Cx000D, 0x0045, Z_(AnalogOutMinValue), 1 }, + { Zbool, Cx000D, 0x0051, Z_(AnalogOutOutOfService),1 }, + { Zsingle, Cx000D, 0x0055, Z_(AnalogOutValue), 1 }, + // { Zunk, Cx000D, 0x0057, (AnalogOutPriorityArray),1 }, + { Zenum8, Cx000D, 0x0067, Z_(AnalogOutReliability), 1 }, + { Zsingle, Cx000D, 0x0068, Z_(AnalogOutRelinquishDefault),1 }, + { Zsingle, Cx000D, 0x006A, Z_(AnalogOutResolution), 1 }, + { Zmap8, Cx000D, 0x006F, Z_(AnalogOutStatusFlags), 1 }, + { Zenum16, Cx000D, 0x0075, Z_(AnalogOutEngineeringUnits),1 }, + { Zuint32, Cx000D, 0x0100, Z_(AnalogOutApplicationType),1 }, // Analog Value cluster - { Zstring, Cx000E, 0x001C, Z_(AnalogDescription), 1, Z_Nop }, - { Zbool, Cx000E, 0x0051, Z_(AnalogOutOfService), 1, Z_Nop }, - { Zsingle, Cx000E, 0x0055, Z_(AnalogValue), 1, Z_Nop }, - { Zunk, Cx000E, 0x0057, Z_(AnalogPriorityArray), 1, Z_Nop }, - { Zenum8, Cx000E, 0x0067, Z_(AnalogReliability), 1, Z_Nop }, - { Zsingle, Cx000E, 0x0068, Z_(AnalogRelinquishDefault),1, Z_Nop }, - { Zmap8, Cx000E, 0x006F, Z_(AnalogStatusFlags), 1, Z_Nop }, - { Zenum16, Cx000E, 0x0075, Z_(AnalogEngineeringUnits),1, Z_Nop }, - { Zuint32, Cx000E, 0x0100, Z_(AnalogApplicationType),1, Z_Nop }, + { Zstring, Cx000E, 0x001C, Z_(AnalogDescription), 1 }, + { Zbool, Cx000E, 0x0051, Z_(AnalogOutOfService), 1 }, + { Zsingle, Cx000E, 0x0055, Z_(AnalogValue), 1 }, + { Zunk, Cx000E, 0x0057, Z_(AnalogPriorityArray), 1 }, + { Zenum8, Cx000E, 0x0067, Z_(AnalogReliability), 1 }, + { Zsingle, Cx000E, 0x0068, Z_(AnalogRelinquishDefault),1 }, + { Zmap8, Cx000E, 0x006F, Z_(AnalogStatusFlags), 1 }, + { Zenum16, Cx000E, 0x0075, Z_(AnalogEngineeringUnits),1 }, + { Zuint32, Cx000E, 0x0100, Z_(AnalogApplicationType),1 }, // Binary Input cluster - { Zstring, Cx000F, 0x0004, Z_(BinaryInActiveText), 1, Z_Nop }, - { Zstring, Cx000F, 0x001C, Z_(BinaryInDescription), 1, Z_Nop }, - { Zstring, Cx000F, 0x002E, Z_(BinaryInInactiveText),1, Z_Nop }, - { Zbool, Cx000F, 0x0051, Z_(BinaryInOutOfService),1, Z_Nop }, - { Zenum8, Cx000F, 0x0054, Z_(BinaryInPolarity), 1, Z_Nop }, - { Zstring, Cx000F, 0x0055, Z_(BinaryInValue), 1, Z_Nop }, - // { 0xFF, Cx000F, 0x0057, (BinaryInPriorityArray),1, Z_Nop }, - { Zenum8, Cx000F, 0x0067, Z_(BinaryInReliability), 1, Z_Nop }, - { Zmap8, Cx000F, 0x006F, Z_(BinaryInStatusFlags), 1, Z_Nop }, - { Zuint32, Cx000F, 0x0100, Z_(BinaryInApplicationType),1, Z_Nop }, + { Zstring, Cx000F, 0x0004, Z_(BinaryInActiveText), 1 }, + { Zstring, Cx000F, 0x001C, Z_(BinaryInDescription), 1 }, + { Zstring, Cx000F, 0x002E, Z_(BinaryInInactiveText),1 }, + { Zbool, Cx000F, 0x0051, Z_(BinaryInOutOfService),1 }, + { Zenum8, Cx000F, 0x0054, Z_(BinaryInPolarity), 1 }, + { Zstring, Cx000F, 0x0055, Z_(BinaryInValue), 1 }, + // { 0xFF, Cx000F, 0x0057, (BinaryInPriorityArray),1 }, + { Zenum8, Cx000F, 0x0067, Z_(BinaryInReliability), 1 }, + { Zmap8, Cx000F, 0x006F, Z_(BinaryInStatusFlags), 1 }, + { Zuint32, Cx000F, 0x0100, Z_(BinaryInApplicationType),1 }, // Binary Output cluster - { Zstring, Cx0010, 0x0004, Z_(BinaryOutActiveText), 1, Z_Nop }, - { Zstring, Cx0010, 0x001C, Z_(BinaryOutDescription), 1, Z_Nop }, - { Zstring, Cx0010, 0x002E, Z_(BinaryOutInactiveText),1, Z_Nop }, - { Zuint32, Cx0010, 0x0042, Z_(BinaryOutMinimumOffTime),1, Z_Nop }, - { Zuint32, Cx0010, 0x0043, Z_(BinaryOutMinimumOnTime),1, Z_Nop }, - { Zbool, Cx0010, 0x0051, Z_(BinaryOutOutOfService),1, Z_Nop }, - { Zenum8, Cx0010, 0x0054, Z_(BinaryOutPolarity), 1, Z_Nop }, - { Zbool, Cx0010, 0x0055, Z_(BinaryOutValue), 1, Z_Nop }, - // { Zunk, Cx0010, 0x0057, (BinaryOutPriorityArray),1, Z_Nop }, - { Zenum8, Cx0010, 0x0067, Z_(BinaryOutReliability), 1, Z_Nop }, - { Zbool, Cx0010, 0x0068, Z_(BinaryOutRelinquishDefault),1, Z_Nop }, - { Zmap8, Cx0010, 0x006F, Z_(BinaryOutStatusFlags), 1, Z_Nop }, - { Zuint32, Cx0010, 0x0100, Z_(BinaryOutApplicationType),1, Z_Nop }, + { Zstring, Cx0010, 0x0004, Z_(BinaryOutActiveText), 1 }, + { Zstring, Cx0010, 0x001C, Z_(BinaryOutDescription), 1 }, + { Zstring, Cx0010, 0x002E, Z_(BinaryOutInactiveText),1 }, + { Zuint32, Cx0010, 0x0042, Z_(BinaryOutMinimumOffTime),1 }, + { Zuint32, Cx0010, 0x0043, Z_(BinaryOutMinimumOnTime),1 }, + { Zbool, Cx0010, 0x0051, Z_(BinaryOutOutOfService),1 }, + { Zenum8, Cx0010, 0x0054, Z_(BinaryOutPolarity), 1 }, + { Zbool, Cx0010, 0x0055, Z_(BinaryOutValue), 1 }, + // { Zunk, Cx0010, 0x0057, (BinaryOutPriorityArray),1 }, + { Zenum8, Cx0010, 0x0067, Z_(BinaryOutReliability), 1 }, + { Zbool, Cx0010, 0x0068, Z_(BinaryOutRelinquishDefault),1 }, + { Zmap8, Cx0010, 0x006F, Z_(BinaryOutStatusFlags), 1 }, + { Zuint32, Cx0010, 0x0100, Z_(BinaryOutApplicationType),1 }, // Binary Value cluster - { Zstring, Cx0011, 0x0004, Z_(BinaryActiveText), 1, Z_Nop }, - { Zstring, Cx0011, 0x001C, Z_(BinaryDescription), 1, Z_Nop }, - { Zstring, Cx0011, 0x002E, Z_(BinaryInactiveText), 1, Z_Nop }, - { Zuint32, Cx0011, 0x0042, Z_(BinaryMinimumOffTime), 1, Z_Nop }, - { Zuint32, Cx0011, 0x0043, Z_(BinaryMinimumOnTime), 1, Z_Nop }, - { Zbool, Cx0011, 0x0051, Z_(BinaryOutOfService), 1, Z_Nop }, - { Zbool, Cx0011, 0x0055, Z_(BinaryValue), 1, Z_Nop }, - // { Zunk, Cx0011, 0x0057, (BinaryPriorityArray), 1, Z_Nop }, - { Zenum8, Cx0011, 0x0067, Z_(BinaryReliability), 1, Z_Nop }, - { Zbool, Cx0011, 0x0068, Z_(BinaryRelinquishDefault),1, Z_Nop }, - { Zmap8, Cx0011, 0x006F, Z_(BinaryStatusFlags), 1, Z_Nop }, - { Zuint32, Cx0011, 0x0100, Z_(BinaryApplicationType),1, Z_Nop }, + { Zstring, Cx0011, 0x0004, Z_(BinaryActiveText), 1 }, + { Zstring, Cx0011, 0x001C, Z_(BinaryDescription), 1 }, + { Zstring, Cx0011, 0x002E, Z_(BinaryInactiveText), 1 }, + { Zuint32, Cx0011, 0x0042, Z_(BinaryMinimumOffTime), 1 }, + { Zuint32, Cx0011, 0x0043, Z_(BinaryMinimumOnTime), 1 }, + { Zbool, Cx0011, 0x0051, Z_(BinaryOutOfService), 1 }, + { Zbool, Cx0011, 0x0055, Z_(BinaryValue), 1 }, + // { Zunk, Cx0011, 0x0057, (BinaryPriorityArray), 1 }, + { Zenum8, Cx0011, 0x0067, Z_(BinaryReliability), 1 }, + { Zbool, Cx0011, 0x0068, Z_(BinaryRelinquishDefault),1 }, + { Zmap8, Cx0011, 0x006F, Z_(BinaryStatusFlags), 1 }, + { Zuint32, Cx0011, 0x0100, Z_(BinaryApplicationType),1 }, // Multistate Input cluster - // { Zunk, Cx0012, 0x000E, (MultiInStateText), 1, Z_Nop }, - { Zstring, Cx0012, 0x001C, Z_(MultiInDescription), 1, Z_Nop }, - { Zuint16, Cx0012, 0x004A, Z_(MultiInNumberOfStates),1, Z_Nop }, - { Zbool, Cx0012, 0x0051, Z_(MultiInOutOfService), 1, Z_Nop }, - { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 0, Z_AqaraCube }, - { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 0, Z_AqaraButton }, - { Zenum8, Cx0012, 0x0067, Z_(MultiInReliability), 1, Z_Nop }, - { Zmap8, Cx0012, 0x006F, Z_(MultiInStatusFlags), 1, Z_Nop }, - { Zuint32, Cx0012, 0x0100, Z_(MultiInApplicationType),1, Z_Nop }, + // { Zunk, Cx0012, 0x000E, (MultiInStateText), 1 }, + { Zstring, Cx0012, 0x001C, Z_(MultiInDescription), 1 }, + { Zuint16, Cx0012, 0x004A, Z_(MultiInNumberOfStates),1 }, + { Zbool, Cx0012, 0x0051, Z_(MultiInOutOfService), 1 }, + { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 1 }, + // { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 0, Z_AqaraCube }, + // { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 0, Z_AqaraButton }, + { Zenum8, Cx0012, 0x0067, Z_(MultiInReliability), 1 }, + { Zmap8, Cx0012, 0x006F, Z_(MultiInStatusFlags), 1 }, + { Zuint32, Cx0012, 0x0100, Z_(MultiInApplicationType),1 }, // Multistate output - // { Zunk, Cx0013, 0x000E, (MultiOutStateText), 1, Z_Nop }, - { Zstring, Cx0013, 0x001C, Z_(MultiOutDescription), 1, Z_Nop }, - { Zuint16, Cx0013, 0x004A, Z_(MultiOutNumberOfStates),1, Z_Nop }, - { Zbool, Cx0013, 0x0051, Z_(MultiOutOutOfService), 1, Z_Nop }, - { Zuint16, Cx0013, 0x0055, Z_(MultiOutValue), 1, Z_Nop }, - // { Zunk, Cx0013, 0x0057, (MultiOutPriorityArray),1, Z_Nop }, - { Zenum8, Cx0013, 0x0067, Z_(MultiOutReliability), 1, Z_Nop }, - { Zuint16, Cx0013, 0x0068, Z_(MultiOutRelinquishDefault),1, Z_Nop }, - { Zmap8, Cx0013, 0x006F, Z_(MultiOutStatusFlags), 1, Z_Nop }, - { Zuint32, Cx0013, 0x0100, Z_(MultiOutApplicationType),1, Z_Nop }, + // { Zunk, Cx0013, 0x000E, (MultiOutStateText), 1 }, + { Zstring, Cx0013, 0x001C, Z_(MultiOutDescription), 1 }, + { Zuint16, Cx0013, 0x004A, Z_(MultiOutNumberOfStates),1 }, + { Zbool, Cx0013, 0x0051, Z_(MultiOutOutOfService), 1 }, + { Zuint16, Cx0013, 0x0055, Z_(MultiOutValue), 1 }, + // { Zunk, Cx0013, 0x0057, (MultiOutPriorityArray),1 }, + { Zenum8, Cx0013, 0x0067, Z_(MultiOutReliability), 1 }, + { Zuint16, Cx0013, 0x0068, Z_(MultiOutRelinquishDefault),1 }, + { Zmap8, Cx0013, 0x006F, Z_(MultiOutStatusFlags), 1 }, + { Zuint32, Cx0013, 0x0100, Z_(MultiOutApplicationType),1 }, // Multistate Value cluster - // { Zunk, Cx0014, 0x000E, (MultiStateText), 1, Z_Nop }, - { Zstring, Cx0014, 0x001C, Z_(MultiDescription), 1, Z_Nop }, - { Zuint16, Cx0014, 0x004A, Z_(MultiNumberOfStates), 1, Z_Nop }, - { Zbool, Cx0014, 0x0051, Z_(MultiOutOfService), 1, Z_Nop }, - { Zuint16, Cx0014, 0x0055, Z_(MultiValue), 1, Z_Nop }, - { Zenum8, Cx0014, 0x0067, Z_(MultiReliability), 1, Z_Nop }, - { Zuint16, Cx0014, 0x0068, Z_(MultiRelinquishDefault),1, Z_Nop }, - { Zmap8, Cx0014, 0x006F, Z_(MultiStatusFlags), 1, Z_Nop }, - { Zuint32, Cx0014, 0x0100, Z_(MultiApplicationType), 1, Z_Nop }, + // { Zunk, Cx0014, 0x000E, (MultiStateText), 1 }, + { Zstring, Cx0014, 0x001C, Z_(MultiDescription), 1 }, + { Zuint16, Cx0014, 0x004A, Z_(MultiNumberOfStates), 1 }, + { Zbool, Cx0014, 0x0051, Z_(MultiOutOfService), 1 }, + { Zuint16, Cx0014, 0x0055, Z_(MultiValue), 1 }, + { Zenum8, Cx0014, 0x0067, Z_(MultiReliability), 1 }, + { Zuint16, Cx0014, 0x0068, Z_(MultiRelinquishDefault),1 }, + { Zmap8, Cx0014, 0x006F, Z_(MultiStatusFlags), 1 }, + { Zuint32, Cx0014, 0x0100, Z_(MultiApplicationType), 1 }, // Power Profile cluster - { Zuint8, Cx001A, 0x0000, Z_(TotalProfileNum), 1, Z_Nop }, - { Zbool, Cx001A, 0x0001, Z_(MultipleScheduling), 1, Z_Nop }, - { Zmap8, Cx001A, 0x0002, Z_(EnergyFormatting), 1, Z_Nop }, - { Zbool, Cx001A, 0x0003, Z_(EnergyRemote), 1, Z_Nop }, - { Zmap8, Cx001A, 0x0004, Z_(ScheduleMode), 1, Z_Nop }, + { Zuint8, Cx001A, 0x0000, Z_(TotalProfileNum), 1 }, + { Zbool, Cx001A, 0x0001, Z_(MultipleScheduling), 1 }, + { Zmap8, Cx001A, 0x0002, Z_(EnergyFormatting), 1 }, + { Zbool, Cx001A, 0x0003, Z_(EnergyRemote), 1 }, + { Zmap8, Cx001A, 0x0004, Z_(ScheduleMode), 1 }, // Poll Control cluster - { Zuint32, Cx0020, 0x0000, Z_(CheckinInterval), 1, Z_Nop }, - { Zuint32, Cx0020, 0x0001, Z_(LongPollInterval), 1, Z_Nop }, - { Zuint16, Cx0020, 0x0002, Z_(ShortPollInterval), 1, Z_Nop }, - { Zuint16, Cx0020, 0x0003, Z_(FastPollTimeout), 1, Z_Nop }, - { Zuint32, Cx0020, 0x0004, Z_(CheckinIntervalMin), 1, Z_Nop }, - { Zuint32, Cx0020, 0x0005, Z_(LongPollIntervalMin), 1, Z_Nop }, - { Zuint16, Cx0020, 0x0006, Z_(FastPollTimeoutMax), 1, Z_Nop }, + { Zuint32, Cx0020, 0x0000, Z_(CheckinInterval), 1 }, + { Zuint32, Cx0020, 0x0001, Z_(LongPollInterval), 1 }, + { Zuint16, Cx0020, 0x0002, Z_(ShortPollInterval), 1 }, + { Zuint16, Cx0020, 0x0003, Z_(FastPollTimeout), 1 }, + { Zuint32, Cx0020, 0x0004, Z_(CheckinIntervalMin), 1 }, + { Zuint32, Cx0020, 0x0005, Z_(LongPollIntervalMin), 1 }, + { Zuint16, Cx0020, 0x0006, Z_(FastPollTimeoutMax), 1 }, // Shade Configuration cluster - { Zuint16, Cx0100, 0x0000, Z_(PhysicalClosedLimit), 1, Z_Nop }, - { Zuint8, Cx0100, 0x0001, Z_(MotorStepSize), 1, Z_Nop }, - { Zmap8, Cx0100, 0x0002, Z_(Status), 1, Z_Nop }, - { Zuint16, Cx0100, 0x0010, Z_(ClosedLimit), 1, Z_Nop }, - { Zenum8, Cx0100, 0x0011, Z_(Mode), 1, Z_Nop }, + { Zuint16, Cx0100, 0x0000, Z_(PhysicalClosedLimit), 1 }, + { Zuint8, Cx0100, 0x0001, Z_(MotorStepSize), 1 }, + { Zmap8, Cx0100, 0x0002, Z_(Status), 1 }, + { Zuint16, Cx0100, 0x0010, Z_(ClosedLimit), 1 }, + { Zenum8, Cx0100, 0x0011, Z_(Mode), 1 }, // Door Lock cluster - { Zenum8, Cx0101, 0x0000, Z_(LockState), 1, Z_Nop }, - { Zenum8, Cx0101, 0x0001, Z_(LockType), 1, Z_Nop }, - { Zbool, Cx0101, 0x0002, Z_(ActuatorEnabled), 1, Z_Nop }, - { Zenum8, Cx0101, 0x0003, Z_(DoorState), 1, Z_Nop }, - { Zuint32, Cx0101, 0x0004, Z_(DoorOpenEvents), 1, Z_Nop }, - { Zuint32, Cx0101, 0x0005, Z_(DoorClosedEvents), 1, Z_Nop }, - { Zuint16, Cx0101, 0x0006, Z_(OpenPeriod), 1, Z_Nop }, + { Zenum8, Cx0101, 0x0000, Z_(LockState), 1 }, + { Zenum8, Cx0101, 0x0001, Z_(LockType), 1 }, + { Zbool, Cx0101, 0x0002, Z_(ActuatorEnabled), 1 }, + { Zenum8, Cx0101, 0x0003, Z_(DoorState), 1 }, + { Zuint32, Cx0101, 0x0004, Z_(DoorOpenEvents), 1 }, + { Zuint32, Cx0101, 0x0005, Z_(DoorClosedEvents), 1 }, + { Zuint16, Cx0101, 0x0006, Z_(OpenPeriod), 1 }, // Aqara Lumi Vibration Sensor - { Zuint16, Cx0101, 0x0055, Z_(AqaraVibrationMode), 0, Z_AqaraVibration }, - { Zuint16, Cx0101, 0x0503, Z_(AqaraVibrationsOrAngle), 1, Z_Nop }, - { Zuint32, Cx0101, 0x0505, Z_(AqaraVibration505), 1, Z_Nop }, - { Zuint48, Cx0101, 0x0508, Z_(AqaraAccelerometer), 0, Z_AqaraVibration }, + { Zuint16, Cx0101, 0x0055, Z_(AqaraVibrationMode), 1 }, + { Zuint16, Cx0101, 0x0503, Z_(AqaraVibrationsOrAngle), 1 }, + { Zuint32, Cx0101, 0x0505, Z_(AqaraVibration505), 1 }, + { Zuint48, Cx0101, 0x0508, Z_(AqaraAccelerometer), 1 }, // Window Covering cluster - { Zenum8, Cx0102, 0x0000, Z_(WindowCoveringType), 1, Z_Nop }, - { Zuint16, Cx0102, 0x0001, Z_(PhysicalClosedLimitLift),1, Z_Nop }, - { Zuint16, Cx0102, 0x0002, Z_(PhysicalClosedLimitTilt),1, Z_Nop }, - { Zuint16, Cx0102, 0x0003, Z_(CurrentPositionLift), 1, Z_Nop }, - { Zuint16, Cx0102, 0x0004, Z_(CurrentPositionTilt), 1, Z_Nop }, - { Zuint16, Cx0102, 0x0005, Z_(NumberofActuationsLift),1, Z_Nop }, - { Zuint16, Cx0102, 0x0006, Z_(NumberofActuationsTilt),1, Z_Nop }, - { Zmap8, Cx0102, 0x0007, Z_(ConfigStatus), 1, Z_Nop }, - { Zuint8, Cx0102, 0x0008, Z_(CurrentPositionLiftPercentage),1, Z_Nop }, - { Zuint8, Cx0102, 0x0009, Z_(CurrentPositionTiltPercentage),1, Z_Nop }, - { Zuint16, Cx0102, 0x0010, Z_(InstalledOpenLimitLift),1, Z_Nop }, - { Zuint16, Cx0102, 0x0011, Z_(InstalledClosedLimitLift),1, Z_Nop }, - { Zuint16, Cx0102, 0x0012, Z_(InstalledOpenLimitTilt),1, Z_Nop }, - { Zuint16, Cx0102, 0x0013, Z_(InstalledClosedLimitTilt),1, Z_Nop }, - { Zuint16, Cx0102, 0x0014, Z_(VelocityLift), 1, Z_Nop }, - { Zuint16, Cx0102, 0x0015, Z_(AccelerationTimeLift),1, Z_Nop }, - { Zuint16, Cx0102, 0x0016, Z_(DecelerationTimeLift), 1, Z_Nop }, - { Zmap8, Cx0102, 0x0017, Z_(Mode), 1, Z_Nop }, - { Zoctstr, Cx0102, 0x0018, Z_(IntermediateSetpointsLift),1, Z_Nop }, - { Zoctstr, Cx0102, 0x0019, Z_(IntermediateSetpointsTilt),1, Z_Nop }, + { Zenum8, Cx0102, 0x0000, Z_(WindowCoveringType), 1 }, + { Zuint16, Cx0102, 0x0001, Z_(PhysicalClosedLimitLift),1 }, + { Zuint16, Cx0102, 0x0002, Z_(PhysicalClosedLimitTilt),1 }, + { Zuint16, Cx0102, 0x0003, Z_(CurrentPositionLift), 1 }, + { Zuint16, Cx0102, 0x0004, Z_(CurrentPositionTilt), 1 }, + { Zuint16, Cx0102, 0x0005, Z_(NumberofActuationsLift),1 }, + { Zuint16, Cx0102, 0x0006, Z_(NumberofActuationsTilt),1 }, + { Zmap8, Cx0102, 0x0007, Z_(ConfigStatus), 1 }, + { Zuint8, Cx0102, 0x0008, Z_(CurrentPositionLiftPercentage),1 }, + { Zuint8, Cx0102, 0x0009, Z_(CurrentPositionTiltPercentage),1 }, + { Zuint16, Cx0102, 0x0010, Z_(InstalledOpenLimitLift),1 }, + { Zuint16, Cx0102, 0x0011, Z_(InstalledClosedLimitLift),1 }, + { Zuint16, Cx0102, 0x0012, Z_(InstalledOpenLimitTilt),1 }, + { Zuint16, Cx0102, 0x0013, Z_(InstalledClosedLimitTilt),1 }, + { Zuint16, Cx0102, 0x0014, Z_(VelocityLift), 1 }, + { Zuint16, Cx0102, 0x0015, Z_(AccelerationTimeLift),1 }, + { Zuint16, Cx0102, 0x0016, Z_(DecelerationTimeLift), 1 }, + { Zmap8, Cx0102, 0x0017, Z_(Mode), 1 }, + { Zoctstr, Cx0102, 0x0018, Z_(IntermediateSetpointsLift),1 }, + { Zoctstr, Cx0102, 0x0019, Z_(IntermediateSetpointsTilt),1 }, // Color Control cluster - { Zuint8, Cx0300, 0x0000, Z_(Hue), 1, Z_Nop }, - { Zuint8, Cx0300, 0x0001, Z_(Sat), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0002, Z_(RemainingTime), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0003, Z_(X), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0004, Z_(Y), 1, Z_Nop }, - { Zenum8, Cx0300, 0x0005, Z_(DriftCompensation), 1, Z_Nop }, - { Zstring, Cx0300, 0x0006, Z_(CompensationText), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0007, Z_(CT), 1, Z_Nop }, - { Zenum8, Cx0300, 0x0008, Z_(ColorMode), 1, Z_Nop }, - { Zuint8, Cx0300, 0x0010, Z_(NumberOfPrimaries), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0011, Z_(Primary1X), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0012, Z_(Primary1Y), 1, Z_Nop }, - { Zuint8, Cx0300, 0x0013, Z_(Primary1Intensity), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0015, Z_(Primary2X), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0016, Z_(Primary2Y), 1, Z_Nop }, - { Zuint8, Cx0300, 0x0017, Z_(Primary2Intensity), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0019, Z_(Primary3X), 1, Z_Nop }, - { Zuint16, Cx0300, 0x001A, Z_(Primary3Y), 1, Z_Nop }, - { Zuint8, Cx0300, 0x001B, Z_(Primary3Intensity), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0030, Z_(WhitePointX), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0031, Z_(WhitePointY), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0032, Z_(ColorPointRX), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0033, Z_(ColorPointRY), 1, Z_Nop }, - { Zuint8, Cx0300, 0x0034, Z_(ColorPointRIntensity), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0036, Z_(ColorPointGX), 1, Z_Nop }, - { Zuint16, Cx0300, 0x0037, Z_(ColorPointGY), 1, Z_Nop }, - { Zuint8, Cx0300, 0x0038, Z_(ColorPointGIntensity), 1, Z_Nop }, - { Zuint16, Cx0300, 0x003A, Z_(ColorPointBX), 1, Z_Nop }, - { Zuint16, Cx0300, 0x003B, Z_(ColorPointBY), 1, Z_Nop }, - { Zuint8, Cx0300, 0x003C, Z_(ColorPointBIntensity), 1, Z_Nop }, + { Zuint8, Cx0300, 0x0000, Z_(Hue), 1 }, + { Zuint8, Cx0300, 0x0001, Z_(Sat), 1 }, + { Zuint16, Cx0300, 0x0002, Z_(RemainingTime), 1 }, + { Zuint16, Cx0300, 0x0003, Z_(X), 1 }, + { Zuint16, Cx0300, 0x0004, Z_(Y), 1 }, + { Zenum8, Cx0300, 0x0005, Z_(DriftCompensation), 1 }, + { Zstring, Cx0300, 0x0006, Z_(CompensationText), 1 }, + { Zuint16, Cx0300, 0x0007, Z_(CT), 1 }, + { Zenum8, Cx0300, 0x0008, Z_(ColorMode), 1 }, + { Zuint8, Cx0300, 0x0010, Z_(NumberOfPrimaries), 1 }, + { Zuint16, Cx0300, 0x0011, Z_(Primary1X), 1 }, + { Zuint16, Cx0300, 0x0012, Z_(Primary1Y), 1 }, + { Zuint8, Cx0300, 0x0013, Z_(Primary1Intensity), 1 }, + { Zuint16, Cx0300, 0x0015, Z_(Primary2X), 1 }, + { Zuint16, Cx0300, 0x0016, Z_(Primary2Y), 1 }, + { Zuint8, Cx0300, 0x0017, Z_(Primary2Intensity), 1 }, + { Zuint16, Cx0300, 0x0019, Z_(Primary3X), 1 }, + { Zuint16, Cx0300, 0x001A, Z_(Primary3Y), 1 }, + { Zuint8, Cx0300, 0x001B, Z_(Primary3Intensity), 1 }, + { Zuint16, Cx0300, 0x0030, Z_(WhitePointX), 1 }, + { Zuint16, Cx0300, 0x0031, Z_(WhitePointY), 1 }, + { Zuint16, Cx0300, 0x0032, Z_(ColorPointRX), 1 }, + { Zuint16, Cx0300, 0x0033, Z_(ColorPointRY), 1 }, + { Zuint8, Cx0300, 0x0034, Z_(ColorPointRIntensity), 1 }, + { Zuint16, Cx0300, 0x0036, Z_(ColorPointGX), 1 }, + { Zuint16, Cx0300, 0x0037, Z_(ColorPointGY), 1 }, + { Zuint8, Cx0300, 0x0038, Z_(ColorPointGIntensity), 1 }, + { Zuint16, Cx0300, 0x003A, Z_(ColorPointBX), 1 }, + { Zuint16, Cx0300, 0x003B, Z_(ColorPointBY), 1 }, + { Zuint8, Cx0300, 0x003C, Z_(ColorPointBIntensity), 1 }, // Illuminance Measurement cluster - { Zuint16, Cx0400, 0x0000, Z_(Illuminance), 1, Z_Nop }, // Illuminance (in Lux) - { Zuint16, Cx0400, 0x0001, Z_(IlluminanceMinMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0400, 0x0002, Z_(IlluminanceMaxMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0400, 0x0003, Z_(IlluminanceTolerance), 1, Z_Nop }, // - { Zenum8, Cx0400, 0x0004, Z_(IlluminanceLightSensorType), 1, Z_Nop }, // - { Zunk, Cx0400, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other values + { Zuint16, Cx0400, 0x0000, Z_(Illuminance), 1 }, // Illuminance (in Lux) + { Zuint16, Cx0400, 0x0001, Z_(IlluminanceMinMeasuredValue), 1 }, // + { Zuint16, Cx0400, 0x0002, Z_(IlluminanceMaxMeasuredValue), 1 }, // + { Zuint16, Cx0400, 0x0003, Z_(IlluminanceTolerance), 1 }, // + { Zenum8, Cx0400, 0x0004, Z_(IlluminanceLightSensorType), 1 }, // + { Zunk, Cx0400, 0xFFFF, Z_(), 0 }, // Remove all other values // Illuminance Level Sensing cluster - { Zenum8, Cx0401, 0x0000, Z_(IlluminanceLevelStatus), 1, Z_Nop }, // Illuminance (in Lux) - { Zenum8, Cx0401, 0x0001, Z_(IlluminanceLightSensorType), 1, Z_Nop }, // LightSensorType - { Zuint16, Cx0401, 0x0010, Z_(IlluminanceTargetLevel), 1, Z_Nop }, // - { Zunk, Cx0401, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other values + { Zenum8, Cx0401, 0x0000, Z_(IlluminanceLevelStatus), 1 }, // Illuminance (in Lux) + { Zenum8, Cx0401, 0x0001, Z_(IlluminanceLightSensorType), 1 }, // LightSensorType + { Zuint16, Cx0401, 0x0010, Z_(IlluminanceTargetLevel), 1 }, // + { Zunk, Cx0401, 0xFFFF, Z_(), 0 }, // Remove all other values // Temperature Measurement cluster - { Zint16, Cx0402, 0x0000, Z_(Temperature), -100, Z_Nop }, // divide by 100 - { Zint16, Cx0402, 0x0001, Z_(TemperatureMinMeasuredValue), -100, Z_Nop }, // - { Zint16, Cx0402, 0x0002, Z_(TemperatureMaxMeasuredValue), -100, Z_Nop }, // - { Zuint16, Cx0402, 0x0003, Z_(TemperatureTolerance), -100, Z_Nop }, // - { Zunk, Cx0402, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other values + { Zint16, Cx0402, 0x0000, Z_(Temperature), -100 }, // divide by 100 + { Zint16, Cx0402, 0x0001, Z_(TemperatureMinMeasuredValue), -100 }, // + { Zint16, Cx0402, 0x0002, Z_(TemperatureMaxMeasuredValue), -100 }, // + { Zuint16, Cx0402, 0x0003, Z_(TemperatureTolerance), -100 }, // + { Zunk, Cx0402, 0xFFFF, Z_(), 0 }, // Remove all other values // Pressure Measurement cluster - { Zunk, Cx0403, 0x0000, Z_(PressureUnit), 0, Z_AddPressureUnit }, // Pressure Unit - { Zint16, Cx0403, 0x0000, Z_(Pressure), 1, Z_Nop }, // Pressure - { Zint16, Cx0403, 0x0001, Z_(PressureMinMeasuredValue), 1, Z_Nop }, // - { Zint16, Cx0403, 0x0002, Z_(PressureMaxMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0403, 0x0003, Z_(PressureTolerance), 1, Z_Nop }, // - { Zint16, Cx0403, 0x0010, Z_(PressureScaledValue), 1, Z_Nop }, // - { Zint16, Cx0403, 0x0011, Z_(PressureMinScaledValue), 1, Z_Nop }, // - { Zint16, Cx0403, 0x0012, Z_(PressureMaxScaledValue), 1, Z_Nop }, // - { Zuint16, Cx0403, 0x0013, Z_(PressureScaledTolerance), 1, Z_Nop }, // - { Zint8, Cx0403, 0x0014, Z_(PressureScale), 1, Z_Nop }, // - { Zunk, Cx0403, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other Pressure values + { Zint16, Cx0403, 0x0000, Z_(Pressure), 1 }, // Pressure + { Zint16, Cx0403, 0x0001, Z_(PressureMinMeasuredValue), 1 }, // + { Zint16, Cx0403, 0x0002, Z_(PressureMaxMeasuredValue), 1 }, // + { Zuint16, Cx0403, 0x0003, Z_(PressureTolerance), 1 }, // + { Zint16, Cx0403, 0x0010, Z_(PressureScaledValue), 1 }, // + { Zint16, Cx0403, 0x0011, Z_(PressureMinScaledValue), 1 }, // + { Zint16, Cx0403, 0x0012, Z_(PressureMaxScaledValue), 1 }, // + { Zuint16, Cx0403, 0x0013, Z_(PressureScaledTolerance), 1 }, // + { Zint8, Cx0403, 0x0014, Z_(PressureScale), 1 }, // + { Zunk, Cx0403, 0xFFFF, Z_(), 0 }, // Remove all other Pressure values // Flow Measurement cluster - { Zuint16, Cx0404, 0x0000, Z_(FlowRate), -10, Z_Nop }, // Flow (in m3/h) - { Zuint16, Cx0404, 0x0001, Z_(FlowMinMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0404, 0x0002, Z_(FlowMaxMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0404, 0x0003, Z_(FlowTolerance), 1, Z_Nop }, // - { Zunk, Cx0404, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other values + { Zuint16, Cx0404, 0x0000, Z_(FlowRate), -10 }, // Flow (in m3/h) + { Zuint16, Cx0404, 0x0001, Z_(FlowMinMeasuredValue), 1 }, // + { Zuint16, Cx0404, 0x0002, Z_(FlowMaxMeasuredValue), 1 }, // + { Zuint16, Cx0404, 0x0003, Z_(FlowTolerance), 1 }, // + { Zunk, Cx0404, 0xFFFF, Z_(), 0 }, // Remove all other values // Relative Humidity Measurement cluster - { Zuint16, Cx0405, 0x0000, Z_(Humidity), -100, Z_Nop }, // Humidity - { Zuint16, Cx0405, 0x0001, Z_(HumidityMinMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0405, 0x0002, Z_(HumidityMaxMeasuredValue), 1, Z_Nop }, // - { Zuint16, Cx0405, 0x0003, Z_(HumidityTolerance), 1, Z_Nop }, // - { Zunk, Cx0405, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other values + { Zuint16, Cx0405, 0x0000, Z_(Humidity), -100 }, // Humidity + { Zuint16, Cx0405, 0x0001, Z_(HumidityMinMeasuredValue), 1 }, // + { Zuint16, Cx0405, 0x0002, Z_(HumidityMaxMeasuredValue), 1 }, // + { Zuint16, Cx0405, 0x0003, Z_(HumidityTolerance), 1 }, // + { Zunk, Cx0405, 0xFFFF, Z_(), 0 }, // Remove all other values // Occupancy Sensing cluster - { Zmap8, Cx0406, 0x0000, Z_(Occupancy), 1, Z_Nop }, // Occupancy (map8) - { Zenum8, Cx0406, 0x0001, Z_(OccupancySensorType), 1, Z_Nop }, // OccupancySensorType - { Zunk, Cx0406, 0xFFFF, Z_(), 0, Z_Nop }, // Remove all other values + { Zmap8, Cx0406, 0x0000, Z_(Occupancy), 1 }, // Occupancy (map8) + { Zenum8, Cx0406, 0x0001, Z_(OccupancySensorType), 1 }, // OccupancySensorType + { Zunk, Cx0406, 0xFFFF, Z_(), 0 }, // Remove all other values // IAS Cluster (Intruder Alarm System) - { Zenum8, Cx0500, 0x0000, Z_(ZoneState), 1, Z_Nop }, // Occupancy (map8) - { Zenum16, Cx0500, 0x0001, Z_(ZoneType), 1, Z_Nop }, // Occupancy (map8) - { Zmap16, Cx0500, 0x0002, Z_(ZoneStatus), 1, Z_Nop }, // Occupancy (map8) + { Zenum8, Cx0500, 0x0000, Z_(ZoneState), 1 }, // Occupancy (map8) + { Zenum16, Cx0500, 0x0001, Z_(ZoneType), 1 }, // Occupancy (map8) + { Zmap16, Cx0500, 0x0002, Z_(ZoneStatus), 1 }, // Occupancy (map8) // Metering (Smart Energy) cluster - { Zuint48, Cx0702, 0x0000, Z_(CurrentSummDelivered), 1, Z_Nop }, + { Zuint48, Cx0702, 0x0000, Z_(CurrentSummDelivered), 1 }, // Meter Identification cluster - { Zstring, Cx0B01, 0x0000, Z_(CompanyName), 1, Z_Nop }, - { Zuint16, Cx0B01, 0x0001, Z_(MeterTypeID), 1, Z_Nop }, - { Zuint16, Cx0B01, 0x0004, Z_(DataQualityID), 1, Z_Nop }, - { Zstring, Cx0B01, 0x0005, Z_(CustomerName), 1, Z_Nop }, - { Zoctstr, Cx0B01, 0x0006, Z_(Model), 1, Z_Nop }, - { Zoctstr, Cx0B01, 0x0007, Z_(PartNumber), 1, Z_Nop }, - { Zoctstr, Cx0B01, 0x0008, Z_(ProductRevision), 1, Z_Nop }, - { Zoctstr, Cx0B01, 0x000A, Z_(SoftwareRevision), 1, Z_Nop }, - { Zstring, Cx0B01, 0x000B, Z_(UtilityName), 1, Z_Nop }, - { Zstring, Cx0B01, 0x000C, Z_(POD), 1, Z_Nop }, - { Zint24, Cx0B01, 0x000D, Z_(AvailablePower), 1, Z_Nop }, - { Zint24, Cx0B01, 0x000E, Z_(PowerThreshold), 1, Z_Nop }, + { Zstring, Cx0B01, 0x0000, Z_(CompanyName), 1 }, + { Zuint16, Cx0B01, 0x0001, Z_(MeterTypeID), 1 }, + { Zuint16, Cx0B01, 0x0004, Z_(DataQualityID), 1 }, + { Zstring, Cx0B01, 0x0005, Z_(CustomerName), 1 }, + { Zoctstr, Cx0B01, 0x0006, Z_(Model), 1 }, + { Zoctstr, Cx0B01, 0x0007, Z_(PartNumber), 1 }, + { Zoctstr, Cx0B01, 0x0008, Z_(ProductRevision), 1 }, + { Zoctstr, Cx0B01, 0x000A, Z_(SoftwareRevision), 1 }, + { Zstring, Cx0B01, 0x000B, Z_(UtilityName), 1 }, + { Zstring, Cx0B01, 0x000C, Z_(POD), 1 }, + { Zint24, Cx0B01, 0x000D, Z_(AvailablePower), 1 }, + { Zint24, Cx0B01, 0x000E, Z_(PowerThreshold), 1 }, // Electrical Measurement cluster - { Zuint16, Cx0B04, 0x0505, Z_(RMSVoltage), 1, Z_Nop }, - { Zuint16, Cx0B04, 0x0508, Z_(RMSCurrent), 1, Z_Nop }, - { Zint16, Cx0B04, 0x050B, Z_(ActivePower), 1, Z_Nop }, + { Zuint16, Cx0B04, 0x0505, Z_(RMSVoltage), 1 }, + { Zuint16, Cx0B04, 0x0508, Z_(RMSCurrent), 1 }, + { Zint16, Cx0B04, 0x050B, Z_(ActivePower), 1 }, // Diagnostics cluster - { Zuint16, Cx0B05, 0x0000, Z_(NumberOfResets), 1, Z_Nop }, - { Zuint16, Cx0B05, 0x0001, Z_(PersistentMemoryWrites),1, Z_Nop }, - { Zuint8, Cx0B05, 0x011C, Z_(LastMessageLQI), 1, Z_Nop }, - { Zuint8, Cx0B05, 0x011D, Z_(LastMessageRSSI), 1, Z_Nop }, + { Zuint16, Cx0B05, 0x0000, Z_(NumberOfResets), 1 }, + { Zuint16, Cx0B05, 0x0001, Z_(PersistentMemoryWrites),1 }, + { Zuint8, Cx0B05, 0x011C, Z_(LastMessageLQI), 1 }, + { Zuint8, Cx0B05, 0x011D, Z_(LastMessageRSSI), 1 }, }; @@ -544,8 +530,7 @@ typedef union ZCLHeaderFrameControl_t { // If not found: // - returns nullptr const __FlashStringHelper* zigbeeFindAttributeByName(const char *command, - uint16_t *cluster, uint16_t *attribute, int8_t *multiplier, - uint8_t *cb) { + uint16_t *cluster, uint16_t *attribute, int8_t *multiplier) { for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) { const Z_AttributeConverter *converter = &Z_PostProcess[i]; if (0 == pgm_read_word(&converter->name_offset)) { continue; } // avoid strcasecmp_P() from crashing @@ -553,7 +538,6 @@ const __FlashStringHelper* zigbeeFindAttributeByName(const char *command, if (cluster) { *cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); } if (attribute) { *attribute = pgm_read_word(&converter->attribute); } if (multiplier) { *multiplier = pgm_read_byte(&converter->multiplier); } - if (cb) { *cb = pgm_read_byte(&converter->cb); } return (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset)); } } @@ -627,16 +611,24 @@ public: return _frame_control.b.frame_type & 1; } - static void generateAttributeName(const JsonObject& json, uint16_t cluster, uint16_t attr, char *key, size_t key_len); - void parseReportAttributes(JsonObject& json, uint8_t offset = 0); - void parseReadAttributes(JsonObject& json, uint8_t offset = 0); - void parseReadAttributesResponse(JsonObject& json, uint8_t offset = 0); - void parseReadConfigAttributes(JsonObject& json, uint8_t offset = 0); - void parseConfigAttributes(JsonObject& json, uint8_t offset = 0); + void parseReportAttributes(Z_attribute_list& attr_list); + void generateSyntheticAttributes(Z_attribute_list& attr_list); + void generateCallBacks(Z_attribute_list& attr_list); + void parseReadAttributes(Z_attribute_list& attr_list); + void parseReadAttributesResponse(Z_attribute_list& attr_list); + void parseReadConfigAttributes(Z_attribute_list& attr_list); + void parseConfigAttributes(Z_attribute_list& attr_list); void parseResponse(void); - void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0); - void postProcessAttributes(uint16_t shortaddr, JsonObject& json); - void updateInternalAttributes(uint16_t shortaddr, JsonObject& json); + void parseResponseOld(void); + void parseClusterSpecificCommand(Z_attribute_list& attr_list); + void postProcessAttributes(uint16_t shortaddr, Z_attribute_list& attr_list); + + // synthetic attributes converters + void syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribute &attr); + void syntheticAqaraSensor2(Z_attribute_list &attr_list, class Z_attribute &attr); + void syntheticAqaraCubeOrButton(Z_attribute_list &attr_list, class Z_attribute &attr); + void syntheticAqaraVibration(Z_attribute_list &attr_list, class Z_attribute &attr); + inline void setGroupId(uint16_t groupid) { _groupaddr = groupid; @@ -782,14 +774,13 @@ int32_t encodeSingleAttribute(class SBuffer &buf, double val_d, const char *val_ // parse a single attribute // // Input: -// json: json Object where to add the attribute -// attrid_str: the key for the attribute +// attr: attribute object to store to // buf: the buffer to read from // offset: location in the buffer to read from // attrtype: type of attribute (byte) or -1 to read from the stream as first byte // Output: // return: the length in bytes of the attribute -uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer &buf, +uint32_t parseSingleAttribute(Z_attribute & attr, const SBuffer &buf, uint32_t offset, int32_t attrtype = -1) { uint32_t i = offset; @@ -798,7 +789,7 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer } // fallback - enter a null value - json[attrid_str] = (char*) nullptr; + attr.setNone(); // set to null by default uint32_t len = Z_getDatatypeLen(attrtype); // pre-compute lenght, overloaded for variable length attributes @@ -814,7 +805,7 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer uint8_t uint8_val = buf.get8(i); // i += 1; if (0xFF != uint8_val) { - json[attrid_str] = uint8_val; + attr.setUInt(uint8_val); } } break; @@ -824,7 +815,7 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer uint16_t uint16_val = buf.get16(i); // i += 2; if (0xFFFF != uint16_val) { - json[attrid_str] = uint16_val; + attr.setUInt(uint16_val); } } break; @@ -834,7 +825,7 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer uint32_t uint32_val = buf.get32(i); // i += 4; if (0xFFFFFFFF != uint32_val) { - json[attrid_str] = uint32_val; + attr.setUInt(uint32_val); } } break; @@ -856,7 +847,7 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer for (uint32_t j=0; j= i + 3) { uint16_t attrid = _payload.get16(i); i += 2; - char key[16]; - generateAttributeName(json, _cluster_id, attrid, key, sizeof(key)); - // exception for Xiaomi lumi.weather - specific field to be treated as octet and not char if ((0x0000 == _cluster_id) && (0xFF01 == attrid)) { if (0x42 == _payload.get8(i)) { _payload.set8(i, 0x41); // change type from 0x42 to 0x41 } } - i += parseSingleAttribute(json, key, _payload, i); + + // TODO look for suffix + Z_attribute & attr = attr_list.addAttribute(_cluster_id, attrid); + + i += parseSingleAttribute(attr, _payload, i); } // Issue Philips outdoor motion sensor SML002, see https://github.com/Koenkk/zigbee2mqtt/issues/897 @@ -1061,19 +1032,67 @@ void ZCLFrame::parseReportAttributes(JsonObject& json, uint8_t offset) { } } +void ZCLFrame::generateSyntheticAttributes(Z_attribute_list& attr_list) { + // scan through attributes and apply specific converters + for (auto &attr : attr_list) { + if (attr.key_is_str) { continue; } // pass if key is a name + uint32_t ccccaaaa = (attr.key.id.cluster << 16) | attr.key.id.attr_id; + + switch (ccccaaaa) { // 0xccccaaaa . c=cluster, a=attribute + case 0x0000FF01: + syntheticAqaraSensor(attr_list, attr); + break; + case 0x0000FF02: + syntheticAqaraSensor2(attr_list, attr); + break; + case 0x00120055: + syntheticAqaraCubeOrButton(attr_list, attr); + break; + case 0x01010055: + case 0x01010508: + syntheticAqaraVibration(attr_list, attr); + break; + } + } +} + +// Set deferred callbacks for Occupancy +// TODO make delay a parameter +void ZCLFrame::generateCallBacks(Z_attribute_list& attr_list) { + static const uint32_t OCCUPANCY_TIMEOUT = 90 * 1000; // 90 s + // scan through attributes and apply specific converters + for (auto &attr : attr_list) { + if (attr.key_is_str) { continue; } // pass if key is a name + uint32_t ccccaaaa = (attr.key.id.cluster << 16) | attr.key.id.attr_id; + + switch (ccccaaaa) { // 0xccccaaaa . c=cluster, a=attribute + case 0x04060000: // Occupancy + uint32_t occupancy = attr.getUInt(); + if (occupancy) { + zigbee_devices.setTimer(_srcaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, _cluster_id, _srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback); + } else { + zigbee_devices.resetTimersForDevice(_srcaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY); + } + break; + } + } +} + // ZCL_READ_ATTRIBUTES -// TODO -void ZCLFrame::parseReadAttributes(JsonObject& json, uint8_t offset) { - uint32_t i = offset; +void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) { + uint32_t i = 0; uint32_t len = _payload.len(); - json[F(D_CMND_ZIGBEE_CLUSTER)] = _cluster_id; + uint16_t read_attr_ids[len/2]; - JsonArray &attr_list = json.createNestedArray(F("Read")); - JsonObject &attr_names = json.createNestedObject(F("ReadNames")); + attr_list.addAttribute(F(D_CMND_ZIGBEE_CLUSTER)).setUInt(_cluster_id); + + Z_json_array attr_numbers; + Z_attribute_list attr_names; while (len >= 2 + i) { uint16_t attrid = _payload.get16(i); - attr_list.add(attrid); + attr_numbers.add(attrid); + read_attr_ids[i/2] = attrid; // find the attribute name for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) { @@ -1082,43 +1101,49 @@ void ZCLFrame::parseReadAttributes(JsonObject& json, uint8_t offset) { uint16_t conv_attribute = pgm_read_word(&converter->attribute); if ((conv_cluster == _cluster_id) && (conv_attribute == attrid)) { - attr_names[(const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset))] = true; + attr_names.addAttribute(Z_strings + pgm_read_word(&converter->name_offset), true).setBool(true); break; } } i += 2; } + attr_list.addAttribute(F("Read")).setStrRaw(attr_numbers.toString().c_str()); + attr_list.addAttribute(F("ReadNames")).setStrRaw(attr_names.toString(true).c_str()); + + // call auto-responder + Z_AutoResponder(_srcaddr, _cluster_id, _srcendpoint, read_attr_ids, len/2); } // ZCL_CONFIGURE_REPORTING_RESPONSE -void ZCLFrame::parseConfigAttributes(JsonObject& json, uint8_t offset) { - uint32_t i = offset; +void ZCLFrame::parseConfigAttributes(Z_attribute_list& attr_list) { + uint32_t i = 0; uint32_t len = _payload.len(); - - JsonObject &config_rsp = json.createNestedObject(F("ConfigResponse")); uint8_t status = _payload.get8(i); - config_rsp[F("Status")] = status; - config_rsp[F("StatusMsg")] = getZigbeeStatusMessage(status); + + Z_attribute_list attr_config_response; + attr_config_response.addAttribute(F("Status")).setUInt(status); + attr_config_response.addAttribute(F("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str()); + + Z_attribute &attr_1 = attr_list.addAttribute(F("ConfigResponse")); + attr_1.setStrRaw(attr_config_response.toString(true).c_str()); } // ZCL_READ_REPORTING_CONFIGURATION_RESPONSE -void ZCLFrame::parseReadConfigAttributes(JsonObject& json, uint8_t offset) { - uint32_t i = offset; +void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) { + uint32_t i = 0; uint32_t len = _payload.len(); - // json[F(D_CMND_ZIGBEE_CLUSTER)] = _cluster_id; // TODO is it necessary? + Z_attribute &attr_root = attr_list.addAttribute(F("ReadConfig")); + Z_attribute_list attr_1; - JsonObject &attr_names = json.createNestedObject(F("ReadConfig")); while (len >= i + 4) { uint8_t status = _payload.get8(i); uint8_t direction = _payload.get8(i+1); uint16_t attrid = _payload.get16(i+2); - char attr_hex[12]; - snprintf_P(attr_hex, sizeof(attr_hex), "%04X/%04X", _cluster_id, attrid); - JsonObject &attr_details = attr_names.createNestedObject(attr_hex); + Z_attribute_list attr_2; if (direction) { - attr_details[F("DirectionReceived")] = true; + attr_2.addAttribute(F("DirectionReceived")).setBool(true); } // find the attribute name @@ -1128,21 +1153,22 @@ void ZCLFrame::parseReadConfigAttributes(JsonObject& json, uint8_t offset) { uint16_t conv_attribute = pgm_read_word(&converter->attribute); if ((conv_cluster == _cluster_id) && (conv_attribute == attrid)) { - attr_details[(const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset))] = true; + const char * attr_name = Z_strings + pgm_read_word(&converter->name_offset); + attr_2.addAttribute(attr_name, true).setBool(true); break; } } i += 4; if (0 != status) { - attr_details[F("Status")] = status; - attr_details[F("StatusMsg")] = getZigbeeStatusMessage(status); + attr_2.addAttribute(F("Status")).setUInt(status); + attr_2.addAttribute(F("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str()); } else { // no error, decode data if (direction) { // only Timeout period is present uint16_t attr_timeout = _payload.get16(i); i += 2; - attr_details[F("TimeoutPeriod")] = (0xFFFF == attr_timeout) ? -1 : attr_timeout; + attr_2.addAttribute(F("TimeoutPeriod")).setUInt((0xFFFF == attr_timeout) ? -1 : attr_timeout); } else { // direction == 0, we have a data type uint8_t attr_type = _payload.get8(i); @@ -1150,22 +1176,23 @@ void ZCLFrame::parseReadConfigAttributes(JsonObject& json, uint8_t offset) { uint16_t attr_min_interval = _payload.get16(i+1); uint16_t attr_max_interval = _payload.get16(i+3); i += 5; - attr_details[F("MinInterval")] = (0xFFFF == attr_min_interval) ? -1 : attr_min_interval; - attr_details[F("MaxInterval")] = (0xFFFF == attr_max_interval) ? -1 : attr_max_interval; + attr_2.addAttribute(F("MinInterval")).setUInt((0xFFFF == attr_min_interval) ? -1 : attr_min_interval); + attr_2.addAttribute(F("MaxInterval")).setUInt((0xFFFF == attr_max_interval) ? -1 : attr_max_interval); if (!attr_discrete) { // decode Reportable Change - char attr_name[20]; - strcpy_P(attr_name, PSTR("ReportableChange")); - i += parseSingleAttribute(attr_details, attr_name, _payload, i, attr_type); + Z_attribute &attr_change = attr_2.addAttribute(F("ReportableChange")); + i += parseSingleAttribute(attr_change, _payload, i, attr_type); } } } + attr_1.addAttribute(_cluster_id, attrid).setStrRaw(attr_2.toString(true).c_str()); } + attr_root.setStrRaw(attr_1.toString(true).c_str()); } // ZCL_READ_ATTRIBUTES_RESPONSE -void ZCLFrame::parseReadAttributesResponse(JsonObject& json, uint8_t offset) { - uint32_t i = offset; +void ZCLFrame::parseReadAttributesResponse(Z_attribute_list& attr_list) { + uint32_t i = 0; uint32_t len = _payload.len(); while (len >= i + 4) { @@ -1174,10 +1201,8 @@ void ZCLFrame::parseReadAttributesResponse(JsonObject& json, uint8_t offset) { uint8_t status = _payload.get8(i++); if (0 == status) { - char key[16]; - generateAttributeName(json, _cluster_id, attrid, key, sizeof(key)); - - i += parseSingleAttribute(json, key, _payload, i); + Z_attribute & attr = attr_list.addAttribute(_cluster_id, attrid); + i += parseSingleAttribute(attr, _payload, i); } } } @@ -1188,185 +1213,224 @@ void ZCLFrame::parseResponse(void) { uint8_t cmd = _payload.get8(0); uint8_t status = _payload.get8(1); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); + Z_attribute_list attr_list; // "Device" char s[12]; snprintf_P(s, sizeof(s), PSTR("0x%04X"), _srcaddr); - json[F(D_JSON_ZIGBEE_DEVICE)] = s; + attr_list.addAttribute(F(D_JSON_ZIGBEE_DEVICE)).setStr(s); // "Name" const char * friendlyName = zigbee_devices.getFriendlyName(_srcaddr); if (friendlyName) { - json[F(D_JSON_ZIGBEE_NAME)] = (char*) friendlyName; + attr_list.addAttribute(F(D_JSON_ZIGBEE_NAME)).setStr(friendlyName); } // "Command" snprintf_P(s, sizeof(s), PSTR("%04X!%02X"), _cluster_id, cmd); - json[F(D_JSON_ZIGBEE_CMD)] = s; + attr_list.addAttribute(F(D_JSON_ZIGBEE_CMD)).setStr(s); // "Status" - json[F(D_JSON_ZIGBEE_STATUS)] = status; + attr_list.addAttribute(F(D_JSON_ZIGBEE_STATUS)).setUInt(status); // "StatusMessage" - json[F(D_JSON_ZIGBEE_STATUS_MSG)] = getZigbeeStatusMessage(status); + attr_list.addAttribute(F(D_JSON_ZIGBEE_STATUS_MSG)).setStr(getZigbeeStatusMessage(status).c_str()); // Add Endpoint - json[F(D_CMND_ZIGBEE_ENDPOINT)] = _srcendpoint; + attr_list.addAttribute(F(D_CMND_ZIGBEE_ENDPOINT)).setUInt(_srcendpoint); // Add Group if non-zero - if (_groupaddr) { - json[F(D_CMND_ZIGBEE_GROUP)] = _groupaddr; + if (_groupaddr) { // TODO what about group zero + attr_list.group_id = _groupaddr; } // Add linkquality - json[F(D_CMND_ZIGBEE_LINKQUALITY)] = _linkquality; + attr_list.lqi = _linkquality; - String msg(""); - msg.reserve(100); - json.printTo(msg); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_RESPONSE "\":%s}"), msg.c_str()); + Response_P(PSTR("{\"" D_JSON_ZIGBEE_RESPONSE "\":%s}"), attr_list.toString(true).c_str()); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } - // Parse non-normalized attributes -void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) { - convertClusterSpecific(json, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload); +void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) { + convertClusterSpecific(attr_list, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload); #ifndef USE_ZIGBEE_NO_READ_ATTRIBUTES // read attributes unless disabled sendHueUpdate(_srcaddr, _groupaddr, _cluster_id, _cmd_id, _frame_control.b.direction); #endif } // ====================================================================== -// Record Manuf -int32_t Z_ManufKeepFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - zigbee_devices.setManufId(shortaddr, value.as()); - return 1; -} -// Record ModelId -int32_t Z_ModelKeepFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - zigbee_devices.setModelId(shortaddr, value.as()); - return 1; -} -// Record BatteryPercentage -int32_t Z_BatteryPercentageKeepFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - zigbee_devices.setBatteryPercent(shortaddr, json[new_name]); - return 1; +// New version of synthetic attribute generation +void ZCLFrame::syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribute &attr) { + const SBuffer * buf = attr.getRaw(); + if (buf) { + const SBuffer & buf2 = *buf; + uint32_t i = 0; + uint32_t len = buf2.len(); + + const char * modelId_c = zigbee_devices.getModelId(_srcaddr); // null if unknown + String modelId((char*) modelId_c); + + while (len >= 2 + i) { + uint8_t attrid = buf2.get8(i++); + + Z_attribute attr; // temporary attribute + i += parseSingleAttribute(attr, buf2, i); + int32_t ival32 = attr.getInt(); + float fval = attr.getFloat(); + bool translated = false; // were we able to translate to a known format? + if (0x01 == attrid) { + float batteryvoltage = fval / 100; + attr_list.addAttribute(0x0001, 0x0020).setFloat(batteryvoltage); + uint8_t batterypercentage = toPercentageCR2032(fval); + attr_list.addAttribute(0x0001, 0x0021).setUInt(batterypercentage * 2); + } else if ((nullptr != modelId) && (0 == getManufCode())) { + translated = true; + if (modelId.startsWith(F("lumi.sensor_ht")) || + modelId.startsWith(F("lumi.weather"))) { // Temp sensor + // Filter according to prefix of model name + // onla Aqara Temp/Humidity has manuf_code of zero. If non-zero we skip the parameters + if (0x64 == attrid) { + attr_list.addAttribute(0x0402, 0x0000).setInt(ival32); // Temperature + } else if (0x65 == attrid) { + attr_list.addAttribute(0x0405, 0x0000).setFloat(fval); // Humidity * 100 + } else if (0x66 == attrid) { + attr_list.addAttribute(0x0403, 0x0000).setUInt((ival32 + 50) / 100); // Pressure + } + } else if (modelId.startsWith(F("lumi.sensor_smoke"))) { // gas leak + if (0x64 == attrid) { + attr_list.addAttribute(F("SmokeDensity")).copyVal(attr); + } + } else if (modelId.startsWith(F("lumi.sensor_natgas"))) { // gas leak + if (0x64 == attrid) { + attr_list.addAttribute(F("GasDensity")).copyVal(attr); + } + } else { + translated = false; // we didn't find a match + } + // } else if (0x115F == zcl->getManufCode()) { // Aqara Motion Sensor, still unknown field + } + if (!translated) { + if (attrid >= 100) { // payload is always above 0x64 or 100 + char attr_name[12]; + snprintf_P(attr_name, sizeof(attr_name), PSTR("Xiaomi_%02X"), attrid); + attr_list.addAttribute(attr_name).copyVal(attr); + } + } + } + } } -// Add pressure unit -int32_t Z_AddPressureUnitFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = F(D_UNIT_PRESSURE); - return 0; // keep original key +void ZCLFrame::syntheticAqaraSensor2(class Z_attribute_list &attr_list, class Z_attribute &attr) { + const SBuffer * buf = attr.getRaw(); + if (buf) { + const SBuffer & buf2 = *buf; + uint32_t len = buf2.len(); + + // Look for battery value which is the first attribute of type 0x21 + uint16_t struct_size = buf2.get16(0); + size_t struct_len = 2; + if (0xFFFF != struct_size) { + if (struct_size > 16) { struct_size = 16; } + for (uint32_t j = 0; (j < struct_size) && (struct_len < len); j++) { + uint8_t attr_type = buf2.get8(struct_len); + if (0x21 == attr_type) { + uint16_t val = buf2.get16(struct_len+1); + float batteryvoltage = (float)val / 100; + attr_list.addAttribute(0x0001, 0x0020).setFloat(batteryvoltage); + uint8_t batterypercentage = toPercentageCR2032(val); + attr_list.addAttribute(0x0001, 0x0021).setUInt(batterypercentage * 2); + break; + } + struct_len += Z_getDatatypeLen(attr_type) + 1; + } + } + } + attr_list.removeAttribute(&attr); } -// Publish a message for `"Occupancy":0` when the timer expired -int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json[F(OCCUPANCY)] = 0; - zigbee_devices.jsonPublishNow(shortaddr, json); - return 0; // Fix GCC 10.1 warning -} - -// Aqara Cube -int32_t Z_AqaraCubeFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - const char * modelId_c = zigbee_devices.findShortAddr(shortaddr).modelId; // null if unknown +// Aqara Cube and Button +void ZCLFrame::syntheticAqaraCubeOrButton(class Z_attribute_list &attr_list, class Z_attribute &attr) { + const char * modelId_c = zigbee_devices.findShortAddr(_srcaddr).modelId; // null if unknown String modelId((char*) modelId_c); if (modelId.startsWith(F("lumi.sensor_cube"))) { // only for Aqara cube - int32_t val = value; + int32_t val = attr.getInt(); const __FlashStringHelper *aqara_cube = F("AqaraCube"); const __FlashStringHelper *aqara_cube_side = F("AqaraCubeSide"); const __FlashStringHelper *aqara_cube_from_side = F("AqaraCubeFromSide"); switch (val) { case 0: - json[aqara_cube] = F("shake"); + attr_list.addAttribute(aqara_cube).setStr(PSTR("shake")); break; case 2: - json[aqara_cube] = F("wakeup"); + attr_list.addAttribute(aqara_cube).setStr(PSTR("wakeup")); break; case 3: - json[aqara_cube] = F("fall"); + attr_list.addAttribute(aqara_cube).setStr(PSTR("fall")); break; case 64 ... 127: - json[aqara_cube] = F("flip90"); - json[aqara_cube_side] = val % 8; - json[aqara_cube_from_side] = (val - 64) / 8; + attr_list.addAttribute(aqara_cube).setStr(PSTR("flip90")); + attr_list.addAttribute(aqara_cube_side).setInt(val % 8); + attr_list.addAttribute(aqara_cube_from_side).setInt((val - 64) / 8); break; case 128 ... 132: - json[aqara_cube] = F("flip180"); - json[aqara_cube_side] = val - 128; + attr_list.addAttribute(aqara_cube).setStr(PSTR("flip180")); + attr_list.addAttribute(aqara_cube_side).setInt(val - 128); break; case 256 ... 261: - json[aqara_cube] = F("slide"); - json[aqara_cube_side] = val - 256; + attr_list.addAttribute(aqara_cube).setStr(PSTR("slide")); + attr_list.addAttribute(aqara_cube_side).setInt(val - 256); break; case 512 ... 517: - json[aqara_cube] = F("tap"); - json[aqara_cube_side] = val - 512; + attr_list.addAttribute(aqara_cube).setStr(PSTR("tap")); + attr_list.addAttribute(aqara_cube_side).setInt(val - 512); break; } - return 1; - } - - // Source: https://github.com/kirovilya/ioBroker.zigbee - // +---+ - // | 2 | - // +---+---+---+ - // | 4 | 0 | 1 | - // +---+---+---+ - // |M5I| - // +---+ - // | 3 | - // +---+ - // Side 5 is with the MI logo, side 3 contains the battery door. - // presentValue = 0 = shake - // presentValue = 2 = wakeup - // presentValue = 3 = fly/fall - // presentValue = y + x * 8 + 64 = 90º Flip from side x on top to side y on top - // presentValue = x + 128 = 180º flip to side x on top - // presentValue = x + 256 = push/slide cube while side x is on top - // presentValue = x + 512 = double tap while side x is on top - return 0; -} - -// Aqara Button -int32_t Z_AqaraButtonFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - const char * modelId_c = zigbee_devices.getModelId(shortaddr); // null if unknown - String modelId((char*) modelId_c); - - if (modelId.startsWith(F("lumi.remote"))) { // only for Aqara button - int32_t val = value; + attr_list.removeAttribute(&attr); + // Source: https://github.com/kirovilya/ioBroker.zigbee + // +---+ + // | 2 | + // +---+---+---+ + // | 4 | 0 | 1 | + // +---+---+---+ + // |M5I| + // +---+ + // | 3 | + // +---+ + // Side 5 is with the MI logo, side 3 contains the battery door. + // presentValue = 0 = shake + // presentValue = 2 = wakeup + // presentValue = 3 = fly/fall + // presentValue = y + x * 8 + 64 = 90º Flip from side x on top to side y on top + // presentValue = x + 128 = 180º flip to side x on top + // presentValue = x + 256 = push/slide cube while side x is on top + // presentValue = x + 512 = double tap while side x is on top + } else if (modelId.startsWith(F("lumi.remote"))) { // only for Aqara button + int32_t val = attr.getInt(); const __FlashStringHelper *aqara_click = F("click"); const __FlashStringHelper *aqara_action = F("action"); switch (val) { case 0: - json[aqara_action] = F("hold"); + attr_list.addAttribute(aqara_action).setStr(PSTR("hold")); break; case 1: - json[aqara_click] = F("single"); + attr_list.addAttribute(aqara_click).setStr(PSTR("single")); break; case 2: - json[aqara_click] = F("double"); + attr_list.addAttribute(aqara_click).setStr(PSTR("double")); break; case 255: - json[aqara_action] = F("release"); + attr_list.addAttribute(aqara_click).setStr(PSTR("release")); break; default: - json[aqara_action] = val; + attr_list.addAttribute(aqara_click).setUInt(val); break; } - return 1; } - - return 0; } -// Aqara Vibration Sensor - special proprietary attributes -int32_t Z_AqaraVibrationFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - //json[new_name] = value; - switch (attr) { +// Aqara vibration device +void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class Z_attribute &attr) { + switch (attr.key.id.attr_id) { case 0x0055: { - int32_t ivalue = value; + int32_t ivalue = attr.getInt(); const __FlashStringHelper * svalue; switch (ivalue) { case 1: svalue = F("vibrate"); break; @@ -1374,283 +1438,123 @@ int32_t Z_AqaraVibrationFunc(const class ZCLFrame *zcl, uint16_t shortaddr, Json case 3: svalue = F("drop"); break; default: svalue = F("unknown"); break; } - json[new_name] = svalue; + attr.setStr((const char*)svalue); } break; - // case 0x0503: - // break; - // case 0x0505: - // break; + case 0x0503: + break; + case 0x0505: + break; case 0x0508: { // see https://github.com/Koenkk/zigbee2mqtt/issues/295 and http://faire-ca-soi-meme.fr/domotique/2018/09/03/test-xiaomi-aqara-vibration-sensor/ // report accelerometer measures - String hex = value; - SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length()); - int16_t x, y, z; - z = buf2.get16(0); - y = buf2.get16(2); - x = buf2.get16(4); - JsonArray& xyz = json.createNestedArray(new_name); - xyz.add(x); - xyz.add(y); - xyz.add(z); - // calculate angles - float X = x; - float Y = y; - float Z = z; - int32_t Angle_X = 0.5f + atanf(X/sqrtf(z*z+y*y)) * f_180pi; - int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi; - int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi; - JsonArray& angles = json.createNestedArray(F("AqaraAngles")); - angles.add(Angle_X); - angles.add(Angle_Y); - angles.add(Angle_Z); + const SBuffer * buf = attr.getRaw(); + if (buf) { + const SBuffer & buf2 = *buf; + int16_t x, y, z; + z = buf2.get16(0); + y = buf2.get16(2); + x = buf2.get16(4); + char temp[32]; + snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", x, y, z); + attr.setStrRaw(temp); + // calculate angles + float X = x; + float Y = y; + float Z = z; + int32_t Angle_X = 0.5f + atanf(X/sqrtf(z*z+y*y)) * f_180pi; + int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi; + int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi; + snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", Angle_X, Angle_Y, Angle_Z); + attr_list.addAttribute(F("AqaraAngles")).setStrRaw(temp); + } } break; } - return 1; // remove original key } -int32_t Z_AqaraSensorFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - String hex = value; - SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length()); - uint32_t i = 0; - uint32_t len = buf2.len(); - char tmp[] = "tmp"; // for obscure reasons, it must be converted from const char* to char*, otherwise ArduinoJson gets confused - - const char * modelId_c = zigbee_devices.getModelId(shortaddr); // null if unknown - String modelId((char*) modelId_c); - - while (len >= 2 + i) { - uint8_t attrid = buf2.get8(i++); - - i += parseSingleAttribute(json, tmp, buf2, i); - float val = json[tmp]; - json.remove(tmp); - bool translated = false; // were we able to translate to a known format? - if (0x01 == attrid) { - float batteryvoltage = val / 1000.0f; - json[F("BatteryVoltage")] = batteryvoltage; - uint8_t batterypercentage = toPercentageCR2032(val); - json[F("BatteryPercentage")] = batterypercentage; - zigbee_devices.setBatteryPercent(shortaddr, batterypercentage); - // deprecated - json[F(D_JSON_VOLTAGE)] = batteryvoltage; - json[F("Battery")] = toPercentageCR2032(val); - } else if ((nullptr != modelId) && (0 == zcl->getManufCode())) { - translated = true; - if (modelId.startsWith(F("lumi.sensor_ht")) || - modelId.startsWith(F("lumi.weather"))) { // Temp sensor - // Filter according to prefix of model name - // onla Aqara Temp/Humidity has manuf_code of zero. If non-zero we skip the parameters - if (0x64 == attrid) { - json[F(D_JSON_TEMPERATURE)] = val / 100.0f; - } else if (0x65 == attrid) { - json[F(D_JSON_HUMIDITY)] = val / 100.0f; - } else if (0x66 == attrid) { - json[F(D_JSON_PRESSURE)] = val / 100.0f; - json[F(D_JSON_PRESSURE_UNIT)] = F(D_UNIT_PRESSURE); // hPa - } - } else if (modelId.startsWith(F("lumi.sensor_smoke"))) { // gas leak - if (0x64 == attrid) { - json[F("SmokeDensity")] = val; - } - } else if (modelId.startsWith(F("lumi.sensor_natgas"))) { // gas leak - if (0x64 == attrid) { - json[F("GasDensity")] = val; - } - } else { - translated = false; // we didn't find a match - } - // } else if (0x115F == zcl->getManufCode()) { // Aqara Motion Sensor, still unknown field - } - if (!translated) { - if (attrid >= 100) { // payload is always above 0x64 or 100 - char attr_name[12]; - snprintf_P(attr_name, sizeof(attr_name), PSTR("Xiaomi_%02X"), attrid); - json[attr_name] = val; - } - } - } - return 1; // remove original key +/// Publish a message for `"Occupancy":0` when the timer expired +int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { + Z_attribute_list attr_list; + attr_list.addAttribute(F(OCCUPANCY)).setUInt(0); + zigbee_devices.jsonPublishNow(shortaddr, attr_list); + return 0; // Fix GCC 10.1 warning } -int32_t Z_AqaraSensorFunc2(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - String hex = value; - SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length()); - uint32_t i = 0; - uint32_t len = buf2.len(); - - // Look for battery value which is the first attribute of type 0x21 - uint16_t struct_size = buf2.get16(0); - size_t struct_len = 2; - if (0xFFFF != struct_size) { - if (struct_size > 16) { struct_size = 16; } - for (uint32_t j = 0; (j < struct_size) && (struct_len < len); j++) { - uint8_t attr_type = buf2.get8(struct_len); - if (0x21 == attr_type) { - uint16_t val = buf2.get16(struct_len+1); - float batteryvoltage = val / 1000.0f; - json[F("BatteryVoltage")] = batteryvoltage; - uint8_t batterypercentage = toPercentageCR2032(val); - json[F("BatteryPercentage")] = batterypercentage; - zigbee_devices.setBatteryPercent(shortaddr, batterypercentage); - break; - } - struct_len += Z_getDatatypeLen(attr_type) + 1; - } - } - - return 0; // remove original key -} // ====================================================================== - -// apply the transformation from the converter -int32_t Z_ApplyConverter(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, - uint16_t cluster, uint16_t attr, int8_t multiplier, uint8_t cb) { - // apply multiplier if needed - if (1 == multiplier) { // copy unchanged - json[new_name] = value; - } else if (0 != multiplier) { - if (multiplier > 0) { - json[new_name] = ((float)value) * multiplier; - } else { - json[new_name] = ((float)value) / (-multiplier); - } - } - - // apply callback if needed - Z_AttrConverter func = nullptr; - switch (cb) { - case Z_Nop: - return 1; // drop original key - case Z_AddPressureUnit: - func = &Z_AddPressureUnitFunc; - break; - case Z_ManufKeep: - func = &Z_ManufKeepFunc; - break; - case Z_ModelKeep: - func = &Z_ModelKeepFunc; - break; - case Z_AqaraSensor: - func = &Z_AqaraSensorFunc; - break; - case Z_AqaraSensor2: - func = &Z_AqaraSensorFunc2; - break; - case Z_AqaraVibration: - func = &Z_AqaraVibrationFunc; - break; - case Z_AqaraCube: - func = &Z_AqaraCubeFunc; - break; - case Z_AqaraButton: - func = &Z_AqaraButtonFunc; - break; - case Z_BatteryPercentage: - func = &Z_BatteryPercentageKeepFunc; - break; - }; - - if (func) { - return (*func)(zcl, shortaddr, json, name, value, new_name, cluster, attr); - } - return 1; // Fix GCC 10.1 warning -} - -// Scan all the final attributes and update any internal representation like sensors -void ZCLFrame::updateInternalAttributes(uint16_t shortaddr, JsonObject& json) { - Z_Device & device = zigbee_devices.getShortAddr(shortaddr); - for (auto kv : json) { - String key_string = kv.key; - const char * key = key_string.c_str(); - JsonVariant& value = kv.value; - - if (key_string.equalsIgnoreCase(F("Temperature"))) { - device.temperature = value.as() * 10 + 0.5f; - } else if (key_string.equalsIgnoreCase(F("Humidity"))) { - device.humidity = value.as() + 0.5f; - } else if (key_string.equalsIgnoreCase(F("Pressure"))) { - device.pressure = value.as() + 0.5f; - } - } -} - -void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) { +void ZCLFrame::postProcessAttributes(uint16_t shortaddr, Z_attribute_list& attr_list) { // source endpoint uint8_t src_ep = _srcendpoint; - // iterate on json elements - for (auto kv : json) { - String key_string = kv.key; - const char * key = key_string.c_str(); - JsonVariant& value = kv.value; - // Check that format looks like "CCCC/AAAA" or "CCCC/AAAA+d" - char * delimiter = strchr(key, '/'); - char * delimiter2 = strchr(key, '+'); - if (delimiter) { - uint16_t attribute; - uint16_t suffix = 1; - uint16_t cluster = strtoul(key, &delimiter, 16); - if (!delimiter2) { - attribute = strtoul(delimiter+1, nullptr, 16); - } else { - attribute = strtoul(delimiter+1, &delimiter2, 16); - suffix = strtoul(delimiter2+1, nullptr, 10); - } - + + for (auto &attr : attr_list) { + // attr is Z_attribute& + if (!attr.key_is_str) { + uint16_t cluster = attr.key.id.cluster; + uint16_t attribute = attr.key.id.attr_id; + uint32_t ccccaaaa = (attr.key.id.cluster << 16) | attr.key.id.attr_id; Z_Device & device = zigbee_devices.getShortAddr(shortaddr); - uint16_t uval16 = value; // call converter from JSonVariant to int only once - int16_t ival16 = value; // call converter from JSonVariant to int only once - // see if we need to update the Hue bulb status - if ((cluster == 0x0006) && ((attribute == 0x0000) || (attribute == 0x8000))) { - bool power = value; - device.setPower(power); - } else if ((cluster == 0x0008) && (attribute == 0x0000)) { - device.dimmer = uval16; - } else if ((cluster == 0x0300) && (attribute == 0x0000)) { - device.hue = changeUIntScale(uval16, 0, 254, 0, 360); // change range from 0..254 to 0..360 - } else if ((cluster == 0x0300) && (attribute == 0x0001)) { - device.sat = uval16; - } else if ((cluster == 0x0300) && (attribute == 0x0003)) { - device.x = uval16; - } else if ((cluster == 0x0300) && (attribute == 0x0004)) { - device.y = uval16; - } else if ((cluster == 0x0300) && (attribute == 0x0007)) { - device.ct = uval16; - } else if ((cluster == 0x0300) && (attribute == 0x0008)) { - device.colormode = uval16; - } else if ((cluster == 0x0B04) && (attribute == 0x0505)) { - device.mains_voltage = uval16; - } else if ((cluster == 0x0B04) && (attribute == 0x050B)) { - device.mains_power = ival16; - } - // Iterate on filter + // Look for an entry in the converter table + bool found = false; + int8_t conv_multiplier; + const char * conv_name; for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) { const Z_AttributeConverter *converter = &Z_PostProcess[i]; uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); uint16_t conv_attribute = pgm_read_word(&converter->attribute); - int8_t conv_multiplier = pgm_read_byte(&converter->multiplier); - uint8_t conv_cb = pgm_read_byte(&converter->cb); // callback id if ((conv_cluster == cluster) && ((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) { - String new_name_str = (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset)); - if (suffix > 1) { new_name_str += suffix; } // append suffix number - // apply the transformation - int32_t drop = Z_ApplyConverter(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute, conv_multiplier, conv_cb); - if (drop) { - json.remove(key); - } + conv_multiplier = pgm_read_byte(&converter->multiplier); + conv_name = Z_strings + pgm_read_word(&converter->name_offset); + found = true; + break; + } + } + // apply multiplier if needed + float fval = attr.getFloat(); + if (found) { + if (0 == conv_multiplier) { attr_list.removeAttribute(&attr); continue; } // remove attribute if multiplier is zero + if (1 != conv_multiplier) { + if (conv_multiplier > 0) { fval = fval * conv_multiplier; } + else { fval = fval / (-conv_multiplier); } + attr.setFloat(fval); + } + } + + uint16_t uval16 = attr.getUInt(); // call converter to uint only once + int16_t ival16 = attr.getInt(); // call converter to int only once + // update any internal structure + switch (ccccaaaa) { + case 0x00000004: zigbee_devices.setManufId(shortaddr, attr.getStr()); break; + case 0x00000005: zigbee_devices.setModelId(shortaddr, attr.getStr()); break; + case 0x00010021: zigbee_devices.setBatteryPercent(shortaddr, uval16); break; + case 0x00060000: + case 0x00068000: device.setPower(attr.getBool()); break; + case 0x00080000: device.dimmer = uval16; break; + case 0x03000000: device.hue = changeUIntScale(uval16, 0, 254, 0, 360); break; + case 0x03000001: device.sat = uval16; break; + case 0x03000003: device.x = uval16; break; + case 0x03000004: device.y = uval16; break; + case 0x03000007: device.ct = uval16; break; + case 0x03000008: device.colormode = uval16; break; + case 0x04020000: device.temperature = fval * 10 + 0.5f; break; + case 0x04030000: device.pressure = fval + 0.5f; break; + case 0x04050000: device.humidity = fval + 0.5f; break; + case 0x0B040505: device.mains_voltage = uval16; break; + case 0x0B04050B: device.mains_power = ival16; break; + } + + // Replace cluster/attribute with name + if (found) { + if (0x00 != pgm_read_byte(conv_name)) {// if name is not null, replace it + attr.setKeyName(conv_name, true); // PMEM string so no need to copy } } } } - - updateInternalAttributes(shortaddr, json); } #endif // USE_ZIGBEE diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index 1a3e5b103..c533eb8ed 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -328,13 +328,8 @@ void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uin // Parse a cluster specific command, and try to convert into human readable -void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, bool direction, uint16_t shortaddr, uint8_t srcendpoint, const SBuffer &payload) { - size_t hex_char_len = payload.len()*2+2; - char *hex_char = (char*) malloc(hex_char_len); - if (!hex_char) { return; } - ToHex_P((unsigned char*)payload.getBuffer(), payload.len(), hex_char, hex_char_len); - - const __FlashStringHelper* command_name = nullptr; +void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, uint8_t cmd, bool direction, uint16_t shortaddr, uint8_t srcendpoint, const SBuffer &payload) { + const char * command_name = nullptr; uint8_t conv_direction; Z_XYZ_Var xyz; @@ -373,7 +368,7 @@ void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, boo p += 2; } if (match) { - command_name = (const __FlashStringHelper*) (Z_strings + pgm_read_word(&conv->tasmota_cmd_offset)); + command_name = Z_strings + pgm_read_word(&conv->tasmota_cmd_offset); parseXYZ(Z_strings + pgm_read_word(&conv->param_offset), payload, &xyz); if (0xFF == conv_cmd) { // shift all values @@ -396,112 +391,105 @@ void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, boo // Format: "0004<00": "00" = "<": "" for commands to devices char attrid_str[12]; snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X%c%02X"), cluster, direction ? '<' : '!', cmd); - json[attrid_str] = hex_char; - free(hex_char); + attr_list.addAttribute(attrid_str).setBuf(payload, 0, payload.len()); if (command_name) { // Now try to transform into a human readable format - String command_name2 = String(command_name); // if (direction & 0x80) then specific transform if (conv_direction & 0x80) { - // TODO need to create a specific command + uint32_t cccc00mm = (cluster << 16) | cmd; // format = cccc00mm, cccc = cluster, mm = command // IAS - if ((cluster == 0x0500) && (cmd == 0x00)) { - // "ZoneStatusChange" - json[command_name] = xyz.x; + switch (cccc00mm) { + case 0x05000000: // "ZoneStatusChange" + attr_list.addAttribute(command_name, true).setUInt(xyz.x); if (0 != xyz.y) { - json[command_name2 + F("Ext")] = xyz.y; + attr_list.addAttribute(command_name, PSTR("Ext")).setUInt(xyz.y); } if ((0 != xyz.z) && (0xFF != xyz.z)) { - json[command_name2 + F("Zone")] = xyz.z; + attr_list.addAttribute(command_name, PSTR("Zone")).setUInt(xyz.z); } - } else if ((cluster == 0x0004) && ((cmd == 0x00) || (cmd == 0x01) || (cmd == 0x03))) { - // AddGroupResp or ViewGroupResp (group name ignored) or RemoveGroup - json[command_name] = xyz.y; - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - } else if ((cluster == 0x0004) && (cmd == 0x02)) { - // GetGroupResp - json[command_name2 + F("Capacity")] = xyz.x; - json[command_name2 + F("Count")] = xyz.y; - JsonArray &arr = json.createNestedArray(command_name); - for (uint32_t i = 0; i < xyz.y; i++) { - arr.add(payload.get16(2 + 2*i)); + break; + case 0x00040000: + case 0x00040001: + case 0x00040003: // AddGroupResp or ViewGroupResp (group name ignored) or RemoveGroup + attr_list.addAttribute(command_name, true).setUInt(xyz.y); + attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x); + attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str()); + break; + case 0x00040002: // GetGroupResp + attr_list.addAttribute(command_name, PSTR("Capacity")).setUInt(xyz.x); + attr_list.addAttribute(command_name, PSTR("Count")).setUInt(xyz.y); + { + + Z_json_array group_list; + for (uint32_t i = 0; i < xyz.y; i++) { + group_list.add(payload.get16(2 + 2*i)); + } + attr_list.addAttribute(command_name, true).setStrRaw(group_list.toString().c_str()); } - } else if ((cluster == 0x0005) && ((cmd == 0x00) || (cmd == 0x02) || (cmd == 0x03))) { - // AddScene or RemoveScene or StoreScene - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("GroupId")] = xyz.y; - json[F("SceneId")] = xyz.z; - } else if ((cluster == 0x0005) && (cmd == 0x01)) { - // ViewScene - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("GroupId")] = xyz.y; - json[F("SceneId")] = xyz.z; - String scene_payload = json[attrid_str]; - json[F("ScenePayload")] = scene_payload.substring(8); // remove first 8 characters - } else if ((cluster == 0x0005) && (cmd == 0x03)) { - // RemoveAllScenes - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("GroupId")] = xyz.y; - } else if ((cluster == 0x0005) && (cmd == 0x06)) { - // GetSceneMembership - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("Capacity")] = xyz.y; - json[F("GroupId")] = xyz.z; - String scene_payload = json[attrid_str]; - json[F("ScenePayload")] = scene_payload.substring(8); // remove first 8 characters - } else if ((cluster == 0x0006) && (cmd == 0x40)) { - // Power Off With Effect - json[F("Power")] = 0; // always "Power":0 - json[F("PowerEffect")] = xyz.x; - json[F("PowerEffectVariant")] = xyz.y; - } else if ((cluster == 0x0006) && (cmd == 0x41)) { - // Power On With Recall Global Scene - json[F("Power")] = 1; // always "Power":1 - json[F("PowerRecallGlobalScene")] = true; - } else if ((cluster == 0x0006) && (cmd == 0x42)) { - // Power On With Timed Off Command - json[F("Power")] = 1; // always "Power":1 - json[F("PowerOnlyWhenOn")] = xyz.x; - json[F("PowerOnTime")] = xyz.y / 10.0f; - json[F("PowerOffWait")] = xyz.z / 10.0f; + break; + case 0x00050000: + case 0x00050001: // ViewScene + case 0x00050002: + case 0x00050004: // AddScene or RemoveScene or StoreScene + attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x); + attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str()); + attr_list.addAttribute(PSTR("GroupId"), true).setUInt(xyz.y); + attr_list.addAttribute(PSTR("SceneId"), true).setUInt(xyz.z); + if (0x00050001 == cccc00mm) { // ViewScene specific + attr_list.addAttribute(PSTR("ScenePayload"), true).setBuf(payload, 4, payload.len()-4); // remove first 4 bytes + } + break; + case 0x00050003: // RemoveAllScenes + attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x); + attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str()); + attr_list.addAttribute(PSTR("GroupId"), true).setUInt(xyz.y); + break; + case 0x00050006: // GetSceneMembership + attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x); + attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str()); + attr_list.addAttribute(PSTR("Capacity"), true).setUInt(xyz.y); + attr_list.addAttribute(PSTR("GroupId"), true).setUInt(xyz.z); + attr_list.addAttribute(PSTR("ScenePayload"), true).setBuf(payload, 4, payload.len()-4); // remove first 4 bytes + break; + case 0x00060040: // Power Off With Effect + attr_list.addAttribute(PSTR("Power"), true).setUInt(0); + attr_list.addAttribute(PSTR("PowerEffect"), true).setUInt(xyz.x); + attr_list.addAttribute(PSTR("PowerEffectVariant"), true).setUInt(xyz.y); + break; + case 0x00060041: // Power On With Recall Global Scene + attr_list.addAttribute(PSTR("Power"), true).setUInt(1); + attr_list.addAttribute(PSTR("PowerRecallGlobalScene"), true).setBool(true); + break; + case 0x00060042: // Power On With Timed Off Command + attr_list.addAttribute(PSTR("Power"), true).setUInt(1); + attr_list.addAttribute(PSTR("PowerOnlyWhenOn"), true).setUInt(xyz.x); + attr_list.addAttribute(PSTR("PowerOnTime"), true).setFloat(xyz.y / 10.0f); + attr_list.addAttribute(PSTR("PowerOffWait"), true).setFloat(xyz.z / 10.0f); + break; } } else { // general case - bool extended_command = false; // do we send command with endpoint suffix + // do we send command with endpoint suffix + char command_suffix[4] = { 0x00 }; // empty string by default // if SO101 and multiple endpoints, append endpoint number if (Settings.flag4.zb_index_ep) { if (zigbee_devices.countEndpoints(shortaddr) > 0) { - command_name2 += srcendpoint; - extended_command = true; + snprintf_P(command_suffix, sizeof(command_suffix), PSTR("%d"), srcendpoint); } } if (0 == xyz.x_type) { - json[command_name] = true; // no parameter - if (extended_command) { json[command_name2] = true; } + attr_list.addAttribute(command_name, command_suffix).setBool(true); } else if (0 == xyz.y_type) { - json[command_name] = xyz.x; // 1 parameter - if (extended_command) { json[command_name2] = xyz.x; } + attr_list.addAttribute(command_name, command_suffix).setUInt(xyz.x); } else { // multiple answers, create an array - JsonArray &arr = json.createNestedArray(command_name); + Z_json_array arr; arr.add(xyz.x); arr.add(xyz.y); if (xyz.z_type) { arr.add(xyz.z); } - if (extended_command) { - JsonArray &arr = json.createNestedArray(command_name2); - arr.add(xyz.x); - arr.add(xyz.y); - if (xyz.z_type) { - arr.add(xyz.z); - } - } + attr_list.addAttribute(command_name, command_suffix).setStrRaw(arr.toString().c_str()); } } } diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 67eafb8b0..1f5d33a8f 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -1011,53 +1011,53 @@ int32_t EZ_ReceiveTCJoinHandler(int32_t res, const class SBuffer &buf) { // Parse incoming ZCL message. // // This code is common to ZNP and EZSP -void Z_IncomingMessage(ZCLFrame &zcl_received) { +void Z_IncomingMessage(class ZCLFrame &zcl_received) { uint16_t srcaddr = zcl_received.getSrcAddr(); uint16_t groupid = zcl_received.getGroupAddr(); uint16_t clusterid = zcl_received.getClusterId(); uint8_t linkquality = zcl_received.getLinkQuality(); uint8_t srcendpoint = zcl_received.getSrcEndpoint(); + linkquality = linkquality != 0xFF ? linkquality : 0xFE; // avoid 0xFF (reserved for unknown) bool defer_attributes = false; // do we defer attributes reporting to coalesce // log the packet details zcl_received.log(); - zigbee_devices.setLQI(srcaddr, linkquality != 0xFF ? linkquality : 0xFE); // EFR32 has a different scale for LQI + zigbee_devices.setLQI(srcaddr, linkquality); // EFR32 has a different scale for LQI char shortaddr[8]; snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); + Z_attribute_list attr_list; + attr_list.lqi = linkquality; + attr_list.src_ep = srcendpoint; + if (groupid) { // TODO we miss the group_id == 0 here + attr_list.group_id = groupid; + } if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_DEFAULT_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseResponse(); // Zigbee general "Degault Response", publish ZbResponse message + zcl_received.parseResponse(); // Zigbee general "Default Response", publish ZbResponse message } else { - // Build the ZbReceive json + // Build the ZbReceive list if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) { - zcl_received.parseReportAttributes(json); // Zigbee report attributes from sensors + zcl_received.parseReportAttributes(attr_list); // Zigbee report attributes from sensors if (clusterid) { defer_attributes = true; } // don't defer system Cluster=0 messages } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_ATTRIBUTES_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseReadAttributesResponse(json); + zcl_received.parseReadAttributesResponse(attr_list); if (clusterid) { defer_attributes = true; } // don't defer system Cluster=0 messages } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_ATTRIBUTES == zcl_received.getCmdId())) { - zcl_received.parseReadAttributes(json); + zcl_received.parseReadAttributes(attr_list); // never defer read_attributes, so the auto-responder can send response back on a per cluster basis } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_REPORTING_CONFIGURATION_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseReadConfigAttributes(json); + zcl_received.parseReadConfigAttributes(attr_list); } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_CONFIGURE_REPORTING_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseConfigAttributes(json); + zcl_received.parseConfigAttributes(attr_list); } else if (zcl_received.isClusterSpecificCommand()) { - zcl_received.parseClusterSpecificCommand(json); + zcl_received.parseClusterSpecificCommand(attr_list); } - { // fence to force early de-allocation of msg - String msg(""); - msg.reserve(100); - json.printTo(msg); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZCL_RAW_RECEIVED ": {\"0x%04X\":%s}"), srcaddr, msg.c_str()); - } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZCL_RAW_RECEIVED ": {\"0x%04X\":{%s}}"), srcaddr, attr_list.toString().c_str()); // discard the message if it was sent by us (broadcast or group loopback) if (srcaddr == localShortAddr) { @@ -1065,37 +1065,25 @@ void Z_IncomingMessage(ZCLFrame &zcl_received) { return; // abort the rest of message management } - zcl_received.postProcessAttributes(srcaddr, json); - // Add Endpoint - json[F(D_CMND_ZIGBEE_ENDPOINT)] = srcendpoint; - // Add Group if non-zero - if (groupid) { - json[F(D_CMND_ZIGBEE_GROUP)] = groupid; - } - // Add linkquality - json[F(D_CMND_ZIGBEE_LINKQUALITY)] = linkquality; + zcl_received.generateSyntheticAttributes(attr_list); + zcl_received.generateCallBacks(attr_list); // set deferred callbacks, ex: Occupancy + zcl_received.postProcessAttributes(srcaddr, attr_list); // since we just receveived data from the device, it is reachable zigbee_devices.resetTimersForDevice(srcaddr, 0 /* groupaddr */, Z_CAT_REACHABILITY); // remove any reachability timer already there zigbee_devices.setReachable(srcaddr, true); // mark device as reachable - // Post-provess for Aqara Presence Senson - Z_AqaraOccupancy(srcaddr, clusterid, srcendpoint, json); - if (defer_attributes) { // Prepare for publish - if (zigbee_devices.jsonIsConflict(srcaddr, json)) { + if (zigbee_devices.jsonIsConflict(srcaddr, attr_list)) { // there is conflicting values, force a publish of the previous message now and don't coalesce zigbee_devices.jsonPublishFlush(srcaddr); } - zigbee_devices.jsonAppend(srcaddr, json); + zigbee_devices.jsonAppend(srcaddr, attr_list); zigbee_devices.setTimer(srcaddr, 0 /* groupaddr */, USE_ZIGBEE_COALESCE_ATTR_TIMER, clusterid, srcendpoint, Z_CAT_READ_ATTR, 0, &Z_PublishAttributes); } else { // Publish immediately - zigbee_devices.jsonPublishNow(srcaddr, json); - - // Add auto-responder here - Z_AutoResponder(srcaddr, clusterid, srcendpoint, json[F("ReadNames")]); + zigbee_devices.jsonPublishNow(srcaddr, attr_list); } } } @@ -1281,30 +1269,8 @@ int32_t EZ_Recv_Default(int32_t res, const class SBuffer &buf) { * Callbacks \*********************************************************************************************/ - -// Aqara Occupancy behavior: the Aqara device only sends Occupancy: true events every 60 seconds. -// Here we add a timer so if we don't receive a Occupancy event for 90 seconds, we send Occupancy:false -void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, const JsonObject &json) { - static const uint32_t OCCUPANCY_TIMEOUT = 90 * 1000; // 90 s - // Read OCCUPANCY value if any - const JsonVariant &val_endpoint = GetCaseInsensitive(json, PSTR(OCCUPANCY)); - if (nullptr != &val_endpoint) { - uint32_t occupancy = strToUInt(val_endpoint); - - if (occupancy) { - zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback); - } else { - zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY); - } - } -} - - // Publish the received values once they have been coalesced int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - const JsonObject *json = zigbee_devices.jsonGet(shortaddr); - if (json == nullptr) { return 0; } // don't crash if not found - zigbee_devices.jsonPublishFlush(shortaddr); return 1; } @@ -1476,49 +1442,61 @@ int32_t Z_State_Ready(uint8_t value) { // // Mostly used for routers/end-devices // json: holds the attributes in JSON format -void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const JsonObject &json) { +void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const uint16_t *attr_list, size_t attr_len) { DynamicJsonBuffer jsonBuffer; JsonObject& json_out = jsonBuffer.createObject(); - // responder - switch (cluster) { - case 0x0000: - if (HasKeyCaseInsensitive(json, PSTR("ModelId"))) { json_out[F("ModelId")] = F(USE_ZIGBEE_MODELID); } - if (HasKeyCaseInsensitive(json, PSTR("Manufacturer"))) { json_out[F("Manufacturer")] = F(USE_ZIGBEE_MANUFACTURER); } - break; + for (uint32_t i=0; i 0xFEFF) ? uxy[i] : 0xFEFF; - } - if (HasKeyCaseInsensitive(json, PSTR("Hue"))) { json_out[F("Hue")] = changeUIntScale(hue, 0, 360, 0, 254); } - if (HasKeyCaseInsensitive(json, PSTR("Sat"))) { json_out[F("Sat")] = changeUIntScale(sat, 0, 255, 0, 254); } - if (HasKeyCaseInsensitive(json, PSTR("CT"))) { json_out[F("CT")] = LightGetColorTemp(); } - if (HasKeyCaseInsensitive(json, PSTR("X"))) { json_out[F("X")] = uxy[0]; } - if (HasKeyCaseInsensitive(json, PSTR("Y"))) { json_out[F("Y")] = uxy[1]; } - } - break; + case 0x00060000: json_out[F("Power")] = Light.power ? 1 : 0; break; // Power + case 0x00080000: json_out[F("Dimmer")] = LightGetDimmer(0); break; // Dimmer + + case 0x03000000: // Hue + case 0x03000001: // Sat + case 0x03000003: // X + case 0x03000004: // Y + case 0x03000007: // CT + { + uint16_t hue; + uint8_t sat; + float XY[2]; + LightGetHSB(&hue, &sat, nullptr); + LightGetXY(&XY[0], &XY[1]); + uint16_t uxy[2]; + for (uint32_t i = 0; i < ARRAY_SIZE(XY); i++) { + uxy[i] = XY[i] * 65536.0f; + uxy[i] = (uxy[i] > 0xFEFF) ? uxy[i] : 0xFEFF; + } + if (0x0000 == attr) { json_out[F("Hue")] = changeUIntScale(hue, 0, 360, 0, 254); } + if (0x0001 == attr) { json_out[F("Sat")] = changeUIntScale(sat, 0, 255, 0, 254); } + if (0x0003 == attr) { json_out[F("X")] = uxy[0]; } + if (0x0004 == attr) { json_out[F("Y")] = uxy[1]; } + if (0x0007 == attr) { json_out[F("CT")] = LightGetColorTemp(); } + } + break; #endif - case 0x000A: // Time - if (HasKeyCaseInsensitive(json, PSTR("Time"))) { json_out[F("Time")] = (Rtc.utc_time > (60 * 60 * 24 * 365 * 10)) ? Rtc.utc_time - 946684800 : Rtc.utc_time; } - if (HasKeyCaseInsensitive(json, PSTR("TimeEpoch"))) { json_out[F("TimeEpoch")] = Rtc.utc_time; } - if (HasKeyCaseInsensitive(json, PSTR("TimeStatus"))) { json_out[F("TimeStatus")] = (Rtc.utc_time > (60 * 60 * 24 * 365 * 10)) ? 0x02 : 0x00; } // if time is beyond 2010 then we are synchronized - if (HasKeyCaseInsensitive(json, PSTR("TimeZone"))) { json_out[F("TimeZone")] = Settings.toffset[0] * 60; } // seconds - break; + case 0x000A0000: // Time + json_out[F("Time")] = (Rtc.utc_time > (60 * 60 * 24 * 365 * 10)) ? Rtc.utc_time - 946684800 : Rtc.utc_time; + break; + case 0x000AFF00: // TimeEpoch - Tasmota specific + json_out[F("TimeEpoch")] = Rtc.utc_time; + break; + case 0x000A0001: // TimeStatus + json_out[F("TimeStatus")] = (Rtc.utc_time > (60 * 60 * 24 * 365 * 10)) ? 0x02 : 0x00; // if time is beyond 2010 then we are synchronized + break; + case 0x000A0002: // TimeZone + json_out[F("TimeZone")] = Settings.toffset[0] * 60; + break; + case 0x000A0007: // LocalTime // TODO take DST + json_out[F("LocalTime")] = Settings.toffset[0] * 60 + ((Rtc.utc_time > (60 * 60 * 24 * 365 * 10)) ? Rtc.utc_time - 946684800 : Rtc.utc_time); + break; + } } if (json_out.size() > 0) { diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index a6386e491..4dd7e99ad 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -795,7 +795,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind if (nullptr != &val_cluster) { cluster = strToUInt(val_cluster); // first convert as number if (0 == cluster) { - zigbeeFindAttributeByName(val_cluster.as(), &cluster, nullptr, nullptr, nullptr); + zigbeeFindAttributeByName(val_cluster.as(), &cluster, nullptr, nullptr); } } From 4f33a68dae58760dd3a790afe600477353149210 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:01:31 +0200 Subject: [PATCH 20/38] Update template info --- MODULES.md | 2 +- TEMPLATES.md | 452 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 282 insertions(+), 172 deletions(-) diff --git a/MODULES.md b/MODULES.md index 6106f73e6..f4a28d3f7 100644 --- a/MODULES.md +++ b/MODULES.md @@ -80,4 +80,4 @@ Module | LCode | Description 74 Sonoff D1 | x | Sonoff D1 Wifi and RF Dimmer 75 Sonoff ZbBridge | x | Sonoff Zigbee bridge -Over 1400 additional devices are supported using [templates](TEMPLATES.md). +Over 1500 additional devices are supported using [templates](TEMPLATES.md). diff --git a/TEMPLATES.md b/TEMPLATES.md index ff354aab7..8df91d725 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -2,12 +2,12 @@ # Templates -Find below the available templates as of July 2020. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) +Find below the available templates as of September 2020. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) ## Aromatherapy Diffuser ``` Asakuki 500ml {"NAME":"Oil Diffuser","GPIO":[255,255,255,255,255,255,0,0,255,255,255,21,22],"FLAG":0,"BASE":18} -Blitzwolf BW-FUN3 400ml {"NAME":"Generic","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":0,"BASE":54} +BlitzWolf BW-FUN3 400ml {"NAME":"Generic","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":0,"BASE":54} Brilex 400ml Oil Diffuser {"NAME":"BrilexDiffuser","GPIO":[255,255,255,255,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} Essential Oil 400ml {"NAME":"XD800W","GPIO":[255,255,255,255,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} GD-30W 300ml {"NAME":"GD-30W","GPIO":[255,255,255,255,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} @@ -38,32 +38,35 @@ Anoopsyche 9W 800lm {"NAME":"Anoop-CW-WW","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0 Arlec Smart 1350lm PAR38 {"NAME":"Arlec GLD302HA","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Arlec Smart 9.5W 806lm {"NAME":"Arlec GLD110HA","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} Arlec Smart 9.5W 806lm {"NAME":"Arlec CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} +BlitzWolf A70 9W 900lm {"NAME":"BW-LT29","GPIO":[0,0,0,0,0,0,0,0,0,47,0,37,0],"FLAG":0,"BASE":18} BrilliantSmart 20696 9W 900lm {"NAME":"Brilliant20696","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} BrilliantSmart 20697 9W 900lm {"NAME":"Brilliant20696","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} +BrilliantSmart 4.5W 400lm {"NAME":"BS-GU10-20887","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Bulbrite Solana A19 Edison Filament {"NAME":"BulbBrite01","GPIO":[0,0,0,0,0,0,0,0,37,0,38,0,0],"FLAG":0,"BASE":18} Bulbrite Solana G25 5.5W 600lm Filament {"NAME":"BulbBrite01","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Bulbrite Solana ST18 16W 140lm Filament {"NAME":"BulbBrite02","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Calex G125 7,5W 1055lm {"NAME":"Calex G125 E27","GPIO":[0,0,0,0,0,140,0,0,38,0,37,142,141],"FLAG":0,"BASE":18} Calex G125 7.5W 1055lm Globe {"NAME":"Calex G125 E27","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} -Connect Smart GU5.3 5W {"NAME":"Connect CSH-GU53WW5W","GPIO":[0,0,0,0,37,38,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Connect SmartHome 10W 900lm {"NAME":"Connect CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} +Connect SmartHome 10W {"NAME":"CSH-B22WW10W","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} +Connect SmartHome 10W {"NAME":"CSH-E27WW10W","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} +Connect SmartHome GU5.3 5W {"NAME":"Connect CSH-GU53WW5W","GPIO":[0,0,0,0,37,38,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Deltaco SH-LE14W 470lm {"NAME":"SH-LE14W","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Deltaco SH-LE27W 810lm {"NAME":"SH-LE27W","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} DORESshop A60 720lm Filament {"NAME":"DORESshop-A60","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Energizer A19 10W Smart White {"NAME":"Energizer CCT ","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Euri Lighting A19 10W 800lm {"NAME":"Euri Lighting ","GPIO":[0,0,0,0,37,38,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Geeni LUX 1050lm {"NAME":"Geeni-1050-WW","GPIO":[0,0,0,0,37,37,0,0,38,0,0,0,0],"FLAG":1,"BASE":18} +Geeni LUX 1050lm {"NAME":"Geeni-1050-WW","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":1,"BASE":18} Globe A19 10W 800lm {"NAME":"GlobeCCT","GPIO":[0,0,0,0,38,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Globe G25 Edison 500lm {"NAME":"Globe 34920","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Globe ST19 Edison 500lm {"NAME":"Globe 34919","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Hama 806lm {"NAME":"Hama 00176550","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Hykker SL-0392 650lm {"NAME":"Hykker 7W","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Iotton 9W 700lm {"NAME":"Iotton Light","GPIO":[0,0,0,0,37,38,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Kogan 10W Cool & Warm White 1050lm {"NAME":"Kogan 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":0,"BASE":48} +Kogan 10W Cool & Warm White 1050lm {"NAME":"Kogan 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} Kogan 4.5W 330lm 110C {"NAME":"Kogan White/Wa","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Kogan 5W {"NAME":"Kogan Co/Wa","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Laser 10W 1000lm {"NAME":"Laser 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} -Laser 10W 1000lm {"NAME":"Laster 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} +Laser 10W 1000lm {"NAME":"Laster 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} LE lampUX 380lm Candle {"NAME":"LE Bulb","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} LE LampUX 4.5W 410lm {"NAME":"LE LampUX","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":48} ledscom.de 4.5W 430lm {"NAME":"GX53","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":0} @@ -75,12 +78,12 @@ Luminea ZX-2831 {"NAME":"Luminea CCT","GPIO":[0,0,0,0,140,37,0,0,38,142 LVWIT A60 6.5W 806lm Filament {"NAME":"LVWIT-E27-WiFi-6.5","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Merkury MI-BW905-999W 700lm {"NAME":"MI-BW905-999W","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Mimoodz A21 10.5W 1050lm {"NAME":"Mimoodz","GPIO":[0,0,0,0,21,22,0,0,23,24,25,26,27],"FLAG":0,"BASE":18} +Mirabella Genio 6W 500lm {"NAME":"GenioGU10","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbCCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbCCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbCCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} -Mirabella Genio I002745 SES 470lm {"NAME":"Mirabella Candle","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} -Mirabella Genio I002746 500lm {"NAME":"GenioGU10","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} -Mirabella Genio I002747 G95 470lm {"NAME":"Genio Filament","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} +Mirabella Genio G95 5W 470lm {"NAME":"Genio Filament","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} +Mirabella Genio SES 5.5W 470lm {"NAME":"Mirabella Candle","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Nedis A60 5.5W 350lm Twisted Filament {"NAME":"WIFILT10GDA60","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Nedis A60 800lm {"NAME":"WIFILW10WTE27","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Nedis C10 350lm {"NAME":"WIFILW10WTE14","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} @@ -89,7 +92,9 @@ Nedis PAR16 330lm {"NAME":"Nedis WIFILW30","GPIO":[0,0,0,0,0,37,0,0,38,0, Nedis PAR16 4.5W 330lm 110C {"NAME":"WIFILW30","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Philips Zhirui Candle 250lm {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,38,0,0,37,0],"FLAG":0,"BASE":48} Phillips Zhirui 450lm {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,38,0,0,37,0],"FLAG":0,"BASE":48} +Polux ST64 5.5W 470lm {"NAME":"basic","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} SmartDGM L-WT9W1 9W 800lm {"NAME":"L-WT9W1","GPIO":[0,0,0,0,0,37,0,0,9,38,0,0,0],"FLAG":0,"BASE":18} +Spectrum Smart 5W 410lm Candle {"NAME":"lightbulb","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Swisstone SH 330 806lm {"NAME":"SwisstoneSH330","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} V-Tac PAR16 4.5W 300lm 110C {"NAME":"V-TAC VT-5174","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Vestaiot BR30 800lm {"NAME":"Vesta BR30 CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} @@ -97,6 +102,36 @@ Wipro Garnet NS9100 810lm {"NAME":"WiproSmartBulb","GPIO":[0,0,0,0,38,0,0,0,37, Wyze WLPA19 A19 800lm {"NAME":"Wyze Bulb","GPIO":[0,0,0,0,0,0,0,0,0,37,38,0,0],"FLAG":0,"BASE":48} ``` +## Ceiling Light +``` +BAZZ 14" RGBCCT {"NAME":"WF19129W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +BlitzWolf 24W {"NAME":"BW-LT20","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":15,"BASE":18} +BrilliantSmart 12W 290mm Salisbury CCT {"NAME":"Brilliant Smart Salisbury","GPIO":[0,0,0,0,0,0,0,0,47,0,37,0,0],"FLAG":0,"BASE":18} +BrilliantSmart 24W 410mm Salisbury CCT {"NAME":"Salisbury","GPIO":[0,0,0,0,0,0,0,0,47,0,37,0,0],"FLAG":0,"BASE":48} +BrilliantSmart Cordia 24W CCT {"NAME":"Cordia","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} +Calex 429250 {"NAME":"Calex_LED","GPIO":[0,0,0,0,0,0,0,0,0,47,37,0,0],"FLAG":0,"BASE":18} +Fcmila 48W RGBCCT {"NAME":"XDD-48W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +LE lampUX 15W RGBCCT {"NAME":"LE lampUX 15W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Lohas ZN026CL10 RGBCCT {"NAME":"Lohas LED Lamp","GPIO":[0,0,0,0,38,37,0,0,40,39,41,0,0],"FLAG":0,"BASE":18} +LSC 20W 1400lm White Ambiance {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} +Luminea 24W CCT {"NAME":"Luminea NX6205-944","GPIO":[0,0,0,0,0,0,0,0,47,0,37,0,0],"FLAG":0,"BASE":48} +LVL 300mm Round {"NAME":"LVL 300m Round 24W Ceiling LED","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":0,"BASE":48} +SMRTLite LED Panel {"NAME":"SMRTLite","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} +Utorch 24W 2000lm CCT {"NAME":"Utorch PZE-911","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":1} +Utorch 24W 2000lm CCT {"NAME":"Utorch UT40","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":1} +Verve Design Angie 18W RGB Ring {"NAME":"ACL12HA Light","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} +Verve Design Charlie 22W CCT {"NAME":"Verve ACL01HA","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":0,"BASE":48} +Verve Design Hana 24W CCT {"NAME":"Verve ACL03HA","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":48} +``` + +## Contact Sensor +``` +Digoo DG-ZXD21 Door Detector {"NAME":"Digoo ZXD21","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Earykong TYMC-1 Door Window {"NAME":"TYMC-1","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +TY01 Door Window {"NAME":"TY01","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Zemismart Door Window {"NAME":"Zemismart","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +``` + ## Curtain Switch ``` Anccy Relax {"NAME":"Tuya Shutter","GPIO":[157,0,54,10,22,19,0,0,17,21,53,23,52],"FLAG":0,"BASE":18} @@ -123,11 +158,10 @@ ESP-01(S) {"NAME":"ESP01","GPIO":[255,255,255,255,0,0,0,0,0,0,0,0 ESP-M3 {"NAME":"ESP-M3","GPIO":[255,255,255,255,255,0,0,0,0,255,255,0,255],"FLAG":0,"BASE":18} Heltec WiFi Kit 8 {"NAME":"HTIT-W8266","GPIO":[255,255,255,255,6,5,0,0,255,255,255,255,162],"FLAG":15,"BASE":18} LC Tech relay and PZEM-004T {"NAME":"HW-655 PZEM","GPIO":[0,63,0,62,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Luani HVIO {"NAME":"Luani HVIO","GPIO":[0,255,255,255,21,22,0,0,9,10,255,52,0],"FLAG":1,"BASE":35} +LC Technology PSF-B04 Ewelink 4 Channel Switch Module {"NAME":"LC-EWL-B04-MB","GPIO":[255,255,255,255,255,255,0,0,255,52,255,255,0],"FLAG":0,"BASE":18} OLED Display Module 0.66" for Wemos D1 Mini {"NAME":"OLED 64x48","GPIO":[255,255,255,255,6,5,0,0,255,255,255,255,162],"FLAG":15,"BASE":18} QuinLED 2 Channel {"NAME":"QuinLED 2 channel","GPIO":[37,0,38,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Splatura USB Device Power Switch {"NAME":"Splatura USB","GPIO":[0,0,52,0,0,0,0,0,0,21,0,122,0],"FLAG":0,"BASE":18} -SUPLA inCan by Espablo {"NAME":"Supla Espablo","GPIO":[0,255,4,255,17,21,0,0,255,22,255,0,52],"FLAG":1,"BASE":31} +WifInfo - Teleinfo Server {"NAME":"WifInfo","GPIO":[7,255,255,210,6,5,255,255,255,255,255,255,255],"FLAG":15,"BASE":18} Witty Cloud {"NAME":"Witty Cloud","GPIO":[255,255,56,255,17,255,0,0,38,39,255,37,255],"FLAG":1,"BASE":32} Yison ESP-01/ESP-202 Development Board {"NAME":"Yison Dev Board","GPIO":[32,157,31,255,33,34,255,255,37,39,30,38,29],"FLAG":15,"BASE":18} ``` @@ -141,7 +175,6 @@ Arlec Smart 4W 380lm Candle {"NAME":"Arlec Bulb 4W","GPIO":[0,0,0,0,0,0,0,0,0,0 Arlec Smart 9W 950lm 4000K {"NAME":"Arlec-GLD124HA","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Avatar ALS15L Candle {"NAME":"AVATAR","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} Cleverio 51396 800lm {"NAME":"Cleverio E27","GPIO":[0,0,0,0,0,0,0,0,0,0,46,0,0],"FLAG":0,"BASE":18} -Connect Smart 10W {"NAME":"CSH-B22WW10W","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Digma DiLight E27 W1 {"NAME":"DiLight E27 W1","GPIO":[0,0,0,0,37,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} DORESshop B11 600lm Filament {"NAME":"Doresshop-cand","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} DORESshop ST64 720lm Filament {"NAME":"DORESshop-ST64","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} @@ -154,6 +187,7 @@ Geeni LUX Edison {"NAME":"Geeni-Edison","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0 Globe A19 10W 800lm {"NAME":"Globe WW 800lm","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Gosund A19 8W 2700K {"NAME":"Gosund Wifi Dimmable Bulb","GPIO":[0,0,0,0,37,0,0,0,0,52,0,0,0],"FLAG":0,"BASE":18} Hama 7W 900lm Filament {"NAME":"Hama Filament","GPIO":[255,255,255,255,255,255,255,255,255,255,46,255,255],"FLAG":15,"BASE":18} +Jetstream 9W 800lm {"NAME":"Jetstream MA19WH","GPIO":[0,0,0,0,37,0,0,0,0,52,0,0,0],"FLAG":0,"BASE":18} KMC 70113 A19 7.5W {"NAME":"Generic","GPIO":[0,0,0,0,0,0,37,38,0,0,0,0,0],"FLAG":15,"BASE":18} Kogan ST-20 Filament {"NAME":"Kogan Filament","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":15,"BASE":18} Krisbow Bohlam 14W {"NAME":"Krisbow SmartL","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} @@ -165,23 +199,29 @@ LSC Filament A60 {"NAME":"LSC Filam E27","GPIO":[0,0,0,0,0,0,0,0,38,0,37 LSC Filament C35 {"NAME":"LSC Filam E14","GPIO":[0,255,0,255,0,0,0,0,38,0,37,0,0],"FLAG":15,"BASE":18} LSC Filament G125 {"NAME":"LSC Filam Huge","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} LSC Filament ST64 5.5W 470lm {"NAME":"LSC Filam Big","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} +Luedd 7W 800lm Filament {"NAME":"Luedd E27","GPIO":[0,0,0,0,0,0,0,0,0,0,46,0,0],"FLAG":0,"BASE":18} Lumary 6W 700lm Edison {"NAME":"Lumary TS3Y","GPIO":[0,0,0,0,0,0,0,0,0,37,0,0,0],"FLAG":0,"BASE":18} Luminea ZX-2880 A60 800lm {"NAME":"LAV-110.w","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Luminea ZX-2982 ST64 Filament {"NAME":"Luminea ZX2982","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} +MagicHome 7.5W Warm White {"NAME":"ZJ-8C2B-CCT-AV1.1","GPIO":[0,0,0,0,0,0,0,0,37,0,0,0,0],"FLAG":0,"BASE":18} Merkury 9W 800lm {"NAME":"MI-BW320-999W","GPIO":[0,0,0,0,0,0,0,0,0,0,21,0,0],"FLAG":0,"BASE":18} Merkury MI-BW902-999W 800lm {"NAME":"MI-BW902-999W","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Merkury MI-BW942-999W 800lm {"NAME":"MI-BW942-999W","GPIO":[0,0,0,0,37,0,0,0,0,52,0,0,0],"FLAG":0,"BASE":18} Merkury MIC-BW902-999W {"NAME":"MI-BW902-999W","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Merkury Vintage Edison A19 {"NAME":"Merkury A19 Ed","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Mirabella Genio 800lm {"NAME":"GenioBulbCW","GPIO":[0,0,0,0,38,37,0,0,0,40,39,0,0],"FLAG":0,"BASE":18} -Mirabella Genio 9W 800lm {"NAME":"GenioB22","GPIO":[0,0,0,0,0,0,0,0,0,37,0,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 9W 800lm {"NAME":"GenioB22","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 9W 800lm {"NAME":"Mirabella Genio I002606","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 9W 800lm WW {"NAME":"Genio WW","GPIO":[0,0,0,0,0,0,0,0,0,37,0,0,0],"FLAG":0,"BASE":18} Mirabella Genio A70 1400lm {"NAME":"GenioB_CW2744","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} +Nedis A60 5W 500lm {"NAME":"WIFILF11WTA60","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Nedis A60 Filament {"NAME":"WIFILF10WTA60","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Nedis A60 Warm White 9W 800lm {"NAME":"WIFILW11WTE27","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Nedis G125 Filament {"NAME":"WIFILF10GDG125","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Nedis PAR16 330lm {"NAME":"Nedis WIFILW31","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Sealight Vintage Edison A19 {"NAME":"SealightEdison","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} TCP Smart 810lm Filament {"NAME":"TCP Filament","GPIO":[0,0,0,0,0,0,0,0,0,0,46,0,0],"FLAG":0,"BASE":18} +TCP Smart 810lm Filament {"NAME":"TCP Filament","GPIO":[0,0,0,0,0,0,0,0,0,0,46,0,0],"FLAG":0,"BASE":18} Xiaomi Philips MUE4088RT {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,0,0,0,37,0],"FLAG":0,"BASE":18} ``` @@ -196,7 +236,8 @@ BrilliantSmart Jupiter {"NAME":"BrSm Jupiter","GPIO":[0,107,0,108,0,0,0,0,0,0, CE Smart Home {"NAME":"CE-WF500D","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} CE Smart Home CFW500D-3W 3 Way {"NAME":"CE-WF500D-3W","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} CNSKOU Touch {"NAME":"CNSKOU Dimmer Switch","GPIO":[0,0,0,0,0,0,0,0,0,0,54,0,0],"FLAG":0,"BASE":54} -Eva Logik WF31 {"NAME":"WF31 Dimmer","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +Eva Logik {"NAME":"WF31 Dimmer","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +Eva Logik 3 Way {"NAME":"EL WF31T","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} EX-Store 2 Kanal RS232 V4 {"NAME":"EXS Dimmer","GPIO":[0,148,0,149,0,0,0,0,0,183,0,0,0],"FLAG":0,"BASE":72} Feit Electric DIM/WIFI {"NAME":"Generic","GPIO":[255,107,255,108,255,255,0,0,255,0,255,0,255],"FLAG":0,"BASE":54} Gosund SW2 {"NAME":"Gosund Dimmer","GPIO":[255,148,255,149,17,0,255,255,56,158,37,255,255],"FLAG":0,"BASE":18} @@ -213,11 +254,18 @@ Tessan MJ-SD02 {"NAME":"MJ-SD02","GPIO":[19,18,0,59,158,58,0,0,57,37,5 TopGreener TGWF500D {"NAME":"TopGreener-Dimmer","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} TreatLife DS01 {"NAME":"DS02S Dimmer","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} TreatLife DS02S {"NAME":"DS02S Dimmer","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +TreatLife Light and Fan {"NAME":"DS03 Fan/Light","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} WF-DS01 {"NAME":"Dimmer WF-DS01","GPIO":[255,255,255,255,255,255,0,0,255,255,54,255,255],"FLAG":0,"BASE":54} WiFi Dimmer Switch {"NAME":"PS-16-DZ","GPIO":[0,148,0,149,0,0,0,0,0,52,0,0,0],"FLAG":0,"BASE":58} Zemismart KS-7011 {"NAME":"KS-7011 Dimmer","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} ``` +## Energy Meter +``` +Hiking Single Phase 65A Din Rail {"NAME":"hiking dds2382wifi","GPIO":[0,107,0,108,0,0,0,0,0,0,56,0,17],"FLAG":0,"BASE":1} +ZMAi-90 Digital {"NAME":"ZMAi-90","GPIO":[0,148,0,149,0,0,0,0,21,90,0,0,0],"FLAG":0,"BASE":18} +``` + ## Fan ``` Anko HEGSM40 {"NAME":"Anko HEGSM40","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} @@ -233,6 +281,11 @@ Technical Pro FXA16 {"NAME":"FXA16 Fan","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0 Zemismart Bladeless {"NAME":"Bladeless Fan","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} ``` +## Gas Sensor +``` +Natural Gas (CH4) Alarm {"NAME":"PA-210WYS","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +``` + ## IR Bridge ``` A1 Universal Remote Control {"NAME":"A1 IR Bridge","GPIO":[255,255,255,255,56,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} @@ -240,7 +293,7 @@ Alfawise KS1 {"NAME":"KS1","GPIO":[255,71,17,72,17,51,0,0,56,0,8,0,0 auvisio S06 {"NAME":"NX-4519-675","GPIO":[255,255,255,255,52,51,0,0,255,255,8,255,255],"FLAG":1,"BASE":18} BlitzWolf BW-RC1 Smart IR Controller {"NAME":"BW-RC1","GPIO":[0,0,0,0,56,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} Connect SmartHome Universal Smart IR Remote {"NAME":"CSH IR Bridge","GPIO":[255,255,255,255,56,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} -Cusam CS-IRC-1 {"NAME":"YTF IR Bridge","GPIO":[255,255,255,255,56,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} +Cusam CS-IRC-1 {"NAME":"YTF IR Bridge","GPIO":[255,255,255,255,52,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} Eachen IR DC6 {"NAME":"Eachen IR","GPIO":[0,0,0,0,56,51,0,0,255,17,8,0,0],"FLAG":0,"BASE":18} Geeklink GK01 {"NAME":"GL IR Blaster","GPIO":[255,255,255,255,56,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} Jinvoo AC/TV Box Controller {"NAME":"Jinvoo IR Bridge","GPIO":[255,255,255,255,56,51,0,0,0,17,8,0,0],"FLAG":0,"BASE":62} @@ -283,10 +336,10 @@ Luminea ZX-2844 {"NAME":"Luminea ZX-284","GPIO":[40,0,0,0,0,39,0,0,38,1 Luminea ZX-2844-675 {"NAME":"ZX-2844-675","GPIO":[17,0,0,0,38,40,0,0,37,0,39,0,0],"FLAG":0,"BASE":18} Lustreon {"NAME":"Lustreon WiFi ","GPIO":[17,0,55,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":38} Magic UFO RGBW {"NAME":"Magic UFO","GPIO":[17,0,157,0,0,37,0,0,39,40,38,56,0],"FLAG":0,"BASE":18} -MagicHome RGB ZJ-WFMN-B V1.1 {"NAME":"MagicHome RGB","GPIO":[0,0,0,0,0,37,0,0,38,39,0,0,0],"FLAG":0,"BASE":34} -MagicHome RGBW ESP-IR-B-v2.3 {"NAME":"ESP-IR-B-v2.3","GPIO":[0,0,51,0,0,38,0,0,37,39,0,40,0],"FLAG":0,"BASE":18} -MagicHome RGBW RF {"NAME":"MagicHome RF","GPIO":[0,0,0,0,0,38,0,0,39,40,37,0,0],"FLAG":0,"BASE":18} -MagicHome RGBW ZJ-WFMN-A V1.1 {"NAME":"MagicHome RGBW","GPIO":[0,0,0,0,51,38,0,0,37,39,0,40,0],"FLAG":0,"BASE":34} +MagicHome RGB ZJ-WFMN-A V1.1 {"NAME":"MagicHome RGB","GPIO":[0,0,0,0,0,37,0,0,38,39,0,0,0],"FLAG":0,"BASE":34} +MagicHome RGBW {"NAME":"ESP-IR-B-v2.3","GPIO":[0,0,51,0,0,38,0,0,37,39,0,40,0],"FLAG":0,"BASE":18} +MagicHome RGBW RF {"NAME":"MagicHome RGBW RF","GPIO":[0,0,56,0,147,38,0,0,39,40,37,159,0],"FLAG":0,"BASE":18} +MagicHome RGBW ZJ-WFMN-B V1.1 {"NAME":"MagicHome RGBW RF (ZJ-WFMN-B V1.1)","GPIO":[0,0,0,0,147,38,0,0,39,40,37,0,159],"FLAG":0,"BASE":34} MagicHome RGBWW w/ RF {"NAME":"MagicHome RF","GPIO":[0,0,159,0,37,38,0,0,41,40,39,147,0],"FLAG":0,"BASE":38} MagicHome RGBWW w/ RF {"NAME":"MagicHome RF","GPIO":[0,0,0,0,147,40,0,0,38,39,37,41,159],"FLAG":0,"BASE":18} MagicHome Single Color 5-28V {"NAME":"MagicHome","GPIO":[0,0,0,0,0,0,0,0,37,0,0,0,0],"FLAG":0,"BASE":18} @@ -308,8 +361,10 @@ Cocoon Smart {"NAME":"Cocoon Smart","GPIO":[17,0,0,0,37,0,0,0,38,0,3 Deltaco 3m RGBCCT {"NAME":"Deltaco Led Strip","GPIO":[0,0,0,0,37,17,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} electriQ 3m RGBCCT {"NAME":"ElectricQ wifiRGBWLEDSTR","GPIO":[0,0,0,0,37,41,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} Elfeland 10m RGB {"NAME":"Elfeland RGB","GPIO":[0,0,0,0,0,38,0,0,39,51,0,37,0],"FLAG":0,"BASE":18} +Energizer Multi-Color 6.5ft {"NAME":"Energizer","GPIO":[0,0,0,0,0,38,0,0,39,0,0,37,0],"FLAG":0,"BASE":18} Geeni Prisma Plus {"NAME":"Geeni Prisma Plus Strip","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Gosund 2.8m RGB {"NAME":"Gosund LED Strip","GPIO":[17,0,0,0,0,0,0,0,37,39,38,0,0],"FLAG":3,"BASE":18} +Gosund SL2 5m RGB {"NAME":"Gosund LED Str","GPIO":[0,0,0,0,17,38,0,0,37,39,0,0,0],"FLAG":3,"BASE":18} HitLights L1012V-MC1 {"NAME":"HitLights RBG","GPIO":[17,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} HomeMate 10m RGB {"NAME":"Homemate Strip","GPIO":[0,0,0,0,0,37,0,0,39,17,38,0,0],"FLAG":0,"BASE":18} Hykker 3m RGB {"NAME":"HYKKER Strip","GPIO":[0,0,0,0,0,37,0,0,39,17,38,0,0],"FLAG":0,"BASE":18} @@ -321,77 +376,64 @@ LE LampUX 5m RGB {"NAME":"LampUX","GPIO":[17,0,0,0,0,38,0,0,39,0,0,37,0] LE LampUX 5m RGB {"NAME":"LE LampUx","GPIO":[0,0,0,0,0,38,0,0,39,0,0,37,0],"FLAG":0,"BASE":34} LE lampUX 5m RGBW {"NAME":"LampUX","GPIO":[0,0,17,0,0,38,0,0,39,0,40,37,0],"FLAG":0,"BASE":18} Lohas ZN022 5m RGBW {"NAME":"LOHAS M5-022","GPIO":[0,0,0,0,38,37,0,0,17,39,0,0,0],"FLAG":0,"BASE":18} -LSC RGBW {"NAME":"LSC RGBW Strip","GPIO":[51,0,0,0,37,0,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} +LSC RGBW {"NAME":"LSC RGBW Strip","GPIO":[51,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Lumary RGBCCT {"NAME":"Lumary LED","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Lumary RGBCCT {"NAME":"Lumary LED","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Maxonar Lightstrip Pro XS-SLD001 {"NAME":"Maxonar LED","GPIO":[0,0,0,0,0,37,0,0,39,17,38,0,0],"FLAG":0,"BASE":18} Merkury Innovations MI-EW003-999W {"NAME":"MI-EW003-999W ","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} -Mirabella Genio I002579 {"NAME":"MirabellaStrip","GPIO":[17,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +Mirabella Genio RGB+CW {"NAME":"MirabellaStrip","GPIO":[17,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Monster Smart IlluminEssence {"NAME":"MI-EW003-999W ","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Polux RGB+NW 2m {"NAME":"Polux Wi-Fi SM","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":37} Powertech 5m RGBW {"NAME":"Jaycar ST3992 LED Strip","GPIO":[122,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +Reafoo RGBW 5m {"NAME":"REAFOO RGBW LS","GPIO":[17,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Sonoff L1 {"NAME":"SonoffL1","GPIO":[0,148,0,149,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":70} Teckin SL02 {"NAME":"Teckin SL02","GPIO":[51,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":52} Teckin SL07 32.8ft RGB {"NAME":"WIFI RGB","GPIO":[51,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} TORCHSTAR CCT 30W Lighting Kit {"NAME":"Torchstar CCT ","GPIO":[0,0,0,0,52,38,0,0,0,17,0,37,53],"FLAG":0,"BASE":18} Torchstar Safe Lighting Kit {"NAME":"Torchstar","GPIO":[0,0,0,0,52,0,0,0,0,0,0,37,53],"FLAG":1,"BASE":18} -Woox 5m RGBW {"NAME":"GardenLedstrip1","GPIO":[0,0,0,0,0,38,0,0,39,9,37,0,0],"FLAG":0,"BASE":18} +WOOX 5m RGBW {"NAME":"GardenLedstrip1","GPIO":[0,0,0,0,0,38,0,0,39,9,37,0,0],"FLAG":0,"BASE":18} Zemismart 3m Extendable RGBW {"NAME":"Zemismart LED","GPIO":[0,0,0,0,38,37,0,0,0,39,40,0,0],"FLAG":0,"BASE":18} ``` ## Light ``` +Arlec Smart 10W LED Bunker {"NAME":"DetaBulkhead","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Arlec Smart 15W Security Floodlight {"NAME":"ArlecFlood","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":15,"BASE":18} Arlec Smart 20W Movement Activated Security {"NAME":"Arlec MAL300HA","GPIO":[0,0,0,0,21,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Arlec Smart 40W 4000lm LED Batten {"NAME":"Arlec Batten","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Arlec Smart Portable Floodlight 10.5W {"NAME":"Arlec GLD301HA","GPIO":[0,0,0,0,0,37,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Arlec Smart Up & Down LED Wall {"NAME":"Arlec Up Down CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} -BAZZ 14" RGBCCT Ceiling Fixture {"NAME":"WF19129W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} BAZZ 4 in. RGB Recessed Fixture {"NAME":"SLMR4RGBWWFW","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} -BlitzWolf BW-LT20 {"NAME":"BW-LT20","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":15,"BASE":18} Brelong USB Charging Night {"NAME":"Brelong Smart USB Charging Lamp","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,40],"FLAG":0,"BASE":18} -Brilex Nightstand Lamp {"NAME":"Smart Table La","GPIO":[0,0,18,0,37,157,0,0,38,17,39,0,40],"FLAG":0,"BASE":18} -BrilliantSmart 12W 290mm Salisbury CCT Ceiling {"NAME":"Brilliant Smart Salisbury","GPIO":[0,0,0,0,0,0,0,0,47,0,37,0,0],"FLAG":0,"BASE":18} +Brilex Nightstand Lamp {"NAME":"Smart Table Lamp","GPIO":[0,0,18,0,37,157,0,0,38,17,39,0,40],"FLAG":0,"BASE":18} BrilliantSmart 20695 Downlight CCT {"NAME":"SmartCCTDwnLgt","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} -BrilliantSmart 24W 410mm Salisbury CCT Ceiling {"NAME":"Salisbury","GPIO":[0,0,0,0,0,0,0,0,47,0,37,0,0],"FLAG":0,"BASE":48} -BrilliantSmart Cordia 24W CCT Ceiling {"NAME":"Cordia","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} BrilliantSmart Prism LED RGBCCT Downlight {"NAME":"Prism","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} BrilliantSmart RGB Garden Kit {"NAME":"Brilliant Gard","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} -Calex 429250 Ceiling {"NAME":"Calex_LED","GPIO":[0,0,0,0,0,0,0,0,0,47,37,0,0],"FLAG":0,"BASE":18} -Connect SmartHome CSH-240RGB10W {"NAME":"Connect1","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Connect SmartHome CSH-240RGB10W {"NAME":"CSH-240RGB10W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Connect SmartHome CSH-FSTN12 {"NAME":"CSH-FSTN12","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Deta 18W 1900lm T8 Tube {"NAME":"DETA Smart LED","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Deta DET902HA 10W 940lm RGB+CCT {"NAME":"Deta DownLight","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} electriQ MOODL Ambiance Lamp {"NAME":"ElectriQ MOODL","GPIO":[0,201,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Fcmila 48W RGBCCT Ceiling Lamp {"NAME":"XDD-48W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Feit Electric 6in. RGBW Recessed Downlight {"NAME":"Feit LEDR6/RGB","GPIO":[0,0,0,0,37,40,0,0,38,50,39,0,0],"FLAG":0,"BASE":48} Globe 5W 4" Recessed RGBCCT {"NAME":"GlobeRGBWW","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Hugoai Table Lamp {"NAME":"HG02","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} Hyperikon 14W 1000lm 6" Downlight {"NAME":"HyperikonDL6","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} iHomma 6W RGBCCT Downlight {"NAME":"iHomma RGBWW","GPIO":[0,0,0,0,41,40,0,0,37,38,39,0,0],"FLAG":0,"BASE":18} iHomma Downlight {"NAME":"iHommaLEDDownl","GPIO":[0,0,0,0,0,40,0,0,37,38,39,0,0],"FLAG":0,"BASE":18} Kogan 9W Downlight RGBCCT {"NAME":"Kogan_SMARTLED","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} -LE lampUX 15W RGBCCT Ceiling {"NAME":"LE lampUX 15W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} -Lohas ZN026CL10 RGBCCT {"NAME":"Lohas LED Lamp","GPIO":[0,0,0,0,38,37,0,0,40,39,41,0,0],"FLAG":0,"BASE":18} -LSC 20W 1400lm White Ambiance Ceiling {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} Lumary 18W RGBCCT Recessed Panel {"NAME":"LumaryDLghtRGB","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} -LVL 300mm Round Ceiling {"NAME":"LVL 300m Round 24W Ceiling LED","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":0,"BASE":48} Mi LED Desk Lamp MJTD01YL {"NAME":"Mi Desk Lamp","GPIO":[0,0,17,0,37,38,0,0,150,151,0,0,0],"FLAG":0,"BASE":66} -MiraBella Genio 6 Pack 30mm Stainless Steel Deck Kit {"NAME":"Genio RGB Deck Lights","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} -Mirabella Genio CCT Deck Lights {"NAME":"Mirabella Deck CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} -Mirabella Genio I002741 {"NAME":"GenioDLightRGB","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} -Mirabella Genio I002742 {"NAME":"GenioDLightCCT","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":48} -Mirabella Genio I002798 Warm White Filament Festoon {"NAME":"GenioFestoon","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 10 LED Filament Festoon {"NAME":"GenioFestoon","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 4 Black LED Garden Path {"NAME":"GenioGardenStr","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 9W CCT Downlight {"NAME":"GenioDLightCCT","GPIO":[0,0,0,0,0,0,0,0,47,0,37,0,0],"FLAG":0,"BASE":48} +Mirabella Genio 9W RGBCCT Downlight {"NAME":"GenioDLightRGB","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} +Mirabella Genio CCT 6 LED 30mm Stainless Steel Deck {"NAME":"Mirabella Deck CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} +MiraBella Genio Colour 6 LED 30mm Stainless Steel Deck {"NAME":"Genio RGB Deck Lights","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Moes 7W RGBCCT Downlight {"NAME":"Moes Downlight","GPIO":[0,0,0,0,40,41,0,0,37,38,39,0,0],"FLAG":0,"BASE":18} Novostella UT88835 20W Floodlight {"NAME":"Novo 20W Flood","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} -Reafoo A27 9W 810lm {"NAME":"ReaFooE27","GPIO":[0,0,0,0,41,40,0,0,37,0,39,38,0],"FLAG":0,"BASE":18} -SMRTLite LED Panel {"NAME":"SMRTLite","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} Sonoff BN-SZ01 {"NAME":"Sonoff BN-SZ","GPIO":[0,0,0,0,0,0,0,0,37,56,0,0,0],"FLAG":0,"BASE":22} Spotlight 9cm RGB+W 7W {"NAME":"Spotlight RGBW","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} Teckin FL41 {"NAME":"Teckin FL41","GPIO":[0,0,0,0,0,17,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} -Utorch PZE-911 {"NAME":"Utorch PZE-911","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":1} -Utorch UT40 {"NAME":"Utorch UT40","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":1} -Verve Design Angie 18W Ceiling Light With RGB Ring {"NAME":"ACL12HA Light","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} -Verve Design Charlie 22W CCT Ceiling {"NAME":"Verve ACL01HA","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":0,"BASE":48} -Verve Design Hana 24W CCT Ceiling {"NAME":"Verve ACL03HA","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":48} Wipro Next 20W Smart LED Batten {"NAME":"WIPROBatten","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":1,"BASE":18} Zemismart 4" 10W RGBCCT {"NAME":"ZemiDownLight4","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Zemismart 4" 10W RGBW {"NAME":"ZemiDownLight","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} @@ -400,6 +442,8 @@ Zemismart 6" 14W RGBCCT {"NAME":"ZemiDownLight6","GPIO":[0,0,0,0,37,40,0,0,38,4 ## Miscellaneous ``` +Alfawise Air Purifier {"NAME":"alfawise P2","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +Dealdig Robvaccum 8 Vacuum {"NAME":"WhiteVacuum","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} iLONDA Fish feeder {"NAME":"Feeder","GPIO":[0,0,0,0,17,56,0,0,42,0,21,0,0],"FLAG":0,"BASE":18} Kogan 1500w Panel Heater {"NAME":"Kogan Panel Heater","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} Mosquito Killer Lamp {"NAME":"MosquitoKiller","GPIO":[17,0,0,0,0,0,0,0,37,56,0,0,0],"FLAG":0,"BASE":18} @@ -407,6 +451,13 @@ Proscenic 807C Humidifier {"NAME":"Generic","GPIO":[255,255,255,255,255,255,0,0 Sonoff RM433 RF Remote Controller {"NAME":"REQUIRES RF DEVICE"} ``` +## Motion Sensor +``` +DP-WP001 PIR {"NAME":"TUYA PIR","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +Lenovo Rechargable PIR Motion {"NAME":"Lenovo PIR","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +Mirabella Genio I002576 {"NAME":"GenioPir","GPIO":[17,107,0,108,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":54} +``` + ## Motor ``` Zemismart BCM300D-TY {"NAME":"Zemistart_Curt","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} @@ -415,14 +466,22 @@ Zemismart Roller Shade {"NAME":"M2805EIGB","GPIO":[255,107,255,108,255,255,0,0 Zemismart Updated RF Remote Roller Shade {"NAME":"Zemismart M515EGB","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} ``` +## Multisensor +``` +NEO Coolcam Siren with Temperature and Humidity {"NAME":"Neo Siren 3in1","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} +Sonoff SC {"NAME":"Sonoff SC","GPIO":[17,148,255,149,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":21} +``` + ## Outdoor Plug ``` Acenx SOP04-US Dual {"NAME":"SOP04-US Dual","GPIO":[255,255,255,255,56,57,0,0,21,17,22,255,255],"FLAG":0,"BASE":18} Aicliv SOP03-US {"NAME":"AICLIV SOP03US","GPIO":[0,0,0,23,57,0,0,0,21,18,22,0,0],"FLAG":15,"BASE":18} Albohes PC-1606 {"NAME":"Albohes PC1606","GPIO":[17,0,0,0,0,22,18,0,21,0,0,0,0],"FLAG":1,"BASE":39} Albohes PS-1602 {"NAME":"Albohes PC1606","GPIO":[17,0,0,0,0,22,18,0,21,0,0,0,0],"FLAG":1,"BASE":39} +Amzdest IP55 {"NAME":"C168 Outdoor","GPIO":[0,0,0,130,134,132,0,0,21,56,22,23,17],"FLAG":0,"BASE":18} Aoycocr X13 {"NAME":"Aoycocr X13","GPIO":[0,0,56,0,0,0,0,0,22,17,0,21,0],"FLAG":0,"BASE":18} Atomi AT1320 {"NAME":"AT1320","GPIO":[0,0,0,0,57,52,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +BN-Link {"NAME":"BNC-60/U130T","GPIO":[255,0,255,0,255,56,255,255,21,17,255,0,0],"FLAG":15,"BASE":18} Brennenstuhl WA 3000 XS02 {"NAME":"WA 3000 XS02","GPIO":[0,0,0,0,21,17,0,0,158,52,0,0,0],"FLAG":0,"BASE":61} C137 IP55 {"NAME":"C137 Outdoor","GPIO":[0,17,0,56,134,132,0,0,21,131,22,0,0],"FLAG":15,"BASE":18} C168 IP64 {"NAME":"C188","GPIO":[56,0,57,0,18,0,0,0,21,17,157,22,0],"FLAG":0,"BASE":18} @@ -459,8 +518,8 @@ Teckin SS42 {"NAME":"Teckin SS42","GPIO":[0,0,0,0,56,57,0,0,21,17,2 Top-Max PS-1602 {"NAME":"PS-1602","GPIO":[17,255,255,255,0,22,18,0,21,56,0,0,0],"FLAG":0,"BASE":29} Torchstar LITEdge 2-in-1 {"NAME":"LITEdge Plug","GPIO":[0,0,0,0,56,57,0,0,21,17,22,0,0],"FLAG":0,"BASE":18} Ucomen PA-GEBA-01SWP {"NAME":"PA-GEBA-01SWP","GPIO":[0,0,0,0,52,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} -Woox R4051 {"NAME":"Woox R4051","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} -Woox R4052 {"NAME":"Woox R4052","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} +WOOX R4051 {"NAME":"WOOX R4051","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} +WOOX R4052 {"NAME":"WOOX R4052","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} ``` ## Plug @@ -475,7 +534,7 @@ Aigoss 16A Mini {"NAME":"Aigoss Plug","GPIO":[255,255,0,255,52,21,0,0,5 Aisirer AWP07L {"NAME":"AISIRER AWP07L","GPIO":[56,0,57,0,0,133,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} Aisirer AWP07L v2 {"NAME":"AWP07L v2","GPIO":[0,17,57,0,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Aisirer AWP07L v3 {"NAME":"AWP07L v3","GPIO":[0,17,52,0,134,132,0,0,130,53,21,0,0],"FLAG":0,"BASE":18} -Aisirer AWP08L {"NAME":"AISIRER AWP08L","GPIO":[0,0,56,0,0,0,0,0,0,0,0,21,0],"FLAG":0,"BASE":18} +Aisirer AWP08L {"NAME":"AISIRER AWP08L","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Aisirer AWP08L v2 {"NAME":"AISIRER AWP08L","GPIO":[0,0,0,0,17,57,0,0,21,0,0,0,0],"FLAG":0,"BASE":18} Aisirer JH-G018 {"NAME":"AISIRER JH-G01","GPIO":[0,0,0,0,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Aisirer SWA11 {"NAME":"SWA11","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} @@ -484,6 +543,7 @@ Alexfirst TV-ASP801EU {"NAME":"Alexfirst","GPIO":[17,0,0,0,54,56,0,0,21,0,0,0 Alfawise PE1004T {"NAME":"PE1004T","GPIO":[0,0,0,0,56,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Alfawise PF1006 {"NAME":"PF1006","GPIO":[0,0,17,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Alfawise PME1606 {"NAME":"PME1606","GPIO":[0,0,0,17,133,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} +Amped Wireless {"NAME":"AWP48W","GPIO":[0,0,0,0,56,17,0,0,0,53,21,0,0],"FLAG":0,"BASE":18} Amysen JSM-WF02 {"NAME":"Amysen JSMWF02","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Amysen YX-WS01 {"NAME":"Amysen YX-WS01","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} ANBES ABS-CZ004 {"NAME":"ANBES ABS-CZ00","GPIO":[0,0,0,0,21,133,0,0,131,17,132,22,18],"FLAG":0,"BASE":18} @@ -530,6 +590,7 @@ Awow EU3S {"NAME":"AWOW BSD33","GPIO":[0,0,56,0,0,134,0,0,131,17, Awow X5P {"NAME":"Awow","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} AWP02L-N {"NAME":"AWP02L-N","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} AzpenHome Smart {"NAME":"Socket2Me","GPIO":[52,255,255,255,22,255,0,0,21,255,17,255,255],"FLAG":0,"BASE":18} +Bagotte SK-EU-A01 {"NAME":"Bagotte SK-EU-A01","GPIO":[122,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} Bakibo TP22Y {"NAME":"Bakibo TP22Y","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":52} Bardi 16A {"NAME":"BARDI","GPIO":[56,0,0,0,0,134,0,0,21,17,132,57,131],"FLAG":0,"BASE":18} Bauhn ASPU-1019 {"NAME":"Bauhn Smart Pl","GPIO":[0,0,0,0,21,22,0,0,0,56,17,0,0],"FLAG":0,"BASE":18} @@ -543,13 +604,13 @@ BlitzWolf BW-SHP3 alt {"NAME":"BlitzWolf SHP3","GPIO":[18,56,0,131,134,132,0, BlitzWolf BW-SHP4 {"NAME":"BlitzWolf SHP","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} BlitzWolf BW-SHP5 {"NAME":"SHP5","GPIO":[57,145,56,146,0,22,0,0,0,0,21,0,17],"FLAG":0,"BASE":18} BlitzWolf BW-SHP6 10A {"NAME":"BW-SHP6 10A","GPIO":[158,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} -Blitzwolf BW-SHP6 15A {"NAME":"Blitzwolf SHP6","GPIO":[56,255,158,255,132,134,0,0,131,17,0,21,0],"FLAG":0,"BASE":45} +BlitzWolf BW-SHP6 15A {"NAME":"BlitzWolf SHP6","GPIO":[56,255,158,255,132,134,0,0,131,17,0,21,0],"FLAG":0,"BASE":45} BlitzWolf BW-SHP7 {"NAME":"SHP7","GPIO":[17,158,57,131,134,132,0,0,18,56,21,0,22],"FLAG":0,"BASE":45} -BN-LINK BNC-60/U133TJ-2P {"NAME":"BNC-60/U133TJ","GPIO":[0,56,0,17,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":18} +BN-Link {"NAME":"BNC-60/U133TJ","GPIO":[0,56,0,17,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":18} BNETA IO-WIFI-PlugSA {"NAME":"BNETA WifiPlug","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Brennenstuhl WA 3000 XS01 {"NAME":"WA 3000 XS01","GPIO":[0,0,0,0,21,17,0,0,158,52,0,0,0],"FLAG":0,"BASE":61} Bright {"NAME":"Bright Wi-Fi Smart Plug","GPIO":[0,0,0,0,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} -Brilliant HK17654S05 {"NAME":"HK17654S05","GPIO":[17,255,255,255,133,132,255,255,131,56,21,255,255],"FLAG":0,"BASE":18} +Brilliant {"NAME":"HK17654S05","GPIO":[17,255,255,255,133,132,255,255,131,56,21,255,255],"FLAG":0,"BASE":18} Brilliant Lighting BL20925 {"NAME":"BL20925","GPIO":[0,0,0,17,133,132,0,0,131,158,21,0,0],"FLAG":0,"BASE":52} Brilliant Smart Double Adaptor {"NAME":"Brilliant_2Plg","GPIO":[0,0,0,52,21,22,255,255,157,17,18,0,0],"FLAG":0,"BASE":18} BrilliantSmart 20676 USB Charger {"NAME":"Brilliant","GPIO":[0,0,0,0,0,21,0,0,0,52,90,0,0],"FLAG":0,"BASE":18} @@ -573,7 +634,7 @@ Coosa {"NAME":"COOSA","GPIO":[0,0,0,0,57,52,0,0,21,17,255,0,0 Coosa SP1 {"NAME":"COOSA SP1","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} CrazyLynX WiFi {"NAME":"CrazyLynX","GPIO":[0,0,0,0,57,56,0,0,21,17,0,0,0],"FLAG":1,"BASE":18} CYYLTF BIFANS J23 {"NAME":"CYYLTD BIFANS J23","GPIO":[56,0,0,0,0,0,0,0,21,17,0,0,0],"FLAG":1,"BASE":18} -D3D Smart Plug with USB & Power Monitor {"NAME":"D3D d_SUM","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} +D3D Smart Plug with USB & Power Monitor {"NAME":"D3D FLHS-ZN04","GPIO":[57,255,56,131,255,133,255,255,255,17,132,21,255],"FLAG":15,"BASE":18} DE-1 16A {"NAME":"DE-1","GPIO":[0,17,0,0,133,0,0,0,0,52,21,0,0],"FLAG":1,"BASE":18} DeLock 11826 {"NAME":"DeLock 11826","GPIO":[17,0,0,0,0,0,0,0,21,158,0,0,0],"FLAG":0,"BASE":1} Deltaco SH-P01 {"NAME":"DELTACO SH-P01","GPIO":[0,0,0,0,0,56,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} @@ -599,24 +660,25 @@ EletecPro 2 {"NAME":"EletecPro-2","GPIO":[255,255,255,255,17,255,0, Enjowi SP111-EU-W {"NAME":"Enjowi SP111-E","GPIO":[17,56,0,0,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":55} Epicka {"NAME":"Epicka","GPIO":[255,255,255,255,57,56,0,0,21,17,255,255,255],"FLAG":1,"BASE":18} Esicoo JSM-WF02 {"NAME":"Esicoo Plug","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} -Esicoo YX-WS01 {"NAME":"Esicoo Plug","GPIO":[255,17,255,255,255,255,0,0,255,56,21,255,255],"FLAG":0,"BASE":18} Estink C178 {"NAME":"Estink C178","GPIO":[0,0,0,0,52,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Etekcity ESW01-USA {"NAME":"ESW01-USA","GPIO":[0,0,0,0,21,157,0,0,132,133,17,130,52],"FLAG":0,"BASE":55} Etekcity ESW15-USA {"NAME":"ESW15-US","GPIO":[0,0,0,0,0,21,0,0,132,133,17,130,52],"FLAG":0,"BASE":18} -Eva Logik NWF001 {"NAME":"EVA LOGIK Plug","GPIO":[255,17,255,255,255,255,0,0,255,52,21,255,255],"FLAG":0,"BASE":18} +Eva Logik {"NAME":"EVA LOGIK Plug","GPIO":[255,17,255,255,255,255,0,0,255,52,21,255,255],"FLAG":0,"BASE":18} EVO-Smart JH-G01U {"NAME":"EVO JH-G01U","GPIO":[0,0,0,0,21,17,0,0,56,0,0,0,0],"FLAG":0,"BASE":18} Feit Electric PLUG/WIFI {"NAME":"Feit Wifi Plug","GPIO":[0,0,0,56,0,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} FK-PW901U {"NAME":"FK-PW901U","GPIO":[56,255,255,255,255,23,0,0,21,17,24,22,255],"FLAG":0,"BASE":18} FLHS-ZN04 {"NAME":"FLHS-ZN04","GPIO":[57,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Fontastic SH01 {"NAME":"Fontastic","GPIO":[255,0,255,0,56,0,0,0,21,17,0,0,0],"FLAG":1,"BASE":18} Foval SM-PW701E {"NAME":"SM-PW701E","GPIO":[0,0,0,0,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} -FrankEver FLHS-ZN04 {"NAME":"Israel plug","GPIO":[57,0,56,131,0,134,0,0,0,17,132,21,0],"FLAG":0,"BASE":45} +FrankEver 15A {"NAME":"Israel plug","GPIO":[57,0,56,131,0,134,0,0,0,17,132,21,0],"FLAG":0,"BASE":45} +FrankEver 16A {"NAME":"FrankEver FK-PW801ER","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +FrankEver Mini {"NAME":"FK-PW801US","GPIO":[0,0,0,0,21,22,0,0,23,24,25,26,27],"FLAG":0,"BASE":18} GDTech W-US001 {"NAME":"GDTech W-US001","GPIO":[255,17,255,255,255,255,0,0,255,56,21,255,255],"FLAG":1,"BASE":18} GDTech W-US003 {"NAME":"W-US003","GPIO":[0,17,255,255,255,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Geekbes YM-WS-1 {"NAME":"Office Test Pl","GPIO":[255,255,255,255,255,255,255,255,158,17,12,21,255],"FLAG":15,"BASE":18} Geeni Spot {"NAME":"Geeni Spot","GPIO":[0,0,0,0,52,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Geeni Spot Glo {"NAME":"Geeni Glo","GPIO":[0,0,0,0,56,0,0,0,21,17,22,0,0],"FLAG":0,"BASE":18} -Geeni Switch {"NAME":"Geeni Switch","GPIO":[0,0,0,0,52,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +Geeni SWITCH {"NAME":"Geeni Switch","GPIO":[0,0,0,0,52,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Geeni Switch Duo {"NAME":"Geeni Duo","GPIO":[0,0,0,0,18,22,0,0,17,52,21,0,53],"FLAG":0,"BASE":18} Globe 50020 2 Outlet {"NAME":"Globe 50020","GPIO":[0,158,0,57,18,17,0,0,21,56,22,0,0],"FLAG":0,"BASE":18} Globe Smart {"NAME":"GlobeSmartPlug","GPIO":[0,0,0,0,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} @@ -624,6 +686,7 @@ GoldenDot Mini {"NAME":"GoldenDot Mini","GPIO":[0,17,0,0,0,0,0,0,0,57, GoldenDot with ADC {"NAME":"W-US003-Power","GPIO":[56,0,0,0,0,0,0,0,0,17,0,21,0],"FLAG":7,"BASE":18} Gosund SP1 {"NAME":"Gosund SP1 v23","GPIO":[0,56,0,17,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":55} Gosund SP111 {"NAME":"Gosund SP111","GPIO":[56,0,57,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} +Gosund SP111 15A {"NAME":"SP111 v1.1","GPIO":[56,0,158,0,132,134,0,0,131,17,0,21,0],"FLAG":0,"BASE":45} Gosund SP111 v1.1 {"NAME":"SP111 v1.1","GPIO":[56,0,158,0,132,134,0,0,131,17,0,21,0],"FLAG":0,"BASE":45} Gosund SP111 v1.4 {"NAME":"Gosund SP111","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Gosund SP112 {"NAME":"SHP5","GPIO":[57,145,56,146,255,22,0,0,255,255,21,255,17],"FLAG":0,"BASE":18} @@ -670,6 +733,7 @@ Insmart WP5 {"NAME":"INSMART","GPIO":[0,0,46,0,0,0,0,0,0,9,0,21,0], iSwitch {"NAME":"Smart Plug XSA","GPIO":[255,17,255,255,255,255,0,0,255,56,21,255,255],"FLAG":0,"BASE":18} Jeeo TF-SH330 {"NAME":"Jeeo TF-SH330","GPIO":[56,0,0,0,0,0,0,0,0,17,0,21,0],"FLAG":1,"BASE":18} Jeeo TF-SH331W {"NAME":"Jeeo SH331W","GPIO":[56,0,158,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} +Jetstream MSP150 {"NAME":"JetstreamMSP150","GPIO":[56,0,57,0,21,134,0,0,131,17,132,0,0],"FLAG":0,"BASE":45} Jinli XS-SSA01 {"NAME":"JINLI","GPIO":[0,0,0,0,0,0,0,0,56,17,0,21,0],"FLAG":0,"BASE":18} Jinvoo SM-PW701U {"NAME":"SM-PW702","GPIO":[0,0,0,0,57,56,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Jinvoo SM-PW712UA 10A {"NAME":"SM-PW712UA","GPIO":[0,0,0,158,56,57,0,0,22,17,21,0,0],"FLAG":15,"BASE":18} @@ -690,11 +754,13 @@ KMC 4 {"NAME":"KMC 4 Outlet","GPIO":[0,56,0,0,133,132,0,0,130 KMC 70011 {"NAME":"KMC 70011","GPIO":[17,0,0,0,133,132,0,0,130,56,21,0,0],"FLAG":0,"BASE":36} Kogan Energy Meter {"NAME":"Kogan Smart Sw","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Kogan Energy Meter & USB {"NAME":"KoganPOW","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":52} +Koogeek {"NAME":"Koogeek KLSP1","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} +Koogeek {"NAME":"Koogeek-KLUP1","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Koogeek KLSP1 {"NAME":"Koogeek-KLSP1","GPIO":[0,56,0,17,134,132,0,0,131,158,21,0,0],"FLAG":0,"BASE":18} Koogeek KLSP2 {"NAME":"KOOGEEK KLSP2","GPIO":[57,145,56,146,0,22,0,0,0,0,21,0,17],"FLAG":0,"BASE":45} -Koogeek KLUP1 {"NAME":"Koogeek-KLUP1","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Koogeek KLWP1 {"NAME":"Koogeek-KLWP1","GPIO":[157,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":1} Koogeek W-DEXI {"NAME":"W-DEXI","GPIO":[0,90,0,0,134,132,0,0,130,52,21,0,0],"FLAG":0,"BASE":18} +Koogeek W-UKX {"NAME":"Koogeek W-UKX","GPIO":[0,17,255,255,255,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":1} KULED K63 {"NAME":"KULED K63","GPIO":[0,0,0,0,21,17,0,0,56,0,0,0,0],"FLAG":0,"BASE":18} Laduo YX-DE01 {"NAME":"YX-DE01","GPIO":[255,17,255,255,255,255,0,0,255,56,21,255,255],"FLAG":0,"BASE":18} Lenovo SE-341A {"NAME":"Lenovo SE-341A","GPIO":[0,0,0,0,17,21,0,0,158,0,56,0,0],"FLAG":0,"BASE":18} @@ -710,10 +776,10 @@ Luminea NX-4491 {"NAME":"Luminea NX-449","GPIO":[56,0,158,0,0,0,0,0,0,1 Luminea NX-4541 {"NAME":"NX-4451","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":55} Luminea ZX-2820 {"NAME":"ZX2820-675","GPIO":[0,0,0,17,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":65} Luminea ZX-2858 {"NAME":"Luminea SF-200","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} +Lunvon {"NAME":"Lunvon Smart Plug","GPIO":[17,0,0,0,0,0,52,21,0,0,0,0,0],"FLAG":0,"BASE":18} Martin Jerry V01 {"NAME":"MJ V01","GPIO":[0,0,0,0,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Martin Jerry XS-SSA01 {"NAME":"MJ_XS-SSA01","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Maxcio W-DE004 {"NAME":"Maxcio W-DE004","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":1,"BASE":18} -Maxcio W-UK007 {"NAME":"Maxcio","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Maxcio W-UK007S {"NAME":"Maxcio","GPIO":[56,0,255,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Maxcio W-US002S {"NAME":"W-US002S","GPIO":[57,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Maxcio W-US003 {"NAME":"W-US003","GPIO":[255,17,255,255,255,255,0,0,255,22,21,255,255],"FLAG":0,"BASE":18} @@ -727,7 +793,7 @@ Merkury MI-WW105-199W {"NAME":"Merkury Switch","GPIO":[255,255,255,255,158,56 Minleaf W-DEXI {"NAME":"W-DEXI","GPIO":[0,17,0,0,134,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} Mirabella Genio 1002341 {"NAME":"Genio 1","GPIO":[0,0,56,0,0,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":1} Mirabella Genio USB {"NAME":"Mirabella Genio 1002826","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":1} -Mirabella Genio USB Port and Plug {"NAME":"Genio I002341","GPIO":[0,0,0,0,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":1} +Mirabella Genio USB Port {"NAME":"Genio I002341","GPIO":[0,0,0,0,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":1} Mistral {"NAME":"Mistral Smart ","GPIO":[56,0,0,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Moes NX-SP203 {"NAME":"Moes NX-SP203","GPIO":[52,0,0,0,17,134,0,0,21,18,0,22,0],"FLAG":0,"BASE":18} Moes W-DE004S {"NAME":"Moes DE004S ","GPIO":[57,0,0,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} @@ -744,10 +810,12 @@ Nightlight and AC Outlet {"NAME":"SWN03","GPIO":[17,0,0,0,0,0,255,255,37,0,0,21 Nishica SM-PW701I {"NAME":"SM-PW701I","GPIO":[255,255,255,255,255,255,255,255,21,52,17,255,255],"FLAG":15,"BASE":18} NX-SM112 {"NAME":"NX-SM112v3","GPIO":[0,0,0,0,134,132,0,0,158,17,130,21,0],"FLAG":0,"BASE":45} NX-SM200 {"NAME":"NX-SM200","GPIO":[56,0,0,0,0,134,0,0,21,17,132,57,131],"FLAG":0,"BASE":18} +NX-SM223 {"NAME":"Smart Thurmm","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Obi Stecker {"NAME":"OBI Socket","GPIO":[255,255,0,255,52,21,0,0,54,255,17,0,255],"FLAG":1,"BASE":51} Obi Stecker 2 {"NAME":"OBI Socket 2","GPIO":[0,0,0,0,21,17,0,0,56,53,0,0,0],"FLAG":0,"BASE":61} Oittm Smart {"NAME":"Oittm","GPIO":[0,0,0,0,21,56,0,0,17,0,0,0,0],"FLAG":0,"BASE":1} Olliwon {"NAME":"Olliwon","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} +Onestyle SD-WL-02 {"NAME":"JH-G01B1","GPIO":[0,145,0,146,0,0,0,0,17,56,21,0,0],"FLAG":0,"BASE":41} Orbecco W-US009 {"NAME":"Orbecco Plug","GPIO":[0,17,0,0,0,0,0,0,0,52,21,0,0],"FLAG":0,"BASE":18} Orvibo B25 {"NAME":"Orvibo B25","GPIO":[0,0,0,0,53,21,0,0,52,0,17,0,0],"FLAG":0,"BASE":18} Oukitel P1 {"NAME":"Oukitel P1Dual","GPIO":[52,255,0,255,0,0,0,0,22,17,0,21,0],"FLAG":0,"BASE":18} @@ -761,6 +829,7 @@ Panamalar Nightlight {"NAME":"Panamalar EWN0","GPIO":[17,0,0,0,0,0,255,255,3 Panamalar NX-SM200 {"NAME":"NX-SM200","GPIO":[0,0,0,0,56,134,0,0,131,17,132,21,0],"FLAG":1,"BASE":18} Positivo PPW1000 {"NAME":"PPW1000","GPIO":[0,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Positivo Max {"NAME":"PPW1600","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":55} +PowerAdd BIE0091 {"NAME":"BIE0091","GPIO":[17,0,0,0,0,0,0,0,37,0,0,21,0],"FLAG":0,"BASE":18} Powertech {"NAME":"Jaycar","GPIO":[56,0,0,0,0,0,0,0,0,9,0,21,0],"FLAG":0,"BASE":6} Powertech MS6104 {"NAME":"Jaycar MS6104","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":52} Powrui 3-Outlet with 4 USB {"NAME":"POWRUI AHR-077","GPIO":[0,0,0,20,19,18,0,0,22,23,17,21,157],"FLAG":0,"BASE":18} @@ -775,8 +844,9 @@ RenPho RF-SM004 {"NAME":"RenPho RFSM004","GPIO":[0,0,0,0,157,56,0,0,21, Robaxo {"NAME":"Robaxo RSP-025","GPIO":[17,0,0,0,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} RSH-WS007-EU {"NAME":"RSH-WS007","GPIO":[0,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":1,"BASE":18} S126 {"NAME":"tuya-plug","GPIO":[0,0,0,0,0,0,0,0,21,20,0,0,0],"FLAG":0,"BASE":8} +SA-P202C 16A {"NAME":"Elivco 202C-G","GPIO":[0,0,0,17,134,132,0,0,130,56,21,0,0],"FLAG":0,"BASE":18} Sansui {"NAME":"Sansui YSP-1","GPIO":[52,0,53,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} -Shelly Plug S {"NAME":"Shelly Plug S","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":2,"BASE":45} +Shelly Plug S {"NAME":"Shelly Plug S","GPIO":[56,255,158,255,255,134,0,0,131,17,132,21,255],"FLAG":2,"BASE":45} Silvergear Slimme Stekker {"NAME":"Silvergear SmartHomePlug","GPIO":[0,0,0,122,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} SimpleHome {"NAME":"SimpleHome","GPIO":[53,0,0,0,0,0,0,0,21,56,17,0,0],"FLAG":0,"BASE":1} Slitinto NX-SM110 {"NAME":"Slitinto SM110","GPIO":[0,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} @@ -790,6 +860,8 @@ SM-PW701K {"NAME":"SM-PW701K","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0, Smaho {"NAME":"SMAHO WiFi P.","GPIO":[17,0,0,0,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} SmartDGM PP-W162 {"NAME":"SmartDGM Plug","GPIO":[0,0,0,17,134,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} SmartGrade AC 5008 {"NAME":"SmartGrade AC","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":49} +Smitch 16A {"NAME":"Smitch SP0602","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} +Smitch 6A {"NAME":"Smitch SP0601","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Sonoff S20 {"NAME":"Sonoff S20","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":8} Sonoff S22 TH {"NAME":"Sonoff S22","GPIO":[17,255,0,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":4} Sonoff S26 {"NAME":"Sonoff S26","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":8} @@ -804,6 +876,7 @@ Steren SHOME-100 {"NAME":"SHOME-100 V1.0","GPIO":[0,0,0,0,0,56,0,0,21,17 STITCH by Monoprice 27937 {"NAME":"Stitch 27937","GPIO":[17,0,56,0,133,132,0,0,131,0,21,0,57],"FLAG":0,"BASE":18} STITCH by Monoprice 35511 {"NAME":"Stitch 35511","GPIO":[56,0,57,0,0,133,0,0,0,17,132,21,131],"FLAG":0,"BASE":18} SuperNight Dual {"NAME":"SuperNight Dua","GPIO":[255,17,255,21,132,133,0,0,22,130,58,255,255],"FLAG":1,"BASE":18} +SWA1 {"NAME":"SWA1","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} SWA1 FR {"NAME":"SWA1","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} SWA1 UK {"NAME":"SWA1","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} SWA11 {"NAME":"SWA11","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} @@ -813,7 +886,7 @@ SwissTone SH 100 {"NAME":"SwissTone","GPIO":[0,0,0,0,56,57,0,0,21,17,0,0 Sygonix SY-4276902 {"NAME":"SYGONIX","GPIO":[0,0,0,17,133,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} TanTan WP2 {"NAME":"TanTan WP2","GPIO":[57,56,158,255,21,134,255,255,131,17,132,22,18],"FLAG":15,"BASE":18} TanTan WP3 {"NAME":"TanTan WP3","GPIO":[0,0,56,0,17,0,0,0,57,0,21,0,0],"FLAG":0,"BASE":18} -TCP Smart WISSINWUK {"NAME":"TCP_Plug","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":45} +TCP Smart 13A {"NAME":"TCP_Plug","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":45} Teckin SP10 {"NAME":"Teckin SP10","GPIO":[255,255,56,255,255,255,0,0,255,17,255,21,255],"FLAG":0,"BASE":18} Teckin SP20 {"NAME":"TECKIN SP20","GPIO":[56,255,57,255,21,134,0,0,131,17,132,0,0],"FLAG":0,"BASE":45} Teckin SP21 {"NAME":"Teckin SP21","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":45} @@ -827,7 +900,7 @@ TikLok TL650 {"NAME":"TikLok Mini","GPIO":[0,0,0,0,57,0,0,0,21,17,0, Timethinker C338 {"NAME":"C338","GPIO":[17,0,255,0,0,0,0,0,21,52,255,0,0],"FLAG":0,"BASE":1} Timethinker TK04 {"NAME":"TimethinkerEU","GPIO":[255,255,255,255,17,255,0,0,255,52,21,255,0],"FLAG":0,"BASE":18} TimeThinker WS2 {"NAME":"TimeThinkerWS2","GPIO":[0,0,0,0,17,0,0,0,0,52,21,0,0],"FLAG":0,"BASE":18} -TomaxUSA HKWL-SO07W {"NAME":"HKWL-SO07W","GPIO":[17,255,255,255,255,255,0,0,255,255,21,255,56],"FLAG":0,"BASE":18} +TomaxUSA {"NAME":"HKWL-SO07W","GPIO":[17,255,255,255,255,255,0,0,255,255,21,255,56],"FLAG":0,"BASE":18} Topersun WL-SC01 {"NAME":"Topersun ","GPIO":[0,0,0,0,52,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} TopGreener TGWF115APM {"NAME":"TGWF115APM","GPIO":[0,56,0,17,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":18} Torchstar LITEdge Smart {"NAME":"LITEdge Plug","GPIO":[0,17,0,0,0,0,0,0,0,52,21,0,0],"FLAG":0,"BASE":18} @@ -842,7 +915,7 @@ Vaupan X6P {"NAME":"Vaupan 10a X6P","GPIO":[0,0,56,0,0,0,0,0,0,17, Vettora Smart Plug {"NAME":"Vettora","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} Vingo {"NAME":"Karpal-01","GPIO":[0,0,0,0,0,56,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Vivanco 39625 Smart Home Power Adapter {"NAME":"Vivianco","GPIO":[0,0,0,17,133,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} -Vivitar HA-1003 {"NAME":"Vivitar HA1003","GPIO":[158,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} +Vivitar {"NAME":"Vivitar HA1003","GPIO":[158,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Vivitar HA-1006 {"NAME":"HA-1006","GPIO":[0,0,0,0,56,0,0,0,21,90,0,0,0],"FLAG":0,"BASE":18} Vivitar HA-1006-AU {"NAME":"HA-1006-AU","GPIO":[0,0,0,0,56,0,0,0,21,90,0,0,0],"FLAG":0,"BASE":18} WAGA life CHCZ02MB {"NAME":"WAGA CHCZ02MB","GPIO":[57,0,0,131,0,134,0,0,21,17,132,56,0],"FLAG":0,"BASE":68} @@ -854,10 +927,11 @@ Wily Electronics {"NAME":"VC Plug","GPIO":[157,0,0,0,0,134,0,0,131,17,13 WiOn 50055 {"NAME":"WiOn","GPIO":[255,0,52,0,0,0,0,0,255,17,0,21,0],"FLAG":0,"BASE":17} Wisdom ZY_ACU02 {"NAME":"ZY-ACU02","GPIO":[0,0,0,157,22,21,0,0,56,17,57,0,0],"FLAG":0,"BASE":18} WL-SC01 {"NAME":"WL-SC01","GPIO":[0,0,0,0,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":1} -Woox R4026 {"NAME":"WOOX R4026","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} -Woox R4785 {"NAME":"WooxR4785","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} -WOOX R5024 {"NAME":"Woox5024","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} +WOOX R4026 {"NAME":"WOOX R4026","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} +WOOX R4785 {"NAME":"WOOXR4785","GPIO":[0,0,0,0,52,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} +WOOX R5024 {"NAME":"WOOX5024","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} WP211 {"NAME":"YUNTAB WP211","GPIO":[56,0,158,0,22,0,0,0,0,18,0,21,17],"FLAG":0,"BASE":18} +WP5 {"NAME":"WP5","GPIO":[57,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Wsiiroon {"NAME":"WSIIROON","GPIO":[0,0,0,0,17,56,0,0,21,0,0,0,0],"FLAG":0,"BASE":18} Wsiiroon {"NAME":"Wsiiroon/Wsky","GPIO":[0,0,0,0,17,56,0,0,21,0,0,0,0],"FLAG":0,"BASE":18} Wyze WLPP1 {"NAME":"WyzePlugWLPP1","GPIO":[0,0,0,0,0,56,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} @@ -869,7 +943,7 @@ XS-A14 {"NAME":"NETVIP XS-A14","GPIO":[37,0,38,0,0,17,0,0,39,2 XS-A17 {"NAME":"XS-A18","GPIO":[37,0,38,0,0,39,0,0,0,17,0,21,0],"FLAG":0,"BASE":45} XS-A18 {"NAME":"XS-A18","GPIO":[37,0,38,0,0,39,0,0,0,17,0,21,0],"FLAG":0,"BASE":45} XS-A23 {"NAME":"XS-A23","GPIO":[56,255,0,131,17,134,0,0,0,18,132,21,22],"FLAG":0,"BASE":45} -XS-SSA01 {"NAME":"XS-SSA01","GPIO":[255,17,255,255,255,255,0,0,255,56,21,255,255],"FLAG":0,"BASE":18} +XS-SSA01 {"NAME":"XS-SSA01","GPIO":[0,17,0,0,0,0,0,0,56,9,0,21,0],"FLAG":0,"BASE":18} XS-SSA01 v2 {"NAME":"XS-SSA01","GPIO":[255,17,255,255,255,255,0,0,56,255,255,21,255],"FLAG":0,"BASE":18} XS-SSA05 {"NAME":"XS-SSA05","GPIO":[30,255,255,131,255,133,0,0,21,17,132,31,255],"FLAG":1,"BASE":18} XS-SSA06 {"NAME":"XS-SSA06","GPIO":[37,0,38,0,0,39,0,0,0,90,0,21,0],"FLAG":0,"BASE":18} @@ -878,6 +952,7 @@ Yelomin JH-G01E {"NAME":"Yelomin","GPIO":[0,145,0,146,0,0,0,0,17,56,21, YERON US101 {"NAME":"YERON_US101","GPIO":[255,255,255,17,133,132,0,0,131,56,21,255,255],"FLAG":0,"BASE":18} YM-WS-1 Mini {"NAME":"YM-WS1","GPIO":[0,0,0,0,0,0,0,0,56,17,0,21,0],"FLAG":0,"BASE":18} YM-WS-3 16A {"NAME":"YM-WS-3","GPIO":[0,17,0,0,0,0,0,0,0,52,21,0,158],"FLAG":1,"BASE":18} +YT-E002 {"NAME":"YT-E002","GPIO":[158,0,0,0,18,0,0,0,22,17,0,21,0],"FLAG":0,"BASE":18} YT-E003 {"NAME":"YT-E003-SP202","GPIO":[17,0,0,0,134,132,0,0,131,52,22,21,91],"FLAG":0,"BASE":64} Yuanguo KS-501 {"NAME":"Yuanguo_KS-501","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} YX-DE01 {"NAME":"YX-DE01","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} @@ -895,8 +970,10 @@ A0F0 ZLD-44EU-W {"NAME":"AOFO-4AC-4USB","GPIO":[0,56,0,17,22,21,0,0,23, Acenx 3AC+3USB {"NAME":"ACENX 3-Outlet","GPIO":[56,55,54,53,0,21,0,0,23,24,22,0,17],"FLAG":0,"BASE":18} AHRise 4+4AC+4USB {"NAME":"AHRise-083","GPIO":[0,0,0,0,56,17,0,0,22,21,23,24,0],"FLAG":0,"BASE":18} AHRise AHR-085 {"NAME":"AHRise AHR-085","GPIO":[0,0,0,0,17,56,0,0,22,23,21,0,0],"FLAG":0,"BASE":18} +Aicliv 4AC 3USB {"NAME":"Aicliv WiFi","GPIO":[0,0,0,24,23,158,0,0,21,17,22,0,0],"FLAG":0,"BASE":18} Annhome 3AC + 2USB {"NAME":"1200W WiFi SPS","GPIO":[32,0,0,0,57,52,0,0,21,17,22,23,33],"FLAG":0,"BASE":18} AOFO 3AC+4USB {"NAME":"AOFO","GPIO":[0,56,0,17,22,21,0,0,0,23,24,0,0],"FLAG":1,"BASE":18} +AOFO 4AC + 4USB {"NAME":"AOFO C379 4AC+4USB UK ","GPIO":[0,158,0,17,24,23,0,0,21,25,22,0,0],"FLAG":0,"BASE":18} AOFO 4AC+4USB {"NAME":"AOFO4AC4USB","GPIO":[0,56,0,17,22,21,0,0,23,24,25,0,0],"FLAG":0,"BASE":18} AOFO 4AC+4USB Tuya {"NAME":"AOFO-4AC-4USB","GPIO":[255,255,255,255,255,255,0,0,255,255,255,255,255],"FLAG":1,"BASE":54} AOFO 4AC+4USB UK {"NAME":"AOFO4AC4USB-UK","GPIO":[0,56,0,17,23,24,0,0,22,21,33,0,0],"FLAG":0,"BASE":18} @@ -909,18 +986,19 @@ BrilliantSmart 20691 Powerboard with USB Chargers {"NAME":"B_WiFi-4","GPIO":[56 CE Smart Home {"NAME":"CE Power Strip","GPIO":[52,0,0,0,22,21,0,0,24,23,25,26,17],"FLAG":0,"BASE":18} CE Smart Home Garden Stake {"NAME":"CE Power Stake","GPIO":[0,0,0,0,56,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} CRST LTS-4G-W {"NAME":"CRST LTS-4G-W","GPIO":[0,0,0,0,24,0,0,0,22,23,21,0,0],"FLAG":0,"BASE":18} -Deltaco SH-P03USB {"NAME":"Deltaco SH-P03","GPIO":[0,56,0,0,0,21,0,0,23,17,22,24,0],"FLAG":1,"BASE":18} +Deltaco SH-P03USB {"NAME":"Deltaco SH-P03","GPIO":[56,0,0,0,0,23,0,0,21,17,22,24,0],"FLAG":0,"BASE":18} Digoo DG-PS01 {"NAME":"Digoo DG-PS01","GPIO":[0,56,0,17,23,22,0,0,0,24,21,0,0],"FLAG":1,"BASE":18} Geekbes 4AC+4USB {"NAME":"Geekbes 4xStri","GPIO":[0,56,0,17,22,21,0,0,23,24,25,0,0],"FLAG":1,"BASE":18} Geeni Surge {"NAME":"Geeni GNCSW003","GPIO":[52,0,0,0,22,21,0,0,24,25,23,26,17],"FLAG":0,"BASE":18} Geeni SURGE 6-Outlet Surge Protector {"NAME":"Geeni 6 Strip","GPIO":[56,0,0,0,22,21,0,0,24,25,23,26,0],"FLAG":0,"BASE":18} Geeni Surge Mini {"NAME":"Geeni-GN-SW004","GPIO":[56,0,0,17,0,0,0,0,22,21,23,0,0],"FLAG":15,"BASE":18} Gosund P1 {"NAME":"Gosund_P1","GPIO":[0,145,157,146,0,32,0,0,22,23,21,0,17],"FLAG":1,"BASE":18} -Gousund WP9 {"NAME":"Gosund WP9","GPIO":[56,55,54,53,0,21,0,0,23,24,22,0,17],"FLAG":0,"BASE":18} +Gosund WP9 {"NAME":"Gosund WP9","GPIO":[56,55,54,53,0,21,0,0,23,24,22,0,17],"FLAG":0,"BASE":18} Heyvalue 3AC+3USB {"NAME":"HeyvalueHLT-330","GPIO":[52,0,53,0,24,29,0,0,30,20,31,0,0],"FLAG":0,"BASE":18} -Heyvalue 4AC+4USB {"NAME":"Heyvalue HLT-331","GPIO":[56,0,57,0,25,22,0,0,24,9,23,21,0],"FLAG":0,"BASE":18} +Heyvalue 4AC+4USB {"NAME":"Heyvalue HLT-331","GPIO":[57,0,158,56,32,17,0,0,30,31,29,0,25],"FLAG":0,"BASE":18} HIPER IoT PS44 {"NAME":"HIPER IoT PS44","GPIO":[0,56,0,17,22,21,0,0,23,24,25,0,0],"FLAG":0,"BASE":18} HLT-333 {"NAME":"BEYAWL","GPIO":[0,0,56,24,0,0,0,0,0,30,29,31,0],"FLAG":0,"BASE":18} +Home Awesome 4AC 4USB {"NAME":"Home Awesome","GPIO":[52,0,53,0,25,22,0,0,24,17,23,21,0],"FLAG":0,"BASE":18} Hyleton 330 {"NAME":"Hyleton-330","GPIO":[57,0,0,56,29,17,0,0,31,30,32,0,25],"FLAG":0,"BASE":18} Hyleton 331 {"NAME":"HLT-331","GPIO":[52,255,255,57,29,17,0,0,31,30,32,255,58],"FLAG":0,"BASE":18} Hyleton 333 {"NAME":"HLT-333","GPIO":[52,0,0,57,29,17,0,0,31,30,0,0,24],"FLAG":0,"BASE":18} @@ -935,15 +1013,17 @@ Luminea 3AC+4USB 16A {"NAME":"Luminea-NX4473","GPIO":[0,56,0,17,22,21,0,0,0, Maxcio ZLD-34EU-W {"NAME":"MAXCIO","GPIO":[0,56,0,17,22,21,0,0,0,23,24,0,0],"FLAG":1,"BASE":18} Meross MSS425 {"NAME":"Meross MSS425","GPIO":[33,0,0,0,56,0,0,0,21,17,22,23,32],"FLAG":0,"BASE":18} Mirabella Genio 4 Outlet Power Board with 2 USB {"NAME":"Genio i002340","GPIO":[56,0,0,0,21,22,0,0,23,17,24,25,0],"FLAG":0,"BASE":18} -Mirabella Genio Powerboard I002578 {"NAME":"Genio Powerboa","GPIO":[21,52,0,0,23,22,0,0,25,17,26,24,0],"FLAG":0,"BASE":18} +Mirabella Genio Powerboard {"NAME":"Genio Powerboa","GPIO":[21,52,0,0,23,22,0,0,25,17,26,24,0],"FLAG":0,"BASE":18} Nedis P310 {"NAME":"Nedis WIFIP310","GPIO":[0,56,0,17,22,21,0,0,0,23,24,0,0],"FLAG":1,"BASE":18} Nozdom 3AC+2USB {"NAME":"NOZDOM SWB3","GPIO":[157,0,53,0,0,23,0,0,21,17,22,24,0],"FLAG":0,"BASE":18} Powrui AHR-079 {"NAME":"Powrui Power S","GPIO":[56,0,0,17,19,21,0,0,23,20,22,24,18],"FLAG":0,"BASE":18} +Powrui AHR-081 {"NAME":"POWRUI AHR-081","GPIO":[0,0,0,0,56,17,0,0,22,23,21,0,0],"FLAG":0,"BASE":18} Powrui AW-39 {"NAME":"Powrui AW-39","GPIO":[56,0,0,0,21,255,0,0,23,24,22,0,9],"FLAG":0,"BASE":18} S2199EU {"NAME":"S2199EU","GPIO":[0,17,0,52,23,25,0,0,21,24,22,0,0],"FLAG":1,"BASE":18} SA-P402A {"NAME":"SA-P402A","GPIO":[0,17,0,56,23,25,21,24,22,0,0,1,0],"FLAG":1,"BASE":18} STITCH by Monoprice 34082 {"NAME":"Stitch 34082","GPIO":[255,255,255,255,21,20,0,0,23,22,24,255,255],"FLAG":0,"BASE":18} SWB1 {"NAME":"SWB1","GPIO":[52,0,0,0,0,24,0,0,21,17,22,23,0],"FLAG":0,"BASE":18} +SWB2 3AC + 2USB {"NAME":"SWB2","GPIO":[158,255,0,255,0,23,0,0,21,17,22,24,0],"FLAG":0,"BASE":18} TCP Smart 4AC+USB {"NAME":"TCP WPS4WUK","GPIO":[255,56,0,17,23,24,0,0,22,21,25,0,0],"FLAG":15,"BASE":18} Teckin SS30 {"NAME":"Teckin SS30","GPIO":[52,255,255,57,29,17,0,0,31,30,32,255,25],"FLAG":0,"BASE":18} Tellur TLL331031 {"NAME":"Tellur","GPIO":[0,56,0,17,22,21,0,0,0,23,24,0,0],"FLAG":1,"BASE":18} @@ -954,7 +1034,8 @@ Vivitar HA-1007 {"NAME":"Vivitar HA-1007 Power Strip","GPIO":[157,0,0,0 Vivitar HA-1007-AU {"NAME":"HA-1007-AU","GPIO":[56,17,0,58,29,57,0,0,31,30,32,0,25],"FLAG":0,"BASE":18} wesmartify essentials 4AC+4USB {"NAME":"essential_4_po","GPIO":[56,0,0,0,24,25,0,0,22,21,23,0,17],"FLAG":0,"BASE":18} Wipro Smart Extension {"NAME":"Generic","GPIO":[57,0,0,0,32,0,0,0,30,31,29,0,25],"FLAG":0,"BASE":18} -Woox R4028 {"NAME":"Woox R4028","GPIO":[0,56,0,17,23,22,0,0,0,24,21,0,0],"FLAG":1,"BASE":18} +WOOX R4028 {"NAME":"WOOX R4028","GPIO":[0,56,0,17,23,22,0,0,0,24,21,0,0],"FLAG":1,"BASE":18} +WP40 {"NAME":"WP40","GPIO":[33,0,0,0,56,0,0,0,21,17,22,23,32],"FLAG":0,"BASE":18} Xenon SM-S0301 {"NAME":"SM-SO301","GPIO":[52,255,255,57,29,17,0,0,31,30,32,255,25],"FLAG":0,"BASE":18} Xenon SM-S0301-U {"NAME":"SM-SO301-U","GPIO":[52,255,255,57,29,17,0,0,31,30,32,255,25],"FLAG":0,"BASE":18} Xenon SM-SO301 v2 {"NAME":"SM-SO301","GPIO":[56,0,0,0,30,17,0,0,32,31,33,0,21],"FLAG":0,"BASE":18} @@ -1005,13 +1086,13 @@ Avatar ALS18L A60 800lm {"NAME":"Avatar E14 7W","GPIO":[0,0,0,0,38,37,0,0,41,39 B.K.Licht BKL1253 9W 806lm {"NAME":"BKL1253","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} Bakibo TB95 9W 1000lm {"NAME":"Bakibo A19 9W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} BAZZ BR30 650lm {"NAME":"BAZZrgb","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":1,"BASE":18} -BlitzWolf BW-LT27 w/ remote 850lm {"NAME":"BW-LT27","GPIO":[0,0,0,0,41,38,0,0,39,51,40,37,0],"FLAG":0,"BASE":18} +BlitzWolf w/ remote 850lm {"NAME":"BW-LT27","GPIO":[0,0,0,0,41,38,0,0,39,51,40,37,0],"FLAG":0,"BASE":18} BNETA 8.5W 800lm {"NAME":"BNETA IO-WIFI60-E27P","GPIO":[0,0,0,0,37,40,0,0,38,50,39,0,0],"FLAG":0,"BASE":18} BNETA 8.5W 800lm {"NAME":"OM60/RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Bomcosy 600lm {"NAME":"Generic","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":1,"BASE":18} -Calex 429002 Reflector 350lm {"NAME":"Calex RGBW","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} Calex 429004 A60 806lm {"NAME":"Calex E27 RGB ","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Calex 429008 B35 5W 470lm {"NAME":"Calex E14 RGBW","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} +Calex 5W 350lm Reflector {"NAME":"Calex RGBW","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} Cleverio 51395 806lm {"NAME":"CleverioE27RGB","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} CMARS 4W Reflector {"NAME":"RGBWW GU10","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":15,"BASE":18} Dogain 320lm {"NAME":"DOGAIN","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} @@ -1021,7 +1102,7 @@ Euri Lighting 10W 800lm {"NAME":"Euri Lighting ","GPIO":[0,0,0,0,37,40,0,0,38,4 EXUP C37 5W {"NAME":"EXUP","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":15,"BASE":18} Feit Electric A19 1600lm {"NAME":"OM100/RGBWW","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Feit Electric A19 800lm {"NAME":" BPA800/RGBW/AG/2","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} -Feit Electric A19 800lm {"NAME":" BPA800/RGBW/AG/2P","GPIO":[0,0,0,0,37,38,0,0,141,142,140,0,0],"FLAG":0,"BASE":48} +Feit Electric A19 800lm {"NAME":"BPA800/RGBW/AG/2P","GPIO":[0,0,0,0,37,47,0,0,141,142,140,0,0],"FLAG":0,"BASE":48} Feit Electric A19 800lm {"NAME":"FE-OM60-15K-AG","GPIO":[0,0,0,0,141,140,0,0,37,142,38,0,0],"FLAG":0,"BASE":18} Feit Electric A19 800lm {"NAME":"OM60/RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Fitop 9W {"NAME":"E27RGBCCT9w","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":15,"BASE":18} @@ -1029,6 +1110,7 @@ Fulighture 9W 810lm {"NAME":"Fulighture 9W","GPIO":[0,0,0,0,38,37,0,0,41,39 Geeni Prisma 10W 1050lm {"NAME":"Geeni Prisma 1050 RGB","GPIO":[0,0,0,0,141,140,0,37,38,142,0,0,0],"FLAG":0,"BASE":18} Geeni Prisma Plus 800lm {"NAME":"Geeni Prisma P","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Generic GU10 5W 460lm {"NAME":"RGBCCT GU10","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Girier 9W {"NAME":"GIRIER E27 9W ","GPIO":[0,0,0,0,41,38,0,0,39,0,40,37,0],"FLAG":0,"BASE":18} Globe A19 10W 800lm {"NAME":"GlobeRGBWW","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Helloify BR30 9W 600lm {"NAME":"Helloify","GPIO":[255,255,255,255,37,40,255,255,38,41,39,255,255],"FLAG":0,"BASE":18} HIPER IoT A61 {"NAME":"HIPER IoT A61","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} @@ -1066,6 +1148,7 @@ LVWIT A60 8.5W 806lm {"NAME":"LVWIT A60 8.5W","GPIO":[0,0,0,0,37,40,0,0,38,4 LVWIT A70 12W 1521lm {"NAME":"LVWIT A70 12W","GPIO":[0,0,0,0,37,40,0,0,38,50,39,0,0],"FLAG":0,"BASE":18} LVWIT BR30 8.5W 650lm {"NAME":"LVWIT BR30 8.5W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} LVWIT G45 5W 470Lm {"NAME":"LVWIT E14 5W G45 RGBWCCT","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} +Lyhope 7W 650lm {"NAME":"Lyhope 014BB06","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} MagicHome 7W {"NAME":"MagicHome E27","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Moes 9W 800lm {"NAME":"Moes 9w","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Nishica JBT 9W 806lm {"NAME":"Nishica","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} @@ -1087,6 +1170,7 @@ Positivo 10W 806lm {"NAME":"Positivo Bulb","GPIO":[0,0,0,0,37,40,0,0,38,50 Powertech SL225X 800lm {"NAME":"Jaycar SL225X","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Qualitel ALS08L 1100lm {"NAME":"Qualitel ALS08","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Reafoo A26 9W {"NAME":"ReaFooE26","GPIO":[0,0,0,0,41,38,0,0,39,0,40,37,0],"FLAG":0,"BASE":18} +Reafoo A27 9W 810lm {"NAME":"ReaFooE27","GPIO":[0,0,0,0,41,40,0,0,37,0,39,38,0],"FLAG":0,"BASE":18} RYE 5W 450LM Candle {"NAME":"RYE Candlebra","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Saudio A19 7W 700lm {"NAME":"X002BU0DOL","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Sealight A19 9W 810lm {"NAME":"DGO/SEASTAR","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} @@ -1122,12 +1206,14 @@ Aoycocr Q9WM A21 10W 900lm {"NAME":"Aoycocr Q9WM","GPIO":[0,0,0,0,0,39,0,0,38,4 Avatar ALS08L A19 910lm {"NAME":"Avatar E27 7W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":20} Avatar ALS09L A60 900lm {"NAME":"Avatar E14 9W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":20} Avatar ALS11L PAR16 500lm {"NAME":"Avatar_GU10","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} +Avatar Controls A19 10W 900lm {"NAME":"Avatar E26 10W","GPIO":[0,0,0,0,0,39,0,0,38,0,37,40,0],"FLAG":0,"BASE":18} +AWOW A60 9W 800lm {"NAME":"AWOW 9W RGBW","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Axtee AI-003 A19 700lm {"NAME":"Axtee E26 7W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":20} Bawoo EUWL122130 925lm {"NAME":"Bawoo","GPIO":[0,0,0,0,140,37,0,0,0,142,141,0,0],"FLAG":0,"BASE":18} -BlitzWolf BW-LT21 900lm {"NAME":"BlitzWolf LT21","GPIO":[0,0,0,0,41,39,0,0,38,0,37,40,0],"FLAG":0,"BASE":18} +BlitzWolf 900lm {"NAME":"BlitzWolf LT21","GPIO":[0,0,0,0,41,39,0,0,38,0,37,40,0],"FLAG":0,"BASE":18} BNeta 4.5W 380lm {"NAME":"BNeta","GPIO":[0,0,0,0,141,140,0,0,37,142,0,0,0],"FLAG":0,"BASE":18} BriHome 6,5W 500lm {"NAME":"BRI E27 6,5W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":20} -Brilliant HK17653S72 350lm {"NAME":"HK17653S72","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +Brilliant 350lm Candle {"NAME":"HK17653S72","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} BrilliantSmart 20698 9W 800lm {"NAME":"Brilliant20698","GPIO":[0,0,0,0,141,140,0,0,37,142,0,0,0],"FLAG":0,"BASE":18} BrilliantSmart 20699 9W 800lm {"NAME":"Brilliant20699","GPIO":[0,0,0,0,141,140,0,0,37,142,0,0,0],"FLAG":0,"BASE":18} BrilliantSmart 20741 9W 750lm {"NAME":"Brilliant RGB+","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} @@ -1140,8 +1226,12 @@ BTZ1 {"NAME":"WifiBulb","GPIO":[0,0,0,0,0,37,0,0,39,40,38,0, Cleverio 4.5W 350lm {"NAME":"HK17653S72","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Cleverio 51398 370lm {"NAME":"CleverioGU10","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Cocoon DY180363-B 800lm {"NAME":"Cocoon RGBW","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} -Connect SmartHome 5W {"NAME":"Connect CSH-E1","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} +Connect SmartHome 10W {"NAME":"CSH-B22RGB10W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Connect SmartHome 10W {"NAME":"CSH-E27RGB10W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Connect SmartHome 5W {"NAME":"CSH-E14RGB5W","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} +Connex A70 10W 1050lm {"NAME":"Connex 10w RGBWW","GPIO":[0,0,0,38,140,37,0,0,0,142,141,0,0],"FLAG":0,"BASE":18} Connex Connect A60 6W 470lm {"NAME":"Connex RGBW Bu","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +DailyComb 7W 600lm {"NAME":"DailyComb RGBW Bulb","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Elari A60 6W 470lm {"NAME":"OM60/RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} electriQ 600lm {"NAME":"ElectricQ B22","GPIO":[0,0,0,0,37,41,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} EleLight 350lm {"NAME":"EleLight 7wA19","GPIO":[0,0,0,0,140,37,0,0,0,142,141,0,0],"FLAG":0,"BASE":18} @@ -1152,7 +1242,9 @@ Fcmila 7W {"NAME":"FCMILA E27 0.1","GPIO":[0,0,0,0,37,40,0,0,38,0 Fcmila Spotlight 460lm {"NAME":"Fcmila LED 6W","GPIO":[0,0,0,0,40,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} Feit Electric BR30 650lm {"NAME":"BR30/RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Feit Electric BR30 700lm {"NAME":"Feit BR30/RGBW","GPIO":[0,0,0,38,141,140,0,0,0,142,37,0,0],"FLAG":0,"BASE":18} +FFHL 12W 900lm {"NAME":"FFHL RGBW Bulb","GPIO":[0,0,0,0,0,37,0,0,39,40,38,0,0],"FLAG":0,"BASE":18} Fulighture A60 810lm {"NAME":"Fulighture A60","GPIO":[0,0,0,0,38,37,0,0,0,39,40,0,0],"FLAG":0,"BASE":18} +Garsent 10W {"NAME":"Garsent 10W RGBW-Bulb","GPIO":[0,0,0,0,0,39,0,0,38,0,37,40,0],"FLAG":1,"BASE":18} Generic GU10 5W 450lm {"NAME":"RGBCW GU10","GPIO":[0,255,0,255,40,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":3} Gosund 8W 800lm {"NAME":"Gosund RGBW 8W","GPIO":[0,0,0,0,41,40,0,0,37,38,39,0,0],"FLAG":0,"BASE":18} Gosund WB3 8W 800lm {"NAME":"Gosund WB3","GPIO":[0,0,0,0,40,0,0,0,37,38,39,0,0],"FLAG":0,"BASE":18} @@ -1160,12 +1252,15 @@ Hama 10W 1050lm {"NAME":"Hama Bulb RGBW","GPIO":[0,0,0,0,140,37,0,0,0,1 Hama 10W 806lm {"NAME":"Hama Smart WiF","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Hama 4.5W {"NAME":"hama E14 RGB","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Hiiten A19 7W 650lm {"NAME":"Hiiten Bulb","GPIO":[37,0,0,0,140,38,0,0,0,142,141,0,0],"FLAG":0,"BASE":18} +Hikenri 7W 640lm {"NAME":"HIKENRI E27 RGB","GPIO":[17,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} +Hombli 4.5W 380lm Candle {"NAME":"Hombli E14 RGB","GPIO":[0,0,0,0,141,140,0,0,0,142,37,0,0],"FLAG":0,"BASE":18} Hykker SL-0492 810lm {"NAME":"Hykker RBGW 9W","GPIO":[0,0,0,0,0,40,0,0,37,0,39,38,0],"FLAG":0,"BASE":18} +Jetstream 9W 800lm {"NAME":"Jetstream MA19CL","GPIO":[0,0,0,0,37,0,0,0,141,142,140,0,0],"FLAG":0,"BASE":18} Kainsy 600lm {"NAME":"KAINSY","GPIO":[17,0,0,0,143,144,0,0,0,0,0,0,0],"FLAG":0,"BASE":27} Kkmoon 9W 800lm {"NAME":"KKMOON V21","GPIO":[0,0,0,0,40,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} Koaanw 650lm {"NAME":"KOAANW Bulb","GPIO":[0,0,0,0,143,144,0,0,0,0,0,0,0],"FLAG":0,"BASE":27} Kogan 10W Ambient 1050lm {"NAME":"Kogan RGB","GPIO":[0,0,0,0,140,37,0,0,0,0,141,0,0],"FLAG":0,"BASE":18} -Kogan 4.5W 330lm 110� {"NAME":"Kogan_GU10","GPIO":[0,0,0,0,39,40,0,0,37,0,38,0,0],"FLAG":0,"BASE":18} +Kogan 4.5W 330lm 110C {"NAME":"Kogan_GU10","GPIO":[0,0,0,0,39,40,0,0,37,0,38,0,0],"FLAG":0,"BASE":18} Kogan Ambient Candle {"NAME":"Kogan_E14","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Kuled 800lm {"NAME":"KULED 60W RGB","GPIO":[0,0,0,0,39,40,0,0,37,0,38,0,0],"FLAG":1,"BASE":18} Laideyi 7W {"NAME":"7W-E14-RGBW-La","GPIO":[0,0,0,0,38,37,0,0,39,0,40,0,0],"FLAG":0,"BASE":18} @@ -1187,6 +1282,7 @@ LTC 10W {"NAME":"LTC LXU403","GPIO":[0,0,0,0,40,0,0,0,38,39,37, Lumiman LM530 7.5W 800lm {"NAME":"Lumiman LM530","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":1,"BASE":18} Lumiman LM530 7.5W 800lm {"NAME":"Lumiman LM530","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":1,"BASE":18} Lumiman LM530 7.5W 800lm {"NAME":"LM530","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":1,"BASE":18} +Luminea 4.5W 350lm Candle {"NAME":"Luminea NX4462 RGB+W","GPIO":[0,0,0,0,39,40,0,0,37,0,38,0,0],"FLAG":0,"BASE":18} Luminea ZX-2832 {"NAME":"Luminea RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":1,"BASE":18} Luminea ZX-2986 1400lm {"NAME":"Luminea RGBW","GPIO":[0,0,0,0,37,41,0,0,0,38,39,40,0],"FLAG":0,"BASE":18} LWE3 600lm {"NAME":"Linganzh LWE3 ","GPIO":[0,0,0,0,0,38,0,0,39,0,40,37,0],"FLAG":0,"BASE":18} @@ -1196,13 +1292,14 @@ Maxcio YX-L01P-E27-2P 9W {"NAME":"Maxcio YXL01P","GPIO":[17,0,0,0,143,144,0,0,0 Melery 5W {"NAME":"MeleryMR16","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} Merkury 75W 1050lm {"NAME":"MIC-BW904-999W","GPIO":[38,0,0,0,141,140,0,0,37,142,0,0,0],"FLAG":0,"BASE":18} Merkury A21 10W 1050lm {"NAME":"MI-BW210-999W","GPIO":[38,0,0,0,140,37,0,0,0,142,141,0,0],"FLAG":0,"BASE":69} +Merkury A21 10W 1050lm {"NAME":"MI-BW210-999W","GPIO":[0,0,0,0,39,38,0,0,0,37,40,0,0],"FLAG":0,"BASE":18} +Merkury BR30 8W 750lm {"NAME":"MI-BW906-999W","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Merkury MI-BW904-999W 1050lm {"NAME":"MI-BW904-999W","GPIO":[0,0,0,0,140,37,0,0,0,142,141,0,0],"FLAG":0,"BASE":18} Merkury MI-BW904-999W v2 1050lm {"NAME":"MI-BW210-999W","GPIO":[0,0,0,0,38,37,0,0,141,142,140,0,0],"FLAG":0,"BASE":48} Merkury MI-BW904-999W v3 {"NAME":"MI-BW904-999W","GPIO":[0,0,0,0,37,38,0,0,141,142,140,0,0],"FLAG":0,"BASE":69} -Merkury MI-BW906-999W BR30 750lm {"NAME":"MI-BW906-999W","GPIO":[0,0,0,0,38,37,0,0,141,142,140,0,0],"FLAG":0,"BASE":18} Mimoodz A19 6.5W {"NAME":"Miimoodz RGBCW LED","GPIO":[0,0,0,0,180,0,0,0,0,0,181,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbRGB","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} -Mirabella Genio 9W 800lm {"NAME":"GenioBulbRGB","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +Mirabella Genio 9W 800lm {"NAME":"MiraBellaGenio","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"MiraBellaGenio","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} Mixigoo 950lm {"NAME":"Mixigoo Bulb","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} MoKo GU10 {"NAME":"MoKo GU10","GPIO":[255,255,255,255,39,255,255,255,38,41,37,40,255],"FLAG":15,"BASE":18} @@ -1229,8 +1326,9 @@ Solimo 12W {"NAME":"Solimo RGBCCT 12","GPIO":[0,0,0,0,37,41,0,0,38 Solimo 810lm {"NAME":"Solimo RGBWW 9","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Swisstone SH 320 350lm {"NAME":"SH 320","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Swisstone SH 340 806lm {"NAME":"SH 340","GPIO":[0,0,0,0,140,37,0,0,0,142,141,0,0],"FLAG":15,"BASE":18} -Syska 720lm {"NAME":"SyskaSmartBulb","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} -TCP Smart 806lm {"NAME":"TCP Smart RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} +Syska 7W 480lm {"NAME":"Syska","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Syska 9W 720lm {"NAME":"SyskaSmartBulb","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} +TCP Smart 9W 806lm {"NAME":"TCP Smart RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Teckin 7.5W 800lm {"NAME":"Teckin SB60","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Teckin SB50 800lm {"NAME":"Teckin SB50","GPIO":[0,0,0,0,40,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} Teckin SB50 v2 800lm {"NAME":"Teckin SB50","GPIO":[0,0,0,0,37,0,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} @@ -1245,7 +1343,7 @@ Wixann C37 5W 450lm {"NAME":"WIXANNE12","GPIO":[0,0,0,0,37,40,0,0,38,41,39, Woopower 460lm {"NAME":"Woopower E14","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} WOOX R4553 650lm {"NAME":"WOOX R4553","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} WOOX R5076 4W 350lm {"NAME":"WOOX R4553","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} -Woox R5077 {"NAME":"WOOX R5077","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} +WOOX R5077 {"NAME":"WOOX R5077","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Zemismart 5W {"NAME":"Zemismart_GU10","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} Zemismart A19 10W {"NAME":"Zemism_E27_A19","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} Zilotek A19 800lm {"NAME":"Zilotek RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} @@ -1253,153 +1351,110 @@ Zilotek A19 800lm {"NAME":"Zilotek RGBW","GPIO":[0,0,0,0,140,37,0,0,38,14 ## Relay ``` -1 Channel Inching/Self-Locking {"NAME":"1 Channel","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":12} Anmbest 2 Channel Inching Self-locking Switch Module {"NAME":"Generic","GPIO":[17,255,255,255,255,22,18,0,21,56,0,0,0],"FLAG":0,"BASE":1} -ATMS1601 230VAC DIN Timer/Switch {"NAME":"ATMS1601","GPIO":[255,255,255,255,157,56,255,255,21,17,255,255,255],"FLAG":15,"BASE":18} -BlitzWolf BW-SS1 {"NAME":"BW-SS1","GPIO":[255,255,255,255,157,21,0,0,255,17,255,255,0],"FLAG":0,"BASE":18} -BlitzWolf BW-SS5 1 Gang {"NAME":"BlitzWolf SS5 1 Gang","GPIO":[0,0,0,0,0,0,0,0,9,21,0,0,0],"FLAG":0,"BASE":18} -BlitzWolf BW-SS5 2 Gang {"NAME":"BlitzWolf SS5 2 Gang","GPIO":[0,0,0,0,160,0,0,0,43,42,21,22,0],"FLAG":0,"BASE":18} -BlitzWolf SS4 {"NAME":"BlitzWolf SS4 Two Gang","GPIO":[0,0,0,0,56,21,0,0,22,17,0,0,0],"FLAG":0,"BASE":18} -Canwing CW-001 {"NAME":"Canwing CW-001","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} -Century Aoke Smart Switch {"NAME":"CenturyAoke","GPIO":[0,255,0,255,21,0,0,0,17,56,255,0,0],"FLAG":0,"BASE":18} -Deta 6000HA Smart Inline Switch {"NAME":"DETA-6000HA","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} -dewenwils Outdoor Timer Box {"NAME":"Dewenwils50054","GPIO":[0,0,54,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} DoHome HomeKit DIY Switch {"NAME":"DoHome DIY","GPIO":[255,255,0,255,255,157,0,0,21,0,0,0,0],"FLAG":0,"BASE":1} Eachen ST-DC2 {"NAME":"Garage Control","GPIO":[11,0,0,0,23,22,18,0,21,52,12,24,0],"FLAG":1,"BASE":18} Eachen ST-UDC1 {"NAME":"ST-UDC1","GPIO":[9,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":1,"BASE":18} Electrodragon Board SPDT {"NAME":"ED Relay Board","GPIO":[255,255,255,255,255,255,0,0,21,22,255,255,52],"FLAG":1,"BASE":18} Electrodragon ESP8266 {"NAME":"ElectroDragon","GPIO":[18,255,17,255,255,255,0,0,22,21,255,255,52],"FLAG":1,"BASE":15} -eMylo 2 Channel {"NAME":"eMylo XL9252WI","GPIO":[0,255,0,0,56,22,0,0,21,0,12,0,0],"FLAG":0,"BASE":18} -eMylo SS-8839-02 {"NAME":"SS-8839-02","GPIO":[0,255,0,255,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} -eMylo SS-8839-03 {"NAME":"SS-8839-03","GPIO":[0,255,0,255,52,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} ESP-01 Relay V4.0 {"NAME":"ESP01v4","GPIO":[29,52,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} ESP-01S 5V Relay Module V1.0 {"NAME":"ESP-01S Relay","GPIO":[29,52,255,255,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} ESP12F 220V 10A 7V-30V DC {"NAME":"Yunshan 10A","GPIO":[17,255,52,255,21,10,0,0,22,0,0,0,0],"FLAG":0,"BASE":18} -EX Store 2 Kanal V5 {"NAME":"EXS Relay V5","GPIO":[255,255,255,255,255,255,0,0,21,22,31,52,32],"FLAG":0,"BASE":16} -Garage Door Controller {"NAME":"Garage Opener","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} -Geekcreit 2 Channel AC 85V-250V {"NAME":"Geekcreit 2ch","GPIO":[17,0,0,0,0,22,18,0,21,52,0,0,0],"FLAG":1,"BASE":18} Geekcreit 5V DIY 4 Channel Jog Inching Self-Locking {"NAME":"Geekcreit-4ch","GPIO":[9,0,0,0,23,22,10,11,21,52,12,24,0],"FLAG":0,"BASE":18} Geekcreit Module 220V 10A {"NAME":"DIY ESP8266 Re","GPIO":[0,0,157,0,21,17,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Gocomma Wi-Fi Smart Switch {"NAME":"GoCommaSmartSw","GPIO":[17,255,255,255,21,0,0,0,255,56,0,0,0],"FLAG":0,"BASE":18} -Hoch Circuit Breaker 1P {"NAME":"HOCH ZJSB9","GPIO":[17,255,255,255,255,255,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} HW-622 ESP8266 {"NAME":"HW-622","GPIO":[0,0,157,0,21,17,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -L-5A01 {"NAME":"L-5A01","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} +LC Technology 12V 4 Channel {"NAME":"LC Technology 4CH Relay","GPIO":[21,0,22,0,23,24,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} LC Technology 5V 2 Channel {"NAME":"LC-ESP01-2R-5V","GPIO":[0,148,0,149,0,0,0,0,21,22,0,0,0],"FLAG":0,"BASE":18} LC Technology 5V 4 Channel {"NAME":"LC-Tech_4CH ","GPIO":[52,255,17,255,0,0,0,0,21,22,23,24,0],"FLAG":0,"BASE":18} LC Technology AC/DC 1 Channel ESP-12F Dev Board {"NAME":"LC-ESP12-1R-MV","GPIO":[255,255,157,255,255,21,255,255,255,255,255,255,57],"FLAG":15,"BASE":18} LC Technology ESP8266 5V {"NAME":"ESP8266-01S","GPIO":[21,148,0,149,0,0,0,0,0,0,0,0,0],"FLAG":1,"BASE":18} LinkNode R4 {"NAME":"LinkNode R4","GPIO":[0,0,0,0,0,0,0,0,21,22,23,0,24],"FLAG":0,"BASE":18} LinkNode R8 {"NAME":"LinkNode R8","GPIO":[0,0,0,0,25,26,0,28,23,24,22,27,21],"FLAG":0,"BASE":18} -LoraTap 10A {"NAME":"LoraTap RR400W","GPIO":[0,0,0,0,157,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} -LoraTap RR500W {"NAME":"LoraTap RR500W","GPIO":[157,255,255,255,9,255,255,255,255,21,255,255,56],"FLAG":15,"BASE":18} Mhcozy 5V {"NAME":"Portail","GPIO":[9,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":1,"BASE":18} -Moes MS-104B-1 {"NAME":"Moes MS-104B","GPIO":[0,0,17,0,160,0,0,0,43,42,21,22,0],"FLAG":0,"BASE":18} -Nova Digital Basic 1 MS101 {"NAME":"NovaDigBasic1","GPIO":[0,255,0,255,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} -OpenEnergyMonitor WiFi MQTT Thermostat {"NAME":"MQTT-RELAY","GPIO":[17,0,255,0,0,21,0,0,0,0,0,0,56],"FLAG":0,"BASE":18} -Protium PS-1604 {"NAME":"Protium16A","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":1} -QS-WIFI-S03 Module Switch {"NAME":"QS-WIFI-S03","GPIO":[17,255,255,255,255,0,0,0,82,21,0,0,0],"FLAG":0,"BASE":1} -QS-WIFI-S05 {"NAME":"QS-WIFI-S05","GPIO":[17,255,255,255,255,0,0,0,82,21,0,0,0],"FLAG":0,"BASE":1} -Shelly 1 {"NAME":"Shelly 1","GPIO":[0,0,0,0,21,82,0,0,0,0,0,0,0],"FLAG":0,"BASE":46} -Shelly 1PM {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} -Shelly 2 {"NAME":"Shelly 2","GPIO":[0,135,0,136,21,22,0,0,9,0,10,137,0],"FLAG":0,"BASE":47} -Shelly 2.5 {"NAME":"Shelly 2.5","GPIO":[56,0,17,0,21,83,0,0,6,82,5,22,156],"FLAG":2,"BASE":18} -Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,6,156,5,21,0],"FLAG":15,"BASE":18} -Sinilink XY-WF36V DC6V-36V Switch Module {"NAME":"Sinilink XY-WF5V","GPIO":[0,0,0,0,21,255,0,0,17,52,0,0,255],"FLAG":0,"BASE":18} -Sinilink XY-WFMS MOS Switch Module {"NAME":"Sinilink MOS","GPIO":[0,0,0,0,21,255,0,0,17,52,0,0,255],"FLAG":0,"BASE":18} -Sinilink XY-WFUSB USB Switch {"NAME":"XY-WFUSB","GPIO":[255,255,0,255,17,21,0,0,0,0,56,0,157],"FLAG":0,"BASE":18} -Smart Home SS-8839-01 {"NAME":"SS-8839-01","GPIO":[0,255,0,255,21,0,0,0,17,57,0,56,0],"FLAG":0,"BASE":18} -Sonoff 4CH (R2) {"NAME":"Sonoff 4CH","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":7} -Sonoff 4CH Pro (R2) {"NAME":"Sonoff 4CH Pro","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":23} -Sonoff 4CHPROR3 {"NAME":"Sonoff 4CHPROR3","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":23} -Sonoff 4CHR3 {"NAME":"Sonoff 4CHR3","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":7} -Sonoff 5V Inching/Selflock Module RE5V1C {"NAME":"Sonoff RE5V1C","GPIO":[17,255,255,255,255,255,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} -Sonoff Basic {"NAME":"Sonoff Basic","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":1} -Sonoff Basic R3 {"NAME":"Basic R3","GPIO":[17,255,0,255,255,0,0,0,21,56,255,0,255],"FLAG":0,"BASE":1} -Sonoff Dual {"NAME":"Sonoff Dual","GPIO":[0,148,0,149,255,0,0,0,0,56,255,0,0],"FLAG":0,"BASE":5} -Sonoff Dual R2 {"NAME":"Sonoff Dual R2","GPIO":[255,255,0,255,0,22,255,17,21,56,0,0,0],"FLAG":0,"BASE":39} -Sonoff Mini {"NAME":"Sonoff Mini","GPIO":[17,0,0,0,9,0,0,0,21,56,0,0,255],"FLAG":0,"BASE":1} -Sonoff Pow {"NAME":"Sonoff Pow","GPIO":[17,0,0,0,0,130,0,0,21,132,133,52,0],"FLAG":0,"BASE":6} -Sonoff Pow R2 {"NAME":"Sonoff Pow R2","GPIO":[17,145,0,146,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":43} -Sonoff RF {"NAME":"Sonoff RF","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":2} +Sinilink DC6V-36V Module {"NAME":"Sinilink XY-WF5V","GPIO":[0,0,0,0,21,255,0,0,17,52,0,0,255],"FLAG":0,"BASE":18} +Sinilink MOS {"NAME":"Sinilink MOS","GPIO":[0,0,0,0,21,255,0,0,17,52,0,0,255],"FLAG":0,"BASE":18} +Sonoff 1 Channel Inching/Self-Locking {"NAME":"1 Channel","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":12} +Sonoff RE5V1C 5V Inching/Selflock {"NAME":"Sonoff RE5V1C","GPIO":[17,255,255,255,255,255,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} Sonoff SV {"NAME":"Sonoff SV","GPIO":[17,255,0,255,255,255,0,0,21,56,255,0,0],"FLAG":1,"BASE":3} -Sonoff TH10/TH16 {"NAME":"Sonoff TH","GPIO":[17,255,0,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":4} -SS-8839-02 {"NAME":"SS-8839-02","GPIO":[0,255,0,255,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} -SS311KWS RF Kinetic Switch and WiFi {"NAME":"SS311KWS","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} -SW-R03 {"NAME":"SW-R03","GPIO":[0,0,0,0,0,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} -WL-SW01_10 {"NAME":"WL-SW01_10","GPIO":[17,149,0,148,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} -Yuntong Smart {"NAME":"Yuntong Smart ","GPIO":[0,0,0,0,21,0,0,0,122,56,0,0,0],"FLAG":0,"BASE":18} -Zemismart ERC309 Kinetic Switch {"NAME":"Kinetic Switch","GPIO":[255,255,255,255,255,255,0,0,255,108,255,107,255],"FLAG":0,"BASE":54} -ZMAi-90 Digital Energy Meter {"NAME":"ZMAi-90","GPIO":[0,148,0,149,0,0,0,0,21,90,0,0,0],"FLAG":0,"BASE":18} ``` -## Sensor +## Smoke Sensor ``` -Digoo DG-ZXD21 Door Detector {"NAME":"Digoo ZXD21","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} -DP-WP001 PIR {"NAME":"TUYA PIR","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} -DS18B20 ESP01 Module Temperature {"NAME":"ESP01S ds18b20","GPIO":[255,255,4,255,255,255,0,0,255,255,255,255,255],"FLAG":15,"BASE":18} -Earykong TYMC-1 Door Window {"NAME":"TYMC-1","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} -ESP01S DHT11 v1.0 Module Temperature {"NAME":"ESP01S DHT11","GPIO":[0,0,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":4} -IOT4SH01DS Temperature {"NAME":"IOT4SH01DS","GPIO":[255,255,255,255,255,255,0,0,255,4,255,255,255],"FLAG":15,"BASE":18} -Lenovo Rechargable PIR Motion {"NAME":"Lenovo PIR","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} -Mirabella Genio I002576 Motion {"NAME":"GenioPir","GPIO":[17,107,0,108,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":54} -Natural Gas (CH4) Alarm {"NAME":"PA-210WYS","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} Nedis Smoke Detector {"NAME":"Nedis Smoke","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} -Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,0,0,0,83,84,82,0,0],"FLAG":0,"BASE":18} -Shelly Temperature Sensor Add-on {"NAME":"Shelly 1 Temp ","GPIO":[192,0,0,4,21,82,0,0,0,0,0,0,0],"FLAG":0,"BASE":46} Smoke Alarm {"NAME":"YG400A","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} -Sonoff SC {"NAME":"Sonoff SC","GPIO":[17,148,255,149,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":21} -TY01 Door Window {"NAME":"TY01","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} -Zemismart Door Window {"NAME":"Zemismart","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} ``` ## Switch ``` -3A Smart Home HGZB-043 {"NAME":"3A Smart Home ","GPIO":[52,0,55,18,22,19,0,0,17,21,54,23,53],"FLAG":0,"BASE":18} -AGL 3 Gang {"NAME":"AGL WiFi 03","GPIO":[0,0,56,0,19,18,0,0,22,21,23,0,17],"FLAG":0,"BASE":18} +3A Smart Home {"NAME":"3A Smart Home ","GPIO":[52,0,55,18,22,19,0,0,17,21,54,23,53],"FLAG":0,"BASE":18} +AGL 2 Gang {"NAME":"AGL WiFi 02","GPIO":[0,0,157,0,0,18,0,0,22,21,0,0,17],"FLAG":0,"BASE":18} +AGL 3 Gang {"NAME":"AGL WiFi 03","GPIO":[0,0,157,0,19,18,0,0,22,21,23,0,17],"FLAG":0,"BASE":18} +AGL Modulo Relay 01 Canal {"NAME":"AGL-Basic","GPIO":[0,255,0,0,21,17,0,0,0,0,56,0,0],"FLAG":0,"BASE":18} +Albohes 2 Channel {"NAME":"Albohes SH-08","GPIO":[0,148,18,149,57,56,0,0,21,157,17,0,22],"FLAG":15,"BASE":18} Aoycocr SW1 {"NAME":"Aoycocr SW1","GPIO":[158,255,57,255,255,255,255,255,56,17,255,21,255],"FLAG":15,"BASE":18} +ATMS1601 230VAC DIN Timer/Switch {"NAME":"ATMS1601","GPIO":[255,255,255,255,157,56,255,255,21,17,255,255,255],"FLAG":15,"BASE":18} Avatto 2 Gang {"NAME":"Avatto Wifi - ","GPIO":[0,0,52,0,0,17,0,0,21,22,0,0,18],"FLAG":0,"BASE":18} +Avatto 3-Gang {"NAME":"AVATTO 3 Gang","GPIO":[0,57,158,19,23,18,0,0,56,21,58,22,17],"FLAG":0,"BASE":18} Avatto Fan Light {"NAME":"AVATTO Smart Wifi Fan Light","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Bardi Smart Wallswitch 1 {"NAME":"Bardi 1 Gang","GPIO":[57,56,157,0,0,17,0,0,0,0,0,21,0],"FLAG":0,"BASE":18} Bardi Smart Wallswitch 2 {"NAME":"BARDI 2 Gang","GPIO":[56,0,157,18,22,0,0,0,52,21,57,0,17],"FLAG":0,"BASE":18} Bardi Smart Wallswitch 3 {"NAME":"BARDI 3 Gang","GPIO":[56,57,157,19,23,18,0,0,52,21,58,22,17],"FLAG":0,"BASE":18} BAZZ SWTCHWFW1 {"NAME":"BAZZ KS-602S","GPIO":[17,0,0,0,0,0,21,52,29,56,0,0,0],"FLAG":0,"BASE":18} -Blitzwolf BW-SS3 1 Gang {"NAME":"BW-SS3-1G-EU","GPIO":[52,0,0,17,0,0,0,0,0,21,0,0,0],"FLAG":0,"BASE":18} +BlitzWolf BW-SS1 {"NAME":"BW-SS1","GPIO":[255,255,255,255,157,21,0,0,255,17,255,255,0],"FLAG":0,"BASE":18} +BlitzWolf BW-SS3 1 Gang {"NAME":"BW-SS3-1G-EU","GPIO":[52,0,0,17,0,0,0,0,0,21,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-SS3 2 Gang {"NAME":"BW-SS3-2G-EU","GPIO":[157,255,255,255,22,18,255,255,17,21,255,255,255],"FLAG":15,"BASE":18} BlitzWolf BW-SS3 3 Gang {"NAME":"BlitzWolf SS3","GPIO":[158,0,0,10,22,11,0,0,9,21,0,23,0],"FLAG":0,"BASE":18} +BlitzWolf BW-SS5 1 Gang {"NAME":"BlitzWolf SS5 1 Gang","GPIO":[0,0,0,0,0,0,0,0,9,21,0,0,0],"FLAG":0,"BASE":18} +BlitzWolf BW-SS5 2 Gang {"NAME":"BlitzWolf SS5 2 Gang","GPIO":[0,0,17,0,160,0,0,0,10,9,21,22,0],"FLAG":0,"BASE":18} +BlitzWolf SS4 {"NAME":"BlitzWolf SS4 Two Gang","GPIO":[0,0,0,0,56,21,0,0,22,17,0,0,0],"FLAG":0,"BASE":18} +Canwing CW-001 {"NAME":"Canwing CW-001","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} CD303 3 Gang Touch {"NAME":"Touch Switch 3","GPIO":[54,57,255,19,23,18,255,255,17,21,255,22,52],"FLAG":15,"BASE":18} -Connect Smart 2 Gang Wall {"NAME":"CSH-SWTCH2","GPIO":[0,0,52,0,0,18,0,0,22,21,0,0,17],"FLAG":0,"BASE":18} +Century Aoke Smart Switch {"NAME":"CenturyAoke","GPIO":[0,255,0,255,21,0,0,0,17,56,255,0,0],"FLAG":0,"BASE":18} +Connect SmartHome 2 Gang Wall {"NAME":"CSH-SWTCH2","GPIO":[0,0,52,0,0,18,0,0,22,21,0,0,17],"FLAG":0,"BASE":18} Deta 1 Gang {"NAME":"Deta 1G Switch","GPIO":[0,0,0,0,157,0,0,0,0,21,0,0,90],"FLAG":0,"BASE":18} Deta 2 Gang {"NAME":"DETA 2G Switch","GPIO":[0,0,0,0,157,0,0,0,91,21,22,0,90],"FLAG":0,"BASE":18} Deta 3 Gang {"NAME":"DETA 3G Switch","GPIO":[157,0,0,92,91,21,0,0,23,0,22,0,90],"FLAG":0,"BASE":18} Deta 4 Gang {"NAME":"Deta 4G Switch","GPIO":[157,0,0,19,18,21,0,0,23,20,22,24,17],"FLAG":0,"BASE":18} +Deta 6000HA Smart Inline Switch {"NAME":"DETA-6000HA","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} +Deta Fan Speed Controller with Light {"NAME":"Deta Fan Speed and Light Controller","GPIO":[18,0,0,157,23,19,0,0,0,22,21,24,17],"FLAG":0,"BASE":18} +dewenwils Outdoor Timer Box {"NAME":"Dewenwils50054","GPIO":[0,0,54,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Digoo DG-S811 3 Gang {"NAME":"DIGOO Switch","GPIO":[0,0,0,0,19,18,0,0,22,21,23,0,17],"FLAG":0,"BASE":18} DS-102 1 Gang {"NAME":"DS-102 1 Gang","GPIO":[57,0,0,17,0,0,0,0,0,21,56,0,0],"FLAG":1,"BASE":18} DS-102 2 Gang {"NAME":"DS-102 2 Gang","GPIO":[158,57,0,17,22,18,0,0,0,21,56,255,0],"FLAG":0,"BASE":18} DS-102 3 Gang {"NAME":"DS-102 3 Gang","GPIO":[158,58,0,18,22,19,0,0,17,21,57,23,56],"FLAG":0,"BASE":18} Eachen CD303 3 Gang {"NAME":"ID Components","GPIO":[157,53,0,11,21,10,0,0,9,22,54,23,52],"FLAG":15,"BASE":18} Eachen SWT-2Gang {"NAME":"ID Components","GPIO":[157,255,255,255,255,10,255,255,9,21,53,22,52],"FLAG":15,"BASE":18} +eMylo 2 Channel {"NAME":"eMylo XL9252WI","GPIO":[0,255,0,0,56,22,0,0,21,0,12,0,0],"FLAG":0,"BASE":18} +eMylo SS-8839-02 {"NAME":"SS-8839-02","GPIO":[0,255,0,255,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} +eMylo SS-8839-03 {"NAME":"SS-8839-03","GPIO":[0,255,0,255,52,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} Enjowi WF-SK301 {"NAME":"Tuya 3 Channel","GPIO":[0,0,0,0,23,18,0,0,17,21,19,22,157],"FLAG":0,"BASE":18} Esmlfe 3 Gang {"NAME":"Esmlfe DS-122","GPIO":[57,0,0,17,0,0,0,0,0,21,52,0,0],"FLAG":0,"BASE":18} Etekcity ESWL01 {"NAME":"EtekCityESWL01","GPIO":[0,255,0,255,52,53,0,0,0,21,122,0,0],"FLAG":1,"BASE":18} Etekcity ESWL03 3-way {"NAME":"Etekcity 3Way","GPIO":[0,0,0,0,23,29,0,0,82,22,10,0,0],"FLAG":0,"BASE":18} -Eva Logik WF30 3-Way {"NAME":"WF30 Switch","GPIO":[0,0,0,0,18,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +Eva Logik 3-Way {"NAME":"WF30 Switch","GPIO":[0,0,0,0,18,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +EX Store 2 Kanal V5 {"NAME":"EXS Relay V5","GPIO":[255,255,255,255,255,255,0,0,21,22,31,52,32],"FLAG":0,"BASE":16} FrankEver 4 Gang {"NAME":"FrankEver Wifi Smart Switch","GPIO":[0,0,0,17,21,18,255,255,19,23,24,22,20],"FLAG":0,"BASE":18} Freecube AWS01F {"NAME":"Freecube","GPIO":[0,0,0,17,21,0,0,0,0,0,22,0,0],"FLAG":0,"BASE":18} +Garage Door Controller {"NAME":"Garage Opener","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Geekcreit 2 Channel AC 85V-250V {"NAME":"Geekcreit 2ch","GPIO":[17,0,0,0,0,22,18,0,21,52,0,0,0],"FLAG":1,"BASE":18} Geeni TAP 3-Way {"NAME":"Geeni 3-Way","GPIO":[157,0,0,0,0,0,0,0,17,21,0,0,0],"FLAG":0,"BASE":18} Girier EK01 RF433Mhz 1 Gang {"NAME":"Girier EK01","GPIO":[157,0,0,0,21,0,0,0,0,0,0,0,17],"FLAG":0,"BASE":18} Girier EK02 RF433Mhz 2 Gang {"NAME":"Girier EK02","GPIO":[157,0,0,0,0,17,0,0,18,21,22,0,0],"FLAG":0,"BASE":18} Girier EK03 RF433Mhz 3 Gang {"NAME":"EK03","GPIO":[157,0,0,0,22,17,0,0,19,21,23,0,18],"FLAG":0,"BASE":18} -Girier JRSWR-SEU01 1 Gang {"NAME":"W601","GPIO":[0,0,0,0,0,17,0,0,0,0,0,21,157],"FLAG":15,"BASE":18} -Girier JRSWR-SEU01 2 Gang {"NAME":"W602","GPIO":[0,0,0,0,22,0,0,0,17,21,18,0,157],"FLAG":15,"BASE":18} -Girier JRSWR-SEU01 3 Gang {"NAME":"W603","GPIO":[0,0,0,0,23,18,0,0,17,21,19,22,157],"FLAG":15,"BASE":18} Girier JRSWR-US01 No Neutral 1 Gang {"NAME":"Tuya 1 Channel","GPIO":[0,0,0,0,0,17,0,0,0,0,0,21,157],"FLAG":0,"BASE":18} Girier JRSWR-US01 No Neutral 3 Gang {"NAME":"Girier JRSWR-U","GPIO":[0,0,0,0,21,18,0,0,19,23,17,22,157],"FLAG":0,"BASE":18} +Girier RF433 1 Gang No Neutral {"NAME":"Girier","GPIO":[0,157,0,0,0,17,0,0,21,0,0,0,0],"FLAG":0,"BASE":18} +Girier RF433 2 Gang No Neutral {"NAME":"W602","GPIO":[0,0,0,0,22,0,0,0,17,21,18,0,157],"FLAG":0,"BASE":18} +Girier RF433 3 Gang No Neutral {"NAME":"W603","GPIO":[0,0,0,0,23,18,0,0,17,21,19,22,157],"FLAG":15,"BASE":18} +Gocomma Wi-Fi Smart Switch {"NAME":"GoCommaSmartSw","GPIO":[17,255,255,255,21,0,0,0,255,56,0,0,0],"FLAG":0,"BASE":18} GoKlug Glass Touch 1 Gang {"NAME":"GoKlug 1x","GPIO":[56,57,0,0,0,9,0,0,0,0,0,21,0],"FLAG":0,"BASE":18} -Gosund KS-602S {"NAME":"Gosund KS-602S","GPIO":[17,0,56,0,0,0,0,0,0,0,21,0,158],"FLAG":0,"BASE":18} +Gosund KS-602S {"NAME":"Gosund KS-602S","GPIO":[17,0,0,0,0,0,0,0,21,157,0,0,0],"FLAG":0,"BASE":18} Gosund SW1 {"NAME":"Gosund SW1","GPIO":[17,0,57,0,0,0,0,0,0,0,21,0,56],"FLAG":0,"BASE":18} Gosund SW6 3-Way {"NAME":"Gosund SW6","GPIO":[17,0,56,0,9,0,0,0,0,0,22,21,158],"FLAG":0,"BASE":18} Hama Flush-mounted {"NAME":"Hama WiFiTouch","GPIO":[157,0,0,0,0,18,0,0,17,22,0,21,0],"FLAG":0,"BASE":45} HBN Wall-Mounted Timer {"NAME":"HBN Timer Switch","GPIO":[0,0,0,0,54,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +Hoch Circuit Breaker 1P {"NAME":"HOCH ZJSB9","GPIO":[17,255,255,255,255,255,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} +HomeMate 4 Node In-wall Smart Switch {"NAME":"HomeMate Wifi 4N ","GPIO":[255,255,255,9,21,12,255,255,10,22,23,24,11],"FLAG":15,"BASE":18} Innens 1 Gang 1 Way {"NAME":"Innens 1 Gang 1 Way","GPIO":[0,0,0,17,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} iSwitch Light & Fan {"NAME":"iSwitchOZ Light Fan","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Jinvoo SM-SW101-1 {"NAME":"SM-SW101-1","GPIO":[52,0,0,18,0,0,0,0,17,21,0,0,0],"FLAG":1,"BASE":18} @@ -1417,6 +1472,7 @@ KTNN-KG-T100 2 Gang Switch {"NAME":"Sonoff T1 2CH","GPIO":[17,255,255,255,0,22, Kuled K36 {"NAME":"KULED-B","GPIO":[9,255,255,255,255,255,21,52,29,56,255,255,255],"FLAG":0,"BASE":18} Kuled KS602S {"NAME":"KULED","GPIO":[17,255,255,255,255,255,0,0,21,56,255,255,255],"FLAG":0,"BASE":18} Kygne CD-301 {"NAME":"KYGNE Touch","GPIO":[0,0,0,0,52,53,0,0,21,17,0,0,0],"FLAG":0,"BASE":10} +L-5A01 {"NAME":"L-5A01","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} Laghten SS02S {"NAME":"Laghten SS02S","GPIO":[0,0,0,0,52,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} LerLink X801A-L No Neutral {"NAME":"LerLink X801-L","GPIO":[0,0,0,0,17,0,0,0,21,56,0,0,0],"FLAG":15,"BASE":18} Lerlink X802A 2 Gang {"NAME":"Lerlink X802A","GPIO":[0,0,0,18,17,0,0,0,21,23,22,0,0],"FLAG":15,"BASE":18} @@ -1426,7 +1482,10 @@ Lonsonho 3 Gang {"NAME":"Lonsonho X803A","GPIO":[0,0,0,18,17,19,0,0,21, Lonsonho SK3-01 {"NAME":"Tuya 1 Channel","GPIO":[0,0,0,0,0,17,0,0,0,0,0,21,52],"FLAG":0,"BASE":18} Lonsonho SK3-02 {"NAME":"Tuya 2 Channel","GPIO":[0,0,0,0,22,0,0,0,17,21,18,0,52],"FLAG":0,"BASE":18} Lonsonho SK3-03 {"NAME":"Tuya 3-ch v2","GPIO":[157,58,0,18,22,19,0,0,17,21,57,23,56],"FLAG":0,"BASE":18} +LoraTap 10A {"NAME":"LoraTap RR400W","GPIO":[0,0,0,0,157,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +LoraTap RR500W {"NAME":"LoraTap RR500W","GPIO":[157,255,255,255,9,255,255,255,255,21,255,255,56],"FLAG":15,"BASE":18} LoraTap WH100W-US 20A {"NAME":"LoraTap Boiler","GPIO":[0,0,0,0,0,0,0,0,17,21,0,0,56],"FLAG":0,"BASE":18} +Luani HVIO {"NAME":"Luani HVIO","GPIO":[0,255,255,255,21,22,0,0,9,10,255,52,0],"FLAG":1,"BASE":35} Luminea LHC-101.on {"NAME":"LHC-101.on","GPIO":[157,0,0,17,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} Luminea LHC-102.on {"NAME":"LHC-102.on","GPIO":[157,0,53,0,0,18,0,0,17,21,0,22,52],"FLAG":0,"BASE":18} LX-WIFI-00M 4 Gang {"NAME":"LX-WIFI-00M","GPIO":[17,25,255,255,23,22,18,19,21,0,20,24,0],"FLAG":0,"BASE":7} @@ -1442,9 +1501,11 @@ Minitiger 1 Gang v2 {"NAME":"MiniTiger1Band","GPIO":[0,56,0,0,0,17,0,0,21,0 Minitiger 2 Gang {"NAME":"minitiger 2 Gang","GPIO":[17,255,255,255,0,22,18,0,21,56,0,0,0],"FLAG":0,"BASE":28} Minitiger 2 Gang v2 {"NAME":"Minitiger2Band","GPIO":[0,0,0,17,18,0,0,0,0,21,22,0,0],"FLAG":0,"BASE":18} Minitiger 3 Gang {"NAME":"Minitiger3gang","GPIO":[0,0,0,9,11,10,255,255,22,21,23,0,0],"FLAG":0,"BASE":18} +Minitiger 4 Gang {"NAME":"Minitiger 4 Gang","GPIO":[17,0,0,0,23,22,18,19,21,158,20,24,0],"FLAG":0,"BASE":18} Moes 2 Gang {"NAME":"Moes WS-EU2-W","GPIO":[157,0,53,0,0,18,0,0,17,21,0,22,52],"FLAG":15,"BASE":18} Moes 3 Gang {"NAME":"Moes WS-EU3-W","GPIO":[157,0,54,18,22,19,0,0,17,21,53,23,52],"FLAG":15,"BASE":18} Moes BS-US-W Boiler {"NAME":"BS-US-W","GPIO":[54,0,0,17,21,0,0,0,0,0,52,0,55],"FLAG":0,"BASE":18} +Moes MS-104B-1 {"NAME":"Moes MS-104B","GPIO":[0,0,17,0,160,0,0,0,10,9,21,22,0],"FLAG":0,"BASE":18} Moes RF433 2 Gang Switch {"NAME":"WS-EUB2-WR","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Moes SS01-1 3-Way {"NAME":"Moes 3-Way","GPIO":[255,255,255,255,21,57,0,0,30,10,9,255,255],"FLAG":0,"BASE":18} Moes SS01S-1 {"NAME":"Moes Switch","GPIO":[255,255,255,255,56,0,0,0,21,17,255,255,255],"FLAG":0,"BASE":18} @@ -1466,6 +1527,11 @@ NaamaSmart KS602 {"NAME":"KS-602","GPIO":[17,0,0,0,0,0,0,0,21,158,0,0,0] Nedis Dual {"NAME":"SM-SW102U-2","GPIO":[158,0,0,18,22,0,0,0,17,21,0,0,0],"FLAG":1,"BASE":18} Nexete DS-123 {"NAME":"DS-123","GPIO":[157,57,255,17,21,18,0,0,255,22,56,255,255],"FLAG":0,"BASE":18} Nexete DS-123 Single {"NAME":"DS-123","GPIO":[157,0,255,18,0,17,0,0,255,21,56,255,255],"FLAG":0,"BASE":18} +Nova Digital Basic 1 MS101 {"NAME":"NovaDigBasic1","GPIO":[0,255,0,255,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +OpenEnergyMonitor WiFi MQTT Thermostat {"NAME":"MQTT-RELAY","GPIO":[17,0,255,0,0,21,0,0,0,0,0,0,56],"FLAG":0,"BASE":18} +PS-1604 16A {"NAME":"PS-1604 16A","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":1} +QS-WIFI-S03 Module {"NAME":"QS-WIFI-S03","GPIO":[17,255,255,255,255,0,0,0,82,21,0,0,0],"FLAG":0,"BASE":1} +QS-WIFI-S05 {"NAME":"QS-WIFI-S05","GPIO":[17,255,255,255,255,0,0,0,82,21,0,0,0],"FLAG":0,"BASE":1} Qualitel 1 Gang {"NAME":"Qualitel 1 Gang","GPIO":[157,0,0,9,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} Qualitel 2-Gang {"NAME":"Qualitel 2 Gang","GPIO":[157,0,53,0,0,10,0,0,9,21,0,22,52],"FLAG":0,"BASE":18} Qualitel 3 Gang {"NAME":"Qualitel 3 Gang","GPIO":[157,0,54,10,22,11,0,0,9,21,53,23,52],"FLAG":0,"BASE":18} @@ -1480,11 +1546,31 @@ Semicom LM-HP/GEVD-W {"NAME":"WaterHeater","GPIO":[158,56,0,0,0,17,0,0,0,0,0 Sesoo WIFI-EU-SK3-01 {"NAME":"Sensoo SK3-01","GPIO":[255,255,57,255,255,17,0,0,255,255,255,21,52],"FLAG":0,"BASE":18} Sesoo WIFI-EU-SK3-02 {"NAME":"Sesoo SK3-02","GPIO":[0,0,57,0,22,0,0,0,17,21,18,0,52],"FLAG":0,"BASE":18} Sesoo WIFI-US-SK3-04 {"NAME":"Tuya 4 Channel","GPIO":[52,255,255,19,23,17,0,0,20,24,22,21,18],"FLAG":0,"BASE":18} +Shelly 1 {"NAME":"Shelly 1","GPIO":[0,0,0,0,21,82,0,0,0,0,0,0,0],"FLAG":0,"BASE":46} +Shelly 1PM {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} +Shelly 2 {"NAME":"Shelly 2","GPIO":[0,135,0,136,21,22,0,0,9,0,10,137,0],"FLAG":0,"BASE":47} +Shelly 2.5 {"NAME":"Shelly 2.5","GPIO":[56,0,17,0,21,83,0,0,6,82,5,22,156],"FLAG":2,"BASE":18} +Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,6,156,5,21,0],"FLAG":15,"BASE":18} +Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,0,0,0,83,84,82,0,0],"FLAG":2,"BASE":18} +Sinilink USB {"NAME":"XY-WFUSB","GPIO":[255,255,0,255,17,21,0,0,0,0,56,0,157],"FLAG":0,"BASE":18} SK-A801-01-US 1 Gang {"NAME":"jsankou US Switch 1 Gang","GPIO":[157,0,0,0,0,0,0,0,17,29,0,0,0],"FLAG":0,"BASE":18} SK-W803-01-US 3 Gang {"NAME":"jsankou US Switch 3 Gang","GPIO":[157,0,0,18,30,19,0,0,17,29,0,31,0],"FLAG":0,"BASE":18} +Smart Home SS-8839-01 {"NAME":"SS-8839-01","GPIO":[0,255,0,255,21,0,0,0,17,57,0,56,0],"FLAG":0,"BASE":18} Smartlife Opard CD302 {"NAME":"CD302","GPIO":[0,0,0,0,52,57,0,0,29,17,0,0,0],"FLAG":0,"BASE":18} SmartPlex 3 Gang {"NAME":"Tuya 3 Channel","GPIO":[255,255,255,255,21,18,0,0,19,23,17,22,255],"FLAG":0,"BASE":18} +Sonoff 4CH (R2) {"NAME":"Sonoff 4CH","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":7} +Sonoff 4CH Pro (R2) {"NAME":"Sonoff 4CH Pro","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":23} +Sonoff 4CHPROR3 {"NAME":"Sonoff 4CHPROR3","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":23} +Sonoff 4CHR3 {"NAME":"Sonoff 4CHR3","GPIO":[17,255,255,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":7} +Sonoff Basic {"NAME":"Sonoff Basic","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":1} +Sonoff Basic R3 {"NAME":"Basic R3","GPIO":[17,255,0,255,255,0,255,255,21,56,0,0,255],"FLAG":0,"BASE":1} +Sonoff Dual {"NAME":"Sonoff Dual","GPIO":[0,148,0,149,255,0,0,0,0,56,255,0,0],"FLAG":0,"BASE":5} +Sonoff Dual R2 {"NAME":"Sonoff Dual R2","GPIO":[255,255,0,255,0,22,255,17,21,56,0,0,0],"FLAG":0,"BASE":39} Sonoff IW101 {"NAME":"Sonoff IW101","GPIO":[17,145,0,146,0,0,0,0,21,157,0,0,0],"FLAG":0,"BASE":41} +Sonoff Mini {"NAME":"Sonoff Mini","GPIO":[17,0,0,0,9,0,0,0,21,56,0,0,255],"FLAG":0,"BASE":1} +Sonoff Pow {"NAME":"Sonoff Pow","GPIO":[17,0,0,0,0,130,0,0,21,132,133,52,0],"FLAG":0,"BASE":6} +Sonoff Pow R2 {"NAME":"Sonoff Pow R2","GPIO":[17,145,0,146,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":43} +Sonoff RF {"NAME":"Sonoff RF","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":2} Sonoff T1 EU 1 Gang {"NAME":"Sonoff T1 1CH","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":28} Sonoff T1 EU 2 Gang {"NAME":"Sonoff T1 2CH","GPIO":[17,255,255,255,0,22,18,0,21,56,0,0,0],"FLAG":0,"BASE":29} Sonoff T1 UK 1 Gang {"NAME":"Sonoff T1 1CH","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":28} @@ -1493,16 +1579,23 @@ Sonoff T1 UK 3 Gang {"NAME":"Sonoff T1 3CH","GPIO":[17,255,255,255,23,22,18 Sonoff T1 US 1 Gang {"NAME":"Sonoff T1 1CH","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":28} Sonoff T1 US 2 Gang {"NAME":"Sonoff T1 2CH","GPIO":[17,255,255,255,0,22,18,0,21,56,0,0,0],"FLAG":0,"BASE":29} Sonoff T1 US 3 Gang {"NAME":"Sonoff T1 3CH","GPIO":[17,255,255,255,23,22,18,19,21,56,0,0,0],"FLAG":0,"BASE":30} +Sonoff TH10/TH16 {"NAME":"Sonoff TH","GPIO":[17,255,0,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":4} Sonoff Touch EU {"NAME":"Sonoff Touch","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":10} Sonoff Touch US {"NAME":"Sonoff Touch","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":10} Sonoff TX T3 EU 3 Gang {"NAME":"TX T3EU3C","GPIO":[17,255,0,255,23,22,18,19,21,158,0,0,0],"FLAG":0,"BASE":30} Sonoff TX T3 US 3 Gang {"NAME":"TX T3US3C","GPIO":[17,255,0,255,23,22,18,19,21,158,0,0,0],"FLAG":0,"BASE":30} SPC Hera {"NAME":"SPC HERA","GPIO":[157,0,0,17,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} +Splatura USB Device Power Switch {"NAME":"Splatura USB","GPIO":[0,0,52,0,0,0,0,0,0,21,0,122,0],"FLAG":0,"BASE":18} SRL 3-4WW 4 Gang {"NAME":"SRL 4WW Switch","GPIO":[0,0,0,19,23,18,0,0,17,21,24,22,20],"FLAG":0,"BASE":18} +SS-8839-02 {"NAME":"SS-8839-02","GPIO":[0,255,0,255,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} SS118-01K1 {"NAME":"SS118-01K1","GPIO":[255,255,255,17,21,255,0,0,255,255,56,255,255],"FLAG":0,"BASE":18} +SS311KWS RF Kinetic Switch and WiFi {"NAME":"SS311KWS","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} SS86-AI 3-Gang {"NAME":"SS86-AI 3 Gang","GPIO":[157,0,58,18,22,19,0,0,17,21,57,23,56],"FLAG":0,"BASE":18} SSMS118-01A1 Scene Light Smart {"NAME":"RGB Switch","GPIO":[30,0,32,10,39,38,0,0,31,9,37,21,0],"FLAG":0,"BASE":18} STITCH by Monoprice 35557 {"NAME":"Tuya WF15S ","GPIO":[255,255,0,0,255,255,0,0,255,108,255,107,0],"FLAG":0,"BASE":54} +SUPLA inCan by Espablo {"NAME":"Supla Espablo","GPIO":[0,255,4,255,17,21,0,0,255,22,255,0,52],"FLAG":1,"BASE":31} +SW-R03 {"NAME":"SW-R03","GPIO":[0,0,0,0,0,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +TCP Smart 1 Gang {"NAME":"TCP 1 Gang 1 Way","GPIO":[157,0,0,17,21,0,0,0,0,0,56,0,0],"FLAG":0,"BASE":18} Teckin SR-41 Single Pole {"NAME":"Teckin SR-41","GPIO":[17,0,0,0,0,0,0,0,21,158,0,0,0],"FLAG":0,"BASE":18} Teckin SR43 {"NAME":"Teckin SR43","GPIO":[0,0,52,0,0,17,0,0,21,22,0,0,18],"FLAG":0,"BASE":18} Teekar 10 Way 1 Gang {"NAME":"Teekar 10way","GPIO":[9,10,11,20,13,14,0,0,15,16,0,0,0],"FLAG":0,"BASE":18} @@ -1523,12 +1616,15 @@ Vaticas 1 {"NAME":"Vaticas","GPIO":[0,0,0,17,21,0,0,0,0,0,52,0,0] vhome RF433 3 Gang {"NAME":"VH-TB-US-003","GPIO":[0,0,0,0,21,18,0,0,19,23,17,22,158],"FLAG":15,"BASE":18} WiFi Smart Switch 2 Gang {"NAME":"Kingart N2","GPIO":[17,255,0,255,0,22,18,0,21,0,0,0,0],"FLAG":15,"BASE":18} WiFi Smart Switch 3 Gang {"NAME":"KingArt-3CH","GPIO":[17,255,0,255,23,22,18,19,21,52,0,0,0],"FLAG":15,"BASE":18} +WL-SW01_10 {"NAME":"WL-SW01_10","GPIO":[17,149,0,148,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} WS-US-03 {"NAME":"WS-US-03","GPIO":[17,255,255,255,23,22,18,19,21,56,0,0,0],"FLAG":0,"BASE":30} Xenon SM-SW102U 2 Gang {"NAME":"SM-SW102U-2","GPIO":[52,0,0,18,22,0,0,0,17,21,0,0,0],"FLAG":1,"BASE":18} Xenon SM-SW202 {"NAME":"SM-SW202","GPIO":[0,0,0,17,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} Yapmor 1-gang {"NAME":"YAPMOR 1CH","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":28} Youngzuth 2in1 {"NAME":"SW02 2W","GPIO":[52,0,0,9,21,0,0,0,10,22,0,0,0],"FLAG":0,"BASE":18} Youngzuth 3in1 {"NAME":"SW02 3W","GPIO":[56,0,0,19,23,18,0,0,17,21,0,22,0],"FLAG":0,"BASE":18} +Yuntong Smart {"NAME":"Yuntong Smart","GPIO":[0,0,0,0,21,0,0,0,122,56,0,158,0],"FLAG":0,"BASE":1} +Zemismart ERC309 Kinetic {"NAME":"Kinetic Switch","GPIO":[255,255,255,255,255,255,0,0,255,108,255,107,255],"FLAG":0,"BASE":54} Zemismart KS-811 1 Gang {"NAME":"KS-811 Single","GPIO":[17,0,0,0,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":18} Zemismart KS-811 2 Gang {"NAME":"KS-811 Dual","GPIO":[0,0,158,0,0,18,0,0,22,21,0,0,17],"FLAG":0,"BASE":18} Zemismart KS-811 3 Gang {"NAME":"KS-811 Triple","GPIO":[0,0,56,0,19,18,0,0,22,21,23,0,17],"FLAG":0,"BASE":18} @@ -1538,10 +1634,19 @@ Zemismart WF-BS01 {"NAME":"WF-BS01","GPIO":[53,0,0,17,21,0,0,0,0,0,52,0,0 Zemismart ZM-L01E {"NAME":"ZSmart ZM-L01E","GPIO":[255,255,255,255,255,255,0,0,255,21,255,255,17],"FLAG":0,"BASE":18} Zemismart ZM-L02E {"NAME":"ZSmart ZM-L02E","GPIO":[255,255,255,255,255,17,0,0,18,21,22,255,255],"FLAG":0,"BASE":18} Zemismart ZM-L03E {"NAME":"ZSmart ZM-L03E","GPIO":[52,53,0,0,23,17,0,0,19,21,22,0,18],"FLAG":0,"BASE":18} +ZUCZUG 1 Gang {"NAME":"2ph105626a x1","GPIO":[0,52,0,0,0,17,0,0,21,0,0,0,0],"FLAG":0,"BASE":1} ZUCZUG 2 Gang {"NAME":"2ph105626a x2","GPIO":[0,52,0,17,18,0,0,0,0,21,22,0,0],"FLAG":0,"BASE":1} ZUCZUG 3 Gang {"NAME":"2ph105626a x3","GPIO":[0,52,0,17,19,18,0,0,22,21,23,0,0],"FLAG":0,"BASE":1} ``` +## Temperature Sensor +``` +DS18B20 ESP01 DIY {"NAME":"ESP01S ds18b20","GPIO":[255,255,4,255,255,255,0,0,255,255,255,255,255],"FLAG":15,"BASE":18} +ESP01S DHT11 v1.0 DIY {"NAME":"ESP01S DHT11","GPIO":[0,0,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":4} +IOT4SH01DS {"NAME":"IOT4SH01DS","GPIO":[255,255,255,255,255,255,0,0,255,4,255,255,255],"FLAG":15,"BASE":18} +Shelly Add-on {"NAME":"Shelly 1 Temp ","GPIO":[192,0,0,4,21,82,0,0,0,0,0,0,0],"FLAG":0,"BASE":46} +``` + ## Valve ``` Garden Water Timer BQ05 {"NAME":"BQ05","GPIO":[17,0,0,0,0,0,0,0,21,157,0,0,0],"FLAG":1,"BASE":18} @@ -1575,13 +1680,18 @@ PS-1607 {"NAME":"PS-1607","GPIO":[17,0,0,0,0,22,18,0,21,0,0,0,0 Smanergy KA10 {"NAME":"KA10","GPIO":[0,56,0,17,134,132,0,0,131,53,21,0,0],"FLAG":0,"BASE":64} Sonoff IW100 {"NAME":"Sonoff IW100","GPIO":[17,145,0,146,0,0,0,0,21,157,0,0,0],"FLAG":0,"BASE":41} Sonoff S55 {"NAME":"Sonoff S55","GPIO":[17,255,0,255,255,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} -T16E Dual USB 10A {"NAME":"t16E 10A","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} +T16E Dual USB 10A {"NAME":"T16E 10A","GPIO":[0,0,0,17,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Teckin SR40 {"NAME":"RF-SR40-US","GPIO":[158,0,0,17,56,18,0,0,22,21,57,23,0],"FLAG":0,"BASE":18} TopGreener TGWF15RM {"NAME":"TGWF15RM","GPIO":[0,56,0,17,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":55} Vigica VGSPK00815 {"NAME":"VIGICA outlet","GPIO":[17,255,255,255,255,22,18,255,21,255,255,255,255],"FLAG":1,"BASE":18} ``` +## Water Sensor +``` +W06 {"NAME":"W06 Water Sensor","GPIO":[0,148,0,149,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} +``` + ## Zigbee Bridge ``` -Sonoff ZBBridge {"NAME":"Sonoff ZbBridge","GPIO":[56,165,0,166,215,0,0,0,0,158,0,0,17],"FLAG":0,"BASE":75} +Sonoff ZBBridge {"NAME":"Sonoff ZbBridge","GPIO":[56,165,0,166,215,0,0,0,6,158,5,0,17],"FLAG":0,"BASE":75} ``` From 2a18de5942b8301cbe8358bf4a7a879c84466361 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 5 Sep 2020 16:33:53 +0200 Subject: [PATCH 21/38] Zigbee better support for WSDCGQ01LM variants --- tasmota/xdrv_23_zigbee_5_converters.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 5655244d7..9c8d10cdf 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -1280,6 +1280,7 @@ void ZCLFrame::syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribu } else if ((nullptr != modelId) && (0 == getManufCode())) { translated = true; if (modelId.startsWith(F("lumi.sensor_ht")) || + modelId.equals(F("lumi.sens")) || modelId.startsWith(F("lumi.weather"))) { // Temp sensor // Filter according to prefix of model name // onla Aqara Temp/Humidity has manuf_code of zero. If non-zero we skip the parameters From 8c555dd22dfd4d24822e337758699e5a9edf9b9e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 18:04:11 +0200 Subject: [PATCH 22/38] Delete core_esp8266_waveform.cpp --- tasmota/core_esp8266_waveform.cpp | 440 ------------------------------ 1 file changed, 440 deletions(-) delete mode 100644 tasmota/core_esp8266_waveform.cpp diff --git a/tasmota/core_esp8266_waveform.cpp b/tasmota/core_esp8266_waveform.cpp deleted file mode 100644 index 371e9e554..000000000 --- a/tasmota/core_esp8266_waveform.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/* - esp8266_waveform - General purpose waveform generation and control, - supporting outputs on all pins in parallel. - - Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. - Copyright (c) 2020 Dirk O. Kaar. - - The core idea is to have a programmable waveform generator with a unique - high and low period (defined in microseconds or CPU clock cycles). TIMER1 is - set to 1-shot mode and is always loaded with the time until the next edge - of any live waveforms. - - Up to one waveform generator per pin supported. - - Each waveform generator is synchronized to the ESP clock cycle counter, not the - timer. This allows for removing interrupt jitter and delay as the counter - always increments once per 80MHz clock. Changes to a waveform are - contiguous and only take effect on the next waveform transition, - allowing for smooth transitions. - - This replaces older tone(), analogWrite(), and the Servo classes. - - Everywhere in the code where "ccy" or "ccys" is used, it means ESP.getCycleCount() - clock cycle time, or an interval measured in clock cycles, but not TIMER1 - cycles (which may be 2 CPU clock cycles @ 160MHz). - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifdef ESP8266 - -#include "core_esp8266_waveform.h" -#include -#include "ets_sys.h" -#include - -// Timer is 80MHz fixed. 160MHz CPU frequency need scaling. -constexpr bool ISCPUFREQ160MHZ = clockCyclesPerMicrosecond() == 160; -// Maximum delay between IRQs, Timer1, <= 2^23 / 80MHz -constexpr int32_t MAXIRQTICKSCCYS = microsecondsToClockCycles(10000); -// Maximum servicing time for any single IRQ -constexpr uint32_t ISRTIMEOUTCCYS = microsecondsToClockCycles(18); -// The latency between in-ISR rearming of the timer and the earliest firing -constexpr int32_t IRQLATENCYCCYS = microsecondsToClockCycles(2); -// The SDK and hardware take some time to actually get to our NMI code -constexpr int32_t DELTAIRQCCYS = ISCPUFREQ160MHZ ? - microsecondsToClockCycles(2) >> 1 : microsecondsToClockCycles(2); - -// for INFINITE, the NMI proceeds on the waveform without expiry deadline. -// for EXPIRES, the NMI expires the waveform automatically on the expiry ccy. -// for UPDATEEXPIRY, the NMI recomputes the exact expiry ccy and transitions to EXPIRES. -// for INIT, the NMI initializes nextPeriodCcy, and if expiryCcy != 0 includes UPDATEEXPIRY. -enum class WaveformMode : uint8_t {INFINITE = 0, EXPIRES = 1, UPDATEEXPIRY = 2, INIT = 3}; - -// Waveform generator can create tones, PWM, and servos -typedef struct { - uint32_t nextPeriodCcy; // ESP clock cycle when a period begins. If WaveformMode::INIT, temporarily holds positive phase offset ccy count - uint32_t endDutyCcy; // ESP clock cycle when going from duty to off - int32_t dutyCcys; // Set next off cycle at low->high to maintain phase - int32_t adjDutyCcys; // Temporary correction for next period - int32_t periodCcys; // Set next phase cycle at low->high to maintain phase - uint32_t expiryCcy; // For time-limited waveform, the CPU clock cycle when this waveform must stop. If WaveformMode::UPDATE, temporarily holds relative ccy count - WaveformMode mode; - int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin - bool autoPwm; // perform PWM duty to idle cycle ratio correction under high load at the expense of precise timings -} Waveform; - -namespace { - - static struct { - Waveform pins[17]; // State of all possible pins - uint32_t states = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code - uint32_t enabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code - - // Enable lock-free by only allowing updates to waveform.states and waveform.enabled from IRQ service routine - int32_t toSetBits = 0; // Message to the NMI handler to start/modify exactly one waveform - int32_t toDisableBits = 0; // Message to the NMI handler to disable exactly one pin from waveform generation - - uint32_t(*timer1CB)() = nullptr; - - bool timer1Running = false; - - uint32_t nextEventCcy; - } waveform; - -} - -// Interrupt on/off control -static ICACHE_RAM_ATTR void timer1Interrupt(); - -// Non-speed critical bits -#pragma GCC optimize ("Os") - -static void initTimer() { - timer1_disable(); - ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); - ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt); - timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE); - waveform.timer1Running = true; - timer1_write(IRQLATENCYCCYS); // Cause an interrupt post-haste -} - -static void ICACHE_RAM_ATTR deinitTimer() { - ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL); - timer1_disable(); - timer1_isr_init(); - waveform.timer1Running = false; -} - -extern "C" { - -// Set a callback. Pass in NULL to stop it -void setTimer1Callback(uint32_t (*fn)()) { - waveform.timer1CB = fn; - std::atomic_thread_fence(std::memory_order_acq_rel); - if (!waveform.timer1Running && fn) { - initTimer(); - } else if (waveform.timer1Running && !fn && !waveform.enabled) { - deinitTimer(); - } -} - -int startWaveform(uint8_t pin, uint32_t highUS, uint32_t lowUS, - uint32_t runTimeUS, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) { - return startWaveformClockCycles(pin, - microsecondsToClockCycles(highUS), microsecondsToClockCycles(lowUS), - microsecondsToClockCycles(runTimeUS), alignPhase, microsecondsToClockCycles(phaseOffsetUS), autoPwm); -} - -// Start up a waveform on a pin, or change the current one. Will change to the new -// waveform smoothly on next low->high transition. For immediate change, stopWaveform() -// first, then it will immediately begin. -int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys, - uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm) { - uint32_t periodCcys = highCcys + lowCcys; - if (periodCcys < MAXIRQTICKSCCYS) { - if (!highCcys) { - periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys; - } - else if (!lowCcys) { - highCcys = periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys; - } - } - // sanity checks, including mixed signed/unsigned arithmetic safety - if ((pin > 16) || isFlashInterfacePin(pin) || (alignPhase > 16) || - static_cast(periodCcys) <= 0 || - static_cast(highCcys) < 0 || static_cast(lowCcys) < 0) { - return false; - } - Waveform& wave = waveform.pins[pin]; - wave.dutyCcys = highCcys; - wave.adjDutyCcys = 0; - wave.periodCcys = periodCcys; - wave.autoPwm = autoPwm; - - std::atomic_thread_fence(std::memory_order_acquire); - const uint32_t pinBit = 1UL << pin; - if (!(waveform.enabled & pinBit)) { - // wave.nextPeriodCcy and wave.endDutyCcy are initialized by the ISR - wave.nextPeriodCcy = phaseOffsetCcys; - wave.expiryCcy = runTimeCcys; // in WaveformMode::INIT, temporarily hold relative cycle count - wave.mode = WaveformMode::INIT; - wave.alignPhase = (alignPhase < 0) ? -1 : alignPhase; - if (!wave.dutyCcys) { - // If initially at zero duty cycle, force GPIO off - if (pin == 16) { - GP16O = 0; - } - else { - GPOC = pinBit; - } - } - std::atomic_thread_fence(std::memory_order_release); - waveform.toSetBits = 1UL << pin; - std::atomic_thread_fence(std::memory_order_release); - if (!waveform.timer1Running) { - initTimer(); - } - else if (T1V > IRQLATENCYCCYS) { - // Must not interfere if Timer is due shortly - timer1_write(IRQLATENCYCCYS); - } - } - else { - wave.mode = WaveformMode::INFINITE; // turn off possible expiry to make update atomic from NMI - std::atomic_thread_fence(std::memory_order_release); - wave.expiryCcy = runTimeCcys; // in WaveformMode::UPDATEEXPIRY, temporarily hold relative cycle count - if (runTimeCcys) { - wave.mode = WaveformMode::UPDATEEXPIRY; - std::atomic_thread_fence(std::memory_order_release); - waveform.toSetBits = 1UL << pin; - } - } - std::atomic_thread_fence(std::memory_order_acq_rel); - while (waveform.toSetBits) { - delay(0); // Wait for waveform to update - std::atomic_thread_fence(std::memory_order_acquire); - } - return true; -} - -// Stops a waveform on a pin -int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) { - // Can't possibly need to stop anything if there is no timer active - if (!waveform.timer1Running) { - return false; - } - // If user sends in a pin >16 but <32, this will always point to a 0 bit - // If they send >=32, then the shift will result in 0 and it will also return false - std::atomic_thread_fence(std::memory_order_acquire); - const uint32_t pinBit = 1UL << pin; - if (waveform.enabled & pinBit) { - waveform.toDisableBits = 1UL << pin; - std::atomic_thread_fence(std::memory_order_release); - // Must not interfere if Timer is due shortly - if (T1V > IRQLATENCYCCYS) { - timer1_write(IRQLATENCYCCYS); - } - while (waveform.toDisableBits) { - /* no-op */ // Can't delay() since stopWaveform may be called from an IRQ - std::atomic_thread_fence(std::memory_order_acquire); - } - } - if (!waveform.enabled && !waveform.timer1CB) { - deinitTimer(); - } - return true; -} - -}; - -// Speed critical bits -#pragma GCC optimize ("O2") - -// For dynamic CPU clock frequency switch in loop the scaling logic would have to be adapted. -// Using constexpr makes sure that the CPU clock frequency is compile-time fixed. -static inline ICACHE_RAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X) { - if (ISCPUFREQ160MHZ) { - return isCPU2X ? ccys : (ccys >> 1); - } - else { - return isCPU2X ? (ccys << 1) : ccys; - } -} - -static ICACHE_RAM_ATTR void timer1Interrupt() { - const uint32_t isrStartCcy = ESP.getCycleCount(); - int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; - const bool isCPU2X = CPU2X & 1; - if ((waveform.toSetBits && !(waveform.enabled & waveform.toSetBits)) || waveform.toDisableBits) { - // Handle enable/disable requests from main app. - waveform.enabled = (waveform.enabled & ~waveform.toDisableBits) | waveform.toSetBits; // Set the requested waveforms on/off - // Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t) - waveform.toDisableBits = 0; - } - - if (waveform.toSetBits) { - const int toSetPin = __builtin_ffs(waveform.toSetBits) - 1; - Waveform& wave = waveform.pins[toSetPin]; - switch (wave.mode) { - case WaveformMode::INIT: - waveform.states &= ~waveform.toSetBits; // Clear the state of any just started - if (wave.alignPhase >= 0 && waveform.enabled & (1UL << wave.alignPhase)) { - wave.nextPeriodCcy = waveform.pins[wave.alignPhase].nextPeriodCcy + wave.nextPeriodCcy; - } - else { - wave.nextPeriodCcy = waveform.nextEventCcy; - } - if (!wave.expiryCcy) { - wave.mode = WaveformMode::INFINITE; - break; - } - // fall through - case WaveformMode::UPDATEEXPIRY: - // in WaveformMode::UPDATEEXPIRY, expiryCcy temporarily holds relative CPU cycle count - wave.expiryCcy = wave.nextPeriodCcy + scaleCcys(wave.expiryCcy, isCPU2X); - wave.mode = WaveformMode::EXPIRES; - break; - default: - break; - } - waveform.toSetBits = 0; - } - - // Exit the loop if the next event, if any, is sufficiently distant. - const uint32_t isrTimeoutCcy = isrStartCcy + ISRTIMEOUTCCYS; - uint32_t busyPins = waveform.enabled; - waveform.nextEventCcy = isrStartCcy + MAXIRQTICKSCCYS; - - uint32_t now = ESP.getCycleCount(); - uint32_t isrNextEventCcy = now; - while (busyPins) { - if (static_cast(isrNextEventCcy - now) > IRQLATENCYCCYS) { - waveform.nextEventCcy = isrNextEventCcy; - break; - } - isrNextEventCcy = waveform.nextEventCcy; - uint32_t loopPins = busyPins; - while (loopPins) { - const int pin = __builtin_ffsl(loopPins) - 1; - const uint32_t pinBit = 1UL << pin; - loopPins ^= pinBit; - - Waveform& wave = waveform.pins[pin]; - - if (clockDrift) { - wave.endDutyCcy += clockDrift; - wave.nextPeriodCcy += clockDrift; - wave.expiryCcy += clockDrift; - } - - uint32_t waveNextEventCcy = (waveform.states & pinBit) ? wave.endDutyCcy : wave.nextPeriodCcy; - if (WaveformMode::EXPIRES == wave.mode && - static_cast(waveNextEventCcy - wave.expiryCcy) >= 0 && - static_cast(now - wave.expiryCcy) >= 0) { - // Disable any waveforms that are done - waveform.enabled ^= pinBit; - busyPins ^= pinBit; - } - else { - const int32_t overshootCcys = now - waveNextEventCcy; - if (overshootCcys >= 0) { - const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X); - if (waveform.states & pinBit) { - // active configuration and forward are 100% duty - if (wave.periodCcys == wave.dutyCcys) { - wave.nextPeriodCcy += periodCcys; - wave.endDutyCcy = wave.nextPeriodCcy; - } - else { - if (wave.autoPwm) { - wave.adjDutyCcys += overshootCcys; - } - waveform.states ^= pinBit; - if (16 == pin) { - GP16O = 0; - } - else { - GPOC = pinBit; - } - } - waveNextEventCcy = wave.nextPeriodCcy; - } - else { - wave.nextPeriodCcy += periodCcys; - if (!wave.dutyCcys) { - wave.endDutyCcy = wave.nextPeriodCcy; - } - else { - int32_t dutyCcys = scaleCcys(wave.dutyCcys, isCPU2X); - if (dutyCcys <= wave.adjDutyCcys) { - dutyCcys >>= 1; - wave.adjDutyCcys -= dutyCcys; - } - else if (wave.adjDutyCcys) { - dutyCcys -= wave.adjDutyCcys; - wave.adjDutyCcys = 0; - } - wave.endDutyCcy = now + dutyCcys; - if (static_cast(wave.endDutyCcy - wave.nextPeriodCcy) > 0) { - wave.endDutyCcy = wave.nextPeriodCcy; - } - waveform.states |= pinBit; - if (16 == pin) { - GP16O = 1; - } - else { - GPOS = pinBit; - } - } - waveNextEventCcy = wave.endDutyCcy; - } - - if (WaveformMode::EXPIRES == wave.mode && static_cast(waveNextEventCcy - wave.expiryCcy) > 0) { - waveNextEventCcy = wave.expiryCcy; - } - } - - if (static_cast(waveNextEventCcy - isrTimeoutCcy) >= 0) { - busyPins ^= pinBit; - if (static_cast(waveform.nextEventCcy - waveNextEventCcy) > 0) { - waveform.nextEventCcy = waveNextEventCcy; - } - } - else if (static_cast(isrNextEventCcy - waveNextEventCcy) > 0) { - isrNextEventCcy = waveNextEventCcy; - } - } - now = ESP.getCycleCount(); - } - clockDrift = 0; - } - - int32_t callbackCcys = 0; - if (waveform.timer1CB) { - callbackCcys = scaleCcys(microsecondsToClockCycles(waveform.timer1CB()), isCPU2X); - } - now = ESP.getCycleCount(); - int32_t nextEventCcys = waveform.nextEventCcy - now; - // Account for unknown duration of timer1CB(). - if (waveform.timer1CB && nextEventCcys > callbackCcys) { - waveform.nextEventCcy = now + callbackCcys; - nextEventCcys = callbackCcys; - } - - // Timer is 80MHz fixed. 160MHz CPU frequency need scaling. - int32_t deltaIrqCcys = DELTAIRQCCYS; - int32_t irqLatencyCcys = IRQLATENCYCCYS; - if (isCPU2X) { - nextEventCcys >>= 1; - deltaIrqCcys >>= 1; - irqLatencyCcys >>= 1; - } - - // Firing timer too soon, the NMI occurs before ISR has returned. - if (nextEventCcys < irqLatencyCcys + deltaIrqCcys) { - waveform.nextEventCcy = now + IRQLATENCYCCYS + DELTAIRQCCYS; - nextEventCcys = irqLatencyCcys; - } - else { - nextEventCcys -= deltaIrqCcys; - } - - // Register access is fast and edge IRQ was configured before. - T1L = nextEventCcys; -} - -#endif // ESP8266 From f3123a276105f4dba1648d4909f7d9382485bbb4 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 18:05:43 +0200 Subject: [PATCH 23/38] Delete core_esp8266_waveform.h --- tasmota/core_esp8266_waveform.h | 93 --------------------------------- 1 file changed, 93 deletions(-) delete mode 100644 tasmota/core_esp8266_waveform.h diff --git a/tasmota/core_esp8266_waveform.h b/tasmota/core_esp8266_waveform.h deleted file mode 100644 index ff5a0f56f..000000000 --- a/tasmota/core_esp8266_waveform.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - esp8266_waveform - General purpose waveform generation and control, - supporting outputs on all pins in parallel. - - Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. - Copyright (c) 2020 Dirk O. Kaar. - - The core idea is to have a programmable waveform generator with a unique - high and low period (defined in microseconds or CPU clock cycles). TIMER1 is - set to 1-shot mode and is always loaded with the time until the next edge - of any live waveforms. - - Up to one waveform generator per pin supported. - - Each waveform generator is synchronized to the ESP clock cycle counter, not the - timer. This allows for removing interrupt jitter and delay as the counter - always increments once per 80MHz clock. Changes to a waveform are - contiguous and only take effect on the next waveform transition, - allowing for smooth transitions. - - This replaces older tone(), analogWrite(), and the Servo classes. - - Everywhere in the code where "ccy" or "ccys" is used, it means ESP.getCycleCount() - clock cycle count, or an interval measured in CPU clock cycles, but not TIMER1 - cycles (which may be 2 CPU clock cycles @ 160MHz). - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifdef ESP8266 - -#include - -#ifndef __ESP8266_WAVEFORM_H -#define __ESP8266_WAVEFORM_H - -#ifdef __cplusplus -extern "C" { -#endif - -// Start or change a waveform of the specified high and low times on specific pin. -// If runtimeUS > 0 then automatically stop it after that many usecs, relative to the next -// full period. -// If waveform is not yet started on pin, and on pin == alignPhase a waveform is running, -// the new waveform is started at phaseOffsetUS phase offset, in microseconds, to that. -// Setting autoPwm to true allows the wave generator to maintain PWM duty to idle cycle ratio -// under load, for applications where frequency or duty cycle must not change, leave false. -// Returns true or false on success or failure. -int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, - uint32_t runTimeUS = 0, int8_t alignPhase = -1, uint32_t phaseOffsetUS = 0, bool autoPwm = false); -// Start or change a waveform of the specified high and low CPU clock cycles on specific pin. -// If runtimeCycles > 0 then automatically stop it after that many CPU clock cycles, relative to the next -// full period. -// If waveform is not yet started on pin, and on pin == alignPhase a waveform is running, -// the new waveform is started at phaseOffsetCcys phase offset, in CPU clock cycles, to that. -// Setting autoPwm to true allows the wave generator to maintain PWM duty to idle cycle ratio -// under load, for applications where frequency or duty cycle must not change, leave false. -// Returns true or false on success or failure. -int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCcys, uint32_t timeLowCcys, - uint32_t runTimeCcys = 0, int8_t alignPhase = -1, uint32_t phaseOffsetCcys = 0, bool autoPwm = false); -// Stop a waveform, if any, on the specified pin. -// Returns true or false on success or failure. -int stopWaveform(uint8_t pin); - -// Add a callback function to be called on *EVERY* timer1 trigger. The -// callback returns the number of microseconds until the next desired call. -// However, since it is called every timer1 interrupt, it may be called -// again before this period. It should therefore use the ESP Cycle Counter -// to determine whether or not to perform an operation. -// Pass in NULL to disable the callback and, if no other waveforms being -// generated, stop the timer as well. -// Make sure the CB function has the ICACHE_RAM_ATTR decorator. -void setTimer1Callback(uint32_t (*fn)()); - -#ifdef __cplusplus -} -#endif - -#endif - -#endif // ESP8266 From 3c2746892ae70ff8f32bd052a843bed21cadbe12 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 18:05:53 +0200 Subject: [PATCH 24/38] Delete core_esp8266_wiring_digital.cpp --- tasmota/core_esp8266_wiring_digital.cpp | 269 ------------------------ 1 file changed, 269 deletions(-) delete mode 100644 tasmota/core_esp8266_wiring_digital.cpp diff --git a/tasmota/core_esp8266_wiring_digital.cpp b/tasmota/core_esp8266_wiring_digital.cpp deleted file mode 100644 index 982e1c6bf..000000000 --- a/tasmota/core_esp8266_wiring_digital.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - digital.c - wiring digital implementation for esp8266 - - Copyright (c) 2015 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifdef ESP8266 - -#define ARDUINO_MAIN -#include "wiring_private.h" -#include "pins_arduino.h" -#include "c_types.h" -#include "eagle_soc.h" -#include "ets_sys.h" -#include "user_interface.h" -#include "core_esp8266_waveform.h" -#include "interrupts.h" - -extern "C" { - -volatile uint32_t* const esp8266_gpioToFn[16] PROGMEM = { &GPF0, &GPF1, &GPF2, &GPF3, &GPF4, &GPF5, &GPF6, &GPF7, &GPF8, &GPF9, &GPF10, &GPF11, &GPF12, &GPF13, &GPF14, &GPF15 }; - -extern void __pinMode(uint8_t pin, uint8_t mode) { - if(pin < 16){ - if(mode == SPECIAL){ - GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - GPEC = (1 << pin); //Disable - GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin) - if(pin == 3) GPF(pin) |= (1 << GPFPU);//enable pullup on RX - } else if(mode & FUNCTION_0){ - GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - GPEC = (1 << pin); //Disable - GPF(pin) = GPFFS((mode >> 4) & 0x07); - if(pin == 13 && mode == FUNCTION_4) GPF(pin) |= (1 << GPFPU);//enable pullup on RX - } else if(mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN){ - GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - if(mode == OUTPUT_OPEN_DRAIN) GPC(pin) |= (1 << GPCD); - GPES = (1 << pin); //Enable - } else if(mode == INPUT || mode == INPUT_PULLUP){ - GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPEC = (1 << pin); //Disable - GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - if(mode == INPUT_PULLUP) { - GPF(pin) |= (1 << GPFPU); // Enable Pullup - } - } else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){ - GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPEC = (1 << pin); //Disable - if(mode == WAKEUP_PULLUP) { - GPF(pin) |= (1 << GPFPU); // Enable Pullup - GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED) - } else { - GPF(pin) |= (1 << GPFPD); // Enable Pulldown - GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED) - } - } - } else if(pin == 16){ - GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPC16 = 0; - if(mode == INPUT || mode == INPUT_PULLDOWN_16){ - if(mode == INPUT_PULLDOWN_16){ - GPF16 |= (1 << GP16FPD);//Enable Pulldown - } - GP16E &= ~1; - } else if(mode == OUTPUT){ - GP16E |= 1; - } - } -} - -extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) { - stopWaveform(pin); - if(pin < 16){ - if(val) GPOS = (1 << pin); - else GPOC = (1 << pin); - } else if(pin == 16){ - if(val) GP16O |= 1; - else GP16O &= ~1; - } -} - -extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) { - if(pin < 16){ - return GPIP(pin); - } else if(pin == 16){ - return GP16I & 0x01; - } - return 0; -} - -/* - GPIO INTERRUPTS -*/ - -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); - -typedef struct { - uint8_t mode; - voidFuncPtr fn; - void * arg; - bool functional; -} interrupt_handler_t; - -//duplicate from functionalInterrupt.h keep in sync -typedef struct InterruptInfo { - uint8_t pin; - uint8_t value; - uint32_t micro; -} InterruptInfo; - -typedef struct { - InterruptInfo* interruptInfo; - void* functionInfo; -} ArgStructure; - -static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0, 0}, }; -static uint32_t interrupt_reg = 0; - -void ICACHE_RAM_ATTR interrupt_handler(void *arg, void *frame) -{ - (void) arg; - (void) frame; - uint32_t status = GPIE; - GPIEC = status;//clear them interrupts - uint32_t levels = GPI; - if(status == 0 || interrupt_reg == 0) return; - ETS_GPIO_INTR_DISABLE(); - int i = 0; - uint32_t changedbits = status & interrupt_reg; - while(changedbits){ - while(!(changedbits & (1 << i))) i++; - changedbits &= ~(1 << i); - interrupt_handler_t *handler = &interrupt_handlers[i]; - if (handler->fn && - (handler->mode == CHANGE || - (handler->mode & 1) == !!(levels & (1 << i)))) { - // to make ISR compatible to Arduino AVR model where interrupts are disabled - // we disable them before we call the client ISR - esp8266::InterruptLock irqLock; // stop other interrupts - if (handler->functional) - { - ArgStructure* localArg = (ArgStructure*)handler->arg; - if (localArg && localArg->interruptInfo) - { - localArg->interruptInfo->pin = i; - localArg->interruptInfo->value = __digitalRead(i); - localArg->interruptInfo->micro = micros(); - } - } - if (handler->arg) - { - ((voidFuncPtrArg)handler->fn)(handler->arg); - } - else - { - handler->fn(); - } - } - } - ETS_GPIO_INTR_ENABLE(); -} - -extern void cleanupFunctional(void* arg); - -static void set_interrupt_handlers(uint8_t pin, voidFuncPtr userFunc, void* arg, uint8_t mode, bool functional) -{ - interrupt_handler_t* handler = &interrupt_handlers[pin]; - handler->mode = mode; - handler->fn = userFunc; - if (handler->functional && handler->arg) // Clean when new attach without detach - { - cleanupFunctional(handler->arg); - } - handler->arg = arg; - handler->functional = functional; -} - -extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode, bool functional) -{ - // #5780 - // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map - if ((uint32_t)userFunc >= 0x40200000) - { - // ISR not in IRAM - ::printf((PGM_P)F("ISR not in IRAM!\r\n")); - abort(); - } - - if(pin < 16) { - ETS_GPIO_INTR_DISABLE(); - set_interrupt_handlers(pin, (voidFuncPtr)userFunc, arg, mode, functional); - interrupt_reg |= (1 << pin); - GPC(pin) &= ~(0xF << GPCI);//INT mode disabled - GPIEC = (1 << pin); //Clear Interrupt for this pin - GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode" - ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg); - ETS_GPIO_INTR_ENABLE(); - } -} - -extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) -{ - __attachInterruptFunctionalArg(pin, userFunc, arg, mode, false); -} - -extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { - if (pin < 16) - { - ETS_GPIO_INTR_DISABLE(); - GPC(pin) &= ~(0xF << GPCI);//INT mode disabled - GPIEC = (1 << pin); //Clear Interrupt for this pin - interrupt_reg &= ~(1 << pin); - set_interrupt_handlers(pin, nullptr, nullptr, 0, false); - if (interrupt_reg) - { - ETS_GPIO_INTR_ENABLE(); - } - } -} - -extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) -{ - __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false); -} - -extern void __resetPins() { - for (int i = 0; i <= 16; ++i) { - if (!isFlashInterfacePin(i)) - pinMode(i, INPUT); - } -} - -extern void initPins() { - //Disable UART interrupts - system_set_os_print(0); - U0IE = 0; - U1IE = 0; - - resetPins(); -} - -extern void resetPins() __attribute__ ((weak, alias("__resetPins"))); -extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); -extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); -extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"), nothrow)); -extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); -extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); -extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); - -}; - -#endif // ESP8266 From 5e03ddc8e8b0995cf33b20aa96f94ed66c556fe8 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 18:06:07 +0200 Subject: [PATCH 25/38] Delete core_esp8266_wiring_pwm.cpp --- tasmota/core_esp8266_wiring_pwm.cpp | 96 ----------------------------- 1 file changed, 96 deletions(-) delete mode 100644 tasmota/core_esp8266_wiring_pwm.cpp diff --git a/tasmota/core_esp8266_wiring_pwm.cpp b/tasmota/core_esp8266_wiring_pwm.cpp deleted file mode 100644 index d879a0001..000000000 --- a/tasmota/core_esp8266_wiring_pwm.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - pwm.c - analogWrite implementation for esp8266 - - Use the shared TIMER1 utilities to generate PWM signals - - Original Copyright (c) 2015 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifdef ESP8266 - -#include -#include "core_esp8266_waveform.h" - -extern "C" { - -static uint32_t analogMap = 0; -static int32_t analogScale = 255; // Match upstream default, breaking change from 2.x.x -static uint16_t analogFreq = 1000; - -extern void __analogWriteRange(uint32_t range) { - if ((range >= 15) && (range <= 65535)) { - analogScale = range; - } -} - -extern void __analogWriteResolution(int res) { - if ((res >= 4) && (res <= 16)) { - analogScale = (1 << res) - 1; - } -} - -extern void __analogWriteFreq(uint32_t freq) { - if (freq < 40) { - analogFreq = 40; - } else if (freq > 60000) { - analogFreq = 60000; - } else { - analogFreq = freq; - } -} - - -extern void __analogWrite(uint8_t pin, int val) { - if (pin > 16) { - return; - } - - uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq; - if (val < 0) { - val = 0; - } else if (val > analogScale) { - val = analogScale; - } - - // Per the Arduino docs at https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/ - // val: the duty cycle: between 0 (always off) and 255 (always on). - // So if val = 0 we have digitalWrite(LOW), if we have val==range we have digitalWrite(HIGH) - - if (analogMap & 1UL << pin) { - analogMap &= ~(1 << pin); - } - else { - pinMode(pin, OUTPUT); - } - uint32_t high = (analogPeriod * val) / analogScale; - uint32_t low = analogPeriod - high; - // Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t) - int phaseReference = __builtin_ffs(analogMap) - 1; - if (startWaveformClockCycles(pin, high, low, 0, phaseReference, 0, true)) { - analogMap |= (1 << pin); - } -} - -extern void analogWrite(uint8_t pin, int val) __attribute__((weak, alias("__analogWrite"))); -extern void analogWriteFreq(uint32_t freq) __attribute__((weak, alias("__analogWriteFreq"))); -extern void analogWriteRange(uint32_t range) __attribute__((weak, alias("__analogWriteRange"))); -extern void analogWriteResolution(int res) __attribute__((weak, alias("__analogWriteResolution"))); - -}; - -#endif // ESP8266 From be12a7e0d0921a14893294c09701736cf82a768a Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sat, 5 Sep 2020 21:52:43 +0200 Subject: [PATCH 26/38] Update Italian language --- tasmota/language/it_IT.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index bca4ea339..70360f15c 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -1,7 +1,7 @@ /* it-IT.h - localization for Italian - Italy for Tasmota - Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 02.09.2020 + Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 05.09.2020 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 @@ -823,8 +823,8 @@ #define D_AS3935_NOISE "rilevato rumore" #define D_AS3935_DISTDET "rilevato disturbatore" #define D_AS3935_INTNOEV "Interrupt senza evento!" -#define D_AS3935_FLICKER "IRQ flicker!" -#define D_AS3935_POWEROFF "Power Off" +#define D_AS3935_FLICKER "Flicker PIN IRQ!" +#define D_AS3935_POWEROFF "Spegnimento" #define D_AS3935_NOMESS "in ascolto..." #define D_AS3935_ON "ON" #define D_AS3935_OFF "OFF" From abc7ba6cacb0f66a9b0c7d50c78557ef2cc9fab5 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 22:42:15 +0200 Subject: [PATCH 27/38] Remove ESP32 move to main --- platformio_override_sample.ini | 41 ---------------------------------- 1 file changed, 41 deletions(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index be5d5f24f..f8bf9ead1 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -167,44 +167,3 @@ build_type = debug build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} -Wstack-usage=300 - - -; *** Experimental ESP32 Tasmota version *** -; *** expect the unexpected. Many features not working!!! *** - -[common32] -platform = espressif32@1.12.4 -platform_packages = tool-esptoolpy@1.20800.0 -board = esp32dev -board_build.ldscript = esp32_out.ld -board_build.partitions = esp32_partition_app1984k_spiffs64k.csv -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_flash = ${common.board_build.f_flash} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${esp_defaults.build_unflags} - -Wpointer-arith -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = 921600 -extra_scripts = ${common.extra_scripts} - -build_flags = ${esp_defaults.build_flags} - - -D CORE_DEBUG_LEVEL=0 - -D BUFFER_LENGTH=128 - -D MQTT_MAX_PACKET_SIZE=1200 - -D uint32=uint32_t - -D uint16=uint16_t - -D uint8=uint8_t - -D sint8_t=int8_t - -D sint32_t=int32_t - -D sint16_t=int16_t - -D memcpy_P=memcpy - -D memcmp_P=memcmp - -lib_extra_dirs = - libesp32 - -lib_ignore = - cc1101 From 7b83aeb5ff773b5e5e14065979e4f7509495c0ff Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 22:50:26 +0200 Subject: [PATCH 28/38] ESP32 settings --- platformio.ini | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/platformio.ini b/platformio.ini index 86f72211a..ace3cc6db 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,6 +14,7 @@ build_dir = .pioenvs workspace_dir = .pioenvs build_cache_dir = .cache extra_configs = platformio_tasmota_env.ini + platformio_tasmota_env32.ini platformio_override.ini ; *** Build/upload environment @@ -76,6 +77,46 @@ upload_resetmethod = nodemcu upload_port = COM5 extra_scripts = ${scripts_defaults.extra_scripts} +; *** BETA ESP32 Tasmota version *** +; *** expect the unexpected. Some features not working!!! *** + +[common32] +platform = espressif32@1.12.4 +platform_packages = tool-esptoolpy@1.20800.0 +board = esp32dev +board_build.ldscript = esp32_out.ld +board_build.partitions = esp32_partition_app1984k_spiffs64k.csv +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_flash = ${common.board_build.f_flash} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${esp_defaults.build_unflags} + -Wpointer-arith +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = 921600 +extra_scripts = ${common.extra_scripts} + +build_flags = ${esp_defaults.build_flags} + + -D CORE_DEBUG_LEVEL=0 + -D BUFFER_LENGTH=128 + -D MQTT_MAX_PACKET_SIZE=1200 + -D uint32=uint32_t + -D uint16=uint16_t + -D uint8=uint8_t + -D sint8_t=int8_t + -D sint32_t=int32_t + -D sint16_t=int16_t + -D memcpy_P=memcpy + -D memcmp_P=memcmp + +lib_extra_dirs = + libesp32 + +lib_ignore = + cc1101 + [scripts_defaults] extra_scripts = pio/strip-floats.py pio/name-firmware.py From e966fbb2f1a51f9a3bd1d197a40b5ee526fbf303 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 22:52:11 +0200 Subject: [PATCH 29/38] Remove esp32 env --- platformio_override_sample.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index f8bf9ead1..ddd74a60d 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -9,8 +9,7 @@ ; http://docs.platformio.org/en/stable/projectconf.html [platformio] -extra_configs = platformio_tasmota_env32.ini - platformio_tasmota_cenv.ini +extra_configs = platformio_tasmota_cenv.ini ; *** Build/upload environment default_envs = From 640117844cb7d49e1ebd184f7214edab32637829 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 23:00:09 +0200 Subject: [PATCH 30/38] Create platformio_tasmota32.ini --- platformio_tasmota32.ini | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 platformio_tasmota32.ini diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini new file mode 100644 index 000000000..0ddf8c692 --- /dev/null +++ b/platformio_tasmota32.ini @@ -0,0 +1,33 @@ +; *** BETA ESP32 Tasmota version *** +; *** expect the unexpected. Some features not working!!! *** + +[common32] +platform = espressif32@1.12.4 +platform_packages = tool-esptoolpy@1.20800.0 +board = esp32dev +board_build.ldscript = esp32_out.ld +board_build.partitions = esp32_partition_app1984k_spiffs64k.csv +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_flash = ${common.board_build.f_flash} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${esp_defaults.build_unflags} + -Wpointer-arith +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = 921600 +extra_scripts = ${common.extra_scripts} + +build_flags = ${esp_defaults.build_flags} + + -D CORE_DEBUG_LEVEL=0 + -D BUFFER_LENGTH=128 + -D MQTT_MAX_PACKET_SIZE=1200 + -D uint32=uint32_t + -D uint16=uint16_t + -D uint8=uint8_t + -D sint8_t=int8_t + -D sint32_t=int32_t + -D sint16_t=int16_t + -D memcpy_P=memcpy + -D memcmp_P=memcmp From 8a5ab7febbc45af5b73336ffc52dc3efc1934b2e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 23:03:19 +0200 Subject: [PATCH 31/38] Move ESP32 in extra platformio32 file --- platformio.ini | 43 ++----------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/platformio.ini b/platformio.ini index ace3cc6db..161c0686f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,8 @@ src_dir = tasmota build_dir = .pioenvs workspace_dir = .pioenvs build_cache_dir = .cache -extra_configs = platformio_tasmota_env.ini +extra_configs = platformio_tasmota32.ini + platformio_tasmota_env.ini platformio_tasmota_env32.ini platformio_override.ini @@ -76,46 +77,6 @@ upload_speed = 115200 upload_resetmethod = nodemcu upload_port = COM5 extra_scripts = ${scripts_defaults.extra_scripts} - -; *** BETA ESP32 Tasmota version *** -; *** expect the unexpected. Some features not working!!! *** - -[common32] -platform = espressif32@1.12.4 -platform_packages = tool-esptoolpy@1.20800.0 -board = esp32dev -board_build.ldscript = esp32_out.ld -board_build.partitions = esp32_partition_app1984k_spiffs64k.csv -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_flash = ${common.board_build.f_flash} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${esp_defaults.build_unflags} - -Wpointer-arith -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = 921600 -extra_scripts = ${common.extra_scripts} - -build_flags = ${esp_defaults.build_flags} - - -D CORE_DEBUG_LEVEL=0 - -D BUFFER_LENGTH=128 - -D MQTT_MAX_PACKET_SIZE=1200 - -D uint32=uint32_t - -D uint16=uint16_t - -D uint8=uint8_t - -D sint8_t=int8_t - -D sint32_t=int32_t - -D sint16_t=int16_t - -D memcpy_P=memcpy - -D memcmp_P=memcmp - -lib_extra_dirs = - libesp32 - -lib_ignore = - cc1101 [scripts_defaults] extra_scripts = pio/strip-floats.py From e581e59e50c0fe5d601abe1b9cc0d12b91865c57 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 23:15:17 +0200 Subject: [PATCH 32/38] Update platformio_tasmota32.ini --- platformio_tasmota32.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index 0ddf8c692..feca8c849 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -31,3 +31,9 @@ build_flags = ${esp_defaults.build_flags} -D sint16_t=int16_t -D memcpy_P=memcpy -D memcmp_P=memcmp + +lib_extra_dirs = + libesp32 + +lib_ignore = + cc1101 From e940c28be99a1d7e1b309cdacc8829e3d57c2442 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 5 Sep 2020 23:22:51 +0200 Subject: [PATCH 33/38] Remove spaces --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 161c0686f..ecf7d41ab 100644 --- a/platformio.ini +++ b/platformio.ini @@ -77,7 +77,7 @@ upload_speed = 115200 upload_resetmethod = nodemcu upload_port = COM5 extra_scripts = ${scripts_defaults.extra_scripts} - + [scripts_defaults] extra_scripts = pio/strip-floats.py pio/name-firmware.py From 201bad3eb0744006886fa3407427008d6108da30 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 6 Sep 2020 18:41:39 +0200 Subject: [PATCH 34/38] Prep release 8.5 --- BUILDS.md | 10 +++++++++- RELEASENOTES.md | 28 ++++++++++++++++++---------- tasmota/CHANGELOG.md | 5 +++-- tasmota/support_features.ino | 8 ++++++-- tools/decode-status.py | 16 +++++++++++----- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/BUILDS.md b/BUILDS.md index 48c1ce19c..023c8ebec 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -10,6 +10,7 @@ | USE_MQTT_TLS_CA_CERT | - | - | - | - | - | - | - | | USE_MQTT_AWS_IOT | - | - | - | - | - | - | - | | USE_4K_RSA | - | - | - | - | - | - | - | +| USE_TELEGRAM | - | - | - | - | - | - | - | | USE_KNX | - | - | - | x | - | - | - | | USE_WEBSERVER | x | x | x | x | x | x | x | | USE_JAVASCRIPT_ES6 | - | - | - | - | - | - | - | @@ -69,7 +70,9 @@ | USE_DDSU666 | - | - | - | - | x | - | - | | USE_SOLAX_X1 | - | - | - | - | - | - | - | | USE_LE01MR | - | - | - | - | - | - | - | +| USE_BL0940 | - | x | x | x | x | - | - | | USE_TELEINFO | - | - | - | - | - | - | - | +| USE_IEM3000 | - | - | - | - | - | - | - | | | | | | | | | | | USE_ADC_VCC | x | x | - | - | - | x | - | | USE_COUNTER | - | - | x | x | x | - | x | @@ -126,6 +129,7 @@ | USE_VEML6075 | - | - | - | - | - | - | - | | USE_VEML7700 | - | - | - | - | - | - | - | | USE_MCP9808 | - | - | - | - | - | - | - | +| USE_HP303B | - | - | - | - | - | - | - | | | | | | | | | | | Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks | USE_SPI | - | - | - | - | - | - | x | @@ -143,8 +147,9 @@ | USE_GPS | - | - | - | - | - | - | - | | USE_HM10 | - | - | - | - | x | - | - | | USE_HRXL | - | - | - | - | x | - | - | -| USE_TASMOTA_SLAVE | - | - | - | - | - | - | - | +| USE_TASMOTA_CLIENT | - | - | - | - | - | - | - | | USE_OPENTHERM | - | - | - | - | - | - | - | +| USE_TCP_BRIDGE | - | - | - | - | - | - | - | zbbridge | | | | | | | | | | USE_NRF24 | - | - | - | - | - | - | - | | USE_MIBLE | - | - | - | - | - | - | - | @@ -157,6 +162,7 @@ | USE_IR_REMOTE_FULL | - | - | - | - | - | x | - | Enable ALL protocols | | | | | | | | | | USE_SR04 | - | - | - | - | x | - | - | +| USE_DYP | - | - | - | - | - | - | - | | USE_TM1638 | - | - | - | - | x | - | - | | USE_HX711 | - | - | - | - | x | - | - | | USE_TX2x_WIND_SENSOR | - | - | - | - | - | - | - | @@ -186,3 +192,5 @@ | USE_MI_ESP32 | - | - | - | - | - | - | - | - | | USE_WEBCAM | - | - | - | - | - | - | - | x | | USE_ETHERNET | - | - | - | - | - | - | - | - | +| USE_I2S_AUDIO | - | - | - | - | - | - | - | - | +| USE_TTGO_WATCH | - | - | - | - | - | - | - | - | diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 76c63cbca..3703517fc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -21,7 +21,7 @@ While fallback or downgrading is common practice it was never supported due to S ## Supported Core versions -This release will be supported from ESP8266/Arduino library Core version **2.7.2.1** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. +This release will be supported from ESP8266/Arduino library Core version **2.7.4.1** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. Support of Core versions before 2.7.1 has been removed. @@ -35,7 +35,7 @@ For initial configuration this release supports Webserver based **WifiManager** ## Provided Binary Downloads -The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.2.1**. +The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.1**. - **tasmota.bin** = The Tasmota version with most drivers. **RECOMMENDED RELEASE BINARY** - **tasmota-BG.bin** to **tasmota-TW.bin** = The Tasmota version in different languages. @@ -55,19 +55,27 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ### Version 8.4.0.3 -- Remove support for 1-step upgrade from versions before 6.6.0.11 to versions after 8.4.0.1 -- Change references from http://thehackbox.org to http://ota.tasmota.com -- Change White blend mode moved to using ``SetOption 105`` instead of ``RGBWWTable`` +- Remove support for direct upgrade from versions before 6.6.0.11 to versions after 8.4.0.1 +- Change references from http://thehackbox.org/tasmota/ to http://ota.tasmota.com/tasmota/ +- Change triple-mode TLS via configuration in a single firmware (TLS AWS IoT, Letsencrypt and No-TLS) +- Change White blend mode to using command ``SetOption 105`` instead of ``RGBWWTable`` - Fix ESP32 PWM range - Fix display power control (#9114) -- Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) - Add Zigbee better support for IKEA Motion Sensor +- Add command ``SetOption102 0/1`` to set Baud rate for Teleinfo communication (0 = 1200 or 1 = 9600) +- Add command ``SetOption103 0/1`` to set TLS mode when TLS is selected +- Add command ``SetOption104 1`` to disable all MQTT retained messages +- Add command ``SetOption106 1`` to create a virtual White ColorTemp for RGBW lights +- Add command ``SetOption107 0/1`` to select virtual White as (0) Warm or (1) Cold +- Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) - Add command ``SetOption109 1`` to force gen1 Alexa mode, for Echo Dot 2nd gen devices only - Add command ``Restart 2`` to halt system. Needs hardware reset or power cycle to restart (#9046) -- Add ESP32 Analog input support for GPIO32 to GPIO39 +- Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134) - Add Zigbee options to ``ZbSend`` ``Config`` and ``ReadCondig`` -- Add Zigbee web gui widget for Temp/Humidity/Pressure sensors +- Add Zigbee better support for IKEA Motion Sensor +- Add Zigbee web gui widget for Battery and Temp/Humidity/Pressure sensors - Add Zigbee web ui for power metering plugs -- Add better config corruption recovery (#9046) +- Add better configuration corruption recovery (#9046) - Add virtual CT for 4 channels lights, emulating a 5th channel - Add support for DYP ME007 ultrasonic distance sensor by Janusz Kostorz (#9113) -- Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134) +- Add ESP32 Analog input support for GPIO32 to GPIO39 +- Add experimental support for ESP32 TTGO Watch and I2S Audio by Gerhard Mutz diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 4f7b20031..e5967a9a1 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -2,15 +2,16 @@ ### 8.4.0.3 20200823 -- Change references from http://thehackbox.org to http://ota.tasmota.com +- Change references from http://thehackbox.org/tasmota/ to http://ota.tasmota.com/tasmota/ - Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134) - Add Zigbee web ui widget for Lights - Add ``SetOption109 1`` to force gen1 Alexa mode, for Echo Dot 2nd gen devices only - Add Zigbee web ui for power metering plugs +- Add experimental support for ESP32 TTGO Watch and I2S Audio by Gerhard Mutz ### 8.4.0.2 20200813 -- Remove support for 1-step upgrade from versions before 6.6.0.11 to versions after 8.4.0.1 +- Remove support for direct upgrade from versions before 6.6.0.11 to versions after 8.4.0.1 - Change White blend mode moved to using ``SetOption 105`` instead of ``RGBWWTable`` - Fix display power control (#9114) - Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) - Add better config corruption recovery (#9046) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 8707650c0..d7f8328d3 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -598,7 +598,9 @@ void GetFeatures(void) #ifdef USE_DYP feature6 |= 0x00400000; // xsns_76_dyp.ino #endif -// feature6 |= 0x00800000; +#ifdef USE_I2S_AUDIO + feature6 |= 0x00800000; // xdrv_42_i2s_audio.ino +#endif // feature6 |= 0x01000000; // feature6 |= 0x02000000; @@ -606,7 +608,9 @@ void GetFeatures(void) // feature6 |= 0x08000000; // feature6 |= 0x10000000; -// feature6 |= 0x20000000; +#if defined(ESP32) && defined(USE_TTGO_WATCH) + feature6 |= 0x20000000; // xdrv_83_esp32watch.ino +#endif #if defined(ESP32) && defined(USE_ETHERNET) feature6 |= 0x40000000; // xdrv_82_ethernet.ino #endif diff --git a/tools/decode-status.py b/tools/decode-status.py index 876c9eb91..26f7fe900 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -155,8 +155,14 @@ a_setoption = [[ "Enable zerocross dimmer on PWM DIMMER", "Remove ZbReceived form JSON message", "Add the source endpoint as suffix to attributes", - "","","","", - "","","","", + "Baud rate for Teleinfo communication (0 = 1200 or 1 = 9600)", + "TLS mode", + "Disable all MQTT retained messages", + "Enable White blend mode", + "Create a virtual White ColorTemp for RGBW lights", + "Select virtual White as (0) Warm or (1) Cold", + "Enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1)", + "Force gen1 Alexa mode", "","","","" ],[ "","","","", @@ -220,9 +226,9 @@ a_features = [[ "USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075", "USE_VEML7700","USE_MCP9808","USE_BL0940","USE_TELEGRAM", "USE_HP303B","USE_TCP_BRIDGE","USE_TELEINFO","USE_LMT01", - "USE_PROMETHEUS","USE_IEM3000","USE_DYP","", + "USE_PROMETHEUS","USE_IEM3000","USE_DYP","USE_I2S_AUDIO", "","","","", - "","","USE_ETHERNET","USE_WEBCAM" + "","USE_TTGO_WATCH","USE_ETHERNET","USE_WEBCAM" ],[ "","","","", "","","","", @@ -259,7 +265,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20200817 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20200906 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) From bac7c6210f04cf112f54c440226fe0f38987d8db Mon Sep 17 00:00:00 2001 From: Federico Leoni Date: Sun, 6 Sep 2020 14:37:27 -0300 Subject: [PATCH 35/38] Bugfix and Prep for new Discovery Correct wrong unsubscribe for HAss lwt, removed the limitation for `Scheme 0` because is not needed anymore. --- tasmota/xdrv_12_home_assistant.ino | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 957c9bb29..ef9d25be9 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -849,7 +849,7 @@ void HAssDiscovery(void) Settings.flag3.hass_tele_on_power = 1; // SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT - send tele/STATE message as stat/RESULT // the purpose of that is so that if HA is restarted, state in HA will be correct within one teleperiod otherwise state // will not be correct until the device state is changed this is why in the patterns for switch and light, we tell HA to trigger on STATE, not RESULT. - Settings.light_scheme = 0; // To just control color it needs to be Scheme 0 + //Settings.light_scheme = 0; // To just control color it needs to be Scheme 0 (on hold due to new light configuration) } if (Settings.flag.hass_discovery || (1 == hass_mode)) @@ -940,7 +940,7 @@ void HassLwtSubscribe(bool hasslwt) { char htopic[TOPSZ]; snprintf_P(htopic, sizeof(htopic), PSTR(HOME_ASSISTANT_LWT_TOPIC)); - if (hasslwt) { + if (hasslwt && Settings.flag.hass_discovery) { MqttSubscribe(htopic); } else { MqttUnsubscribe(htopic); } } @@ -984,9 +984,7 @@ bool Xdrv12(uint8_t function) hass_mode = 0; // Discovery only if Settings.flag.hass_discovery is set hass_init_step = 2; // Delayed discovery break; - // if (!Settings.flag.hass_discovery) { - // AddLog_P2(LOG_LEVEL_INFO, PSTR("MQT: homeassistant/49A3BC/Discovery = {\"dev\":{\"ids\":[\"49A3BC\"]},\"cmd_t\":\"cmnd/test1/\",\"Discovery\":0}")); - // } + case FUNC_MQTT_SUBSCRIBE: HassLwtSubscribe(hasslwt); break; From 8d49a4b037a974abea611a2cce03ba18a7f45a67 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 6 Sep 2020 20:51:20 +0200 Subject: [PATCH 36/38] Zigbee fixes --- tasmota/xdrv_23_zigbee_1_headers.ino | 17 ++++- tasmota/xdrv_23_zigbee_5_converters.ino | 62 +++++++++++++++++- tasmota/xdrv_23_zigbee_6_commands.ino | 85 ++++-------------------- tasmota/xdrv_23_zigbee_8_parsers.ino | 15 ++++- tasmota/xdrv_23_zigbee_9_serial.ino | 86 ++++++++++++------------- tasmota/xdrv_23_zigbee_A_impl.ino | 50 ++++++++++++-- 6 files changed, 187 insertions(+), 128 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_1_headers.ino b/tasmota/xdrv_23_zigbee_1_headers.ino index 046450927..bb7555757 100644 --- a/tasmota/xdrv_23_zigbee_1_headers.ino +++ b/tasmota/xdrv_23_zigbee_1_headers.ino @@ -21,7 +21,22 @@ // contains some definitions for functions used before their declarations -void ZigbeeZCLSend_Raw(uint16_t dtsAddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId); +class ZigbeeZCLSendMessage { +public: + uint16_t shortaddr; + uint16_t groupaddr; + uint16_t clusterId; + uint8_t endpoint; + uint8_t cmdId; + uint16_t manuf; + bool clusterSpecific; + bool needResponse; + uint8_t transacId; // ZCL transaction number + const uint8_t *msg; + size_t len; +}; + +void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl); // get the result as a string (const char*) and nullptr if there is no field or the string is empty const char * getCaseInsensitiveConstCharNull(const JsonObject &json, const char *needle) { diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 9c8d10cdf..1155a6f2e 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -1028,7 +1028,19 @@ void ZCLFrame::parseReportAttributes(Z_attribute_list& attr_list) { SBuffer buf(2); buf.add8(_cmd_id); buf.add8(0x00); // Status = OK - ZigbeeZCLSend_Raw(_srcaddr, 0x0000, 0x0000 /*cluster*/, _srcendpoint, ZCL_DEFAULT_RESPONSE, false /* not cluster specific */, _manuf_code, buf.getBuffer(), buf.len(), false /* noresponse */, _transact_seq); + + ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ + _srcaddr, + 0x0000, + _cluster_id, + _srcendpoint, + ZCL_DEFAULT_RESPONSE, + _manuf_code, + false /* not cluster specific */, + false /* noresponse */, + _transact_seq, /* zcl transaction id */ + buf.getBuffer(), buf.len() + })); } } @@ -1078,6 +1090,48 @@ void ZCLFrame::generateCallBacks(Z_attribute_list& attr_list) { } } + +// A command has been sent to a device this device, or to a group +// Set timers to read back values. +// If it's a device address, also set a timer for reachability test +void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint = 0) { + int32_t z_cat = -1; + uint32_t wait_ms = 0; + + switch (cluster) { + case 0x0006: + z_cat = Z_CAT_READ_0006; + wait_ms = 200; // wait 0.2 s + break; + case 0x0008: + z_cat = Z_CAT_READ_0008; + wait_ms = 1050; // wait 1.0 s + break; + case 0x0102: + z_cat = Z_CAT_READ_0102; + wait_ms = 10000; // wait 10.0 s + break; + case 0x0300: + z_cat = Z_CAT_READ_0300; + wait_ms = 1050; // wait 1.0 s + break; + default: + break; + } + if (z_cat >= 0) { + if ((BAD_SHORTADDR != shortaddr) && (0 == endpoint)) { + endpoint = zigbee_devices.findFirstEndpoint(shortaddr); + } + if ((BAD_SHORTADDR == shortaddr) || (endpoint)) { // send if group address or endpoint is known + zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, z_cat, 0 /* value */, &Z_ReadAttrCallback); + if (BAD_SHORTADDR != shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group + zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable); + } + + } + } +} + // ZCL_READ_ATTRIBUTES void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) { uint32_t i = 0; @@ -1248,7 +1302,11 @@ void ZCLFrame::parseResponse(void) { void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) { convertClusterSpecific(attr_list, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload); #ifndef USE_ZIGBEE_NO_READ_ATTRIBUTES // read attributes unless disabled - sendHueUpdate(_srcaddr, _groupaddr, _cluster_id, _cmd_id, _frame_control.b.direction); + if (!_frame_control.b.direction) { // only handle server->client (i.e. device->coordinator) + if (_wasbroadcast) { // only update for broadcast messages since we don't see unicast from device to device and we wouldn't know the target + sendHueUpdate(BAD_SHORTADDR, _groupaddr, _cluster_id); + } + } #endif } diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index c533eb8ed..a32f637c4 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -174,7 +174,19 @@ int32_t Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t clus if (groupaddr) { shortaddr = BAD_SHORTADDR; // if group address, don't send to device } - ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, ZCL_READ_ATTRIBUTES, false, 0, attrs, attrs_len, true /* we do want a response */, zigbee_devices.getNextSeqNumber(shortaddr)); + uint8_t seq = zigbee_devices.getNextSeqNumber(shortaddr); + ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ + shortaddr, + groupaddr, + cluster /*cluster*/, + endpoint, + ZCL_READ_ATTRIBUTES, + 0, /* manuf */ + false /* not cluster specific */, + true /* response */, + seq, /* zcl transaction id */ + attrs, attrs_len + })); } return 0; // Fix GCC 10.1 warning } @@ -188,31 +200,6 @@ int32_t Z_Unreachable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, return 0; // Fix GCC 10.1 warning } -// set a timer to read back the value in the future -void zigbeeSetCommandTimer(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint) { - uint32_t wait_ms = 0; - - switch (cluster) { - case 0x0006: // for On/Off - case 0x0009: // for Alamrs - wait_ms = 200; // wait 0.2 s - break; - case 0x0008: // for Dimmer - case 0x0300: // for Color - wait_ms = 1050; // wait 1.0 s - break; - case 0x0102: // for Shutters - wait_ms = 10000; // wait 10.0 s - break; - } - if (wait_ms) { - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, Z_CAT_NONE, 0 /* value */, &Z_ReadAttrCallback); - if (BAD_SHORTADDR != shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable); - } - } -} - // returns true if char is 'x', 'y' or 'z' inline bool isXYZ(char c) { return (c >= 'x') && (c <= 'z'); @@ -280,52 +267,6 @@ void parseXYZ(const char *model, const SBuffer &payload, struct Z_XYZ_Var *xyz) } } -// works on big endiand hex only -// Returns if found: -// - cluster number -// - command number or 0xFF if command is part of the variable part -// - the payload in the form of a HEX string with x/y/z variables -void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t cmd, bool direction) { - if (direction) { return; } // no need to update if server->client - - int32_t z_cat = -1; - uint32_t wait_ms = 0; - - switch (cluster) { - case 0x0006: - z_cat = Z_CAT_READ_0006; - wait_ms = 200; // wait 0.2 s - break; - case 0x0008: - z_cat = Z_CAT_READ_0008; - wait_ms = 1050; // wait 1.0 s - break; - case 0x0102: - z_cat = Z_CAT_READ_0102; - wait_ms = 10000; // wait 10.0 s - break; - case 0x0300: - z_cat = Z_CAT_READ_0300; - wait_ms = 1050; // wait 1.0 s - break; - default: - break; - } - if (z_cat >= 0) { - uint8_t endpoint = 0; - if (BAD_SHORTADDR != shortaddr) { - endpoint = zigbee_devices.findFirstEndpoint(shortaddr); - } - if ((BAD_SHORTADDR == shortaddr) || (endpoint)) { // send if group address or endpoint is known - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, z_cat, 0 /* value */, &Z_ReadAttrCallback); - if (BAD_SHORTADDR != shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable); - } - - } - } -} - // Parse a cluster specific command, and try to convert into human readable void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, uint8_t cmd, bool direction, uint16_t shortaddr, uint8_t srcendpoint, const SBuffer &payload) { diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 1f5d33a8f..d800eaf71 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -969,9 +969,18 @@ void Z_SendAFInfoRequest(uint16_t shortaddr) { uint8_t InfoReq[] = { 0x04, 0x00, 0x05, 0x00 }; - ZigbeeZCLSend_Raw(shortaddr, 0x0000 /*group*/, 0x0000 /*cluster*/, endpoint, ZCL_READ_ATTRIBUTES, - false /*clusterSpecific*/, 0x0000 /*manuf*/, - InfoReq, sizeof(InfoReq), true /*needResponse*/, transacid); + ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ + shortaddr, + 0x0000, /* group */ + 0x0000 /*cluster*/, + endpoint, + ZCL_READ_ATTRIBUTES, + 0x0000, /* manuf */ + false /* not cluster specific */, + true /* response */, + transacid, /* zcl transaction id */ + InfoReq, sizeof(InfoReq) + })); } diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index 3fdddfedb..f5056c58c 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -765,96 +765,96 @@ void CmndZbEZSPSend(void) // - transacId: 8-bits, transation id of message (should be incremented at each message), used both for Zigbee message number and ZCL message number // Returns: None // -void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, uint16_t manuf, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId) { +void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) { #ifdef USE_ZIGBEE_ZNP - SBuffer buf(32+len); + SBuffer buf(32+zcl.len); buf.add8(Z_SREQ | Z_AF); // 24 buf.add8(AF_DATA_REQUEST_EXT); // 02 - if (BAD_SHORTADDR == shortaddr) { // if no shortaddr we assume group address + if (BAD_SHORTADDR == zcl.shortaddr) { // if no shortaddr we assume group address buf.add8(Z_Addr_Group); // 01 - buf.add64(groupaddr); // group address, only 2 LSB, upper 6 MSB are discarded + buf.add64(zcl.groupaddr); // group address, only 2 LSB, upper 6 MSB are discarded buf.add8(0xFF); // dest endpoint is not used for group addresses } else { buf.add8(Z_Addr_ShortAddress); // 02 - buf.add64(shortaddr); // dest address, only 2 LSB, upper 6 MSB are discarded - buf.add8(endpoint); // dest endpoint + buf.add64(zcl.shortaddr); // dest address, only 2 LSB, upper 6 MSB are discarded + buf.add8(zcl.endpoint); // dest endpoint } buf.add16(0x0000); // dest Pan ID, 0x0000 = intra-pan buf.add8(0x01); // source endpoint - buf.add16(clusterId); - buf.add8(transacId); // transacId + buf.add16(zcl.clusterId); + buf.add8(zcl.transacId); // transacId buf.add8(0x30); // 30 options buf.add8(0x1E); // 1E radius - buf.add16(3 + len + (manuf ? 2 : 0)); - buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field - if (manuf) { - buf.add16(manuf); // add Manuf Id if not null + buf.add16(3 + zcl.len + (zcl.manuf ? 2 : 0)); + buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field + if (zcl.manuf) { + buf.add16(zcl.manuf); // add Manuf Id if not null } - buf.add8(transacId); // Transaction Sequence Number - buf.add8(cmdId); - if (len > 0) { - buf.addBuffer(msg, len); // add the payload + buf.add8(zcl.transacId); // Transaction Sequence Number + buf.add8(zcl.cmdId); + if (zcl.len > 0) { + buf.addBuffer(zcl.msg, zcl.len); // add the payload } ZigbeeZNPSend(buf.getBuffer(), buf.len()); #endif // USE_ZIGBEE_ZNP #ifdef USE_ZIGBEE_EZSP - SBuffer buf(32+len); + SBuffer buf(32+zcl.len); - if (BAD_SHORTADDR != shortaddr) { + if (BAD_SHORTADDR != zcl.shortaddr) { // send unicast message to an address buf.add16(EZSP_sendUnicast); // 3400 buf.add8(EMBER_OUTGOING_DIRECT); // 00 - buf.add16(shortaddr); // dest addr + buf.add16(zcl.shortaddr); // dest addr // ApsFrame buf.add16(Z_PROF_HA); // Home Automation profile - buf.add16(clusterId); // cluster + buf.add16(zcl.clusterId); // cluster buf.add8(0x01); // srcEp - buf.add8(endpoint); // dstEp + buf.add8(zcl.endpoint); // dstEp buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame - buf.add16(groupaddr); // groupId - buf.add8(transacId); + buf.add16(zcl.groupaddr); // groupId + buf.add8(zcl.transacId); // end of ApsFrame buf.add8(0x01); // tag TODO - buf.add8(3 + len + (manuf ? 2 : 0)); - buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field - if (manuf) { - buf.add16(manuf); // add Manuf Id if not null + buf.add8(3 + zcl.len + (zcl.manuf ? 2 : 0)); + buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field + if (zcl.manuf) { + buf.add16(zcl.manuf); // add Manuf Id if not null } - buf.add8(transacId); // Transaction Sequance Number - buf.add8(cmdId); - if (len > 0) { - buf.addBuffer(msg, len); // add the payload + buf.add8(zcl.transacId); // Transaction Sequance Number + buf.add8(zcl.cmdId); + if (zcl.len > 0) { + buf.addBuffer(zcl.msg, zcl.len); // add the payload } } else { // send broadcast group address, aka groupcast buf.add16(EZSP_sendMulticast); // 3800 // ApsFrame buf.add16(Z_PROF_HA); // Home Automation profile - buf.add16(clusterId); // cluster + buf.add16(zcl.clusterId); // cluster buf.add8(0x01); // srcEp - buf.add8(endpoint); // broadcast endpoint for groupcast + buf.add8(zcl.endpoint); // broadcast endpoint for groupcast buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame - buf.add16(groupaddr); // groupId - buf.add8(transacId); + buf.add16(zcl.groupaddr); // groupId + buf.add8(zcl.transacId); // end of ApsFrame buf.add8(0); // hops, 0x00 = EMBER_MAX_HOPS buf.add8(7); // nonMemberRadius, 7 = infinite buf.add8(0x01); // tag TODO - buf.add8(3 + len + (manuf ? 2 : 0)); - buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field - if (manuf) { - buf.add16(manuf); // add Manuf Id if not null + buf.add8(3 + zcl.len + (zcl.manuf ? 2 : 0)); + buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field + if (zcl.manuf) { + buf.add16(zcl.manuf); // add Manuf Id if not null } - buf.add8(transacId); // Transaction Sequance Number - buf.add8(cmdId); - if (len > 0) { - buf.addBuffer(msg, len); // add the payload + buf.add8(zcl.transacId); // Transaction Sequance Number + buf.add8(zcl.cmdId); + if (zcl.len > 0) { + buf.addBuffer(zcl.msg, zcl.len); // add the payload } } diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 4dd7e99ad..fff151af6 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -139,7 +139,6 @@ void CmndZbReset(void) { // High-level function // Send a command specified as an HEX string for the workload. // The target endpoint is computed if zero, i.e. sent to the first known endpoint of the device. -// If cluster-specific, a timer may be set calling `zigbeeSetCommandTimer()`, for ex to coalesce attributes or Aqara presence sensor // // Inputs: // - shortaddr: 16-bits short address, or 0x0000 if group address @@ -176,11 +175,24 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, } // everything is good, we can send the command - ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, cmd, clusterSpecific, manuf, buf.getBuffer(), buf.len(), true, zigbee_devices.getNextSeqNumber(shortaddr)); + + uint8_t seq = zigbee_devices.getNextSeqNumber(shortaddr); + ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ + shortaddr, + groupaddr, + cluster /*cluster*/, + endpoint, + cmd, + manuf, /* manuf */ + clusterSpecific /* not cluster specific */, + true /* response */, + seq, /* zcl transaction id */ + buf.getBuffer(), buf.len() + })); // now set the timer, if any, to read back the state later if (clusterSpecific) { #ifndef USE_ZIGBEE_NO_READ_ATTRIBUTES // read back attribute value unless it is disabled - zigbeeSetCommandTimer(shortaddr, groupaddr, cluster, endpoint); + sendHueUpdate(shortaddr, groupaddr, cluster, endpoint); #endif } } @@ -202,7 +214,7 @@ void ZbApplyMultiplier(double &val_d, int8_t multiplier) { // Parse "Report", "Write", "Response" or "Condig" attribute // Operation is one of: ZCL_REPORT_ATTRIBUTES (0x0A), ZCL_WRITE_ATTRIBUTES (0x02) or ZCL_READ_ATTRIBUTES_RESPONSE (0x01) -void ZbSendReportWrite(const JsonObject &val_pubwrite, uint16_t device, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint16_t manuf, uint32_t operation) { +void ZbSendReportWrite(const JsonObject &val_pubwrite, uint16_t device, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint16_t manuf, uint8_t operation) { SBuffer buf(200); // buffer to store the binary output of attibutes if (nullptr == XdrvMailbox.command) { @@ -376,7 +388,19 @@ void ZbSendReportWrite(const JsonObject &val_pubwrite, uint16_t device, uint16_t } // all good, send the packet - ZigbeeZCLSend_Raw(device, groupaddr, cluster, endpoint, operation, false /* not cluster specific */, manuf, buf.getBuffer(), buf.len(), false /* noresponse */, zigbee_devices.getNextSeqNumber(device)); + uint8_t seq = zigbee_devices.getNextSeqNumber(device); + ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ + device, + groupaddr, + cluster /*cluster*/, + endpoint, + operation, + manuf, /* manuf */ + false /* not cluster specific */, + false /* no response */, + seq, /* zcl transaction id */ + buf.getBuffer(), buf.len() + })); ResponseCmndDone(); } @@ -510,7 +534,7 @@ void ZbSendSend(const JsonVariant &val_cmd, uint16_t device, uint16_t groupaddr, // Parse the "Send" attribute and send the command -void ZbSendRead(const JsonVariant &val_attr, uint16_t device, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint16_t manuf, uint32_t operation) { +void ZbSendRead(const JsonVariant &val_attr, uint16_t device, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint16_t manuf, uint8_t operation) { // ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":5} // ZbSend {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Read":"0x0005"} // ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":[5,6,7,4]} @@ -602,7 +626,19 @@ void ZbSendRead(const JsonVariant &val_attr, uint16_t device, uint16_t groupaddr } if (attrs_len > 0) { - ZigbeeZCLSend_Raw(device, groupaddr, cluster, endpoint, operation, false, manuf, attrs, attrs_len, true /* we do want a response */, zigbee_devices.getNextSeqNumber(device)); + uint8_t seq = zigbee_devices.getNextSeqNumber(device); + ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ + device, + groupaddr, + cluster /*cluster*/, + endpoint, + operation, + manuf, /* manuf */ + false /* not cluster specific */, + true /* response */, + seq, /* zcl transaction id */ + attrs, attrs_len + })); ResponseCmndDone(); } else { ResponseCmndChar_P(PSTR("Missing parameters")); From 5176e3ab02ffab614e1fb1a52e55b06694ed1fe7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 7 Sep 2020 14:54:31 +0200 Subject: [PATCH 37/38] Bump version to 8.5.0.1 --- RELEASENOTES.md | 27 +-------------------------- tasmota/CHANGELOG.md | 14 ++++++++++++++ tasmota/tasmota_version.h | 2 +- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3703517fc..8c95d47b5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -53,29 +53,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.4.0.3 - -- Remove support for direct upgrade from versions before 6.6.0.11 to versions after 8.4.0.1 -- Change references from http://thehackbox.org/tasmota/ to http://ota.tasmota.com/tasmota/ -- Change triple-mode TLS via configuration in a single firmware (TLS AWS IoT, Letsencrypt and No-TLS) -- Change White blend mode to using command ``SetOption 105`` instead of ``RGBWWTable`` -- Fix ESP32 PWM range -- Fix display power control (#9114) -- Add command ``SetOption102 0/1`` to set Baud rate for Teleinfo communication (0 = 1200 or 1 = 9600) -- Add command ``SetOption103 0/1`` to set TLS mode when TLS is selected -- Add command ``SetOption104 1`` to disable all MQTT retained messages -- Add command ``SetOption106 1`` to create a virtual White ColorTemp for RGBW lights -- Add command ``SetOption107 0/1`` to select virtual White as (0) Warm or (1) Cold -- Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) -- Add command ``SetOption109 1`` to force gen1 Alexa mode, for Echo Dot 2nd gen devices only -- Add command ``Restart 2`` to halt system. Needs hardware reset or power cycle to restart (#9046) -- Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134) -- Add Zigbee options to ``ZbSend`` ``Config`` and ``ReadCondig`` -- Add Zigbee better support for IKEA Motion Sensor -- Add Zigbee web gui widget for Battery and Temp/Humidity/Pressure sensors -- Add Zigbee web ui for power metering plugs -- Add better configuration corruption recovery (#9046) -- Add virtual CT for 4 channels lights, emulating a 5th channel -- Add support for DYP ME007 ultrasonic distance sensor by Janusz Kostorz (#9113) -- Add ESP32 Analog input support for GPIO32 to GPIO39 -- Add experimental support for ESP32 TTGO Watch and I2S Audio by Gerhard Mutz +### Version 8.5.0.1 diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index e5967a9a1..0f5b4ec47 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,5 +1,15 @@ +## Released + ## Unreleased (development) +### 8.5.0.1 20200907 + +- New released + +### 8.5.0 20200907 + +- Release Hannah + ### 8.4.0.3 20200823 - Change references from http://thehackbox.org/tasmota/ to http://ota.tasmota.com/tasmota/ @@ -14,6 +24,10 @@ - Remove support for direct upgrade from versions before 6.6.0.11 to versions after 8.4.0.1 - Change White blend mode moved to using ``SetOption 105`` instead of ``RGBWWTable`` - Fix display power control (#9114) +- Add command ``SetOption103 0/1`` to set TLS mode when TLS is selected +- Add command ``SetOption104 1`` to disable all MQTT retained messages +- Add command ``SetOption106 1`` to create a virtual White ColorTemp for RGBW lights +- Add command ``SetOption107 0/1`` to select virtual White as (0) Warm or (1) Cold - Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) - Add better config corruption recovery (#9046) - Add virtual CT for 4 channels lights, emulating a 5th channel - Add support for DYP ME007 ultrasonic distance sensor by Janusz Kostorz (#9113) diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index ce7e073c2..3103534c2 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,7 +20,7 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x08040003; +const uint32_t VERSION = 0x08050001; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; From 654f9de322e89ee6743244adff0a50905dfd0d9e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 7 Sep 2020 17:16:23 +0200 Subject: [PATCH 38/38] espressif32@2.0.0 --- platformio_tasmota32.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index feca8c849..549f2e333 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -2,7 +2,7 @@ ; *** expect the unexpected. Some features not working!!! *** [common32] -platform = espressif32@1.12.4 +platform = espressif32@2.0.0 platform_packages = tool-esptoolpy@1.20800.0 board = esp32dev board_build.ldscript = esp32_out.ld