From d4e4440a40bcb2499e505ac9ad4ef0c7e4ee8f0c Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Mon, 16 May 2022 19:17:40 +0200 Subject: [PATCH] Zigbee merge ZCLMessage and ZCLFrame --- tasmota/xdrv_23_zigbee_1_headers.ino | 41 +-- tasmota/xdrv_23_zigbee_2_devices.ino | 11 +- tasmota/xdrv_23_zigbee_2a_devices_impl.ino | 10 +- tasmota/xdrv_23_zigbee_5_converters.ino | 244 ++++++++++-------- ...e_3_hue.ino => xdrv_23_zigbee_6_5_hue.ino} | 4 +- tasmota/xdrv_23_zigbee_6_commands.ino | 6 +- tasmota/xdrv_23_zigbee_8_parsers.ino | 63 ++--- tasmota/xdrv_23_zigbee_9_serial.ino | 36 +-- tasmota/xdrv_23_zigbee_A_impl.ino | 78 +++--- 9 files changed, 244 insertions(+), 249 deletions(-) rename tasmota/{xdrv_23_zigbee_3_hue.ino => xdrv_23_zigbee_6_5_hue.ino} (99%) diff --git a/tasmota/xdrv_23_zigbee_1_headers.ino b/tasmota/xdrv_23_zigbee_1_headers.ino index 063c6ddc6..38359d00b 100644 --- a/tasmota/xdrv_23_zigbee_1_headers.ino +++ b/tasmota/xdrv_23_zigbee_1_headers.ino @@ -30,43 +30,6 @@ // contains some definitions for functions used before their declarations -// -// structure containing all needed information to send a ZCL packet -// -class ZCLMessage { - -public: - ZCLMessage(void); // allocate 16 bytes vy default - ZCLMessage(size_t size); - - inline bool validShortaddr(void) const { return BAD_SHORTADDR != shortaddr; } - inline bool validGroupaddr(void) const { return 0 != groupaddr; } - inline bool validCluster(void) const { return 0xFFFF != cluster; } - inline bool validEndpoint(void) const { return 0x00 != endpoint; } - inline bool validCmd(void) const { return 0xFF != cmd; } - - inline void setTransac(uint8_t _transac) { transac = _transac; transacSet = true; } - - uint16_t shortaddr = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid - uint16_t groupaddr = 0x0000; // group address valid only if device == BAD_SHORTADDR - uint16_t cluster = 0xFFFF; // no default - uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint - uint8_t cmd = 0xFF; // 0xFF is invalid command number - uint16_t manuf = 0x0000; // default manuf id - bool clusterSpecific = false; - bool needResponse = true; - bool direct = false; // true if direct, false if discover router - bool transacSet = false; // is transac already set - uint8_t transac = 0; // ZCL transaction number - SBuffer buf; - // const uint8_t *msg = nullptr; - // size_t len = 0; -}; - -// define constructor seperately to avoid inlining and reduce Flash size -ZCLMessage::ZCLMessage(void) : buf(12) {}; -ZCLMessage::ZCLMessage(size_t size) : buf(size) {}; - typedef int32_t (*ZB_Func)(uint8_t value); typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const SBuffer &buf); @@ -150,8 +113,8 @@ public: struct ZigbeeStatus zigbee; SBuffer *zigbee_buffer = nullptr; -void zigbeeZCLSendCmd(ZCLMessage &msg); -void ZigbeeZCLSend_Raw(const ZCLMessage &zcl); +void zigbeeZCLSendCmd(ZCLFrame &msg); +void ZigbeeZCLSend_Raw(const ZCLFrame &zcl); bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_status_ok = false); // parse Hex formatted attribute names like '0301/0001" diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index 9ae8114f7..929676bfb 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -975,7 +975,7 @@ public: void clean(void); // avoid writing to flash the last changes // Find device by name, can be short_addr, long_addr, number_in_array or name - Z_Device & parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr = nullptr); + Z_Device & parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr = nullptr, int32_t mailbox_payload = 0); bool isTuyaProtocol(uint16_t shortaddr, uint8_t ep = 0) const; @@ -983,7 +983,7 @@ private: LList _devices; // list of devices LList _deferred; // list of deferred calls uint32_t _saveTimer = 0; - uint8_t _seqNumber = 0; // global seqNumber if device is unknown + uint8_t _seqnumber = 0; // global seqNumber if device is unknown //int32_t findShortAddrIdx(uint16_t shortaddr) const; // Create a new entry in the devices list - must be called if it is sure it does not already exist @@ -991,6 +991,13 @@ private: void freeDeviceEntry(Z_Device *device); }; +/*********************************************************************************************\ + * Berry support +\*********************************************************************************************/ +#ifdef USE_BERRY +extern "C" void callBerryZigbeeDispatcher(const char* type, ZCLFrame* zcl_received); +#endif // USE_BERRY + /*********************************************************************************************\ * Singleton variable \*********************************************************************************************/ diff --git a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino index 77027fc91..b28ee0462 100644 --- a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino +++ b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino @@ -345,8 +345,8 @@ uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) { device.seqNumber += 1; return device.seqNumber; } else { - _seqNumber += 1; - return _seqNumber; + _seqnumber += 1; + return _seqnumber; } } @@ -622,7 +622,7 @@ void Z_Devices::clean(void) { // - a friendly name, between quotes, example: "Room_Temp" // // In case the device is not found, the parsed 0x.... short address is passed to *parsed_shortaddr -Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr) { +Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr, int32_t mailbox_payload) { if (nullptr == param) { return device_unk; } size_t param_len = strlen(param); char dataBuf[param_len + 1]; @@ -632,8 +632,8 @@ Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_ if ((dataBuf[0] >= '0') && (dataBuf[0] <= '9') && (strlen(dataBuf) < 4)) { // simple number 0..99 - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 99)) { - return isKnownIndexDevice(XdrvMailbox.payload - 1); + if ((mailbox_payload > 0) && (mailbox_payload <= 99)) { + return isKnownIndexDevice(mailbox_payload - 1); } else { return device_unk; } diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 4d57c1906..5c45df943 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -722,18 +722,25 @@ const __FlashStringHelper* zigbeeFindAttributeById(uint16_t cluster, uint16_t at class ZCLFrame { public: + // constructor used when creating a message from scratch to send it later + ZCLFrame(void); // allocate 16 bytes by default + ZCLFrame(size_t size); + + // constructore used when receiving a Zigbee frame and populating the class ZCLFrame(uint8_t frame_control, uint16_t manuf_code, uint8_t transact_seq, uint8_t cmd_id, const char *buf, size_t buf_len, uint16_t clusterid, uint16_t groupaddr, uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast, uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber): - _manuf_code(manuf_code), _transact_seq(transact_seq), _cmd_id(cmd_id), - _payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough - _cluster_id(clusterid), _groupaddr(groupaddr), - _srcaddr(srcaddr), _srcendpoint(srcendpoint), _dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast), + manuf(manuf_code), transactseq(transact_seq), cmd(cmd_id), + payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough + cluster(clusterid), groupaddr(groupaddr), + shortaddr(srcaddr), _srcendpoint(srcendpoint), dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast), _linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber) { _frame_control.d8 = frame_control; - _payload.addBuffer(buf, buf_len); + clusterSpecific = (_frame_control.b.frame_type != 0); + needResponse = !_frame_control.b.disable_def_resp; + payload.addBuffer(buf, buf_len); }; @@ -746,13 +753,13 @@ public: "\"frametype\":%d,\"direction\":%d,\"disableresp\":%d," "\"manuf\":\"0x%04X\",\"transact\":%d," "\"cmdid\":\"0x%02X\",\"payload\":\"%_B\"}}"), - _groupaddr, _cluster_id, _srcaddr, - _srcendpoint, _dstendpoint, _wasbroadcast, + groupaddr, cluster, shortaddr, + _srcendpoint, dstendpoint, _wasbroadcast, _linkquality, _securityuse, _seqnumber, _frame_control, _frame_control.b.frame_type, _frame_control.b.direction, _frame_control.b.disable_def_resp, - _manuf_code, _transact_seq, _cmd_id, - &_payload); + manuf, transactseq, cmd, + &payload); if (Settings->flag3.tuya_serial_mqtt_publish) { MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); } else { @@ -788,6 +795,7 @@ public: return _frame_control.b.frame_type & 1; } + // parsers for received messages void parseReportAttributes(Z_attribute_list& attr_list); void generateSyntheticAttributes(Z_attribute_list& attr_list); void removeInvalidAttributes(Z_attribute_list& attr_list); @@ -813,47 +821,59 @@ public: void autoResponder(const uint16_t *attr_list_ids, size_t attr_len); inline void setGroupId(uint16_t groupid) { - _groupaddr = groupid; + groupaddr = groupid; } inline void setClusterId(uint16_t clusterid) { - _cluster_id = clusterid; + cluster = clusterid; } - inline uint16_t getSrcAddr(void) const { return _srcaddr; } - inline uint16_t getGroupAddr(void) const { return _groupaddr; } - inline uint16_t getClusterId(void) const { return _cluster_id; } + inline uint16_t getSrcAddr(void) const { return shortaddr; } + inline uint16_t getGroupAddr(void) const { return groupaddr; } + inline uint16_t getClusterId(void) const { return cluster; } inline uint8_t getLinkQuality(void) const { return _linkquality; } - inline uint8_t getCmdId(void) const { return _cmd_id; } + inline uint8_t getCmdId(void) const { return cmd; } inline uint16_t getSrcEndpoint(void) const { return _srcendpoint; } + const SBuffer &getPayload(void) const { return payload; } + uint16_t getManufCode(void) const { return manuf; } - const SBuffer &getPayload(void) const { - return _payload; - } + inline void setTransac(uint8_t _transac) { transactseq = _transac; transacSet = true; } - uint16_t getManufCode(void) const { - return _manuf_code; - } + inline bool validShortaddr(void) const { return BAD_SHORTADDR != shortaddr; } + inline bool validCluster(void) const { return 0xFFFF != cluster; } + inline bool validEndpoint(void) const { return 0x00 != dstendpoint; } + inline bool validCmd(void) const { return 0xFF != cmd; } - -private: - ZCLHeaderFrameControl_t _frame_control = { .d8 = 0 }; - uint16_t _manuf_code = 0; // optional - uint8_t _transact_seq = 0; // transaction sequence number - uint8_t _cmd_id = 0; - SBuffer _payload; - uint16_t _cluster_id = 0; - uint16_t _groupaddr = 0; +public: + uint16_t manuf = 0; // optional + uint8_t transactseq = 0; // transaction sequence number + uint8_t cmd = 0; + SBuffer payload; + uint16_t cluster = 0; + uint16_t groupaddr = 0; // information from decoded ZCL frame - uint16_t _srcaddr; - uint8_t _srcendpoint; - uint8_t _dstendpoint; - uint8_t _wasbroadcast; - uint8_t _linkquality; - uint8_t _securityuse; - uint8_t _seqnumber; + uint16_t shortaddr = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid + uint8_t dstendpoint = 0x00; // 0x00 is invalid for the dst endpoint + // attributes used in send-only mode + bool clusterSpecific = false; + bool needResponse = true; + bool direct = false; // true if direct, false if discover router + bool transacSet = false; // is transac already set + + // below private attributes are not used when sending a message +private: + uint8_t _srcendpoint = 0x00; // 0x00 is invalid for the src endpoint + ZCLHeaderFrameControl_t _frame_control = { .d8 = 0 }; + bool _wasbroadcast = false; + uint8_t _linkquality = 0x00; + uint8_t _securityuse = 0; // not used by Z2T, logging only + uint8_t _seqnumber = 0; // not used by Z2T, logging only }; +// define constructor seperately to avoid inlining and reduce Flash size +ZCLFrame::ZCLFrame(void) : payload(12) {}; +ZCLFrame::ZCLFrame(size_t size) : payload(size) {}; + // Zigbee ZCL converters // from https://github.com/Koenkk/zigbee-shepherd-converters/blob/638d29f0cace6343052b9a4e7fd60980fa785479/converters/fromZigbee.js#L55 @@ -1197,45 +1217,45 @@ uint32_t parseSingleAttribute(Z_attribute & attr, const SBuffer &buf, // First pass, parse all attributes in their native format void ZCLFrame::parseReportAttributes(Z_attribute_list& attr_list) { uint32_t i = 0; - uint32_t len = _payload.len(); + uint32_t len = payload.len(); if (ZCL_WRITE_ATTRIBUTES == getCmdId()) { attr_list.addAttribute(PSTR("Command"), true).setStr(PSTR("Write")); } while (len >= i + 3) { - uint16_t attrid = _payload.get16(i); + uint16_t attrid = payload.get16(i); i += 2; // exception for Xiaomi lumi.weather - specific field to be treated as octet and not char - if ((0x0000 == _cluster_id) && (0xFF01 == attrid)) { - if (0x42 == _payload.get8(i)) { - _payload.set8(i, 0x41); // change type from 0x42 to 0x41 + if ((0x0000 == cluster) && (0xFF01 == attrid)) { + if (0x42 == payload.get8(i)) { + payload.set8(i, 0x41); // change type from 0x42 to 0x41 } } // TODO look for suffix - Z_attribute & attr = attr_list.addAttribute(_cluster_id, attrid); + Z_attribute & attr = attr_list.addAttribute(cluster, attrid); - i += parseSingleAttribute(attr, _payload, i); + i += parseSingleAttribute(attr, payload, i); } // Issue Philips outdoor motion sensor SML002, see https://github.com/Koenkk/zigbee2mqtt/issues/897 // The sensor expects the coordinator to send a Default Response to acknowledge the attribute reporting if (0 == _frame_control.b.disable_def_resp) { // the device expects a default response - ZCLMessage zcl(2); // message is 2 bytes - zcl.shortaddr = _srcaddr; - zcl.cluster = _cluster_id; - zcl.endpoint = _srcendpoint; + ZCLFrame zcl(2); // message is 2 bytes + zcl.shortaddr = shortaddr; + zcl.cluster = cluster; + zcl.dstendpoint = _srcendpoint; zcl.cmd = ZCL_DEFAULT_RESPONSE; - zcl.manuf = _manuf_code; + zcl.manuf = manuf; zcl.clusterSpecific = false; /* not cluster specific */ zcl.needResponse = false; /* noresponse */ zcl.direct = true; /* direct no retry */ - zcl.setTransac(_transact_seq); - zcl.buf.add8(_cmd_id); - zcl.buf.add8(0); // Status = OK + zcl.setTransac(transactseq); + zcl.payload.add8(cmd); + zcl.payload.add8(0); // Status = OK zigbeeZCLSendCmd(zcl); } } @@ -1295,8 +1315,8 @@ void ZCLFrame::removeInvalidAttributes(Z_attribute_list& attr_list) { // Note: both function are now split to compute on extracted attributes // void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) { - const Z_Device & device = zigbee_devices.findShortAddr(_srcaddr); - const char * model_c = zigbee_devices.getModelId(_srcaddr); // null if unknown + const Z_Device & device = zigbee_devices.findShortAddr(shortaddr); + const char * model_c = zigbee_devices.getModelId(shortaddr); // null if unknown String modelId((char*) model_c); // scan through attributes and apply specific converters for (auto &attr : attr_list) { @@ -1324,7 +1344,7 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) { case 0x02010008: // Pi Heating Demand - solve Eutotronic bug case 0x02014008: // Eurotronic Host Flags decoding { - const char * manufacturer_c = zigbee_devices.getManufacturerId(_srcaddr); // null if unknown + const char * manufacturer_c = zigbee_devices.getManufacturerId(shortaddr); // null if unknown String manufacturerId((char*) manufacturer_c); if (manufacturerId.equals(F("Eurotronic"))) { if (ccccaaaa == 0x02010008) { @@ -1382,7 +1402,7 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) { } break; case 0x05000002: // ZoneStatus - const Z_Data_Alarm & alarm = (const Z_Data_Alarm&) zigbee_devices.getShortAddr(_srcaddr).data.find(Z_Data_Type::Z_Alarm, _srcendpoint); + const Z_Data_Alarm & alarm = (const Z_Data_Alarm&) zigbee_devices.getShortAddr(shortaddr).data.find(Z_Data_Type::Z_Alarm, _srcendpoint); if (&alarm != nullptr) { alarm.convertZoneStatus(attr_list, attr.getUInt()); } @@ -1405,15 +1425,15 @@ void ZCLFrame::generateCallBacks(Z_attribute_list& attr_list) { uint32_t occupancy = attr.getUInt(); if (occupancy) { uint32_t pir_timer = OCCUPANCY_TIMEOUT; - const Z_Data_PIR & pir_found = (const Z_Data_PIR&) zigbee_devices.getShortAddr(_srcaddr).data.find(Z_Data_Type::Z_PIR, _srcendpoint); + const Z_Data_PIR & pir_found = (const Z_Data_PIR&) zigbee_devices.getShortAddr(shortaddr).data.find(Z_Data_Type::Z_PIR, _srcendpoint); if (&pir_found != nullptr) { pir_timer = pir_found.getTimeoutSeconds() * 1000; } if (pir_timer > 0) { - zigbee_devices.setTimer(_srcaddr, 0 /* groupaddr */, pir_timer, _cluster_id, _srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback); + zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, pir_timer, cluster, _srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback); } } else { - zigbee_devices.resetTimersForDevice(_srcaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY); + zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY); } break; } @@ -1460,16 +1480,16 @@ void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uin // ZCL_READ_ATTRIBUTES void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) { uint32_t i = 0; - uint32_t len = _payload.len(); + uint32_t len = payload.len(); uint16_t read_attr_ids[len/2]; - attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_CLUSTER)).setUInt(_cluster_id); + attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_CLUSTER)).setUInt(cluster); JsonGeneratorArray attr_numbers; Z_attribute_list attr_names; while (len >= 2 + i) { - uint16_t attrid = _payload.get16(i); + uint16_t attrid = payload.get16(i); attr_numbers.add(attrid); read_attr_ids[i/2] = attrid; @@ -1479,7 +1499,7 @@ void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) { uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); uint16_t conv_attribute = pgm_read_word(&converter->attribute); - if ((conv_cluster == _cluster_id) && (conv_attribute == attrid)) { + if ((conv_cluster == cluster) && (conv_attribute == attrid)) { attr_names.addAttribute(Z_strings + pgm_read_word(&converter->name_offset), true).setBool(true); break; } @@ -1490,29 +1510,29 @@ void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) { attr_list.addAttributePMEM(PSTR("ReadNames")).setStrRaw(attr_names.toString(true).c_str()); // call auto-responder only if src address if different from ourselves and it was a broadcast - if (_srcaddr != localShortAddr || !_wasbroadcast) { + if (shortaddr != localShortAddr || !_wasbroadcast) { autoResponder(read_attr_ids, len/2); } } // ZCL_CONFIGURE_REPORTING_RESPONSE void ZCLFrame::parseConfigAttributes(Z_attribute_list& attr_list) { - uint32_t len = _payload.len(); + uint32_t len = payload.len(); Z_attribute_list attr_config_list; for (uint32_t i=0; len >= i+4; i+=4) { - uint8_t status = _payload.get8(i); - uint16_t attr_id = _payload.get8(i+2); + uint8_t status = payload.get8(i); + uint16_t attr_id = payload.get8(i+2); Z_attribute_list attr_config_response; attr_config_response.addAttributePMEM(PSTR("Status")).setUInt(status); attr_config_response.addAttributePMEM(PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str()); - const __FlashStringHelper* attr_name = zigbeeFindAttributeById(_cluster_id, attr_id, nullptr, nullptr); + const __FlashStringHelper* attr_name = zigbeeFindAttributeById(cluster, attr_id, nullptr, nullptr); if (attr_name) { attr_config_list.addAttribute(attr_name).setStrRaw(attr_config_response.toString(true).c_str()); } else { - attr_config_list.addAttribute(_cluster_id, attr_id).setStrRaw(attr_config_response.toString(true).c_str()); + attr_config_list.addAttribute(cluster, attr_id).setStrRaw(attr_config_response.toString(true).c_str()); } } @@ -1522,21 +1542,21 @@ void ZCLFrame::parseConfigAttributes(Z_attribute_list& attr_list) { // ZCL_WRITE_ATTRIBUTES_RESPONSE void ZCLFrame::parseWriteAttributesResponse(Z_attribute_list& attr_list) { - parseResponse_inner(ZCL_WRITE_ATTRIBUTES_RESPONSE, false, _payload.get8(0)); + parseResponse_inner(ZCL_WRITE_ATTRIBUTES_RESPONSE, false, payload.get8(0)); } // ZCL_READ_REPORTING_CONFIGURATION_RESPONSE void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) { uint32_t i = 0; - uint32_t len = _payload.len(); + uint32_t len = payload.len(); Z_attribute &attr_root = attr_list.addAttributePMEM(PSTR("ReadConfig")); Z_attribute_list attr_1; while (len >= i + 4) { - uint8_t status = _payload.get8(i); - uint8_t direction = _payload.get8(i+1); - uint16_t attrid = _payload.get16(i+2); + uint8_t status = payload.get8(i); + uint8_t direction = payload.get8(i+1); + uint16_t attrid = payload.get16(i+2); Z_attribute_list attr_2; if (direction) { @@ -1550,7 +1570,7 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) { uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); uint16_t conv_attribute = pgm_read_word(&converter->attribute); - if ((conv_cluster == _cluster_id) && (conv_attribute == attrid)) { + if ((conv_cluster == cluster) && (conv_attribute == attrid)) { const char * attr_name = Z_strings + pgm_read_word(&converter->name_offset); attr_2.addAttribute(attr_name, true).setBool(true); multiplier = CmToMultiplier(pgm_read_byte(&converter->multiplier_idx)); @@ -1565,22 +1585,22 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) { // no error, decode data if (direction) { // only Timeout period is present - uint16_t attr_timeout = _payload.get16(i); + uint16_t attr_timeout = payload.get16(i); i += 2; attr_2.addAttributePMEM(PSTR("TimeoutPeriod")).setUInt((0xFFFF == attr_timeout) ? -1 : attr_timeout); } else { // direction == 0, we have a data type - uint8_t attr_type = _payload.get8(i); + uint8_t attr_type = payload.get8(i); bool attr_discrete = Z_isDiscreteDataType(attr_type); - uint16_t attr_min_interval = _payload.get16(i+1); - uint16_t attr_max_interval = _payload.get16(i+3); + uint16_t attr_min_interval = payload.get16(i+1); + uint16_t attr_max_interval = payload.get16(i+3); i += 5; attr_2.addAttributePMEM(PSTR("MinInterval")).setUInt((0xFFFF == attr_min_interval) ? -1 : attr_min_interval); attr_2.addAttributePMEM(PSTR("MaxInterval")).setUInt((0xFFFF == attr_max_interval) ? -1 : attr_max_interval); if (!attr_discrete) { // decode Reportable Change Z_attribute &attr_change = attr_2.addAttributePMEM(PSTR("ReportableChange")); - i += parseSingleAttribute(attr_change, _payload, i, attr_type); + i += parseSingleAttribute(attr_change, payload, i, attr_type); if ((1 != multiplier) && (0 != multiplier)) { float fval = attr_change.getFloat(); if (multiplier > 0) { fval = fval * multiplier; } @@ -1590,7 +1610,7 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) { } } } - attr_1.addAttribute(_cluster_id, attrid).setStrRaw(attr_2.toString(true).c_str()); + attr_1.addAttribute(cluster, attrid).setStrRaw(attr_2.toString(true).c_str()); } attr_root.setStrRaw(attr_1.toString(true).c_str()); } @@ -1598,16 +1618,16 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) { // ZCL_READ_ATTRIBUTES_RESPONSE void ZCLFrame::parseReadAttributesResponse(Z_attribute_list& attr_list) { uint32_t i = 0; - uint32_t len = _payload.len(); + uint32_t len = payload.len(); while (len >= i + 4) { - uint16_t attrid = _payload.get16(i); + uint16_t attrid = payload.get16(i); i += 2; - uint8_t status = _payload.get8(i++); + uint8_t status = payload.get8(i++); if (0 == status) { - Z_attribute & attr = attr_list.addAttribute(_cluster_id, attrid); - i += parseSingleAttribute(attr, _payload, i); + Z_attribute & attr = attr_list.addAttribute(cluster, attrid); + i += parseSingleAttribute(attr, payload, i); } } } @@ -1618,15 +1638,15 @@ void ZCLFrame::parseResponse_inner(uint8_t cmd, bool cluster_specific, uint8_t s // "Device" char s[12]; - snprintf_P(s, sizeof(s), PSTR("0x%04X"), _srcaddr); + snprintf_P(s, sizeof(s), PSTR("0x%04X"), shortaddr); attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_DEVICE)).setStr(s); // "Name" - const char * friendlyName = zigbee_devices.getFriendlyName(_srcaddr); + const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); if (friendlyName) { attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_NAME)).setStr(friendlyName); } // "Command" - snprintf_P(s, sizeof(s), PSTR("%04X%c%02X"), _cluster_id, cluster_specific ? '!' : '_', cmd); + snprintf_P(s, sizeof(s), PSTR("%04X%c%02X"), cluster, cluster_specific ? '!' : '_', cmd); attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_CMD)).setStr(s); // "Status" attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_STATUS)).setUInt(status); @@ -1635,8 +1655,8 @@ void ZCLFrame::parseResponse_inner(uint8_t cmd, bool cluster_specific, uint8_t s // Add Endpoint attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_ENDPOINT)).setUInt(_srcendpoint); // Add Group if non-zero - if (_groupaddr) { // TODO what about group zero - attr_list.group_id = _groupaddr; + if (groupaddr) { // TODO what about group zero + attr_list.group_id = groupaddr; } // Add linkquality attr_list.lqi = _linkquality; @@ -1647,9 +1667,9 @@ void ZCLFrame::parseResponse_inner(uint8_t cmd, bool cluster_specific, uint8_t s // ZCL_DEFAULT_RESPONSE void ZCLFrame::parseResponse(void) { - if (_payload.len() < 2) { return; } // wrong format - uint8_t cmd = _payload.get8(0); - uint8_t status = _payload.get8(1); + if (payload.len() < 2) { return; } // wrong format + uint8_t cmd = payload.get8(0); + uint8_t status = payload.get8(1); parseResponse_inner(cmd, true, status); } @@ -1665,22 +1685,22 @@ void Z_ResetDebounce(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, u // Parse non-normalized attributes void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) { // Check if debounce is active and if the packet is a duplicate - Z_Device & device = zigbee_devices.getShortAddr(_srcaddr); - if ((device.debounce_endpoint != 0) && (device.debounce_endpoint == _srcendpoint) && (device.debounce_transact == _transact_seq)) { + Z_Device & device = zigbee_devices.getShortAddr(shortaddr); + if ((device.debounce_endpoint != 0) && (device.debounce_endpoint == _srcendpoint) && (device.debounce_transact == transactseq)) { // this is a duplicate, drop the packet - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Discarding duplicate command from 0x%04X, endpoint %d"), _srcaddr, _srcendpoint); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Discarding duplicate command from 0x%04X, endpoint %d"), shortaddr, _srcendpoint); } else { // reset the duplicate marker, parse the packet normally, and set a timer to reset the marker later (which will discard any existing timer for the same device/endpoint) device.debounce_endpoint = _srcendpoint; - device.debounce_transact = _transact_seq; - zigbee_devices.setTimer(_srcaddr, 0 /* groupaddr */, USE_ZIGBEE_DEBOUNCE_COMMANDS, 0 /*clusterid*/, _srcendpoint, Z_CAT_DEBOUNCE_CMD, 0, &Z_ResetDebounce); + device.debounce_transact = transactseq; + zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, USE_ZIGBEE_DEBOUNCE_COMMANDS, 0 /*clusterid*/, _srcendpoint, Z_CAT_DEBOUNCE_CMD, 0, &Z_ResetDebounce); - convertClusterSpecific(attr_list, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload); + convertClusterSpecific(attr_list, cluster, cmd, _frame_control.b.direction, shortaddr, _srcendpoint, payload); if (!Settings->flag5.zb_disable_autoquery) { // read attributes unless disabled if (!_frame_control.b.direction) { // only handle server->client (i.e. device->coordinator) if (_wasbroadcast) { // only update for broadcast messages since we don't see unicast from device to device and we wouldn't know the target - sendHueUpdate(BAD_SHORTADDR, _groupaddr, _cluster_id); + sendHueUpdate(BAD_SHORTADDR, groupaddr, cluster); } } } @@ -1688,18 +1708,18 @@ void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) { // Send Default Response to acknowledge the attribute reporting if (0 == _frame_control.b.disable_def_resp) { // the device expects a default response - ZCLMessage zcl(2); // message is 4 bytes - zcl.shortaddr = _srcaddr; - zcl.cluster = _cluster_id; - zcl.endpoint = _srcendpoint; + ZCLFrame zcl(2); // message is 4 bytes + zcl.shortaddr = shortaddr; + zcl.cluster = cluster; + zcl.dstendpoint = _srcendpoint; zcl.cmd = ZCL_DEFAULT_RESPONSE; - zcl.manuf = _manuf_code; + zcl.manuf = manuf; zcl.clusterSpecific = false; /* not cluster specific */ zcl.needResponse = false; /* noresponse */ zcl.direct = true; /* direct no retry */ - zcl.setTransac(_transact_seq); - zcl.buf.add8(_cmd_id); - zcl.buf.add8(0x00); // Status = OK + zcl.setTransac(transactseq); + zcl.payload.add8(cmd); + zcl.payload.add8(0x00); // Status = OK zigbeeZCLSendCmd(zcl); } } @@ -1707,7 +1727,7 @@ void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) { // ====================================================================== // Convert AnalogValue according to the device type void ZCLFrame::syntheticAnalogValue(Z_attribute_list &attr_list, class Z_attribute &attr) { - const char * modelId_c = zigbee_devices.getModelId(_srcaddr); // null if unknown + const char * modelId_c = zigbee_devices.getModelId(shortaddr); // null if unknown String modelId((char*) modelId_c); if (modelId.startsWith(F("lumi.sensor_cube"))) { @@ -1731,7 +1751,7 @@ void ZCLFrame::syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribu uint32_t i = 0; uint32_t len = buf2.len(); - const char * modelId_c = zigbee_devices.getModelId(_srcaddr); // null if unknown + const char * modelId_c = zigbee_devices.getModelId(shortaddr); // null if unknown String modelId((char*) modelId_c); while (len >= 2 + i) { @@ -1830,7 +1850,7 @@ void ZCLFrame::syntheticAqaraSensor2(class Z_attribute_list &attr_list, class Z_ // Aqara Cube and Button void ZCLFrame::syntheticAqaraCubeOrButton(class Z_attribute_list &attr_list, class Z_attribute &attr) { - const char * modelId_c = zigbee_devices.findShortAddr(_srcaddr).modelId; // null if unknown + const char * modelId_c = zigbee_devices.findShortAddr(shortaddr).modelId; // null if unknown String modelId((char*) modelId_c); if (modelId.startsWith(F("lumi.sensor_cube"))) { // only for Aqara cube diff --git a/tasmota/xdrv_23_zigbee_3_hue.ino b/tasmota/xdrv_23_zigbee_6_5_hue.ino similarity index 99% rename from tasmota/xdrv_23_zigbee_3_hue.ino rename to tasmota/xdrv_23_zigbee_6_5_hue.ino index 0485e244a..33d6c9a61 100644 --- a/tasmota/xdrv_23_zigbee_3_hue.ino +++ b/tasmota/xdrv_23_zigbee_6_5_hue.ino @@ -152,14 +152,14 @@ void ZigbeeHueGroups(String * lights) { } void ZigbeeSendHue(uint16_t shortaddr, uint16_t cluster, uint8_t cmd, const SBuffer & s) { - ZCLMessage zcl(s.len()); + ZCLFrame zcl(s.len()); zcl.shortaddr = shortaddr; zcl.cluster = cluster; zcl.cmd = cmd; zcl.clusterSpecific = true; zcl.needResponse = true; zcl.direct = false; // discover route - zcl.buf.replace(s); + zcl.payload.replace(s); zigbeeZCLSendCmd(zcl); } diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index 9df4a3c60..3921a9aef 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -183,16 +183,16 @@ void Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster shortaddr = BAD_SHORTADDR; // if group address, don't send to device } - ZCLMessage zcl(attrs_len); // message is `attrs_len` bytes + ZCLFrame zcl(attrs_len); // message is `attrs_len` bytes zcl.shortaddr = shortaddr; zcl.groupaddr = groupaddr; zcl.cluster = cluster; - zcl.endpoint = endpoint; + zcl.dstendpoint = endpoint; zcl.cmd = ZCL_READ_ATTRIBUTES; zcl.clusterSpecific = false; zcl.needResponse = true; zcl.direct = false; // discover route - zcl.buf.addBuffer(attrs, attrs_len); + zcl.payload.addBuffer(attrs, attrs_len); zigbeeZCLSendCmd(zcl); } } diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index f728e1827..348e8e7b7 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -1380,15 +1380,15 @@ void Z_SendSimpleDescReq(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluste // Iterate among // void Z_SendDeviceInfoRequest(uint16_t shortaddr) { - ZCLMessage zcl(4); // message is 4 bytes + ZCLFrame zcl(4); // message is 4 bytes zcl.shortaddr = shortaddr; zcl.cluster = 0; zcl.cmd = ZCL_READ_ATTRIBUTES; zcl.clusterSpecific = false; zcl.needResponse = true; zcl.direct = false; // discover route - zcl.buf.add16(0x0005); - zcl.buf.add16(0x0004); + zcl.payload.add16(0x0005); + zcl.payload.add16(0x0004); zigbeeZCLSendCmd(zcl); } @@ -1396,15 +1396,15 @@ void Z_SendDeviceInfoRequest(uint16_t shortaddr) { // Send single attribute read request in Timer // void Z_SendSingleAttributeRead(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - ZCLMessage zcl(2); // message is 2 bytes + ZCLFrame zcl(2); // message is 2 bytes zcl.shortaddr = shortaddr; zcl.cluster = cluster; - zcl.endpoint = endpoint; + zcl.dstendpoint = endpoint; zcl.cmd = ZCL_READ_ATTRIBUTES; zcl.clusterSpecific = false; zcl.needResponse = true; zcl.direct = false; // discover route - zcl.buf.add16(value); // 04000500 + zcl.payload.add16(value); // 04000500 zigbeeZCLSendCmd(zcl); } @@ -1413,17 +1413,17 @@ void Z_SendSingleAttributeRead(uint16_t shortaddr, uint16_t groupaddr, uint16_t // void Z_WriteCIEAddress(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Sending CIE Address for Cluster %d in Endpoint %d of Device 0x%04X"), cluster, endpoint, shortaddr); - ZCLMessage zcl(12); // message is 12 bytes + ZCLFrame zcl(12); // message is 12 bytes zcl.shortaddr = shortaddr; zcl.cluster = 0x0500; - zcl.endpoint = endpoint; + zcl.dstendpoint = endpoint; zcl.cmd = ZCL_WRITE_ATTRIBUTES; zcl.clusterSpecific = false; zcl.needResponse = true; zcl.direct = false; // discover route - zcl.buf.add16(0x0010); // attribute 0x0010 - zcl.buf.add8(ZEUI64); - zcl.buf.add64(localIEEEAddr); + zcl.payload.add16(0x0010); // attribute 0x0010 + zcl.payload.add8(ZEUI64); + zcl.payload.add64(localIEEEAddr); zigbeeZCLSendCmd(zcl); } @@ -1433,16 +1433,16 @@ void Z_WriteCIEAddress(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, // void Z_SendCIEZoneEnrollResponse(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Sending Enroll Zone %d for Cluster %d in Endpoint %d of Device 0x%04X"), Z_B0(value), cluster, endpoint, shortaddr); - ZCLMessage zcl(2); // message is 2 bytes + ZCLFrame zcl(2); // message is 2 bytes zcl.shortaddr = shortaddr; zcl.cluster = 0x0500; - zcl.endpoint = endpoint; + zcl.dstendpoint = endpoint; zcl.cmd = 0x00; // Zone Enroll Response zcl.clusterSpecific = true; zcl.needResponse = true; zcl.direct = false; // discover route - zcl.buf.add8(0x00); // success - zcl.buf.add8(Z_B0(value)); // ZoneID + zcl.payload.add8(0x00); // success + zcl.payload.add8(Z_B0(value)); // ZoneID zigbeeZCLSendCmd(zcl); } @@ -1579,15 +1579,15 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin if (buf.len() > 0) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "auto-bind `%s`"), ResponseData()); - ZCLMessage zcl(buf.len()); // message is 4 bytes + ZCLFrame zcl(buf.len()); // message is 4 bytes zcl.shortaddr = shortaddr; zcl.cluster = cluster; - zcl.endpoint = endpoint; + zcl.dstendpoint = endpoint; zcl.cmd = ZCL_CONFIGURE_REPORTING; zcl.clusterSpecific = false; /* not cluster specific */ zcl.needResponse = false; /* noresponse */ zcl.direct = false; /* discover route */ - zcl.buf.addBuffer(buf); + zcl.payload.addBuffer(buf); zigbeeZCLSendCmd(zcl); } } @@ -1639,6 +1639,11 @@ void Z_IncomingMessage(class ZCLFrame &zcl_received) { // log the packet details zcl_received.log(); +#ifdef USE_BERRY + // Berry pre-process messages + // callBerryZigbeeDispatcher("pre", &zcl_received); +#endif // USE_BERRY + // create the device entry if it does not exist and if it's not the local device Z_Device & device = (srcaddr != localShortAddr) ? zigbee_devices.getShortAddr(srcaddr) : device_unk; @@ -2097,9 +2102,9 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) { for (uint32_t i=0; iflag5.zb_disable_autoquery) { // read back attribute value unless it is disabled - sendHueUpdate(zcl.shortaddr, zcl.groupaddr, zcl.cluster, zcl.endpoint); + sendHueUpdate(zcl.shortaddr, zcl.groupaddr, zcl.cluster, zcl.dstendpoint); } } } @@ -321,15 +321,15 @@ bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_stat // Parse "Report", "Write", "Response" or "Config" attribute // Operation is one of: ZCL_REPORT_ATTRIBUTES (0x0A), ZCL_WRITE_ATTRIBUTES (0x02) or ZCL_READ_ATTRIBUTES_RESPONSE (0x01) // -void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLMessage & zcl) { - zcl.buf.reserve(200); // buffer to store the binary output of attibutes - SBuffer & buf = zcl.buf; // synonym +void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLFrame & zcl) { + zcl.payload.reserve(200); // buffer to store the binary output of attibutes + SBuffer & buf = zcl.payload; // synonym if (nullptr == XdrvMailbox.command) { XdrvMailbox.command = (char*) ""; // prevent a crash when calling ReponseCmndChar and there was no previous command } - bool tuya_protocol = zigbee_devices.isTuyaProtocol(zcl.shortaddr, zcl.endpoint); + bool tuya_protocol = zigbee_devices.isTuyaProtocol(zcl.shortaddr, zcl.dstendpoint); // iterate on keys for (auto key : val_pubwrite.getObject()) { @@ -449,7 +449,7 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLMessage & zc } // Parse the "Send" attribute and send the command -void ZbSendSend(class JsonParserToken val_cmd, ZCLMessage & zcl) { +void ZbSendSend(class JsonParserToken val_cmd, ZCLFrame & zcl) { zcl.clusterSpecific = true; static const char delim[] = ", "; // delimiters for parameters @@ -525,7 +525,7 @@ void ZbSendSend(class JsonParserToken val_cmd, ZCLMessage & zcl) { } else { zcl.cmd = cmd_var; // or simply copy the cmd number } - zigbeeCmdAddParams(zcl.buf, tasmota_cmd, x, y, z); // fill in parameters + zigbeeCmdAddParams(zcl.payload, tasmota_cmd, x, y, z); // fill in parameters } else { // we have zero command, pass through until last error for missing command return; @@ -563,7 +563,7 @@ void ZbSendSend(class JsonParserToken val_cmd, ZCLMessage & zcl) { // delimiter is optional if ('/' == *data) { data++; } // skip delimiter - zcl.buf.replace(SBuffer::SBufferFromHex(data, strlen(data))); + zcl.payload.replace(SBuffer::SBufferFromHex(data, strlen(data))); zigbeeZCLSendCmd(zcl); } else { // we have an unsupported command type @@ -574,7 +574,7 @@ void ZbSendSend(class JsonParserToken val_cmd, ZCLMessage & zcl) { } // Parse the "Send" attribute and send the command -void ZbSendRead(JsonParserToken val_attr, ZCLMessage & zcl) { +void ZbSendRead(JsonParserToken val_attr, ZCLFrame & zcl) { // ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":5} // ZbSend {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Read":"0x0005"} // ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":[5,6,7,4]} @@ -670,9 +670,9 @@ void ZbSendRead(JsonParserToken val_attr, ZCLMessage & zcl) { if (attrs_len > 0) { // all good, send the packet - zcl.buf.reserve(attrs_len); - zcl.buf.setLen(0); // clear any previous buffer - zcl.buf.addBuffer(attrs, attrs_len); + zcl.payload.reserve(attrs_len); + zcl.payload.setLen(0); // clear any previous buffer + zcl.payload.addBuffer(attrs, attrs_len); zigbeeZCLSendCmd(zcl); ResponseCmndDone(); } else { @@ -712,7 +712,7 @@ void CmndZbSend(void) { if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; } // params - ZCLMessage zcl; // prepare the ZCL structure + ZCLFrame zcl; // prepare the ZCL structure // parse "Device" and "Group" JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)]; @@ -733,15 +733,15 @@ void CmndZbSend(void) { // read other parameters zcl.cluster = root.getUInt(PSTR(D_CMND_ZIGBEE_CLUSTER), zcl.cluster); - zcl.endpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), zcl.endpoint); + zcl.dstendpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), zcl.dstendpoint); zcl.manuf = root.getUInt(PSTR(D_CMND_ZIGBEE_MANUF), zcl.manuf); // infer endpoint if (!zcl.validShortaddr()) { - zcl.endpoint = 0xFF; // endpoint not used for group addresses, so use a dummy broadcast endpoint + zcl.dstendpoint = 0xFF; // endpoint not used for group addresses, so use a dummy broadcast endpoint } else if (!zcl.validEndpoint()) { // if it was not already specified, try to guess it - zcl.endpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr); - AddLog(LOG_LEVEL_DEBUG, PSTR("ZIG: guessing endpoint %d"), zcl.endpoint); + zcl.dstendpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr); + AddLog(LOG_LEVEL_DEBUG, PSTR("ZIG: guessing endpoint %d"), zcl.dstendpoint); } if (!zcl.validEndpoint()) { // after this, if it is still zero, then it's an error ResponseCmndChar_P(PSTR("Missing endpoint")); @@ -848,7 +848,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind // Information about source device: "Device", "Endpoint", "Cluster" // - the source endpoint must have a known IEEE address - const Z_Device & src_device = zigbee_devices.parseDeviceFromName(root.getStr(PSTR(D_CMND_ZIGBEE_DEVICE), nullptr)); + const Z_Device & src_device = zigbee_devices.parseDeviceFromName(root.getStr(PSTR(D_CMND_ZIGBEE_DEVICE))); if (!src_device.valid()) { ResponseCmndChar_P(PSTR("Unknown source device")); return; } // check if IEEE address is known uint64_t srcLongAddr = src_device.longaddr; @@ -961,7 +961,7 @@ void CmndZbUnbind(void) { // void CmndZbLeave(void) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data).shortaddr; + uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload).shortaddr; if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } #ifdef USE_ZIGBEE_ZNP @@ -993,7 +993,7 @@ void CmndZbLeave(void) { void CmndZbBindState_or_Map(bool map) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } uint16_t parsed_shortaddr;; - uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, &parsed_shortaddr).shortaddr; + uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, &parsed_shortaddr, XdrvMailbox.payload).shortaddr; if (BAD_SHORTADDR == shortaddr) { if ((map) && (parsed_shortaddr != shortaddr)) { shortaddr = parsed_shortaddr; // allow a non-existent address when ZbMap @@ -1069,7 +1069,7 @@ void CmndZbProbe(void) { // void CmndZbProbeOrPing(boolean probe) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data).shortaddr; + uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload).shortaddr; if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } // set a timer for Reachable - 2s default value @@ -1107,7 +1107,7 @@ void CmndZbName(void) { strtok_r(XdrvMailbox.data, ",", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // it's the only case where we create a new device + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // it's the only case where we create a new device if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p == nullptr) { @@ -1139,7 +1139,7 @@ void CmndZbModelId(void) { strtok_r(XdrvMailbox.data, ",", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p != nullptr) { @@ -1166,7 +1166,7 @@ void CmndZbLight(void) { strtok_r(XdrvMailbox.data, ", ", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p) { @@ -1210,7 +1210,7 @@ void CmndZbOccupancy(void) { strtok_r(XdrvMailbox.data, ", ", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } int8_t occupancy_time = -1; @@ -1237,7 +1237,7 @@ void CmndZbOccupancy(void) { // void CmndZbForget(void) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } // everything is good, we can send the command @@ -1267,7 +1267,7 @@ void CmndZbInfo(void) { CmndZbInfo_inner(device); } } else { // try JSON - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } // everything is good, we can send the command @@ -1337,7 +1337,7 @@ void CmndZbenroll(void) { if ((XdrvMailbox.data_len) && (ArgC() > 1)) { // Process parameter entry char argument[XdrvMailbox.data_len]; - Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1)); + Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1), nullptr, XdrvMailbox.payload); int enrollEndpoint = atoi(ArgV(argument, 2)); if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } @@ -1355,7 +1355,7 @@ void CmndZbcie(void) { if ((XdrvMailbox.data_len) && (ArgC() > 1)) { // Process parameter entry char argument[XdrvMailbox.data_len]; - Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1)); + Z_Device & device = zigbee_devices.parseDeviceFromName(ArgV(argument, 1), nullptr, XdrvMailbox.payload); int enrollEndpoint = atoi(ArgV(argument, 2)); if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } @@ -1576,7 +1576,7 @@ void CmndZbStatus(void) { if (0 == XdrvMailbox.index) { dump = zigbee_devices.dumpCoordinator(); } else { - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); if (XdrvMailbox.data_len > 0) { if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device); @@ -1608,7 +1608,7 @@ void CmndZbData(void) { strtok_r(XdrvMailbox.data, ",", &p); // parse first part, - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } if (p) {