mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 03:06:33 +00:00
Merge branch 'development' into rtsp_auth
This commit is contained in:
commit
8e4dcd7b62
@ -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
|
||||
|
||||
|
@ -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
46
boards/esp32s3usb.json
Normal 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"
|
||||
}
|
@ -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.
|
||||
|
@ -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ń"
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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--; }
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
\*********************************************************************************************/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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
|
||||
\*********************************************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user