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)
- Support for EZO O2 sensors by Christopher Tremblay (#9619)
- Zigbee reduce battery drain (#9642)
- Zigbee added ``ZbMap`` command to describe Zigbee topology
### Changed
- PlatformIO library structure redesigned for compilation speed by Jason2866

View File

@ -565,6 +565,8 @@
#define D_JSON_ZIGBEE_UNBIND "ZbUnbind"
#define D_CMND_ZIGBEE_BIND_STATE "BindState"
#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_CMND_ZIGBEE_PING "Ping"
#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;
}
//
// Handle MgMt Bind Rsp incoming message
//
@ -1002,6 +1003,116 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
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
//
// 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);
case ZDO_Unbind_rsp:
return Z_UnbindRsp(res, zdo_buf);
case ZDO_Mgmt_Lqi_rsp:
return Z_MgmtLqiRsp(res, zdo_buf);
case ZDO_Mgmt_Bind_rsp:
return Z_MgmtBindRsp(res, zdo_buf);
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_BIND_RSP }, &Z_BindRsp }, // 45A1
{ { 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
};

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_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_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
;
@ -47,7 +47,7 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
&CmndZbStatus, &CmndZbReset, &CmndZbSend, &CmndZbProbe,
&CmndZbForget, &CmndZbSave, &CmndZbName,
&CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId,
&CmndZbLight, &CmndZbRestore, &CmndZbBindState,
&CmndZbLight, &CmndZbRestore, &CmndZbBindState, &CmndZbMap,
&CmndZbConfig, CmndZbData,
};
@ -937,11 +937,7 @@ void CmndZbUnbind(void) {
ZbBindUnbind(true);
}
//
// Command `ZbBindState`
// `ZbBindState<x>` as index if it does not fit. If default, `1` starts at the beginning
//
void CmndZbBindState(void) {
void CmndZbBindState_or_Map(uint16_t zdo_cmd) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
@ -950,7 +946,7 @@ void CmndZbBindState(void) {
#ifdef USE_ZIGBEE_ZNP
SBuffer buf(10);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_BIND_REQ); // 33
buf.add8(zdo_cmd); // 33
buf.add16(shortaddr); // shortaddr
buf.add8(index); // StartIndex = 0
@ -962,12 +958,28 @@ void CmndZbBindState(void) {
// ZDO message payload (see Zigbee spec 2.4.3.3.4)
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
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
void CmndZbProbe(void) {
CmndZbProbeOrPing(true);