Merge branch 'development' into rtsp_auth

This commit is contained in:
Nemobi 2022-05-20 13:25:42 +00:00
commit 8e4dcd7b62
21 changed files with 420 additions and 350 deletions

View File

@ -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

View File

@ -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

46
boards/esp32s3usb.json Normal file
View File

@ -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"
}

View File

@ -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.

View File

@ -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ń"

View File

@ -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 uint32_t pinmode_init[2] = { 0 }; // Pins 0 to 63 !!!
if (PinUsed(gpio_pin, index)) {
digitalWrite(Pin(gpio_pin, index), state &1);
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);
}
digitalWrite(pin, state &1);
}
}

View File

@ -2048,10 +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);
// Digital input
for (uint32_t i = 0; i < MAX_SWITCHES; i++) {
@ -2106,10 +2103,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,17 +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);
#ifdef USE_PWM_DIMMER
if (PWM_DIMMER == TasmotaGlobal.module_type && PinUsed(GPIO_REL1)) { TasmotaGlobal.devices_present--; }

View File

@ -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

View File

@ -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];

View File

@ -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"

View File

@ -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<Z_Device> _devices; // list of devices
LList<Z_Deferred> _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
\*********************************************************************************************/

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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; i<attr_len; i++) {
uint16_t attr_id = attr_list_ids[i];
uint32_t ccccaaaa = (_cluster_id << 16) | attr_id;
uint32_t ccccaaaa = (cluster << 16) | attr_id;
Z_attribute attr;
attr.setKeyId(_cluster_id, attr_id);
attr.setKeyId(cluster, attr_id);
switch (ccccaaaa) {
case 0x00000004: attr.setStr(PSTR(USE_ZIGBEE_MANUFACTURER)); break; // Manufacturer
@ -2149,8 +2154,8 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
break;
}
if (!attr.isNone()) {
Z_parseAttributeKey(attr, _cluster_id);
attr_list.addAttribute(_cluster_id, attr_id) = attr;
Z_parseAttributeKey(attr, cluster);
attr_list.addAttribute(cluster, attr_id) = attr;
}
}
@ -2170,21 +2175,21 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
",\"Endpoint\":%d"
",\"Response\":%s}"
),
_srcaddr, _cluster_id, _srcendpoint,
shortaddr, cluster, _srcendpoint,
attr_list.toString().c_str());
// send
// all good, send the packet
ZCLMessage zcl(buf.len()); // message is 4 bytes
zcl.shortaddr = _srcaddr;
zcl.cluster = _cluster_id;
zcl.endpoint = _srcendpoint;
ZCLFrame zcl(buf.len()); // message is 4 bytes
zcl.shortaddr = shortaddr;
zcl.cluster = cluster;
zcl.dstendpoint = _srcendpoint;
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
zcl.clusterSpecific = false; /* not cluster specific */
zcl.needResponse = false; /* noresponse */
zcl.direct = true; /* direct response */
zcl.setTransac(_transact_seq);
zcl.buf.addBuffer(buf);
zcl.setTransac(transactseq);
zcl.payload.addBuffer(buf);
zigbeeZCLSendCmd(zcl);
}
}

View File

