mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 03:06:33 +00:00
Merge pull request #8862 from s-hadinger/zigbee_july_5
Zigbee EZSP support for bindings and groups
This commit is contained in:
commit
d612d2b62e
@ -461,6 +461,7 @@ enum EZSP_ZDO {
|
||||
// Network Management Server Services Requests
|
||||
ZDO_Mgmt_Lqi_req = 0x0031,
|
||||
ZDO_Mgmt_Rtg_req = 0x0032,
|
||||
ZDO_Mgmt_Bind_req = 0x0033,
|
||||
ZDO_Mgmt_Leave_req = 0x0034,
|
||||
ZDO_Mgmt_Permit_Joining_req = 0x0036,
|
||||
ZDO_Mgmt_NWK_Update_req = 0x0038,
|
||||
@ -496,6 +497,7 @@ enum EZSP_ZDO {
|
||||
// Network Management Server Services Responses
|
||||
ZDO_Mgmt_Lqi_rsp = 0x8031,
|
||||
ZDO_Mgmt_Rtg_rsp = 0x8032,
|
||||
ZDO_Mgmt_Bind_rsp = 0x8033,
|
||||
ZDO_Mgmt_Leave_rsp = 0x8034,
|
||||
ZDO_Mgmt_Permit_Joining_rsp = 0x8036,
|
||||
ZDO_Mgmt_NWK_Update_rsp = 0x8038,
|
||||
@ -1106,6 +1108,34 @@ typedef struct Z_StatusLine {
|
||||
const char * status_msg;
|
||||
} Z_StatusLine;
|
||||
|
||||
|
||||
// ZDP Enumeration, see Zigbee spec 2.4.5
|
||||
String getZDPStatusMessage(uint8_t status) {
|
||||
static const char StatusMsg[] PROGMEM = "SUCCESS|INV_REQUESTTYPE|DEVICE_NOT_FOUND|INVALID_EP|NOT_ACTIVE|NOT_SUPPORTED"
|
||||
"|TIMEOUT|NO_MATCH|NO_ENTRY|NO_DESCRIPTOR|INSUFFICIENT_SPACE|NOT_PERMITTED"
|
||||
"|TABLE_FULL|NOT_AUTHORIZED|DEVICE_BINDING_TABLE_FULL"
|
||||
;
|
||||
static const uint8_t StatusIdx[] PROGMEM = { 0x00, 0x80, 0x81, 0x82, 0x83, 0x84,
|
||||
0x85, 0x86, 0x88, 0x89, 0x8A, 0x8B,
|
||||
0x8C, 0x8D, 0x8E };
|
||||
|
||||
char msg[32];
|
||||
int32_t idx = -1;
|
||||
for (uint32_t i = 0; i < sizeof(StatusIdx); i++) {
|
||||
if (status == pgm_read_byte(&StatusIdx[i])) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx >= 0) {
|
||||
GetTextIndexed(msg, sizeof(msg), idx, StatusMsg);
|
||||
} else {
|
||||
*msg = 0x00; // empty string
|
||||
}
|
||||
return String(msg);
|
||||
}
|
||||
|
||||
|
||||
// Undocumented Zigbee ZCL code here: https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Zigbee-Error-Codes-in-the-Log
|
||||
String getZigbeeStatusMessage(uint8_t status) {
|
||||
static const char StatusMsg[] PROGMEM = "SUCCESS|FAILURE|NOT_AUTHORIZED|RESERVED_FIELD_NOT_ZERO|MALFORMED_COMMAND|UNSUP_CLUSTER_COMMAND|UNSUP_GENERAL_COMMAND"
|
||||
|
@ -670,9 +670,17 @@ int32_t ZNP_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) {
|
||||
//
|
||||
// Handle Bind Rsp incoming message
|
||||
//
|
||||
int32_t ZNP_BindRsp(int32_t res, const class SBuffer &buf) {
|
||||
int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) {
|
||||
#ifdef USE_ZIGBEE_ZNP
|
||||
Z_ShortAddress nwkAddr = buf.get16(2);
|
||||
uint8_t status = buf.get8(4);
|
||||
String msg = getZigbeeStatusMessage(status);
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
uint8_t status = buf.get8(0);
|
||||
Z_ShortAddress nwkAddr = buf.get16(buf.len()-2); // last 2 bytes
|
||||
String msg = getZDPStatusMessage(status);
|
||||
#endif // USE_ZIGBEE_EZSP
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
||||
|
||||
@ -682,7 +690,7 @@ int32_t ZNP_BindRsp(int32_t res, const class SBuffer &buf) {
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), status, getZigbeeStatusMessage(status).c_str());
|
||||
"}}"), status, msg.c_str());
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
@ -693,9 +701,17 @@ int32_t ZNP_BindRsp(int32_t res, const class SBuffer &buf) {
|
||||
//
|
||||
// Handle Unbind Rsp incoming message
|
||||
//
|
||||
int32_t ZNP_UnbindRsp(int32_t res, const class SBuffer &buf) {
|
||||
int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) {
|
||||
#ifdef USE_ZIGBEE_ZNP
|
||||
Z_ShortAddress nwkAddr = buf.get16(2);
|
||||
uint8_t status = buf.get8(4);
|
||||
String msg = getZigbeeStatusMessage(status);
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
uint8_t status = buf.get8(0);
|
||||
Z_ShortAddress nwkAddr = buf.get16(buf.len()-2); // last 2 bytes
|
||||
String msg = getZDPStatusMessage(status);
|
||||
#endif // USE_ZIGBEE_EZSP
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
||||
|
||||
@ -703,8 +719,9 @@ int32_t ZNP_UnbindRsp(int32_t res, const class SBuffer &buf) {
|
||||
if (friendlyName) {
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName);
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), status, getZigbeeStatusMessage(status).c_str());
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), status, msg.c_str());
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
@ -714,12 +731,23 @@ int32_t ZNP_UnbindRsp(int32_t res, const class SBuffer &buf) {
|
||||
//
|
||||
// Handle MgMt Bind Rsp incoming message
|
||||
//
|
||||
int32_t ZNP_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
|
||||
int32_t Z_MgmtBindRsp(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 bind_total = buf.get8(5);
|
||||
uint8_t bind_start = buf.get8(6);
|
||||
uint8_t bind_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 bind_total = buf.get8(1);
|
||||
uint8_t bind_start = buf.get8(2);
|
||||
uint8_t bind_len = buf.get8(3);
|
||||
const size_t prefix_len = 4;
|
||||
#endif // USE_ZIGBEE_EZSP
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
|
||||
|
||||
@ -733,7 +761,7 @@ int32_t ZNP_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
|
||||
",\"Bindings\":["
|
||||
), status, getZigbeeStatusMessage(status).c_str(), bind_total);
|
||||
|
||||
uint32_t idx = 8;
|
||||
uint32_t idx = prefix_len;
|
||||
for (uint32_t i = 0; i < bind_len; i++) {
|
||||
if (idx + 14 > buf.len()) { break; } // overflow, frame size is between 14 and 21
|
||||
|
||||
@ -791,7 +819,8 @@ void Z_SendIEEEAddrReq(uint16_t shortaddr) {
|
||||
ZigbeeZNPSend(IEEEAddrReq, sizeof(IEEEAddrReq));
|
||||
#endif
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
// TODO
|
||||
uint8_t IEEEAddrReq[] = { Z_B0(shortaddr), Z_B1(shortaddr), 0x00, 0x00 };
|
||||
EZ_SendZDO(shortaddr, ZDO_IEEE_addr_req, IEEEAddrReq, sizeof(IEEEAddrReq));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -991,25 +1020,31 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||
uint8_t linkquality = buf.get8(14);
|
||||
// uint8_t linkrsssi = buf.get8(15); // probably not used as there is no equivalent in Z-Stack
|
||||
uint16_t srcaddr = buf.get16(16);
|
||||
uint8_t bindingindex = buf.get8(18); // TODO not sure we need this one as a coordinator
|
||||
uint8_t addressindex = buf.get8(19); // TODO not sure how to handle this one
|
||||
// uint8_t bindingindex = buf.get8(18); // not sure we need this one as a coordinator
|
||||
// uint8_t addressindex = buf.get8(19); // not sure how to handle this one
|
||||
// offset 20 is len, and buffer starts at offset 21
|
||||
|
||||
|
||||
if ((0x0000 == profileid) && (0x00 == srcendpoint)) {
|
||||
// ZDO request
|
||||
// Since ZDO messages start with a sequence number, we skip it
|
||||
SBuffer zdo_buf = buf.subBuffer(22, buf.get8(20) - 1);
|
||||
// but we add the source address in the last 2 bytes
|
||||
SBuffer zdo_buf(buf.get8(20) - 1 + 2);
|
||||
zdo_buf.addBuffer(buf.buf(22), buf.get8(20) - 1);
|
||||
zdo_buf.add16(srcaddr);
|
||||
switch (clusterid) {
|
||||
case ZDO_Device_annce:
|
||||
return Z_ReceiveEndDeviceAnnonce(res, zdo_buf);
|
||||
break;
|
||||
case ZDO_Active_EP_rsp:
|
||||
return Z_ReceiveActiveEp(res, zdo_buf);
|
||||
break;
|
||||
case ZDO_IEEE_addr_rsp:
|
||||
return Z_ReceiveIEEEAddr(res, zdo_buf);
|
||||
break;
|
||||
case ZDO_Bind_rsp:
|
||||
return Z_BindRsp(res, zdo_buf);
|
||||
case ZDO_Unbind_rsp:
|
||||
return Z_UnbindRsp(res, zdo_buf);
|
||||
case ZDO_Mgmt_Bind_rsp:
|
||||
return Z_MgmtBindRsp(res, zdo_buf);
|
||||
}
|
||||
} else {
|
||||
bool defer_attributes = false; // do we defer attributes reporting to coalesce
|
||||
@ -1130,15 +1165,6 @@ int32_t ZNP_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Callback for loading Zigbee configuration from Flash, called by the state machine
|
||||
//
|
||||
int32_t Z_Reset_Device(uint8_t value) {
|
||||
// TODO - GPIO is hardwired to GPIO4
|
||||
digitalWrite(4, value ? HIGH : LOW);
|
||||
return 0; // continue
|
||||
}
|
||||
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
|
||||
|
||||
@ -1189,9 +1215,9 @@ const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
|
||||
{ { Z_AREQ | Z_ZDO, ZDO_NODE_DESC_RSP }, &ZNP_ReceiveNodeDesc }, // 4582
|
||||
{ { Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP }, &Z_ReceiveActiveEp }, // 4585
|
||||
{ { Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP }, &Z_ReceiveIEEEAddr }, // 4581
|
||||
{ { Z_AREQ | Z_ZDO, ZDO_BIND_RSP }, &ZNP_BindRsp }, // 45A1
|
||||
{ { Z_AREQ | Z_ZDO, ZDO_UNBIND_RSP }, &ZNP_UnbindRsp }, // 45A2
|
||||
{ { Z_AREQ | Z_ZDO, ZDO_MGMT_BIND_RSP }, &ZNP_MgmtBindRsp }, // 45B3
|
||||
{ { 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_BIND_RSP }, &Z_MgmtBindRsp }, // 45B3
|
||||
};
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -718,33 +718,61 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
SBuffer buf(32+len);
|
||||
|
||||
buf.add16(EZSP_sendUnicast); // 3400
|
||||
buf.add8(EMBER_OUTGOING_DIRECT); // 00
|
||||
buf.add16(shortaddr); // dest addr
|
||||
// ApsFrame
|
||||
buf.add16(Z_PROF_HA); // Home Automation profile
|
||||
buf.add16(clusterId); // cluster
|
||||
buf.add8(0x01); // srcEp
|
||||
buf.add8(endpoint); // dstEp
|
||||
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
||||
buf.add16(groupaddr); // groupId
|
||||
buf.add8(transacId);
|
||||
// end of ApsFrame
|
||||
buf.add8(0x01); // tag TODO
|
||||
if (BAD_SHORTADDR != shortaddr) {
|
||||
// send unicast message to an address
|
||||
buf.add16(EZSP_sendUnicast); // 3400
|
||||
buf.add8(EMBER_OUTGOING_DIRECT); // 00
|
||||
buf.add16(shortaddr); // dest addr
|
||||
// ApsFrame
|
||||
buf.add16(Z_PROF_HA); // Home Automation profile
|
||||
buf.add16(clusterId); // cluster
|
||||
buf.add8(0x01); // srcEp
|
||||
buf.add8(endpoint); // dstEp
|
||||
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
||||
buf.add16(groupaddr); // groupId
|
||||
buf.add8(transacId);
|
||||
// end of ApsFrame
|
||||
buf.add8(0x01); // tag TODO
|
||||
|
||||
buf.add8(3 + len + (manuf ? 2 : 0));
|
||||
buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field
|
||||
if (manuf) {
|
||||
buf.add16(manuf); // add Manuf Id if not null
|
||||
}
|
||||
buf.add8(transacId); // Transaction Sequance Number
|
||||
buf.add8(cmdId);
|
||||
if (len > 0) {
|
||||
buf.addBuffer(msg, len); // add the payload
|
||||
buf.add8(3 + len + (manuf ? 2 : 0));
|
||||
buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field
|
||||
if (manuf) {
|
||||
buf.add16(manuf); // add Manuf Id if not null
|
||||
}
|
||||
buf.add8(transacId); // Transaction Sequance Number
|
||||
buf.add8(cmdId);
|
||||
if (len > 0) {
|
||||
buf.addBuffer(msg, len); // add the payload
|
||||
}
|
||||
} else {
|
||||
// send broadcast group address, aka groupcast
|
||||
buf.add16(EZSP_sendMulticast); // 3800
|
||||
// ApsFrame
|
||||
buf.add16(Z_PROF_HA); // Home Automation profile
|
||||
buf.add16(clusterId); // cluster
|
||||
buf.add8(0x01); // srcEp
|
||||
buf.add8(endpoint); // broadcast endpoint for groupcast
|
||||
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
||||
buf.add16(groupaddr); // groupId
|
||||
buf.add8(transacId);
|
||||
// end of ApsFrame
|
||||
buf.add8(0); // hops, 0x00 = EMBER_MAX_HOPS
|
||||
buf.add8(7); // nonMemberRadius, 7 = infinite
|
||||
buf.add8(0x01); // tag TODO
|
||||
|
||||
buf.add8(3 + len + (manuf ? 2 : 0));
|
||||
buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); // Frame Control Field
|
||||
if (manuf) {
|
||||
buf.add16(manuf); // add Manuf Id if not null
|
||||
}
|
||||
buf.add8(transacId); // Transaction Sequance Number
|
||||
buf.add8(cmdId);
|
||||
if (len > 0) {
|
||||
buf.addBuffer(msg, len); // add the payload
|
||||
}
|
||||
}
|
||||
|
||||
ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true);
|
||||
|
||||
#endif // USE_ZIGBEE_EZSP
|
||||
}
|
||||
|
||||
|
@ -713,6 +713,25 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
SBuffer buf(24);
|
||||
|
||||
// ZDO message payload (see Zigbee spec 2.4.3.2.2)
|
||||
buf.add64(srcLongAddr);
|
||||
buf.add8(endpoint);
|
||||
buf.add16(cluster);
|
||||
if (dstLongAddr) {
|
||||
buf.add8(Z_Addr_IEEEAddress); // DstAddrMode - 0x03 = ADDRESS_64_BIT
|
||||
buf.add64(dstLongAddr);
|
||||
buf.add8(toendpoint);
|
||||
} else {
|
||||
buf.add8(Z_Addr_Group); // DstAddrMode - 0x01 = GROUP_ADDRESS
|
||||
buf.add16(toGroup);
|
||||
}
|
||||
|
||||
EZ_SendZDO(srcDevice, unbind ? ZDO_UNBIND_REQ : ZDO_BIND_REQ, buf.buf(), buf.len());
|
||||
#endif // USE_ZIGBEE_EZSP
|
||||
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
@ -748,6 +767,14 @@ void CmndZbBindState(void) {
|
||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
|
||||
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
// ZDO message payload (see Zigbee spec 2.4.3.3.4)
|
||||
uint8_t buf[] = { 0x00 }; // index = 0
|
||||
|
||||
EZ_SendZDO(shortaddr, ZDO_Mgmt_Bind_req, buf, sizeof(buf));
|
||||
#endif // USE_ZIGBEE_EZSP
|
||||
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user