Zigbee added `ZbMap` command to describe Zigbee topology

This commit is contained in:
Stephan Hadinger 2020-10-28 17:30:46 +01:00
parent 7ce5365cf6
commit a0801b11da
4 changed files with 138 additions and 9 deletions

View File

@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- TLS in binary tasmota-zbbridge (#9635) - TLS in binary tasmota-zbbridge (#9635)
- Support for EZO O2 sensors by Christopher Tremblay (#9619) - Support for EZO O2 sensors by Christopher Tremblay (#9619)
- Zigbee reduce battery drain (#9642) - Zigbee reduce battery drain (#9642)
- Zigbee added ``ZbMap`` command to describe Zigbee topology
### Changed ### Changed
- PlatformIO library structure redesigned for compilation speed by Jason2866 - PlatformIO library structure redesigned for compilation speed by Jason2866

View File

@ -565,6 +565,8 @@
#define D_JSON_ZIGBEE_UNBIND "ZbUnbind" #define D_JSON_ZIGBEE_UNBIND "ZbUnbind"
#define D_CMND_ZIGBEE_BIND_STATE "BindState" #define D_CMND_ZIGBEE_BIND_STATE "BindState"
#define D_JSON_ZIGBEE_BIND_STATE "ZbBindState" #define D_JSON_ZIGBEE_BIND_STATE "ZbBindState"
#define D_CMND_ZIGBEE_MAP "Map"
#define D_JSON_ZIGBEE_MAP "ZbMap"
#define D_JSON_ZIGBEE_PARENT "ZbParent" #define D_JSON_ZIGBEE_PARENT "ZbParent"
#define D_CMND_ZIGBEE_PING "Ping" #define D_CMND_ZIGBEE_PING "Ping"
#define D_JSON_ZIGBEE_PING "ZbPing" #define D_JSON_ZIGBEE_PING "ZbPing"

View File

@ -925,6 +925,7 @@ int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) {
return -1; return -1;
} }
// //
// Handle MgMt Bind Rsp incoming message // Handle MgMt Bind Rsp incoming message
// //
@ -1002,6 +1003,116 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
return -1; return -1;
} }
// Return false, true or null (if unknown)
const char * TrueFalseNull(uint32_t value) {
if (value == 0) {
return PSTR("false");
} else if (value == 1) {
return PSTR("true");
} else {
return PSTR("null");
}
}
const char * Z_DeviceRelationship(uint32_t value) {
switch (value) {
case 0: return PSTR("Parent");
case 1: return PSTR("Child");
case 2: return PSTR("Sibling");
case 4: return PSTR("Previous");
case 3:
default: return PSTR("None");
}
}
const char * Z_DeviceType(uint32_t value) {
switch (value) {
case 0: return PSTR("Coordinator");
case 1: return PSTR("Router");
case 2: return PSTR("Device");
default: return PSTR("Unknown");
}
}
//
// Handle MgMt Bind Rsp incoming message
//
int32_t Z_MgmtLqiRsp(int32_t res, const class SBuffer &buf) {
#ifdef USE_ZIGBEE_ZNP
uint16_t shortaddr = buf.get16(2);
uint8_t status = buf.get8(4);
uint8_t lqi_total = buf.get8(5);
uint8_t lqi_start = buf.get8(6);
uint8_t lqi_len = buf.get8(7);
const size_t prefix_len = 8;
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
uint16_t shortaddr = buf.get16(buf.len()-2);
uint8_t status = buf.get8(0);
uint8_t lqi_total = buf.get8(1);
uint8_t lqi_start = buf.get8(2);
uint8_t lqi_len = buf.get8(3);
const size_t prefix_len = 4;
#endif // USE_ZIGBEE_EZSP
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
Response_P(PSTR("{\"" D_JSON_ZIGBEE_MAP "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), shortaddr);
if (friendlyName) {
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName);
}
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d"
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
",\"MapTotal\":%d"
",\"MapStart\":%d"
",\"Map\":["
), status, getZigbeeStatusMessage(status).c_str(), lqi_total, lqi_start + 1);
uint32_t idx = prefix_len;
for (uint32_t i = 0; i < lqi_len; i++) {
if (idx + 22 > buf.len()) { break; } // size 22 for EZSP
//uint64_t extpanid = buf.get16(idx); // unused
// uint64_t m_longaddr = buf.get64(idx + 8);
uint16_t m_shortaddr = buf.get16(idx + 16);
uint8_t m_dev_type = buf.get8(idx + 18);
uint8_t m_permitjoin = buf.get8(idx + 19);
uint8_t m_depth = buf.get8(idx + 20);
uint8_t m_lqi = buf.get8(idx + 21);
idx += 22;
if (i > 0) {
ResponseAppend_P(PSTR(","));
}
ResponseAppend_P(PSTR("{\"Device\":\"0x%04X\","), m_shortaddr);
const char * friendlyName = zigbee_devices.getFriendlyName(m_shortaddr);
if (friendlyName) {
ResponseAppend_P(PSTR("\"Name\":\"%s\","), friendlyName);
}
ResponseAppend_P(PSTR("\"DeviceType\":\"%s\","
"\"RxOnWhenIdle\":%s,"
"\"Relationship\":\"%s\","
"\"PermitJoin\":%s,"
"\"Depth\":%d,"
"\"LinkQuality\":%d"
"}"
),
Z_DeviceType(m_dev_type & 0x03),
TrueFalseNull((m_dev_type & 0x0C) >> 2),
Z_DeviceRelationship((m_dev_type & 0x70) >> 4),
TrueFalseNull(m_permitjoin & 0x02),
m_depth,
m_lqi);
}
ResponseAppend_P(PSTR("]}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_MAP));
return -1;
}
#ifdef USE_ZIGBEE_EZSP #ifdef USE_ZIGBEE_EZSP
// //
// Handle Parent Annonce Rsp incoming message // Handle Parent Annonce Rsp incoming message
@ -1524,6 +1635,8 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) {
return Z_BindRsp(res, zdo_buf); return Z_BindRsp(res, zdo_buf);
case ZDO_Unbind_rsp: case ZDO_Unbind_rsp:
return Z_UnbindRsp(res, zdo_buf); return Z_UnbindRsp(res, zdo_buf);
case ZDO_Mgmt_Lqi_rsp:
return Z_MgmtLqiRsp(res, zdo_buf);
case ZDO_Mgmt_Bind_rsp: case ZDO_Mgmt_Bind_rsp:
return Z_MgmtBindRsp(res, zdo_buf); return Z_MgmtBindRsp(res, zdo_buf);
case ZDO_Parent_annce: case ZDO_Parent_annce:
@ -1697,6 +1810,7 @@ const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
{ { Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP }, &Z_ReceiveIEEEAddr }, // 4581 { { Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP }, &Z_ReceiveIEEEAddr }, // 4581
{ { Z_AREQ | Z_ZDO, ZDO_BIND_RSP }, &Z_BindRsp }, // 45A1 { { Z_AREQ | Z_ZDO, ZDO_BIND_RSP }, &Z_BindRsp }, // 45A1
{ { Z_AREQ | Z_ZDO, ZDO_UNBIND_RSP }, &Z_UnbindRsp }, // 45A2 { { Z_AREQ | Z_ZDO, ZDO_UNBIND_RSP }, &Z_UnbindRsp }, // 45A2
{ { Z_AREQ | Z_ZDO, ZDO_MGMT_LQI_RSP }, &Z_MgmtLqiRsp }, // 45B1
{ { Z_AREQ | Z_ZDO, ZDO_MGMT_BIND_RSP }, &Z_MgmtBindRsp }, // 45B3 { { Z_AREQ | Z_ZDO, ZDO_MGMT_BIND_RSP }, &Z_MgmtBindRsp }, // 45B3
}; };

