mirror of https://github.com/arendst/Tasmota.git
Code optimization, cleaning and more error codes
This commit is contained in:
parent
0a573bd0d6
commit
ac4d4ac571
|
@ -112,7 +112,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t addBuffer(const uint8_t *buf2, size_t len2) {
|
size_t addBuffer(const uint8_t *buf2, size_t len2) {
|
||||||
if (len() + len2 <= size()) {
|
if ((buf2) && (len() + len2 <= size())) {
|
||||||
for (uint32_t i = 0; i < len2; i++) {
|
for (uint32_t i = 0; i < len2; i++) {
|
||||||
_buf->buf[_buf->len++] = pgm_read_byte(&buf2[i]);
|
_buf->buf[_buf->len++] = pgm_read_byte(&buf2[i]);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t addBuffer(const char *buf2, size_t len2) {
|
size_t addBuffer(const char *buf2, size_t len2) {
|
||||||
if (len() + len2 <= size()) {
|
if ((buf2) && (len() + len2 <= size())) {
|
||||||
for (uint32_t i = 0; i < len2; i++) {
|
for (uint32_t i = 0; i < len2; i++) {
|
||||||
_buf->buf[_buf->len++] = pgm_read_byte(&buf2[i]);
|
_buf->buf[_buf->len++] = pgm_read_byte(&buf2[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -393,88 +393,36 @@ typedef struct Z_StatusLine {
|
||||||
const char * status_msg;
|
const char * status_msg;
|
||||||
} Z_StatusLine;
|
} Z_StatusLine;
|
||||||
|
|
||||||
ZF(SUCCESS)
|
// Undocumented Zigbee ZCL code here: https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Zigbee-Error-Codes-in-the-Log
|
||||||
ZF(FAILURE)
|
String getZigbeeStatusMessage(uint8_t status) {
|
||||||
ZF(NOT_AUTHORIZED)
|
static const char StatusMsg[] PROGMEM = "SUCCESS|FAILURE|NOT_AUTHORIZED|RESERVED_FIELD_NOT_ZERO|MALFORMED_COMMAND|UNSUP_CLUSTER_COMMAND|UNSUP_GENERAL_COMMAND"
|
||||||
ZF(RESERVED_FIELD_NOT_ZERO)
|
"|UNSUP_MANUF_CLUSTER_COMMAND|UNSUP_MANUF_GENERAL_COMMAND|INVALID_FIELD|UNSUPPORTED_ATTRIBUTE|INVALID_VALE|READ_ONLY"
|
||||||
ZF(MALFORMED_COMMAND)
|
"|INSUFFICIENT_SPACE|DUPLICATE_EXISTS|NOT_FOUND|UNREPORTABLE_ATTRIBUTE|INVALID_DATA_TYPE|INVALID_SELECTOR|WRITE_ONLY"
|
||||||
ZF(UNSUP_CLUSTER_COMMAND)
|
"|INCONSISTENT_STARTUP_STATE|DEFINED_OUT_OF_BAND|INCONSISTENT|ACTION_DENIED|TIMEOUT|ABORT|INVALID_IMAGE|WAIT_FOR_DATA"
|
||||||
ZF(UNSUP_GENERAL_COMMAND)
|
"|NO_IMAGE_AVAILABLE|REQUIRE_MORE_IMAGE|NOTIFICATION_PENDING|HARDWARE_FAILURE|SOFTWARE_FAILURE|CALIBRATION_ERROR|UNSUPPORTED_CLUSTER"
|
||||||
ZF(UNSUP_MANUF_CLUSTER_COMMAND)
|
"|CHANNEL_ACCESS_FAILURE|NO_ACK|NO_APP_ACK|NO_ROUTE"
|
||||||
ZF(UNSUP_MANUF_GENERAL_COMMAND)
|
;
|
||||||
ZF(INVALID_FIELD)
|
static const uint8_t StatusIdx[] PROGMEM = { 0x00, 0x01, 0x7E, 0x7F, 0x80, 0x81, 0x82,
|
||||||
ZF(UNSUPPORTED_ATTRIBUTE)
|
0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
|
||||||
ZF(INVALID_VALUE)
|
0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||||
ZF(READ_ONLY)
|
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||||
ZF(INSUFFICIENT_SPACE)
|
0x98, 0x99, 0x9A, 0xC0, 0xC1, 0xC2, 0xC3,
|
||||||
ZF(DUPLICATE_EXISTS)
|
0xE1, 0xE9, 0xA7, 0xD0};
|
||||||
ZF(NOT_FOUND)
|
|
||||||
ZF(UNREPORTABLE_ATTRIBUTE)
|
|
||||||
ZF(INVALID_DATA_TYPE)
|
|
||||||
ZF(INVALID_SELECTOR)
|
|
||||||
ZF(WRITE_ONLY)
|
|
||||||
ZF(INCONSISTENT_STARTUP_STATE)
|
|
||||||
ZF(DEFINED_OUT_OF_BAND)
|
|
||||||
ZF(INCONSISTENT)
|
|
||||||
ZF(ACTION_DENIED)
|
|
||||||
ZF(TIMEOUT)
|
|
||||||
ZF(ABORT)
|
|
||||||
ZF(INVALID_IMAGE)
|
|
||||||
ZF(WAIT_FOR_DATA)
|
|
||||||
ZF(NO_IMAGE_AVAILABLE)
|
|
||||||
ZF(REQUIRE_MORE_IMAGE)
|
|
||||||
ZF(NOTIFICATION_PENDING)
|
|
||||||
ZF(HARDWARE_FAILURE)
|
|
||||||
ZF(SOFTWARE_FAILURE)
|
|
||||||
ZF(CALIBRATION_ERROR)
|
|
||||||
ZF(UNSUPPORTED_CLUSTER)
|
|
||||||
|
|
||||||
const Z_StatusLine Z_Status[] PROGMEM = {
|
char msg[32];
|
||||||
0x00, Z(SUCCESS),
|
int32_t idx = -1;
|
||||||
0x01, Z(FAILURE),
|
for (uint32_t i = 0; i < sizeof(StatusIdx); i++) {
|
||||||
0x7E, Z(NOT_AUTHORIZED),
|
if (status == pgm_read_byte(&StatusIdx[i])) {
|
||||||
0x7F, Z(RESERVED_FIELD_NOT_ZERO),
|
idx = i;
|
||||||
0x80, Z(MALFORMED_COMMAND),
|
break;
|
||||||
0x81, Z(UNSUP_CLUSTER_COMMAND),
|
|
||||||
0x82, Z(UNSUP_GENERAL_COMMAND),
|
|
||||||
0x83, Z(UNSUP_MANUF_CLUSTER_COMMAND),
|
|
||||||
0x84, Z(UNSUP_MANUF_GENERAL_COMMAND),
|
|
||||||
0x85, Z(INVALID_FIELD),
|
|
||||||
0x86, Z(UNSUPPORTED_ATTRIBUTE),
|
|
||||||
0x87, Z(INVALID_VALUE),
|
|
||||||
0x88, Z(READ_ONLY),
|
|
||||||
0x89, Z(INSUFFICIENT_SPACE),
|
|
||||||
0x8A, Z(DUPLICATE_EXISTS),
|
|
||||||
0x8B, Z(NOT_FOUND),
|
|
||||||
0x8C, Z(UNREPORTABLE_ATTRIBUTE),
|
|
||||||
0x8D, Z(INVALID_DATA_TYPE),
|
|
||||||
0x8E, Z(INVALID_SELECTOR),
|
|
||||||
0x8F, Z(WRITE_ONLY),
|
|
||||||
0x90, Z(INCONSISTENT_STARTUP_STATE),
|
|
||||||
0x91, Z(DEFINED_OUT_OF_BAND),
|
|
||||||
0x92, Z(INCONSISTENT),
|
|
||||||
0x93, Z(ACTION_DENIED),
|
|
||||||
0x94, Z(TIMEOUT),
|
|
||||||
0x95, Z(ABORT),
|
|
||||||
0x96, Z(INVALID_IMAGE),
|
|
||||||
0x97, Z(WAIT_FOR_DATA),
|
|
||||||
0x98, Z(NO_IMAGE_AVAILABLE),
|
|
||||||
0x99, Z(REQUIRE_MORE_IMAGE),
|
|
||||||
0x9A, Z(NOTIFICATION_PENDING),
|
|
||||||
0xC0, Z(HARDWARE_FAILURE),
|
|
||||||
0xC1, Z(SOFTWARE_FAILURE),
|
|
||||||
0xC2, Z(CALIBRATION_ERROR),
|
|
||||||
0xC3, Z(UNSUPPORTED_CLUSTER),
|
|
||||||
};
|
|
||||||
|
|
||||||
const __FlashStringHelper* getZigbeeStatusMessage(uint8_t status) {
|
|
||||||
for (uint32_t i = 0; i < sizeof(Z_Status) / sizeof(Z_Status[0]); i++) {
|
|
||||||
const Z_StatusLine *statl = &Z_Status[i];
|
|
||||||
if (statl->status == status) {
|
|
||||||
return (const __FlashStringHelper*) statl->status_msg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return F("");
|
if (idx >= 0) {
|
||||||
|
GetTextIndexed(msg, sizeof(msg), idx, StatusMsg);
|
||||||
|
} else {
|
||||||
|
*msg = 0x00; // empty string
|
||||||
|
}
|
||||||
|
return String(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USE_ZIGBEE
|
#endif // USE_ZIGBEE
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
#endif
|
#endif
|
||||||
const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait for x seconds
|
const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait for x seconds
|
||||||
|
|
||||||
typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value);
|
/*********************************************************************************************\
|
||||||
|
* Structures for device configuration
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
const size_t endpoints_max = 8; // we limit to 8 endpoints
|
const size_t endpoints_max = 8; // we limit to 8 endpoints
|
||||||
|
|
||||||
|
@ -53,6 +55,12 @@ typedef struct Z_Device {
|
||||||
uint16_t x, y; // last color [x,y]
|
uint16_t x, y; // last color [x,y]
|
||||||
} Z_Device;
|
} Z_Device;
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Structures for deferred callbacks
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value);
|
||||||
|
|
||||||
// Category for Deferred actions, this allows to selectively remove active deferred or update them
|
// Category for Deferred actions, this allows to selectively remove active deferred or update them
|
||||||
typedef enum Z_Def_Category {
|
typedef enum Z_Def_Category {
|
||||||
Z_CAT_NONE = 0, // no category, it will happen anyways
|
Z_CAT_NONE = 0, // no category, it will happen anyways
|
||||||
|
@ -76,6 +84,10 @@ typedef struct Z_Deferred {
|
||||||
Z_DeviceTimer func; // function to call when timer occurs
|
Z_DeviceTimer func; // function to call when timer occurs
|
||||||
} Z_Deferred;
|
} Z_Deferred;
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Singleton for device configuration
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
// All devices are stored in a Vector
|
// All devices are stored in a Vector
|
||||||
// Invariants:
|
// Invariants:
|
||||||
// - shortaddr is unique if not null
|
// - shortaddr is unique if not null
|
||||||
|
@ -190,13 +202,22 @@ private:
|
||||||
// Create a new entry in the devices list - must be called if it is sure it does not already exist
|
// Create a new entry in the devices list - must be called if it is sure it does not already exist
|
||||||
Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0);
|
Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0);
|
||||||
void freeDeviceEntry(Z_Device *device);
|
void freeDeviceEntry(Z_Device *device);
|
||||||
|
|
||||||
|
void setStringAttribute(char*& attr, const char * str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Singleton variable
|
||||||
|
\*********************************************************************************************/
|
||||||
Z_Devices zigbee_devices = Z_Devices();
|
Z_Devices zigbee_devices = Z_Devices();
|
||||||
|
|
||||||
// Local coordinator information
|
// Local coordinator information
|
||||||
uint64_t localIEEEAddr = 0;
|
uint64_t localIEEEAddr = 0;
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Implementation
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
// https://thispointer.com/c-how-to-find-an-element-in-vector-and-get-its-index/
|
// https://thispointer.com/c-how-to-find-an-element-in-vector-and-get-its-index/
|
||||||
template < typename T>
|
template < typename T>
|
||||||
bool Z_Devices::findInVector(const std::vector<T> & vecOfElements, const T & element) {
|
bool Z_Devices::findInVector(const std::vector<T> & vecOfElements, const T & element) {
|
||||||
|
@ -493,73 +514,55 @@ uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const {
|
||||||
return device.endpoints[0]; // returns 0x00 if no endpoint
|
return device.endpoints[0]; // returns 0x00 if no endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
void Z_Devices::setManufId(uint16_t shortaddr, const char * str) {
|
void Z_Devices::setStringAttribute(char*& attr, const char * str) {
|
||||||
Z_Device & device = getShortAddr(shortaddr);
|
|
||||||
if (&device == nullptr) { return; } // don't crash if not found
|
|
||||||
size_t str_len = str ? strlen(str) : 0; // len, handle both null ptr and zero length string
|
size_t str_len = str ? strlen(str) : 0; // len, handle both null ptr and zero length string
|
||||||
|
|
||||||
if ((!device.manufacturerId) && (0 == str_len)) { return; } // if both empty, don't do anything
|
if ((nullptr == attr) && (0 == str_len)) { return; } // if both empty, don't do anything
|
||||||
if (device.manufacturerId) {
|
if (attr) {
|
||||||
// we already have a value
|
// we already have a value
|
||||||
if (strcmp(device.manufacturerId, str) != 0) {
|
if (strcmp(attr, str) != 0) {
|
||||||
// new value
|
// new value
|
||||||
free(device.manufacturerId); // free previous value
|
free(attr); // free previous value
|
||||||
device.manufacturerId = nullptr;
|
attr = nullptr;
|
||||||
} else {
|
} else {
|
||||||
return; // same value, don't change anything
|
return; // same value, don't change anything
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (str_len) {
|
if (str_len) {
|
||||||
device.manufacturerId = (char*) malloc(str_len + 1);
|
attr = (char*) malloc(str_len + 1);
|
||||||
strlcpy(device.manufacturerId, str, str_len + 1);
|
strlcpy(attr, str, str_len + 1);
|
||||||
}
|
}
|
||||||
dirty();
|
dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sets the ManufId for a device.
|
||||||
|
// No action taken if the device does not exist.
|
||||||
|
// Inputs:
|
||||||
|
// - shortaddr: 16-bits short address of the device. No action taken if the device is unknown
|
||||||
|
// - str: string pointer, if nullptr it is considered as empty string
|
||||||
|
// Impact:
|
||||||
|
// - Any actual change in ManufId (i.e. setting a different value) triggers a `dirty()` and saving to Flash
|
||||||
|
//
|
||||||
|
void Z_Devices::setManufId(uint16_t shortaddr, const char * str) {
|
||||||
|
Z_Device & device = getShortAddr(shortaddr);
|
||||||
|
if (&device == nullptr) { return; } // don't crash if not found
|
||||||
|
|
||||||
|
setStringAttribute(device.manufacturerId, str);
|
||||||
|
}
|
||||||
|
|
||||||
void Z_Devices::setModelId(uint16_t shortaddr, const char * str) {
|
void Z_Devices::setModelId(uint16_t shortaddr, const char * str) {
|
||||||
Z_Device & device = getShortAddr(shortaddr);
|
Z_Device & device = getShortAddr(shortaddr);
|
||||||
if (&device == nullptr) { return; } // don't crash if not found
|
if (&device == nullptr) { return; } // don't crash if not found
|
||||||
size_t str_len = str ? strlen(str) : 0; // len, handle both null ptr and zero length string
|
|
||||||
|
|
||||||
if ((!device.modelId) && (0 == str_len)) { return; } // if both empty, don't do anything
|
setStringAttribute(device.modelId, str);
|
||||||
if (device.modelId) {
|
|
||||||
// we already have a value
|
|
||||||
if (strcmp(device.modelId, str) != 0) {
|
|
||||||
// new value
|
|
||||||
free(device.modelId); // free previous value
|
|
||||||
device.modelId = nullptr;
|
|
||||||
} else {
|
|
||||||
return; // same value, don't change anything
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (str_len) {
|
|
||||||
device.modelId = (char*) malloc(str_len + 1);
|
|
||||||
strlcpy(device.modelId, str, str_len + 1);
|
|
||||||
}
|
|
||||||
dirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) {
|
void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) {
|
||||||
Z_Device & device = getShortAddr(shortaddr);
|
Z_Device & device = getShortAddr(shortaddr);
|
||||||
if (&device == nullptr) { return; } // don't crash if not found
|
if (&device == nullptr) { return; } // don't crash if not found
|
||||||
size_t str_len = str ? strlen(str) : 0; // len, handle both null ptr and zero length string
|
|
||||||
|
|
||||||
if ((!device.friendlyName) && (0 == str_len)) { return; } // if both empty, don't do anything
|
setStringAttribute(device.friendlyName, str);
|
||||||
if (device.friendlyName) {
|
|
||||||
// we already have a value
|
|
||||||
if (strcmp(device.friendlyName, str) != 0) {
|
|
||||||
// new value
|
|
||||||
free(device.friendlyName); // free previous value
|
|
||||||
device.friendlyName = nullptr;
|
|
||||||
} else {
|
|
||||||
return; // same value, don't change anything
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (str_len) {
|
|
||||||
device.friendlyName = (char*) malloc(str_len + 1);
|
|
||||||
strlcpy(device.friendlyName, str, str_len + 1);
|
|
||||||
}
|
|
||||||
dirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * Z_Devices::getFriendlyName(uint16_t shortaddr) const {
|
const char * Z_Devices::getFriendlyName(uint16_t shortaddr) const {
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
|
|
||||||
#ifdef USE_ZIGBEE
|
#ifdef USE_ZIGBEE
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* ZCL Command Structures
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
typedef struct Z_CommandConverter {
|
typedef struct Z_CommandConverter {
|
||||||
const char * tasmota_cmd;
|
const char * tasmota_cmd;
|
||||||
uint16_t cluster;
|
uint16_t cluster;
|
||||||
|
@ -130,6 +134,9 @@ const Z_CommandConverter Z_Commands[] PROGMEM = {
|
||||||
{ Z(GetSceneMembership),0x0005, 0x06, 0x82,Z(xxyyzzzz) }, // specific
|
{ Z(GetSceneMembership),0x0005, 0x06, 0x82,Z(xxyyzzzz) }, // specific
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* ZCL Read Light status based on cluster number
|
||||||
|
\*********************************************************************************************/
|
||||||
#define ZLE(x) ((x) & 0xFF), ((x) >> 8) // Little Endian
|
#define ZLE(x) ((x) & 0xFF), ((x) >> 8) // Little Endian
|
||||||
|
|
||||||
// Below are the attributes we wand to read from each cluster
|
// Below are the attributes we wand to read from each cluster
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifdef USE_ZIGBEE
|
#ifdef USE_ZIGBEE
|
||||||
|
|
||||||
// Status code used for ZigbeeStatus MQTT message
|
// Status code used for ZigbeeStatus MQTT message
|
||||||
// Ex: {"ZigbeeStatus":{"Status": 3,"Message":"Configured, starting coordinator"}}
|
// Ex: {"ZbStatus":{"Status": 3,"Message":"Configured, starting coordinator"}}
|
||||||
const uint8_t ZIGBEE_STATUS_OK = 0; // Zigbee started and working
|
const uint8_t ZIGBEE_STATUS_OK = 0; // Zigbee started and working
|
||||||
const uint8_t ZIGBEE_STATUS_BOOT = 1; // CC2530 booting
|
const uint8_t ZIGBEE_STATUS_BOOT = 1; // CC2530 booting
|
||||||
const uint8_t ZIGBEE_STATUS_RESET_CONF = 2; // Resetting CC2530 configuration
|
const uint8_t ZIGBEE_STATUS_RESET_CONF = 2; // Resetting CC2530 configuration
|
||||||
|
@ -33,7 +33,6 @@ 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_ACTIVE_EP = 32; // Endpoints descriptor
|
||||||
const uint8_t ZIGBEE_STATUS_SIMPLE_DESC = 33; // Simple Descriptor (clusters)
|
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_DEVICE_INDICATION = 34; // Device announces its address
|
||||||
//const uint8_t ZIGBEE_STATUS_DEVICE_IEEE = 35; // Request of device address
|
|
||||||
const uint8_t ZIGBEE_STATUS_CC_VERSION = 50; // Status: CC2530 ZNP Version
|
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_CC_INFO = 51; // Status: CC2530 Device Configuration
|
||||||
const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version
|
const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version
|
||||||
|
@ -50,9 +49,6 @@ typedef union Zigbee_Instruction {
|
||||||
} i;
|
} i;
|
||||||
const void *p; // pointer
|
const void *p; // pointer
|
||||||
} Zigbee_Instruction;
|
} Zigbee_Instruction;
|
||||||
//
|
|
||||||
// Zigbee_Instruction z1 = { .i = {1,2,3}};
|
|
||||||
// Zigbee_Instruction z3 = { .p = nullptr };
|
|
||||||
|
|
||||||
typedef struct Zigbee_Instruction_Type {
|
typedef struct Zigbee_Instruction_Type {
|
||||||
uint8_t instr;
|
uint8_t instr;
|
||||||
|
@ -488,7 +484,6 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
if (zigbee.state_waiting) { // state machine is waiting for external event or timeout
|
if (zigbee.state_waiting) { // state machine is waiting for external event or timeout
|
||||||
// checking if timeout expired
|
// checking if timeout expired
|
||||||
if ((zigbee.next_timeout) && (now > zigbee.next_timeout)) { // if next_timeout == 0 then wait forever
|
if ((zigbee.next_timeout) && (now > zigbee.next_timeout)) { // if next_timeout == 0 then wait forever
|
||||||
//AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "timeout occured pc=%d"), zigbee.pc);
|
|
||||||
if (!zigbee.state_no_timeout) {
|
if (!zigbee.state_no_timeout) {
|
||||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "timeout, goto label %d"), zigbee.on_timeout_goto);
|
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "timeout, goto label %d"), zigbee.on_timeout_goto);
|
||||||
ZigbeeGotoLabel(zigbee.on_timeout_goto);
|
ZigbeeGotoLabel(zigbee.on_timeout_goto);
|
||||||
|
@ -505,7 +500,6 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
zigbee.recv_until = false;
|
zigbee.recv_until = false;
|
||||||
zigbee.state_no_timeout = false; // reset the no_timeout for next instruction
|
zigbee.state_no_timeout = false; // reset the no_timeout for next instruction
|
||||||
|
|
||||||
// AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeStateMachine_Run PC = %d, Mem1 = %d"), zigbee.pc, ESP.getFreeHeap());
|
|
||||||
if (zigbee.pc > (sizeof(zb_prog)/sizeof(zb_prog[0]))) {
|
if (zigbee.pc > (sizeof(zb_prog)/sizeof(zb_prog[0]))) {
|
||||||
AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Invalid pc: %d, aborting"), zigbee.pc);
|
AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Invalid pc: %d, aborting"), zigbee.pc);
|
||||||
zigbee.pc = -1;
|
zigbee.pc = -1;
|
||||||
|
@ -516,7 +510,6 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load current instruction details
|
// load current instruction details
|
||||||
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Executing instruction pc=%d"), zigbee.pc);
|
|
||||||
const Zigbee_Instruction *cur_instr_line = &zb_prog[zigbee.pc];
|
const Zigbee_Instruction *cur_instr_line = &zb_prog[zigbee.pc];
|
||||||
cur_instr = pgm_read_byte(&cur_instr_line->i.i);
|
cur_instr = pgm_read_byte(&cur_instr_line->i.i);
|
||||||
cur_d8 = pgm_read_byte(&cur_instr_line->i.d8);
|
cur_d8 = pgm_read_byte(&cur_instr_line->i.d8);
|
||||||
|
@ -553,7 +546,6 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
case ZGB_INSTR_WAIT_FOREVER:
|
case ZGB_INSTR_WAIT_FOREVER:
|
||||||
zigbee.next_timeout = 0;
|
zigbee.next_timeout = 0;
|
||||||
zigbee.state_waiting = true;
|
zigbee.state_waiting = true;
|
||||||
//zigbee.state_no_timeout = true; // do not generate a timeout error when waiting is done
|
|
||||||
break;
|
break;
|
||||||
case ZGB_INSTR_STOP:
|
case ZGB_INSTR_STOP:
|
||||||
zigbee.state_machine = false;
|
zigbee.state_machine = false;
|
||||||
|
@ -617,4 +609,82 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process a bytes buffer and call any callback that matches the received message
|
||||||
|
//
|
||||||
|
int32_t ZigbeeProcessInput(class SBuffer &buf) {
|
||||||
|
if (!zigbee.state_machine) { return -1; } // if state machine is stopped, send 'ignore' message
|
||||||
|
|
||||||
|
// apply the receive filter, acts as 'startsWith()'
|
||||||
|
bool recv_filter_match = true;
|
||||||
|
bool recv_prefix_match = false; // do the first 2 bytes match the response
|
||||||
|
if ((zigbee.recv_filter) && (zigbee.recv_filter_len > 0)) {
|
||||||
|
if (zigbee.recv_filter_len >= 2) {
|
||||||
|
recv_prefix_match = false;
|
||||||
|
if ( (pgm_read_byte(&zigbee.recv_filter[0]) == buf.get8(0)) &&
|
||||||
|
(pgm_read_byte(&zigbee.recv_filter[1]) == buf.get8(1)) ) {
|
||||||
|
recv_prefix_match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < zigbee.recv_filter_len; i++) {
|
||||||
|
if (pgm_read_byte(&zigbee.recv_filter[i]) != buf.get8(i)) {
|
||||||
|
recv_filter_match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a recv_callback, call it now
|
||||||
|
int32_t res = -1; // default to ok
|
||||||
|
// res = 0 - proceed to next state
|
||||||
|
// res > 0 - proceed to the specified state
|
||||||
|
// res = -1 - silently ignore the message
|
||||||
|
// res <= -2 - move to error state
|
||||||
|
// pre-compute the suggested value
|
||||||
|
if ((zigbee.recv_filter) && (zigbee.recv_filter_len > 0)) {
|
||||||
|
if (!recv_prefix_match) {
|
||||||
|
res = -1; // ignore
|
||||||
|
} else { // recv_prefix_match
|
||||||
|
if (recv_filter_match) {
|
||||||
|
res = 0; // ok
|
||||||
|
} else {
|
||||||
|
if (zigbee.recv_until) {
|
||||||
|
res = -1; // ignore until full match
|
||||||
|
} else {
|
||||||
|
res = -2; // error, because message is expected but wrong value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // we don't have any filter, ignore message by default
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recv_prefix_match) {
|
||||||
|
if (zigbee.recv_func) {
|
||||||
|
res = (*zigbee.recv_func)(res, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-1 == res) {
|
||||||
|
// if frame was ignored up to now
|
||||||
|
if (zigbee.recv_unexpected) {
|
||||||
|
res = (*zigbee.recv_unexpected)(res, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// change state accordingly
|
||||||
|
if (0 == res) {
|
||||||
|
// if ok, continue execution
|
||||||
|
zigbee.state_waiting = false;
|
||||||
|
} else if (res > 0) {
|
||||||
|
ZigbeeGotoLabel(res); // if >0 then go to specified label
|
||||||
|
} else if (-1 == res) {
|
||||||
|
// -1 means ignore message
|
||||||
|
// just do nothing
|
||||||
|
} else {
|
||||||
|
// any other negative value means error
|
||||||
|
ZigbeeGotoLabel(zigbee.on_error_goto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // USE_ZIGBEE
|
#endif // USE_ZIGBEE
|
||||||
|
|
|
@ -19,6 +19,13 @@
|
||||||
|
|
||||||
#ifdef USE_ZIGBEE
|
#ifdef USE_ZIGBEE
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Parsers for incoming ZNP messages
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle a "Receive Device Info" incoming message
|
||||||
|
//
|
||||||
int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) {
|
int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) {
|
||||||
// Ex= 6700.00.6263151D004B1200.0000.07.09.02.83869991
|
// Ex= 6700.00.6263151D004B1200.0000.07.09.02.83869991
|
||||||
// IEEE Adr (8 bytes) = 0x00124B001D156362
|
// IEEE Adr (8 bytes) = 0x00124B001D156362
|
||||||
|
@ -76,12 +83,12 @@ int32_t Z_CheckNVWrite(int32_t res, class SBuffer &buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char Z_RebootReason[] PROGMEM = "Power-up|External|Watchdog";
|
|
||||||
|
|
||||||
int32_t Z_Reboot(int32_t res, class SBuffer &buf) {
|
int32_t Z_Reboot(int32_t res, class SBuffer &buf) {
|
||||||
// print information about the reboot of device
|
// print information about the reboot of device
|
||||||
// 4180.02.02.00.02.06.03
|
// 4180.02.02.00.02.06.03
|
||||||
//
|
//
|
||||||
|
static const char Z_RebootReason[] PROGMEM = "Power-up|External|Watchdog";
|
||||||
|
|
||||||
uint8_t reason = buf.get8(2);
|
uint8_t reason = buf.get8(2);
|
||||||
uint8_t transport_rev = buf.get8(3);
|
uint8_t transport_rev = buf.get8(3);
|
||||||
uint8_t product_id = buf.get8(4);
|
uint8_t product_id = buf.get8(4);
|
||||||
|
@ -140,6 +147,9 @@ int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helper function, checks if the incoming buffer matches the 2-bytes prefix, i.e. message type in PMEM
|
||||||
|
//
|
||||||
bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) {
|
bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) {
|
||||||
if ( (pgm_read_byte(&match[0]) == buf.get8(0)) &&
|
if ( (pgm_read_byte(&match[0]) == buf.get8(0)) &&
|
||||||
(pgm_read_byte(&match[1]) == buf.get8(1)) ) {
|
(pgm_read_byte(&match[1]) == buf.get8(1)) ) {
|
||||||
|
@ -149,6 +159,9 @@ bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle Permit Join response
|
||||||
|
//
|
||||||
int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) {
|
||||||
// we received a PermitJoin status change
|
// we received a PermitJoin status change
|
||||||
uint8_t duration = buf.get8(2);
|
uint8_t duration = buf.get8(2);
|
||||||
|
@ -176,22 +189,6 @@ int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send ZDO_IEEE_ADDR_REQ request to get IEEE long address
|
|
||||||
void Z_SendIEEEAddrReq(uint16_t shortaddr) {
|
|
||||||
uint8_t IEEEAddrReq[] = { Z_SREQ | Z_ZDO, ZDO_IEEE_ADDR_REQ,
|
|
||||||
Z_B0(shortaddr), Z_B1(shortaddr), 0x00, 0x00 };
|
|
||||||
|
|
||||||
ZigbeeZNPSend(IEEEAddrReq, sizeof(IEEEAddrReq));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send ACTIVE_EP_REQ to collect active endpoints for this address
|
|
||||||
void Z_SendActiveEpReq(uint16_t shortaddr) {
|
|
||||||
uint8_t ActiveEpReq[] = { Z_SREQ | Z_ZDO, ZDO_ACTIVE_EP_REQ,
|
|
||||||
Z_B0(shortaddr), Z_B1(shortaddr), Z_B0(shortaddr), Z_B1(shortaddr) };
|
|
||||||
|
|
||||||
ZigbeeZNPSend(ActiveEpReq, sizeof(ActiveEpReq));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Z_DeviceType[] = { "Coordinator", "Router", "End Device", "Unknown" };
|
const char* Z_DeviceType[] = { "Coordinator", "Router", "End Device", "Unknown" };
|
||||||
int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) {
|
||||||
// Received ZDO_NODE_DESC_RSP
|
// Received ZDO_NODE_DESC_RSP
|
||||||
|
@ -226,6 +223,9 @@ int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Porcess Receive Active Endpoint
|
||||||
|
//
|
||||||
int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) {
|
||||||
// Received ZDO_ACTIVE_EP_RSP
|
// Received ZDO_ACTIVE_EP_RSP
|
||||||
Z_ShortAddress srcAddr = buf.get16(2);
|
Z_ShortAddress srcAddr = buf.get16(2);
|
||||||
|
@ -254,37 +254,14 @@ int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Z_SendAFInfoRequest(uint16_t shortaddr) {
|
//
|
||||||
uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
// Handle IEEEAddr incoming message
|
||||||
if (0x00 == endpoint) { endpoint = 0x01; } // if we don't know the endpoint, try 0x01
|
//
|
||||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
|
||||||
|
|
||||||
SBuffer buf(100);
|
|
||||||
buf.add8(Z_SREQ | Z_AF); // 24
|
|
||||||
buf.add8(AF_DATA_REQUEST); // 01
|
|
||||||
buf.add16(shortaddr);
|
|
||||||
buf.add8(endpoint); // dest endpoint
|
|
||||||
buf.add8(0x01); // source endpoint
|
|
||||||
buf.add16(0x0000);
|
|
||||||
buf.add8(transacid);
|
|
||||||
buf.add8(0x30); // 30 options
|
|
||||||
buf.add8(0x1E); // 1E radius
|
|
||||||
|
|
||||||
buf.add8(3 + 2*sizeof(uint16_t)); // Len = 0x07
|
|
||||||
buf.add8(0x00); // Frame Control Field
|
|
||||||
buf.add8(transacid); // Transaction Sequence Number
|
|
||||||
buf.add8(ZCL_READ_ATTRIBUTES); // 00 Command
|
|
||||||
buf.add16(0x0004); // 0400 ManufacturerName
|
|
||||||
buf.add16(0x0005); // 0500 ModelIdentifier
|
|
||||||
|
|
||||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) {
|
||||||
uint8_t status = buf.get8(2);
|
uint8_t status = buf.get8(2);
|
||||||
Z_IEEEAddress ieeeAddr = buf.get64(3);
|
Z_IEEEAddress ieeeAddr = buf.get64(3);
|
||||||
Z_ShortAddress nwkAddr = buf.get16(11);
|
Z_ShortAddress nwkAddr = buf.get16(11);
|
||||||
// uint8_t startIndex = buf.get8(13);
|
// uint8_t startIndex = buf.get8(13); // not used
|
||||||
// uint8_t numAssocDev = buf.get8(14);
|
// uint8_t numAssocDev = buf.get8(14);
|
||||||
|
|
||||||
if (0 == status) { // SUCCESS
|
if (0 == status) { // SUCCESS
|
||||||
|
@ -308,34 +285,6 @@ int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) {
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) {
|
|
||||||
Z_ShortAddress nwkAddr = buf.get16(2);
|
|
||||||
uint8_t status = buf.get8(4);
|
|
||||||
char status_message[32];
|
|
||||||
|
|
||||||
strncpy_P(status_message, (const char*) getZigbeeStatusMessage(status), sizeof(status_message));
|
|
||||||
status_message[sizeof(status_message)-1] = 0; // truncate if needed, strlcpy is safer but strlcpy_P does not exist
|
|
||||||
|
|
||||||
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
|
||||||
if (friendlyName) {
|
|
||||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
|
||||||
",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""
|
|
||||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
|
||||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
|
||||||
"}}"), nwkAddr, friendlyName, status, status_message);
|
|
||||||
} else {
|
|
||||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
|
||||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
|
||||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
|
||||||
"}}"), nwkAddr, status, status_message);
|
|
||||||
}
|
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
|
||||||
XdrvRulesProcess();
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Report any AF_DATA_CONFIRM message
|
// Report any AF_DATA_CONFIRM message
|
||||||
// Ex: {"ZbConfirm":{"Endpoint":1,"Status":0,"StatusMessage":"SUCCESS"}}
|
// Ex: {"ZbConfirm":{"Endpoint":1,"Status":0,"StatusMessage":"SUCCESS"}}
|
||||||
|
@ -343,17 +292,13 @@ int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) {
|
||||||
int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf) {
|
int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf) {
|
||||||
uint8_t status = buf.get8(2);
|
uint8_t status = buf.get8(2);
|
||||||
uint8_t endpoint = buf.get8(3);
|
uint8_t endpoint = buf.get8(3);
|
||||||
//uint8_t transId = buf.get8(4);
|
//uint8_t transId = buf.get8(4); // unused
|
||||||
char status_message[32];
|
|
||||||
|
|
||||||
if (status) { // only report errors
|
if (status) { // only report errors
|
||||||
strncpy_P(status_message, (const char*) getZigbeeStatusMessage(status), sizeof(status_message));
|
|
||||||
status_message[sizeof(status_message)-1] = 0; // truncate if needed, strlcpy is safer but strlcpy_P does not exist
|
|
||||||
|
|
||||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_CONFIRM "\":{\"" D_CMND_ZIGBEE_ENDPOINT "\":%d"
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_CONFIRM "\":{\"" D_CMND_ZIGBEE_ENDPOINT "\":%d"
|
||||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||||
"}}"), endpoint, status, status_message);
|
"}}"), endpoint, status, getZigbeeStatusMessage(status).c_str());
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||||
XdrvRulesProcess();
|
XdrvRulesProcess();
|
||||||
}
|
}
|
||||||
|
@ -361,6 +306,10 @@ int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle Receive End Device Announce incoming message
|
||||||
|
// Send back Active Ep Req message
|
||||||
|
//
|
||||||
int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
||||||
Z_ShortAddress srcAddr = buf.get16(2);
|
Z_ShortAddress srcAddr = buf.get16(2);
|
||||||
Z_ShortAddress nwkAddr = buf.get16(4);
|
Z_ShortAddress nwkAddr = buf.get16(4);
|
||||||
|
@ -386,7 +335,10 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle Receive TC Dev Ind incoming message
|
||||||
// 45CA
|
// 45CA
|
||||||
|
//
|
||||||
int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) {
|
||||||
Z_ShortAddress srcAddr = buf.get16(2);
|
Z_ShortAddress srcAddr = buf.get16(2);
|
||||||
Z_IEEEAddress ieeeAddr = buf.get64(4);
|
Z_IEEEAddress ieeeAddr = buf.get64(4);
|
||||||
|
@ -404,15 +356,82 @@ int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) {
|
||||||
|
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||||
XdrvRulesProcess();
|
XdrvRulesProcess();
|
||||||
//Z_SendActiveEpReq(srcAddr);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle Bind Rsp incoming message
|
||||||
|
//
|
||||||
|
int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) {
|
||||||
|
Z_ShortAddress nwkAddr = buf.get16(2);
|
||||||
|
uint8_t status = buf.get8(4);
|
||||||
|
|
||||||
|
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
||||||
|
if (friendlyName) {
|
||||||
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||||
|
",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""
|
||||||
|
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||||
|
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||||
|
"}}"), nwkAddr, friendlyName, status, getZigbeeStatusMessage(status).c_str());
|
||||||
|
} else {
|
||||||
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||||
|
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||||
|
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||||
|
"}}"), nwkAddr, status, getZigbeeStatusMessage(status).c_str());
|
||||||
|
}
|
||||||
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||||
|
XdrvRulesProcess();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Send specific ZNP messages
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send ZDO_IEEE_ADDR_REQ request to get IEEE long address
|
||||||
|
//
|
||||||
|
void Z_SendIEEEAddrReq(uint16_t shortaddr) {
|
||||||
|
uint8_t IEEEAddrReq[] = { Z_SREQ | Z_ZDO, ZDO_IEEE_ADDR_REQ, Z_B0(shortaddr), Z_B1(shortaddr), 0x00, 0x00 };
|
||||||
|
|
||||||
|
ZigbeeZNPSend(IEEEAddrReq, sizeof(IEEEAddrReq));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send ACTIVE_EP_REQ to collect active endpoints for this address
|
||||||
|
//
|
||||||
|
void Z_SendActiveEpReq(uint16_t shortaddr) {
|
||||||
|
uint8_t ActiveEpReq[] = { Z_SREQ | Z_ZDO, ZDO_ACTIVE_EP_REQ, Z_B0(shortaddr), Z_B1(shortaddr), Z_B0(shortaddr), Z_B1(shortaddr) };
|
||||||
|
|
||||||
|
ZigbeeZNPSend(ActiveEpReq, sizeof(ActiveEpReq));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send AF Info Request
|
||||||
|
//
|
||||||
|
void Z_SendAFInfoRequest(uint16_t shortaddr) {
|
||||||
|
uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||||
|
if (0x00 == endpoint) { endpoint = 0x01; } // if we don't know the endpoint, try 0x01
|
||||||
|
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
||||||
|
|
||||||
|
uint8_t AFInfoReq[] = { Z_SREQ | Z_AF, AF_DATA_REQUEST, Z_B0(shortaddr), Z_B1(shortaddr), endpoint,
|
||||||
|
0x01, 0x00, 0x00, transacid, 0x30, 0x1E, 3 + 2*sizeof(uint16_t),
|
||||||
|
0x00, transacid, ZCL_READ_ATTRIBUTES, 0x04, 0x00, 0x05, 0x00
|
||||||
|
};
|
||||||
|
ZigbeeZNPSend(AFInfoReq, sizeof(AFInfoReq));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Callbacks
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
// Aqara Occupancy behavior: the Aqara device only sends Occupancy: true events every 60 seconds.
|
// 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
|
// 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
|
|
||||||
|
|
||||||
void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, const JsonObject *json) {
|
void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, const JsonObject *json) {
|
||||||
|
static const uint32_t OCCUPANCY_TIMEOUT = 90 * 1000; // 90 s
|
||||||
// Read OCCUPANCY value if any
|
// Read OCCUPANCY value if any
|
||||||
const JsonVariant &val_endpoint = getCaseInsensitive(*json, PSTR(OCCUPANCY));
|
const JsonVariant &val_endpoint = getCaseInsensitive(*json, PSTR(OCCUPANCY));
|
||||||
if (nullptr != &val_endpoint) {
|
if (nullptr != &val_endpoint) {
|
||||||
|
@ -436,6 +455,10 @@ int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Global dispatcher for incoming messages
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||||
uint16_t groupid = buf.get16(2);
|
uint16_t groupid = buf.get16(2);
|
||||||
uint16_t clusterid = buf.get16(4);
|
uint16_t clusterid = buf.get16(4);
|
||||||
|
@ -506,22 +529,24 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Structure for the Dispatcher callbacks table
|
||||||
typedef struct Z_Dispatcher {
|
typedef struct Z_Dispatcher {
|
||||||
const uint8_t* match;
|
const uint8_t* match;
|
||||||
ZB_RecvMsgFunc func;
|
ZB_RecvMsgFunc func;
|
||||||
} Z_Dispatcher;
|
} Z_Dispatcher;
|
||||||
|
|
||||||
// Filters for ZCL frames
|
// Ffilters based on ZNP frames
|
||||||
ZBM(AREQ_AF_DATA_CONFIRM, Z_AREQ | Z_AF, AF_DATA_CONFIRM) // 4480
|
ZBM(AREQ_AF_DATA_CONFIRM, Z_AREQ | Z_AF, AF_DATA_CONFIRM) // 4480
|
||||||
ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
|
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_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_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_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_ACTIVEEPRSP, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP) // 4585
|
||||||
ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584
|
ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584
|
||||||
ZBM(AREQ_ZDO_IEEE_ADDR_RSP, Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP) // 4581
|
ZBM(AREQ_ZDO_IEEE_ADDR_RSP, Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP) // 4581
|
||||||
ZBM(AREQ_ZDO_BIND_RSP, Z_AREQ | Z_ZDO, ZDO_BIND_RSP) // 45A1
|
ZBM(AREQ_ZDO_BIND_RSP, Z_AREQ | Z_ZDO, ZDO_BIND_RSP) // 45A1
|
||||||
|
|
||||||
|
// Dispatcher callbacks table
|
||||||
const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
|
const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
|
||||||
{ AREQ_AF_DATA_CONFIRM, &Z_DataConfirm },
|
{ AREQ_AF_DATA_CONFIRM, &Z_DataConfirm },
|
||||||
{ AREQ_AF_INCOMING_MESSAGE, &Z_ReceiveAfIncomingMessage },
|
{ AREQ_AF_INCOMING_MESSAGE, &Z_ReceiveAfIncomingMessage },
|
||||||
|
@ -534,6 +559,10 @@ const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
|
||||||
{ AREQ_ZDO_BIND_RSP, &Z_BindRsp },
|
{ AREQ_ZDO_BIND_RSP, &Z_BindRsp },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Default resolver
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
|
int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
|
||||||
// Default message handler for new messages
|
// Default message handler for new messages
|
||||||
if (zigbee.init_phase) {
|
if (zigbee.init_phase) {
|
||||||
|
@ -549,12 +578,22 @@ int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Functions called by State Machine
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Callback for loading Zigbee configuration from Flash, called by the state machine
|
||||||
|
//
|
||||||
int32_t Z_Load_Devices(uint8_t value) {
|
int32_t Z_Load_Devices(uint8_t value) {
|
||||||
// try to hidrate from known devices
|
// try to hidrate from known devices
|
||||||
loadZigbeeDevices();
|
loadZigbeeDevices();
|
||||||
return 0; // continue
|
return 0; // continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send messages to query the state of each Hue emulated light
|
||||||
|
//
|
||||||
int32_t Z_Query_Bulbs(uint8_t value) {
|
int32_t Z_Query_Bulbs(uint8_t value) {
|
||||||
// Scan all devices and send deferred requests to know the state of bulbs
|
// Scan all devices and send deferred requests to know the state of bulbs
|
||||||
uint32_t wait_ms = 1000; // start with 1.0 s delay
|
uint32_t wait_ms = 1000; // start with 1.0 s delay
|
||||||
|
@ -588,6 +627,9 @@ int32_t Z_Query_Bulbs(uint8_t value) {
|
||||||
return 0; // continue
|
return 0; // continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Zigbee initialization is complete, let the party begin
|
||||||
|
//
|
||||||
int32_t Z_State_Ready(uint8_t value) {
|
int32_t Z_State_Ready(uint8_t value) {
|
||||||
zigbee.init_phase = false; // initialization phase complete
|
zigbee.init_phase = false; // initialization phase complete
|
||||||
return 0; // continue
|
return 0; // continue
|
||||||
|
|
|
@ -47,85 +47,10 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
|
||||||
&CmndZbLight, CmndZbRestore,
|
&CmndZbLight, CmndZbRestore,
|
||||||
};
|
};
|
||||||
|
|
||||||
int32_t ZigbeeProcessInput(class SBuffer &buf) {
|
//
|
||||||
if (!zigbee.state_machine) { return -1; } // if state machine is stopped, send 'ignore' message
|
// Called at event loop, checks for incoming data from the CC2530
|
||||||
|
//
|
||||||
// apply the receive filter, acts as 'startsWith()'
|
void ZigbeeInputLoop(void)
|
||||||
bool recv_filter_match = true;
|
|
||||||
bool recv_prefix_match = false; // do the first 2 bytes match the response
|
|
||||||
if ((zigbee.recv_filter) && (zigbee.recv_filter_len > 0)) {
|
|
||||||
if (zigbee.recv_filter_len >= 2) {
|
|
||||||
recv_prefix_match = false;
|
|
||||||
if ( (pgm_read_byte(&zigbee.recv_filter[0]) == buf.get8(0)) &&
|
|
||||||
(pgm_read_byte(&zigbee.recv_filter[1]) == buf.get8(1)) ) {
|
|
||||||
recv_prefix_match = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < zigbee.recv_filter_len; i++) {
|
|
||||||
if (pgm_read_byte(&zigbee.recv_filter[i]) != buf.get8(i)) {
|
|
||||||
recv_filter_match = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "ZbProcessInput: recv_prefix_match = %d, recv_filter_match = %d"), recv_prefix_match, recv_filter_match);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is a recv_callback, call it now
|
|
||||||
int32_t res = -1; // default to ok
|
|
||||||
// res = 0 - proceed to next state
|
|
||||||
// res > 0 - proceed to the specified state
|
|
||||||
// res = -1 - silently ignore the message
|
|
||||||
// res <= -2 - move to error state
|
|
||||||
// pre-compute the suggested value
|
|
||||||
if ((zigbee.recv_filter) && (zigbee.recv_filter_len > 0)) {
|
|
||||||
if (!recv_prefix_match) {
|
|
||||||
res = -1; // ignore
|
|
||||||
} else { // recv_prefix_match
|
|
||||||
if (recv_filter_match) {
|
|
||||||
res = 0; // ok
|
|
||||||
} else {
|
|
||||||
if (zigbee.recv_until) {
|
|
||||||
res = -1; // ignore until full match
|
|
||||||
} else {
|
|
||||||
res = -2; // error, because message is expected but wrong value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // we don't have any filter, ignore message by default
|
|
||||||
res = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recv_prefix_match) {
|
|
||||||
if (zigbee.recv_func) {
|
|
||||||
res = (*zigbee.recv_func)(res, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (-1 == res) {
|
|
||||||
// if frame was ignored up to now
|
|
||||||
if (zigbee.recv_unexpected) {
|
|
||||||
res = (*zigbee.recv_unexpected)(res, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "ZbProcessInput: res = %d"), res);
|
|
||||||
|
|
||||||
// change state accordingly
|
|
||||||
if (0 == res) {
|
|
||||||
// if ok, continue execution
|
|
||||||
zigbee.state_waiting = false;
|
|
||||||
} else if (res > 0) {
|
|
||||||
ZigbeeGotoLabel(res); // if >0 then go to specified label
|
|
||||||
} else if (-1 == res) {
|
|
||||||
// -1 means ignore message
|
|
||||||
// just do nothing
|
|
||||||
} else {
|
|
||||||
// any other negative value means error
|
|
||||||
ZigbeeGotoLabel(zigbee.on_error_goto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZigbeeInput(void)
|
|
||||||
{
|
{
|
||||||
static uint32_t zigbee_polling_window = 0;
|
static uint32_t zigbee_polling_window = 0;
|
||||||
static uint8_t fcs = ZIGBEE_SOF;
|
static uint8_t fcs = ZIGBEE_SOF;
|
||||||
|
@ -217,6 +142,7 @@ void ZigbeeInput(void)
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
|
||||||
|
// Initialize internal structures
|
||||||
void ZigbeeInit(void)
|
void ZigbeeInit(void)
|
||||||
{
|
{
|
||||||
// AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeInit Mem1 = %d"), ESP.getFreeHeap());
|
// AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeInit Mem1 = %d"), ESP.getFreeHeap());
|
||||||
|
@ -260,10 +186,10 @@ uint32_t strToUInt(const JsonVariant &val) {
|
||||||
return 0; // couldn't parse anything
|
return 0; // couldn't parse anything
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do a factory reset of the CC2530
|
||||||
const unsigned char ZIGBEE_FACTORY_RESET[] PROGMEM =
|
const unsigned char ZIGBEE_FACTORY_RESET[] PROGMEM =
|
||||||
{ Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 /* len */, 0x01 /* STARTOPT_CLEAR_CONFIG */};
|
{ Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 /* len */, 0x01 /* STARTOPT_CLEAR_CONFIG */};
|
||||||
//"2605030101"; // Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 len, 0x01 STARTOPT_CLEAR_CONFIG
|
//"2605030101"; // Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 len, 0x01 STARTOPT_CLEAR_CONFIG
|
||||||
// Do a factory reset of the CC2530
|
|
||||||
void CmndZbReset(void) {
|
void CmndZbReset(void) {
|
||||||
if (ZigbeeSerial) {
|
if (ZigbeeSerial) {
|
||||||
switch (XdrvMailbox.payload) {
|
switch (XdrvMailbox.payload) {
|
||||||
|
@ -279,6 +205,10 @@ void CmndZbReset(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Same code for `ZbZNPSend` and `ZbZNPReceive`
|
||||||
|
// building the complete message (intro, length)
|
||||||
|
//
|
||||||
void CmndZbZNPSendOrReceive(bool send)
|
void CmndZbZNPSendOrReceive(bool send)
|
||||||
{
|
{
|
||||||
if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) {
|
if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) {
|
||||||
|
@ -298,8 +228,10 @@ void CmndZbZNPSendOrReceive(bool send)
|
||||||
codes += 2;
|
codes += 2;
|
||||||
}
|
}
|
||||||
if (send) {
|
if (send) {
|
||||||
|
// Command was `ZbZNPSend`
|
||||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||||
} else {
|
} else {
|
||||||
|
// Command was `ZbZNPReceive`
|
||||||
ZigbeeProcessInput(buf);
|
ZigbeeProcessInput(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,6 +279,21 @@ void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
|
||||||
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
|
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Internal function, send the low-level frame
|
||||||
|
// Input:
|
||||||
|
// - shortaddr: 16-bits short address, or 0x0000 if group address
|
||||||
|
// - groupaddr: 16-bits group address, or 0x0000 if unicast using shortaddr
|
||||||
|
// - clusterIf: 16-bits cluster number
|
||||||
|
// - endpoint: 8-bits target endpoint (source is always 0x01), unused for group addresses. Should not be 0x00 except when sending to group address.
|
||||||
|
// - cmdId: 8-bits ZCL command number
|
||||||
|
// - clusterSpecific: boolean, is the message general cluster or cluster specific, used to create the FC byte of ZCL
|
||||||
|
// - 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
|
||||||
|
// - transacId: 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(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId) {
|
void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId) {
|
||||||
|
|
||||||
SBuffer buf(32+len);
|
SBuffer buf(32+len);
|
||||||
|
@ -379,7 +326,22 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI
|
||||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a command specified as an HEX string for the workload
|
/********************************************************************************************/
|
||||||
|
//
|
||||||
|
// High-level function
|
||||||
|
// Send a command specified as an HEX string for the workload.
|
||||||
|
// The target endpoint is computed if zero, i.e. sent to the first known endpoint of the device.
|
||||||
|
// If cluster-specific, a timer may be set calling `zigbeeSetCommandTimer()`, for ex to coalesce attributes or Aqara presence sensor
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// - shortaddr: 16-bits short address, or 0x0000 if group address
|
||||||
|
// - groupaddr: 16-bits group address, or 0x0000 if unicast using shortaddr
|
||||||
|
// - endpoint: 8-bits target endpoint (source is always 0x01), if 0x00, it will be guessed from ZbStatus information (basically the first endpoint of the device)
|
||||||
|
// - clusterSpecific: boolean, is the message general cluster or cluster specific, used to create the FC byte of ZCL
|
||||||
|
// - clusterIf: 16-bits cluster number
|
||||||
|
// - param: pointer to HEX string for payload, should not be nullptr
|
||||||
|
// Returns: None
|
||||||
|
//
|
||||||
void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, bool clusterSpecific,
|
void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, bool clusterSpecific,
|
||||||
uint16_t cluster, uint8_t cmd, const char *param) {
|
uint16_t cluster, uint8_t cmd, const char *param) {
|
||||||
size_t size = param ? strlen(param) : 0;
|
size_t size = param ? strlen(param) : 0;
|
||||||
|
@ -395,15 +357,15 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
|
||||||
if ((0 == endpoint) && (shortaddr)) {
|
if ((0 == endpoint) && (shortaddr)) {
|
||||||
// endpoint is not specified, let's try to find it from shortAddr, unless it's a group address
|
// endpoint is not specified, let's try to find it from shortAddr, unless it's a group address
|
||||||
endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
||||||
}
|
}
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"),
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"),
|
||||||
shortaddr, groupaddr, cluster, endpoint, cmd, param);
|
shortaddr, groupaddr, cluster, endpoint, cmd, param);
|
||||||
|
|
||||||
if ((0 == endpoint) && (shortaddr)) {
|
if ((0 == endpoint) && (shortaddr)) { // endpoint null is ok for group address
|
||||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
||||||
return;
|
return;
|
||||||
} // endpoint null is ok for group address
|
}
|
||||||
|
|
||||||
// everything is good, we can send the command
|
// everything is good, we can send the command
|
||||||
ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, cmd, clusterSpecific, buf.getBuffer(), buf.len(), true, zigbee_devices.getNextSeqNumber(shortaddr));
|
ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, cmd, clusterSpecific, buf.getBuffer(), buf.len(), true, zigbee_devices.getNextSeqNumber(shortaddr));
|
||||||
|
@ -413,21 +375,24 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbSend`
|
||||||
|
//
|
||||||
void CmndZbSend(void) {
|
void CmndZbSend(void) {
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":1} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":1} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"3"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"3"} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"0xFF"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"0xFF"} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":null} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":null} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":false} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":false} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":true} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":true} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"true"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"true"} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"ShutterClose":null} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"ShutterClose":null} }
|
||||||
// ZigbeeSend { "devicse":"0x1234", "endpoint":"0x03", "send":{"Power":1} }
|
// ZbSend { "devicse":"0x1234", "endpoint":"0x03", "send":{"Power":1} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"1,2"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"1,2"} }
|
||||||
// ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"0x1122,0xFFEE"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"0x1122,0xFFEE"} }
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
DynamicJsonBuffer jsonBuf;
|
DynamicJsonBuffer jsonBuf;
|
||||||
JsonObject &json = jsonBuf.parseObject(XdrvMailbox.data);
|
const JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data);
|
||||||
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
// params
|
// params
|
||||||
|
@ -463,16 +428,16 @@ void CmndZbSend(void) {
|
||||||
// If String, it's a low level command
|
// If String, it's a low level command
|
||||||
if (val_cmd.is<JsonObject>()) {
|
if (val_cmd.is<JsonObject>()) {
|
||||||
// we have a high-level command
|
// we have a high-level command
|
||||||
JsonObject &cmd_obj = val_cmd.as<JsonObject&>();
|
const JsonObject &cmd_obj = val_cmd.as<const JsonObject&>();
|
||||||
int32_t cmd_size = cmd_obj.size();
|
int32_t cmd_size = cmd_obj.size();
|
||||||
if (cmd_size > 1) {
|
if (cmd_size > 1) {
|
||||||
Response_P(PSTR("Only 1 command allowed (%d)"), cmd_size);
|
Response_P(PSTR("Only 1 command allowed (%d)"), cmd_size);
|
||||||
return;
|
return;
|
||||||
} else if (1 == cmd_size) {
|
} else if (1 == cmd_size) {
|
||||||
// We have exactly 1 command, parse it
|
// We have exactly 1 command, parse it
|
||||||
JsonObject::iterator it = cmd_obj.begin(); // just get the first key/value
|
JsonObject::const_iterator it = cmd_obj.begin(); // just get the first key/value
|
||||||
String key = it->key;
|
String key = it->key;
|
||||||
JsonVariant& value = it->value;
|
const JsonVariant& value = it->value;
|
||||||
uint32_t x = 0, y = 0, z = 0;
|
uint32_t x = 0, y = 0, z = 0;
|
||||||
uint16_t cmd_var;
|
uint16_t cmd_var;
|
||||||
|
|
||||||
|
@ -526,7 +491,7 @@ void CmndZbSend(void) {
|
||||||
} else {
|
} else {
|
||||||
// we have zero command, pass through until last error for missing command
|
// we have zero command, pass through until last error for missing command
|
||||||
}
|
}
|
||||||
} else if (val_cmd.is<char*>()) {
|
} else if (val_cmd.is<const char*>()) {
|
||||||
// low-level command
|
// low-level command
|
||||||
cmd_str = val_cmd.as<String>();
|
cmd_str = val_cmd.as<String>();
|
||||||
// Now parse the string to extract cluster, command, and payload
|
// Now parse the string to extract cluster, command, and payload
|
||||||
|
@ -564,16 +529,18 @@ void CmndZbSend(void) {
|
||||||
Response_P(PSTR("Missing zigbee 'Send'"));
|
Response_P(PSTR("Missing zigbee 'Send'"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbBind`
|
||||||
|
//
|
||||||
void CmndZbBind(void) {
|
void CmndZbBind(void) {
|
||||||
// ZbBind { "device":"0x1234", "endpoint":1, "cluster":6 }
|
// ZbBind {"Device":"<device>", "Endpoint":<endpoint>, "Cluster":<cluster>, "ToDevice":"<to_device>", "ToEndpoint":<to_endpoint>, "ToGroup":<to_group> }
|
||||||
|
|
||||||
// local endpoint is always 1, IEEE addresses are calculated
|
// local endpoint is always 1, IEEE addresses are calculated
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
DynamicJsonBuffer jsonBuf;
|
DynamicJsonBuffer jsonBuf;
|
||||||
JsonObject &json = jsonBuf.parseObject(XdrvMailbox.data);
|
const JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data);
|
||||||
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
// params
|
// params
|
||||||
|
@ -658,6 +625,9 @@ void CmndZbProbe(void) {
|
||||||
CmndZbProbeOrPing(true);
|
CmndZbProbeOrPing(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Common code for `ZbProbe` and `ZbPing`
|
||||||
|
//
|
||||||
void CmndZbProbeOrPing(boolean probe) {
|
void CmndZbProbeOrPing(boolean probe) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||||
|
@ -677,12 +647,15 @@ void CmndZbPing(void) {
|
||||||
CmndZbProbeOrPing(false);
|
CmndZbProbeOrPing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbName`
|
||||||
// Specify, read or erase a Friendly Name
|
// Specify, read or erase a Friendly Name
|
||||||
|
//
|
||||||
void CmndZbName(void) {
|
void CmndZbName(void) {
|
||||||
// Syntax is:
|
// Syntax is:
|
||||||
// ZigbeeName <device_id>,<friendlyname> - assign a friendly name
|
// ZbName <device_id>,<friendlyname> - assign a friendly name
|
||||||
// ZigbeeName <device_id> - display the current friendly name
|
// ZbName <device_id> - display the current friendly name
|
||||||
// ZigbeeName <device_id>, - remove friendly name
|
// ZbName <device_id>, - remove friendly name
|
||||||
//
|
//
|
||||||
// Where <device_id> can be: short_addr, long_addr, device_index, friendly_name
|
// Where <device_id> can be: short_addr, long_addr, device_index, friendly_name
|
||||||
|
|
||||||
|
@ -706,12 +679,15 @@ void CmndZbName(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbName`
|
||||||
// Specify, read or erase a ModelId, only for debug purposes
|
// Specify, read or erase a ModelId, only for debug purposes
|
||||||
|
//
|
||||||
void CmndZbModelId(void) {
|
void CmndZbModelId(void) {
|
||||||
// Syntax is:
|
// Syntax is:
|
||||||
// ZigbeeName <device_id>,<friendlyname> - assign a friendly name
|
// ZbName <device_id>,<friendlyname> - assign a friendly name
|
||||||
// ZigbeeName <device_id> - display the current friendly name
|
// ZbName <device_id> - display the current friendly name
|
||||||
// ZigbeeName <device_id>, - remove friendly name
|
// ZbName <device_id>, - remove friendly name
|
||||||
//
|
//
|
||||||
// Where <device_id> can be: short_addr, long_addr, device_index, friendly_name
|
// Where <device_id> can be: short_addr, long_addr, device_index, friendly_name
|
||||||
|
|
||||||
|
@ -735,6 +711,8 @@ void CmndZbModelId(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbLight`
|
||||||
// Specify, read or erase a Light type for Hue/Alexa integration
|
// Specify, read or erase a Light type for Hue/Alexa integration
|
||||||
void CmndZbLight(void) {
|
void CmndZbLight(void) {
|
||||||
// Syntax is:
|
// Syntax is:
|
||||||
|
@ -768,7 +746,10 @@ void CmndZbLight(void) {
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbForget`
|
||||||
// Remove an old Zigbee device from the list of known devices, use ZigbeeStatus to know all registered devices
|
// Remove an old Zigbee device from the list of known devices, use ZigbeeStatus to know all registered devices
|
||||||
|
//
|
||||||
void CmndZbForget(void) {
|
void CmndZbForget(void) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||||
|
@ -783,12 +764,13 @@ void CmndZbForget(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbSave`
|
||||||
// Save Zigbee information to flash
|
// Save Zigbee information to flash
|
||||||
|
//
|
||||||
void CmndZbSave(void) {
|
void CmndZbSave(void) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
|
|
||||||
saveZigbeeDevices();
|
saveZigbeeDevices();
|
||||||
|
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,7 +785,7 @@ void CmndZbSave(void) {
|
||||||
void CmndZbRestore(void) {
|
void CmndZbRestore(void) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
DynamicJsonBuffer jsonBuf;
|
DynamicJsonBuffer jsonBuf;
|
||||||
const JsonVariant json_parsed = jsonBuf.parse((const char*)XdrvMailbox.data); // const to force a copy of parameter
|
const JsonVariant json_parsed = jsonBuf.parse((const char*) XdrvMailbox.data); // const to force a copy of parameter
|
||||||
const JsonVariant * json = &json_parsed; // root of restore, to be changed if needed
|
const JsonVariant * json = &json_parsed; // root of restore, to be changed if needed
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
@ -846,14 +828,17 @@ void CmndZbRestore(void) {
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbRead`
|
||||||
// Send an attribute read command to a device, specifying cluster and list of attributes
|
// Send an attribute read command to a device, specifying cluster and list of attributes
|
||||||
|
//
|
||||||
void CmndZbRead(void) {
|
void CmndZbRead(void) {
|
||||||
// ZigbeeRead {"Device":"0xF289","Cluster":0,"Endpoint":3,"Attr":5}
|
// ZbRead {"Device":"0xF289","Cluster":0,"Endpoint":3,"Attr":5}
|
||||||
// ZigbeeRead {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Attr":"0x0005"}
|
// ZbRead {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Attr":"0x0005"}
|
||||||
// ZigbeeRead {"Device":"0xF289","Cluster":0,"Endpoint":3,"Attr":[5,6,7,4]}
|
// ZbRead {"Device":"0xF289","Cluster":0,"Endpoint":3,"Attr":[5,6,7,4]}
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
DynamicJsonBuffer jsonBuf;
|
DynamicJsonBuffer jsonBuf;
|
||||||
JsonObject &json = jsonBuf.parseObject(XdrvMailbox.data);
|
JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data);
|
||||||
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
// params
|
// params
|
||||||
|
@ -884,7 +869,7 @@ void CmndZbRead(void) {
|
||||||
if (nullptr != &val_attr) {
|
if (nullptr != &val_attr) {
|
||||||
uint16_t val = strToUInt(val_attr);
|
uint16_t val = strToUInt(val_attr);
|
||||||
if (val_attr.is<JsonArray>()) {
|
if (val_attr.is<JsonArray>()) {
|
||||||
JsonArray& attr_arr = val_attr;
|
const JsonArray& attr_arr = val_attr.as<const JsonArray&>();
|
||||||
attrs_len = attr_arr.size() * 2;
|
attrs_len = attr_arr.size() * 2;
|
||||||
attrs = new uint8_t[attrs_len];
|
attrs = new uint8_t[attrs_len];
|
||||||
|
|
||||||
|
@ -920,7 +905,10 @@ void CmndZbRead(void) {
|
||||||
if (attrs) { delete[] attrs; }
|
if (attrs) { delete[] attrs; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbPermitJoin`
|
||||||
// Allow or Deny pairing of new Zigbee devices
|
// Allow or Deny pairing of new Zigbee devices
|
||||||
|
//
|
||||||
void CmndZbPermitJoin(void) {
|
void CmndZbPermitJoin(void) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
uint32_t payload = XdrvMailbox.payload;
|
uint32_t payload = XdrvMailbox.payload;
|
||||||
|
@ -946,6 +934,9 @@ void CmndZbPermitJoin(void) {
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command `ZbStatus`
|
||||||
|
//
|
||||||
void CmndZbStatus(void) {
|
void CmndZbStatus(void) {
|
||||||
if (ZigbeeSerial) {
|
if (ZigbeeSerial) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
|
@ -976,7 +967,7 @@ bool Xdrv23(uint8_t function)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FUNC_LOOP:
|
case FUNC_LOOP:
|
||||||
if (ZigbeeSerial) { ZigbeeInput(); }
|
if (ZigbeeSerial) { ZigbeeInputLoop(); }
|
||||||
if (zigbee.state_machine) {
|
if (zigbee.state_machine) {
|
||||||
ZigbeeStateMachine_Run();
|
ZigbeeStateMachine_Run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue