From b4aca5a3f341425bedcf1e1f2471972ad19b4953 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 2 Oct 2022 20:54:49 +0200 Subject: [PATCH 1/2] Zigbee friendly names per endpoint --- CHANGELOG.md | 1 + lib/default/Ext-printf/src/SBuffer.hpp | 6 + tasmota/include/i18n.h | 1 + tasmota/include/tasmota_globals.h | 3 +- tasmota/language/af_AF.h | 2 + tasmota/language/bg_BG.h | 2 + tasmota/language/ca_AD.h | 2 + tasmota/language/cs_CZ.h | 2 + tasmota/language/de_DE.h | 2 + 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/fy_NL.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/vi_VN.h | 2 + tasmota/language/zh_CN.h | 2 + tasmota/language/zh_TW.h | 2 + .../xdrv_23_zigbee_2_devices.ino | 120 ++++++++++++- .../xdrv_23_zigbee_2a_devices_impl.ino | 111 ++++++++++-- .../xdrv_23_zigbee_4a_nano_fs.ino | 5 +- .../xdrv_23_zigbee_4c_devices.ino | 167 +++++++++++++----- .../xdrv_23_zigbee_A_impl.ino | 68 ++++--- 36 files changed, 450 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4faf91562..f3cc815a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [12.1.1.3] ### Added - ESP32-S2 and ESP32-S3 touch input support +- Zigbee friendly names per endpoint ### Changed diff --git a/lib/default/Ext-printf/src/SBuffer.hpp b/lib/default/Ext-printf/src/SBuffer.hpp index 9c545add0..b336a1d7b 100644 --- a/lib/default/Ext-printf/src/SBuffer.hpp +++ b/lib/default/Ext-printf/src/SBuffer.hpp @@ -79,6 +79,12 @@ public: _buf->buf[offset] = data; } } + void set16(const size_t offset, const uint16_t data) { + if (offset + 1 < _buf->len) { + _buf->buf[offset] = data & 0xFF; + _buf->buf[offset+1] = (data >> 8) & 0xFF; + } + } size_t add8(const uint8_t data) { // append 8 bits value if (_buf->len < _buf->size) { // do we have room for 1 byte diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index c303d49b3..669e22e14 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -623,6 +623,7 @@ #define D_JSON_ZIGBEEZCL_RAW_RECEIVED "ZbZCLRawReceived" #define D_JSON_ZIGBEE_DEVICE "Device" #define D_JSON_ZIGBEE_NAME "Name" + #define D_JSON_ZIGBEE_NAMES "Names" #define D_JSON_ZIGBEE_CONFIRM "ZbConfirm" #define D_CMND_ZIGBEE_NAME "Name" #define D_CMND_ZIGBEE_MODELID "ModelId" diff --git a/tasmota/include/tasmota_globals.h b/tasmota/include/tasmota_globals.h index e0ff3de01..187209279 100644 --- a/tasmota/include/tasmota_globals.h +++ b/tasmota/include/tasmota_globals.h @@ -258,7 +258,8 @@ String EthernetMacAddress(void); #define TASM_FILE_DRIVER "/.drvset%03d" #define TASM_FILE_SENSOR "/.snsset%03d" #define TASM_FILE_TLSKEY "/tlskey" // TLS private key -#define TASM_FILE_ZIGBEE "/zb" // Zigbee devices information blob +#define TASM_FILE_ZIGBEE_LEGACY_V2 "/zb" // Zigbee devices information blob, legacy v2 +#define TASM_FILE_ZIGBEE "/zbv4" // Zigbee devices information blob, now v4 #define TASM_FILE_ZIGBEE_DATA "/zbdata" // Zigbee last known values of devices #define TASM_FILE_AUTOEXEC "/autoexec.bat" // Commands executed after restart #define TASM_FILE_CONFIG "/config.sys" // Settings executed after restart diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 72fe31896..d95a6784d 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "genereer ewekansige Zigbee-netwerksleutel" #define D_ZIGBEE_UNKNOWN_DEVICE "Onbekende toestel" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Onbekende kenmerk" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Ongeldige parameter" #define D_ZIGBEE_MISSING_PARAM "Ontbrekende parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Onbekende kenmerknaam (geïgnoreer): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Nie meer as een groep-ID per opdrag nie" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Verkeerde afbakening vir payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Onherkenbare zigbee-opdrag: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Slegs 1 opdrag toegelaat (%d)" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 949dbdb16..621c46c8d 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h index bbdb4eee1..d84d7cbfd 100644 --- a/tasmota/language/ca_AD.h +++ b/tasmota/language/ca_AD.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 71d42ddfc..0c36cc121 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index e9a9f6609..a612e393b 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "Erzeuge zufälligen Zigbee Netzwerkschlüssel" #define D_ZIGBEE_UNKNOWN_DEVICE "Unbekanntes Gerät" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unbekanntes Attribut" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Ungültiger Parameter" #define D_ZIGBEE_MISSING_PARAM "Fehlende Parameter" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unbekannter Attribut Name (ignoriert): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Nur eine Cluster id pro Kommando" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Falscher Delimeter für Payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unerkanntes Zigbee Kommando: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Nur 1 Kommando zulässig (%d)" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index de7e19335..bff351bb3 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 60b9e8942..dfadd7372 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index e9a5c46fe..cbf7e58e3 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "Generando una clave aleatoria de red Zigbee" #define D_ZIGBEE_UNKNOWN_DEVICE "Dispositivo desconocido" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Atributo desconocido" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Parámetro inválido" #define D_ZIGBEE_MISSING_PARAM "Parámetros faltantes" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Nombre de atributo desconocido (ignorado): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No mas de un id de cluster por comando" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Delimitador incorrecto para payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Comando zigbee no reconocido: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Solo un comando es permitido (%d)" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index b94af9891..b22d8203d 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "création d'une clé réseau ZigBee aléatoire" #define D_ZIGBEE_UNKNOWN_DEVICE "Module inconnu" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Attribut inconnu" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Paramètre invalide" #define D_ZIGBEE_MISSING_PARAM "Paramètres manquants" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Nom d'attribut inconnu (ignoré): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Pas plus d'un Id de Cluster par commande" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Mauvais délimiteur dans le contenu du message" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Commande ZigBee inconnue: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Une seule commande autorisée (%d)" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index fbe031e89..551d7107a 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generearjen willekeurige Zigbee netwurksleutel" #define D_ZIGBEE_UNKNOWN_DEVICE "Unbekend apparaat" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unbekend attribút" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unbekende attribútenamme (negeare): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Net mear dan ien kluster-id per kommando" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Ferkearde skiedingsteken foar lading" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unerkend zigbee kommando: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Allinich 1 kommando tastien (%d)" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 6c5cbb225..445224746 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index d31d0957d..9b4a1af86 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "véletlen Zigbee hálózati kulcs generálása" #define D_ZIGBEE_UNKNOWN_DEVICE "Ismeretlen eszköz" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Ismeretlen tulajdonság" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Érvénytelen paraméter" #define D_ZIGBEE_MISSING_PARAM "Hiányzó paraméter(ek)" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Ismeretlen tulajdonság név (kihagyva): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Egynél több klaszter id nem lehet parancsonként" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Hibás adatcsomag elválasztó" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Nem értelmezhető Zigbee parancs: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Csak egy parancs engedélyezett (%d)" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index ba49afae4..e63008ea1 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "Generazione chiave casuale rete Zigbee" #define D_ZIGBEE_UNKNOWN_DEVICE "Dispositivo sconosciuto" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Attributo sconosciuto" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Parametro non valido" #define D_ZIGBEE_MISSING_PARAM "Parametro mancante" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Nome sconosciuto attributo (ignorato): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Non più di un ID cluster per comando" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Delimitatore errato carico utile" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Comando Zigbee non riconosciuto: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "È consentito solo 1 comando (%d)" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 92400dfe5..c6db32664 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 729aa5e0e..ccb5eaca6 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "willekeurig Zigbee netwerk sleutel maken" #define D_ZIGBEE_UNKNOWN_DEVICE "Onbekend apparaat" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Onbekende attribuut" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Ongeldige parameter" #define D_ZIGBEE_MISSING_PARAM "Ontbrekende parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Onbekend attribuut naam: %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Max een cluster id per opdracht" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Fout scheidingsteken voor payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Onbekende zigbee opdracht: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Maar een opdracht toegestaan (%d)" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index fa9c391c2..8f33f9b84 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generuj losowo klucz sieci Zigbee" #define D_ZIGBEE_UNKNOWN_DEVICE "Nieznane urządzenie" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Nieznany atrybut" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Zły parametr" #define D_ZIGBEE_MISSING_PARAM "Brak parametrów" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Nieznana nazwa atrybutu (ignoruję): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Nie więcej niż jeden cluster id na komendę" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Błędny delimiter autoryzacji" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Nieznana komenda zigbee: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Tylko 1 komenda dozwolona (%d)" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index b845055a4..62a23856c 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "Gerando chave randomizada de rede Zigbee" // "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Dispositivo desconhecido" // "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Atributo desconhecido" // "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Parametro inválido" // "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Parametros faltantes" // "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Nome desconhecido atribuido (ignorado) %s" // "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Usar somente um Cluster ID por comando" // "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Delimitador incorreto para a carga" // "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Comando Zigbee não reconhecido: %s" // "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Somente 1 comando permitido (%d)" // "Only 1 command allowed (%d)" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index a473a6b7f..9eabdd14a 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "A gerar chave aleatória de rede Zigbee" #define D_ZIGBEE_UNKNOWN_DEVICE "dispositivo desconhecido" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Atributo desconhecido" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Parâmetro inválido" #define D_ZIGBEE_MISSING_PARAM "Parâmetros em falta" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Atributo de nome desconhecido (ignorado): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Apenas um cluster id por comando" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Delimitador de payload inválido" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Comando zigbee desconhecido: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Permitido apenas 1 comando (%d)" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 93f2381b1..f6aeb9e07 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 81e66fa2c..ff21ba5ba 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index f1a60f325..fbfcfe8fd 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index fa52fe7fe..6895bc7ec 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 90337d4cb..da884d474 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 8258e3a0a..1b84e2d37 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 3422ab65d..4a3eb2f24 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index c06627648..980b08f0e 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "正在生成 Zigbee 网络随机秘钥" #define D_ZIGBEE_UNKNOWN_DEVICE "未知设备" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "未知属性" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "参数无效" #define D_ZIGBEE_MISSING_PARAM "缺失参数" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "未知属性名称: %s , 忽略" #define D_ZIGBEE_TOO_MANY_CLUSTERS "每个命令不应有多个簇 ID" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "消息体分隔符错误" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "无法识别的 Zigbee 命令: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "只允许一个命令 (%d)" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 00b247f74..a7aa434ff 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -495,10 +495,12 @@ #define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" #define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" #define D_ZIGBEE_INVALID_PARAM "Invalid parameter" #define D_ZIGBEE_MISSING_PARAM "Missing parameters" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" #define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2_devices.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2_devices.ino index ea886130f..1bc7d04df 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2_devices.ino @@ -815,6 +815,114 @@ const Z_Data & Z_Data_Set::find(Z_Data_Type type, uint8_t ep) const { return z_data_unk; // mark as unknown } +/*********************************************************************************************\ + * Class used to store friendly names of endpoints +\*********************************************************************************************/ +class Z_EP_Name { +public: + Z_EP_Name() : + endpoint(0), + name(nullptr) + {} + + inline const char * getName(void) const { return name != nullptr ? name : PSTR(""); } + void setName(const char *new_name); + + ~Z_EP_Name() { if (name) free(name); } + +public: + uint8_t endpoint; + char * name; +}; + + +class Z_EP_Name_list : public LList { +public: + + // INVARIANT: there is at most one entry for any `endpoint` value + // INVARIANT: if an entry exists, then the name is not null nor empty string + + // we don't need explicit constructor, the superclass handles it + + // add or change an ep name, or remove if set to empty string + void setEPName(uint8_t ep, const char * name) { + if (name == nullptr || strlen_P(name) == 0) { + this->removeEPName(ep); + return; + } + for (auto & epn : *this) { + if (epn.endpoint == ep) { + epn.setName(name); + return; // found it, exit + } + } + // ep not found, create it + Z_EP_Name & epn = this->addToLast(); + epn.endpoint = ep; + epn.setName(name); + } + + // remove ep name from list + void removeEPName(uint8_t ep) { + for (auto & epn : *this) { + if (epn.endpoint == ep) { + this->remove(&epn); + return; // found it, exit + } + } + + } + + // find a endpoint by name, or return 0 if not found + uint8_t findEPName(const char * name) const { + if (name == nullptr || strlen_P(name) == 0) { return 0; } + for (const auto & epn : *this) { + if (strcasecmp(epn.name, name) == 0) { return epn.endpoint; } + } + return 0; // not found + } + + // get ep name, or return nullptr if none + const char * getEPName(uint8_t ep) const { + for (auto & epn : *this) { + if (epn.endpoint == ep) { + return epn.name; + } + } + return nullptr; + } + + // Publish endpoint names if any as `"Names":{"2":"name2","3":"name3"}` + String tojson(void) const { + String s; + if (!this->isEmpty()) { + s += '{'; + bool first = true; + for (const auto & epn : *this) { + if (!first) { s += ','; } + s += '"'; + s += epn.endpoint; + s += F("\":\""); + s += EscapeJSONString(epn.name); + s += '"'; + first = false; + } + s += '}'; + } + return s; + } + + // append to JSON + void ResponseAppend(void) const { + String s = tojson(); + if (s.length() > 0) { + ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAMES "\":%s"), s.c_str()); + } + } +}; + + + /*********************************************************************************************\ * Structures for Rules variables related to the last received message \*********************************************************************************************/ @@ -832,6 +940,8 @@ public: uint32_t defer_last_message_sent; uint8_t endpoints[endpoints_max]; // static array to limit memory consumption, list of endpoints until 0x00 or end of array + // List of names for endpoints + Z_EP_Name_list ep_names; // Used for attribute reporting Z_attribute_list attr_list; // sequence number for Zigbee frames @@ -927,15 +1037,18 @@ public: bool addEndpoint(uint8_t endpoint); void clearEndpoints(void); uint32_t countEndpoints(void) const; // return the number of known endpoints (0 if unknown) + bool setEPName(uint8_t ep, const char * name); void setManufId(const char * str); void setModelId(const char * str); void setFriendlyName(const char * str); + void setFriendlyEPName(uint8_t ep, const char * str); // ability to have friendly names for endpoints void setLastSeenNow(void); // multiple function to dump part of the Device state into JSON void jsonAddDeviceNamme(Z_attribute_list & attr_list) const; + void jsonAddEPName(Z_attribute_list & attr_list) const; void jsonAddIEEE(Z_attribute_list & attr_list) const; void jsonAddModelManuf(Z_attribute_list & attr_list) const; void jsonAddEndpoints(Z_attribute_list & attr_list) const; @@ -964,8 +1077,6 @@ public: void setLightChannels(int8_t channels); -protected: - static void setStringAttribute(char*& attr, const char * str); }; @@ -1032,7 +1143,7 @@ public: // - 0x = the device's short address Z_Device & isKnownLongAddrDevice(uint64_t longaddr) const; Z_Device & isKnownIndexDevice(uint32_t index) const; - Z_Device & isKnownFriendlyNameDevice(const char * name) const; + Z_Device & isKnownFriendlyNameDevice(const char * name, uint8_t * ep = nullptr) const; Z_Device & findShortAddr(uint16_t shortaddr); const Z_Device & findShortAddr(uint16_t shortaddr) const; @@ -1044,6 +1155,7 @@ public: inline bool foundDevice(const Z_Device & device) const { return device.valid(); } int32_t findFriendlyName(const char * name) const; + int32_t findFriendlyNameOrEPName(const char * name, uint8_t * ep) const; uint64_t getDeviceLongAddr(uint16_t shortaddr) const; uint8_t findFirstEndpoint(uint16_t shortaddr) const; @@ -1110,7 +1222,7 @@ public: void clean(void); // avoid writing to flash the last changes // Find device by name, can be short_addr, long_addr, number_in_array or name - Z_Device & parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr = nullptr, int32_t mailbox_payload = 0); + Z_Device & parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr = nullptr, uint8_t * ep = nullptr, int32_t mailbox_payload = 0); bool isTuyaProtocol(uint16_t shortaddr, uint8_t ep = 0) const; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2a_devices_impl.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2a_devices_impl.ino index 27a627b28..4489b8a63 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2a_devices_impl.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_2a_devices_impl.ino @@ -118,6 +118,37 @@ int32_t Z_Devices::findFriendlyName(const char * name) const { return -1; } +// +// Scan all devices to find a corresponding friendlyNme +// Looks info device.friendlyName entry or the name of an endpoint +// In: +// friendlyName (null terminated, should not be empty) +// Out: +// index in _devices of entry, -1 if not found +// ep == 0 means ep not found +// +int32_t Z_Devices::findFriendlyNameOrEPName(const char * name, uint8_t * ep) const { + if (ep) { *ep = 0; } + if (!name) { return -1; } // if pointer is null + size_t name_len = strlen(name); + int32_t found = 0; + if (name_len) { + for (auto &elem : _devices) { + if (elem.friendlyName) { + if (strcasecmp(elem.friendlyName, name) == 0) { return found; } + } + uint8_t ep_found = elem.ep_names.findEPName(name); + if (ep_found) { + // found via ep name + if (ep) { *ep = ep_found; } // update ep + return found; + } + found++; + } + } + return -1; +} + Z_Device & Z_Devices::isKnownLongAddrDevice(uint64_t longaddr) const { return (Z_Device &) findLongAddr(longaddr); } @@ -130,10 +161,12 @@ Z_Device & Z_Devices::isKnownIndexDevice(uint32_t index) const { } } -Z_Device & Z_Devices::isKnownFriendlyNameDevice(const char * name) const { +Z_Device & Z_Devices::isKnownFriendlyNameDevice(const char * name, uint8_t * ep) const { if ((!name) || (0 == strlen(name))) { return device_unk; } // Error - int32_t found = findFriendlyName(name); + uint8_t ep_found; + int32_t found = findFriendlyNameOrEPName(name, &ep_found); if (found >= 0) { + if (ep) { *ep = ep_found; } return devicesAt(found); } else { return device_unk; @@ -242,7 +275,7 @@ void Z_Device::clearEndpoints(void) { // return true if a change was made // bool Z_Device::addEndpoint(uint8_t endpoint) { - if ((0x00 == endpoint) || (endpoint > 240)) { return false; } + if ((0x00 == endpoint) || (endpoint > 240 && endpoint != 0xF2)) { return false; } for (uint32_t i = 0; i < endpoints_max; i++) { if (endpoint == endpoints[i]) { @@ -276,8 +309,21 @@ uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const { return findShortAddr(shortaddr).endpoints[0]; // returns 0x00 if no endpoint } +// set a name to an endpoint, must exist in the list or return `false` +bool Z_Device::setEPName(uint8_t ep, const char * name) { + if ((0x00 == ep) || (ep > 240 && ep != 0xF2)) { return false; } + + for (uint32_t i = 0; i < endpoints_max; i++) { + if (ep == endpoints[i]) { + ep_names.setEPName(ep, name); + return true; + } + } + return false; +} + void Z_Device::setStringAttribute(char*& attr, const char * str) { - if (nullptr == str) { return; } // ignore a null parameter + if (nullptr == str) { str = PSTR(""); } // nullptr is considered empty string size_t str_len = strlen(str); if ((nullptr == attr) && (0 == str_len)) { return; } // if both empty, don't do anything @@ -320,6 +366,15 @@ void Z_Device::setFriendlyName(const char * str) { setStringAttribute(friendlyName, str); } +void Z_Device::setFriendlyEPName(uint8_t ep, const char * str) { + ep_names.setEPName(ep, str); +} + +// needs to push the implementation here to use Z_Device static method +void Z_EP_Name::setName(const char *new_name) { + Z_Device::setStringAttribute(name, new_name); +} + void Z_Device::setLastSeenNow(void) { // Only update time if after 2020-01-01 0000. // Fixes issue where zigbee device pings before WiFi/NTP has set utc_time @@ -523,7 +578,13 @@ void Z_Devices::jsonAppend(uint16_t shortaddr, const Z_attribute_list &attr_list // internal function to publish device information with respect to all `SetOption`s // void Z_Device::jsonPublishAttrList(const char * json_prefix, const Z_attribute_list &attr_list, bool include_time) const { - bool use_fname = (Settings->flag4.zigbee_use_names) && (friendlyName); // should we replace shortaddr with friendlyname? + const char * local_friendfly_name; // friendlyname publish can depend on the source endpoint + local_friendfly_name = ep_names.getEPName(attr_list.src_ep); // check if this ep has a specific name + if (local_friendfly_name == nullptr) { + // if no ep-specific name, get the device name + local_friendfly_name = friendlyName; + } + bool use_fname = (Settings->flag4.zigbee_use_names) && (local_friendfly_name); // should we replace shortaddr with friendlyname? ResponseClear(); // clear string @@ -541,7 +602,7 @@ void Z_Device::jsonPublishAttrList(const char * json_prefix, const Z_attribute_l // What key do we use, shortaddr or name? if (!Settings->flag5.zb_omit_json_addr) { if (use_fname) { - ResponseAppend_P(PSTR("{\"%s\":"), friendlyName); + ResponseAppend_P(PSTR("{\"%s\":"), local_friendfly_name); } else { ResponseAppend_P(PSTR("{\"0x%04X\":"), shortaddr); } @@ -551,8 +612,8 @@ void Z_Device::jsonPublishAttrList(const char * json_prefix, const Z_attribute_l // Add "Device":"0x...." ResponseAppend_P(PSTR("\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\","), shortaddr); // Add "Name":"xxx" if name is present - if (friendlyName) { - ResponseAppend_P(PSTR("\"" D_JSON_ZIGBEE_NAME "\":\"%s\","), EscapeJSONString(friendlyName).c_str()); + if (local_friendfly_name) { + ResponseAppend_P(PSTR("\"" D_JSON_ZIGBEE_NAME "\":\"%s\","), EscapeJSONString(local_friendfly_name).c_str()); } // Add all other attributes ResponseAppend_P(PSTR("%s}"), attr_list.toString(false).c_str()); @@ -571,10 +632,10 @@ void Z_Device::jsonPublishAttrList(const char * json_prefix, const Z_attribute_l if (Settings->flag4.zigbee_distinct_topics) { char subtopic[TOPSZ]; - if (Settings->flag4.zb_topic_fname && friendlyName && strlen(friendlyName)) { + if (Settings->flag4.zb_topic_fname && local_friendfly_name && strlen(local_friendfly_name)) { // Clean special characters char stemp[TOPSZ]; - strlcpy(stemp, friendlyName, sizeof(stemp)); + strlcpy(stemp, local_friendfly_name, sizeof(stemp)); MakeValidMqtt(0, stemp); if (Settings->flag5.zigbee_hide_bridge_topic) { snprintf_P(subtopic, sizeof(subtopic), PSTR("%s"), stemp); @@ -646,7 +707,8 @@ void Z_Devices::clean(void) { // - a friendly name, between quotes, example: "Room_Temp" // // In case the device is not found, the parsed 0x.... short address is passed to *parsed_shortaddr -Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr, int32_t mailbox_payload) { +Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr, uint8_t * ep, int32_t mailbox_payload) { + if (ep) { *ep = 0; } // mark as not found if (nullptr == param) { return device_unk; } size_t param_len = strlen(param); char dataBuf[param_len + 1]; @@ -675,7 +737,7 @@ Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_ } } else { // expect a Friendly Name - return isKnownFriendlyNameDevice(dataBuf); + return isKnownFriendlyNameDevice(dataBuf, ep); } } @@ -696,6 +758,14 @@ void Z_Device::jsonAddDeviceNamme(Z_attribute_list & attr_list) const { } } +// Add "Names":{"1":"name1","2":"name2"} +void Z_Device::jsonAddEPName(Z_attribute_list & attr_list) const { + String s = ep_names.tojson(); + if (s.length() > 0) { + attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_NAMES)).setStrRaw(s.c_str()); + } +} + // Add "IEEEAddr":"0x1234567812345678" void Z_Device::jsonAddIEEE(Z_attribute_list & attr_list) const { attr_list.addAttributePMEM(PSTR("IEEEAddr")).setHex64(longaddr); @@ -795,6 +865,7 @@ void Z_Device::jsonDumpSingleDevice(Z_attribute_list & attr_list, uint32_t dump_ jsonAddDeviceNamme(attr_list); } if (dump_mode >= 2) { + jsonAddEPName(attr_list); jsonAddIEEE(attr_list); jsonAddModelManuf(attr_list); jsonAddEndpoints(attr_list); @@ -889,6 +960,22 @@ int32_t Z_Devices::deviceRestore(JsonParserObject json) { } } + // read "Names" + JsonParserToken val_names = json[PSTR("Names")]; + if (val_names.isObject()) { + JsonParserObject attr_names = val_names.getObject(); + // iterate on keys + for (auto key : attr_names) { + int32_t ep = key.getUInt(); + if (ep > 255) { ep = 0; } // ep == 0 is invalid + const char * ep_name = key.getValue().getStr(); + if (!ep || !device.setEPName(ep, ep_name)) { + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ignoring ep=%i name='%s'"), ep, ep_name); + } + } + } + + // read "Config" JsonParserToken val_config = json[PSTR("Config")]; if (val_config.isArray()) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4a_nano_fs.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4a_nano_fs.ino index 6d2a64fc8..eb8e16969 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4a_nano_fs.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4a_nano_fs.ino @@ -22,8 +22,9 @@ // #define Z_EEPROM_DEBUG -const static uint32_t ZIGB_NAME1 = 0x3167697A; // 'zig1' little endian +// const static uint32_t ZIGB_NAME1 = 0x3167697A; // 'zig1' little endian const static uint32_t ZIGB_NAME2 = 0x3267697A; // 'zig2' little endian, v2 +const static uint32_t ZIGB_NAME4 = 0x3467697A; // 'zig4' little endian, v2 const static uint32_t ZIGB_DATA2 = 0x32746164; // 'dat2' little endian, v2 extern FS *dfsp; extern "C" uint32_t _FS_end; @@ -32,7 +33,7 @@ bool flash_valid(void) { return (((uint32_t)&_FS_end) > 0x40280000) && (((uint32_t)&_FS_end) < 0x402FF000); } -void hydrateSingleDevice(const SBuffer & buf_d); +void hydrateSingleDevice(const SBuffer & buf_d, uint32_t version); #ifdef USE_ZIGBEE_EEPROM // The EEPROM is 64KB in size with individually writable bytes. diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino index 70bfc53c4..9b0d76cca 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino @@ -77,6 +77,32 @@ // uint8[] - list of configuration bytes, 0xFF marks the end // i.e. 0xFF-0xFF marks the end of the array of endpoints // +// ======================= +// v4 which provides more extensibility +// File structure: (all values are little Endian) +// +// uint8 - number of devices, 0xFF indicates invalid file (or erased Flash?) +// [Array of devices, max to number of devices] +// [starts at offset = 3] +// uint16 - length of the device record, including the length field - allows to jump to next device + +// [mandatory device data] +// uint16 - short address +// uint64 - long IEEE address +// +// str - ModelID (null terminated C string, 32 chars max) +// str - Manuf (null terminated C string, 32 chars max) +// str - FriendlyName (null terminated C string, 32 chars max) +// +// [Array of endpoints] +// uint8 - endpoint number, 0xFF marks the end of endpoints +// uint8 - length of the endpoint information, excuding length byte and endpoint number +// uint8[] - list of configuration bytes, 0xFF marks the end +// str - (optional) FriendlyName for this endpoint (null terminated C string, 32 chars max), 0x00 if none +// +// [extended attributes] +// : any other data until `length of the device record` is reached +// // Memory footprint @@ -139,9 +165,9 @@ bool hibernateDeviceConfiguration(SBuffer & buf, const class Z_Data_Set & data, * Only supports v2 (not the legacy old one long forgotten) \*********************************************************************************************/ SBuffer hibernateDevice(const struct Z_Device &device) { - SBuffer buf(128); + SBuffer buf(256); - buf.add8(0x00); // overall length, will be updated later + buf.add16(0x0000); // overall length, will be updated later buf.add16(device.shortaddr); buf.add64(device.longaddr); @@ -159,18 +185,36 @@ SBuffer hibernateDevice(const struct Z_Device &device) { // check if we need to write fake endpoint 0x00 buf.add8(0x00); + uint32_t ep0_len_offset = buf.len(); // mark where to update the ep data length + buf.add8(0x00); if (hibernateDeviceConfiguration(buf, device.data, 0)) { buf.add8(0xFF); // end of configuration + buf.add8(0x00); // empty ep friendly name, as it would duplicate the global friendly name + // update the lenght of ep0_data_lenth + buf.set8(ep0_len_offset, buf.len() - ep0_len_offset - 1); } else { - buf.setLen(buf.len()-1); // remove 1 byte header + buf.setLen(buf.len()-2); // remove 2 bytes header } // scan endpoints for (uint32_t i=0; i 32) { len = 32; } // max 32 chars + buf.addBuffer(ep_name, len); + buf.add8(0x00); // end of string marker + } else { + buf.add8(0x00); // no endpoint name + } + // update the lenght of ep0_data_lenth + buf.set8(ep_len_offset, buf.len() - ep_len_offset - 1); } buf.add8(0xFF); // end of endpoints @@ -184,6 +228,8 @@ SBuffer hibernateDevice(const struct Z_Device &device) { /*********************************************************************************************\ * Write Devices in EEPROM/File/Flash * + * Updated to v4 format + * * Writes the preamble and all devices in the Univ_Write_File structure. * Does not close the file at the end. * Returns true if succesful. @@ -193,9 +239,10 @@ SBuffer hibernateDevice(const struct Z_Device &device) { bool hibernateDevices(Univ_Write_File & write_data); bool hibernateDevices(Univ_Write_File & write_data) { // first prefix is number of devices - uint8_t devices_size = zigbee_devices.devicesSize(); + size_t devices_size = zigbee_devices.devicesSize(); if (devices_size > 250) { devices_size = 250; } // arbitrarily limit to 250 devices in EEPROM instead of 32 in Flash - write_data.writeBytes(&devices_size, sizeof(devices_size)); + uint8_t devices_size8 = devices_size; + write_data.writeBytes((uint8_t*)&devices_size8, sizeof(devices_size8)); // write number of devices in file for (const auto & device : zigbee_devices.getDevices()) { const SBuffer buf = hibernateDevice(device); @@ -224,10 +271,10 @@ const char * hydrateSingleString(const SBuffer & buf, uint32_t *d) { * hydrateSingleDevice * * Transforms a binary representation to a Zigbee device - * Supports only v2 + * Supports only v2 and v4 \*********************************************************************************************/ -void hydrateSingleDevice(const SBuffer & buf_d) { - uint32_t d = 1; // index in device buffer +void hydrateSingleDevice(const SBuffer & buf_d, uint32_t version) { + uint32_t d = 0; // index in device buffer uint16_t shortaddr = buf_d.get16(d); d += 2; uint64_t longaddr = buf_d.get64(d); d += 8; size_t buf_len = buf_d.len(); @@ -244,23 +291,52 @@ void hydrateSingleDevice(const SBuffer & buf_d) { if (d >= buf_len) { return; } - // Hue bulbtype - if present - while (d < buf_len) { + // Read per-endpoint information + while (d < buf_len) { uint8_t ep = buf_d.get8(d++); if (0xFF == ep) { break; } // ep 0xFF marks the end of the endpoints - if (ep > 240) { ep = 0xFF; } // ep == 0xFF means ignore + if (ep > 240 && ep != 0xF2) { ep = 0xFF; } // ep == 0xFF means ignore device.addEndpoint(ep); // it will ignore invalid endpoints - while (d < buf_len) { - uint8_t config_type = buf_d.get8(d++); - if (0xFF == config_type) { break; } // 0xFF marks the end of congiguration - uint8_t config = config_type & 0x0F; - Z_Data_Type type = (Z_Data_Type) (config_type >> 4); - // set the configuration - if (ep != 0xFF) { - Z_Data & z_data = device.data.getByType(type, ep); - if (&z_data != nullptr) { - z_data.setConfig(config); - Z_Data_Set::updateData(z_data); + + if (version == 4) { + if (d >= buf_len) { break; } // end of buffer + uint8_t ep_len = buf_d.get8(d++); + if (d + ep_len > buf_len) { break; } // buffer is too small to contain the announced data + + while (d < buf_len) { + uint8_t config_type = buf_d.get8(d++); + if (0xFF == config_type) { break; } // 0xFF marks the end of congiguration + uint8_t config = config_type & 0x0F; + Z_Data_Type type = (Z_Data_Type) (config_type >> 4); + // set the configuration + if (ep != 0xFF) { + Z_Data & z_data = device.data.getByType(type, ep); + if (&z_data != nullptr) { + z_data.setConfig(config); + Z_Data_Set::updateData(z_data); + } + } + } + // ability to have additional fields here + // friendly name for ep + if (d < buf_len) { + device.setFriendlyEPName(ep, hydrateSingleString(buf_d, &d)); + } + // additional information comes here + } else { + // version == 2 + while (d < buf_len) { + uint8_t config_type = buf_d.get8(d++); + if (0xFF == config_type) { break; } // 0xFF marks the end of congiguration + uint8_t config = config_type & 0x0F; + Z_Data_Type type = (Z_Data_Type) (config_type >> 4); + // set the configuration + if (ep != 0xFF) { + Z_Data & z_data = device.data.getByType(type, ep); + if (&z_data != nullptr) { + z_data.setConfig(config); + Z_Data_Set::updateData(z_data); + } } } } @@ -277,11 +353,18 @@ void hydrateSingleDevice(const SBuffer & buf_d) { bool loadZigbeeDevices(void) { Univ_Read_File f; // universal reader const char * storage_class = PSTR(""); + uint32_t file_version = 4; // currently supporting v3 and v4 #ifdef USE_ZIGBEE_EEPROM if (zigbee.eeprom_ready) { - f.init(ZIGB_NAME2); - storage_class = PSTR("EEPROM"); + f.init(ZIGB_NAME4); // try v4 first + if (!f.valid) { + f.init(ZIGB_NAME2); // else try v2 + if (f.valid) { file_version = 2; } // v2 found + } + if (f.valid) { + storage_class = PSTR("EEPROM"); + } } #endif // USE_ZIGBEE_EEPROM @@ -289,15 +372,11 @@ bool loadZigbeeDevices(void) { File file; if (!f.valid() && dfsp) { file = dfsp->open(TASM_FILE_ZIGBEE, "r"); + if (!file) { + file = dfsp->open(TASM_FILE_ZIGBEE_LEGACY_V2, "r"); + if (file) { file_version = 2; } // v2 found + } if (file) { - uint32_t signature = 0x0000; - file.read((uint8_t*)&signature, 4); - if (signature == ZIGB_NAME2) { - // skip another 4 bytes - file.read((uint8_t*)&signature, 4); - } else { - file.seek(0); // seek back to beginning of file - } f.init(&file); storage_class = PSTR("File System"); } @@ -314,10 +393,10 @@ bool loadZigbeeDevices(void) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Zigbee signature in Flash: %08X - %d"), flashdata.name, flashdata.len); // Check the signature - if ( ((flashdata.name == ZIGB_NAME1) || (flashdata.name == ZIGB_NAME2)) + if ( ((flashdata.name == ZIGB_NAME2) || (flashdata.name == ZIGB_NAME4)) && (flashdata.len > 0)) { uint16_t buf_len = flashdata.len; - // uint32_t version = (flashdata.name == ZIGB_NAME2) ? 2 : 1; + if (flashdata.name == ZIGB_NAME2) { file_version = 2; } // v2 found f.init(z_dev_start + sizeof(Z_Flashentry), buf_len); storage_class = PSTR("Flash"); } @@ -338,26 +417,25 @@ bool loadZigbeeDevices(void) { uint32_t k = 1; // byte index in global buffer for (uint32_t i = 0; (i < num_devices) && (k < file_len); i++) { - uint8_t dev_record_len = 0; - f.readBytes(&dev_record_len, sizeof(dev_record_len)); - // int32_t ret = ZFS::readBytes(ZIGB_NAME2, &dev_record_len, 1, k, 1); + uint16_t dev_record_len = 0; + size_t dev_record_len_bytes = file_version >= 4 ? 2 : 1; + f.readBytes((uint8_t*)&dev_record_len, dev_record_len_bytes); // starting with v4, length is 2 bytes if (dev_record_len == 0) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Invalid device information, aborting")); zigbee_devices.clean(); // don't write back to Flash what we just loaded return false; } - SBuffer buf(dev_record_len); - buf.setLen(dev_record_len); - buf.set8(0, dev_record_len); // push the first byte (len including this first byte) - int32_t ret = f.readBytes(buf.buf(1), dev_record_len - 1); - // ret = ZFS::readBytes(ZIGB_NAME2, buf.getBuffer(), dev_record_len, k, dev_record_len); - if (ret != dev_record_len - 1) { + SBuffer buf(dev_record_len - dev_record_len_bytes); + buf.setLen(dev_record_len - dev_record_len_bytes); + buf.set8(0, dev_record_len - dev_record_len_bytes); // push the first byte (len including this first byte) + int32_t ret = f.readBytes(buf.buf(), dev_record_len - dev_record_len_bytes); + if (ret != dev_record_len - dev_record_len_bytes) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Invalid device information, aborting")); zigbee_devices.clean(); // don't write back to Flash what we just loaded return false; } - hydrateSingleDevice(buf); + hydrateSingleDevice(buf, file_version); // next iteration k += dev_record_len; @@ -377,6 +455,7 @@ void saveZigbeeDevices(void) { Univ_Write_File f; const char * storage_class = PSTR(""); +// TODO can we prioritize filesystem instead of eeprom? #ifdef USE_ZIGBEE_EEPROM if (!f.valid() && zigbee.eeprom_ready) { f.init(ZIGB_NAME2); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino index b6d2aa58a..3052d3aa5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino @@ -744,7 +744,7 @@ void CmndZbSend(void) { JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)]; if (val_device) { uint16_t parsed_shortaddr = BAD_SHORTADDR; - zcl.shortaddr = zigbee_devices.parseDeviceFromName(val_device.getStr(), &parsed_shortaddr).shortaddr; + zcl.shortaddr = zigbee_devices.parseDeviceFromName(val_device.getStr(), &parsed_shortaddr, &zcl.dstendpoint).shortaddr; if (!zcl.validShortaddr()) { if (parsed_shortaddr != BAD_SHORTADDR) { // we still got a short address @@ -768,9 +768,17 @@ void CmndZbSend(void) { // read other parameters zcl.cluster = root.getUInt(PSTR(D_CMND_ZIGBEE_CLUSTER), zcl.cluster); - zcl.dstendpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), zcl.dstendpoint); zcl.manuf = root.getUInt(PSTR(D_CMND_ZIGBEE_MANUF), zcl.manuf); + // read dest endpoint and check if it's not in conflict with ep name + uint8_t json_endpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), 0); + if (zcl.dstendpoint && json_endpoint && zcl.dstendpoint != json_endpoint) { + AddLog(LOG_LEVEL_DEBUG, PSTR("ZIG: conflicting endpoints, from name:%i from json:%i"), zcl.dstendpoint, json_endpoint); + ResponseCmndChar_P(PSTR(D_ZIGBEE_CONFLICTING_ENDPOINTS)); + return; + } + zcl.dstendpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), zcl.dstendpoint); + // infer endpoint if (!zcl.validShortaddr()) { zcl.dstendpoint = 0xFF; // endpoint not used for group addresses, so use a dummy broadcast endpoint @@ -1003,7 +1011,7 @@ void CmndZbUnbind(void) { // void CmndZbLeave(void) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload).shortaddr; + uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload).shortaddr; if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } #ifdef USE_ZIGBEE_ZNP @@ -1035,7 +1043,7 @@ void CmndZbLeave(void) { void CmndZbBindState_or_Map(bool map) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } uint16_t parsed_shortaddr;; - uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, &parsed_shortaddr, XdrvMailbox.payload).shortaddr; + uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, &parsed_shortaddr, nullptr, XdrvMailbox.payload).shortaddr; if (BAD_SHORTADDR == shortaddr) { if ((map) && (parsed_shortaddr != shortaddr)) { shortaddr = parsed_shortaddr; // allow a non-existent address when ZbMap @@ -1111,7 +1119,7 @@ void CmndZbProbe(void) { // void CmndZbProbeOrPing(boolean probe) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload).shortaddr; + uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload).shortaddr; if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } // set a timer for Reachable - 2s default value @@ -1140,26 +1148,40 @@ void CmndZbName(void) { // ZbName - display the current friendly name // ZbName , - remove friendly name // + // New: + // ZbName ,, - assign a friendly name to a endpoint + // ZbName ,, - remove name to endpoint + // // Where can be: short_addr, long_addr, device_index, friendly_name if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } // check if parameters contain a comma ',' - char *p; - strtok_r(XdrvMailbox.data, ",", &p); + char *p = XdrvMailbox.data; + char *device_id = strsep(&p, ","); // zigbee identifier + bool has_comma = (p != nullptr); + char *new_friendlyname = strsep(&p, ","); // friendly name + int32_t ep = (p != nullptr) ? strtol(p, nullptr, 10) : 0; // get endpoint number, or `0` if none // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // it's the only case where we create a new device + Z_Device & device = zigbee_devices.parseDeviceFromName(device_id, nullptr, nullptr, XdrvMailbox.payload); // it's the only case where we create a new device if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } - if (p == nullptr) { + if (!has_comma) { const char * friendlyName = device.friendlyName; - Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), device.shortaddr, friendlyName ? friendlyName : ""); } else { - if (strlen(p) > 32) { p[32] = 0x00; } // truncate to 32 chars max - device.setFriendlyName(p); - Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), device.shortaddr, p); + if (new_friendlyname != nullptr && strlen(new_friendlyname) > 32) { new_friendlyname[32] = 0x00; } // truncate to 32 chars max + if (ep == 0) { + device.setFriendlyName(new_friendlyname); + } else { + if (!device.setEPName(ep, new_friendlyname)) { + ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_ENDPOINT)); return; + } + } } + Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), device.shortaddr, device.friendlyName ? device.friendlyName : ""); + device.ep_names.ResponseAppend(); + ResponseAppend_P(PSTR("}}")); } // @@ -1181,7 +1203,7 @@ void CmndZbModelId(void) { strtok_r(XdrvMailbox.data, ",", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p != nullptr) { @@ -1208,7 +1230,7 @@ void CmndZbLight(void) { strtok_r(XdrvMailbox.data, ", ", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p) { @@ -1252,7 +1274,7 @@ void CmndZbOccupancy(void) { strtok_r(XdrvMailbox.data, ", ", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } int8_t occupancy_time = -1; @@ -1279,7 +1301,7 @@ void CmndZbOccupancy(void) { // void CmndZbForget(void) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } // everything is good, we can send the command @@ -1309,7 +1331,7 @@ void CmndZbInfo(void) { CmndZbInfo_inner(device); } } else { // try JSON - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } // everything is good, we can send the command @@ -1426,7 +1448,7 @@ void CmndZbenroll(void) { if ((XdrvMailbox.data_len) && (ArgC() > 1)) { // Process parameter entry char argument[XdrvMailbox.data_len]; - Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1), nullptr, XdrvMailbox.payload); + Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1), nullptr, nullptr, XdrvMailbox.payload); int enrollEndpoint = atoi(ArgV(argument, 2)); if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } @@ -1444,7 +1466,7 @@ void CmndZbcie(void) { if ((XdrvMailbox.data_len) && (ArgC() > 1)) { // Process parameter entry char argument[XdrvMailbox.data_len]; - Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1), nullptr, XdrvMailbox.payload); + Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1), nullptr, nullptr, XdrvMailbox.payload); int enrollEndpoint = atoi(ArgV(argument, 2)); if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } @@ -1512,7 +1534,7 @@ void CmndZbRestore(void) { // do a sanity check, the first byte must equal the length of the buffer if (buf.get8(0) == buf.len()) { // good, we can hydrate - hydrateSingleDevice(buf); + hydrateSingleDevice(buf, 4); } else { ResponseCmndChar_P(PSTR("Restore failed")); return; @@ -1684,7 +1706,7 @@ void CmndZbStatus(void) { if (0 == XdrvMailbox.index) { dump = zigbee_devices.dumpCoordinator(); } else { - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); if (XdrvMailbox.data_len > 0) { if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device); @@ -1716,7 +1738,7 @@ void CmndZbData(void) { strtok_r(XdrvMailbox.data, ",", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p) { From 58c0ca4076a6141623c28edb9aa730c9e5264f32 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 2 Oct 2022 21:13:32 +0200 Subject: [PATCH 2/2] fix compilation --- tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino index 9b0d76cca..3e15ba5db 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_4c_devices.ino @@ -358,11 +358,11 @@ bool loadZigbeeDevices(void) { #ifdef USE_ZIGBEE_EEPROM if (zigbee.eeprom_ready) { f.init(ZIGB_NAME4); // try v4 first - if (!f.valid) { + if (!f.valid()) { f.init(ZIGB_NAME2); // else try v2 - if (f.valid) { file_version = 2; } // v2 found + if (f.valid()) { file_version = 2; } // v2 found } - if (f.valid) { + if (f.valid()) { storage_class = PSTR("EEPROM"); } }