mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 18:56:38 +00:00
Zigbee refactor sending ZCL packets
This commit is contained in:
parent
c5cd97064a
commit
a67528680e
@ -52,6 +52,20 @@ public:
|
|||||||
delete[] _buf;
|
delete[] _buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// increase the internal buffer if needed
|
||||||
|
// do nothing if the buffer is big enough
|
||||||
|
void reserve(const size_t size) {
|
||||||
|
if (size > _buf->size) {
|
||||||
|
// we need to increase the buffer size
|
||||||
|
SBuffer_impl * new_buf = (SBuffer_impl*) new char[size+4]; // add 4 bytes for size and len
|
||||||
|
new_buf->size = size;
|
||||||
|
new_buf->len = _buf->len;
|
||||||
|
memmove(&new_buf->buf, &_buf->buf, _buf->len); // copy buffer
|
||||||
|
delete[] _buf;
|
||||||
|
_buf = new_buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void setLen(const size_t len) {
|
inline void setLen(const size_t len) {
|
||||||
uint16_t old_len = _buf->len;
|
uint16_t old_len = _buf->len;
|
||||||
_buf->len = (len <= _buf->size) ? len : _buf->size;
|
_buf->len = (len <= _buf->size) ? len : _buf->size;
|
||||||
@ -118,6 +132,13 @@ public:
|
|||||||
return _buf->len;
|
return _buf->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void replace(const SBuffer &buf2) {
|
||||||
|
uint32_t len = buf2.len();
|
||||||
|
reserve(len);
|
||||||
|
setLen(0); // clear buffer
|
||||||
|
addBuffer(buf2);
|
||||||
|
}
|
||||||
|
|
||||||
size_t addBuffer(const SBuffer &buf2) {
|
size_t addBuffer(const SBuffer &buf2) {
|
||||||
if (len() + buf2.len() <= size()) {
|
if (len() + buf2.len() <= size()) {
|
||||||
for (uint32_t i = 0; i < buf2.len(); i++) {
|
for (uint32_t i = 0; i < buf2.len(); i++) {
|
||||||
|
@ -28,22 +28,40 @@
|
|||||||
//
|
//
|
||||||
// structure containing all needed information to send a ZCL packet
|
// structure containing all needed information to send a ZCL packet
|
||||||
//
|
//
|
||||||
class ZigbeeZCLSendMessage {
|
class ZCLMessage {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint16_t shortaddr;
|
ZCLMessage(void); // allocate 16 bytes vy default
|
||||||
uint16_t groupaddr;
|
ZCLMessage(size_t size);
|
||||||
uint16_t cluster;
|
|
||||||
uint8_t endpoint;
|
inline bool validShortaddr(void) const { return BAD_SHORTADDR != shortaddr; }
|
||||||
uint8_t cmd;
|
inline bool validGroupaddr(void) const { return 0 != groupaddr; }
|
||||||
uint16_t manuf;
|
inline bool validCluster(void) const { return 0xFFFF != cluster; }
|
||||||
bool clusterSpecific;
|
inline bool validEndpoint(void) const { return 0x00 != endpoint; }
|
||||||
bool needResponse;
|
inline bool validCmd(void) const { return 0xFF != cmd; }
|
||||||
bool direct; // true if direct, false if discover router
|
|
||||||
uint8_t transacId; // ZCL transaction number
|
inline void setTransac(uint8_t _transac) { transac = _transac; transacSet = true; }
|
||||||
const uint8_t *msg;
|
|
||||||
size_t len;
|
uint16_t shortaddr = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid
|
||||||
|
uint16_t groupaddr = 0x0000; // group address valid only if device == BAD_SHORTADDR
|
||||||
|
uint16_t cluster = 0xFFFF; // no default
|
||||||
|
uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint
|
||||||
|
uint8_t cmd = 0xFF; // 0xFF is invalid command number
|
||||||
|
uint16_t manuf = 0x0000; // default manuf id
|
||||||
|
bool clusterSpecific = false;
|
||||||
|
bool needResponse = true;
|
||||||
|
bool direct = false; // true if direct, false if discover router
|
||||||
|
bool transacSet = false; // is transac already set
|
||||||
|
uint8_t transac = 0; // ZCL transaction number
|
||||||
|
SBuffer buf;
|
||||||
|
// const uint8_t *msg = nullptr;
|
||||||
|
// size_t len = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// define constructor seperately to avoid inlining and reduce Flash size
|
||||||
|
ZCLMessage::ZCLMessage(void) : buf(12) {};
|
||||||
|
ZCLMessage::ZCLMessage(size_t size) : buf(size) {};
|
||||||
|
|
||||||
typedef int32_t (*ZB_Func)(uint8_t value);
|
typedef int32_t (*ZB_Func)(uint8_t value);
|
||||||
typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const SBuffer &buf);
|
typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const SBuffer &buf);
|
||||||
|
|
||||||
@ -119,8 +137,8 @@ public:
|
|||||||
struct ZigbeeStatus zigbee;
|
struct ZigbeeStatus zigbee;
|
||||||
SBuffer *zigbee_buffer = nullptr;
|
SBuffer *zigbee_buffer = nullptr;
|
||||||
|
|
||||||
void zigbeeZCLSendCmd(const ZigbeeZCLSendMessage &msg);
|
void zigbeeZCLSendCmd(ZCLMessage &msg);
|
||||||
void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl);
|
void ZigbeeZCLSend_Raw(const ZCLMessage &zcl);
|
||||||
bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_status_ok = false);
|
bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_status_ok = false);
|
||||||
|
|
||||||
// parse Hex formatted attribute names like '0301/0001"
|
// parse Hex formatted attribute names like '0301/0001"
|
||||||
|
@ -152,27 +152,21 @@ void ZigbeeHueGroups(String * lights) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeSendHue(uint16_t shortaddr, uint16_t cluster, uint8_t cmd, const SBuffer & s) {
|
void ZigbeeSendHue(uint16_t shortaddr, uint16_t cluster, uint8_t cmd, const SBuffer & s) {
|
||||||
zigbeeZCLSendCmd(ZigbeeZCLSendMessage({
|
ZCLMessage zcl(&s ? s.len() : 0);
|
||||||
shortaddr,
|
zcl.shortaddr = shortaddr;
|
||||||
0 /* groupaddr */,
|
zcl.cluster = cluster;
|
||||||
cluster /*cluster*/,
|
zcl.cmd = cmd;
|
||||||
0 /* endpoint */,
|
zcl.clusterSpecific = true;
|
||||||
cmd /* cmd */,
|
zcl.needResponse = true;
|
||||||
0, /* manuf */
|
zcl.direct = false; // discover route
|
||||||
true /* cluster specific */,
|
if (&s) { zcl.buf.replace(s); }
|
||||||
true /* response */,
|
zigbeeZCLSendCmd(zcl);
|
||||||
false /* discover route */,
|
|
||||||
0, /* zcl transaction id */
|
|
||||||
(&s != nullptr) ? s.getBuffer() : nullptr,
|
|
||||||
(&s != nullptr) ? s.len() : 0
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send commands
|
// Send commands
|
||||||
// Power On/Off
|
// Power On/Off
|
||||||
void ZigbeeHuePower(uint16_t shortaddr, bool power) {
|
void ZigbeeHuePower(uint16_t shortaddr, bool power) {
|
||||||
ZigbeeSendHue(shortaddr, 0x0006, power ? 1 : 0, *(SBuffer*)nullptr);
|
ZigbeeSendHue(shortaddr, 0x0006, power ? 1 : 0, *(SBuffer*)nullptr);
|
||||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0006, power ? 1 : 0, "");
|
|
||||||
zigbee_devices.getShortAddr(shortaddr).setPower(power, 0);
|
zigbee_devices.getShortAddr(shortaddr).setPower(power, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,23 +177,16 @@ void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) {
|
|||||||
s.add8(dimmer);
|
s.add8(dimmer);
|
||||||
s.add16(0x000A); // transition time = 1s
|
s.add16(0x000A); // transition time = 1s
|
||||||
ZigbeeSendHue(shortaddr, 0x0008, 0x04, s);
|
ZigbeeSendHue(shortaddr, 0x0008, 0x04, s);
|
||||||
// char param[8];
|
|
||||||
// snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer);
|
|
||||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0008, 0x04, param);
|
|
||||||
zigbee_devices.getLight(shortaddr).setDimmer(dimmer);
|
zigbee_devices.getLight(shortaddr).setDimmer(dimmer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CT
|
// CT
|
||||||
void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
|
void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
|
||||||
if (ct > 0xFEFF) { ct = 0xFEFF; }
|
if (ct > 0xFEFF) { ct = 0xFEFF; }
|
||||||
// AddLog(LOG_LEVEL_INFO, PSTR("ZigbeeHueCT 0x%04X - %d"), shortaddr, ct);
|
|
||||||
SBuffer s(4);
|
SBuffer s(4);
|
||||||
s.add16(ct);
|
s.add16(ct);
|
||||||
s.add16(0x000A); // transition time = 1s
|
s.add16(0x000A); // transition time = 1s
|
||||||
ZigbeeSendHue(shortaddr, 0x0300, 0x0A, s);
|
ZigbeeSendHue(shortaddr, 0x0300, 0x0A, s);
|
||||||
// char param[12];
|
|
||||||
// snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8);
|
|
||||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x0A, param);
|
|
||||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||||
light.setColorMode(2); // "ct"
|
light.setColorMode(2); // "ct"
|
||||||
light.setCT(ct);
|
light.setCT(ct);
|
||||||
@ -214,10 +201,6 @@ void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y) {
|
|||||||
s.add16(y);
|
s.add16(y);
|
||||||
s.add16(0x000A); // transition time = 1s
|
s.add16(0x000A); // transition time = 1s
|
||||||
ZigbeeSendHue(shortaddr, 0x0300, 0x07, s);
|
ZigbeeSendHue(shortaddr, 0x0300, 0x07, s);
|
||||||
// char param[16];
|
|
||||||
// snprintf_P(param, sizeof(param), PSTR("%02X%02X%02X%02X0A00"), x & 0xFF, x >> 8, y & 0xFF, y >> 8);
|
|
||||||
// uint8_t colormode = 1; // "xy"
|
|
||||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x07, param);
|
|
||||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||||
light.setColorMode(1); // "xy"
|
light.setColorMode(1); // "xy"
|
||||||
light.setX(x);
|
light.setX(x);
|
||||||
@ -233,10 +216,6 @@ void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat) {
|
|||||||
s.add8(sat);
|
s.add8(sat);
|
||||||
s.add16(0);
|
s.add16(0);
|
||||||
ZigbeeSendHue(shortaddr, 0x0300, 0x06, s);
|
ZigbeeSendHue(shortaddr, 0x0300, 0x06, s);
|
||||||
// char param[16];
|
|
||||||
// snprintf_P(param, sizeof(param), PSTR("%02X%02X0000"), hue8, sat);
|
|
||||||
// uint8_t colormode = 0; // "hs"
|
|
||||||
// zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x06, param);
|
|
||||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||||
light.setColorMode(0); // "hs"
|
light.setColorMode(0); // "hs"
|
||||||
light.setSat(sat);
|
light.setSat(sat);
|
||||||
|
@ -381,7 +381,6 @@ const char Z_strings[] PROGMEM =
|
|||||||
"ProductURL" "\x00"
|
"ProductURL" "\x00"
|
||||||
"QualityMeasure" "\x00"
|
"QualityMeasure" "\x00"
|
||||||
"RGB" "\x00"
|
"RGB" "\x00"
|
||||||
"RGBb" "\x00"
|
|
||||||
"RMSCurrent" "\x00"
|
"RMSCurrent" "\x00"
|
||||||
"RMSVoltage" "\x00"
|
"RMSVoltage" "\x00"
|
||||||
"ReactivePower" "\x00"
|
"ReactivePower" "\x00"
|
||||||
@ -474,6 +473,7 @@ const char Z_strings[] PROGMEM =
|
|||||||
"ZoneStatus" "\x00"
|
"ZoneStatus" "\x00"
|
||||||
"ZoneStatusChange" "\x00"
|
"ZoneStatusChange" "\x00"
|
||||||
"ZoneType" "\x00"
|
"ZoneType" "\x00"
|
||||||
|
"_" "\x00"
|
||||||
"xx" "\x00"
|
"xx" "\x00"
|
||||||
"xx000A00" "\x00"
|
"xx000A00" "\x00"
|
||||||
"xx0A" "\x00"
|
"xx0A" "\x00"
|
||||||
@ -805,121 +805,121 @@ enum Z_offsets {
|
|||||||
Zo_ProductURL = 4956,
|
Zo_ProductURL = 4956,
|
||||||
Zo_QualityMeasure = 4967,
|
Zo_QualityMeasure = 4967,
|
||||||
Zo_RGB = 4982,
|
Zo_RGB = 4982,
|
||||||
Zo_RGBb = 4986,
|
Zo_RMSCurrent = 4986,
|
||||||
Zo_RMSCurrent = 4991,
|
Zo_RMSVoltage = 4997,
|
||||||
Zo_RMSVoltage = 5002,
|
Zo_ReactivePower = 5008,
|
||||||
Zo_ReactivePower = 5013,
|
Zo_RecallScene = 5022,
|
||||||
Zo_RecallScene = 5027,
|
Zo_RemainingTime = 5034,
|
||||||
Zo_RemainingTime = 5039,
|
Zo_RemoteSensing = 5048,
|
||||||
Zo_RemoteSensing = 5053,
|
Zo_RemoveAllGroups = 5062,
|
||||||
Zo_RemoveAllGroups = 5067,
|
Zo_RemoveAllScenes = 5078,
|
||||||
Zo_RemoveAllScenes = 5083,
|
Zo_RemoveGroup = 5094,
|
||||||
Zo_RemoveGroup = 5099,
|
Zo_RemoveScene = 5106,
|
||||||
Zo_RemoveScene = 5111,
|
Zo_ResetAlarm = 5118,
|
||||||
Zo_ResetAlarm = 5123,
|
Zo_ResetAllAlarms = 5129,
|
||||||
Zo_ResetAllAlarms = 5134,
|
Zo_SWBuildID = 5144,
|
||||||
Zo_SWBuildID = 5149,
|
Zo_Sat = 5154,
|
||||||
Zo_Sat = 5159,
|
Zo_SatMove = 5158,
|
||||||
Zo_SatMove = 5163,
|
Zo_SatStep = 5166,
|
||||||
Zo_SatStep = 5171,
|
Zo_SceneCount = 5174,
|
||||||
Zo_SceneCount = 5179,
|
Zo_SceneValid = 5185,
|
||||||
Zo_SceneValid = 5190,
|
Zo_ScheduleMode = 5196,
|
||||||
Zo_ScheduleMode = 5201,
|
Zo_SeaPressure = 5209,
|
||||||
Zo_SeaPressure = 5214,
|
Zo_ShortPollInterval = 5221,
|
||||||
Zo_ShortPollInterval = 5226,
|
Zo_Shutter = 5239,
|
||||||
Zo_Shutter = 5244,
|
Zo_ShutterClose = 5247,
|
||||||
Zo_ShutterClose = 5252,
|
Zo_ShutterLift = 5260,
|
||||||
Zo_ShutterLift = 5265,
|
Zo_ShutterOpen = 5272,
|
||||||
Zo_ShutterOpen = 5277,
|
Zo_ShutterStop = 5284,
|
||||||
Zo_ShutterStop = 5289,
|
Zo_ShutterTilt = 5296,
|
||||||
Zo_ShutterTilt = 5301,
|
Zo_SoftwareRevision = 5308,
|
||||||
Zo_SoftwareRevision = 5313,
|
Zo_StackVersion = 5325,
|
||||||
Zo_StackVersion = 5330,
|
Zo_StandardTime = 5338,
|
||||||
Zo_StandardTime = 5343,
|
Zo_StartUpOnOff = 5351,
|
||||||
Zo_StartUpOnOff = 5356,
|
Zo_Status = 5364,
|
||||||
Zo_Status = 5369,
|
Zo_StoreScene = 5371,
|
||||||
Zo_StoreScene = 5376,
|
Zo_SwitchType = 5382,
|
||||||
Zo_SwitchType = 5387,
|
Zo_SystemMode = 5393,
|
||||||
Zo_SystemMode = 5398,
|
Zo_TRVBoost = 5404,
|
||||||
Zo_TRVBoost = 5409,
|
Zo_TRVChildProtection = 5413,
|
||||||
Zo_TRVChildProtection = 5418,
|
Zo_TRVMirrorDisplay = 5432,
|
||||||
Zo_TRVMirrorDisplay = 5437,
|
Zo_TRVMode = 5449,
|
||||||
Zo_TRVMode = 5454,
|
Zo_TRVWindowOpen = 5457,
|
||||||
Zo_TRVWindowOpen = 5462,
|
Zo_TempTarget = 5471,
|
||||||
Zo_TempTarget = 5476,
|
Zo_Temperature = 5482,
|
||||||
Zo_Temperature = 5487,
|
Zo_TemperatureMaxMeasuredValue = 5494,
|
||||||
Zo_TemperatureMaxMeasuredValue = 5499,
|
Zo_TemperatureMinMeasuredValue = 5522,
|
||||||
Zo_TemperatureMinMeasuredValue = 5527,
|
Zo_TemperatureTolerance = 5550,
|
||||||
Zo_TemperatureTolerance = 5555,
|
Zo_TerncyDuration = 5571,
|
||||||
Zo_TerncyDuration = 5576,
|
Zo_TerncyRotate = 5586,
|
||||||
Zo_TerncyRotate = 5591,
|
Zo_ThSetpoint = 5599,
|
||||||
Zo_ThSetpoint = 5604,
|
Zo_Time = 5610,
|
||||||
Zo_Time = 5615,
|
Zo_TimeEpoch = 5615,
|
||||||
Zo_TimeEpoch = 5620,
|
Zo_TimeStatus = 5625,
|
||||||
Zo_TimeStatus = 5630,
|
Zo_TimeZone = 5636,
|
||||||
Zo_TimeZone = 5641,
|
Zo_TotalProfileNum = 5645,
|
||||||
Zo_TotalProfileNum = 5650,
|
Zo_TuyaAutoLock = 5661,
|
||||||
Zo_TuyaAutoLock = 5666,
|
Zo_TuyaAwayDays = 5674,
|
||||||
Zo_TuyaAwayDays = 5679,
|
Zo_TuyaAwayTemp = 5687,
|
||||||
Zo_TuyaAwayTemp = 5692,
|
Zo_TuyaBattery = 5700,
|
||||||
Zo_TuyaBattery = 5705,
|
Zo_TuyaBoostTime = 5712,
|
||||||
Zo_TuyaBoostTime = 5717,
|
Zo_TuyaChildLock = 5726,
|
||||||
Zo_TuyaChildLock = 5731,
|
Zo_TuyaComfortTemp = 5740,
|
||||||
Zo_TuyaComfortTemp = 5745,
|
Zo_TuyaEcoTemp = 5756,
|
||||||
Zo_TuyaEcoTemp = 5761,
|
Zo_TuyaFanMode = 5768,
|
||||||
Zo_TuyaFanMode = 5773,
|
Zo_TuyaForceMode = 5780,
|
||||||
Zo_TuyaForceMode = 5785,
|
Zo_TuyaMaxTemp = 5794,
|
||||||
Zo_TuyaMaxTemp = 5799,
|
Zo_TuyaMinTemp = 5806,
|
||||||
Zo_TuyaMinTemp = 5811,
|
Zo_TuyaPreset = 5818,
|
||||||
Zo_TuyaPreset = 5823,
|
Zo_TuyaScheduleHolidays = 5829,
|
||||||
Zo_TuyaScheduleHolidays = 5834,
|
Zo_TuyaScheduleWorkdays = 5850,
|
||||||
Zo_TuyaScheduleWorkdays = 5855,
|
Zo_TuyaTempTarget = 5871,
|
||||||
Zo_TuyaTempTarget = 5876,
|
Zo_TuyaValveDetection = 5886,
|
||||||
Zo_TuyaValveDetection = 5891,
|
Zo_TuyaValvePosition = 5905,
|
||||||
Zo_TuyaValvePosition = 5910,
|
Zo_TuyaWeekSelect = 5923,
|
||||||
Zo_TuyaWeekSelect = 5928,
|
Zo_TuyaWindowDetection = 5938,
|
||||||
Zo_TuyaWindowDetection = 5943,
|
Zo_UnoccupiedCoolingSetpoint = 5958,
|
||||||
Zo_UnoccupiedCoolingSetpoint = 5963,
|
Zo_UnoccupiedHeatingSetpoint = 5984,
|
||||||
Zo_UnoccupiedHeatingSetpoint = 5989,
|
Zo_UtilityName = 6010,
|
||||||
Zo_UtilityName = 6015,
|
Zo_ValidUntilTime = 6022,
|
||||||
Zo_ValidUntilTime = 6027,
|
Zo_ValvePosition = 6037,
|
||||||
Zo_ValvePosition = 6042,
|
Zo_VelocityLift = 6051,
|
||||||
Zo_VelocityLift = 6056,
|
Zo_ViewGroup = 6064,
|
||||||
Zo_ViewGroup = 6069,
|
Zo_ViewScene = 6074,
|
||||||
Zo_ViewScene = 6079,
|
Zo_Water = 6084,
|
||||||
Zo_Water = 6089,
|
Zo_WhitePointX = 6090,
|
||||||
Zo_WhitePointX = 6095,
|
Zo_WhitePointY = 6102,
|
||||||
Zo_WhitePointY = 6107,
|
Zo_WindowCoveringType = 6114,
|
||||||
Zo_WindowCoveringType = 6119,
|
Zo_X = 6133,
|
||||||
Zo_X = 6138,
|
Zo_Y = 6135,
|
||||||
Zo_Y = 6140,
|
Zo_ZCLVersion = 6137,
|
||||||
Zo_ZCLVersion = 6142,
|
Zo_ZoneState = 6148,
|
||||||
Zo_ZoneState = 6153,
|
Zo_ZoneStatus = 6158,
|
||||||
Zo_ZoneStatus = 6163,
|
Zo_ZoneStatusChange = 6169,
|
||||||
Zo_ZoneStatusChange = 6174,
|
Zo_ZoneType = 6186,
|
||||||
Zo_ZoneType = 6191,
|
Zo__ = 6195,
|
||||||
Zo_xx = 6200,
|
Zo_xx = 6197,
|
||||||
Zo_xx000A00 = 6203,
|
Zo_xx000A00 = 6200,
|
||||||
Zo_xx0A = 6212,
|
Zo_xx0A = 6209,
|
||||||
Zo_xx0A00 = 6217,
|
Zo_xx0A00 = 6214,
|
||||||
Zo_xx19 = 6224,
|
Zo_xx19 = 6221,
|
||||||
Zo_xx190A = 6229,
|
Zo_xx190A = 6226,
|
||||||
Zo_xx190A00 = 6236,
|
Zo_xx190A00 = 6233,
|
||||||
Zo_xxxx = 6245,
|
Zo_xxxx = 6242,
|
||||||
Zo_xxxx00 = 6250,
|
Zo_xxxx00 = 6247,
|
||||||
Zo_xxxx0A00 = 6257,
|
Zo_xxxx0A00 = 6254,
|
||||||
Zo_xxxxyy = 6266,
|
Zo_xxxxyy = 6263,
|
||||||
Zo_xxxxyyyy = 6273,
|
Zo_xxxxyyyy = 6270,
|
||||||
Zo_xxxxyyyy0A00 = 6282,
|
Zo_xxxxyyyy0A00 = 6279,
|
||||||
Zo_xxxxyyzz = 6295,
|
Zo_xxxxyyzz = 6292,
|
||||||
Zo_xxyy = 6304,
|
Zo_xxyy = 6301,
|
||||||
Zo_xxyy0A00 = 6309,
|
Zo_xxyy0A00 = 6306,
|
||||||
Zo_xxyyyy = 6318,
|
Zo_xxyyyy = 6315,
|
||||||
Zo_xxyyyy000000000000 = 6325,
|
Zo_xxyyyy000000000000 = 6322,
|
||||||
Zo_xxyyyy0A0000000000 = 6344,
|
Zo_xxyyyy0A0000000000 = 6341,
|
||||||
Zo_xxyyyyzz = 6363,
|
Zo_xxyyyyzz = 6360,
|
||||||
Zo_xxyyyyzzzz = 6372,
|
Zo_xxyyyyzzzz = 6369,
|
||||||
Zo_xxyyzzzz = 6383,
|
Zo_xxyyzzzz = 6380,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1209,23 +1209,19 @@ void ZCLFrame::parseReportAttributes(Z_attribute_list& attr_list) {
|
|||||||
// The sensor expects the coordinator to send a Default Response to acknowledge the attribute reporting
|
// The sensor expects the coordinator to send a Default Response to acknowledge the attribute reporting
|
||||||
if (0 == _frame_control.b.disable_def_resp) {
|
if (0 == _frame_control.b.disable_def_resp) {
|
||||||
// the device expects a default response
|
// the device expects a default response
|
||||||
SBuffer buf(2);
|
ZCLMessage zcl(2); // message is 2 bytes
|
||||||
buf.add8(_cmd_id);
|
zcl.shortaddr = _srcaddr;
|
||||||
buf.add8(0x00); // Status = OK
|
zcl.cluster = _cluster_id;
|
||||||
|
zcl.endpoint = _srcendpoint;
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
||||||
_srcaddr,
|
zcl.manuf = _manuf_code;
|
||||||
0x0000,
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
_cluster_id,
|
zcl.needResponse = false; /* noresponse */
|
||||||
_srcendpoint,
|
zcl.direct = true; /* direct no retry */
|
||||||
ZCL_DEFAULT_RESPONSE,
|
zcl.setTransac(_transact_seq);
|
||||||
_manuf_code,
|
zcl.buf.add8(_cmd_id);
|
||||||
false /* not cluster specific */,
|
zcl.buf.add8(0); // Status = OK
|
||||||
false /* noresponse */,
|
zigbeeZCLSendCmd(zcl);
|
||||||
true /* direct no retry */,
|
|
||||||
_transact_seq, /* zcl transaction id */
|
|
||||||
buf.getBuffer(), buf.len()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1674,23 +1670,19 @@ void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) {
|
|||||||
// Send Default Response to acknowledge the attribute reporting
|
// Send Default Response to acknowledge the attribute reporting
|
||||||
if (0 == _frame_control.b.disable_def_resp) {
|
if (0 == _frame_control.b.disable_def_resp) {
|
||||||
// the device expects a default response
|
// the device expects a default response
|
||||||
SBuffer buf(2);
|
ZCLMessage zcl(2); // message is 4 bytes
|
||||||
buf.add8(_cmd_id);
|
zcl.shortaddr = _srcaddr;
|
||||||
buf.add8(0x00); // Status = OK
|
zcl.cluster = _cluster_id;
|
||||||
|
zcl.endpoint = _srcendpoint;
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
||||||
_srcaddr,
|
zcl.manuf = _manuf_code;
|
||||||
0x0000,
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
_cluster_id,
|
zcl.needResponse = false; /* noresponse */
|
||||||
_srcendpoint,
|
zcl.direct = true; /* direct no retry */
|
||||||
ZCL_DEFAULT_RESPONSE,
|
zcl.setTransac(_transact_seq);
|
||||||
_manuf_code,
|
zcl.buf.add8(_cmd_id);
|
||||||
false /* not cluster specific */,
|
zcl.buf.add8(0x00); // Status = OK
|
||||||
false /* noresponse */,
|
zigbeeZCLSendCmd(zcl);
|
||||||
true /* direct no retry */,
|
|
||||||
_transact_seq, /* zcl transaction id */
|
|
||||||
buf.getBuffer(), buf.len()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ typedef struct Z_XYZ_Var { // Holds values for vairables X, Y and Z
|
|||||||
// - cluster: cluster number of the command
|
// - cluster: cluster number of the command
|
||||||
// - cmd: the command number, of 0xFF if it's actually a variable to be assigned from 'xx'
|
// - cmd: the command number, of 0xFF if it's actually a variable to be assigned from 'xx'
|
||||||
// - direction: the direction of the command (bit field). 0x01=from client to server (coord to device), 0x02= from server to client (response), 0x80=needs specific decoding
|
// - direction: the direction of the command (bit field). 0x01=from client to server (coord to device), 0x02= from server to client (response), 0x80=needs specific decoding
|
||||||
// - param: the paylod template, x/y/z are substituted with arguments, little endian. For command display, payload must match until x/y/z character or until the end of the paylod. '??' means ignore.
|
// - param: the paylod template, x/y/z are substituted with arguments, little endian. For command display, payload must match until x/y/z character or until the end of the paylod. '_' means custom converter.
|
||||||
const Z_CommandConverter Z_Commands[] PROGMEM = {
|
const Z_CommandConverter Z_Commands[] PROGMEM = {
|
||||||
// Identify cluster
|
// Identify cluster
|
||||||
{ Z_(Identify), 0x0003, 0x00, 0x01, Z_(xxxx) }, // Identify device, time in seconds
|
{ Z_(Identify), 0x0003, 0x00, 0x01, Z_(xxxx) }, // Identify device, time in seconds
|
||||||
@ -82,7 +82,7 @@ const Z_CommandConverter Z_Commands[] PROGMEM = {
|
|||||||
{ Z_(HueSat), 0x0300, 0x06, 0x01, Z_(xxyy0A00) }, // Hue, Sat
|
{ Z_(HueSat), 0x0300, 0x06, 0x01, Z_(xxyy0A00) }, // Hue, Sat
|
||||||
{ Z_(Color), 0x0300, 0x07, 0x01, Z_(xxxxyyyy0A00) }, // x, y (uint16)
|
{ Z_(Color), 0x0300, 0x07, 0x01, Z_(xxxxyyyy0A00) }, // x, y (uint16)
|
||||||
{ Z_(CT), 0x0300, 0x0A, 0x01, Z_(xxxx0A00) }, // Color Temperature Mireds (uint16)
|
{ Z_(CT), 0x0300, 0x0A, 0x01, Z_(xxxx0A00) }, // Color Temperature Mireds (uint16)
|
||||||
{ Z_(RGB), 0x0300, 0xF0, 0x81, Z_() }, // synthetic commands converting RGB to XY
|
{ Z_(RGB), 0x0300, 0xF0, 0x81, Z_(_) }, // synthetic commands converting RGB to XY
|
||||||
{ Z_(ShutterOpen), 0x0102, 0x00, 0x01, Z_() },
|
{ Z_(ShutterOpen), 0x0102, 0x00, 0x01, Z_() },
|
||||||
{ Z_(ShutterClose), 0x0102, 0x01, 0x01, Z_() },
|
{ Z_(ShutterClose), 0x0102, 0x01, 0x01, Z_() },
|
||||||
{ Z_(ShutterStop), 0x0102, 0x02, 0x01, Z_() },
|
{ Z_(ShutterStop), 0x0102, 0x02, 0x01, Z_() },
|
||||||
@ -180,20 +180,18 @@ void Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster
|
|||||||
if (groupaddr) {
|
if (groupaddr) {
|
||||||
shortaddr = BAD_SHORTADDR; // if group address, don't send to device
|
shortaddr = BAD_SHORTADDR; // if group address, don't send to device
|
||||||
}
|
}
|
||||||
uint8_t seq = zigbee_devices.getNextSeqNumber(shortaddr);
|
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
ZCLMessage zcl(attrs_len); // message is `attrs_len` bytes
|
||||||
shortaddr,
|
zcl.shortaddr = shortaddr;
|
||||||
groupaddr,
|
zcl.groupaddr = groupaddr;
|
||||||
cluster /*cluster*/,
|
zcl.cluster = cluster;
|
||||||
endpoint,
|
zcl.endpoint = endpoint;
|
||||||
ZCL_READ_ATTRIBUTES,
|
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||||
0, /* manuf */
|
zcl.clusterSpecific = false;
|
||||||
false /* not cluster specific */,
|
zcl.needResponse = true;
|
||||||
true /* response */,
|
zcl.direct = false; // discover route
|
||||||
false /* discover route */,
|
zcl.buf.addBuffer(attrs, attrs_len);
|
||||||
seq, /* zcl transaction id */
|
zigbeeZCLSendCmd(zcl);
|
||||||
attrs, attrs_len
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,17 +533,19 @@ bool convertTuyaSpecificCluster(class Z_attribute_list &attr_list, uint16_t clus
|
|||||||
// Only take commands outgoing, i.e. direction == 0
|
// Only take commands outgoing, i.e. direction == 0
|
||||||
// If not found:
|
// If not found:
|
||||||
// - returns nullptr
|
// - returns nullptr
|
||||||
const __FlashStringHelper* zigbeeFindCommand(const char *command, uint16_t *cluster, uint16_t *cmd) {
|
// - return PROGMEM string
|
||||||
|
const char * zigbeeFindCommand(const char *command, uint16_t *cluster, uint16_t *cmd) {
|
||||||
if (nullptr == command) { return nullptr; }
|
if (nullptr == command) { return nullptr; }
|
||||||
for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) {
|
for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) {
|
||||||
const Z_CommandConverter *conv = &Z_Commands[i];
|
const Z_CommandConverter *conv = &Z_Commands[i];
|
||||||
uint8_t conv_direction = pgm_read_byte(&conv->direction);
|
uint8_t conv_direction = pgm_read_byte(&conv->direction);
|
||||||
uint8_t conv_cmd = pgm_read_byte(&conv->cmd);
|
uint8_t conv_cmd = pgm_read_byte(&conv->cmd);
|
||||||
uint16_t conv_cluster = pgm_read_word(&conv->cluster);
|
uint16_t conv_cluster = pgm_read_word(&conv->cluster);
|
||||||
|
// conv_direction must be client (coord) -> server (device), we can only send commands to end devices
|
||||||
if ((conv_direction & 0x01) && (0 == strcasecmp_P(command, Z_strings + pgm_read_word(&conv->tasmota_cmd_offset)))) {
|
if ((conv_direction & 0x01) && (0 == strcasecmp_P(command, Z_strings + pgm_read_word(&conv->tasmota_cmd_offset)))) {
|
||||||
*cluster = conv_cluster;
|
*cluster = conv_cluster;
|
||||||
*cmd = conv_cmd;
|
*cmd = conv_cmd;
|
||||||
return (const __FlashStringHelper*) (Z_strings + pgm_read_word(&conv->param_offset));
|
return Z_strings + pgm_read_word(&conv->param_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,16 +559,17 @@ inline char hexDigit(uint32_t h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// replace all xx/yy/zz substrings with unsigned ints, and the corresponding len (8, 16 or 32 bits)
|
// replace all xx/yy/zz substrings with unsigned ints, and the corresponding len (8, 16 or 32 bits)
|
||||||
String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z) {
|
// Returns a SBuffer allocated object, it is the caller's responsibility to delete it
|
||||||
size_t len = strlen_P(zcl_cmd_P);
|
void zigbeeCmdAddParams(SBuffer & buf, const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z) {
|
||||||
char zcl_cmd[len+1];
|
size_t hex_len = strlen_P(zcl_cmd_P);
|
||||||
strcpy_P(zcl_cmd, zcl_cmd_P); // copy into RAM
|
buf.reserve((hex_len + 1)/2);
|
||||||
|
|
||||||
char *p = zcl_cmd;
|
const char * p = zcl_cmd_P;
|
||||||
while (*p) {
|
char c0, c1;
|
||||||
if (isXYZ(*p) && (*p == *(p+1))) { // if char is [x-z] and followed by same char
|
while ((c0 = pgm_read_byte(p)) && (c1 = pgm_read_byte(p+1))) {
|
||||||
|
if (isXYZ(c0) && (c0 == c1)) { // if char is [x-z] and followed by same char
|
||||||
uint8_t val = 0;
|
uint8_t val = 0;
|
||||||
switch (*p) {
|
switch (pgm_read_byte(p)) {
|
||||||
case 'x':
|
case 'x':
|
||||||
val = x & 0xFF;
|
val = x & 0xFF;
|
||||||
x = x >> 8;
|
x = x >> 8;
|
||||||
@ -582,15 +583,18 @@ String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_
|
|||||||
z = z >> 8;
|
z = z >> 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*p = hexDigit(val >> 4);
|
buf.add8(val);
|
||||||
*(p+1) = hexDigit(val);
|
// *p = hexDigit(val >> 4);
|
||||||
p++;
|
// *(p+1) = hexDigit(val);
|
||||||
|
} else {
|
||||||
|
char hex[4];
|
||||||
|
hex[0] = c0;
|
||||||
|
hex[1] = c1;
|
||||||
|
hex[2] = 0;
|
||||||
|
buf.add8(strtoul(hex, nullptr, 16) & 0xFF);
|
||||||
}
|
}
|
||||||
p++;
|
p += 2;
|
||||||
}
|
}
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SendZCLCommand_P: zcl_cmd = %s"), zcl_cmd);
|
|
||||||
|
|
||||||
return String(zcl_cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char kZ_Alias[] PROGMEM = "OFF|" D_OFF "|" D_FALSE "|" D_STOP "|" "OPEN" "|" // 0
|
const char kZ_Alias[] PROGMEM = "OFF|" D_OFF "|" D_FALSE "|" D_STOP "|" "OPEN" "|" // 0
|
||||||
|
@ -1319,78 +1319,55 @@ void Z_SendSimpleDescReq(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluste
|
|||||||
//
|
//
|
||||||
// Send AF Info Request
|
// Send AF Info Request
|
||||||
// Queue requests for the device
|
// Queue requests for the device
|
||||||
// 1. Request for 'ModelId' and 'Manufacturer': 0000/0005, 0000/0006
|
// 1. Request for 'ModelId' and 'Manufacturer': 0000/0005, 0000/0004
|
||||||
// 2. Auto-bind to coordinator:
|
// 2. Auto-bind to coordinator:
|
||||||
// Iterate among
|
// Iterate among
|
||||||
//
|
//
|
||||||
void Z_SendDeviceInfoRequest(uint16_t shortaddr) {
|
void Z_SendDeviceInfoRequest(uint16_t shortaddr) {
|
||||||
uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
ZCLMessage zcl(4); // message is 4 bytes
|
||||||
if (0x00 == endpoint) { endpoint = 0x01; } // if we don't know the endpoint, try 0x01
|
zcl.shortaddr = shortaddr;
|
||||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
zcl.cluster = 0;
|
||||||
|
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||||
uint8_t InfoReq[] = { 0x04, 0x00, 0x05, 0x00 };
|
zcl.clusterSpecific = false;
|
||||||
|
zcl.needResponse = true;
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
zcl.direct = false; // discover route
|
||||||
shortaddr,
|
zcl.buf.add16(0x0005);
|
||||||
0x0000, /* group */
|
zcl.buf.add16(0x0004);
|
||||||
0x0000 /*cluster*/,
|
zigbeeZCLSendCmd(zcl);
|
||||||
endpoint,
|
|
||||||
ZCL_READ_ATTRIBUTES,
|
|
||||||
0x0000, /* manuf */
|
|
||||||
false /* not cluster specific */,
|
|
||||||
true /* response */,
|
|
||||||
false /* discover route */,
|
|
||||||
transacid, /* zcl transaction id */
|
|
||||||
InfoReq, sizeof(InfoReq)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Send single attribute read request in Timer
|
// Send single attribute read request in Timer
|
||||||
//
|
//
|
||||||
void Z_SendSingleAttributeRead(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
void Z_SendSingleAttributeRead(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
||||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
ZCLMessage zcl(2); // message is 2 bytes
|
||||||
uint8_t InfoReq[2] = { Z_B0(value), Z_B1(value) }; // list of single attribute
|
zcl.shortaddr = shortaddr;
|
||||||
|
zcl.cluster = cluster;
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
zcl.endpoint = endpoint;
|
||||||
shortaddr,
|
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||||
0x0000, /* group */
|
zcl.clusterSpecific = false;
|
||||||
cluster /*cluster*/,
|
zcl.needResponse = true;
|
||||||
endpoint,
|
zcl.direct = false; // discover route
|
||||||
ZCL_READ_ATTRIBUTES,
|
zcl.buf.add16(value); // 04000500
|
||||||
0x0000, /* manuf */
|
zigbeeZCLSendCmd(zcl);
|
||||||
false /* not cluster specific */,
|
|
||||||
true /* response */,
|
|
||||||
false /* discover route */,
|
|
||||||
transacid, /* zcl transaction id */
|
|
||||||
InfoReq, sizeof(InfoReq)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Write CIE address
|
// Write CIE address
|
||||||
//
|
//
|
||||||
void Z_WriteCIEAddress(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
void Z_WriteCIEAddress(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
||||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
ZCLMessage zcl(12); // message is 12 bytes
|
||||||
SBuffer buf(12);
|
zcl.shortaddr = shortaddr;
|
||||||
buf.add16(0x0010); // attribute 0x0010
|
zcl.cluster = 0x0500;
|
||||||
buf.add8(ZEUI64);
|
zcl.endpoint = endpoint;
|
||||||
buf.add64(localIEEEAddr);
|
zcl.cmd = ZCL_WRITE_ATTRIBUTES;
|
||||||
|
zcl.clusterSpecific = false;
|
||||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Writing CIE address"));
|
zcl.needResponse = true;
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
zcl.direct = false; // discover route
|
||||||
shortaddr,
|
zcl.buf.add16(0x0010); // attribute 0x0010
|
||||||
0x0000, /* group */
|
zcl.buf.add8(ZEUI64);
|
||||||
0x0500 /*cluster*/,
|
zcl.buf.add64(localIEEEAddr);
|
||||||
endpoint,
|
zigbeeZCLSendCmd(zcl);
|
||||||
ZCL_WRITE_ATTRIBUTES,
|
|
||||||
0x0000, /* manuf */
|
|
||||||
false /* not cluster specific */,
|
|
||||||
true /* response */,
|
|
||||||
false /* discover route */,
|
|
||||||
transacid, /* zcl transaction id */
|
|
||||||
buf.getBuffer(), buf.len()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1398,23 +1375,18 @@ void Z_WriteCIEAddress(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster,
|
|||||||
// Write CIE address
|
// Write CIE address
|
||||||
//
|
//
|
||||||
void Z_SendCIEZoneEnrollResponse(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
void Z_SendCIEZoneEnrollResponse(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
||||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
|
||||||
uint8_t EnrollRSP[2] = { 0x00 /* Sucess */, Z_B0(value) /* ZoneID */ };
|
|
||||||
|
|
||||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Sending Enroll Zone %d"), Z_B0(value));
|
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Sending Enroll Zone %d"), Z_B0(value));
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
ZCLMessage zcl(2); // message is 2 bytes
|
||||||
shortaddr,
|
zcl.shortaddr = shortaddr;
|
||||||
0x0000, /* group */
|
zcl.cluster = 0x0500;
|
||||||
0x0500 /*cluster*/,
|
zcl.endpoint = endpoint;
|
||||||
endpoint,
|
zcl.cmd = 0x00, // Zone Enroll Response
|
||||||
0x00, // Zone Enroll Response
|
zcl.clusterSpecific = true;
|
||||||
0x0000, /* manuf */
|
zcl.needResponse = true;
|
||||||
true /* cluster specific */,
|
zcl.direct = false; // discover route
|
||||||
true /* response */,
|
zcl.buf.add8(0x00); // success
|
||||||
false /* discover route */,
|
zcl.buf.add8(Z_B0(value)); // ZoneID
|
||||||
transacid, /* zcl transaction id */
|
zigbeeZCLSendCmd(zcl);
|
||||||
EnrollRSP, sizeof(EnrollRSP)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1549,19 +1521,16 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin
|
|||||||
|
|
||||||
if (buf.len() > 0) {
|
if (buf.len() > 0) {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "auto-bind `%s`"), TasmotaGlobal.mqtt_data);
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "auto-bind `%s`"), TasmotaGlobal.mqtt_data);
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
ZCLMessage zcl(buf.len()); // message is 4 bytes
|
||||||
shortaddr,
|
zcl.shortaddr = shortaddr;
|
||||||
0x0000, /* group */
|
zcl.cluster = cluster;
|
||||||
cluster /*cluster*/,
|
zcl.endpoint = endpoint;
|
||||||
endpoint,
|
zcl.cmd = ZCL_CONFIGURE_REPORTING;
|
||||||
ZCL_CONFIGURE_REPORTING,
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
0x0000, /* manuf */
|
zcl.needResponse = false; /* noresponse */
|
||||||
false /* not cluster specific */,
|
zcl.direct = false; /* discover route */
|
||||||
false /* no response */,
|
zcl.buf.addBuffer(buf);
|
||||||
false /* discover route */,
|
zigbeeZCLSendCmd(zcl);
|
||||||
zigbee_devices.getNextSeqNumber(shortaddr), /* zcl transaction id */
|
|
||||||
buf.buf(), buf.len()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2149,19 +2118,17 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
|
|||||||
|
|
||||||
// send
|
// send
|
||||||
// all good, send the packet
|
// all good, send the packet
|
||||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
ZCLMessage zcl(buf.len()); // message is 4 bytes
|
||||||
_srcaddr,
|
zcl.shortaddr = _srcaddr;
|
||||||
0x0000,
|
zcl.cluster = _cluster_id;
|
||||||
_cluster_id /*cluster*/,
|
zcl.endpoint = _srcendpoint;
|
||||||
_srcendpoint,
|
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
||||||
ZCL_READ_ATTRIBUTES_RESPONSE,
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
0x0000, /* manuf */
|
zcl.needResponse = false; /* noresponse */
|
||||||
false /* not cluster specific */,
|
zcl.direct = true; /* direct response */
|
||||||
false /* no response */,
|
zcl.setTransac(_transact_seq);
|
||||||
true /* direct response */,
|
zcl.buf.addBuffer(buf);
|
||||||
_transact_seq, /* zcl transaction id */
|
zigbeeZCLSendCmd(zcl);
|
||||||
buf.getBuffer(), buf.len()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,16 +748,17 @@ void CmndZbEZSPSend(void)
|
|||||||
// - msg: pointer to byte array, payload of ZCL message (len is following), ignored if nullptr
|
// - msg: pointer to byte array, payload of ZCL message (len is following), ignored if nullptr
|
||||||
// - len: length of the 'msg' payload
|
// - len: length of the 'msg' payload
|
||||||
// - needResponse: boolean, true = we ask the target to respond, false = the target should not respond
|
// - 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
|
// - transac: 8-bits, transation id of message (should be incremented at each message), used both for Zigbee message number and ZCL message number
|
||||||
// Returns: None
|
// Returns: None
|
||||||
//
|
//
|
||||||
void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
|
|
||||||
|
void ZigbeeZCLSend_Raw(const ZCLMessage &zcl) {
|
||||||
|
SBuffer buf(32+zcl.buf.len());
|
||||||
|
|
||||||
#ifdef USE_ZIGBEE_ZNP
|
#ifdef USE_ZIGBEE_ZNP
|
||||||
SBuffer buf(32+zcl.len);
|
|
||||||
buf.add8(Z_SREQ | Z_AF); // 24
|
buf.add8(Z_SREQ | Z_AF); // 24
|
||||||
buf.add8(AF_DATA_REQUEST_EXT); // 02
|
buf.add8(AF_DATA_REQUEST_EXT); // 02
|
||||||
if (BAD_SHORTADDR == zcl.shortaddr) { // if no shortaddr we assume group address
|
if (!zcl.validShortaddr()) { // if no shortaddr we assume group address
|
||||||
buf.add8(Z_Addr_Group); // 01
|
buf.add8(Z_Addr_Group); // 01
|
||||||
buf.add64(zcl.groupaddr); // group address, only 2 LSB, upper 6 MSB are discarded
|
buf.add64(zcl.groupaddr); // group address, only 2 LSB, upper 6 MSB are discarded
|
||||||
buf.add8(0xFF); // dest endpoint is not used for group addresses
|
buf.add8(0xFF); // dest endpoint is not used for group addresses
|
||||||
@ -769,28 +770,24 @@ void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
|
|||||||
buf.add16(0x0000); // dest Pan ID, 0x0000 = intra-pan
|
buf.add16(0x0000); // dest Pan ID, 0x0000 = intra-pan
|
||||||
buf.add8(0x01); // source endpoint
|
buf.add8(0x01); // source endpoint
|
||||||
buf.add16(zcl.cluster);
|
buf.add16(zcl.cluster);
|
||||||
buf.add8(zcl.transacId); // transacId
|
buf.add8(zcl.transac); // transac
|
||||||
buf.add8(0x30); // 30 options
|
buf.add8(0x30); // 30 options
|
||||||
buf.add8(0x1E); // 1E radius
|
buf.add8(0x1E); // 1E radius
|
||||||
|
|
||||||
buf.add16(3 + zcl.len + (zcl.manuf ? 2 : 0));
|
buf.add16(3 + zcl.buf.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)); // 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
|
||||||
}
|
}
|
||||||
buf.add8(zcl.transacId); // Transaction Sequence Number
|
buf.add8(zcl.transac); // Transaction Sequence Number
|
||||||
buf.add8(zcl.cmd);
|
buf.add8(zcl.cmd);
|
||||||
if (zcl.len > 0) {
|
buf.addBuffer(zcl.buf);
|
||||||
buf.addBuffer(zcl.msg, zcl.len); // add the payload
|
|
||||||
}
|
|
||||||
|
|
||||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||||
#endif // USE_ZIGBEE_ZNP
|
#endif // USE_ZIGBEE_ZNP
|
||||||
|
|
||||||
#ifdef USE_ZIGBEE_EZSP
|
#ifdef USE_ZIGBEE_EZSP
|
||||||
SBuffer buf(32+zcl.len);
|
if (zcl.validShortaddr()) {
|
||||||
|
|
||||||
if (BAD_SHORTADDR != zcl.shortaddr) {
|
|
||||||
// send unicast message to an address
|
// send unicast message to an address
|
||||||
buf.add16(EZSP_sendUnicast); // 3400
|
buf.add16(EZSP_sendUnicast); // 3400
|
||||||
buf.add8(EMBER_OUTGOING_DIRECT); // 00
|
buf.add8(EMBER_OUTGOING_DIRECT); // 00
|
||||||
@ -806,20 +803,18 @@ void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
|
|||||||
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
||||||
}
|
}
|
||||||
buf.add16(zcl.groupaddr); // groupId
|
buf.add16(zcl.groupaddr); // groupId
|
||||||
buf.add8(zcl.transacId);
|
buf.add8(zcl.transac);
|
||||||
// end of ApsFrame
|
// end of ApsFrame
|
||||||
buf.add8(0x01); // tag TODO
|
buf.add8(0x01); // tag TODO
|
||||||
|
|
||||||
buf.add8(3 + zcl.len + (zcl.manuf ? 2 : 0));
|
buf.add8(3 + zcl.buf.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)); // 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
|
||||||
}
|
}
|
||||||
buf.add8(zcl.transacId); // Transaction Sequance Number
|
buf.add8(zcl.transac); // Transaction Sequance Number
|
||||||
buf.add8(zcl.cmd);
|
buf.add8(zcl.cmd);
|
||||||
if (zcl.len > 0) {
|
buf.addBuffer(zcl.buf);
|
||||||
buf.addBuffer(zcl.msg, zcl.len); // add the payload
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// send broadcast group address, aka groupcast
|
// send broadcast group address, aka groupcast
|
||||||
buf.add16(EZSP_sendMulticast); // 3800
|
buf.add16(EZSP_sendMulticast); // 3800
|
||||||
@ -834,22 +829,20 @@ void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
|
|||||||
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame
|
||||||
}
|
}
|
||||||
buf.add16(zcl.groupaddr); // groupId
|
buf.add16(zcl.groupaddr); // groupId
|
||||||
buf.add8(zcl.transacId);
|
buf.add8(zcl.transac);
|
||||||
// end of ApsFrame
|
// end of ApsFrame
|
||||||
buf.add8(0); // hops, 0x00 = EMBER_MAX_HOPS
|
buf.add8(0); // hops, 0x00 = EMBER_MAX_HOPS
|
||||||
buf.add8(7); // nonMemberRadius, 7 = infinite
|
buf.add8(7); // nonMemberRadius, 7 = infinite
|
||||||
buf.add8(0x01); // tag TODO
|
buf.add8(0x01); // tag TODO
|
||||||
|
|
||||||
buf.add8(3 + zcl.len + (zcl.manuf ? 2 : 0));
|
buf.add8(3 + zcl.buf.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)); // 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
|
||||||
}
|
}
|
||||||
buf.add8(zcl.transacId); // Transaction Sequance Number
|
buf.add8(zcl.transac); // Transaction Sequance Number
|
||||||
buf.add8(zcl.cmd);
|
buf.add8(zcl.cmd);
|
||||||
if (zcl.len > 0) {
|
buf.addBuffer(zcl.buf);
|
||||||
buf.addBuffer(zcl.msg, zcl.len); // add the payload
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeEZSPSendCmd(buf.buf(), buf.len());
|
ZigbeeEZSPSendCmd(buf.buf(), buf.len());
|
||||||
|
@ -179,59 +179,39 @@ void CmndZbReset(void) {
|
|||||||
// - param: pointer to HEX string for payload, should not be nullptr
|
// - param: pointer to HEX string for payload, should not be nullptr
|
||||||
// Returns: None
|
// Returns: None
|
||||||
//
|
//
|
||||||
void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, bool clusterSpecific, uint16_t manuf,
|
void zigbeeZCLSendCmd(class ZCLMessage &zcl) {
|
||||||
uint16_t cluster, uint8_t cmd, const char *param) {
|
if ((0 == zcl.endpoint) && (zcl.validShortaddr())) {
|
||||||
size_t size = param ? strlen(param) : 0;
|
|
||||||
SBuffer buf((size+2)/2); // actual bytes buffer for data
|
|
||||||
|
|
||||||
if (param) {
|
|
||||||
while (*param) {
|
|
||||||
uint8_t code = parseHex_P(¶m, 2);
|
|
||||||
buf.add8(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zigbeeZCLSendCmd(ZigbeeZCLSendMessage({
|
|
||||||
shortaddr,
|
|
||||||
groupaddr,
|
|
||||||
cluster /*cluster*/,
|
|
||||||
endpoint,
|
|
||||||
cmd,
|
|
||||||
manuf, /* manuf */
|
|
||||||
clusterSpecific /* not cluster specific */,
|
|
||||||
true /* response */,
|
|
||||||
false /* discover route */,
|
|
||||||
0, /* zcl transaction id */
|
|
||||||
buf.getBuffer(), buf.len()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void zigbeeZCLSendCmd(const class ZigbeeZCLSendMessage &msg_const) {
|
|
||||||
ZigbeeZCLSendMessage msg = msg_const; // copy to a modifiable variable
|
|
||||||
|
|
||||||
if ((0 == msg.endpoint) && (BAD_SHORTADDR != msg.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
|
||||||
msg.endpoint = zigbee_devices.findFirstEndpoint(msg.shortaddr);
|
zcl.endpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr);
|
||||||
|
if (0x00 == zcl.endpoint) { zcl.endpoint = 0x01; } // if we don't know the endpoint, try 0x01
|
||||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %*_H"),
|
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %_B"),
|
||||||
msg.shortaddr, msg.groupaddr, msg.cluster, msg.endpoint, msg.cmd, msg.len, msg.msg);
|
// zcl.shortaddr, zcl.groupaddr, zcl.cluster, zcl.endpoint, zcl.cmd, &zcl.buf);
|
||||||
|
|
||||||
if ((0 == msg.endpoint) && (BAD_SHORTADDR != msg.shortaddr)) { // endpoint null is ok for group address
|
if ((0 == zcl.endpoint) && (zcl.validShortaddr())) { // endpoint null is ok for group address
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
AddLog_P(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// everything is good, we can send the command
|
// everything is good, we can send the command
|
||||||
|
|
||||||
msg.transacId = zigbee_devices.getNextSeqNumber(msg.shortaddr);
|
if (!zcl.transacSet) {
|
||||||
ZigbeeZCLSend_Raw(msg);
|
zcl.transac = zigbee_devices.getNextSeqNumber(zcl.shortaddr);
|
||||||
|
zcl.transacSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZigbeeZCLSend device: 0x%04X, group: 0x%04X, endpoint:%d, cluster:0x%04X, cmd:0x%02X, send:\"%_B\""),
|
||||||
|
zcl.shortaddr, zcl.groupaddr, zcl.endpoint, zcl.cluster, zcl.cmd, &zcl.buf);
|
||||||
|
|
||||||
|
ZigbeeZCLSend_Raw(zcl);
|
||||||
|
|
||||||
// now set the timer, if any, to read back the state later
|
// now set the timer, if any, to read back the state later
|
||||||
if (msg.clusterSpecific) {
|
if (zcl.clusterSpecific) {
|
||||||
if (!Settings.flag5.zb_disable_autoquery) {
|
if (!Settings.flag5.zb_disable_autoquery) {
|
||||||
// read back attribute value unless it is disabled
|
// read back attribute value unless it is disabled
|
||||||
sendHueUpdate(msg.shortaddr, msg.groupaddr, msg.cluster, msg.endpoint);
|
sendHueUpdate(zcl.shortaddr, zcl.groupaddr, zcl.cluster, zcl.endpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,14 +322,15 @@ bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_stat
|
|||||||
// Parse "Report", "Write", "Response" or "Config" attribute
|
// Parse "Report", "Write", "Response" or "Config" attribute
|
||||||
// Operation is one of: ZCL_REPORT_ATTRIBUTES (0x0A), ZCL_WRITE_ATTRIBUTES (0x02) or ZCL_READ_ATTRIBUTES_RESPONSE (0x01)
|
// Operation is one of: ZCL_REPORT_ATTRIBUTES (0x0A), ZCL_WRITE_ATTRIBUTES (0x02) or ZCL_READ_ATTRIBUTES_RESPONSE (0x01)
|
||||||
//
|
//
|
||||||
void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMessage & packet) {
|
void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLMessage & zcl) {
|
||||||
SBuffer buf(200); // buffer to store the binary output of attibutes
|
zcl.buf.reserve(200); // buffer to store the binary output of attibutes
|
||||||
|
SBuffer & buf = zcl.buf; // synonym
|
||||||
|
|
||||||
if (nullptr == XdrvMailbox.command) {
|
if (nullptr == XdrvMailbox.command) {
|
||||||
XdrvMailbox.command = (char*) ""; // prevent a crash when calling ReponseCmndChar and there was no previous command
|
XdrvMailbox.command = (char*) ""; // prevent a crash when calling ReponseCmndChar and there was no previous command
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tuya_protocol = zigbee_devices.isTuyaProtocol(packet.shortaddr, packet.endpoint);
|
bool tuya_protocol = zigbee_devices.isTuyaProtocol(zcl.shortaddr, zcl.endpoint);
|
||||||
|
|
||||||
// iterate on keys
|
// iterate on keys
|
||||||
for (auto key : val_pubwrite.getObject()) {
|
for (auto key : val_pubwrite.getObject()) {
|
||||||
@ -361,9 +342,9 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMe
|
|||||||
// Buffer ready, do some sanity checks
|
// Buffer ready, do some sanity checks
|
||||||
|
|
||||||
// all attributes must use the same cluster
|
// all attributes must use the same cluster
|
||||||
if (0xFFFF == packet.cluster) {
|
if (0xFFFF == zcl.cluster) {
|
||||||
packet.cluster = attr.key.id.cluster; // set the cluster for this packet
|
zcl.cluster = attr.key.id.cluster; // set the cluster for this packet
|
||||||
} else if (packet.cluster != attr.key.id.cluster) {
|
} else if (zcl.cluster != attr.key.id.cluster) {
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -390,20 +371,20 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMe
|
|||||||
const char* val_str = ""; // variant as string
|
const char* val_str = ""; // variant as string
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Split encoding depending on message
|
// Split encoding depending on message
|
||||||
if (packet.cmd != ZCL_CONFIGURE_REPORTING) {
|
if (zcl.cmd != ZCL_CONFIGURE_REPORTING) {
|
||||||
if ((packet.cluster == 0XEF00) && (packet.cmd == ZCL_WRITE_ATTRIBUTES)) {
|
if ((zcl.cluster == 0XEF00) && (zcl.cmd == ZCL_WRITE_ATTRIBUTES)) {
|
||||||
// special case of Tuya / Moes / Lidl attributes
|
// special case of Tuya / Moes / Lidl attributes
|
||||||
if (buf.len() == 0) {
|
if (buf.len() == 0) {
|
||||||
// add the prefix to data
|
// add the prefix to data
|
||||||
buf.add8(0); // status
|
buf.add8(0); // status
|
||||||
buf.add8(zigbee_devices.getNextSeqNumber(packet.shortaddr));
|
buf.add8(zigbee_devices.getNextSeqNumber(zcl.shortaddr));
|
||||||
}
|
}
|
||||||
packet.clusterSpecific = true;
|
zcl.clusterSpecific = true;
|
||||||
packet.cmd = 0x00;
|
zcl.cmd = 0x00;
|
||||||
if (!ZbTuyaWrite(buf, attr)) {
|
if (!ZbTuyaWrite(buf, attr)) {
|
||||||
return; // error
|
return; // error
|
||||||
}
|
}
|
||||||
} else if (!ZbAppendWriteBuf(buf, attr, packet.cmd == ZCL_READ_ATTRIBUTES_RESPONSE)) { // general case
|
} else if (!ZbAppendWriteBuf(buf, attr, zcl.cmd == ZCL_READ_ATTRIBUTES_RESPONSE)) { // general case
|
||||||
return; // error
|
return; // error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -464,19 +445,13 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// all good, send the packet
|
// all good, send the packet
|
||||||
packet.transacId = zigbee_devices.getNextSeqNumber(packet.shortaddr);
|
zigbeeZCLSendCmd(zcl);
|
||||||
packet.msg = buf.getBuffer();
|
|
||||||
packet.len = buf.len();
|
|
||||||
ZigbeeZCLSend_Raw(packet);
|
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the "Send" attribute and send the command
|
// Parse the "Send" attribute and send the command
|
||||||
void ZbSendSend(class JsonParserToken val_cmd, uint16_t device, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint16_t manuf) {
|
void ZbSendSend(class JsonParserToken val_cmd, ZCLMessage & zcl) {
|
||||||
uint8_t cmd = 0;
|
zcl.clusterSpecific = true;
|
||||||
String cmd_str = ""; // the actual low-level command, either specified or computed
|
|
||||||
const char *cmd_s = ""; // pointer to payload string
|
|
||||||
bool clusterSpecific = true;
|
|
||||||
|
|
||||||
static const char delim[] = ", "; // delimiters for parameters
|
static const char delim[] = ", "; // delimiters for parameters
|
||||||
// probe the type of the argument
|
// probe the type of the argument
|
||||||
@ -497,17 +472,16 @@ void ZbSendSend(class JsonParserToken val_cmd, uint16_t device, uint16_t groupad
|
|||||||
uint16_t cmd_var;
|
uint16_t cmd_var;
|
||||||
uint16_t local_cluster_id;
|
uint16_t local_cluster_id;
|
||||||
|
|
||||||
const __FlashStringHelper* tasmota_cmd = zigbeeFindCommand(key.getStr(), &local_cluster_id, &cmd_var);
|
const char * tasmota_cmd = zigbeeFindCommand(key.getStr(), &local_cluster_id, &cmd_var);
|
||||||
if (tasmota_cmd) {
|
if (tasmota_cmd == nullptr) { // did we find the command?
|
||||||
cmd_str = tasmota_cmd;
|
|
||||||
} else {
|
|
||||||
Response_P(PSTR(D_ZIGBEE_UNRECOGNIZED_COMMAND), key.getStr());
|
Response_P(PSTR(D_ZIGBEE_UNRECOGNIZED_COMMAND), key.getStr());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check cluster
|
// check cluster
|
||||||
if (0xFFFF == cluster) {
|
if (0xFFFF == zcl.cluster) {
|
||||||
cluster = local_cluster_id;
|
zcl.cluster = local_cluster_id;
|
||||||
} else if (cluster != local_cluster_id) {
|
} else if (zcl.cluster != local_cluster_id) {
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -546,64 +520,62 @@ void ZbSendSend(class JsonParserToken val_cmd, uint16_t device, uint16_t groupad
|
|||||||
|
|
||||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: command_template = %s"), cmd_str.c_str());
|
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: command_template = %s"), cmd_str.c_str());
|
||||||
if (0xFF == cmd_var) { // if command number is a variable, replace it with x
|
if (0xFF == cmd_var) { // if command number is a variable, replace it with x
|
||||||
cmd = x;
|
zcl.cmd = x;
|
||||||
x = y; // and shift other variables
|
x = y; // and shift other variables
|
||||||
y = z;
|
y = z;
|
||||||
} else {
|
} else {
|
||||||
cmd = cmd_var; // or simply copy the cmd number
|
zcl.cmd = cmd_var; // or simply copy the cmd number
|
||||||
}
|
}
|
||||||
cmd_str = zigbeeCmdAddParams(cmd_str.c_str(), x, y, z); // fill in parameters
|
zigbeeCmdAddParams(zcl.buf, tasmota_cmd, x, y, z); // fill in parameters
|
||||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: command_final = %s"), cmd_str.c_str());
|
|
||||||
cmd_s = cmd_str.c_str();
|
|
||||||
} 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
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
zigbeeZCLSendCmd(zcl);
|
||||||
} else if (val_cmd.isStr()) {
|
} else if (val_cmd.isStr()) {
|
||||||
// low-level command
|
// low-level command
|
||||||
// Now parse the string to extract cluster, command, and payload
|
// Now parse the string to extract cluster, command, and payload
|
||||||
// Parse 'cmd' in the form "AAAA_BB/CCCCCCCC" or "AAAA!BB/CCCCCCCC"
|
// Parse 'cmd' in the form "AAAA_BB/CCCCCCCC" or "AAAA!BB/CCCCCCCC"
|
||||||
// where AA is the cluster number, BBBB the command number, CCCC... the payload
|
// where AAAA is the cluster number, BB the command number, CCCC... the payload
|
||||||
// First delimiter is '_' for a global command, or '!' for a cluster specific command
|
// First delimiter is '_' for a global command, or '!' for a cluster specific command
|
||||||
const char * data = val_cmd.getStr();
|
const char * data = val_cmd.getStr();
|
||||||
uint16_t local_cluster_id = parseHex(&data, 4);
|
uint16_t local_cluster_id = parseHex(&data, 4);
|
||||||
|
|
||||||
// check cluster
|
// check cluster
|
||||||
if (0xFFFF == cluster) {
|
if (0xFFFF == zcl.cluster) {
|
||||||
cluster = local_cluster_id;
|
zcl.cluster = local_cluster_id;
|
||||||
} else if (cluster != local_cluster_id) {
|
} else if (zcl.cluster != local_cluster_id) {
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delimiter
|
// delimiter
|
||||||
if (('_' == *data) || ('!' == *data)) {
|
if (('_' == *data) || ('!' == *data)) {
|
||||||
if ('_' == *data) { clusterSpecific = false; }
|
if ('_' == *data) { zcl.clusterSpecific = false; }
|
||||||
data++;
|
data++;
|
||||||
} else {
|
} else {
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_WRONG_DELIMITER));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_WRONG_DELIMITER));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// parse cmd number
|
// parse cmd number
|
||||||
cmd = parseHex(&data, 2);
|
zcl.cmd = parseHex(&data, 2);
|
||||||
|
|
||||||
// move to end of payload
|
// move to end of payload
|
||||||
// delimiter is optional
|
// delimiter is optional
|
||||||
if ('/' == *data) { data++; } // skip delimiter
|
if ('/' == *data) { data++; } // skip delimiter
|
||||||
|
|
||||||
cmd_s = data;
|
zcl.buf.replace(SBuffer::SBufferFromHex(data, strlen(data)));
|
||||||
|
zigbeeZCLSendCmd(zcl);
|
||||||
} else {
|
} else {
|
||||||
// we have an unsupported command type, just ignore it and fallback to missing command
|
// we have an unsupported command type
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZigbeeZCLSend device: 0x%04X, group: 0x%04X, endpoint:%d, cluster:0x%04X, cmd:0x%02X, send:\"%s\""),
|
|
||||||
device, groupaddr, endpoint, cluster, cmd, cmd_s);
|
|
||||||
zigbeeZCLSendStr(device, groupaddr, endpoint, clusterSpecific, manuf, cluster, cmd, cmd_s);
|
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Parse the "Send" attribute and send the command
|
// Parse the "Send" attribute and send the command
|
||||||
void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
void ZbSendRead(JsonParserToken val_attr, ZCLMessage & zcl) {
|
||||||
// ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":5}
|
// ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":5}
|
||||||
// ZbSend {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Read":"0x0005"}
|
// ZbSend {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Read":"0x0005"}
|
||||||
// ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":[5,6,7,4]}
|
// ZbSend {"Device":"0xF289","Cluster":0,"Endpoint":3,"Read":[5,6,7,4]}
|
||||||
@ -618,7 +590,7 @@ void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
|||||||
uint8_t* attrs = nullptr; // empty string is valid
|
uint8_t* attrs = nullptr; // empty string is valid
|
||||||
size_t attr_item_len = 2; // how many bytes per attribute, standard for "Read"
|
size_t attr_item_len = 2; // how many bytes per attribute, standard for "Read"
|
||||||
size_t attr_item_offset = 0; // how many bytes do we offset to store attribute
|
size_t attr_item_offset = 0; // how many bytes do we offset to store attribute
|
||||||
if (ZCL_READ_REPORTING_CONFIGURATION == packet.cmd) {
|
if (ZCL_READ_REPORTING_CONFIGURATION == zcl.cmd) {
|
||||||
attr_item_len = 3;
|
attr_item_len = 3;
|
||||||
attr_item_offset = 1;
|
attr_item_offset = 1;
|
||||||
}
|
}
|
||||||
@ -670,9 +642,9 @@ void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
|||||||
actual_attr_len += attr_item_len - 2 - attr_item_offset; // normally 0
|
actual_attr_len += attr_item_len - 2 - attr_item_offset; // normally 0
|
||||||
found = true;
|
found = true;
|
||||||
// check cluster
|
// check cluster
|
||||||
if (0xFFFF == packet.cluster) {
|
if (!zcl.validCluster()) {
|
||||||
packet.cluster = local_cluster_id;
|
zcl.cluster = local_cluster_id;
|
||||||
} else if (packet.cluster != local_cluster_id) {
|
} else if (zcl.cluster != local_cluster_id) {
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||||
if (attrs) { free(attrs); }
|
if (attrs) { free(attrs); }
|
||||||
return;
|
return;
|
||||||
@ -688,7 +660,7 @@ void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
|||||||
attrs_len = actual_attr_len;
|
attrs_len = actual_attr_len;
|
||||||
} else {
|
} else {
|
||||||
// value is a literal
|
// value is a literal
|
||||||
if (0xFFFF != packet.cluster) {
|
if (zcl.validCluster()) {
|
||||||
uint16_t val = val_attr.getUInt();
|
uint16_t val = val_attr.getUInt();
|
||||||
attrs_len = attr_item_len;
|
attrs_len = attr_item_len;
|
||||||
attrs = (uint8_t*) calloc(attrs_len, 1);
|
attrs = (uint8_t*) calloc(attrs_len, 1);
|
||||||
@ -699,10 +671,10 @@ void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
|||||||
|
|
||||||
if (attrs_len > 0) {
|
if (attrs_len > 0) {
|
||||||
// all good, send the packet
|
// all good, send the packet
|
||||||
packet.transacId = zigbee_devices.getNextSeqNumber(packet.shortaddr);
|
zcl.buf.reserve(attrs_len);
|
||||||
packet.msg = attrs;
|
zcl.buf.setLen(0); // clear any previous buffer
|
||||||
packet.len = attrs_len;
|
zcl.buf.addBuffer(attrs, attrs_len);
|
||||||
ZigbeeZCLSend_Raw(packet);
|
zigbeeZCLSendCmd(zcl);
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
} else {
|
} else {
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||||
@ -741,44 +713,38 @@ void CmndZbSend(void) {
|
|||||||
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
// params
|
// params
|
||||||
uint16_t device = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid
|
ZCLMessage zcl; // prepare the ZCL structure
|
||||||
uint16_t groupaddr = 0x0000; // group address valid only if device == BAD_SHORTADDR
|
|
||||||
uint16_t cluster = 0xFFFF; // no default
|
|
||||||
uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint
|
|
||||||
uint16_t manuf = 0x0000; // Manuf Id in ZCL frame
|
|
||||||
|
|
||||||
|
|
||||||
// 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) {
|
||||||
device = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
|
zcl.shortaddr = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
|
||||||
if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR(D_ZIGBEE_INVALID_PARAM)); return; }
|
if (!zcl.validShortaddr()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_INVALID_PARAM)); return; }
|
||||||
}
|
}
|
||||||
if (BAD_SHORTADDR == device) { // 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)];
|
||||||
if (val_group) {
|
if (val_group) {
|
||||||
groupaddr = val_group.getUInt();
|
zcl.groupaddr = val_group.getUInt();
|
||||||
} else { // no device nor group
|
} else { // no device nor group
|
||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// from here, either device has a device shortaddr, or if BAD_SHORTADDR then use group address
|
// from here, either device has a device shortaddr, or if BAD_SHORTADDR then use group address
|
||||||
// Note: groupaddr == 0 is valid
|
// Note: groupaddr == 0 is valid
|
||||||
|
|
||||||
// read other parameters
|
// read other parameters
|
||||||
cluster = root.getUInt(PSTR(D_CMND_ZIGBEE_CLUSTER), cluster);
|
zcl.cluster = root.getUInt(PSTR(D_CMND_ZIGBEE_CLUSTER), zcl.cluster);
|
||||||
endpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), endpoint);
|
zcl.endpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), zcl.endpoint);
|
||||||
manuf = root.getUInt(PSTR(D_CMND_ZIGBEE_MANUF), manuf);
|
zcl.manuf = root.getUInt(PSTR(D_CMND_ZIGBEE_MANUF), zcl.manuf);
|
||||||
|
|
||||||
// infer endpoint
|
// infer endpoint
|
||||||
if (BAD_SHORTADDR == device) {
|
if (!zcl.validShortaddr()) {
|
||||||
endpoint = 0xFF; // endpoint not used for group addresses, so use a dummy broadcast endpoint
|
zcl.endpoint = 0xFF; // endpoint not used for group addresses, so use a dummy broadcast endpoint
|
||||||
} else if (0 == endpoint) { // if it was not already specified, try to guess it
|
} else if (!zcl.validEndpoint()) { // if it was not already specified, try to guess it
|
||||||
endpoint = zigbee_devices.findFirstEndpoint(device);
|
zcl.endpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr);
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZIG: guessing endpoint %d"), endpoint);
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZIG: guessing endpoint %d"), zcl.endpoint);
|
||||||
}
|
}
|
||||||
if (0 == endpoint) { // after this, if it is still zero, then it's an error
|
if (!zcl.validEndpoint()) { // after this, if it is still zero, then it's an error
|
||||||
ResponseCmndChar_P(PSTR("Missing endpoint"));
|
ResponseCmndChar_P(PSTR("Missing endpoint"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -800,30 +766,19 @@ void CmndZbSend(void) {
|
|||||||
}
|
}
|
||||||
// from here we have one and only one command
|
// from here we have one and only one command
|
||||||
|
|
||||||
// collate information in a ready to send packet
|
zcl.clusterSpecific = false; /* not cluster specific */
|
||||||
ZigbeeZCLSendMessage packet({
|
zcl.needResponse = false; /* no response */
|
||||||
device,
|
zcl.direct = false; /* discover route */
|
||||||
groupaddr,
|
|
||||||
cluster /*cluster*/,
|
|
||||||
endpoint,
|
|
||||||
ZCL_READ_ATTRIBUTES,
|
|
||||||
manuf, /* manuf */
|
|
||||||
false /* not cluster specific */,
|
|
||||||
false /* no response */,
|
|
||||||
false /* discover route */,
|
|
||||||
0, /* zcl transaction id */
|
|
||||||
nullptr, 0
|
|
||||||
});
|
|
||||||
|
|
||||||
if (val_cmd) {
|
if (val_cmd) {
|
||||||
// "Send":{...commands...}
|
// "Send":{...commands...}
|
||||||
// we accept either a string or a JSON object
|
// we accept either a string or a JSON object
|
||||||
ZbSendSend(val_cmd, device, groupaddr, cluster, endpoint, manuf);
|
ZbSendSend(val_cmd, zcl);
|
||||||
} else if (val_read) {
|
} else if (val_read) {
|
||||||
// "Read":{...attributes...}, "Read":attribute or "Read":[...attributes...]
|
// "Read":{...attributes...}, "Read":attribute or "Read":[...attributes...]
|
||||||
// we accept eitehr a number, a string, an array of numbers/strings, or a JSON object
|
// we accept eitehr a number, a string, an array of numbers/strings, or a JSON object
|
||||||
packet.cmd = ZCL_READ_ATTRIBUTES;
|
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||||
ZbSendRead(val_read, packet);
|
ZbSendRead(val_read, zcl);
|
||||||
} else if (val_write) {
|
} else if (val_write) {
|
||||||
// only KSON object
|
// only KSON object
|
||||||
if (!val_write.isObject()) {
|
if (!val_write.isObject()) {
|
||||||
@ -831,8 +786,8 @@ void CmndZbSend(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// "Write":{...attributes...}
|
// "Write":{...attributes...}
|
||||||
packet.cmd = ZCL_WRITE_ATTRIBUTES;
|
zcl.cmd = ZCL_WRITE_ATTRIBUTES;
|
||||||
ZbSendReportWrite(val_write, packet);
|
ZbSendReportWrite(val_write, zcl);
|
||||||
} else if (val_publish) {
|
} else if (val_publish) {
|
||||||
// "Publish":{...attributes...}
|
// "Publish":{...attributes...}
|
||||||
// only KSON object
|
// only KSON object
|
||||||
@ -840,8 +795,8 @@ void CmndZbSend(void) {
|
|||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet.cmd = ZCL_REPORT_ATTRIBUTES;
|
zcl.cmd = ZCL_REPORT_ATTRIBUTES;
|
||||||
ZbSendReportWrite(val_publish, packet);
|
ZbSendReportWrite(val_publish, zcl);
|
||||||
} else if (val_response) {
|
} else if (val_response) {
|
||||||
// "Report":{...attributes...}
|
// "Report":{...attributes...}
|
||||||
// only KSON object
|
// only KSON object
|
||||||
@ -849,13 +804,13 @@ void CmndZbSend(void) {
|
|||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
||||||
ZbSendReportWrite(val_response, packet);
|
ZbSendReportWrite(val_response, zcl);
|
||||||
} else if (val_read_config) {
|
} else if (val_read_config) {
|
||||||
// "ReadConfg":{...attributes...}, "ReadConfg":attribute or "ReadConfg":[...attributes...]
|
// "ReadConfg":{...attributes...}, "ReadConfg":attribute or "ReadConfg":[...attributes...]
|
||||||
// we accept eitehr a number, a string, an array of numbers/strings, or a JSON object
|
// we accept eitehr a number, a string, an array of numbers/strings, or a JSON object
|
||||||
packet.cmd = ZCL_READ_REPORTING_CONFIGURATION;
|
zcl.cmd = ZCL_READ_REPORTING_CONFIGURATION;
|
||||||
ZbSendRead(val_read_config, packet);
|
ZbSendRead(val_read_config, zcl);
|
||||||
} else if (val_config) {
|
} else if (val_config) {
|
||||||
// "Config":{...attributes...}
|
// "Config":{...attributes...}
|
||||||
// only JSON object
|
// only JSON object
|
||||||
@ -863,8 +818,8 @@ void CmndZbSend(void) {
|
|||||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet.cmd = ZCL_CONFIGURE_REPORTING;
|
zcl.cmd = ZCL_CONFIGURE_REPORTING;
|
||||||
ZbSendReportWrite(val_config, packet);
|
ZbSendReportWrite(val_config, zcl);
|
||||||
} else {
|
} else {
|
||||||
Response_P(PSTR("Missing zigbee 'Send', 'Write', 'Report' or 'Response'"));
|
Response_P(PSTR("Missing zigbee 'Send', 'Write', 'Report' or 'Response'"));
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user