View File

@ -32,7 +32,7 @@ const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" D_CMND_ZIGBEE_PROBE "|"
D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|" D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|"
D_CMND_ZIGBEE_BIND "|" D_CMND_ZIGBEE_UNBIND "|" D_CMND_ZIGBEE_PING "|" D_CMND_ZIGBEE_MODELID "|" D_CMND_ZIGBEE_BIND "|" D_CMND_ZIGBEE_UNBIND "|" D_CMND_ZIGBEE_PING "|" D_CMND_ZIGBEE_MODELID "|"
D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|" D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|" D_CMND_ZIGBEE_MAP "|"
D_CMND_ZIGBEE_CONFIG "|" D_CMND_ZIGBEE_DATA D_CMND_ZIGBEE_CONFIG "|" D_CMND_ZIGBEE_DATA
; ;
@ -47,7 +47,7 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
&CmndZbStatus, &CmndZbReset, &CmndZbSend, &CmndZbProbe, &CmndZbStatus, &CmndZbReset, &CmndZbSend, &CmndZbProbe,
&CmndZbForget, &CmndZbSave, &CmndZbName, &CmndZbForget, &CmndZbSave, &CmndZbName,
&CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId, &CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId,
&CmndZbLight, &CmndZbRestore, &CmndZbBindState, &CmndZbLight, &CmndZbRestore, &CmndZbBindState, &CmndZbMap,
&CmndZbConfig, CmndZbData, &CmndZbConfig, CmndZbData,
}; };
@ -937,11 +937,7 @@ void CmndZbUnbind(void) {
ZbBindUnbind(true); ZbBindUnbind(true);
} }
// void CmndZbBindState_or_Map(uint16_t zdo_cmd) {
// Command `ZbBindState`
// `ZbBindState<x>` as index if it does not fit. If default, `1` starts at the beginning
//
void CmndZbBindState(void) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
@ -950,7 +946,7 @@ void CmndZbBindState(void) {
#ifdef USE_ZIGBEE_ZNP #ifdef USE_ZIGBEE_ZNP
SBuffer buf(10); SBuffer buf(10);
buf.add8(Z_SREQ | Z_ZDO); // 25 buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_BIND_REQ); // 33 buf.add8(zdo_cmd); // 33
buf.add16(shortaddr); // shortaddr buf.add16(shortaddr); // shortaddr
buf.add8(index); // StartIndex = 0 buf.add8(index); // StartIndex = 0
@ -962,12 +958,28 @@ void CmndZbBindState(void) {
// ZDO message payload (see Zigbee spec 2.4.3.3.4) // ZDO message payload (see Zigbee spec 2.4.3.3.4)
uint8_t buf[] = { index }; // index = 0 uint8_t buf[] = { index }; // index = 0
EZ_SendZDO(shortaddr, ZDO_Mgmt_Bind_req, buf, sizeof(buf)); EZ_SendZDO(shortaddr, zdo_cmd, buf, sizeof(buf));
#endif // USE_ZIGBEE_EZSP #endif // USE_ZIGBEE_EZSP
ResponseCmndDone(); ResponseCmndDone();
} }
//
// Command `ZbBindState`
// `ZbBindState<x>` as index if it does not fit. If default, `1` starts at the beginning
//
void CmndZbBindState(void) {
CmndZbBindState_or_Map(ZDO_Mgmt_Bind_req);
}
//
// Command `ZbMap`
// `ZbMap<x>` as index if it does not fit. If default, `1` starts at the beginning
//
void CmndZbMap(void) {
CmndZbBindState_or_Map(ZDO_Mgmt_Lqi_req);
}
// Probe a specific device to get its endpoints and supported clusters // Probe a specific device to get its endpoints and supported clusters
void CmndZbProbe(void) { void CmndZbProbe(void) {
CmndZbProbeOrPing(true); CmndZbProbeOrPing(true);