@ -753,12 +753,12 @@ void CmndZbEZSPSend(void)
// - msg: pointer to byte array, payload of ZCL message (len is following), ignored if nullptr
// - len: length of the 'msg' payload
// - needResponse: boolean, true = we ask the target to respond, false = the target should not respond
// - transac: 8-bits, transation id of message (should be incremented at each message), used both for Zigbee message number and ZCL message number
// - transactseq: 8-bits, transation id of message (should be incremented at each message), used both for Zigbee message number and ZCL message number
// Returns: None
//
void ZigbeeZCLSend_Raw(const ZCLMessage &zcl) {
SBuffer buf(32+zcl.buf.len());
void ZigbeeZCLSend_Raw(const ZCLFrame &zcl) {
SBuffer buf(32+zcl.payload.len());
#ifdef USE_ZIGBEE_ZNP
buf.add8(Z_SREQ | Z_AF); // 24
@ -770,23 +770,23 @@ void ZigbeeZCLSend_Raw(const ZCLMessage &zcl) {
} else {
buf.add8(Z_Addr_ShortAddress); // 02
buf.add64(zcl.shortaddr); // dest address, only 2 LSB, upper 6 MSB are discarded
buf.add8(zcl.endpoint); // dest endpoint
buf.add8(zcl.dstendpoint); // dest endpoint
}
buf.add16(0x0000); // dest Pan ID, 0x0000 = intra-pan
buf.add8(0x01); // source endpoint
buf.add16(zcl.cluster);
buf.add8(zcl.transac); // transac
buf.add8(zcl.transactseq); // transactseq
buf.add8(0x30); // 30 options
buf.add8(0x1E); // 1E radius
buf.add16(3 + zcl.buf.len() + (zcl.manuf ? 2 : 0));
buf.add16(3 + zcl.payload.len() + (zcl.manuf ? 2 : 0));
buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field
if (zcl.manuf) {
buf.add16(zcl.manuf); // add Manuf Id if not null
}
buf.add8(zcl.transac); // Transaction Sequence Number
buf.add8(zcl.transactseq); // Transaction Sequence Number
buf.add8(zcl.cmd);
buf.addBuffer(zcl.buf);
buf.addBuffer(zcl.payload);
ZigbeeZNPSend(buf.getBuffer(), buf.len());
#endif // USE_ZIGBEE_ZNP
@ -801,25 +801,25 @@ void ZigbeeZCLSend_Raw(const ZCLMessage &zcl) {
buf.add16(Z_PROF_HA); // Home Automation profile
buf.add16(zcl.cluster); // cluster
buf.add8(0x01); // srcEp
buf.add8(zcl.endpoint); // dstEp
buf.add8(zcl.dstendpoint); // dstEp
if (zcl.direct) {
buf.add16(0x0000); // APS frame
} else {
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
}
buf.add16(zcl.groupaddr); // groupId
buf.add8(zcl.transac);
buf.add8(zcl.transactseq);
// end of ApsFrame
buf.add8(0x01); // tag TODO
buf.add8(3 + zcl.buf.len() + (zcl.manuf ? 2 : 0));
buf.add8(3 + zcl.payload.len() + (zcl.manuf ? 2 : 0));
buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field
if (zcl.manuf) {
buf.add16(zcl.manuf); // add Manuf Id if not null
}
buf.add8(zcl.transac); // Transaction Sequance Number
buf.add8(zcl.transactseq); // Transaction Sequance Number
buf.add8(zcl.cmd);
buf.addBuffer(zcl.buf);
buf.addBuffer(zcl.payload);
} else {
// send broadcast group address, aka groupcast
buf.add16(EZSP_sendMulticast); // 3800
@ -827,27 +827,27 @@ void ZigbeeZCLSend_Raw(const ZCLMessage &zcl) {
buf.add16(Z_PROF_HA); // Home Automation profile
buf.add16(zcl.cluster); // cluster
buf.add8(0x01); // srcEp
buf.add8(zcl.endpoint); // broadcast endpoint for groupcast
buf.add8(zcl.dstendpoint); // broadcast endpoint for groupcast
if (zcl.direct) {
buf.add16(0x0000); // APS frame
} else {
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
}
buf.add16(zcl.groupaddr); // groupId
buf.add8(zcl.transac);
buf.add8(zcl.transactseq);
// end of ApsFrame
buf.add8(0); // hops, 0x00 = EMBER_MAX_HOPS
buf.add8(7); // nonMemberRadius, 7 = infinite
buf.add8(0x01); // tag TODO
buf.add8(3 + zcl.buf.len() + (zcl.manuf ? 2 : 0));
buf.add8(3 + zcl.payload.len() + (zcl.manuf ? 2 : 0));
buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field
if (zcl.manuf) {
buf.add16(zcl.manuf); // add Manuf Id if not null
}
buf.add8(zcl.transac); // Transaction Sequance Number
buf.add8(zcl.transactseq); // Transaction Sequance Number
buf.add8(zcl.cmd);
buf.addBuffer(zcl.buf);
buf.addBuffer(zcl.payload);
}
ZigbeeEZSPSendCmd(buf.buf(), buf.len());

View File

@ -178,18 +178,18 @@ void CmndZbReset(void) {
// - param: pointer to HEX string for payload, should not be nullptr
// Returns: None
//
void zigbeeZCLSendCmd(class ZCLMessage &zcl) {
if ((0 == zcl.endpoint) && (zcl.validShortaddr())) {
void zigbeeZCLSendCmd(class ZCLFrame &zcl) {
if ((0 == zcl.dstendpoint) && (zcl.validShortaddr())) {
// endpoint is not specified, let's try to find it from shortAddr, unless it's a group address
zcl.endpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr);
if (0x00 == zcl.endpoint) { zcl.endpoint = 0x01; } // if we don't know the endpoint, try 0x01
zcl.dstendpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr);
if (0x00 == zcl.dstendpoint) { zcl.dstendpoint = 0x01; } // if we don't know the endpoint, try 0x01
//AddLog(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
}
// AddLog(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %_B"),
// zcl.shortaddr, zcl.groupaddr, zcl.cluster, zcl.endpoint, zcl.cmd, &zcl.buf);
// zcl.shortaddr, zcl.groupaddr, zcl.cluster, zcl.dstendpoint, zcl.cmd, &zcl.payload);
if ((0 == zcl.endpoint) && (zcl.validShortaddr())) { // endpoint null is ok for group address
if ((0 == zcl.dstendpoint) && (zcl.validShortaddr())) { // endpoint null is ok for group address
AddLog(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
return;
}
@ -197,12 +197,12 @@ void zigbeeZCLSendCmd(class ZCLMessage &zcl) {
// everything is good, we can send the command
if (!zcl.transacSet) {
zcl.transac = zigbee_devices.getNextSeqNumber(zcl.shortaddr);
zcl.transactseq = zigbee_devices.getNextSeqNumber(zcl.shortaddr);
zcl.transacSet = true;
}
AddLog(LOG_LEVEL_DEBUG, PSTR("ZigbeeZCLSend %s: 0x%04X, endpoint:%d, cluster:0x%04X, cmd:0x%02X, send:\"%_B\""),
zcl.validShortaddr() ? "device":"group", zcl.validShortaddr() ? zcl.shortaddr : zcl.groupaddr, zcl.endpoint, zcl.cluster, zcl.cmd, &zcl.buf);
zcl.validShortaddr() ? "device":"group", zcl.validShortaddr() ? zcl.shortaddr : zcl.groupaddr, zcl.dstendpoint, zcl.cluster, zcl.cmd, &zcl.payload);
ZigbeeZCLSend_Raw(zcl);
@ -210,7 +210,7 @@ void zigbeeZCLSendCmd(class ZCLMessage &zcl) {
if (zcl.clusterSpecific) {
if (!Settings->flag5.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, <device_id>
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, <device_id>
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, <device_id>
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, <device_id>
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, <device_id>
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) {

View File

@ -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();

View File

@ -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"));
}

View File

@ -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
\*********************************************************************************************/