mirror of https://github.com/arendst/Tasmota.git
Add Zigbee better support for Xiaomi Double Switch and Xiaomi Vibration sensor
This commit is contained in:
parent
a10b199808
commit
749960533f
|
@ -3,6 +3,7 @@
|
|||
### 8.0.0.2 20191223
|
||||
|
||||
- Changed Settings variable namings
|
||||
- Add Zigbee better support for Xiaomi Double Switch and Xiaomi Vibration sensor
|
||||
|
||||
### 8.0.0.1 20191221
|
||||
|
||||
|
|
|
@ -468,6 +468,7 @@
|
|||
#define D_CMND_ZIGBEE_STATUS "ZigbeeStatus"
|
||||
#define D_CMND_ZIGBEE_RESET "ZigbeeReset"
|
||||
#define D_JSON_ZIGBEE_CC2530 "CC2530"
|
||||
#define D_CMND_ZIGBEEZNPRECEIVE "ZigbeeZNPReceive" // only for debug
|
||||
#define D_CMND_ZIGBEEZNPSEND "ZigbeeZNPSend"
|
||||
#define D_JSON_ZIGBEE_STATE "ZigbeeState"
|
||||
#define D_JSON_ZIGBEEZNPRECEIVED "ZigbeeZNPReceived"
|
||||
|
|
|
@ -91,6 +91,8 @@ public:
|
|||
void jsonClear(uint16_t shortaddr);
|
||||
void jsonAppend(uint16_t shortaddr, JsonObject &values);
|
||||
const JsonObject *jsonGet(uint16_t shortaddr);
|
||||
const void jsonPublish(uint16_t shortaddr); // publish the json message and clear buffer
|
||||
bool jsonIsConflict(uint16_t shortaddr, const JsonObject &values);
|
||||
|
||||
private:
|
||||
std::vector<Z_Device> _devices = {};
|
||||
|
@ -419,6 +421,67 @@ void Z_Devices::jsonClear(uint16_t shortaddr) {
|
|||
device.json_buffer->clear();
|
||||
}
|
||||
|
||||
void CopyJsonVariant(JsonObject &to, const String &key, const JsonVariant &val) {
|
||||
to.remove(key); // force remove to have metadata like LinkQuality at the end
|
||||
|
||||
if (val.is<char*>()) {
|
||||
String sval = val.as<String>(); // force a copy of the String value
|
||||
to.set(key, sval);
|
||||
} else if (val.is<JsonArray>()) {
|
||||
JsonArray &nested_arr = to.createNestedArray(key);
|
||||
CopyJsonArray(nested_arr, val.as<JsonArray>());
|
||||
} else if (val.is<JsonObject>()) {
|
||||
JsonObject &nested_obj = to.createNestedObject(key);
|
||||
CopyJsonObject(nested_obj, val.as<JsonObject>());
|
||||
} else {
|
||||
to.set(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyJsonArray(JsonArray &to, const JsonArray &arr) {
|
||||
for (auto v : arr) {
|
||||
if (v.is<char*>()) {
|
||||
String sval = v.as<String>(); // force a copy of the String value
|
||||
to.add(sval);
|
||||
} else if (v.is<JsonArray>()) {
|
||||
} else if (v.is<JsonObject>()) {
|
||||
} else {
|
||||
to.add(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CopyJsonObject(JsonObject &to, const JsonObject &from) {
|
||||
for (auto kv : from) {
|
||||
String key_string = kv.key;
|
||||
JsonVariant &val = kv.value;
|
||||
|
||||
CopyJsonVariant(to, key_string, val);
|
||||
}
|
||||
}
|
||||
|
||||
// does the new payload conflicts with the existing payload, i.e. values would be overwritten
|
||||
bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return false; } // don't crash if not found
|
||||
if (&values == nullptr) { return false; }
|
||||
|
||||
if (nullptr == device.json) {
|
||||
return false; // if no previous value, no conflict
|
||||
}
|
||||
|
||||
for (auto kv : values) {
|
||||
String key_string = kv.key;
|
||||
|
||||
if (strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_LINKQUALITY))) { // exception = ignore duplicates for LinkQuality
|
||||
if (device.json->containsKey(kv.key)) {
|
||||
return true; // conflict!
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Z_Devices::jsonAppend(uint16_t shortaddr, JsonObject &values) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
@ -428,24 +491,7 @@ void Z_Devices::jsonAppend(uint16_t shortaddr, JsonObject &values) {
|
|||
device.json = &(device.json_buffer->createObject());
|
||||
}
|
||||
// copy all values from 'values' to 'json'
|
||||
for (auto kv : values) {
|
||||
String key_string = kv.key;
|
||||
const char * key = key_string.c_str();
|
||||
JsonVariant &val = kv.value;
|
||||
|
||||
device.json->remove(key_string); // force remove to have metadata like LinkQuality at the end
|
||||
|
||||
if (val.is<char*>()) {
|
||||
String sval = val.as<String>(); // force a copy of the String value
|
||||
device.json->set(key_string, sval);
|
||||
} else if (val.is<JsonArray>()) {
|
||||
// todo
|
||||
} else if (val.is<JsonObject>()) {
|
||||
// todo
|
||||
} else {
|
||||
device.json->set(key_string, kv.value);
|
||||
}
|
||||
}
|
||||
CopyJsonObject(*device.json, values);
|
||||
}
|
||||
|
||||
const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) {
|
||||
|
@ -454,6 +500,19 @@ const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) {
|
|||
return device.json;
|
||||
}
|
||||
|
||||
const void Z_Devices::jsonPublish(uint16_t shortaddr) {
|
||||
const JsonObject *json = zigbee_devices.jsonGet(shortaddr);
|
||||
if (json == nullptr) { return; } // don't crash if not found
|
||||
|
||||
String msg = "";
|
||||
json->printTo(msg);
|
||||
zigbee_devices.jsonClear(shortaddr);
|
||||
Response_P(PSTR("{\"" D_CMND_ZIGBEE_RECEIVED "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str());
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR));
|
||||
XdrvRulesProcess();
|
||||
}
|
||||
|
||||
|
||||
// Dump the internal memory of Zigbee devices
|
||||
// Mode = 1: simple dump of devices addresses and names
|
||||
// Mode = 2: Mode 1 + also dump the endpoints, profiles and clusters
|
||||
|
|
|
@ -100,6 +100,7 @@ public:
|
|||
return _frame_control.b.frame_type & 1;
|
||||
}
|
||||
|
||||
static void generateAttributeName(const JsonObject& json, uint16_t cluster, uint16_t attr, char *key, size_t key_len);
|
||||
void parseRawAttributes(JsonObject& json, uint8_t offset = 0);
|
||||
void parseReadAttributes(JsonObject& json, uint8_t offset = 0);
|
||||
void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0);
|
||||
|
@ -290,17 +291,20 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer
|
|||
bool parse_as_string = true;
|
||||
uint32_t len = (attrtype <= 0x42) ? buf.get8(i) : buf.get16(i); // len is 8 or 16 bits
|
||||
i += (attrtype <= 0x42) ? 1 : 2; // increment pointer
|
||||
if (i + len > buf.len()) { // make sure we don't get past the buffer
|
||||
len = buf.len() - i;
|
||||
}
|
||||
|
||||
// check if we can safely use a string
|
||||
if ((0x41 == attrtype) || (0x43 == attrtype)) { parse_as_string = false; }
|
||||
else {
|
||||
for (uint32_t j = 0; j < len; j++) {
|
||||
if (0x00 == buf.get8(i+j)) {
|
||||
parse_as_string = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// for (uint32_t j = 0; j < len; j++) {
|
||||
// if (0x00 == buf.get8(i+j)) {
|
||||
// parse_as_string = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (parse_as_string) {
|
||||
char str[len+1];
|
||||
|
@ -409,19 +413,28 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer
|
|||
return i - offset; // how much have we increased the index
|
||||
}
|
||||
|
||||
// Generate an attribute name based on cluster number, attribute, and suffix if duplicates
|
||||
void ZCLFrame::generateAttributeName(const JsonObject& json, uint16_t cluster, uint16_t attr, char *key, size_t key_len) {
|
||||
uint32_t suffix = 1;
|
||||
|
||||
snprintf_P(key, key_len, PSTR("%04X/%04X"), cluster, attr);
|
||||
while (json.containsKey(key)) {
|
||||
suffix++;
|
||||
snprintf_P(key, key_len, PSTR("%04X/%04X+%d"), cluster, attr, suffix); // add "0008/0001+2" suffix if duplicate
|
||||
}
|
||||
}
|
||||
|
||||
// First pass, parse all attributes in their native format
|
||||
void ZCLFrame::parseRawAttributes(JsonObject& json, uint8_t offset) {
|
||||
uint32_t i = offset;
|
||||
uint32_t len = _payload.len();
|
||||
|
||||
while (len - i >= 3) {
|
||||
while (len >= i + 3) {
|
||||
uint16_t attrid = _payload.get16(i);
|
||||
i += 2;
|
||||
|
||||
char key[16];
|
||||
snprintf_P(key, sizeof(key), PSTR("%04X/%04X"),
|
||||
_cluster_id, attrid);
|
||||
generateAttributeName(json, _cluster_id, attrid, key, sizeof(key));
|
||||
|
||||
// exception for Xiaomi lumi.weather - specific field to be treated as octet and not char
|
||||
if ((0x0000 == _cluster_id) && (0xFF01 == attrid)) {
|
||||
|
@ -445,8 +458,7 @@ void ZCLFrame::parseReadAttributes(JsonObject& json, uint8_t offset) {
|
|||
|
||||
if (0 == status) {
|
||||
char key[16];
|
||||
snprintf_P(key, sizeof(key), PSTR("%04X/%04X"),
|
||||
_cluster_id, attrid);
|
||||
generateAttributeName(json, _cluster_id, attrid, key, sizeof(key));
|
||||
|
||||
i += parseSingleAttribute(json, key, _payload, i, len);
|
||||
}
|
||||
|
@ -472,7 +484,7 @@ void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) {
|
|||
// return value:
|
||||
// 0 = keep initial value
|
||||
// 1 = remove initial value
|
||||
typedef int32_t (*Z_AttrConverter)(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper* new_name, uint16_t cluster, uint16_t attr);
|
||||
typedef int32_t (*Z_AttrConverter)(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr);
|
||||
typedef struct Z_AttributeConverter {
|
||||
uint16_t cluster;
|
||||
uint16_t attribute;
|
||||
|
@ -775,13 +787,13 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
|
|||
|
||||
// ======================================================================
|
||||
// Record Manuf
|
||||
int32_t Z_ManufKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_ManufKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
json[new_name] = value;
|
||||
zigbee_devices.setManufId(shortaddr, value.as<const char*>());
|
||||
return 1;
|
||||
}
|
||||
//
|
||||
int32_t Z_ModelKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_ModelKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
json[new_name] = value;
|
||||
zigbee_devices.setModelId(shortaddr, value.as<const char*>());
|
||||
return 1;
|
||||
|
@ -789,29 +801,29 @@ int32_t Z_ModelKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& j
|
|||
|
||||
// ======================================================================
|
||||
// Remove attribute
|
||||
int32_t Z_Remove(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_Remove(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
return 1; // remove original key
|
||||
}
|
||||
|
||||
// Copy value as-is
|
||||
int32_t Z_Copy(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_Copy(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
json[new_name] = value;
|
||||
return 1; // remove original key
|
||||
}
|
||||
|
||||
// Add pressure unit
|
||||
int32_t Z_AddPressureUnit(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_AddPressureUnit(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
json[new_name] = F(D_UNIT_PRESSURE);
|
||||
return 0; // keep original key
|
||||
}
|
||||
|
||||
// Convert int to float and divide by 100
|
||||
int32_t Z_FloatDiv100(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_FloatDiv100(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
json[new_name] = ((float)value) / 100.0f;
|
||||
return 1; // remove original key
|
||||
}
|
||||
// Convert int to float and divide by 10
|
||||
int32_t Z_FloatDiv10(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_FloatDiv10(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
json[new_name] = ((float)value) / 10.0f;
|
||||
return 1; // remove original key
|
||||
}
|
||||
|
@ -825,7 +837,7 @@ int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t cluster, uint16_t endpo
|
|||
}
|
||||
|
||||
// Aqara Vibration Sensor - special proprietary attributes
|
||||
int32_t Z_AqaraVibration(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_AqaraVibration(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
//json[new_name] = value;
|
||||
switch (attr) {
|
||||
case 0x0055:
|
||||
|
@ -879,7 +891,7 @@ int32_t Z_AqaraVibration(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObje
|
|||
return 1; // remove original key
|
||||
}
|
||||
|
||||
int32_t Z_AqaraSensor(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const __FlashStringHelper *new_name, uint16_t cluster, uint16_t attr) {
|
||||
int32_t Z_AqaraSensor(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
|
||||
String hex = value;
|
||||
SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length());
|
||||
uint32_t i = 0;
|
||||
|
@ -925,11 +937,19 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
|
|||
String key_string = kv.key;
|
||||
const char * key = key_string.c_str();
|
||||
JsonVariant& value = kv.value;
|
||||
// Check that format looks like "CCCC/AAAA"
|
||||
// Check that format looks like "CCCC/AAAA" or "CCCC/AAAA+d"
|
||||
char * delimiter = strchr(key, '/');
|
||||
char * delimiter2 = strchr(key, '+');
|
||||
if (delimiter) {
|
||||
uint16_t attribute;
|
||||
uint16_t suffix = 1;
|
||||
uint16_t cluster = strtoul(key, &delimiter, 16);
|
||||
uint16_t attribute = strtoul(delimiter+1, nullptr, 16);
|
||||
if (!delimiter2) {
|
||||
attribute = strtoul(delimiter+1, nullptr, 16);
|
||||
} else {
|
||||
attribute = strtoul(delimiter+1, &delimiter2, 16);
|
||||
suffix = strtoul(delimiter2+1, nullptr, 10);
|
||||
}
|
||||
|
||||
// Iterate on filter
|
||||
for (uint32_t i = 0; i < sizeof(Z_PostProcess) / sizeof(Z_PostProcess[0]); i++) {
|
||||
|
@ -939,7 +959,9 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
|
|||
|
||||
if ((conv_cluster == cluster) &&
|
||||
((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) {
|
||||
int32_t drop = (*converter->func)(this, shortaddr, json, key, value, (const __FlashStringHelper*) converter->name, conv_cluster, conv_attribute);
|
||||
String new_name_str = converter->name;
|
||||
if (suffix > 1) { new_name_str += suffix; } // append suffix number
|
||||
int32_t drop = (*converter->func)(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute);
|
||||
if (drop) {
|
||||
json.remove(key);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ const uint8_t ZIGBEE_STATUS_DEVICE_ANNOUNCE = 30; // Device announces its
|
|||
const uint8_t ZIGBEE_STATUS_NODE_DESC = 31; // Node descriptor
|
||||
const uint8_t ZIGBEE_STATUS_ACTIVE_EP = 32; // Endpoints descriptor
|
||||
const uint8_t ZIGBEE_STATUS_SIMPLE_DESC = 33; // Simple Descriptor (clusters)
|
||||
const uint8_t ZIGBEE_STATUS_DEVICE_INDICATION = 34; // Device announces its address
|
||||
const uint8_t ZIGBEE_STATUS_CC_VERSION = 50; // Status: CC2530 ZNP Version
|
||||
const uint8_t ZIGBEE_STATUS_CC_INFO = 51; // Status: CC2530 Device Configuration
|
||||
const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version
|
||||
|
|
|
@ -357,6 +357,28 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
// 45CA
|
||||
int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) {
|
||||
Z_ShortAddress srcAddr = buf.get16(2);
|
||||
Z_IEEEAddress ieeeAddr = buf.get64(4);
|
||||
Z_ShortAddress parentNw = buf.get16(12);
|
||||
|
||||
zigbee_devices.updateDevice(srcAddr, ieeeAddr);
|
||||
|
||||
char hex[20];
|
||||
Uint64toHex(ieeeAddr, hex, 64);
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
|
||||
"\"Status\":%d,\"IEEEAddr\":\"%s\",\"ShortAddr\":\"0x%04X\""
|
||||
",\"ParentNetwork\":\"0x%04X\"}}"),
|
||||
ZIGBEE_STATUS_DEVICE_INDICATION, hex, srcAddr, parentNw
|
||||
);
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
//Z_SendActiveEpReq(srcAddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Aqara Occupancy behavior: the Aqara device only sends Occupancy: true events every 60 seconds.
|
||||
// Here we add a timer so if we don't receive a Occupancy event for 90 seconds, we send Occupancy:false
|
||||
const uint32_t OCCUPANCY_TIMEOUT = 90 * 1000; // 90 s
|
||||
|
@ -378,16 +400,11 @@ void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint16_t endpoint, c
|
|||
int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t cluster, uint16_t endpoint, uint32_t value) {
|
||||
const JsonObject *json = zigbee_devices.jsonGet(shortaddr);
|
||||
if (json == nullptr) { return 0; } // don't crash if not found
|
||||
|
||||
// Post-provess for Aqara Presence Senson
|
||||
Z_AqaraOccupancy(shortaddr, cluster, endpoint, json);
|
||||
|
||||
String msg = "";
|
||||
json->printTo(msg);
|
||||
zigbee_devices.jsonClear(shortaddr);
|
||||
Response_P(PSTR("{\"" D_CMND_ZIGBEE_RECEIVED "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str());
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR));
|
||||
XdrvRulesProcess();
|
||||
zigbee_devices.jsonPublish(shortaddr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||
|
@ -438,8 +455,13 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
|||
|
||||
if (defer_attributes) {
|
||||
// Prepare for publish
|
||||
zigbee_devices.jsonAppend(srcaddr, json);
|
||||
zigbee_devices.setTimer(srcaddr, USE_ZIGBEE_COALESCE_ATTR_TIMER, clusterid, srcendpoint, 0, &Z_PublishAttributes);
|
||||
if (zigbee_devices.jsonIsConflict(srcaddr, json)) {
|
||||
// there is conflicting values, force a publish of the previous message now and don't coalesce
|
||||
zigbee_devices.jsonPublish(srcaddr);
|
||||
} else {
|
||||
zigbee_devices.jsonAppend(srcaddr, json);
|
||||
zigbee_devices.setTimer(srcaddr, USE_ZIGBEE_COALESCE_ATTR_TIMER, clusterid, srcendpoint, 0, &Z_PublishAttributes);
|
||||
}
|
||||
} else {
|
||||
// Publish immediately
|
||||
msg = "";
|
||||
|
@ -459,6 +481,7 @@ typedef struct Z_Dispatcher {
|
|||
// Filters for ZCL frames
|
||||
ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
|
||||
ZBM(AREQ_END_DEVICE_ANNCE_IND, Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND) // 45C1
|
||||
ZBM(AREQ_END_DEVICE_TC_DEV_IND, Z_AREQ | Z_ZDO, ZDO_TC_DEV_IND) // 45CA
|
||||
ZBM(AREQ_PERMITJOIN_OPEN_XX, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND ) // 45CB
|
||||
ZBM(AREQ_ZDO_ACTIVEEPRSP, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP) // 4585
|
||||
ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584
|
||||
|
@ -466,6 +489,7 @@ ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584
|
|||
const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
|
||||
{ AREQ_AF_INCOMING_MESSAGE, &Z_ReceiveAfIncomingMessage },
|
||||
{ AREQ_END_DEVICE_ANNCE_IND, &Z_ReceiveEndDeviceAnnonce },
|
||||
{ AREQ_END_DEVICE_TC_DEV_IND, &Z_ReceiveTCDevInd },
|
||||
{ AREQ_PERMITJOIN_OPEN_XX, &Z_ReceivePermitJoinStatus },
|
||||
{ AREQ_ZDO_NODEDESCRSP, &Z_ReceiveNodeDesc },
|
||||
{ AREQ_ZDO_ACTIVEEPRSP, &Z_ReceiveActiveEp },
|
||||
|
|
|
@ -31,12 +31,14 @@ TasmotaSerial *ZigbeeSerial = nullptr;
|
|||
const char kZigbeeCommands[] PROGMEM = "|"
|
||||
D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN "|"
|
||||
D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|"
|
||||
D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_READ ;
|
||||
D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_READ "|" D_CMND_ZIGBEEZNPRECEIVE
|
||||
;
|
||||
|
||||
void (* const ZigbeeCommand[])(void) PROGMEM = {
|
||||
&CmndZigbeeZNPSend, &CmndZigbeePermitJoin,
|
||||
&CmndZigbeeStatus, &CmndZigbeeReset, &CmndZigbeeSend,
|
||||
&CmndZigbeeProbe, &CmndZigbeeRead };
|
||||
&CmndZigbeeProbe, &CmndZigbeeRead, &CmndZigbeeZNPReceive
|
||||
};
|
||||
|
||||
int32_t ZigbeeProcessInput(class SBuffer &buf) {
|
||||
if (!zigbee.state_machine) { return -1; } // if state machine is stopped, send 'ignore' message
|
||||
|
@ -268,7 +270,7 @@ void CmndZigbeeStatus(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void CmndZigbeeZNPSend(void)
|
||||
void CmndZigbeeZNPSendOrReceive(bool send)
|
||||
{
|
||||
if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) {
|
||||
uint8_t code;
|
||||
|
@ -286,11 +288,26 @@ void CmndZigbeeZNPSend(void)
|
|||
size -= 2;
|
||||
codes += 2;
|
||||
}
|
||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||
if (send) {
|
||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||
} else {
|
||||
ZigbeeProcessInput(buf);
|
||||
}
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
// For debug purposes only, simulates a message received
|
||||
void CmndZigbeeZNPReceive(void)
|
||||
{
|
||||
CmndZigbeeZNPSendOrReceive(false);
|
||||
}
|
||||
|
||||
void CmndZigbeeZNPSend(void)
|
||||
{
|
||||
CmndZigbeeZNPSendOrReceive(true);
|
||||
}
|
||||
|
||||
void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
|
||||
if ((len < 2) || (len > 252)) {
|
||||
// abort, message cannot be less than 2 bytes for CMD1 and CMD2
|
||||
|
|
Loading…
Reference in New Issue