Merge pull request #8825 from s-hadinger/zigbee_ezsp_5

Zigbee EZSP milestone 3
This commit is contained in:
Theo Arends 2020-06-30 08:34:49 +02:00 committed by GitHub
commit a44f82d072
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 655 additions and 173 deletions

View File

@ -57,7 +57,53 @@ enum ZnpSubsystem {
#ifdef USE_ZIGBEE_EZSP
enum EZSPCondigId {
enum EZSPNodeType {
EMBER_UNKNOWN_DEVICE = 0x00,
EMBER_COORDINATOR = 0x01,
EMBER_ROUTER = 0x02,
EMBER_END_DEVICE = 0x03,
EMBER_SLEEPY_END_DEVICE = 0x04
};
enum EZSPDeviceUpdate {
EMBER_STANDARD_SECURITY_SECURED_REJOIN = 0x00,
EMBER_STANDARD_SECURITY_UNSECURED_JOIN = 0x01,
EMBER_DEVICE_LEFT = 0x02,
EMBER_STANDARD_SECURITY_UNSECURED_REJOIN = 0x03,
};
enum EZSPJoinDecision {
EMBER_USE_PRECONFIGURED_KEY = 0x00,
EMBER_SEND_KEY_IN_THE_CLEAR = 0x01,
EMBER_DENY_JOIN = 0x02,
EMBER_NO_ACTION = 0x03
};
enum EZSPCurrentSecurytBitMask {
EMBER_STANDARD_SECURITY_MODE = 0x0000,
EMBER_DISTRIBUTED_TRUST_CENTER_MODE = 0x0002,
EMBER_GLOBAL_LINK_KEY = 0x0004,
EMBER_TRUST_CENTER_GLOBAL_LINK_KEY = 0x0004,
EMBER_PRECONFIGURED_NETWORK_KEY_MODE = 0x0008,
EMBER_HAVE_TRUST_CENTER_LINK_KEY = 0x0010,
EMBER_TRUST_CENTER_USES_HASHED_LINK_KEY = 0x0084,
EMBER_HAVE_PRECONFIGURED_KEY = 0x0100,
EMBER_HAVE_NETWORK_KEY = 0x0200,
EMBER_GET_LINK_KEY_WHEN_JOINING = 0x0400,
EMBER_REQUIRE_ENCRYPTED_KEY = 0x0800,
EMBER_NO_FRAME_COUNTER_RESET = 0x1000,
EMBER_GET_PRECONFIGURED_KEY_FROM_INSTALL_CODE = 0x2000,
EMBER_HAVE_TRUST_CENTER_EUI64 = 0x0040
};
enum EZSPJoinMethod {
EMBER_USE_MAC_ASSOCIATION = 0x0,
EMBER_USE_NWK_REJOIN = 0x1,
EMBER_USE_NWK_REJOIN_HAVE_NWK_KEY = 0x2,
EMBER_USE_CONFIGURED_NWK_STATE = 0x3
};
enum EZSPConfigId {
EZSP_CONFIG_PACKET_BUFFER_COUNT = 0x01,
EZSP_CONFIG_NEIGHBOR_TABLE_SIZE = 0x02,
EZSP_CONFIG_APS_UNICAST_MESSAGE_COUNT = 0x03,
@ -301,6 +347,159 @@ enum EZSPStatusId {
EZSP_NO_ERROR = 0xFF
};
enum EZSPPolicyId {
EZSP_TRUST_CENTER_POLICY = 0x00,
EZSP_BINDING_MODIFICATION_POLICY = 0x01,
EZSP_UNICAST_REPLIES_POLICY = 0x02,
EZSP_POLL_HANDLER_POLICY = 0x03,
EZSP_MESSAGE_CONTENTS_IN_CALLBACK_POLICY = 0x04,
EZSP_TC_KEY_REQUEST_POLICY = 0x05,
EZSP_APP_KEY_REQUEST_POLICY = 0x06,
EZSP_PACKET_VALIDATE_LIBRARY_POLICY = 0x07,
EZSP_ZLL_POLICY = 0x08,
EZSP_TC_REJOINS_USING_WELL_KNOWN_KEY_POLICY = 0x09
};
enum EZSPDecisionBitmask {
EZSP_DECISION_BITMASK_DEFAULT_CONFIGURATION = 0x0000,
EZSP_DECISION_ALLOW_JOINS = 0x0001,
EZSP_DECISION_ALLOW_UNSECURED_REJOINS = 0x0002,
EZSP_DECISION_SEND_KEY_IN_CLEAR = 0x0004,
EZSP_DECISION_IGNORE_UNSECURED_REJOINS = 0x0008,
EZSP_DECISION_JOINS_USE_INSTALL_CODE_KEY = 0x0010,
EZSP_DECISION_DEFER_JOINS = 0x0020
};
enum EZSPDecisionId {
EZSP_DEFER_JOINS_REJOINS_HAVE_LINK_KEY = 0x07,
EZSP_DISALLOW_BINDING_MODIFICATION = 0x10,
EZSP_ALLOW_BINDING_MODIFICATION = 0x11,
EZSP_CHECK_BINDING_MODIFICATIONS_ARE_VALID_ENDPOINT_CLUSTERS = 0x12,
EZSP_HOST_WILL_NOT_SUPPLY_REPLY = 0x20,
EZSP_HOST_WILL_SUPPLY_REPLY = 0x21,
EZSP_POLL_HANDLER_IGNORE = 0x30,
EZSP_POLL_HANDLER_CALLBACK = 0x31,
EZSP_MESSAGE_TAG_ONLY_IN_CALLBACK = 0x40,
EZSP_MESSAGE_TAG_AND_CONTENTS_IN_CALLBACK = 0x41,
EZSP_DENY_TC_KEY_REQUESTS = 0x50,
EZSP_ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY = 0x51,
EZSP_ALLOW_TC_KEY_REQUEST_AND_GENERATE_NEW_KEY = 0x52,
EZSP_DENY_APP_KEY_REQUESTS = 0x60,
EZSP_ALLOW_APP_KEY_REQUESTS = 0x61,
EZSP_PACKET_VALIDATE_LIBRARY_CHECKS_ENABLED = 0x62,
EZSP_PACKET_VALIDATE_LIBRARY_CHECKS_DISABLED = 0x63
};
enum EZSP_ZdoConfigurationFlags {
EMBER_APP_RECEIVES_SUPPORTED_ZDO_REQUESTS = 0x01,
EMBER_APP_HANDLES_UNSUPPORTED_ZDO_REQUESTS = 0x02,
EMBER_APP_HANDLES_ZDO_ENDPOINT_REQUESTS = 0x04,
EMBER_APP_HANDLES_ZDO_BINDING_REQUESTS = 0x08
};
enum EZSP_EmberIncomingMessageType {
EMBER_INCOMING_UNICAST = 0x00,
EMBER_INCOMING_UNICAST_REPLY = 0x01,
EMBER_INCOMING_MULTICAST = 0x02,
EMBER_INCOMING_MULTICAST_LOOPBACK = 0x03,
EMBER_INCOMING_BROADCAST = 0x04,
EMBER_INCOMING_BROADCAST_LOOPBACK = 0x05,
EMBER_INCOMING_MANY_TO_ONE_ROUTE_REQUEST = 0x06
};
enum EZSP_EmberApsOption {
EMBER_APS_OPTION_NONE = 0x0000,
EMBER_APS_OPTION_ENCRYPTION = 0x0020,
EMBER_APS_OPTION_RETRY = 0x0040,
EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY = 0x0100,
EMBER_APS_OPTION_FORCE_ROUTE_DISCOVERY = 0x0200,
EMBER_APS_OPTION_SOURCE_EUI64 = 0x0400,
EMBER_APS_OPTION_DESTINATION_EUI64 = 0x0800,
EMBER_APS_OPTION_ENABLE_ADDRESS_DISCOVERY = 0x1000,
EMBER_APS_OPTION_POLL_RESPONSE = 0x2000,
EMBER_APS_OPTION_ZDO_RESPONSE_REQUIRED = 0x4000,
EMBER_APS_OPTION_FRAGMENT = 0x8000
};
enum EZSP_EmberOutgoingMessageType {
EMBER_OUTGOING_DIRECT = 0x00,
EMBER_OUTGOING_VIA_ADDRESS_TABLE = 0x01,
EMBER_OUTGOING_VIA_BINDING = 0x02,
EMBER_OUTGOING_MULTICAST = 0x03,
EMBER_OUTGOING_BROADCAST = 0x04
};
// inspired from https://github.com/zigpy/zigpy/blob/dev/zigpy/zdo/types.py
enum EZSP_ZDO {
ZDO_NWK_addr_req = 0x0000,
ZDO_IEEE_addr_req = 0x0001,
ZDO_Node_Desc_req = 0x0002,
ZDO_Power_Desc_req = 0x0003,
ZDO_Simple_Desc_req = 0x0004,
ZDO_Active_EP_req = 0x0005,
ZDO_Match_Desc_req = 0x0006,
ZDO_Complex_Desc_req = 0x0010,
ZDO_User_Desc_req = 0x0011,
ZDO_Discovery_Cache_req = 0x0012,
ZDO_Device_annce = 0x0013,
ZDO_User_Desc_set = 0x0014,
ZDO_System_Server_Discovery_req = 0x0015,
ZDO_Discovery_store_req = 0x0016,
ZDO_Node_Desc_store_req = 0x0017,
ZDO_Active_EP_store_req = 0x0019,
ZDO_Simple_Desc_store_req = 0x001A,
ZDO_Remove_node_cache_req = 0x001B,
ZDO_Find_node_cache_req = 0x001C,
ZDO_Extended_Simple_Desc_req = 0x001D,
ZDO_Extended_Active_EP_req = 0x001E,
ZDO_Parent_annce = 0x001F,
// Bind Management Server Services Responses
ZDO_End_Device_Bind_req = 0x0020,
ZDO_Bind_req = 0x0021,
ZDO_Unbind_req = 0x0022,
// Network Management Server Services Requests
ZDO_Mgmt_Lqi_req = 0x0031,
ZDO_Mgmt_Rtg_req = 0x0032,
ZDO_Mgmt_Leave_req = 0x0034,
ZDO_Mgmt_Permit_Joining_req = 0x0036,
ZDO_Mgmt_NWK_Update_req = 0x0038,
// Responses
// Device and Service Discovery Server Responses
ZDO_NWK_addr_rsp = 0x8000,
ZDO_IEEE_addr_rsp = 0x8001,
ZDO_Node_Desc_rsp = 0x8002,
ZDO_Power_Desc_rsp = 0x8003,
ZDO_Simple_Desc_rsp = 0x8004,
ZDO_Active_EP_rsp = 0x8005,
ZDO_Match_Desc_rsp = 0x8006,
ZDO_Complex_Desc_rsp = 0x8010,
ZDO_User_Desc_rsp = 0x8011,
ZDO_Discovery_Cache_rsp = 0x8012,
ZDO_User_Desc_conf = 0x8014,
ZDO_System_Server_Discovery_rsp = 0x8015,
ZDO_Discovery_Store_rsp = 0x8016,
ZDO_Node_Desc_store_rsp = 0x8017,
ZDO_Power_Desc_store_rsp = 0x8018,
ZDO_Active_EP_store_rsp = 0x8019,
ZDO_Simple_Desc_store_rsp = 0x801A,
ZDO_Remove_node_cache_rsp = 0x801B,
ZDO_Find_node_cache_rsp = 0x801C,
ZDO_Extended_Simple_Desc_rsp = 0x801D,
ZDO_Extended_Active_EP_rsp = 0x801E,
ZDO_Parent_annce_rsp = 0x801F,
// Bind Management Server Services Responses
ZDO_End_Device_Bind_rsp = 0x8020,
ZDO_Bind_rsp = 0x8021,
ZDO_Unbind_rsp = 0x8022,
// Network Management Server Services Responses
ZDO_Mgmt_Lqi_rsp = 0x8031,
ZDO_Mgmt_Rtg_rsp = 0x8032,
ZDO_Mgmt_Leave_rsp = 0x8034,
ZDO_Mgmt_Permit_Joining_rsp = 0x8036,
ZDO_Mgmt_NWK_Update_rsp = 0x8038,
};
enum EZSP_Commands {
EZSP_version = 0x0000,
EZSP_getLibraryStatus = 0x0001,

View File

@ -244,6 +244,7 @@ Z_Devices zigbee_devices = Z_Devices();
// Local coordinator information
uint64_t localIEEEAddr = 0;
uint16_t localShortAddr = 0;
/*********************************************************************************************\
* Implementation

View File

@ -595,14 +595,12 @@ public:
ZCLFrame(uint8_t frame_control, uint16_t manuf_code, uint8_t transact_seq, uint8_t cmd_id,
const char *buf, size_t buf_len, uint16_t clusterid, uint16_t groupaddr,
uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast,
uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber,
uint32_t timestamp):
uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber):
_manuf_code(manuf_code), _transact_seq(transact_seq), _cmd_id(cmd_id),
_payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough
_cluster_id(clusterid), _groupaddr(groupaddr),
_srcaddr(srcaddr), _srcendpoint(srcendpoint), _dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast),
_linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber),
_timestamp(timestamp)
_linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber)
{
_frame_control.d8 = frame_control;
_payload.addBuffer(buf, buf_len);
@ -616,13 +614,11 @@ public:
"\"groupid\":%d," "\"clusterid\":%d," "\"srcaddr\":\"0x%04X\","
"\"srcendpoint\":%d," "\"dstendpoint\":%d," "\"wasbroadcast\":%d,"
"\"" D_CMND_ZIGBEE_LINKQUALITY "\":%d," "\"securityuse\":%d," "\"seqnumber\":%d,"
"\"timestamp\":%d,"
"\"fc\":\"0x%02X\",\"manuf\":\"0x%04X\",\"transact\":%d,"
"\"cmdid\":\"0x%02X\",\"payload\":\"%s\"}}"),
_groupaddr, _cluster_id, _srcaddr,
_srcendpoint, _dstendpoint, _wasbroadcast,
_linkquality, _securityuse, _seqnumber,
_timestamp,
_frame_control, _manuf_code, _transact_seq, _cmd_id,
hex_char);
if (Settings.flag3.tuya_serial_mqtt_publish) {
@ -635,8 +631,7 @@ public:
static ZCLFrame parseRawFrame(const SBuffer &buf, uint8_t offset, uint8_t len, uint16_t clusterid, uint16_t groupid,
uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast,
uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber,
uint32_t timestamp) { // parse a raw frame and build the ZCL frame object
uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber) { // parse a raw frame and build the ZCL frame object
uint32_t i = offset;
ZCLHeaderFrameControl_t frame_control;
uint16_t manuf_code = 0;
@ -654,8 +649,7 @@ public:
(const char *)(buf.buf() + i), len + offset - i,
clusterid, groupid,
srcaddr, srcendpoint, dstendpoint, wasbroadcast,
linkquality, securityuse, seqnumber,
timestamp);
linkquality, securityuse, seqnumber);
return zcl_frame;
}
@ -679,17 +673,12 @@ public:
_cluster_id = clusterid;
}
inline uint8_t getCmdId(void) const {
return _cmd_id;
}
inline uint16_t getClusterId(void) const {
return _cluster_id;
}
inline uint16_t getSrcEndpoint(void) const {
return _srcendpoint;
}
inline uint16_t getSrcAddr(void) const { return _srcaddr; }
inline uint16_t getGroupAddr(void) const { return _groupaddr; }
inline uint16_t getClusterId(void) const { return _cluster_id; }
inline uint8_t getLinkQuality(void) const { return _linkquality; }
inline uint8_t getCmdId(void) const { return _cmd_id; }
inline uint16_t getSrcEndpoint(void) const { return _srcendpoint; }
const SBuffer &getPayload(void) const {
return _payload;
@ -699,6 +688,7 @@ public:
return _manuf_code;
}
private:
ZCLHeaderFrameControl_t _frame_control = { .d8 = 0 };
uint16_t _manuf_code = 0; // optional
@ -715,7 +705,6 @@ private:
uint8_t _linkquality;
uint8_t _securityuse;
uint8_t _seqnumber;
uint32_t _timestamp;
};
// Zigbee ZCL converters

View File

@ -50,12 +50,15 @@ ZF(HueSat) ZF(Color)
ZF(ShutterOpen) ZF(ShutterClose) ZF(ShutterStop) ZF(ShutterLift) ZF(ShutterTilt) ZF(Shutter)
//ZF(Occupancy)
ZF(DimmerMove) ZF(DimmerStep) ZF(DimmerStepUp) ZF(DimmerStepDown)
ZF(HueMove) ZF(HueStep) ZF(HueStepUp) ZF(HueStepDown) ZF(SatMove) ZF(SatStep) ZF(ColorMove) ZF(ColorStep) ZF(ColorTempStep) ZF(ColorTempStepUp) ZF(ColorTempStepDown)
ZF(HueMove) ZF(HueStep) ZF(HueStepUp) ZF(HueStepDown) ZF(SatMove) ZF(SatStep) ZF(ColorMove) ZF(ColorStep)
ZF(ColorTempMoveUp) ZF(ColorTempMoveDown) ZF(ColorTempMoveStop) ZF(ColorTempMove)
ZF(ColorTempStep) ZF(ColorTempStepUp) ZF(ColorTempStepDown)
ZF(ArrowClick) ZF(ArrowHold) ZF(ArrowRelease) ZF(ZoneStatusChange)
ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(03xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(00190200) ZF(01190200) ZF(xxyyyy) ZF(xx)
ZF(xx000A00) ZF(xx0A00) ZF(xxyy0A00) ZF(xxxxyyyy0A00) ZF(xxxx0A00) ZF(xx0A)
ZF(xx190A00) ZF(xx19) ZF(xx190A) ZF(xxxxyyyy) ZF(xxxxyyzz) ZF(xxyyzzzz) ZF(xxyyyyzz)
ZF(01xxxx000000000000) ZF(03xxxx000000000000) ZF(00xxxx000000000000) ZF(xxyyyy000000000000)
ZF(00xx0A00) ZF(01xx0A00) ZF(03xx0A00) ZF(01xxxx0A0000000000) ZF(03xxxx0A0000000000) ZF(xxyyyy0A0000000000)
// Cluster specific commands
@ -119,8 +122,12 @@ const Z_CommandConverter Z_Commands[] PROGMEM = {
{ Z(SatStep), 0x0300, 0x05, 0x01, Z(xx190A) },
{ Z(ColorMove), 0x0300, 0x08, 0x01, Z(xxxxyyyy) },
{ Z(ColorStep), 0x0300, 0x09, 0x01, Z(xxxxyyyy0A00) },
{ Z(ColorTempStepUp), 0x0300, 0x4C, 0x01, Z(01xxxx0A0000000000) }, //xxxx = step
{ Z(ColorTempStepDown),0x0300, 0x4C, 0x01, Z(03xxxx0A0000000000) }, //xxxx = step
{ Z(ColorTempMoveUp), 0x0300, 0x4B, 0x01, Z(01xxxx000000000000) },
{ Z(ColorTempMoveDown),0x0300, 0x4B, 0x01, Z(03xxxx000000000000) },
{ Z(ColorTempMoveStop),0x0300, 0x4B, 0x01, Z(00xxxx000000000000) },
{ Z(ColorTempMove), 0x0300, 0x4B, 0x01, Z(xxyyyy000000000000) },
{ Z(ColorTempStepUp), 0x0300, 0x4C, 0x01, Z(01xxxx0A0000000000) },
{ Z(ColorTempStepDown),0x0300, 0x4C, 0x01, Z(03xxxx0A0000000000) },
{ Z(ColorTempStep), 0x0300, 0x4C, 0x01, Z(xxyyyy0A0000000000) }, //xx = 0x01 up, 0x03 down, yyyy = step
// Tradfri
{ Z(ArrowClick), 0x0005, 0x07, 0x01, Z(xx) }, // xx == 0x01 = left, 0x00 = right

View File

@ -36,6 +36,8 @@ const uint8_t ZIGBEE_STATUS_DEVICE_INDICATION = 34; // Device announces its
const uint8_t ZIGBEE_STATUS_SCANNING = 40; // State change
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_EZ_VERSION = 55; // Status: EFR32 EZ Version
const uint8_t ZIGBEE_STATUS_EZ_INFO = 56; // Status: EFR32 EZ Device Configuration
const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version
const uint8_t ZIGBEE_STATUS_ABORT = 99; // Fatal error, Zigbee not working
@ -170,6 +172,19 @@ SBuffer *zigbee_buffer = nullptr;
#define USE_ZIGBEE_CHANNEL_MASK (1 << (USE_ZIGBEE_CHANNEL))
const char kCheckingDeviceConfiguration[] PROGMEM = D_LOG_ZIGBEE "checking device configuration";
const char kConfiguredCoord[] PROGMEM = "Configured, starting coordinator";
const char kConfiguredRouter[] PROGMEM = "Configured, starting router";
const char kConfiguredDevice[] PROGMEM = "Configured, starting device";
const char kStarted[] PROGMEM = "Started";
const char kZigbeeStarted[] PROGMEM = D_LOG_ZIGBEE "Zigbee started";
const char kResetting[] PROGMEM = "Resetting configuration";
const char kResettingDevice[] PROGMEM = D_LOG_ZIGBEE "Resetting EZSP device";
const char kZNP12[] PROGMEM = "Only ZNP 1.2 is currently supported";
const char kEZ8[] PROGMEM = "Only EZSP protocol v8 is currently supported";
const char kAbort[] PROGMEM = "Abort";
const char kZigbeeAbort[] PROGMEM = D_LOG_ZIGBEE "Abort";
#ifdef USE_ZIGBEE_ZNP
// ZBS_* Zigbee Send
@ -402,17 +417,6 @@ void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_pani
) // 2605621001030507090B0D0F00020406080A0C0D
}
const char kCheckingDeviceConfiguration[] PROGMEM = D_LOG_ZIGBEE "checking device configuration";
const char kConfiguredCoord[] PROGMEM = "Configured, starting coordinator";
const char kConfiguredRouter[] PROGMEM = "Configured, starting router";
const char kConfiguredDevice[] PROGMEM = "Configured, starting device";
const char kStarted[] PROGMEM = "Started";
const char kZigbeeStarted[] PROGMEM = D_LOG_ZIGBEE "Zigbee started";
const char kResetting[] PROGMEM = "Resetting configuration";
const char kZNP12[] PROGMEM = "Only ZNP 1.2 is currently supported";
const char kAbort[] PROGMEM = "Abort";
const char kZigbeeAbort[] PROGMEM = D_LOG_ZIGBEE "Abort";
static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_LABEL(0)
ZI_NOOP()
@ -543,7 +547,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
// ======================================================================
// Start as Zigbee Router
// ======================================================================
ZI_LABEL(ZIGBEE_LABEL_INIT_ROUTER) // Init as a router
ZI_LABEL(ZIGBEE_LABEL_INIT_ROUTER) // Init as a router
// Check the configuration as Router
ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_FACT_RESET_ROUTER)
ZI_SEND(ZBS_ZNPHC) // check value of ZNP Has Configured
@ -654,8 +658,7 @@ ZBM(ZBS_SET_TC_CACHE, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG
ZBM(ZBS_SET_ROUTE_TBL, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_SOURCE_ROUTE_TABLE_SIZE, 0x10, 0x00) // 53001A1000
ZBM(ZBS_SET_KEY_TBL, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_KEY_TABLE_SIZE, 0x04, 0x00) // 53001E0400
ZBM(ZBS_SET_PANID_CNFLCT, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_PAN_ID_CONFLICT_REPORT_THRESHOLD, 0x02, 0x00)// 5300220200
// TODO APP_RECEIVES_SUPPORTED_ZDO_REQUESTS
ZBM(ZBS_SET_ZDO_REQ, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_APPLICATION_ZDO_FLAGS, 0x03, 0x00) // 53002A0300
ZBM(ZBS_SET_ZDO_REQ, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_APPLICATION_ZDO_FLAGS, EMBER_APP_RECEIVES_SUPPORTED_ZDO_REQUESTS | EMBER_APP_HANDLES_UNSUPPORTED_ZDO_REQUESTS, 0x00) // 53002A0300
ZBM(ZBS_SET_NETWORKS, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_SUPPORTED_NETWORKS, 0x01, 0x00) // 53002D0100
ZBM(ZBS_SET_PACKET_BUF, EZSP_setConfigurationValue, 0x00 /*high*/, EZSP_CONFIG_PACKET_BUFFER_COUNT, 0xFF, 0x00) // 530001FF00
@ -667,23 +670,24 @@ ZBM(ZBS_GET_APS_UNI, EZSP_getConfigurationValue, 0x00 /*high*/, EZSP_CONFIG
ZBM(ZBR_GET_OK, EZSP_getConfigurationValue, 0x00 /*high*/, 0x00 /*ok*/) // 5200 - followed by the value
// Add Endpoints
// ZBM(ZBS_ADD_ENDPOINT1, EZSP_addEndpoint, 0x00 /*high*/, 0x01 /*ep*/, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA),
// 0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */,
// 0x0E /* inputClusterCount */, // actually all clusters will be received
// 0X00 /* outputClusterCount */,
// 0x00,0x00, 0x04,0x00, 0x05,0x00, 0x06,0x00, // 0x0000, 0x0004, 0x0005, 0x0006
// 0x07,0x00, 0x08,0x00, 0x0A,0x00, 0x02,0x01, // 0x0007, 0x0008, 0x000A, 0X0102
// 0x00,0x03, 0x00,0x04, 0x02,0x04, 0x03,0x04, // 0x0300, 0x0400, 0x0402, 0x0403
// 0x05,0x04, 0x06,0x04, // 0x0405, 0x0406
// )
ZBM(ZBS_ADD_ENDPOINT1, EZSP_addEndpoint, 0x00 /*high*/, 0x01 /*ep*/, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA),
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */,
0x00 /* inputClusterCount */, // actually all clusters will be received
0X00 /* outputClusterCount */ ) // 02000104010500000000
0x0E /* inputClusterCount */, // actually all clusters will be received
0X00 /* outputClusterCount */, // 02000104010500000000
0x00,0x00, 0x04,0x00, 0x05,0x00, 0x06,0x00, // 0x0000, 0x0004, 0x0005, 0x0006
0x07,0x00, 0x08,0x00, 0x0A,0x00, 0x02,0x01, // 0x0007, 0x0008, 0x000A, 0X0102
0x00,0x03, 0x00,0x04, 0x02,0x04, 0x03,0x04, // 0x0300, 0x0400, 0x0402, 0x0403
0x05,0x04, 0x06,0x04, // 0x0405, 0x0406
)
ZBM(ZBS_ADD_ENDPOINTB, EZSP_addEndpoint, 0x00 /*high*/, 0x0B /*ep*/, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA),
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */,
0x00 /* inputClusterCount */, // actually all clusters will be received
0X00 /* outputClusterCount */ ) // 02000B04010500000000
0x0E /* inputClusterCount */, // actually all clusters will be received
0X00 /* outputClusterCount */, // 02000B04010500000000
0x00,0x00, 0x04,0x00, 0x05,0x00, 0x06,0x00, // 0x0000, 0x0004, 0x0005, 0x0006
0x07,0x00, 0x08,0x00, 0x0A,0x00, 0x02,0x01, // 0x0007, 0x0008, 0x000A, 0X0102
0x00,0x03, 0x00,0x04, 0x02,0x04, 0x03,0x04, // 0x0300, 0x0400, 0x0402, 0x0403
0x05,0x04, 0x06,0x04, // 0x0405, 0x0406
)
ZBM(ZBR_ADD_ENDPOINT, EZSP_addEndpoint, 0x00 /*high*/, 0x00 /*ok*/) // 020000
// set concentrator false
@ -691,11 +695,58 @@ ZBM(ZBS_SET_CONCENTRATOR, EZSP_setConcentrator, 0x00 /*high*/, 0x00 /*false*/, 0
0x58,0x02 /*minTime*/, 0x08,0x07 /*maxTime*/, 0x02 /*errThr*/, 0x05 /*failThr*/, 0x00 /*maxHops*/) // 100000F9FF58020807020500
ZBM(ZBR_SET_CONCENTRATOR, EZSP_setConcentrator, 0x00 /*high*/, 0x00 /*ok*/) // 100000
//False, <EmberConcentratorType.HIGH_RAM_CONCENTRATOR: 65529>, 600, 1800, 2, 5, 0)
// setInitialSecurityState
#define EZ_SECURITY_MODE EMBER_TRUST_CENTER_GLOBAL_LINK_KEY | EMBER_PRECONFIGURED_NETWORK_KEY_MODE | EMBER_HAVE_NETWORK_KEY | EMBER_HAVE_PRECONFIGURED_KEY
ZBM(ZBS_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/,
Z_B0(EZ_SECURITY_MODE), Z_B1(EZ_SECURITY_MODE),
// preConfiguredKey
0x5A, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6C, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x30, 0x39, // well known key "ZigBeeAlliance09"
// networkKey
Z_B0(USE_ZIGBEE_PRECFGKEY_L), Z_B1(USE_ZIGBEE_PRECFGKEY_L), Z_B2(USE_ZIGBEE_PRECFGKEY_L), Z_B3(USE_ZIGBEE_PRECFGKEY_L),
Z_B4(USE_ZIGBEE_PRECFGKEY_L), Z_B5(USE_ZIGBEE_PRECFGKEY_L), Z_B6(USE_ZIGBEE_PRECFGKEY_L), Z_B7(USE_ZIGBEE_PRECFGKEY_L),
Z_B0(USE_ZIGBEE_PRECFGKEY_H), Z_B1(USE_ZIGBEE_PRECFGKEY_H), Z_B2(USE_ZIGBEE_PRECFGKEY_H), Z_B3(USE_ZIGBEE_PRECFGKEY_H),
Z_B4(USE_ZIGBEE_PRECFGKEY_H), Z_B5(USE_ZIGBEE_PRECFGKEY_H), Z_B6(USE_ZIGBEE_PRECFGKEY_H), Z_B7(USE_ZIGBEE_PRECFGKEY_H),
0x00 /*sequence*/,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*trustcenter*/
)
ZBM(ZBR_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, 0x00 /*status*/)
// setIndividual policies
ZBM(ZBS_SET_POLICY_00, EZSP_setPolicy, 0x00 /*high*/, EZSP_TRUST_CENTER_POLICY,
EZSP_DECISION_ALLOW_JOINS | EZSP_DECISION_ALLOW_UNSECURED_REJOINS) // 55000003
ZBM(ZBS_SET_POLICY_02, EZSP_setPolicy, 0x00 /*high*/, EZSP_UNICAST_REPLIES_POLICY,
EZSP_HOST_WILL_NOT_SUPPLY_REPLY) // 550002210
ZBM(ZBS_SET_POLICY_03, EZSP_setPolicy, 0x00 /*high*/, EZSP_POLL_HANDLER_POLICY,
EZSP_POLL_HANDLER_IGNORE) // 55000330
ZBM(ZBS_SET_POLICY_05, EZSP_setPolicy, 0x00 /*high*/, EZSP_TC_KEY_REQUEST_POLICY,
EZSP_ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY) // 55000551
ZBM(ZBS_SET_POLICY_06, EZSP_setPolicy, 0x00 /*high*/, EZSP_APP_KEY_REQUEST_POLICY,
EZSP_DENY_APP_KEY_REQUESTS) // 55000660
ZBM(ZBR_SET_POLICY_XX, EZSP_setPolicy, 0x00 /*high*/, 0x00 /*status*/)
// formNetwork - i.e. start zigbee network as coordinator
ZBM(ZBS_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/,
Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID),
Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID),
Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID),
20 /*radioTxPower*/,
USE_ZIGBEE_CHANNEL /*channel*/,
EMBER_USE_MAC_ASSOCIATION,
0xFF,0xFF, /*nwkManagerId, unused*/
0x00, /*nwkUpdateId, unused*/
0x00,0x00,0x00,0x00, /*NWK channel mask, unused*/
) // 1E00...
ZBM(ZBR_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, 0x00 /*status*/) // 1E0000
ZBM(ZBR_NETWORK_UP, EZSP_stackStatusHandler, 0x00 /*high*/, EMBER_NETWORK_UP) // 190090
// read configuration details
ZBM(ZBS_GET_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/) // 2800
ZBM(ZBR_GET_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/, 0x00 /*ok*/) // 2800
ZBM(ZBS_GET_EUI64, EZSP_getEui64, 0x00 /*high*/) // 2600
ZBM(ZBR_GET_EUI64, EZSP_getEui64, 0x00 /*high*/) // 2600
ZBM(ZBS_GET_NODEID, EZSP_getNodeId, 0x00 /*high*/) // 2700
ZBM(ZBR_GET_NODEID, EZSP_getNodeId, 0x00 /*high*/) // 2700
const char kResetingDevice[] PROGMEM = D_LOG_ZIGBEE "resetting EZSP device";
const char kAbort[] PROGMEM = "Abort";
const char kZigbeeAbort[] PROGMEM = D_LOG_ZIGBEE "Abort";
static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_LABEL(0)
@ -706,7 +757,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize
// Hardware reset
ZI_LOG(LOG_LEVEL_INFO, kResetingDevice) // Log Debug: resetting EZSP device
ZI_LOG(LOG_LEVEL_INFO, kResettingDevice) // Log Debug: resetting EZSP device
ZI_CALL(&Z_Reset_Device, 0) // LOW = reset
ZI_WAIT(100) // wait for .1 second
ZI_CALL(&Z_Reset_Device, 1) // HIGH = release reset
@ -715,9 +766,10 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_WAIT_UNTIL(5000, ZBR_RSTACK) // wait for RSTACK message
// Init device and probe version
ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV(1000, ZBR_VERSION) // check EXT PAN ID
ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(1000, ZBR_VERSION, &Z_ReceiveCheckVersion) // check EXT PAN ID
// configure EFR32
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
ZI_SEND(ZBS_SET_ADDR_TABLE) ZI_WAIT_RECV(500, ZBR_SET_OK) // Address table size
ZI_SEND(ZBS_SET_MCAST_TABLE) ZI_WAIT_RECV(500, ZBR_SET_OK)
ZI_SEND(ZBS_SET_STK_PROF) ZI_WAIT_RECV(500, ZBR_SET_OK)
@ -733,7 +785,8 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_SEND(ZBS_SET_PACKET_BUF) ZI_WAIT_RECV(500, ZBR_SET_OK2)
// read configuration
ZI_SEND(ZBS_GET_APS_UNI) ZI_WAIT_RECV_FUNC(500, ZBR_GET_OK, &Z_ReadAPSUnicastMessage)
// TODO - not sure it's useful
//ZI_SEND(ZBS_GET_APS_UNI) ZI_WAIT_RECV_FUNC(500, ZBR_GET_OK, &Z_ReadAPSUnicastMessage)
// add endpoint 0x01 and 0x0B
ZI_SEND(ZBS_ADD_ENDPOINT1) ZI_WAIT_RECV(500, ZBR_ADD_ENDPOINT)
@ -742,9 +795,38 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
// set Concentrator
ZI_SEND(ZBS_SET_CONCENTRATOR) ZI_WAIT_RECV(500, ZBR_SET_CONCENTRATOR)
// setInitialSecurityState
ZI_SEND(ZBS_SET_SECURITY) ZI_WAIT_RECV(500, ZBR_SET_SECURITY)
ZI_SEND(ZBS_SET_POLICY_00) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX)
ZI_SEND(ZBS_SET_POLICY_02) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX)
ZI_SEND(ZBS_SET_POLICY_03) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX)
ZI_SEND(ZBS_SET_POLICY_05) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX)
ZI_SEND(ZBS_SET_POLICY_06) ZI_WAIT_RECV(500, ZBR_SET_POLICY_XX)
// formNetwork
ZI_SEND(ZBS_FORM_NETWORK) ZI_WAIT_RECV(500, ZBR_FORM_NETWORK)
ZI_WAIT_RECV(5000, ZBR_NETWORK_UP) // wait for network to start
// Query device information
ZI_SEND(ZBS_GET_EUI64) ZI_WAIT_RECV_FUNC(500, ZBR_GET_EUI64, &Z_EZSPGetEUI64)
ZI_SEND(ZBS_GET_NODEID) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NODEID, &Z_EZSPGetNodeId)
ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NETW_PARM, &Z_EZSPNetworkParameters)
ZI_LABEL(ZIGBEE_LABEL_READY)
ZI_MQTT_STATE(ZIGBEE_STATUS_OK, kStarted)
ZI_LOG(LOG_LEVEL_INFO, kZigbeeStarted)
ZI_CALL(&Z_State_Ready, 1) // Now accept incoming messages
ZI_CALL(&Z_Load_Devices, 0)
ZI_CALL(&Z_Query_Bulbs, 0)
ZI_LABEL(ZIGBEE_LABEL_MAIN_LOOP)
ZI_WAIT_FOREVER()
ZI_GOTO(ZIGBEE_LABEL_READY)
ZI_GOTO(ZIGBEE_LABEL_MAIN_LOOP)
// Error: version of Z-Stack is not supported
ZI_LABEL(ZIGBEE_LABEL_UNSUPPORTED_VERSION)
ZI_MQTT_STATE(ZIGBEE_STATUS_UNSUPPORTED_VERSION, kEZ8)
ZI_GOTO(ZIGBEE_LABEL_ABORT)
// Abort state machine, general error
ZI_LABEL(ZIGBEE_LABEL_ABORT) // Label 99: abort

View File

@ -64,26 +64,6 @@ int32_t Z_EZSP_ERROR(uint8_t error_code) {
XdrvRulesProcess();
}
/*********************************************************************************************\
* Default resolver
\*********************************************************************************************/
int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
// Default message handler for new messages
if (zigbee.init_phase) {
// if still during initialization phase, ignore any unexpected message
return -1; // ignore message
} else {
// TODO
// for (uint32_t i = 0; i < sizeof(Z_DispatchTable)/sizeof(Z_Dispatcher); i++) {
// if (Z_ReceiveMatchPrefix(buf, Z_DispatchTable[i].match)) {
// (*Z_DispatchTable[i].func)(res, buf);
// }
// }
return -1;
}
}
int32_t Z_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) {
// Called when receiving a response from getConfigurationValue
// Value is in bytes 2+3
@ -94,6 +74,53 @@ int32_t Z_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) {
#endif // USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Parsers for incoming EZSP messages
\*********************************************************************************************/
//
// Handle a "getEui64" incoming message
//
int32_t Z_EZSPGetEUI64(int32_t res, class SBuffer &buf) {
localIEEEAddr = buf.get64(2);
return res;
}
//
// Handle a "getEui64" incoming message
//
int32_t Z_EZSPGetNodeId(int32_t res, class SBuffer &buf) {
localShortAddr = buf.get8(2);
return res;
}
//
// Handle a "getNetworkParameters" incoming message
//
int32_t Z_EZSPNetworkParameters(int32_t res, class SBuffer &buf) {
uint8_t node_type = buf.get8(3);
// ext panid: 4->11
// panid: 12->13
// radioTxPower: 14
// radioChannel: 15
// Local short and long addresses are supposed to be already retrieved
// localIEEEAddr = long_adr;
// localShortAddr = short_adr;
char hex[20];
Uint64toHex(localIEEEAddr, hex, 64);
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
"\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\""
",\"DeviceType\":%d}}"),
ZIGBEE_STATUS_EZ_INFO, hex, localShortAddr, node_type);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
XdrvRulesProcess();
return res;
}
/*********************************************************************************************\
* Parsers for incoming ZNP messages
\*********************************************************************************************/
@ -117,6 +144,7 @@ int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) {
// keep track of the local IEEE address
localIEEEAddr = long_adr;
localShortAddr = short_adr;
char hex[20];
Uint64toHex(long_adr, hex, 64);
@ -194,6 +222,7 @@ int32_t Z_Reboot(int32_t res, class SBuffer &buf) {
}
int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
#ifdef USE_ZIGBEE_ZNP
// check that the version is supported
// typical version for ZNP 1.2
// 61020200-02.06.03.D9143401.0200000000
@ -222,6 +251,34 @@ int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
} else {
return ZIGBEE_LABEL_UNSUPPORTED_VERSION; // abort
}
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
uint8_t protocol_version = buf.get8(2);
uint8_t stack_type = buf.get8(3);
uint16_t stack_version = buf.get16(4);
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
"\"Status\":%d,\"Version\":\"%d.%d.%d.%d\",\"Protocol\":%d"
",\"Stack\":%d}}"),
ZIGBEE_STATUS_EZ_VERSION,
(stack_version & 0xF000) >> 12,
(stack_version & 0x0F00) >> 8,
(stack_version & 0x00F0) >> 4,
stack_version & 0x000F,
protocol_version,
stack_type
);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE));
XdrvRulesProcess();
if (0x08 == protocol_version) {
return 0; // protocol v8 is ok
} else {
return ZIGBEE_LABEL_UNSUPPORTED_VERSION; // abort
}
#endif // USE_ZIGBEE_EZSP
}
// checks the device type (coordinator, router, end-device)
@ -466,10 +523,18 @@ int32_t Z_ReceiveStateChange(int32_t res, const class SBuffer &buf) {
// Send back Active Ep Req message
//
int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
Z_ShortAddress srcAddr = buf.get16(2);
#ifdef USE_ZIGBEE_ZNP
// Z_ShortAddress srcAddr = buf.get16(2);
Z_ShortAddress nwkAddr = buf.get16(4);
Z_IEEEAddress ieeeAddr = buf.get64(6);
uint8_t capabilities = buf.get8(14);
#endif
#ifdef USE_ZIGBEE_EZSP
// uint8_t seq = buf.get8(0);
Z_ShortAddress nwkAddr = buf.get16(1);
Z_IEEEAddress ieeeAddr = buf.get64(3);
uint8_t capabilities = buf.get8(11);
#endif
zigbee_devices.updateDevice(nwkAddr, ieeeAddr);
@ -627,7 +692,6 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
return -1;
}
#ifdef USE_ZIGBEE_ZNP
/*********************************************************************************************\
* Send specific ZNP messages
\*********************************************************************************************/
@ -636,24 +700,32 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
// Send ZDO_IEEE_ADDR_REQ request to get IEEE long address
//
void Z_SendIEEEAddrReq(uint16_t shortaddr) {
#ifdef USE_ZIGBEE_ZNP
uint8_t IEEEAddrReq[] = { Z_SREQ | Z_ZDO, ZDO_IEEE_ADDR_REQ, Z_B0(shortaddr), Z_B1(shortaddr), 0x00, 0x00 };
ZigbeeZNPSend(IEEEAddrReq, sizeof(IEEEAddrReq));
#endif
}
//
// Send ACTIVE_EP_REQ to collect active endpoints for this address
//
void Z_SendActiveEpReq(uint16_t shortaddr) {
#ifdef USE_ZIGBEE_ZNP
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));
#endif
#ifdef USE_ZIGBEE_EZSP
uint8_t ActiveEpReq[] = { Z_B0(shortaddr), Z_B1(shortaddr) };
EZ_SendZDO(shortaddr, ZDO_Active_EP_req, ActiveEpReq, sizeof(ActiveEpReq));
#endif
}
//
// Send AF Info Request
//
void Z_SendAFInfoRequest(uint16_t shortaddr) {
#ifdef USE_ZIGBEE_ZNP
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);
@ -663,106 +735,63 @@ void Z_SendAFInfoRequest(uint16_t shortaddr) {
0x00, transacid, ZCL_READ_ATTRIBUTES, 0x04, 0x00, 0x05, 0x00
};
ZigbeeZNPSend(AFInfoReq, sizeof(AFInfoReq));
#endif
}
#endif // USE_ZIGBEE_ZNP
//
// Handle trustCenterJoinHandler
// 2400
//
#ifdef USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Send specific EZS¨ messages
\*********************************************************************************************/
int32_t EZ_ReceiveTCJoinHandler(int32_t res, const class SBuffer &buf) {
uint16_t srcAddr = buf.get16(2);
uint64_t ieeeAddr = buf.get64(4);
uint8_t status = buf.get8(12);
uint8_t decision = buf.get8(13);
uint16_t parentNw = buf.get16(14);
//
// Callback for loading Zigbee configuration from Flash, called by the state machine
//
int32_t Z_Reset_Device(uint8_t value) {
// TODO - GPIO is hardwired to GPIO4
digitalWrite(4, value ? HIGH : LOW);
return 0; // continue
if (EMBER_DEVICE_LEFT != status) { // ignore message if the device is leaving
zigbee_devices.updateDevice(srcAddr, ieeeAddr);
char hex[20];
Uint64toHex(ieeeAddr, hex, 64);
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
"\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\""
",\"ParentNetwork\":\"0x%04X\""
",\"Status\":%d,\"Decision\":%d"
"}}"),
ZIGBEE_STATUS_DEVICE_INDICATION, hex, srcAddr, parentNw,
status, decision
);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
XdrvRulesProcess();
}
return -1;
}
//
// Send ZDO_IEEE_ADDR_REQ request to get IEEE long address
//
void Z_SendIEEEAddrReq(uint16_t shortaddr) {
}
//
// Send ACTIVE_EP_REQ to collect active endpoints for this address
//
void Z_SendActiveEpReq(uint16_t shortaddr) {
}
//
// Send AF Info Request
//
void Z_SendAFInfoRequest(uint16_t shortaddr) {
}
#endif // USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Callbacks
\*********************************************************************************************/
// 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
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
const JsonVariant &val_endpoint = GetCaseInsensitive(json, PSTR(OCCUPANCY));
if (nullptr != &val_endpoint) {
uint32_t occupancy = strToUInt(val_endpoint);
if (occupancy) {
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
} else {
zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY);
}
}
}
// Publish the received values once they have been coalesced
int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
const JsonObject *json = zigbee_devices.jsonGet(shortaddr);
if (json == nullptr) { return 0; } // don't crash if not found
zigbee_devices.jsonPublishFlush(shortaddr);
return 1;
}
/*********************************************************************************************\
* Global dispatcher for incoming messages
\*********************************************************************************************/
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
uint16_t groupid = buf.get16(2);
uint16_t clusterid = buf.get16(4);
uint16_t srcaddr = buf.get16(6);
uint8_t srcendpoint = buf.get8(8);
uint8_t dstendpoint = buf.get8(9);
uint8_t wasbroadcast = buf.get8(10);
uint8_t linkquality = buf.get8(11);
uint8_t securityuse = buf.get8(12);
uint32_t timestamp = buf.get32(13);
uint8_t seqnumber = buf.get8(17);
//
// Parse incoming ZCL message. This code is common to ZNP and EZSP
//
void Z_IncomingMessage(ZCLFrame &zcl_received) {
uint16_t srcaddr = zcl_received.getSrcAddr();
uint16_t groupid = zcl_received.getGroupAddr();
uint16_t clusterid = zcl_received.getClusterId();
uint8_t linkquality = zcl_received.getLinkQuality();
uint8_t srcendpoint = zcl_received.getSrcEndpoint();
bool defer_attributes = false; // do we defer attributes reporting to coalesce
ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid,
srcaddr,
srcendpoint, dstendpoint, wasbroadcast,
linkquality, securityuse, seqnumber,
timestamp);
// log the packet details
zcl_received.log();
zigbee_devices.setLQI(srcaddr, linkquality);
zigbee_devices.setLQI(srcaddr, linkquality != 0xFF ? linkquality : 0xFE); // EFR32 has a different scale for LQI
char shortaddr[8];
snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr);
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
@ -823,17 +852,180 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
Z_AutoResponder(srcaddr, clusterid, srcendpoint, json[F("ReadNames")]);
}
}
}
#ifdef USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Send ZDO Message
\*********************************************************************************************/
void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload, size_t payload_len) {
SBuffer buf(payload_len + 20);
uint8_t seq = zigbee_devices.getNextSeqNumber(0x0000);
buf.add8(EMBER_OUTGOING_DIRECT); // 00
buf.add16(shortaddr); // dest addr
// ApsFrame
buf.add16(0x0000); // ZOD profile
buf.add16(cmd); // ZDO cmd in cluster
buf.add8(0); // srcEp
buf.add8(0); // dstEp
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
buf.add16(0x0000); // groupId
buf.add8(seq);
// end of ApsFrame
buf.add8(0x01); // tag TODO
buf.add8(payload_len + 1); // insert seq number
buf.add8(seq);
buf.addBuffer(payload, payload_len);
}
/*********************************************************************************************\
* Send specific EZSP messages
\*********************************************************************************************/
int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) {
uint8_t msgtype = buf.get8(2); // see EZSP_EmberIncomingMessageType
bool wasbroadcast = (msgtype >= EMBER_INCOMING_MULTICAST) && (msgtype <= EMBER_INCOMING_BROADCAST_LOOPBACK);
uint16_t profileid = buf.get16(3); // HA = 0x0104, ZDO = 0x0000
uint16_t clusterid = buf.get16(5);
uint8_t srcendpoint = buf.get8(7);
uint8_t dstendpoint = buf.get8(8);
uint16_t apsoptions = buf.get16(9); // see EZSP_EmberApsOption, usually EMBER_APS_OPTION_ENABLE_ADDRESS_DISCOVERY
bool securityuse = (apsoptions & EMBER_APS_OPTION_ENCRYPTION) ? true : false;
uint16_t groupid = buf.get16(11);
uint8_t seqnumber = buf.get8(13);
uint8_t linkquality = buf.get8(14);
// uint8_t linkrsssi = buf.get8(15); // probably not used as there is no equivalent in Z-Stack
uint16_t srcaddr = buf.get16(16);
uint8_t bindingindex = buf.get8(18); // TODO not sure we need this one as a coordinator
uint8_t addressindex = buf.get8(19); // TODO not sure how to handle this one
// offset 20 is len, and buffer starts at offset 21
if ((0x0000 == profileid) && (0x00 == srcendpoint)) {
// ZDO request
SBuffer zdo_buf = buf.subBuffer(21, buf.get8(20));
switch (clusterid) {
case ZDO_Device_annce:
Z_ReceiveEndDeviceAnnonce(res, zdo_buf);
break;
}
} else {
bool defer_attributes = false; // do we defer attributes reporting to coalesce
ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 21, buf.get8(20), clusterid, groupid,
srcaddr,
srcendpoint, dstendpoint, wasbroadcast,
linkquality, securityuse, seqnumber);
//
Z_IncomingMessage(zcl_received);
}
return -1;
}
//
// Callback for loading Zigbee configuration from Flash, called by the state machine
//
int32_t Z_Reset_Device(uint8_t value) {
// TODO - GPIO is hardwired to GPIO4
digitalWrite(4, value ? HIGH : LOW);
return 0; // continue
}
/*********************************************************************************************\
* Default resolver
\*********************************************************************************************/
int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
// Default message handler for new messages
if (zigbee.init_phase) {
// if still during initialization phase, ignore any unexpected message
return -1; // ignore message
} else {
switch (buf.get8(0)) {
case EZSP_incomingMessageHandler:
return EZ_IncomingMessage(res, buf);
break;
case EZSP_trustCenterJoinHandler:
return EZ_ReceiveTCJoinHandler(res, buf);
break;
}
return -1;
}
}
#endif // USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Callbacks
\*********************************************************************************************/
// 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
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
const JsonVariant &val_endpoint = GetCaseInsensitive(json, PSTR(OCCUPANCY));
if (nullptr != &val_endpoint) {
uint32_t occupancy = strToUInt(val_endpoint);
if (occupancy) {
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
} else {
zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY);
}
}
}
// Publish the received values once they have been coalesced
int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
const JsonObject *json = zigbee_devices.jsonGet(shortaddr);
if (json == nullptr) { return 0; } // don't crash if not found
zigbee_devices.jsonPublishFlush(shortaddr);
return 1;
}
/*********************************************************************************************\
* Global dispatcher for incoming messages
\*********************************************************************************************/
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
uint16_t groupid = buf.get16(2);
uint16_t clusterid = buf.get16(4);
uint16_t srcaddr = buf.get16(6);
uint8_t srcendpoint = buf.get8(8);
uint8_t dstendpoint = buf.get8(9);
uint8_t wasbroadcast = buf.get8(10);
uint8_t linkquality = buf.get8(11);
uint8_t securityuse = buf.get8(12);
// uint32_t timestamp = buf.get32(13);
uint8_t seqnumber = buf.get8(17);
bool defer_attributes = false; // do we defer attributes reporting to coalesce
ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid,
srcaddr,
srcendpoint, dstendpoint, wasbroadcast,
linkquality, securityuse, seqnumber);
//
Z_IncomingMessage(zcl_received);
return -1;
}
#ifdef USE_ZIGBEE_ZNP
// Structure for the Dispatcher callbacks table
typedef struct Z_Dispatcher {
const uint8_t* match;
ZB_RecvMsgFunc func;
} Z_Dispatcher;
#ifdef USE_ZIGBEE_ZNP
// Ffilters based on ZNP frames
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
@ -874,7 +1066,7 @@ int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
// if still during initialization phase, ignore any unexpected message
return -1; // ignore message
} else {
for (uint32_t i = 0; i < sizeof(Z_DispatchTable)/sizeof(Z_Dispatcher); i++) {
for (uint32_t i = 0; i < ARRAY_SIZE(Z_DispatchTable); i++) {
if (Z_ReceiveMatchPrefix(buf, Z_DispatchTable[i].match)) {
(*Z_DispatchTable[i].func)(res, buf);
}

View File

@ -495,7 +495,7 @@ int32_t ZigbeeProcessInputEZSP(class SBuffer &buf) {
bool overflow = frame_control & 0x01;
bool callbackPending = frame_control & 0x04;
bool security_enabled = frame_control & 0x8000;
if (frame_control != 0x0180) {
if (truncated || overflow || security_enabled) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: specific frame_control 0x%04X"), frame_control);
}

View File

@ -954,8 +954,8 @@ void CmndZbRestore(void) {
//
void CmndZbPermitJoin(void) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
uint32_t payload = XdrvMailbox.payload;
uint16_t dstAddr = 0xFFFC; // default addr
uint8_t duration = 60; // default 60s
if (payload <= 0) {
@ -964,7 +964,10 @@ void CmndZbPermitJoin(void) {
duration = 0xFF; // unlimited time
}
// ZNP Version
#ifdef USE_ZIGBEE_ZNP
uint16_t dstAddr = 0xFFFC; // default addr
SBuffer buf(34);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); // 36
@ -974,8 +977,17 @@ void CmndZbPermitJoin(void) {
buf.add8(0x00); // TCSignificance
ZigbeeZNPSend(buf.getBuffer(), buf.len());
#endif // USE_ZIGBEE_ZNP
// EZSP VERSION
#ifdef USE_ZIGBEE_EZSP
SBuffer buf(3);
buf.add16(EZSP_permitJoining);
buf.add8(duration);
ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true);
#endif // USE_ZIGBEE_EZSP
ResponseCmndDone();
}