mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 19:26:37 +00:00
Zigbee added `ZbMap
` command to describe Zigbee topology
This commit is contained in:
parent
7ce5365cf6
commit
a0801b11da
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user