Glowing led when permit join

This commit is contained in:
Stephan Hadinger 2020-10-19 20:34:40 +02:00
parent 4eb8be1e64
commit db79409411
6 changed files with 69 additions and 16 deletions

View File

@ -34,6 +34,7 @@ public:
uint16_t manuf; uint16_t manuf;
bool clusterSpecific; bool clusterSpecific;
bool needResponse; bool needResponse;
bool direct; // true if direct, false if discover router
uint8_t transacId; // ZCL transaction number uint8_t transacId; // ZCL transaction number
const uint8_t *msg; const uint8_t *msg;
size_t len; size_t len;
@ -86,6 +87,8 @@ struct ZigbeeStatus {
ZB_RecvMsgFunc recv_func = nullptr; // function to call when message is expected ZB_RecvMsgFunc recv_func = nullptr; // function to call when message is expected
ZB_RecvMsgFunc recv_unexpected = nullptr; // function called when unexpected message is received ZB_RecvMsgFunc recv_unexpected = nullptr; // function called when unexpected message is received
uint32_t permit_end_time = 0; // timestamp when permit join ends
}; };
struct ZigbeeStatus zigbee; struct ZigbeeStatus zigbee;
SBuffer *zigbee_buffer = nullptr; SBuffer *zigbee_buffer = nullptr;

View File

@ -753,6 +753,8 @@ public:
void syntheticAqaraCubeOrButton(Z_attribute_list &attr_list, class Z_attribute &attr); void syntheticAqaraCubeOrButton(Z_attribute_list &attr_list, class Z_attribute &attr);
void syntheticAqaraVibration(Z_attribute_list &attr_list, class Z_attribute &attr); void syntheticAqaraVibration(Z_attribute_list &attr_list, class Z_attribute &attr);
// handle read attributes auto-responder
void autoResponder(const uint16_t *attr_list_ids, size_t attr_len);
inline void setGroupId(uint16_t groupid) { inline void setGroupId(uint16_t groupid) {
_groupaddr = groupid; _groupaddr = groupid;
@ -1182,6 +1184,7 @@ void ZCLFrame::parseReportAttributes(Z_attribute_list& attr_list) {
_manuf_code, _manuf_code,
false /* not cluster specific */, false /* not cluster specific */,
false /* noresponse */, false /* noresponse */,
true /* direct no retry */,
_transact_seq, /* zcl transaction id */ _transact_seq, /* zcl transaction id */
buf.getBuffer(), buf.len() buf.getBuffer(), buf.len()
})); }));
@ -1349,7 +1352,7 @@ void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) {
attr_list.addAttribute(F("ReadNames")).setStrRaw(attr_names.toString(true).c_str()); attr_list.addAttribute(F("ReadNames")).setStrRaw(attr_names.toString(true).c_str());
// call auto-responder // call auto-responder
Z_AutoResponder(_srcaddr, _cluster_id, _srcendpoint, read_attr_ids, len/2); autoResponder(read_attr_ids, len/2);
} }
// ZCL_CONFIGURE_REPORTING_RESPONSE // ZCL_CONFIGURE_REPORTING_RESPONSE

View File

@ -186,6 +186,7 @@ void Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster
0, /* manuf */ 0, /* manuf */
false /* not cluster specific */, false /* not cluster specific */,
true /* response */, true /* response */,
false /* discover route */,
seq, /* zcl transaction id */ seq, /* zcl transaction id */
attrs, attrs_len attrs, attrs_len
})); }));

View File

@ -176,7 +176,7 @@ int32_t EZ_PermitJoinRsp(int32_t res, const class SBuffer &buf) {
// //
// Special case: EZSP does not send an event for PermitJoin end, so we generate a synthetic one // Special case: EZSP does not send an event for PermitJoin end, so we generate a synthetic one
// //
void Z_PermitJoinDisable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { void Z_PermitJoinDisable(void) {
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":20,\"Message\":\"Pairing mode disabled\"}}")); Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":20,\"Message\":\"Pairing mode disabled\"}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
} }
@ -1134,6 +1134,7 @@ void Z_SendDeviceInfoRequest(uint16_t shortaddr) {
0x0000, /* manuf */ 0x0000, /* manuf */
false /* not cluster specific */, false /* not cluster specific */,
true /* response */, true /* response */,
false /* discover route */,
transacid, /* zcl transaction id */ transacid, /* zcl transaction id */
InfoReq, sizeof(InfoReq) InfoReq, sizeof(InfoReq)
})); }));
@ -1155,6 +1156,7 @@ void Z_SendSingleAttributeRead(uint16_t shortaddr, uint16_t groupaddr, uint16_t
0x0000, /* manuf */ 0x0000, /* manuf */
false /* not cluster specific */, false /* not cluster specific */,
true /* response */, true /* response */,
false /* discover route */,
transacid, /* zcl transaction id */ transacid, /* zcl transaction id */
InfoReq, sizeof(InfoReq) InfoReq, sizeof(InfoReq)
})); }));
@ -1301,6 +1303,7 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin
0x0000, /* manuf */ 0x0000, /* manuf */
false /* not cluster specific */, false /* not cluster specific */,
false /* no response */, false /* no response */,
false /* discover route */,
zigbee_devices.getNextSeqNumber(shortaddr), /* zcl transaction id */ zigbee_devices.getNextSeqNumber(shortaddr), /* zcl transaction id */
buf.buf(), buf.len() buf.buf(), buf.len()
})); }));
@ -1779,14 +1782,14 @@ int32_t Z_State_Ready(uint8_t value) {
// //
// Mostly used for routers/end-devices // Mostly used for routers/end-devices
// json: holds the attributes in JSON format // json: holds the attributes in JSON format
void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const uint16_t *attr_list_ids, size_t attr_len) { void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
Z_attribute_list attr_list; Z_attribute_list attr_list;
for (uint32_t i=0; i<attr_len; i++) { for (uint32_t i=0; i<attr_len; i++) {
uint16_t attr_id = attr_list_ids[i]; uint16_t attr_id = attr_list_ids[i];
uint32_t ccccaaaa = (cluster << 16) | attr_id; uint32_t ccccaaaa = (_cluster_id << 16) | attr_id;
Z_attribute attr; Z_attribute attr;
attr.setKeyId(cluster, attr_id); attr.setKeyId(_cluster_id, attr_id);
switch (ccccaaaa) { switch (ccccaaaa) {
case 0x00000004: attr.setStr(PSTR(USE_ZIGBEE_MANUFACTURER)); break; // Manufacturer case 0x00000004: attr.setStr(PSTR(USE_ZIGBEE_MANUFACTURER)); break; // Manufacturer
@ -1837,7 +1840,7 @@ void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const
} }
if (!attr.isNone()) { if (!attr.isNone()) {
Z_parseAttributeKey(attr); Z_parseAttributeKey(attr);
attr_list.addAttribute(cluster, attr_id) = attr; attr_list.addAttribute(_cluster_id, attr_id) = attr;
} }
} }
@ -1857,22 +1860,22 @@ void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const
",\"Endpoint\":%d" ",\"Endpoint\":%d"
",\"Response\":%s}" ",\"Response\":%s}"
), ),
srcaddr, cluster, endpoint, _srcaddr, _cluster_id, _srcendpoint,
attr_list.toString().c_str()); attr_list.toString().c_str());
// send // send
// all good, send the packet // all good, send the packet
uint8_t seq = zigbee_devices.getNextSeqNumber(srcaddr);
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({ ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
srcaddr, _srcaddr,
0x0000, 0x0000,
cluster /*cluster*/, _cluster_id /*cluster*/,
endpoint, _srcendpoint,
ZCL_READ_ATTRIBUTES_RESPONSE, ZCL_READ_ATTRIBUTES_RESPONSE,
0x0000, /* manuf */ 0x0000, /* manuf */
false /* not cluster specific */, false /* not cluster specific */,
false /* no response */, false /* no response */,
seq, /* zcl transaction id */ true /* direct response */,
_transact_seq, /* zcl transaction id */
buf.getBuffer(), buf.len() buf.getBuffer(), buf.len()
})); }));
} }

View File

@ -819,7 +819,11 @@ void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
buf.add16(zcl.cluster); // cluster buf.add16(zcl.cluster); // cluster
buf.add8(0x01); // srcEp buf.add8(0x01); // srcEp
buf.add8(zcl.endpoint); // dstEp buf.add8(zcl.endpoint); // dstEp
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame if (zcl.direct) {
buf.add16(0x0000); // APS frame
} else {
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
}
buf.add16(zcl.groupaddr); // groupId buf.add16(zcl.groupaddr); // groupId
buf.add8(zcl.transacId); buf.add8(zcl.transacId);
// end of ApsFrame // end of ApsFrame
@ -843,7 +847,11 @@ void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
buf.add16(zcl.cluster); // cluster buf.add16(zcl.cluster); // cluster
buf.add8(0x01); // srcEp buf.add8(0x01); // srcEp
buf.add8(zcl.endpoint); // broadcast endpoint for groupcast buf.add8(zcl.endpoint); // broadcast endpoint for groupcast
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame if (zcl.direct) {
buf.add16(0x0000); // APS frame
} else {
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
}
buf.add16(zcl.groupaddr); // groupId buf.add16(zcl.groupaddr); // groupId
buf.add8(zcl.transacId); buf.add8(zcl.transacId);
// end of ApsFrame // end of ApsFrame

View File

@ -192,6 +192,7 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
manuf, /* manuf */ manuf, /* manuf */
clusterSpecific /* not cluster specific */, clusterSpecific /* not cluster specific */,
true /* response */, true /* response */,
false /* discover route */,
seq, /* zcl transaction id */ seq, /* zcl transaction id */
buf.getBuffer(), buf.len() buf.getBuffer(), buf.len()
})); }));
@ -739,6 +740,7 @@ void CmndZbSend(void) {
manuf, /* manuf */ manuf, /* manuf */
false /* not cluster specific */, false /* not cluster specific */,
false /* no response */, false /* no response */,
false /* discover route */,
0, /* zcl transaction id */ 0, /* zcl transaction id */
nullptr, 0 nullptr, 0
}); });
@ -1219,9 +1221,11 @@ void CmndZbPermitJoin(void) {
// Log pairing mode enabled // Log pairing mode enabled
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":21,\"Message\":\"Pairing mode enabled\"}}")); Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":21,\"Message\":\"Pairing mode enabled\"}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
zigbee.permit_end_time = millis() + duration * 1000;
AddLog_P2(LOG_LEVEL_INFO, "zigbee.permit_end_time = %d", zigbee.permit_end_time);
} else {
zigbee.permit_end_time = millis();
} }
// always register timer for disable, might happen at next tick
zigbee_devices.setTimer(0x0000 /* coordinator */, 0 /* group addr*/, duration * 1000, 0, 0 /* endpoint */, Z_CAT_PERMIT_JOIN, 0 /* value */, &Z_PermitJoinDisable);
#endif // USE_ZIGBEE_EZSP #endif // USE_ZIGBEE_EZSP
ResponseCmndDone(); ResponseCmndDone();
@ -1255,6 +1259,34 @@ void CmndZbEZSPListen(void) {
ResponseCmndDone(); ResponseCmndDone();
} }
void ZigbeeGlowPermitJoinLight(void) {
static const uint16_t cycle_time = 1000; // cycle up and down in 1000 ms
static const uint16_t half_cycle_time = cycle_time / 2; // cycle up and down in 1000 ms
if (zigbee.permit_end_time) {
uint16_t led_power = 0; // turn led off
// permit join is ongoing
if (TimeReached(zigbee.permit_end_time)) {
zigbee.permit_end_time = 0; // disable timer
Z_PermitJoinDisable();
} else {
uint32_t millis_to_go = millis() - zigbee.permit_end_time;
uint32_t sub_second = millis_to_go % cycle_time;
if (sub_second <= half_cycle_time) {
led_power = changeUIntScale(sub_second, 0, half_cycle_time, 0, 1023);
} else {
led_power = changeUIntScale(sub_second, half_cycle_time, cycle_time, 1023, 0);
}
led_power = ledGamma10_10(led_power);
}
// change the led state
uint32_t led_pin = Pin(GPIO_LEDLNK);
if (led_pin < 99) {
analogWrite(led_pin, ledlnk_inverted ? 1023 - led_power : led_power);
}
}
}
#endif // USE_ZIGBEE_EZSP #endif // USE_ZIGBEE_EZSP
// //
@ -1801,6 +1833,9 @@ bool Xdrv23(uint8_t function)
if (ZigbeeSerial) { if (ZigbeeSerial) {
ZigbeeInputLoop(); ZigbeeInputLoop();
ZigbeeOutputLoop(); // send any outstanding data ZigbeeOutputLoop(); // send any outstanding data
#ifdef USE_ZIGBEE_EZSP
ZigbeeGlowPermitJoinLight();
#endif // USE_ZIGBEE_EZSP
} }
if (zigbee.state_machine) { if (zigbee.state_machine) {
ZigbeeStateMachine_Run(); ZigbeeStateMachine_Run();