mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 18:56:38 +00:00
Merge pull request #16407 from s-hadinger/zigbee_greenpower_phase1
Zigbee prepare for Green Power support
This commit is contained in:
commit
d6a74563eb
@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Support for Modbus writing using ModbusBridge by JeroenSt (#16351)
|
- Support for Modbus writing using ModbusBridge by JeroenSt (#16351)
|
||||||
- Support for Ethernet in ESP32 safeboot firmware (#16388)
|
- Support for Ethernet in ESP32 safeboot firmware (#16388)
|
||||||
- Flowrate meter flow amount/duration, show values in table format (#16385)
|
- Flowrate meter flow amount/duration, show values in table format (#16385)
|
||||||
|
- Zigbee prepare for Green Power support
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- TasmotaModbus library from v3.5.0 to v3.6.0 (#16351)
|
- TasmotaModbus library from v3.5.0 to v3.6.0 (#16351)
|
||||||
|
@ -923,6 +923,8 @@ enum Z_App_Profiles {
|
|||||||
Z_PROF_TA = 0x0107, // Telecom Applications
|
Z_PROF_TA = 0x0107, // Telecom Applications
|
||||||
Z_PROF_PHHC = 0x0108, // Personal Home & Hospital Care
|
Z_PROF_PHHC = 0x0108, // Personal Home & Hospital Care
|
||||||
Z_PROF_AMI = 0x0109, // Advanced Metering Initiative
|
Z_PROF_AMI = 0x0109, // Advanced Metering Initiative
|
||||||
|
// Green Power
|
||||||
|
Z_PROF_GP = 0xa1e0, // Green Power profile
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Z_Device_Ids {
|
enum Z_Device_Ids {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -187,8 +187,8 @@ const uint8_t Z_EXPORT_DATA = 0x80;
|
|||||||
enum Cx_cluster_short {
|
enum Cx_cluster_short {
|
||||||
Cx0000, Cx0001, Cx0002, Cx0003, Cx0004, Cx0005, Cx0006, Cx0007,
|
Cx0000, Cx0001, Cx0002, Cx0003, Cx0004, Cx0005, Cx0006, Cx0007,
|
||||||
Cx0008, Cx0009, Cx000A, Cx000B, Cx000C, Cx000D, Cx000E, Cx000F,
|
Cx0008, Cx0009, Cx000A, Cx000B, Cx000C, Cx000D, Cx000E, Cx000F,
|
||||||
Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0100,
|
Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0021,
|
||||||
Cx0101, Cx0102, Cx0201, Cx0202, Cx0203, Cx0204,
|
Cx0100, Cx0101, Cx0102, Cx0201, Cx0202, Cx0203, Cx0204,
|
||||||
Cx0300, Cx0301, Cx0400, Cx0401, Cx0402, Cx0403,
|
Cx0300, Cx0301, Cx0400, Cx0401, Cx0402, Cx0403,
|
||||||
Cx0404, Cx0405, Cx0406, Cx0500, Cx0702, Cx0B01, Cx0B04, Cx0B05,
|
Cx0404, Cx0405, Cx0406, Cx0500, Cx0702, Cx0B01, Cx0B04, Cx0B05,
|
||||||
CxEF00, CxFC01, CxFC40, CxFCC0, CxFCCC,
|
CxEF00, CxFC01, CxFC40, CxFCC0, CxFCCC,
|
||||||
@ -197,8 +197,8 @@ enum Cx_cluster_short {
|
|||||||
const uint16_t Cx_cluster[] PROGMEM = {
|
const uint16_t Cx_cluster[] PROGMEM = {
|
||||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||||
0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0100,
|
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0021,
|
||||||
0x0101, 0x0102, 0x0201, 0x0202, 0x0203, 0x0204,
|
0x0100, 0x0101, 0x0102, 0x0201, 0x0202, 0x0203, 0x0204,
|
||||||
0x0300, 0x0301, 0x0400, 0x0401, 0x0402, 0x0403,
|
0x0300, 0x0301, 0x0400, 0x0401, 0x0402, 0x0403,
|
||||||
0x0404, 0x0405, 0x0406, 0x0500, 0x0702, 0x0B01, 0x0B04, 0x0B05,
|
0x0404, 0x0405, 0x0406, 0x0500, 0x0702, 0x0B01, 0x0B04, 0x0B05,
|
||||||
0xEF00, 0xFC01, 0xFC40, 0xFCC0, 0xFCCC,
|
0xEF00, 0xFC01, 0xFC40, 0xFCC0, 0xFCCC,
|
||||||
@ -746,6 +746,27 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
|
|||||||
{ Zuint32, Cx0020, 0x0005, Z_(LongPollIntervalMin), Cm1, 0 },
|
{ Zuint32, Cx0020, 0x0005, Z_(LongPollIntervalMin), Cm1, 0 },
|
||||||
{ Zuint16, Cx0020, 0x0006, Z_(FastPollTimeoutMax), Cm1, 0 },
|
{ Zuint16, Cx0020, 0x0006, Z_(FastPollTimeoutMax), Cm1, 0 },
|
||||||
|
|
||||||
|
// Green Power
|
||||||
|
{ Zuint8, Cx0021, 0x0000, Z_(MaxSinkTableEntries), Cm1, 0 },
|
||||||
|
{ Zoctstr16,Cx0021, 0x0001, Z_(SinkTable), Cm1, 0 },
|
||||||
|
{ Zmap8, Cx0021, 0x0002, Z_(CommunicationMode), Cm1, 0 },
|
||||||
|
{ Zmap8, Cx0021, 0x0003, Z_(CcommissioningExitMode),Cm1, 0 },
|
||||||
|
{ Zuint16, Cx0021, 0x0004, Z_(CommissioningWindow), Cm1, 0 },
|
||||||
|
{ Zmap8, Cx0021, 0x0005, Z_(SecurityLevel), Cm1, 0 },
|
||||||
|
{ Zmap24, Cx0021, 0x0006, Z_(ServerFunctionality), Cm1, 0 },
|
||||||
|
{ Zmap24, Cx0021, 0x0007, Z_(ServerActiveFunctionality), Cm1, 0 },
|
||||||
|
{ Zuint8, Cx0021, 0x0010, Z_(MaxProxyTableEntries), Cm1, 0 },
|
||||||
|
{ Zoctstr16,Cx0021, 0x0011, Z_(ProxyTable), Cm1, 0 },
|
||||||
|
{ Zuint8, Cx0021, 0x0012, Z_(NotificationRetryNumber),Cm1, 0 },
|
||||||
|
{ Zuint8, Cx0021, 0x0013, Z_(NotificationRetryTimer),Cm1, 0 },
|
||||||
|
{ Zuint8, Cx0021, 0x0014, Z_(MaxSearchCounter), Cm1, 0 },
|
||||||
|
{ Zoctstr16,Cx0021, 0x0015, Z_(BlockedGPDID), Cm1, 0 },
|
||||||
|
{ Zmap24, Cx0021, 0x0016, Z_(ClientFunctionality), Cm1, 0 },
|
||||||
|
{ Zmap24, Cx0021, 0x0017, Z_(ClientActiveFunctionality), Cm1, 0 },
|
||||||
|
{ Zmap8, Cx0021, 0x0020, Z_(SharedSecurityKeyType),Cm1, 0 },
|
||||||
|
{ Zkey128, Cx0021, 0x0021, Z_(SharedSecurityKey), Cm1, 0 },
|
||||||
|
{ Zkey128, Cx0021, 0x0022, Z_(LinkKey), Cm1, 0 },
|
||||||
|
|
||||||
// Shade Configuration cluster
|
// Shade Configuration cluster
|
||||||
{ Zuint16, Cx0100, 0x0000, Z_(PhysicalClosedLimit), Cm1, 0 },
|
{ Zuint16, Cx0100, 0x0000, Z_(PhysicalClosedLimit), Cm1, 0 },
|
||||||
{ Zuint8, Cx0100, 0x0001, Z_(MotorStepSize), Cm1, 0 },
|
{ Zuint8, Cx0100, 0x0001, Z_(MotorStepSize), Cm1, 0 },
|
||||||
|
@ -108,7 +108,7 @@ public:
|
|||||||
manuf(manuf_code), transactseq(transact_seq), cmd(cmd_id),
|
manuf(manuf_code), transactseq(transact_seq), cmd(cmd_id),
|
||||||
payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough
|
payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough
|
||||||
cluster(clusterid), groupaddr(groupaddr),
|
cluster(clusterid), groupaddr(groupaddr),
|
||||||
shortaddr(srcaddr), _srcendpoint(srcendpoint), dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast),
|
shortaddr(srcaddr), srcendpoint(srcendpoint), dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast),
|
||||||
_linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber)
|
_linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber)
|
||||||
{
|
{
|
||||||
_frame_control.d8 = frame_control;
|
_frame_control.d8 = frame_control;
|
||||||
@ -128,7 +128,7 @@ public:
|
|||||||
"\"manuf\":\"0x%04X\",\"transact\":%d,"
|
"\"manuf\":\"0x%04X\",\"transact\":%d,"
|
||||||
"\"cmdid\":\"0x%02X\",\"payload\":\"%_B\"}}"),
|
"\"cmdid\":\"0x%02X\",\"payload\":\"%_B\"}}"),
|
||||||
groupaddr, cluster, shortaddr,
|
groupaddr, cluster, shortaddr,
|
||||||
_srcendpoint, dstendpoint, _wasbroadcast,
|
srcendpoint, dstendpoint, _wasbroadcast,
|
||||||
_linkquality, _securityuse, _seqnumber,
|
_linkquality, _securityuse, _seqnumber,
|
||||||
_frame_control,
|
_frame_control,
|
||||||
_frame_control.b.frame_type, _frame_control.b.direction, _frame_control.b.disable_def_resp,
|
_frame_control.b.frame_type, _frame_control.b.direction, _frame_control.b.disable_def_resp,
|
||||||
@ -207,7 +207,7 @@ public:
|
|||||||
inline uint16_t getClusterId(void) const { return cluster; }
|
inline uint16_t getClusterId(void) const { return cluster; }
|
||||||
inline uint8_t getLinkQuality(void) const { return _linkquality; }
|
inline uint8_t getLinkQuality(void) const { return _linkquality; }
|
||||||
inline uint8_t getCmdId(void) const { return cmd; }
|
inline uint8_t getCmdId(void) const { return cmd; }
|
||||||
inline uint16_t getSrcEndpoint(void) const { return _srcendpoint; }
|
inline uint16_t getSrcEndpoint(void) const { return srcendpoint; }
|
||||||
const SBuffer &getPayload(void) const { return payload; }
|
const SBuffer &getPayload(void) const { return payload; }
|
||||||
uint16_t getManufCode(void) const { return manuf; }
|
uint16_t getManufCode(void) const { return manuf; }
|
||||||
|
|
||||||
@ -234,9 +234,11 @@ public:
|
|||||||
bool direct = false; // true if direct, false if discover router
|
bool direct = false; // true if direct, false if discover router
|
||||||
bool transacSet = false; // is transac already set
|
bool transacSet = false; // is transac already set
|
||||||
|
|
||||||
|
uint8_t srcendpoint = 0x00; // 0x00 is invalid for the src endpoint
|
||||||
|
bool direction = false; // false = client to server (default), true = server to client (rare)
|
||||||
|
|
||||||
// below private attributes are not used when sending a message
|
// below private attributes are not used when sending a message
|
||||||
private:
|
private:
|
||||||
uint8_t _srcendpoint = 0x00; // 0x00 is invalid for the src endpoint
|
|
||||||
ZCLHeaderFrameControl_t _frame_control = { .d8 = 0 };
|
ZCLHeaderFrameControl_t _frame_control = { .d8 = 0 };
|
||||||
bool _wasbroadcast = false;
|
bool _wasbroadcast = false;
|
||||||
uint8_t _linkquality = 0x00;
|
uint8_t _linkquality = 0x00;
|
||||||
@ -531,6 +533,16 @@ uint32_t parseSingleAttribute(Z_attribute & attr, const SBuffer &buf,
|
|||||||
attr.setUInt(uint16_val);
|
attr.setUInt(uint16_val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Zdata24: // data16
|
||||||
|
case Zmap24: // map16
|
||||||
|
{
|
||||||
|
uint32_t uint32_val = buf.get16(i);
|
||||||
|
uint8_t high = buf.get8(i+2);
|
||||||
|
uint32_val = uint32_val | (high << 16);
|
||||||
|
// i += 3;
|
||||||
|
attr.setUInt(uint32_val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Zdata32: // data32
|
case Zdata32: // data32
|
||||||
case Zmap32: // map32
|
case Zmap32: // map32
|
||||||
{
|
{
|
||||||
@ -549,7 +561,7 @@ uint32_t parseSingleAttribute(Z_attribute & attr, const SBuffer &buf,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO
|
// All other fixed size, convert to a HEX dump
|
||||||
case ZToD: // ToD
|
case ZToD: // ToD
|
||||||
case Zdate: // date
|
case Zdate: // date
|
||||||
case ZclusterId: // clusterId
|
case ZclusterId: // clusterId
|
||||||
@ -558,17 +570,19 @@ uint32_t parseSingleAttribute(Z_attribute & attr, const SBuffer &buf,
|
|||||||
case ZEUI64: // EUI64
|
case ZEUI64: // EUI64
|
||||||
case Zkey128: // key128
|
case Zkey128: // key128
|
||||||
case Zsemi: // semi (float on 2 bytes)
|
case Zsemi: // semi (float on 2 bytes)
|
||||||
|
{
|
||||||
|
attr.setBuf(buf, i, len);
|
||||||
|
}
|
||||||
|
// i += 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Other un-implemented data types
|
// Other un-implemented data types
|
||||||
case Zdata24: // data24
|
|
||||||
case Zdata40: // data40
|
case Zdata40: // data40
|
||||||
case Zdata48: // data48
|
case Zdata48: // data48
|
||||||
case Zdata56: // data56
|
case Zdata56: // data56
|
||||||
case Zdata64: // data64
|
case Zdata64: // data64
|
||||||
break;
|
break;
|
||||||
// map<x>
|
// map<x>
|
||||||
case Zmap24: // map24
|
|
||||||
case Zmap40: // map40
|
case Zmap40: // map40
|
||||||
case Zmap48: // map48
|
case Zmap48: // map48
|
||||||
case Zmap56: // map56
|
case Zmap56: // map56
|
||||||
@ -621,7 +635,7 @@ void ZCLFrame::parseReportAttributes(Z_attribute_list& attr_list) {
|
|||||||
ZCLFrame zcl(2); // message is 2 bytes
|
ZCLFrame zcl(2); // message is 2 bytes
|
||||||
zcl.shortaddr = shortaddr;
|
zcl.shortaddr = shortaddr;
|
||||||
zcl.cluster = cluster;
|
zcl.cluster = cluster;
|
||||||
zcl.dstendpoint = _srcendpoint;
|
zcl.dstendpoint = srcendpoint;
|
||||||
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
||||||
zcl.manuf = manuf;
|
zcl.manuf = manuf;
|
||||||
zcl.clusterSpecific = false; /* not cluster specific */
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
@ -768,7 +782,7 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) {
|
|||||||
if (attr_rgb == nullptr) { // make sure we didn't already computed it
|
if (attr_rgb == nullptr) { // make sure we didn't already computed it
|
||||||
uint8_t brightness = 255;
|
uint8_t brightness = 255;
|
||||||
if (device.valid()) {
|
if (device.valid()) {
|
||||||
const Z_Data_Light & light = device.data.find<Z_Data_Light>(_srcendpoint);
|
const Z_Data_Light & light = device.data.find<Z_Data_Light>(srcendpoint);
|
||||||
if ((&light != &z_data_unk) && (light.validDimmer())) {
|
if ((&light != &z_data_unk) && (light.validDimmer())) {
|
||||||
// Dimmer has a valid value
|
// Dimmer has a valid value
|
||||||
brightness = changeUIntScale(light.getDimmer(), 0, 254, 0, 255); // range is 0..255
|
brightness = changeUIntScale(light.getDimmer(), 0, 254, 0, 255); // range is 0..255
|
||||||
@ -798,7 +812,7 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x05000002: // ZoneStatus
|
case 0x05000002: // ZoneStatus
|
||||||
const Z_Data_Alarm & alarm = (const Z_Data_Alarm&) zigbee_devices.getShortAddr(shortaddr).data.find(Z_Data_Type::Z_Alarm, _srcendpoint);
|
const Z_Data_Alarm & alarm = (const Z_Data_Alarm&) zigbee_devices.getShortAddr(shortaddr).data.find(Z_Data_Type::Z_Alarm, srcendpoint);
|
||||||
if (&alarm != nullptr) {
|
if (&alarm != nullptr) {
|
||||||
alarm.convertZoneStatus(attr_list, attr.getUInt());
|
alarm.convertZoneStatus(attr_list, attr.getUInt());
|
||||||
}
|
}
|
||||||
@ -821,12 +835,12 @@ void ZCLFrame::generateCallBacks(Z_attribute_list& attr_list) {
|
|||||||
uint32_t occupancy = attr.getUInt();
|
uint32_t occupancy = attr.getUInt();
|
||||||
if (occupancy) {
|
if (occupancy) {
|
||||||
uint32_t pir_timer = OCCUPANCY_TIMEOUT;
|
uint32_t pir_timer = OCCUPANCY_TIMEOUT;
|
||||||
const Z_Data_PIR & pir_found = (const Z_Data_PIR&) zigbee_devices.getShortAddr(shortaddr).data.find(Z_Data_Type::Z_PIR, _srcendpoint);
|
const Z_Data_PIR & pir_found = (const Z_Data_PIR&) zigbee_devices.getShortAddr(shortaddr).data.find(Z_Data_Type::Z_PIR, srcendpoint);
|
||||||
if (&pir_found != nullptr) {
|
if (&pir_found != nullptr) {
|
||||||
pir_timer = pir_found.getTimeoutSeconds() * 1000;
|
pir_timer = pir_found.getTimeoutSeconds() * 1000;
|
||||||
}
|
}
|
||||||
if (pir_timer > 0) {
|
if (pir_timer > 0) {
|
||||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, pir_timer, cluster, _srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
|
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, pir_timer, cluster, srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY);
|
zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY);
|
||||||
@ -1049,7 +1063,7 @@ void ZCLFrame::parseResponse_inner(uint8_t cmd, bool cluster_specific, uint8_t s
|
|||||||
// "StatusMessage"
|
// "StatusMessage"
|
||||||
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_STATUS_MSG)).setStr(getZigbeeStatusMessage(status).c_str());
|
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_STATUS_MSG)).setStr(getZigbeeStatusMessage(status).c_str());
|
||||||
// Add Endpoint
|
// Add Endpoint
|
||||||
attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_ENDPOINT)).setUInt(_srcendpoint);
|
attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_ENDPOINT)).setUInt(srcendpoint);
|
||||||
// Add Group if non-zero
|
// Add Group if non-zero
|
||||||
if (groupaddr) { // TODO what about group zero
|
if (groupaddr) { // TODO what about group zero
|
||||||
attr_list.group_id = groupaddr;
|
attr_list.group_id = groupaddr;
|
||||||
@ -1082,16 +1096,16 @@ void Z_ResetDebounce(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, u
|
|||||||
void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) {
|
void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) {
|
||||||
// Check if debounce is active and if the packet is a duplicate
|
// Check if debounce is active and if the packet is a duplicate
|
||||||
Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
|
Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
|
||||||
if ((device.debounce_endpoint != 0) && (device.debounce_endpoint == _srcendpoint) && (device.debounce_transact == transactseq)) {
|
if ((device.debounce_endpoint != 0) && (device.debounce_endpoint == srcendpoint) && (device.debounce_transact == transactseq)) {
|
||||||
// this is a duplicate, drop the packet
|
// this is a duplicate, drop the packet
|
||||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Discarding duplicate command from 0x%04X, endpoint %d"), shortaddr, _srcendpoint);
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Discarding duplicate command from 0x%04X, endpoint %d"), shortaddr, srcendpoint);
|
||||||
} else {
|
} else {
|
||||||
// reset the duplicate marker, parse the packet normally, and set a timer to reset the marker later (which will discard any existing timer for the same device/endpoint)
|
// reset the duplicate marker, parse the packet normally, and set a timer to reset the marker later (which will discard any existing timer for the same device/endpoint)
|
||||||
device.debounce_endpoint = _srcendpoint;
|
device.debounce_endpoint = srcendpoint;
|
||||||
device.debounce_transact = transactseq;
|
device.debounce_transact = transactseq;
|
||||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, USE_ZIGBEE_DEBOUNCE_COMMANDS, 0 /*clusterid*/, _srcendpoint, Z_CAT_DEBOUNCE_CMD, 0, &Z_ResetDebounce);
|
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, USE_ZIGBEE_DEBOUNCE_COMMANDS, 0 /*clusterid*/, srcendpoint, Z_CAT_DEBOUNCE_CMD, 0, &Z_ResetDebounce);
|
||||||
|
|
||||||
convertClusterSpecific(attr_list, cluster, cmd, _frame_control.b.direction, shortaddr, _srcendpoint, payload);
|
convertClusterSpecific(attr_list, cluster, cmd, _frame_control.b.direction, shortaddr, srcendpoint, payload);
|
||||||
if (!Settings->flag5.zb_disable_autoquery) {
|
if (!Settings->flag5.zb_disable_autoquery) {
|
||||||
// read attributes unless disabled
|
// read attributes unless disabled
|
||||||
if (!_frame_control.b.direction) { // only handle server->client (i.e. device->coordinator)
|
if (!_frame_control.b.direction) { // only handle server->client (i.e. device->coordinator)
|
||||||
@ -1107,7 +1121,7 @@ void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) {
|
|||||||
ZCLFrame zcl(2); // message is 4 bytes
|
ZCLFrame zcl(2); // message is 4 bytes
|
||||||
zcl.shortaddr = shortaddr;
|
zcl.shortaddr = shortaddr;
|
||||||
zcl.cluster = cluster;
|
zcl.cluster = cluster;
|
||||||
zcl.dstendpoint = _srcendpoint;
|
zcl.dstendpoint = srcendpoint;
|
||||||
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
||||||
zcl.manuf = manuf;
|
zcl.manuf = manuf;
|
||||||
zcl.clusterSpecific = false; /* not cluster specific */
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
|
@ -315,16 +315,22 @@ ZBM(ZBR_ZDO_ACTIVEEPREQ, Z_SRSP | Z_ZDO, ZDO_ACTIVE_EP_REQ, Z_SUCCESS) // 65050
|
|||||||
// Change #14819 - we now allow some EP to be alreaady declared
|
// Change #14819 - we now allow some EP to be alreaady declared
|
||||||
ZBM(ZBR_ZDO_ACTIVEEPRSP_SUCESS, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS) // 45050000xxxx - no Ep running
|
ZBM(ZBR_ZDO_ACTIVEEPRSP_SUCESS, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS) // 45050000xxxx - no Ep running
|
||||||
ZBM(ZBR_ZDO_ACTIVEEPRSP_OK, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS,
|
ZBM(ZBR_ZDO_ACTIVEEPRSP_OK, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS,
|
||||||
0x00, 0x00 /* nwkaddr */, 0x02 /* activeepcount */, 0x0B, 0x01 /* the actual endpoints */) // 25050000 - no Ep running
|
0x00, 0x00 /* nwkaddr */, 0x03 /* activeepcount */, 0xF2, 0x0B, 0x01 /* the actual endpoints */) // 4585000000000003F20B01
|
||||||
|
|
||||||
// Z_AF:register profile:104, ep:01
|
// Z_AF:register profile:104, ep:01
|
||||||
ZBM(ZBS_AF_REGISTER01, Z_SREQ | Z_AF, AF_REGISTER, 0x01 /* endpoint */, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), // 24000401050000000000
|
ZBM(ZBS_AF_REGISTER01, Z_SREQ | Z_AF, AF_REGISTER, 0x01 /* endpoint */, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), // 24000401050000000000
|
||||||
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
||||||
0x00 /* AppNumInClusters */, 0x00 /* AppNumInClusters */)
|
0x00 /* AppNumInClusters */, 0x00 /* AppNumOutClusters */)
|
||||||
ZBM(ZBR_AF_REGISTER, Z_SRSP | Z_AF, AF_REGISTER, Z_SUCCESS) // 640000
|
ZBM(ZBR_AF_REGISTER, Z_SRSP | Z_AF, AF_REGISTER, Z_SUCCESS) // 640000
|
||||||
ZBM(ZBS_AF_REGISTER0B, Z_SREQ | Z_AF, AF_REGISTER, 0x0B /* endpoint */, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), // 2400040B050000000000
|
ZBM(ZBS_AF_REGISTER0B, Z_SREQ | Z_AF, AF_REGISTER, 0x0B /* endpoint */, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), // 2400040B050000000000
|
||||||
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
||||||
0x00 /* AppNumInClusters */, 0x00 /* AppNumInClusters */)
|
0x00 /* AppNumInClusters */, 0x00 /* AppNumOutClusters */)
|
||||||
|
// Green Power endpoint 242 0xF2
|
||||||
|
ZBM(ZBS_AF_REGISTERF2, Z_SREQ | Z_AF, AF_REGISTER, 0xF2 /* endpoint */, Z_B0(Z_PROF_GP), Z_B1(Z_PROF_GP), //
|
||||||
|
0x05, 0x61 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
||||||
|
0x00 /* AppNumInClusters */,
|
||||||
|
0x01 /* AppNumOutClusters */,
|
||||||
|
0x21,0x00) // 0x0021
|
||||||
// Z_AF:register profile:104, ep:01 - main clusters for router or device
|
// Z_AF:register profile:104, ep:01 - main clusters for router or device
|
||||||
ZBM(ZBS_AF_REGISTER_ALL, Z_SREQ | Z_AF, AF_REGISTER, 0x01 /* endpoint */, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), // 24000401050000000000
|
ZBM(ZBS_AF_REGISTER_ALL, Z_SREQ | Z_AF, AF_REGISTER, 0x01 /* endpoint */, Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), // 24000401050000000000
|
||||||
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
0x05, 0x00 /* AppDeviceId */, 0x00 /* AppDevVer */, 0x00 /* LatencyReq */,
|
||||||
@ -333,7 +339,7 @@ ZBM(ZBS_AF_REGISTER_ALL, Z_SREQ | Z_AF, AF_REGISTER, 0x01 /* endpoint */, Z_B0(Z
|
|||||||
0x07,0x00, 0x08,0x00, 0x0A,0x00, 0x02,0x01, // 0x0007, 0x0008, 0x000A, 0X0102
|
0x07,0x00, 0x08,0x00, 0x0A,0x00, 0x02,0x01, // 0x0007, 0x0008, 0x000A, 0X0102
|
||||||
0x00,0x03, 0x00,0x04, 0x02,0x04, 0x03,0x04, // 0x0300, 0x0400, 0x0402, 0x0403
|
0x00,0x03, 0x00,0x04, 0x02,0x04, 0x03,0x04, // 0x0300, 0x0400, 0x0402, 0x0403
|
||||||
0x05,0x04, 0x06,0x04, // 0x0405, 0x0406
|
0x05,0x04, 0x06,0x04, // 0x0405, 0x0406
|
||||||
0x00 /* AppNumInClusters */)
|
0x00 /* AppNumOutClusters */)
|
||||||
|
|
||||||
// Z_ZDO:mgmtPermitJoinReq
|
// Z_ZDO:mgmtPermitJoinReq
|
||||||
ZBM(ZBS_PERMITJOINREQ_CLOSE, Z_SREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_REQ, 0x02 /* AddrMode */, // 25360200000000
|
ZBM(ZBS_PERMITJOINREQ_CLOSE, Z_SREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_REQ, 0x02 /* AddrMode */, // 25360200000000
|
||||||
@ -506,6 +512,8 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
|||||||
ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
||||||
ZI_SEND(ZBS_AF_REGISTER0B) // Z_AF register for endpoint 0B, profile 0x0104 Home Automation
|
ZI_SEND(ZBS_AF_REGISTER0B) // Z_AF register for endpoint 0B, profile 0x0104 Home Automation
|
||||||
ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
||||||
|
ZI_SEND(ZBS_AF_REGISTERF2) // Z_AF register for endpoint F2, profile 0xa1e0 Green Power
|
||||||
|
ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
||||||
// Write again channels, see https://github.com/Koenkk/zigbee-herdsman/blob/37bea20ba04ee5d4938abc21a7569b43f831de32/src/adapter/z-stack/adapter/startZnp.ts#L244-L245
|
// Write again channels, see https://github.com/Koenkk/zigbee-herdsman/blob/37bea20ba04ee5d4938abc21a7569b43f831de32/src/adapter/z-stack/adapter/startZnp.ts#L244-L245
|
||||||
ZI_SEND(ZBS_W_CHANN) // write CHANNEL
|
ZI_SEND(ZBS_W_CHANN) // write CHANNEL
|
||||||
ZI_WAIT_RECV(1000, ZBR_WNV_OK)
|
ZI_WAIT_RECV(1000, ZBR_WNV_OK)
|
||||||
|
@ -2232,7 +2232,7 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
|
|||||||
",\"Endpoint\":%d"
|
",\"Endpoint\":%d"
|
||||||
",\"Response\":%s}"
|
",\"Response\":%s}"
|
||||||
),
|
),
|
||||||
shortaddr, cluster, _srcendpoint,
|
shortaddr, cluster, srcendpoint,
|
||||||
attr_list.toString().c_str());
|
attr_list.toString().c_str());
|
||||||
|
|
||||||
// send
|
// send
|
||||||
@ -2240,7 +2240,7 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
|
|||||||
ZCLFrame zcl(buf.len()); // message is 4 bytes
|
ZCLFrame zcl(buf.len()); // message is 4 bytes
|
||||||
zcl.shortaddr = shortaddr;
|
zcl.shortaddr = shortaddr;
|
||||||
zcl.cluster = cluster;
|
zcl.cluster = cluster;
|
||||||
zcl.dstendpoint = _srcendpoint;
|
zcl.dstendpoint = srcendpoint;
|
||||||
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
||||||
zcl.clusterSpecific = false; /* not cluster specific */
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
zcl.needResponse = false; /* noresponse */
|
zcl.needResponse = false; /* noresponse */
|
||||||
|
@ -775,14 +775,19 @@ void ZigbeeZCLSend_Raw(const ZCLFrame &zcl) {
|
|||||||
buf.add8(zcl.dstendpoint); // dest endpoint
|
buf.add8(zcl.dstendpoint); // dest endpoint
|
||||||
}
|
}
|
||||||
buf.add16(0x0000); // dest Pan ID, 0x0000 = intra-pan
|
buf.add16(0x0000); // dest Pan ID, 0x0000 = intra-pan
|
||||||
buf.add8(0x01); // source endpoint
|
if (zcl.srcendpoint) {
|
||||||
|
buf.add8(zcl.srcendpoint); // source endpoint
|
||||||
|
} else {
|
||||||
|
buf.add8(1); // set endpoint to 1 if not specified
|
||||||
|
}
|
||||||
buf.add16(zcl.cluster);
|
buf.add16(zcl.cluster);
|
||||||
buf.add8(zcl.transactseq); // transactseq
|
buf.add8(zcl.transactseq); // transactseq
|
||||||
buf.add8(0x30); // 30 options
|
buf.add8(zcl.direct ? 0x00 : 0x30); // 30 options
|
||||||
buf.add8(0x1E); // 1E radius
|
buf.add8(0x1E); // 1E radius
|
||||||
|
|
||||||
buf.add16(3 + zcl.payload.len() + (zcl.manuf ? 2 : 0));
|
buf.add16(3 + zcl.payload.len() + (zcl.manuf ? 2 : 0));
|
||||||
buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) | (zcl.manuf ? 0x04 : 0x00)); // Frame Control Field
|
buf.add8((zcl.needResponse ? 0x00 : 0x10) | (zcl.clusterSpecific ? 0x01 : 0x00) |
|
||||||
|
(zcl.manuf ? 0x04 : 0x00) | (zcl.direction ? 0x08 : 0x00)); // Frame Control Field
|
||||||
if (zcl.manuf) {
|
if (zcl.manuf) {
|
||||||
buf.add16(zcl.manuf); // add Manuf Id if not null
|
buf.add16(zcl.manuf); // add Manuf Id if not null
|
||||||
}
|
}
|
||||||
|
@ -730,8 +730,17 @@ void CmndZbSend(void) {
|
|||||||
// parse "Device" and "Group"
|
// parse "Device" and "Group"
|
||||||
JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)];
|
JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)];
|
||||||
if (val_device) {
|
if (val_device) {
|
||||||
zcl.shortaddr = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
|
uint16_t parsed_shortaddr = BAD_SHORTADDR;
|
||||||
if (!zcl.validShortaddr()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_INVALID_PARAM)); return; }
|
zcl.shortaddr = zigbee_devices.parseDeviceFromName(val_device.getStr(), &parsed_shortaddr).shortaddr;
|
||||||
|
if (!zcl.validShortaddr()) {
|
||||||
|
if (parsed_shortaddr != BAD_SHORTADDR) {
|
||||||
|
// we still got a short address
|
||||||
|
zcl.shortaddr = parsed_shortaddr;
|
||||||
|
} else {
|
||||||
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_INVALID_PARAM));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!zcl.validShortaddr()) { // if not found, check if we have a group
|
if (!zcl.validShortaddr()) { // if not found, check if we have a group
|
||||||
JsonParserToken val_group = root[PSTR(D_CMND_ZIGBEE_GROUP)];
|
JsonParserToken val_group = root[PSTR(D_CMND_ZIGBEE_GROUP)];
|
||||||
@ -760,6 +769,10 @@ void CmndZbSend(void) {
|
|||||||
ResponseCmndChar_P(PSTR("Missing endpoint"));
|
ResponseCmndChar_P(PSTR("Missing endpoint"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Special case for Green Power, if dstendpoint is 0xF2, then source endpoint should also be 0xF2
|
||||||
|
if (zcl.dstendpoint == 0xF2) {
|
||||||
|
zcl.srcendpoint = 0xF2;
|
||||||
|
}
|
||||||
// from here endpoint is valid and non-zero
|
// from here endpoint is valid and non-zero
|
||||||
// cluster may be already specified or 0xFFFF
|
// cluster may be already specified or 0xFFFF
|
||||||
|
|
||||||
@ -1517,6 +1530,7 @@ void CmndZbPermitJoin(void) {
|
|||||||
|
|
||||||
// ZNP Version
|
// ZNP Version
|
||||||
#ifdef USE_ZIGBEE_ZNP
|
#ifdef USE_ZIGBEE_ZNP
|
||||||
|
// put all routers in pairing mode
|
||||||
SBuffer buf(34);
|
SBuffer buf(34);
|
||||||
buf.add8(Z_SREQ | Z_ZDO); // 25
|
buf.add8(Z_SREQ | Z_ZDO); // 25
|
||||||
buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); // 36
|
buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); // 36
|
||||||
@ -1527,6 +1541,22 @@ void CmndZbPermitJoin(void) {
|
|||||||
|
|
||||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||||
|
|
||||||
|
// send Green Power pairing mode
|
||||||
|
ZCLFrame zcl(4); // message is 4 bytes max
|
||||||
|
|
||||||
|
zcl.cmd = 0x02; // GP Proxy Commissioning Mode
|
||||||
|
zcl.cluster = 0x0021; // GP cluster
|
||||||
|
zcl.shortaddr = 0xFFFC; // Broadcast to all routers
|
||||||
|
zcl.srcendpoint = 0xF2; // GP endpoint
|
||||||
|
zcl.dstendpoint = 0xF2; // GP endpoint
|
||||||
|
zcl.needResponse = false; // as per GP spec The Disable default response sub-field of the Frame Control Field of the ZCL header shall be set to 0b1."
|
||||||
|
zcl.clusterSpecific = true; // command
|
||||||
|
zcl.direct = true; // broadcast so no need to discover routes
|
||||||
|
zcl.direction = true; // server to client
|
||||||
|
zcl.payload.add8(0x0B); // Action=1, gpsCommissioningExitMode=0b101 (window expiration + GP Proxy Commissioning Mode)
|
||||||
|
zcl.payload.add16(duration);
|
||||||
|
zigbeeZCLSendCmd(zcl);
|
||||||
|
|
||||||
#endif // USE_ZIGBEE_ZNP
|
#endif // USE_ZIGBEE_ZNP
|
||||||
|
|
||||||
// EZSP VERSION
|
// EZSP VERSION
|
||||||
|
Loading…
x
Reference in New Issue
Block a user