mirror of https://github.com/arendst/Tasmota.git
Merge pull request #10804 from s-hadinger/zigbee_refactor_send
Zigbee refactor sending ZCL packets
This commit is contained in:
commit
afbf7fa1a0
|
@ -52,6 +52,20 @@ public:
|
|||
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) {
|
||||
uint16_t old_len = _buf->len;
|
||||
_buf->len = (len <= _buf->size) ? len : _buf->size;
|
||||
|
@ -118,6 +132,13 @@ public:
|
|||
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) {
|
||||
if (len() + buf2.len() <= size()) {
|
||||
for (uint32_t i = 0; i < buf2.len(); i++) {
|
||||
|
|
|
@ -28,22 +28,40 @@
|
|||
//
|
||||
// structure containing all needed information to send a ZCL packet
|
||||
//
|
||||
class ZigbeeZCLSendMessage {
|
||||
class ZCLMessage {
|
||||
|
||||
public:
|
||||
uint16_t shortaddr;
|
||||
uint16_t groupaddr;
|
||||
uint16_t cluster;
|
||||
uint8_t endpoint;
|
||||
uint8_t cmd;
|
||||
uint16_t manuf;
|
||||
bool clusterSpecific;
|
||||
bool needResponse;
|
||||
bool direct; // true if direct, false if discover router
|
||||
uint8_t transacId; // ZCL transaction number
|
||||
const uint8_t *msg;
|
||||
size_t len;
|
||||
ZCLMessage(void); // allocate 16 bytes vy default
|
||||
ZCLMessage(size_t size);
|
||||
|
||||
inline bool validShortaddr(void) const { return BAD_SHORTADDR != shortaddr; }
|
||||
inline bool validGroupaddr(void) const { return 0 != groupaddr; }
|
||||
inline bool validCluster(void) const { return 0xFFFF != cluster; }
|
||||
inline bool validEndpoint(void) const { return 0x00 != endpoint; }
|
||||
inline bool validCmd(void) const { return 0xFF != cmd; }
|
||||
|
||||
inline void setTransac(uint8_t _transac) { transac = _transac; transacSet = true; }
|
||||
|
||||
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_RecvMsgFunc)(int32_t res, const SBuffer &buf);
|
||||
|
||||
|
@ -119,8 +137,8 @@ public:
|
|||
struct ZigbeeStatus zigbee;
|
||||
SBuffer *zigbee_buffer = nullptr;
|
||||
|
||||
void zigbeeZCLSendCmd(const ZigbeeZCLSendMessage &msg);
|
||||
void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl);
|
||||
void zigbeeZCLSendCmd(ZCLMessage &msg);
|
||||
void ZigbeeZCLSend_Raw(const ZCLMessage &zcl);
|
||||
bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_status_ok = false);
|
||||
|
||||
// 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) {
|
||||
zigbeeZCLSendCmd(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0 /* groupaddr */,
|
||||
cluster /*cluster*/,
|
||||
0 /* endpoint */,
|
||||
cmd /* cmd */,
|
||||
0, /* manuf */
|
||||
true /* cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
0, /* zcl transaction id */
|
||||
(&s != nullptr) ? s.getBuffer() : nullptr,
|
||||
(&s != nullptr) ? s.len() : 0
|
||||
}));
|
||||
ZCLMessage zcl(&s ? s.len() : 0);
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.cluster = cluster;
|
||||
zcl.cmd = cmd;
|
||||
zcl.clusterSpecific = true;
|
||||
zcl.needResponse = true;
|
||||
zcl.direct = false; // discover route
|
||||
if (&s) { zcl.buf.replace(s); }
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
|
||||
// Send commands
|
||||
// Power On/Off
|
||||
void ZigbeeHuePower(uint16_t shortaddr, bool power) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -183,23 +177,16 @@ void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) {
|
|||
s.add8(dimmer);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
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);
|
||||
}
|
||||
|
||||
// CT
|
||||
void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
|
||||
if (ct > 0xFEFF) { ct = 0xFEFF; }
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("ZigbeeHueCT 0x%04X - %d"), shortaddr, ct);
|
||||
SBuffer s(4);
|
||||
s.add16(ct);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
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);
|
||||
light.setColorMode(2); // "ct"
|
||||
light.setCT(ct);
|
||||
|
@ -214,10 +201,6 @@ void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y) {
|
|||
s.add16(y);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
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);
|
||||
light.setColorMode(1); // "xy"
|
||||
light.setX(x);
|
||||
|
@ -233,10 +216,6 @@ void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat) {
|
|||
s.add8(sat);
|
||||
s.add16(0);
|
||||
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);
|
||||
light.setColorMode(0); // "hs"
|
||||
light.setSat(sat);
|
||||
|
|
|
@ -381,7 +381,6 @@ const char Z_strings[] PROGMEM =
|
|||
"ProductURL" "\x00"
|
||||
"QualityMeasure" "\x00"
|
||||
"RGB" "\x00"
|
||||
"RGBb" "\x00"
|
||||
"RMSCurrent" "\x00"
|
||||
"RMSVoltage" "\x00"
|
||||
"ReactivePower" "\x00"
|
||||
|
@ -474,6 +473,7 @@ const char Z_strings[] PROGMEM =
|
|||
"ZoneStatus" "\x00"
|
||||
"ZoneStatusChange" "\x00"
|
||||
"ZoneType" "\x00"
|
||||
"_" "\x00"
|
||||
"xx" "\x00"
|
||||
"xx000A00" "\x00"
|
||||
"xx0A" "\x00"
|
||||
|
@ -805,121 +805,121 @@ enum Z_offsets {
|
|||
Zo_ProductURL = 4956,
|
||||
Zo_QualityMeasure = 4967,
|
||||
Zo_RGB = 4982,
|
||||
Zo_RGBb = 4986,
|
||||
Zo_RMSCurrent = 4991,
|
||||
Zo_RMSVoltage = 5002,
|
||||
Zo_ReactivePower = 5013,
|
||||
Zo_RecallScene = 5027,
|
||||
Zo_RemainingTime = 5039,
|
||||
Zo_RemoteSensing = 5053,
|
||||
Zo_RemoveAllGroups = 5067,
|
||||
Zo_RemoveAllScenes = 5083,
|
||||
Zo_RemoveGroup = 5099,
|
||||
Zo_RemoveScene = 5111,
|
||||
Zo_ResetAlarm = 5123,
|
||||
Zo_ResetAllAlarms = 5134,
|
||||
Zo_SWBuildID = 5149,
|
||||
Zo_Sat = 5159,
|
||||
Zo_SatMove = 5163,
|
||||
Zo_SatStep = 5171,
|
||||
Zo_SceneCount = 5179,
|
||||
Zo_SceneValid = 5190,
|
||||
Zo_ScheduleMode = 5201,
|
||||
Zo_SeaPressure = 5214,
|
||||
Zo_ShortPollInterval = 5226,
|
||||
Zo_Shutter = 5244,
|
||||
Zo_ShutterClose = 5252,
|
||||
Zo_ShutterLift = 5265,
|
||||
Zo_ShutterOpen = 5277,
|
||||
Zo_ShutterStop = 5289,
|
||||
Zo_ShutterTilt = 5301,
|
||||
Zo_SoftwareRevision = 5313,
|
||||
Zo_StackVersion = 5330,
|
||||
Zo_StandardTime = 5343,
|
||||
Zo_StartUpOnOff = 5356,
|
||||
Zo_Status = 5369,
|
||||
Zo_StoreScene = 5376,
|
||||
Zo_SwitchType = 5387,
|
||||
Zo_SystemMode = 5398,
|
||||
Zo_TRVBoost = 5409,
|
||||
Zo_TRVChildProtection = 5418,
|
||||
Zo_TRVMirrorDisplay = 5437,
|
||||
Zo_TRVMode = 5454,
|
||||
Zo_TRVWindowOpen = 5462,
|
||||
Zo_TempTarget = 5476,
|
||||
Zo_Temperature = 5487,
|
||||
Zo_TemperatureMaxMeasuredValue = 5499,
|
||||
Zo_TemperatureMinMeasuredValue = 5527,
|
||||
Zo_TemperatureTolerance = 5555,
|
||||
Zo_TerncyDuration = 5576,
|
||||
Zo_TerncyRotate = 5591,
|
||||
Zo_ThSetpoint = 5604,
|
||||
Zo_Time = 5615,
|
||||
Zo_TimeEpoch = 5620,
|
||||
Zo_TimeStatus = 5630,
|
||||
Zo_TimeZone = 5641,
|
||||
Zo_TotalProfileNum = 5650,
|
||||
Zo_TuyaAutoLock = 5666,
|
||||
Zo_TuyaAwayDays = 5679,
|
||||
Zo_TuyaAwayTemp = 5692,
|
||||
Zo_TuyaBattery = 5705,
|
||||
Zo_TuyaBoostTime = 5717,
|
||||
Zo_TuyaChildLock = 5731,
|
||||
Zo_TuyaComfortTemp = 5745,
|
||||
Zo_TuyaEcoTemp = 5761,
|
||||
Zo_TuyaFanMode = 5773,
|
||||
Zo_TuyaForceMode = 5785,
|
||||
Zo_TuyaMaxTemp = 5799,
|
||||
Zo_TuyaMinTemp = 5811,
|
||||
Zo_TuyaPreset = 5823,
|
||||
Zo_TuyaScheduleHolidays = 5834,
|
||||
Zo_TuyaScheduleWorkdays = 5855,
|
||||
Zo_TuyaTempTarget = 5876,
|
||||
Zo_TuyaValveDetection = 5891,
|
||||
Zo_TuyaValvePosition = 5910,
|
||||
Zo_TuyaWeekSelect = 5928,
|
||||
Zo_TuyaWindowDetection = 5943,
|
||||
Zo_UnoccupiedCoolingSetpoint = 5963,
|
||||
Zo_UnoccupiedHeatingSetpoint = 5989,
|
||||
Zo_UtilityName = 6015,
|
||||
Zo_ValidUntilTime = 6027,
|
||||
Zo_ValvePosition = 6042,
|
||||
Zo_VelocityLift = 6056,
|
||||
Zo_ViewGroup = 6069,
|
||||
Zo_ViewScene = 6079,
|
||||
Zo_Water = 6089,
|
||||
Zo_WhitePointX = 6095,
|
||||
Zo_WhitePointY = 6107,
|
||||
Zo_WindowCoveringType = 6119,
|
||||
Zo_X = 6138,
|
||||
Zo_Y = 6140,
|
||||
Zo_ZCLVersion = 6142,
|
||||
Zo_ZoneState = 6153,
|
||||
Zo_ZoneStatus = 6163,
|
||||
Zo_ZoneStatusChange = 6174,
|
||||
Zo_ZoneType = 6191,
|
||||
Zo_xx = 6200,
|
||||
Zo_xx000A00 = 6203,
|
||||
Zo_xx0A = 6212,
|
||||
Zo_xx0A00 = 6217,
|
||||
Zo_xx19 = 6224,
|
||||
Zo_xx190A = 6229,
|
||||
Zo_xx190A00 = 6236,
|
||||
Zo_xxxx = 6245,
|
||||
Zo_xxxx00 = 6250,
|
||||
Zo_xxxx0A00 = 6257,
|
||||
Zo_xxxxyy = 6266,
|
||||
Zo_xxxxyyyy = 6273,
|
||||
Zo_xxxxyyyy0A00 = 6282,
|
||||
Zo_xxxxyyzz = 6295,
|
||||
Zo_xxyy = 6304,
|
||||
Zo_xxyy0A00 = 6309,
|
||||
Zo_xxyyyy = 6318,
|
||||
Zo_xxyyyy000000000000 = 6325,
|
||||
Zo_xxyyyy0A0000000000 = 6344,
|
||||
Zo_xxyyyyzz = 6363,
|
||||
Zo_xxyyyyzzzz = 6372,
|
||||
Zo_xxyyzzzz = 6383,
|
||||
Zo_RMSCurrent = 4986,
|
||||
Zo_RMSVoltage = 4997,
|
||||
Zo_ReactivePower = 5008,
|
||||
Zo_RecallScene = 5022,
|
||||
Zo_RemainingTime = 5034,
|
||||
Zo_RemoteSensing = 5048,
|
||||
Zo_RemoveAllGroups = 5062,
|
||||
Zo_RemoveAllScenes = 5078,
|
||||
Zo_RemoveGroup = 5094,
|
||||
Zo_RemoveScene = 5106,
|
||||
Zo_ResetAlarm = 5118,
|
||||
Zo_ResetAllAlarms = 5129,
|
||||
Zo_SWBuildID = 5144,
|
||||
Zo_Sat = 5154,
|
||||
Zo_SatMove = 5158,
|
||||
Zo_SatStep = 5166,
|
||||
Zo_SceneCount = 5174,
|
||||
Zo_SceneValid = 5185,
|
||||
Zo_ScheduleMode = 5196,
|
||||
Zo_SeaPressure = 5209,
|
||||
Zo_ShortPollInterval = 5221,
|
||||
Zo_Shutter = 5239,
|
||||
Zo_ShutterClose = 5247,
|
||||
Zo_ShutterLift = 5260,
|
||||
Zo_ShutterOpen = 5272,
|
||||
Zo_ShutterStop = 5284,
|
||||
Zo_ShutterTilt = 5296,
|
||||
Zo_SoftwareRevision = 5308,
|
||||
Zo_StackVersion = 5325,
|
||||
Zo_StandardTime = 5338,
|
||||
Zo_StartUpOnOff = 5351,
|
||||
Zo_Status = 5364,
|
||||
Zo_StoreScene = 5371,
|
||||
Zo_SwitchType = 5382,
|
||||
Zo_SystemMode = 5393,
|
||||
Zo_TRVBoost = 5404,
|
||||
Zo_TRVChildProtection = 5413,
|
||||
Zo_TRVMirrorDisplay = 5432,
|
||||
Zo_TRVMode = 5449,
|
||||
Zo_TRVWindowOpen = 5457,
|
||||
Zo_TempTarget = 5471,
|
||||
Zo_Temperature = 5482,
|
||||
Zo_TemperatureMaxMeasuredValue = 5494,
|
||||
Zo_TemperatureMinMeasuredValue = 5522,
|
||||
Zo_TemperatureTolerance = 5550,
|
||||
Zo_TerncyDuration = 5571,
|
||||
Zo_TerncyRotate = 5586,
|
||||
Zo_ThSetpoint = 5599,
|
||||
Zo_Time = 5610,
|
||||
Zo_TimeEpoch = 5615,
|
||||
Zo_TimeStatus = 5625,
|
||||
Zo_TimeZone = 5636,
|
||||
Zo_TotalProfileNum = 5645,
|
||||
Zo_TuyaAutoLock = 5661,
|
||||
Zo_TuyaAwayDays = 5674,
|
||||
Zo_TuyaAwayTemp = 5687,
|
||||
Zo_TuyaBattery = 5700,
|
||||
Zo_TuyaBoostTime = 5712,
|
||||
Zo_TuyaChildLock = 5726,
|
||||
Zo_TuyaComfortTemp = 5740,
|
||||
Zo_TuyaEcoTemp = 5756,
|
||||
Zo_TuyaFanMode = 5768,
|
||||
Zo_TuyaForceMode = 5780,
|
||||
Zo_TuyaMaxTemp = 5794,
|
||||
Zo_TuyaMinTemp = 5806,
|
||||
Zo_TuyaPreset = 5818,
|
||||
Zo_TuyaScheduleHolidays = 5829,
|
||||
Zo_TuyaScheduleWorkdays = 5850,
|
||||
Zo_TuyaTempTarget = 5871,
|
||||
Zo_TuyaValveDetection = 5886,
|
||||
Zo_TuyaValvePosition = 5905,
|
||||
Zo_TuyaWeekSelect = 5923,
|
||||
Zo_TuyaWindowDetection = 5938,
|
||||
Zo_UnoccupiedCoolingSetpoint = 5958,
|
||||
Zo_UnoccupiedHeatingSetpoint = 5984,
|
||||
Zo_UtilityName = 6010,
|
||||
Zo_ValidUntilTime = 6022,
|
||||
Zo_ValvePosition = 6037,
|
||||
Zo_VelocityLift = 6051,
|
||||
Zo_ViewGroup = 6064,
|
||||
Zo_ViewScene = 6074,
|
||||
Zo_Water = 6084,
|
||||
Zo_WhitePointX = 6090,
|
||||
Zo_WhitePointY = 6102,
|
||||
Zo_WindowCoveringType = 6114,
|
||||
Zo_X = 6133,
|
||||
Zo_Y = 6135,
|
||||
Zo_ZCLVersion = 6137,
|
||||
Zo_ZoneState = 6148,
|
||||
Zo_ZoneStatus = 6158,
|
||||
Zo_ZoneStatusChange = 6169,
|
||||
Zo_ZoneType = 6186,
|
||||
Zo__ = 6195,
|
||||
Zo_xx = 6197,
|
||||
Zo_xx000A00 = 6200,
|
||||
Zo_xx0A = 6209,
|
||||
Zo_xx0A00 = 6214,
|
||||
Zo_xx19 = 6221,
|
||||
Zo_xx190A = 6226,
|
||||
Zo_xx190A00 = 6233,
|
||||
Zo_xxxx = 6242,
|
||||
Zo_xxxx00 = 6247,
|
||||
Zo_xxxx0A00 = 6254,
|
||||
Zo_xxxxyy = 6263,
|
||||
Zo_xxxxyyyy = 6270,
|
||||
Zo_xxxxyyyy0A00 = 6279,
|
||||
Zo_xxxxyyzz = 6292,
|
||||
Zo_xxyy = 6301,
|
||||
Zo_xxyy0A00 = 6306,
|
||||
Zo_xxyyyy = 6315,
|
||||
Zo_xxyyyy000000000000 = 6322,
|
||||
Zo_xxyyyy0A0000000000 = 6341,
|
||||
Zo_xxyyyyzz = 6360,
|
||||
Zo_xxyyyyzzzz = 6369,
|
||||
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
|
||||
if (0 == _frame_control.b.disable_def_resp) {
|
||||
// the device expects a default response
|
||||
SBuffer buf(2);
|
||||
buf.add8(_cmd_id);
|
||||
buf.add8(0x00); // Status = OK
|
||||
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
_srcaddr,
|
||||
0x0000,
|
||||
_cluster_id,
|
||||
_srcendpoint,
|
||||
ZCL_DEFAULT_RESPONSE,
|
||||
_manuf_code,
|
||||
false /* not cluster specific */,
|
||||
false /* noresponse */,
|
||||
true /* direct no retry */,
|
||||
_transact_seq, /* zcl transaction id */
|
||||
buf.getBuffer(), buf.len()
|
||||
}));
|
||||
ZCLMessage zcl(2); // message is 2 bytes
|
||||
zcl.shortaddr = _srcaddr;
|
||||
zcl.cluster = _cluster_id;
|
||||
zcl.endpoint = _srcendpoint;
|
||||
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
||||
zcl.manuf = _manuf_code;
|
||||
zcl.clusterSpecific = false; /* not cluster specific */
|
||||
zcl.needResponse = false; /* noresponse */
|
||||
zcl.direct = true; /* direct no retry */
|
||||
zcl.setTransac(_transact_seq);
|
||||
zcl.buf.add8(_cmd_id);
|
||||
zcl.buf.add8(0); // Status = OK
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1674,23 +1670,19 @@ void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) {
|
|||
// Send Default Response to acknowledge the attribute reporting
|
||||
if (0 == _frame_control.b.disable_def_resp) {
|
||||
// the device expects a default response
|
||||
SBuffer buf(2);
|
||||
buf.add8(_cmd_id);
|
||||
buf.add8(0x00); // Status = OK
|
||||
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
_srcaddr,
|
||||
0x0000,
|
||||
_cluster_id,
|
||||
_srcendpoint,
|
||||
ZCL_DEFAULT_RESPONSE,
|
||||
_manuf_code,
|
||||
false /* not cluster specific */,
|
||||
false /* noresponse */,
|
||||
true /* direct no retry */,
|
||||
_transact_seq, /* zcl transaction id */
|
||||
buf.getBuffer(), buf.len()
|
||||
}));
|
||||
ZCLMessage zcl(2); // message is 4 bytes
|
||||
zcl.shortaddr = _srcaddr;
|
||||
zcl.cluster = _cluster_id;
|
||||
zcl.endpoint = _srcendpoint;
|
||||
zcl.cmd = ZCL_DEFAULT_RESPONSE;
|
||||
zcl.manuf = _manuf_code;
|
||||
zcl.clusterSpecific = false; /* not cluster specific */
|
||||
zcl.needResponse = false; /* noresponse */
|
||||
zcl.direct = true; /* direct no retry */
|
||||
zcl.setTransac(_transact_seq);
|
||||
zcl.buf.add8(_cmd_id);
|
||||
zcl.buf.add8(0x00); // Status = OK
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ typedef struct Z_XYZ_Var { // Holds values for vairables X, Y and Z
|
|||
// - cluster: cluster number of the command
|
||||
// - 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
|
||||
// - 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 = {
|
||||
// Identify cluster
|
||||
{ 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_(Color), 0x0300, 0x07, 0x01, Z_(xxxxyyyy0A00) }, // x, y (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_(ShutterClose), 0x0102, 0x01, 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) {
|
||||
shortaddr = BAD_SHORTADDR; // if group address, don't send to device
|
||||
}
|
||||
uint8_t seq = zigbee_devices.getNextSeqNumber(shortaddr);
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
groupaddr,
|
||||
cluster /*cluster*/,
|
||||
endpoint,
|
||||
ZCL_READ_ATTRIBUTES,
|
||||
0, /* manuf */
|
||||
false /* not cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
seq, /* zcl transaction id */
|
||||
attrs, attrs_len
|
||||
}));
|
||||
|
||||
ZCLMessage zcl(attrs_len); // message is `attrs_len` bytes
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.groupaddr = groupaddr;
|
||||
zcl.cluster = cluster;
|
||||
zcl.endpoint = endpoint;
|
||||
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||
zcl.clusterSpecific = false;
|
||||
zcl.needResponse = true;
|
||||
zcl.direct = false; // discover route
|
||||
zcl.buf.addBuffer(attrs, attrs_len);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,17 +533,19 @@ bool convertTuyaSpecificCluster(class Z_attribute_list &attr_list, uint16_t clus
|
|||
// Only take commands outgoing, i.e. direction == 0
|
||||
// If not found:
|
||||
// - 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; }
|
||||
for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) {
|
||||
const Z_CommandConverter *conv = &Z_Commands[i];
|
||||
uint8_t conv_direction = pgm_read_byte(&conv->direction);
|
||||
uint8_t conv_cmd = pgm_read_byte(&conv->cmd);
|
||||
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)))) {
|
||||
*cluster = conv_cluster;
|
||||
*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)
|
||||
String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z) {
|
||||
size_t len = strlen_P(zcl_cmd_P);
|
||||
char zcl_cmd[len+1];
|
||||
strcpy_P(zcl_cmd, zcl_cmd_P); // copy into RAM
|
||||
// Returns a SBuffer allocated object, it is the caller's responsibility to delete it
|
||||
void zigbeeCmdAddParams(SBuffer & buf, const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z) {
|
||||
size_t hex_len = strlen_P(zcl_cmd_P);
|
||||
buf.reserve((hex_len + 1)/2);
|
||||
|
||||
char *p = zcl_cmd;
|
||||
while (*p) {
|
||||
if (isXYZ(*p) && (*p == *(p+1))) { // if char is [x-z] and followed by same char
|
||||
const char * p = zcl_cmd_P;
|
||||
char c0, c1;
|
||||
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;
|
||||
switch (*p) {
|
||||
switch (pgm_read_byte(p)) {
|
||||
case 'x':
|
||||
val = x & 0xFF;
|
||||
x = x >> 8;
|
||||
|
@ -582,15 +583,18 @@ String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_
|
|||
z = z >> 8;
|
||||
break;
|
||||
}
|
||||
*p = hexDigit(val >> 4);
|
||||
*(p+1) = hexDigit(val);
|
||||
p++;
|
||||
buf.add8(val);
|
||||
// *p = hexDigit(val >> 4);
|
||||
// *(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
|
||||
|
|
|
@ -1319,78 +1319,55 @@ void Z_SendSimpleDescReq(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluste
|
|||
//
|
||||
// Send AF Info Request
|
||||
// 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:
|
||||
// Iterate among
|
||||
//
|
||||
void Z_SendDeviceInfoRequest(uint16_t shortaddr) {
|
||||
uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||
if (0x00 == endpoint) { endpoint = 0x01; } // if we don't know the endpoint, try 0x01
|
||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
||||
|
||||
uint8_t InfoReq[] = { 0x04, 0x00, 0x05, 0x00 };
|
||||
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0x0000, /* group */
|
||||
0x0000 /*cluster*/,
|
||||
endpoint,
|
||||
ZCL_READ_ATTRIBUTES,
|
||||
0x0000, /* manuf */
|
||||
false /* not cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
transacid, /* zcl transaction id */
|
||||
InfoReq, sizeof(InfoReq)
|
||||
}));
|
||||
ZCLMessage zcl(4); // message is 4 bytes
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.cluster = 0;
|
||||
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||
zcl.clusterSpecific = false;
|
||||
zcl.needResponse = true;
|
||||
zcl.direct = false; // discover route
|
||||
zcl.buf.add16(0x0005);
|
||||
zcl.buf.add16(0x0004);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
|
||||
//
|
||||
// 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) {
|
||||
uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr);
|
||||
uint8_t InfoReq[2] = { Z_B0(value), Z_B1(value) }; // list of single attribute
|
||||
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0x0000, /* group */
|
||||
cluster /*cluster*/,
|
||||
endpoint,
|
||||
ZCL_READ_ATTRIBUTES,
|
||||
0x0000, /* manuf */
|
||||
false /* not cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
transacid, /* zcl transaction id */
|
||||
InfoReq, sizeof(InfoReq)
|
||||
}));
|
||||
ZCLMessage zcl(2); // message is 2 bytes
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.cluster = cluster;
|
||||
zcl.endpoint = endpoint;
|
||||
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||
zcl.clusterSpecific = false;
|
||||
zcl.needResponse = true;
|
||||
zcl.direct = false; // discover route
|
||||
zcl.buf.add16(value); // 04000500
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
|
||||
//
|
||||
// Write CIE address
|
||||
//
|
||||
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);
|
||||
SBuffer buf(12);
|
||||
buf.add16(0x0010); // attribute 0x0010
|
||||
buf.add8(ZEUI64);
|
||||
buf.add64(localIEEEAddr);
|
||||
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Writing CIE address"));
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0x0000, /* group */
|
||||
0x0500 /*cluster*/,
|
||||
endpoint,
|
||||
ZCL_WRITE_ATTRIBUTES,
|
||||
0x0000, /* manuf */
|
||||
false /* not cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
transacid, /* zcl transaction id */
|
||||
buf.getBuffer(), buf.len()
|
||||
}));
|
||||
ZCLMessage zcl(12); // message is 12 bytes
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.cluster = 0x0500;
|
||||
zcl.endpoint = endpoint;
|
||||
zcl.cmd = ZCL_WRITE_ATTRIBUTES;
|
||||
zcl.clusterSpecific = false;
|
||||
zcl.needResponse = true;
|
||||
zcl.direct = false; // discover route
|
||||
zcl.buf.add16(0x0010); // attribute 0x0010
|
||||
zcl.buf.add8(ZEUI64);
|
||||
zcl.buf.add64(localIEEEAddr);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1398,23 +1375,18 @@ void Z_WriteCIEAddress(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster,
|
|||
// Write CIE address
|
||||
//
|
||||
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));
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0x0000, /* group */
|
||||
0x0500 /*cluster*/,
|
||||
endpoint,
|
||||
0x00, // Zone Enroll Response
|
||||
0x0000, /* manuf */
|
||||
true /* cluster specific */,
|
||||
true /* response */,
|
||||
false /* discover route */,
|
||||
transacid, /* zcl transaction id */
|
||||
EnrollRSP, sizeof(EnrollRSP)
|
||||
}));
|
||||
ZCLMessage zcl(2); // message is 2 bytes
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.cluster = 0x0500;
|
||||
zcl.endpoint = endpoint;
|
||||
zcl.cmd = 0x00, // Zone Enroll Response
|
||||
zcl.clusterSpecific = true;
|
||||
zcl.needResponse = true;
|
||||
zcl.direct = false; // discover route
|
||||
zcl.buf.add8(0x00); // success
|
||||
zcl.buf.add8(Z_B0(value)); // ZoneID
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1549,19 +1521,16 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin
|
|||
|
||||
if (buf.len() > 0) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "auto-bind `%s`"), TasmotaGlobal.mqtt_data);
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
shortaddr,
|
||||
0x0000, /* group */
|
||||
cluster /*cluster*/,
|
||||
endpoint,
|
||||
ZCL_CONFIGURE_REPORTING,
|
||||
0x0000, /* manuf */
|
||||
false /* not cluster specific */,
|
||||
false /* no response */,
|
||||
false /* discover route */,
|
||||
zigbee_devices.getNextSeqNumber(shortaddr), /* zcl transaction id */
|
||||
buf.buf(), buf.len()
|
||||
}));
|
||||
ZCLMessage zcl(buf.len()); // message is 4 bytes
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.cluster = cluster;
|
||||
zcl.endpoint = endpoint;
|
||||
zcl.cmd = ZCL_CONFIGURE_REPORTING;
|
||||
zcl.clusterSpecific = false; /* not cluster specific */
|
||||
zcl.needResponse = false; /* noresponse */
|
||||
zcl.direct = false; /* discover route */
|
||||
zcl.buf.addBuffer(buf);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2149,19 +2118,17 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
|
|||
|
||||
// send
|
||||
// all good, send the packet
|
||||
ZigbeeZCLSend_Raw(ZigbeeZCLSendMessage({
|
||||
_srcaddr,
|
||||
0x0000,
|
||||
_cluster_id /*cluster*/,
|
||||
_srcendpoint,
|
||||
ZCL_READ_ATTRIBUTES_RESPONSE,
|
||||
0x0000, /* manuf */
|
||||
false /* not cluster specific */,
|
||||
false /* no response */,
|
||||
true /* direct response */,
|
||||
_transact_seq, /* zcl transaction id */
|
||||
buf.getBuffer(), buf.len()
|
||||
}));
|
||||
ZCLMessage zcl(buf.len()); // message is 4 bytes
|
||||
zcl.shortaddr = _srcaddr;
|
||||
zcl.cluster = _cluster_id;
|
||||
zcl.endpoint = _srcendpoint;
|
||||
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
||||
zcl.clusterSpecific = false; /* not cluster specific */
|
||||
zcl.needResponse = false; /* noresponse */
|
||||
zcl.direct = true; /* direct response */
|
||||
zcl.setTransac(_transact_seq);
|
||||
zcl.buf.addBuffer(buf);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -748,16 +748,17 @@ void CmndZbEZSPSend(void)
|
|||
// - msg: pointer to byte array, payload of ZCL message (len is following), ignored if nullptr
|
||||
// - len: length of the 'msg' payload
|
||||
// - needResponse: boolean, true = we ask the target to respond, false = the target should not respond
|
||||
// - transacId: 8-bits, transation id of message (should be incremented at each message), used both for Zigbee message number and ZCL message number
|
||||
// - 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
|
||||
//
|
||||
void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl) {
|
||||
|
||||
void ZigbeeZCLSend_Raw(const ZCLMessage &zcl) {
|
||||
SBuffer buf(32+zcl.buf.len());
|
||||
|
||||
#ifdef USE_ZIGBEE_ZNP
|
||||
SBuffer buf(32+zcl.len);
|
||||
buf.add8(Z_SREQ | Z_AF); // 24
|
||||
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.add64(zcl.groupaddr); // group address, only 2 LSB, upper 6 MSB are discarded
|
||||
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.add8(0x01); // source endpoint
|
||||
buf.add16(zcl.cluster);
|
||||
buf.add8(zcl.transacId); // transacId
|
||||
buf.add8(zcl.transac); // transac
|
||||
buf.add8(0x30); // 30 options
|
||||
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
|
||||
if (zcl.manuf) {
|
||||
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);
|
||||
if (zcl.len > 0) {
|
||||
buf.addBuffer(zcl.msg, zcl.len); // add the payload
|
||||
}
|
||||
buf.addBuffer(zcl.buf);
|
||||
|
||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
|
||||
#ifdef USE_ZIGBEE_EZSP
|
||||
SBuffer buf(32+zcl.len);
|
||||
|
||||
if (BAD_SHORTADDR != zcl.shortaddr) {
|
||||
if (zcl.validShortaddr()) {
|
||||
// send unicast message to an address
|
||||
buf.add16(EZSP_sendUnicast); // 3400
|
||||
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(zcl.groupaddr); // groupId
|
||||
buf.add8(zcl.transacId);
|
||||
buf.add8(zcl.transac);
|
||||
// end of ApsFrame
|
||||
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
|
||||
if (zcl.manuf) {
|
||||
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);
|
||||
if (zcl.len > 0) {
|
||||
buf.addBuffer(zcl.msg, zcl.len); // add the payload
|
||||
}
|
||||
buf.addBuffer(zcl.buf);
|
||||
} else {
|
||||
// send broadcast group address, aka groupcast
|
||||
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(zcl.groupaddr); // groupId
|
||||
buf.add8(zcl.transacId);
|
||||
buf.add8(zcl.transac);
|
||||
// end of ApsFrame
|
||||
buf.add8(0); // hops, 0x00 = EMBER_MAX_HOPS
|
||||
buf.add8(7); // nonMemberRadius, 7 = infinite
|
||||
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
|
||||
if (zcl.manuf) {
|
||||
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);
|
||||
if (zcl.len > 0) {
|
||||
buf.addBuffer(zcl.msg, zcl.len); // add the payload
|
||||
}
|
||||
buf.addBuffer(zcl.buf);
|
||||
}
|
||||
|
||||
ZigbeeEZSPSendCmd(buf.buf(), buf.len());
|
||||
|
|
|
@ -179,59 +179,39 @@ void CmndZbReset(void) {
|
|||
// - param: pointer to HEX string for payload, should not be nullptr
|
||||
// Returns: None
|
||||
//
|
||||
void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, bool clusterSpecific, uint16_t manuf,
|
||||
uint16_t cluster, uint8_t cmd, const char *param) {
|
||||
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)) {
|
||||
void zigbeeZCLSendCmd(class ZCLMessage &zcl) {
|
||||
if ((0 == zcl.endpoint) && (zcl.validShortaddr())) {
|
||||
// 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: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %*_H"),
|
||||
msg.shortaddr, msg.groupaddr, msg.cluster, msg.endpoint, msg.cmd, msg.len, msg.msg);
|
||||
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %_B"),
|
||||
// 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"));
|
||||
return;
|
||||
}
|
||||
|
||||
// everything is good, we can send the command
|
||||
|
||||
msg.transacId = zigbee_devices.getNextSeqNumber(msg.shortaddr);
|
||||
ZigbeeZCLSend_Raw(msg);
|
||||
if (!zcl.transacSet) {
|
||||
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
|
||||
if (msg.clusterSpecific) {
|
||||
if (zcl.clusterSpecific) {
|
||||
if (!Settings.flag5.zb_disable_autoquery) {
|
||||
// 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
|
||||
// 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) {
|
||||
SBuffer buf(200); // buffer to store the binary output of attibutes
|
||||
void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLMessage & zcl) {
|
||||
zcl.buf.reserve(200); // buffer to store the binary output of attibutes
|
||||
SBuffer & buf = zcl.buf; // synonym
|
||||
|
||||
if (nullptr == XdrvMailbox.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
|
||||
for (auto key : val_pubwrite.getObject()) {
|
||||
|
@ -361,9 +342,9 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMe
|
|||
// Buffer ready, do some sanity checks
|
||||
|
||||
// all attributes must use the same cluster
|
||||
if (0xFFFF == packet.cluster) {
|
||||
packet.cluster = attr.key.id.cluster; // set the cluster for this packet
|
||||
} else if (packet.cluster != attr.key.id.cluster) {
|
||||
if (0xFFFF == zcl.cluster) {
|
||||
zcl.cluster = attr.key.id.cluster; // set the cluster for this packet
|
||||
} else if (zcl.cluster != attr.key.id.cluster) {
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||
return;
|
||||
}
|
||||
|
@ -390,20 +371,20 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMe
|
|||
const char* val_str = ""; // variant as string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Split encoding depending on message
|
||||
if (packet.cmd != ZCL_CONFIGURE_REPORTING) {
|
||||
if ((packet.cluster == 0XEF00) && (packet.cmd == ZCL_WRITE_ATTRIBUTES)) {
|
||||
if (zcl.cmd != ZCL_CONFIGURE_REPORTING) {
|
||||
if ((zcl.cluster == 0XEF00) && (zcl.cmd == ZCL_WRITE_ATTRIBUTES)) {
|
||||
// special case of Tuya / Moes / Lidl attributes
|
||||
if (buf.len() == 0) {
|
||||
// add the prefix to data
|
||||
buf.add8(0); // status
|
||||
buf.add8(zigbee_devices.getNextSeqNumber(packet.shortaddr));
|
||||
buf.add8(zigbee_devices.getNextSeqNumber(zcl.shortaddr));
|
||||
}
|
||||
packet.clusterSpecific = true;
|
||||
packet.cmd = 0x00;
|
||||
zcl.clusterSpecific = true;
|
||||
zcl.cmd = 0x00;
|
||||
if (!ZbTuyaWrite(buf, attr)) {
|
||||
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
|
||||
}
|
||||
} else {
|
||||
|
@ -464,19 +445,13 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZigbeeZCLSendMe
|
|||
}
|
||||
|
||||
// all good, send the packet
|
||||
packet.transacId = zigbee_devices.getNextSeqNumber(packet.shortaddr);
|
||||
packet.msg = buf.getBuffer();
|
||||
packet.len = buf.len();
|
||||
ZigbeeZCLSend_Raw(packet);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
// 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) {
|
||||
uint8_t cmd = 0;
|
||||
String cmd_str = ""; // the actual low-level command, either specified or computed
|
||||
const char *cmd_s = ""; // pointer to payload string
|
||||
bool clusterSpecific = true;
|
||||
void ZbSendSend(class JsonParserToken val_cmd, ZCLMessage & zcl) {
|
||||
zcl.clusterSpecific = true;
|
||||
|
||||
static const char delim[] = ", "; // delimiters for parameters
|
||||
// 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 local_cluster_id;
|
||||
|
||||
const __FlashStringHelper* tasmota_cmd = zigbeeFindCommand(key.getStr(), &local_cluster_id, &cmd_var);
|
||||
if (tasmota_cmd) {
|
||||
cmd_str = tasmota_cmd;
|
||||
} else {
|
||||
const char * tasmota_cmd = zigbeeFindCommand(key.getStr(), &local_cluster_id, &cmd_var);
|
||||
if (tasmota_cmd == nullptr) { // did we find the command?
|
||||
Response_P(PSTR(D_ZIGBEE_UNRECOGNIZED_COMMAND), key.getStr());
|
||||
return;
|
||||
}
|
||||
|
||||
// check cluster
|
||||
if (0xFFFF == cluster) {
|
||||
cluster = local_cluster_id;
|
||||
} else if (cluster != local_cluster_id) {
|
||||
if (0xFFFF == zcl.cluster) {
|
||||
zcl.cluster = local_cluster_id;
|
||||
} else if (zcl.cluster != local_cluster_id) {
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||
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());
|
||||
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
|
||||
y = z;
|
||||
} 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
|
||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZbSend: command_final = %s"), cmd_str.c_str());
|
||||
cmd_s = cmd_str.c_str();
|
||||
zigbeeCmdAddParams(zcl.buf, tasmota_cmd, x, y, z); // fill in parameters
|
||||
} else {
|
||||
// we have zero command, pass through until last error for missing command
|
||||
return;
|
||||
}
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
} else if (val_cmd.isStr()) {
|
||||
// low-level command
|
||||
// Now parse the string to extract cluster, command, and payload
|
||||
// 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
|
||||
const char * data = val_cmd.getStr();
|
||||
uint16_t local_cluster_id = parseHex(&data, 4);
|
||||
|
||||
// check cluster
|
||||
if (0xFFFF == cluster) {
|
||||
cluster = local_cluster_id;
|
||||
} else if (cluster != local_cluster_id) {
|
||||
if (0xFFFF == zcl.cluster) {
|
||||
zcl.cluster = local_cluster_id;
|
||||
} else if (zcl.cluster != local_cluster_id) {
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||
return;
|
||||
}
|
||||
|
||||
// delimiter
|
||||
if (('_' == *data) || ('!' == *data)) {
|
||||
if ('_' == *data) { clusterSpecific = false; }
|
||||
if ('_' == *data) { zcl.clusterSpecific = false; }
|
||||
data++;
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_WRONG_DELIMITER));
|
||||
return;
|
||||
}
|
||||
// parse cmd number
|
||||
cmd = parseHex(&data, 2);
|
||||
zcl.cmd = parseHex(&data, 2);
|
||||
|
||||
// move to end of payload
|
||||
// delimiter is optional
|
||||
if ('/' == *data) { data++; } // skip delimiter
|
||||
|
||||
cmd_s = data;
|
||||
zcl.buf.replace(SBuffer::SBufferFromHex(data, strlen(data)));
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
} 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();
|
||||
}
|
||||
|
||||
|
||||
// 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":"0x0000","Endpoint":"0x0003","Read":"0x0005"}
|
||||
// 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
|
||||
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
|
||||
if (ZCL_READ_REPORTING_CONFIGURATION == packet.cmd) {
|
||||
if (ZCL_READ_REPORTING_CONFIGURATION == zcl.cmd) {
|
||||
attr_item_len = 3;
|
||||
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
|
||||
found = true;
|
||||
// check cluster
|
||||
if (0xFFFF == packet.cluster) {
|
||||
packet.cluster = local_cluster_id;
|
||||
} else if (packet.cluster != local_cluster_id) {
|
||||
if (!zcl.validCluster()) {
|
||||
zcl.cluster = local_cluster_id;
|
||||
} else if (zcl.cluster != local_cluster_id) {
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_TOO_MANY_CLUSTERS));
|
||||
if (attrs) { free(attrs); }
|
||||
return;
|
||||
|
@ -688,7 +660,7 @@ void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
|||
attrs_len = actual_attr_len;
|
||||
} else {
|
||||
// value is a literal
|
||||
if (0xFFFF != packet.cluster) {
|
||||
if (zcl.validCluster()) {
|
||||
uint16_t val = val_attr.getUInt();
|
||||
attrs_len = attr_item_len;
|
||||
attrs = (uint8_t*) calloc(attrs_len, 1);
|
||||
|
@ -699,10 +671,10 @@ void ZbSendRead(JsonParserToken val_attr, ZigbeeZCLSendMessage & packet) {
|
|||
|
||||
if (attrs_len > 0) {
|
||||
// all good, send the packet
|
||||
packet.transacId = zigbee_devices.getNextSeqNumber(packet.shortaddr);
|
||||
packet.msg = attrs;
|
||||
packet.len = attrs_len;
|
||||
ZigbeeZCLSend_Raw(packet);
|
||||
zcl.buf.reserve(attrs_len);
|
||||
zcl.buf.setLen(0); // clear any previous buffer
|
||||
zcl.buf.addBuffer(attrs, attrs_len);
|
||||
zigbeeZCLSendCmd(zcl);
|
||||
ResponseCmndDone();
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||
|
@ -741,44 +713,38 @@ void CmndZbSend(void) {
|
|||
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||
|
||||
// params
|
||||
uint16_t device = 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
|
||||
uint16_t manuf = 0x0000; // Manuf Id in ZCL frame
|
||||
|
||||
ZCLMessage zcl; // prepare the ZCL structure
|
||||
|
||||
// parse "Device" and "Group"
|
||||
JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)];
|
||||
if (val_device) {
|
||||
device = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
|
||||
if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR(D_ZIGBEE_INVALID_PARAM)); return; }
|
||||
zcl.shortaddr = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
|
||||
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)];
|
||||
if (val_group) {
|
||||
groupaddr = val_group.getUInt();
|
||||
zcl.groupaddr = val_group.getUInt();
|
||||
} else { // no device nor group
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE));
|
||||
return;
|
||||
ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return;
|
||||
}
|
||||
}
|
||||
// from here, either device has a device shortaddr, or if BAD_SHORTADDR then use group address
|
||||
// Note: groupaddr == 0 is valid
|
||||
|
||||
// read other parameters
|
||||
cluster = root.getUInt(PSTR(D_CMND_ZIGBEE_CLUSTER), cluster);
|
||||
endpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), endpoint);
|
||||
manuf = root.getUInt(PSTR(D_CMND_ZIGBEE_MANUF), manuf);
|
||||
zcl.cluster = root.getUInt(PSTR(D_CMND_ZIGBEE_CLUSTER), zcl.cluster);
|
||||
zcl.endpoint = root.getUInt(PSTR(D_CMND_ZIGBEE_ENDPOINT), zcl.endpoint);
|
||||
zcl.manuf = root.getUInt(PSTR(D_CMND_ZIGBEE_MANUF), zcl.manuf);
|
||||
|
||||
// infer endpoint
|
||||
if (BAD_SHORTADDR == device) {
|
||||
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
|
||||
endpoint = zigbee_devices.findFirstEndpoint(device);
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("ZIG: guessing endpoint %d"), endpoint);
|
||||
if (!zcl.validShortaddr()) {
|
||||
zcl.endpoint = 0xFF; // endpoint not used for group addresses, so use a dummy broadcast endpoint
|
||||
} else if (!zcl.validEndpoint()) { // if it was not already specified, try to guess it
|
||||
zcl.endpoint = zigbee_devices.findFirstEndpoint(zcl.shortaddr);
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
|
@ -800,30 +766,19 @@ void CmndZbSend(void) {
|
|||
}
|
||||
// from here we have one and only one command
|
||||
|
||||
// collate information in a ready to send packet
|
||||
ZigbeeZCLSendMessage packet({
|
||||
device,
|
||||
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
|
||||
});
|
||||
zcl.clusterSpecific = false; /* not cluster specific */
|
||||
zcl.needResponse = false; /* no response */
|
||||
zcl.direct = false; /* discover route */
|
||||
|
||||
if (val_cmd) {
|
||||
// "Send":{...commands...}
|
||||
// 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) {
|
||||
// "Read":{...attributes...}, "Read":attribute or "Read":[...attributes...]
|
||||
// we accept eitehr a number, a string, an array of numbers/strings, or a JSON object
|
||||
packet.cmd = ZCL_READ_ATTRIBUTES;
|
||||
ZbSendRead(val_read, packet);
|
||||
zcl.cmd = ZCL_READ_ATTRIBUTES;
|
||||
ZbSendRead(val_read, zcl);
|
||||
} else if (val_write) {
|
||||
// only KSON object
|
||||
if (!val_write.isObject()) {
|
||||
|
@ -831,8 +786,8 @@ void CmndZbSend(void) {
|
|||
return;
|
||||
}
|
||||
// "Write":{...attributes...}
|
||||
packet.cmd = ZCL_WRITE_ATTRIBUTES;
|
||||
ZbSendReportWrite(val_write, packet);
|
||||
zcl.cmd = ZCL_WRITE_ATTRIBUTES;
|
||||
ZbSendReportWrite(val_write, zcl);
|
||||
} else if (val_publish) {
|
||||
// "Publish":{...attributes...}
|
||||
// only KSON object
|
||||
|
@ -840,8 +795,8 @@ void CmndZbSend(void) {
|
|||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||
return;
|
||||
}
|
||||
packet.cmd = ZCL_REPORT_ATTRIBUTES;
|
||||
ZbSendReportWrite(val_publish, packet);
|
||||
zcl.cmd = ZCL_REPORT_ATTRIBUTES;
|
||||
ZbSendReportWrite(val_publish, zcl);
|
||||
} else if (val_response) {
|
||||
// "Report":{...attributes...}
|
||||
// only KSON object
|
||||
|
@ -849,13 +804,13 @@ void CmndZbSend(void) {
|
|||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||
return;
|
||||
}
|
||||
packet.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
||||
ZbSendReportWrite(val_response, packet);
|
||||
zcl.cmd = ZCL_READ_ATTRIBUTES_RESPONSE;
|
||||
ZbSendReportWrite(val_response, zcl);
|
||||
} else if (val_read_config) {
|
||||
// "ReadConfg":{...attributes...}, "ReadConfg":attribute or "ReadConfg":[...attributes...]
|
||||
// we accept eitehr a number, a string, an array of numbers/strings, or a JSON object
|
||||
packet.cmd = ZCL_READ_REPORTING_CONFIGURATION;
|
||||
ZbSendRead(val_read_config, packet);
|
||||
zcl.cmd = ZCL_READ_REPORTING_CONFIGURATION;
|
||||
ZbSendRead(val_read_config, zcl);
|
||||
} else if (val_config) {
|
||||
// "Config":{...attributes...}
|
||||
// only JSON object
|
||||
|
@ -863,8 +818,8 @@ void CmndZbSend(void) {
|
|||
ResponseCmndChar_P(PSTR(D_ZIGBEE_MISSING_PARAM));
|
||||
return;
|
||||
}
|
||||
packet.cmd = ZCL_CONFIGURE_REPORTING;
|
||||
ZbSendReportWrite(val_config, packet);
|
||||
zcl.cmd = ZCL_CONFIGURE_REPORTING;
|
||||
ZbSendReportWrite(val_config, zcl);
|
||||
} else {
|
||||
Response_P(PSTR("Missing zigbee 'Send', 'Write', 'Report' or 'Response'"));
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue