From 91724dc8c123a036ebd9cd4e140c6a63ffa4645e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 16 May 2022 13:30:20 +0200 Subject: [PATCH 01/12] Update README.md --- lib/lib_basic/OneWire-Stickbreaker/README.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/lib_basic/OneWire-Stickbreaker/README.md b/lib/lib_basic/OneWire-Stickbreaker/README.md index fcc566fbf..39dbbbad7 100644 --- a/lib/lib_basic/OneWire-Stickbreaker/README.md +++ b/lib/lib_basic/OneWire-Stickbreaker/README.md @@ -1,11 +1,6 @@ # OneWire library - A modification of the Arduino OneWire library maintained by @PaulStoffregen. This modifications supports the ESP32 under the Arduino-esp32 Environment. - - No changes are required for compatibility with Arduino coding. + A @stickbreaker @arendst modified version of the Arduino OneWire library maintained by @PaulStoffregen. + This modifications supports the ESP8266, ESP32, ESP32c3, ESP32s2 and ESP32s3 under the Arduino-esp32 Environment. + -Original Source is Paul's 2.3 version. Forked 28DEC2017 - -@stickbreaker -V2.3.1 30APR2018 add IRAM_ATTR to read_bit() write_bit() to solve ICache miss timing failure. - thanks @everslick re: https://github.com/espressif/arduino-esp32/issues/1335 -V2.3 28DEC2017 original mods to support ESP32 +Original Source is Paul's 2.3 version. From d4e4440a40bcb2499e505ac9ad4ef0c7e4ee8f0c Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Mon, 16 May 2022 19:17:40 +0200 Subject: [PATCH 02/12] 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) { From b1edb98495449888a280ed4aa05fadc393675bf1 Mon Sep 17 00:00:00 2001 From: TID Date: Tue, 17 May 2022 13:33:36 +0200 Subject: [PATCH 03/12] Update pl_PL.h --- tasmota/language/pl_PL.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 81b2bf557..a8b514340 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v10.1.0.7 - Last update 04.02.2022 + * Updated until v11.1.0.3 - Last update 17.05.2022 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -140,7 +140,7 @@ #define D_PASSWORD "Hasło" #define D_PH "pH" #define D_MQ "MQ" -#define D_PARTITION "Partition" // As in flash and firmware partition +#define D_PARTITION "Partycja" // As in flash and firmware partition #define D_PORT "Port" #define D_POWER_FACTOR "Cosinus fi" #define D_POWERUSAGE "Moc" @@ -184,7 +184,7 @@ #define D_UPGRADE "aktualizacji" #define D_UPLOAD "Wgraj" #define D_UPTIME "Czas pracy" -#define D_USED "used" +#define D_USED "użyte" #define D_USER "Użytkownik" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indeks UV" @@ -203,8 +203,8 @@ #define D_WEIGHT "Waga" #define D_WARMLIGHT "Temperatura światła" #define D_WEB_SERVER "Serwer Web" -#define D_SOC "State of Charge" -#define D_SOH "State of Health" +#define D_SOC "Stan naładowania" +#define D_SOH "Kondycja" // tasmota.ino #define D_WARNING_MINIMAL_VERSION "UWAGA Ta wersja nie obsługuje zapisu ustawień" From 54dfead6d998d76263d34300db67d79c26785b88 Mon Sep 17 00:00:00 2001 From: Paul C Diem Date: Tue, 17 May 2022 08:11:56 -0500 Subject: [PATCH 04/12] Use adjusted bri for LED's after timeout --- tasmota/tasmota.ino | 1 + tasmota/xdrv_04_light.ino | 5 ++++- tasmota/xdrv_35_pwm_dimmer.ino | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index dc815a21b..d15cfc001 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -240,6 +240,7 @@ struct TasmotaGlobal_t { uint8_t discovery_counter; // Delayed discovery counter #ifdef USE_PWM_DIMMER uint8_t restore_powered_off_led_counter; // Seconds before powered-off LED (LEDLink) is restored + uint8_t pwm_dimmer_led_bri; // Adjusted brightness LED level #endif // USE_PWM_DIMMER #ifndef SUPPORT_IF_STATEMENT diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 0ecdeffca..4a11cabf6 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -2168,7 +2168,10 @@ void LightSetOutputs(const uint16_t *cur_col_10) { #ifdef USE_PWM_DIMMER // Animate brightness LEDs to follow PWM dimmer brightness - if (PWM_DIMMER == TasmotaGlobal.module_type) PWMDimmerSetBrightnessLeds(change10to8(max_col)); + if (PWM_DIMMER == TasmotaGlobal.module_type) { + TasmotaGlobal.pwm_dimmer_led_bri = change10to8(max_col); + PWMDimmerSetBrightnessLeds(-1); + } #endif // USE_PWM_DIMMER } // char msg[24]; diff --git a/tasmota/xdrv_35_pwm_dimmer.ino b/tasmota/xdrv_35_pwm_dimmer.ino index d95e5c03d..4a8587dc8 100644 --- a/tasmota/xdrv_35_pwm_dimmer.ino +++ b/tasmota/xdrv_35_pwm_dimmer.ino @@ -152,7 +152,7 @@ void PWMModulePreInit(void) #endif // USE_PWM_DIMMER_REMOTE } -// bri: -1 = set to current light bri, -2 = timeout, 0-255 = set to bri +// bri: -1 = set to last local light bri, -2 = timeout, 0-255 = set to bri void PWMDimmerSetBrightnessLeds(int32_t bri) { // Find out how many of the LEDs have their ledmask bit set. @@ -169,7 +169,7 @@ void PWMDimmerSetBrightnessLeds(int32_t bri) if (leds) { led_timeout_seconds = 5; if (bri < 0) { - bri = ((bri == -2 && Settings->flag4.led_timeout) || !Light.power ? 0 : light_state.getBri()); + bri = ((bri == -2 && Settings->flag4.led_timeout) || !Light.power ? 0 : TasmotaGlobal.pwm_dimmer_led_bri); if (!bri || !Settings->flag4.led_timeout) led_timeout_seconds = 0; } @@ -438,13 +438,13 @@ void PWMDimmerHandleButton(uint32_t button_index, bool pressed) if (!active_remote_pwm_dimmer) { #endif // USE_PWM_DIMMER_REMOTE - // Toggle the powered-off LED option. + // Toggle the LED timeout. if (down_button_tapped) { Settings->flag4.led_timeout ^= 1; if (Light.power) PWMDimmerSetBrightnessLeds(Settings->flag4.led_timeout ? 0 : -1); } - // Toggle the LED timeout. + // Toggle the powered-off LED option. else { Settings->flag4.powered_off_led ^= 1; PWMDimmerSetPoweredOffLed(); From e496e368262abab28781ea6dafdf4c4f3de9e2f0 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 19 May 2022 13:37:18 +0200 Subject: [PATCH 05/12] SPM updated with latest knowledge SPM updated with latest knowledge - No functional change --- tasmota/xdrv_86_esp32_sonoff_spm.ino | 162 ++++++++++++++++----------- 1 file changed, 97 insertions(+), 65 deletions(-) diff --git a/tasmota/xdrv_86_esp32_sonoff_spm.ino b/tasmota/xdrv_86_esp32_sonoff_spm.ino index 55b91e1c1..7c9c37246 100644 --- a/tasmota/xdrv_86_esp32_sonoff_spm.ino +++ b/tasmota/xdrv_86_esp32_sonoff_spm.ino @@ -137,16 +137,15 @@ #define SSPM_FUNC_SET_TIME 12 // 0x0C #define SSPM_FUNC_IAMHERE 13 // 0x0D #define SSPM_FUNC_INIT_SCAN 16 // 0x10 -#define SSPM_FUNC_UPLOAD_HEADER 20 // 0x14 - Upload header +#define SSPM_FUNC_UPLOAD_HEADER 20 // 0x14 - SPI Upload header #define SSPM_FUNC_UNITS 21 // 0x15 #define SSPM_FUNC_GET_ENERGY_TOTAL 22 // 0x16 #define SSPM_FUNC_GET_ENERGY 24 // 0x18 #define SSPM_FUNC_GET_LOG 26 // 0x1A #define SSPM_FUNC_ENERGY_PERIOD 27 // 0x1B #define SSPM_FUNC_RESET 28 // 0x1C - Remove device from eWelink and factory reset -#define SSPM_FUNC_ARM_RESTART 30 // 0x1E - Restart ARM -#define SSPM_FUNC_UPLOAD_DATA 31 // 0x1F - Upload incremental data blocks of max 512 bytes to ARM -#define SSPM_FUNC_UPLOAD_DONE 33 // 0x21 - Finish upload +#define SSPM_FUNC_UPLOAD_DATA 31 // 0x1F - SPI Upload incremental data blocks of max 512 bytes to ARM +#define SSPM_FUNC_UPLOAD_DONE 33 // 0x21 - SPI Finish upload #define SSPM_FUNC_GET_NEW1 37 // 0x25 // From ARM to ESP @@ -155,6 +154,7 @@ #define SSPM_FUNC_SCAN_START 15 // 0x0F #define SSPM_FUNC_SCAN_RESULT 19 // 0x13 #define SSPM_FUNC_SCAN_DONE 25 // 0x19 +#define SSPM_FUNC_UPLOAD_DONE_ACK 30 // 0x1E - Restart ARM // Unknown #define SSPM_FUNC_01 1 // 0x01 @@ -535,6 +535,20 @@ void SSPMSendCmnd(uint32_t command) { /*********************************************************************************************/ +void SSPMSendFindAck(void) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 01 00 00 FC 73 + Marker |Module id |Ac|Cm|Size | |Ix|Chksm| + */ + SSPMInitSend(); + SspmBuffer[15] = 0x80; // Ack +// SspmBuffer[16] = SSPM_FUNC_FIND; // 0x00 + SspmBuffer[18] = 1; + SspmBuffer[19] = 0; + SSPMSend(23); +} + void SSPMSendOPS(uint32_t relay) { /* Overload Protection @@ -799,21 +813,6 @@ void SSPMSendInitScan(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: Start relay scan...")); } -void SSPMSendUploadHeader(void) { - /* - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 - AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 14 00 0b 09 09 00 1b e5 a4 c7 00 02 88 74 00 6d df - Marker | | |Cm|Size | |Checksum |UploadSize |Ix|Chksm| - */ - SSPMInitSend(); - SspmBuffer[16] = SSPM_FUNC_UPLOAD_HEADER; // 0x14 - SspmBuffer[18] = 0x0B; - - - SspmBuffer[30] = 0; - SSPMSend(33); -} - void SSPMSendGetEnergyTotal(uint32_t relay) { /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @@ -923,49 +922,6 @@ void SSPMSendGetEnergyPeriod(uint32_t relay) { } -void SSPMSendArmRestart(void) { - /* - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 - aa 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 01 00 01 fe 05 - Marker | | |Cm|Size | |Ix|Chksm| - */ - SSPMInitSend(); - SspmBuffer[16] = SSPM_FUNC_ARM_RESTART; // 0x1E - SspmBuffer[18] = 1; - Sspm->command_sequence++; - SspmBuffer[20] = Sspm->command_sequence; - SSPMSend(23); -} - -void SSPMSendUpload(void) { - /* - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 539 540 541 542 543 544 545 - AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 02 0c 00 00 00 00 00 00 02 00 a2 99 c3 22 00 00 01 20 cd 95 01 08 ... 04 48 af f3 01 xx yy - AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 02 0c 00 00 02 00 00 00 02 00 27 f7 24 87 00 80 01 23 23 70 10 bd ... 21 fa 04 f3 02 xx yy - ... - AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 02 0c 00 02 86 00 00 00 02 00 f8 f5 25 6d f1 61 00 08 02 01 ff 00 ... 44 xx yy - AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 80 00 02 88 00 00 00 00 74 95 4e 01 c1 c5 e5 02 08 c5 e5 02 08 ... 45 xx yy - Marker | | |Cm|Size |Address |UploadSize |Checksum |512 data bytes |Ix |Chksm | - */ - SSPMInitSend(); - SspmBuffer[16] = SSPM_FUNC_UPLOAD_DATA; // 0x1F - - - - Sspm->command_sequence++; - SspmBuffer[543] = Sspm->command_sequence; - SSPMSend(546); -} - -void SSPMSendUploadDone(void) { - /* - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 - AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 46 32 da - Marker | | |Cm|Size |Ix|Chksm| - */ - SSPMSendCmnd(SSPM_FUNC_UPLOAD_DONE); // 0x21 -} - void SSPMSendGetNew1(uint32_t module) { /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @@ -1635,6 +1591,14 @@ void SSPMHandleReceivedData(void) { SSPMSendSetTime(); break; + case SSPM_FUNC_UPLOAD_DONE_ACK: + /* 0x1E + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + aa 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 01 00 01 fe 05 + Marker | | |Cm|Size | |Ix|Chksm| + */ + SSPMSendFindAck(); + break; } } } @@ -1766,6 +1730,54 @@ bool SSPMSendSPIFind(void) { return false; } +void SSPMSendSPIUploadHeader(void) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 14 00 0b 09 09 00 1b e5 a4 c7 00 02 88 74 00 6d df + Marker | | |Cm|Size | |Checksum |UploadSize |Ix|Chksm| + */ + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_UPLOAD_HEADER; // 0x14 + SspmBuffer[18] = 0x0B; + + + SspmBuffer[30] = 0; + SSPMSendSPI(33); +} + +void SSPMSendSPIUpload(void) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 539 540 541 542 543 544 545 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 02 0c 00 00 00 00 00 00 02 00 a2 99 c3 22 00 00 01 20 cd 95 01 08 ... 04 48 af f3 01 xx yy + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 02 0c 00 00 02 00 00 00 02 00 27 f7 24 87 00 80 01 23 23 70 10 bd ... 21 fa 04 f3 02 xx yy + ... + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 02 0c 00 02 86 00 00 00 02 00 f8 f5 25 6d f1 61 00 08 02 01 ff 00 ... 44 xx yy + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 80 00 02 88 00 00 00 00 74 95 4e 01 c1 c5 e5 02 08 c5 e5 02 08 ... 45 xx yy + Marker | | |Cm|Size |Address |UploadSize |Checksum |512 data bytes |Ix |Chksm | + */ + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_UPLOAD_DATA; // 0x1F + + + + Sspm->command_sequence++; + SspmBuffer[543] = Sspm->command_sequence; + SSPMSendSPI(546); +} + +void SSPMSendSPIUploadDone(void) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 46 32 da + Marker | | |Cm|Size |Ix|Chksm| + */ + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_UPLOAD_DONE; // 0x21 + Sspm->command_sequence++; + SspmBuffer[19] = Sspm->command_sequence; + SSPMSendSPI(22); +} + /*********************************************************************************************/ void SSPMInit(void) { @@ -1848,7 +1860,7 @@ void SSPMEvery100ms(void) { // Fix race condition if the ARM doesn't respond if ((Sspm->mstate > SPM_NONE) && (Sspm->mstate < SPM_SEND_FUNC_UNITS)) { Sspm->counter++; - if (Sspm->counter > 20) { + if (Sspm->counter > 30) { Sspm->mstate = SPM_NONE; Sspm->error_led_blinks = 255; } @@ -2146,13 +2158,13 @@ const char kSSPMCommands[] PROGMEM = "SSPM|" // Prefix "Display|Dump|" // SetOptions "Log|Energy|History|Scan|IamHere|" "Reset|Map|Overload|" - D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYYESTERDAY; + D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYYESTERDAY "|Send"; void (* const SSPMCommand[])(void) PROGMEM = { &CmndSSPMDisplay, &CmndSSPMDump, &CmndSSPMLog, &CmndSSPMEnergy, &CmndSSPMHistory, &CmndSSPMScan, &CmndSSPMIamHere, &CmndSSPMReset, &CmndSSPMMap, &CmndSSPMOverload, - &CmndSpmEnergyTotal, &CmndSpmEnergyYesterday }; + &CmndSpmEnergyTotal, &CmndSpmEnergyYesterday, &CmndSSPMSend }; void CmndSSPMDisplay(void) { // Select either all relays or only powered on relays @@ -2377,6 +2389,26 @@ void CmndSSPMMap(void) { } } +void CmndSSPMSend(void) { + // Want to send AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 ix ch ks + // SspmSend 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 + char data[TOPSZ]; + if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(data))) { + strlcpy(data, XdrvMailbox.data, sizeof(data)); + uint32_t len = (XdrvMailbox.data_len +1) / 3; + char *p = data; + SSPMInitSend(); + for (uint32_t i = 0; i < len; i++) { + SspmBuffer[i +3] = strtol(p, &p, 16); + } + Sspm->command_sequence++; + SspmBuffer[len +3] = Sspm->command_sequence; + SSPMSend(len +6); + + ResponseCmndIdxChar(ToHex_P((unsigned char *)SspmBuffer, len +6, data, sizeof(data), ' ')); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ From cc3fc2b0ac75ea070379bd23bee8719a978e2b48 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 19 May 2022 13:46:34 +0200 Subject: [PATCH 06/12] Add Tasmota supported ESP32S3usb board file --- boards/esp32s3usb.json | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 boards/esp32s3usb.json diff --git a/boards/esp32s3usb.json b/boards/esp32s3usb.json new file mode 100644 index 000000000..f495bc5d8 --- /dev/null +++ b/boards/esp32s3usb.json @@ -0,0 +1,46 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32s3_out.ld", + "memory_type": "qspi_qspi" + }, + "core": "esp32", + "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_SERIAL_CONSOLE -DESP32_4M -DESP32S3", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "dio", + "mcu": "esp32s3", + "variant": "esp32s3", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "espidf", + "arduino" + ], + "name": "Espressif Generic ESP32-S3 4M Flash, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "variants/tasmota/tasmota32s3usb-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", + "vendor": "Espressif" +} From 41b82fd0767dbf554698b85b88a55ee4cf8d42e6 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 19 May 2022 18:02:05 +0200 Subject: [PATCH 07/12] Possible pin output toggle after power on Possible pin output toggle after power on (#15630) --- CHANGELOG.md | 2 +- RELEASENOTES.md | 1 + tasmota/support.ino | 12 +++++++++--- tasmota/support_tasmota.ino | 27 +++++++++++++++------------ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aac70f934..4dbda3dcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to this project will be documented in this file. ### Fixed - +- Possible pin output toggle after power on (#15630) ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 24af1c458..25da59439 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -127,6 +127,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Improv initial or erase device installation failing to provide Configure WiFi option - SCD40 start low power command [#15361](https://github.com/arendst/Tasmota/issues/15361) - BL09xx negative power presentation [#15374](https://github.com/arendst/Tasmota/issues/15374) +- Possible pin output toggle after power on [#15630](https://github.com/arendst/Tasmota/issues/15630) ### Removed - Arduino IDE support diff --git a/tasmota/support.ino b/tasmota/support.ino index 6f8dc8288..7364a7230 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1326,10 +1326,16 @@ void SetPin(uint32_t lpin, uint32_t gpio) { TasmotaGlobal.gpio_pin[lpin] = gpio; } -void DigitalWrite(uint32_t gpio_pin, uint32_t index, uint32_t state) -{ +void DigitalWrite(uint32_t gpio_pin, uint32_t index, uint32_t state) { + static uint64_t pinmode_init = 0; // Pins 0 to 63 !!! + if (PinUsed(gpio_pin, index)) { - digitalWrite(Pin(gpio_pin, index), state &1); + uint32_t pin = Pin(gpio_pin, index); + if (!bitRead(pinmode_init, pin)) { + pinMode(pin, OUTPUT); + bitSet(pinmode_init, pin); + } + digitalWrite(pin, state &1); } } diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 42f573d54..3758f2939 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -2010,12 +2010,14 @@ void GpioInit(void) uint32_t mpin = ValidPin(i, TasmotaGlobal.my_module.io[i]); // AddLog(LOG_LEVEL_DEBUG, PSTR("INI: gpio pin %d, mpin %d"), i, mpin); if (AGPIO(GPIO_OUTPUT_HI) == mpin) { - pinMode(i, OUTPUT); - digitalWrite(i, 1); +// pinMode(i, OUTPUT); +// digitalWrite(i, 1); + DigitalWrite(i, 0, 1); } else if (AGPIO(GPIO_OUTPUT_LO) == mpin) { - pinMode(i, OUTPUT); - digitalWrite(i, 0); +// pinMode(i, OUTPUT); +// digitalWrite(i, 0); + DigitalWrite(i, 0, 0); } /* @@ -2049,8 +2051,9 @@ void GpioInit(void) } if (PinUsed(GPIO_HEARTBEAT)) { - pinMode(Pin(GPIO_HEARTBEAT), OUTPUT); - digitalWrite(Pin(GPIO_HEARTBEAT), TasmotaGlobal.heartbeat_inverted); +// pinMode(Pin(GPIO_HEARTBEAT), OUTPUT); +// digitalWrite(Pin(GPIO_HEARTBEAT), TasmotaGlobal.heartbeat_inverted); + DigitalWrite(GPIO_HEARTBEAT, 0, TasmotaGlobal.heartbeat_inverted); } // Digital input @@ -2106,10 +2109,8 @@ void GpioInit(void) for (uint32_t i = 0; i < MAX_RELAYS; i++) { if (PinUsed(GPIO_REL1, i)) { TasmotaGlobal.devices_present++; - pinMode(Pin(GPIO_REL1, i), OUTPUT); #ifdef ESP8266 if (EXS_RELAY == TasmotaGlobal.module_type) { - digitalWrite(Pin(GPIO_REL1, i), bitRead(TasmotaGlobal.rel_inverted, i) ? 1 : 0); if (i &1) { TasmotaGlobal.devices_present--; } } #endif // ESP8266 @@ -2124,16 +2125,18 @@ void GpioInit(void) } else { #endif TasmotaGlobal.leds_present++; - pinMode(Pin(GPIO_LED1, i), OUTPUT); - digitalWrite(Pin(GPIO_LED1, i), bitRead(TasmotaGlobal.led_inverted, i)); +// pinMode(Pin(GPIO_LED1, i), OUTPUT); +// digitalWrite(Pin(GPIO_LED1, i), bitRead(TasmotaGlobal.led_inverted, i)); + DigitalWrite(GPIO_LED1, i, bitRead(TasmotaGlobal.led_inverted, i)); #ifdef USE_ARILUX_RF } #endif } } if (PinUsed(GPIO_LEDLNK)) { - pinMode(Pin(GPIO_LEDLNK), OUTPUT); - digitalWrite(Pin(GPIO_LEDLNK), TasmotaGlobal.ledlnk_inverted); +// pinMode(Pin(GPIO_LEDLNK), OUTPUT); +// digitalWrite(Pin(GPIO_LEDLNK), TasmotaGlobal.ledlnk_inverted); + DigitalWrite(GPIO_LEDLNK, 0, TasmotaGlobal.ledlnk_inverted); } #ifdef USE_PWM_DIMMER From 90a14ee518adfd1835e9c3ab07a1a06d4a70b205 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 19 May 2022 22:35:59 +0200 Subject: [PATCH 08/12] Fix regression from pin output toggle after power on --- tasmota/support_tasmota.ino | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 3758f2939..53f0768e4 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -2010,14 +2010,12 @@ void GpioInit(void) uint32_t mpin = ValidPin(i, TasmotaGlobal.my_module.io[i]); // AddLog(LOG_LEVEL_DEBUG, PSTR("INI: gpio pin %d, mpin %d"), i, mpin); if (AGPIO(GPIO_OUTPUT_HI) == mpin) { -// pinMode(i, OUTPUT); -// digitalWrite(i, 1); - DigitalWrite(i, 0, 1); + pinMode(i, OUTPUT); + digitalWrite(i, 1); } else if (AGPIO(GPIO_OUTPUT_LO) == mpin) { -// pinMode(i, OUTPUT); -// digitalWrite(i, 0); - DigitalWrite(i, 0, 0); + pinMode(i, OUTPUT); + digitalWrite(i, 0); } /* From 84314cf921a8211ad657eede81a1521f420099ca Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 20 May 2022 11:22:49 +0200 Subject: [PATCH 09/12] Generalize pinmode for most digitalwrites --- tasmota/support.ino | 7 +------ tasmota/support_tasmota.ino | 14 ++------------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/tasmota/support.ino b/tasmota/support.ino index 7364a7230..6f0e39c35 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1327,14 +1327,9 @@ void SetPin(uint32_t lpin, uint32_t gpio) { } void DigitalWrite(uint32_t gpio_pin, uint32_t index, uint32_t state) { - static uint64_t pinmode_init = 0; // Pins 0 to 63 !!! - if (PinUsed(gpio_pin, index)) { uint32_t pin = Pin(gpio_pin, index); - if (!bitRead(pinmode_init, pin)) { - pinMode(pin, OUTPUT); - bitSet(pinmode_init, pin); - } + pinMode(pin, OUTPUT); digitalWrite(pin, state &1); } } diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 53f0768e4..a362a91e5 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -2048,11 +2048,7 @@ void GpioInit(void) #endif // ESP8266 } - if (PinUsed(GPIO_HEARTBEAT)) { -// pinMode(Pin(GPIO_HEARTBEAT), OUTPUT); -// digitalWrite(Pin(GPIO_HEARTBEAT), TasmotaGlobal.heartbeat_inverted); - DigitalWrite(GPIO_HEARTBEAT, 0, TasmotaGlobal.heartbeat_inverted); - } + DigitalWrite(GPIO_HEARTBEAT, 0, TasmotaGlobal.heartbeat_inverted); // Digital input for (uint32_t i = 0; i < MAX_SWITCHES; i++) { @@ -2123,19 +2119,13 @@ void GpioInit(void) } else { #endif TasmotaGlobal.leds_present++; -// pinMode(Pin(GPIO_LED1, i), OUTPUT); -// digitalWrite(Pin(GPIO_LED1, i), bitRead(TasmotaGlobal.led_inverted, i)); DigitalWrite(GPIO_LED1, i, bitRead(TasmotaGlobal.led_inverted, i)); #ifdef USE_ARILUX_RF } #endif } } - if (PinUsed(GPIO_LEDLNK)) { -// pinMode(Pin(GPIO_LEDLNK), OUTPUT); -// digitalWrite(Pin(GPIO_LEDLNK), TasmotaGlobal.ledlnk_inverted); - DigitalWrite(GPIO_LEDLNK, 0, TasmotaGlobal.ledlnk_inverted); - } + DigitalWrite(GPIO_LEDLNK, 0, TasmotaGlobal.ledlnk_inverted); #ifdef USE_PWM_DIMMER if (PWM_DIMMER == TasmotaGlobal.module_type && PinUsed(GPIO_REL1)) { TasmotaGlobal.devices_present--; } From c4c03b7c1bcc14f940aeb5f33963d30f29d79ea7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 20 May 2022 11:38:11 +0200 Subject: [PATCH 10/12] Add pinmode once for digitalwrite --- tasmota/support.ino | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tasmota/support.ino b/tasmota/support.ino index 6f0e39c35..a7c08eeda 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1327,9 +1327,18 @@ void SetPin(uint32_t lpin, uint32_t gpio) { } void DigitalWrite(uint32_t gpio_pin, uint32_t index, uint32_t state) { +#ifdef ESP8266 + static uint32_t pinmode_init = 0; // Pins 0 to 31 !!! - saves 40 bytes code space compared to uint64_t +#else + static uint64_t pinmode_init = 0; // Pins 0 to 63 !!! +#endif + if (PinUsed(gpio_pin, index)) { uint32_t pin = Pin(gpio_pin, index); - pinMode(pin, OUTPUT); + if (!bitRead(pinmode_init, pin)) { + pinMode(pin, OUTPUT); + bitSet(pinmode_init, pin); + } digitalWrite(pin, state &1); } } From 51af8611bbc461de5af5f4ff879b128602b7d4c6 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 20 May 2022 12:10:46 +0200 Subject: [PATCH 11/12] Fix max 32-bit bitRead/bitSet size issue --- tasmota/support.ino | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tasmota/support.ino b/tasmota/support.ino index a7c08eeda..a09a6fe59 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1327,17 +1327,13 @@ void SetPin(uint32_t lpin, uint32_t gpio) { } void DigitalWrite(uint32_t gpio_pin, uint32_t index, uint32_t state) { -#ifdef ESP8266 - static uint32_t pinmode_init = 0; // Pins 0 to 31 !!! - saves 40 bytes code space compared to uint64_t -#else - static uint64_t pinmode_init = 0; // Pins 0 to 63 !!! -#endif + static uint32_t pinmode_init[2] = { 0 }; // Pins 0 to 63 !!! if (PinUsed(gpio_pin, index)) { - uint32_t pin = Pin(gpio_pin, index); - if (!bitRead(pinmode_init, pin)) { + uint32_t pin = Pin(gpio_pin, index) & 0x3F; // Fix possible overflow over 63 gpios + if (!bitRead(pinmode_init[pin / 32], pin % 32)) { + bitSet(pinmode_init[pin / 32], pin % 32); pinMode(pin, OUTPUT); - bitSet(pinmode_init, pin); } digitalWrite(pin, state &1); } From d1692efddf81c3d6ad8a723e038910a863f8d59d Mon Sep 17 00:00:00 2001 From: Nemobi Date: Fri, 20 May 2022 14:42:32 +0200 Subject: [PATCH 12/12] Fixed stream redirect --- tasmota/xdrv_81_esp32_webcam.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_81_esp32_webcam.ino b/tasmota/xdrv_81_esp32_webcam.ino index fb75a5ffa..c654d35d5 100644 --- a/tasmota/xdrv_81_esp32_webcam.ino +++ b/tasmota/xdrv_81_esp32_webcam.ino @@ -911,7 +911,7 @@ void HandleWebcamMjpegTask(void) { void HandleWebcamRoot(void) { //CamServer->redirect("http://" + String(ip) + ":81/cam.mjpeg"); - Wc.CamServer->sendHeader("Location", WiFi.localIP().toString() + ":81/cam.mjpeg"); + Wc.CamServer->sendHeader("Location", "/cam.mjpeg"); Wc.CamServer->send(302, "", ""); AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Root called")); }