mirror of https://github.com/arendst/Tasmota.git
Merge pull request #16718 from s-hadinger/zigbee_alexa_multi_ep
Zigbee Alexa/Hue emulation, support multiple switches on separate endpoints
This commit is contained in:
commit
9e2f18c0a4
|
@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
|
|||
## [12.1.1.4]
|
||||
### Added
|
||||
- Support for Shelly Plus 2PM using template ``{"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3458,0,0,0,0,0,9472,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}``
|
||||
- Zigbee Alexa/Hue emulation, support multiple switches on separate endpoints
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -415,12 +415,14 @@ const char HueConfigResponse_JSON[] PROGMEM = "\x3D\xA7\xB3\xAC\x6B\x3D\x87\x99\
|
|||
|
||||
/********************************************************************************************/
|
||||
|
||||
String GetHueDeviceId(uint16_t id)
|
||||
String GetHueDeviceId(uint16_t id, uint8_t ep = 0)
|
||||
{
|
||||
char s[32];
|
||||
String deviceid = WiFi.macAddress();
|
||||
deviceid.toLowerCase();
|
||||
snprintf(s, sizeof(s), "%s:%02x:11-%02x", deviceid.c_str(), (id >> 8) & 0xFF, id & 0xFF);
|
||||
if (0x11 == ep) { ep = 0xFE; } // avoid collision with 0x11 which is used as default for `0`
|
||||
if (0 == ep) { ep = 0x11; } // if ep is zero, revert to original value
|
||||
snprintf(s, sizeof(s), "%s:%02x:%02X-%02x", deviceid.c_str(), (id >> 8) & 0xFF, ep, id & 0xFF);
|
||||
return String(s); // 5c:cf:7f:13:9f:3d:00:11-01
|
||||
}
|
||||
|
||||
|
@ -989,7 +991,7 @@ void HueLights(String *path_req)
|
|||
uint16_t shortaddr;
|
||||
device = DecodeLightIdZigbee(device_id, &shortaddr); // device is endpoint when in Zigbee mode
|
||||
if (shortaddr) {
|
||||
code = ZigbeeHandleHue(shortaddr, device_id, device, response);
|
||||
code = ZigbeeHandleHue(shortaddr, device, device_id, device, response);
|
||||
goto exit;
|
||||
}
|
||||
#endif // USE_ZIGBEE
|
||||
|
@ -1022,7 +1024,7 @@ void HueLights(String *path_req)
|
|||
uint16_t shortaddr;
|
||||
device = DecodeLightIdZigbee(device_id, &shortaddr);
|
||||
if (shortaddr) {
|
||||
code = ZigbeeHueStatus(&response, shortaddr);
|
||||
code = ZigbeeHueStatus(&response, shortaddr, device);
|
||||
goto exit;
|
||||
}
|
||||
#endif // USE_ZIGBEE
|
||||
|
|
|
@ -1010,7 +1010,7 @@ public:
|
|||
|
||||
inline void setReachable(bool _reachable) { reachable = _reachable; }
|
||||
inline bool getReachable(void) const { return reachable; }
|
||||
inline bool getPower(uint8_t ep =0) const;
|
||||
inline bool getPower(uint8_t ep = 0) const;
|
||||
|
||||
inline bool isRouter(void) const { return is_router; }
|
||||
inline bool isCoordinator(void) const { return 0x0000 == shortaddr; }
|
||||
|
@ -1066,8 +1066,8 @@ public:
|
|||
void setPower(bool power_on, uint8_t ep = 0);
|
||||
|
||||
// If light, returns the number of channels, or 0xFF if unknown
|
||||
int8_t getLightChannels(void) const {
|
||||
const Z_Data_Light & light = data.find<Z_Data_Light>(0);
|
||||
int8_t getLightChannels(uint8_t ep = 0) const {
|
||||
const Z_Data_Light & light = data.find<Z_Data_Light>(ep);
|
||||
if (&light != &z_data_unk) {
|
||||
return light.getConfig();
|
||||
} else {
|
||||
|
@ -1075,7 +1075,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setLightChannels(int8_t channels);
|
||||
int8_t getHueBulbtype(uint8_t ep = 0) const {
|
||||
int8_t light_profile = getLightChannels(ep);
|
||||
if (0x00 == (light_profile & 0xF0)) {
|
||||
return (light_profile & 0x07);
|
||||
} else {
|
||||
// not a bulb
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
void setLightChannels(int8_t channels, uint8_t ep);
|
||||
|
||||
static void setStringAttribute(char*& attr, const char * str);
|
||||
};
|
||||
|
@ -1097,9 +1106,10 @@ typedef enum Z_Def_Category {
|
|||
Z_CAT_PERMIT_JOIN, // timer to signal the end of the PermitJoin period
|
||||
// Below will clear based on device + cluster pair.
|
||||
Z_CLEAR_DEVICE_CLUSTER,
|
||||
Z_CAT_READ_CLUSTER,
|
||||
// none for now
|
||||
// Below will clear based on device + cluster + endpoint
|
||||
Z_CLEAR_DEVICE_CLUSTER_ENDPOINT,
|
||||
Z_CAT_READ_CLUSTER,
|
||||
Z_CAT_EP_DESC, // read endpoint descriptor to gather clusters
|
||||
Z_CAT_BIND, // send auto-binding to coordinator
|
||||
Z_CAT_CONFIG_ATTR, // send a config attribute reporting request
|
||||
|
@ -1183,10 +1193,10 @@ public:
|
|||
int32_t deviceRestore(JsonParserObject json);
|
||||
|
||||
// Hue support
|
||||
int8_t getHueBulbtype(uint16_t shortaddr) const ;
|
||||
int8_t getHueBulbtype(uint16_t shortaddr, uint8_t ep = 0) const ;
|
||||
void hideHueBulb(uint16_t shortaddr, bool hidden);
|
||||
bool isHueBulbHidden(uint16_t shortaddr) const ;
|
||||
Z_Data_Light & getLight(uint16_t shortaddr);
|
||||
Z_Data_Light & getLight(uint16_t shortaddr, uint8_t ep = 0);
|
||||
|
||||
// device is reachable
|
||||
void deviceWasReached(uint16_t shortaddr);
|
||||
|
|
|
@ -413,38 +413,47 @@ uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) {
|
|||
}
|
||||
|
||||
// returns: dirty flag, did we change the value of the object
|
||||
void Z_Device::setLightChannels(int8_t channels) {
|
||||
void Z_Device::setLightChannels(int8_t channels, uint8_t ep) {
|
||||
if (channels >= 0) {
|
||||
if (ep) { // if ep is not zero, the endpoint must exist
|
||||
bool found = false;
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
if (ep == endpoints[i]) { found = true; break; }
|
||||
}
|
||||
if (!found) {
|
||||
AddLog(LOG_LEVEL_INFO, D_LOG_ZIGBEE "cannot set light type to unknown ep=%i", ep);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// if ep == 0, use first endpoint, or zero if no endpoint is known
|
||||
ep = endpoints[0];
|
||||
}
|
||||
// retrieve of create light object
|
||||
Z_Data_Light & light = data.get<Z_Data_Light>(0);
|
||||
Z_Data_Light & light = data.get<Z_Data_Light>(ep);
|
||||
if (channels != light.getConfig()) {
|
||||
light.setConfig(channels);
|
||||
zigbee_devices.dirty();
|
||||
}
|
||||
Z_Data_OnOff & onoff = data.get<Z_Data_OnOff>(0);
|
||||
Z_Data_OnOff & onoff = data.get<Z_Data_OnOff>(ep);
|
||||
(void)onoff;
|
||||
} else {
|
||||
// remove light / onoff object if any
|
||||
for (auto & data_elt : data) {
|
||||
if ((data_elt.getType() == Z_Data_Type::Z_Light) ||
|
||||
(data_elt.getType() == Z_Data_Type::Z_OnOff)) {
|
||||
if (ep == 0 || data_elt.getEndpoint() == ep) { // if remove ep==0 then remove all definitions
|
||||
// remove light object
|
||||
data.remove(&data_elt);
|
||||
zigbee_devices.dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t Z_Devices::getHueBulbtype(uint16_t shortaddr) const {
|
||||
int8_t Z_Devices::getHueBulbtype(uint16_t shortaddr, uint8_t ep) const {
|
||||
const Z_Device &device = findShortAddr(shortaddr);
|
||||
int8_t light_profile = device.getLightChannels();
|
||||
if (0x00 == (light_profile & 0xF0)) {
|
||||
return (light_profile & 0x07);
|
||||
} else {
|
||||
// not a bulb
|
||||
return -1;
|
||||
}
|
||||
return device.getHueBulbtype(ep);
|
||||
}
|
||||
|
||||
void Z_Devices::hideHueBulb(uint16_t shortaddr, bool hidden) {
|
||||
|
@ -1001,8 +1010,8 @@ int32_t Z_Devices::deviceRestore(JsonParserObject json) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
Z_Data_Light & Z_Devices::getLight(uint16_t shortaddr) {
|
||||
return getShortAddr(shortaddr).data.get<Z_Data_Light>();
|
||||
Z_Data_Light & Z_Devices::getLight(uint16_t shortaddr, uint8_t ep) {
|
||||
return getShortAddr(shortaddr).data.get<Z_Data_Light>(ep);
|
||||
}
|
||||
|
||||
bool Z_Devices::isTuyaProtocol(uint16_t shortaddr, uint8_t ep) const {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
// Add global functions for Hue Emulation
|
||||
|
||||
// idx: index in the list of zigbee_devices
|
||||
void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, String *response) {
|
||||
void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t ep, uint8_t local_light_subtype, String *response) {
|
||||
static const char HUE_LIGHTS_STATUS_JSON1_SUFFIX_ZIGBEE[] PROGMEM =
|
||||
"%s\"alert\":\"none\","
|
||||
"\"effect\":\"none\","
|
||||
|
@ -41,7 +41,7 @@ void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, Stri
|
|||
uint32_t echo_gen = findEchoGeneration(); // 1 for 1st gen =+ Echo Dot 2nd gen, 2 for 2nd gen and above
|
||||
|
||||
const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
|
||||
const Z_Data_Light & light = device.data.find<Z_Data_Light>();
|
||||
const Z_Data_Light & light = device.data.find<Z_Data_Light>(ep);
|
||||
if (&light != &z_data_unk) {
|
||||
bri = light.getDimmer();
|
||||
colormode = light.getColorMode();
|
||||
|
@ -51,7 +51,7 @@ void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, Stri
|
|||
x = light.getX();
|
||||
y = light.getY();
|
||||
}
|
||||
power = device.getPower();
|
||||
power = device.getPower(ep);
|
||||
reachable = device.getReachable();
|
||||
|
||||
if (bri > 254) bri = 254; // Philips Hue bri is between 1 and 254
|
||||
|
@ -89,29 +89,45 @@ void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, Stri
|
|||
free(buf);
|
||||
}
|
||||
|
||||
void HueLightStatus2Zigbee(uint16_t shortaddr, String *response)
|
||||
void HueLightStatus2Zigbee(uint16_t shortaddr, uint8_t ep, String *response)
|
||||
{
|
||||
const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
|
||||
const char * friendlyName = device.friendlyName;
|
||||
const char * modelId = device.modelId;
|
||||
const char * manufacturerId = device.manufacturerId;
|
||||
char shortaddrname[8];
|
||||
snprintf_P(shortaddrname, sizeof(shortaddrname), PSTR("0x%04X"), shortaddr);
|
||||
|
||||
char* buf = HueLightStatus2Generic((friendlyName) ? friendlyName : shortaddrname,
|
||||
char name[32+4];
|
||||
const char * local_friendfly_name = device.ep_names.getEPName(ep != 0 ? ep : device.endpoints[0]); // try endpoint, if `0` then found nothing
|
||||
if (local_friendfly_name != nullptr) {
|
||||
snprintf_P(name, sizeof(name), PSTR("%s"), local_friendfly_name);
|
||||
} else if (friendlyName != nullptr) {
|
||||
if (ep == 0 || ep == device.endpoints[0]) { // default endpoint, no suffix
|
||||
snprintf_P(name, sizeof(name), PSTR("%s"), friendlyName);
|
||||
} else { // no endpoint specific name so add suffix
|
||||
snprintf_P(name, sizeof(name), PSTR("%s-%i"), friendlyName, ep);
|
||||
}
|
||||
} else {
|
||||
if (ep == 0 || ep == device.endpoints[0]) { // default endpoint, no suffix
|
||||
snprintf_P(name, sizeof(name), PSTR("0x%04X"), shortaddr);
|
||||
} else {
|
||||
snprintf_P(name, sizeof(name), PSTR("0x%04X-%i"), shortaddr, ep);
|
||||
}
|
||||
}
|
||||
|
||||
char* buf = HueLightStatus2Generic(name,
|
||||
(modelId) ? modelId : PSTR("Unknown"),
|
||||
(manufacturerId) ? manufacturerId : PSTR("Tasmota"),
|
||||
GetHueDeviceId(shortaddr).c_str());
|
||||
GetHueDeviceId(shortaddr, ep).c_str());
|
||||
*response += buf;
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int32_t ZigbeeHueStatus(String * response, uint16_t shortaddr) {
|
||||
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr);
|
||||
int32_t ZigbeeHueStatus(String * response, uint16_t shortaddr, uint8_t ep) {
|
||||
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr, ep);
|
||||
if (bulbtype >= 0) { // respond only if eligible
|
||||
*response += F("{\"state\":");
|
||||
HueLightStatus1Zigbee(shortaddr, zigbee_devices.getHueBulbtype(shortaddr), response);
|
||||
HueLightStatus2Zigbee(shortaddr, response);
|
||||
HueLightStatus1Zigbee(shortaddr, ep, zigbee_devices.getHueBulbtype(shortaddr, ep), response);
|
||||
HueLightStatus2Zigbee(shortaddr, ep, response);
|
||||
return 200;
|
||||
} else {
|
||||
return -3;
|
||||
|
@ -120,40 +136,51 @@ int32_t ZigbeeHueStatus(String * response, uint16_t shortaddr) {
|
|||
|
||||
void ZigbeeCheckHue(String & response, bool * appending) {
|
||||
uint32_t zigbee_num = zigbee_devices.devicesSize();
|
||||
for (uint32_t i = 0; i < zigbee_num; i++) {
|
||||
uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr;
|
||||
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr);
|
||||
for (uint32_t idx = 0; idx < zigbee_num; idx++) {
|
||||
const Z_Device & device = zigbee_devices.devicesAt(idx);
|
||||
uint16_t shortaddr = device.shortaddr;
|
||||
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
uint8_t ep = device.endpoints[i];
|
||||
if (i > 0 && ep == 0) { break; }
|
||||
int8_t bulbtype = device.getHueBulbtype(ep);
|
||||
if (bulbtype >= 0) {
|
||||
// this bulb is advertized
|
||||
if (*appending) { response += ","; }
|
||||
response += "\"";
|
||||
response += EncodeLightIdZigbee(0, shortaddr);
|
||||
response += EncodeLightIdZigbee((i == 0) ? 0 : ep, shortaddr);
|
||||
response += F("\":{\"state\":");
|
||||
HueLightStatus1Zigbee(shortaddr, bulbtype, &response); // TODO
|
||||
HueLightStatus2Zigbee(shortaddr, &response);
|
||||
HueLightStatus1Zigbee(shortaddr, ep, bulbtype, &response);
|
||||
HueLightStatus2Zigbee(shortaddr, (i == 0) ? 0 : ep, &response); // if first endpoint ,announce as `0`
|
||||
*appending = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeHueGroups(String * lights) {
|
||||
uint32_t zigbee_num = zigbee_devices.devicesSize();
|
||||
for (uint32_t i = 0; i < zigbee_num; i++) {
|
||||
uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr;
|
||||
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr);
|
||||
for (uint32_t idx = 0; idx < zigbee_num; idx++) {
|
||||
const Z_Device & device = zigbee_devices.devicesAt(idx);
|
||||
uint16_t shortaddr = device.shortaddr;
|
||||
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
uint8_t ep = device.endpoints[i];
|
||||
if (i > 0 && ep == 0) { break; } // no more endpoints
|
||||
int8_t bulbtype = device.getHueBulbtype(ep);
|
||||
if (bulbtype >= 0) {
|
||||
*lights += ",\"";
|
||||
*lights += EncodeLightIdZigbee(0, shortaddr);
|
||||
*lights += EncodeLightIdZigbee((i == 0) ? 0 : ep, shortaddr); // if first endpont, announce as `0`
|
||||
*lights += "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeSendHue(uint16_t shortaddr, uint16_t cluster, uint8_t cmd, const SBuffer & s) {
|
||||
void ZigbeeSendHue(uint16_t shortaddr, uint8_t ep, uint16_t cluster, uint8_t cmd, const SBuffer & s) {
|
||||
ZCLFrame zcl(s.len());
|
||||
zcl.shortaddr = shortaddr;
|
||||
zcl.dstendpoint = ep; // if set to `0`, we will use the first endpoint
|
||||
zcl.cluster = cluster;
|
||||
zcl.cmd = cmd;
|
||||
zcl.clusterSpecific = true;
|
||||
|
@ -165,69 +192,69 @@ void ZigbeeSendHue(uint16_t shortaddr, uint16_t cluster, uint8_t cmd, const SBuf
|
|||
|
||||
// Send commands
|
||||
// Power On/Off
|
||||
void ZigbeeHuePower(uint16_t shortaddr, bool power) {
|
||||
void ZigbeeHuePower(uint16_t shortaddr, uint8_t ep, bool power) {
|
||||
SBuffer s(0);
|
||||
ZigbeeSendHue(shortaddr, 0x0006, power ? 1 : 0, s);
|
||||
zigbee_devices.getShortAddr(shortaddr).setPower(power, 0);
|
||||
ZigbeeSendHue(shortaddr, ep, 0x0006, power ? 1 : 0, s);
|
||||
zigbee_devices.getShortAddr(shortaddr).setPower(power, ep);
|
||||
}
|
||||
|
||||
// Dimmer
|
||||
void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) {
|
||||
void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t ep, uint8_t dimmer) {
|
||||
if (dimmer > 0xFE) { dimmer = 0xFE; }
|
||||
SBuffer s(4);
|
||||
s.add8(dimmer);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
ZigbeeSendHue(shortaddr, 0x0008, 0x04, s);
|
||||
zigbee_devices.getLight(shortaddr).setDimmer(dimmer);
|
||||
ZigbeeSendHue(shortaddr, ep, 0x0008, 0x04, s);
|
||||
zigbee_devices.getLight(shortaddr, ep).setDimmer(dimmer);
|
||||
}
|
||||
|
||||
// CT
|
||||
void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
|
||||
void ZigbeeHueCT(uint16_t shortaddr, uint8_t ep, uint16_t ct) {
|
||||
if (ct > 0xFEFF) { ct = 0xFEFF; }
|
||||
SBuffer s(4);
|
||||
s.add16(ct);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
ZigbeeSendHue(shortaddr, 0x0300, 0x0A, s);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||
ZigbeeSendHue(shortaddr, ep, 0x0300, 0x0A, s);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr, ep);
|
||||
light.setColorMode(2); // "ct"
|
||||
light.setCT(ct);
|
||||
}
|
||||
|
||||
// XY
|
||||
void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y) {
|
||||
void ZigbeeHueXY(uint16_t shortaddr, uint8_t ep, uint16_t x, uint16_t y) {
|
||||
if (x > 0xFEFF) { x = 0xFEFF; }
|
||||
if (y > 0xFEFF) { y = 0xFEFF; }
|
||||
SBuffer s(8);
|
||||
s.add16(x);
|
||||
s.add16(y);
|
||||
s.add16(0x000A); // transition time = 1s
|
||||
ZigbeeSendHue(shortaddr, 0x0300, 0x07, s);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||
ZigbeeSendHue(shortaddr, ep, 0x0300, 0x07, s);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr, ep);
|
||||
light.setColorMode(1); // "xy"
|
||||
light.setX(x);
|
||||
light.setY(y);
|
||||
}
|
||||
|
||||
// HueSat
|
||||
void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat) {
|
||||
void ZigbeeHueHS(uint16_t shortaddr, uint8_t ep, uint16_t hue, uint8_t sat) {
|
||||
uint8_t hue8 = changeUIntScale(hue, 0, 360, 0, 254);
|
||||
if (sat > 0xFE) { sat = 0xFE; }
|
||||
SBuffer s(4);
|
||||
s.add8(hue8);
|
||||
s.add8(sat);
|
||||
s.add16(0);
|
||||
ZigbeeSendHue(shortaddr, 0x0300, 0x06, s);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr);
|
||||
ZigbeeSendHue(shortaddr, ep, 0x0300, 0x06, s);
|
||||
Z_Data_Light & light = zigbee_devices.getLight(shortaddr, ep);
|
||||
light.setColorMode(0); // "hs"
|
||||
light.setSat(sat);
|
||||
light.setHue(hue);
|
||||
}
|
||||
|
||||
int32_t ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, uint8_t endpoint, String &response) {
|
||||
int32_t ZigbeeHandleHue(uint16_t shortaddr, uint8_t ep, uint32_t device_id, uint8_t endpoint, String &response) {
|
||||
uint8_t bri, sat;
|
||||
uint16_t ct, hue;
|
||||
|
||||
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr);
|
||||
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr, ep);
|
||||
if (bulbtype < 0) { // respond only if eligible
|
||||
response = F("{}");
|
||||
return 200;
|
||||
|
@ -259,9 +286,9 @@ int32_t ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, uint8_t endpoint
|
|||
device_id, on ? PSTR("true") : PSTR("false"));
|
||||
|
||||
if (on) {
|
||||
ZigbeeHuePower(shortaddr, 0x01);
|
||||
ZigbeeHuePower(shortaddr, ep, 0x01);
|
||||
} else {
|
||||
ZigbeeHuePower(shortaddr, 0x00);
|
||||
ZigbeeHuePower(shortaddr, ep, 0x00);
|
||||
}
|
||||
response += buf;
|
||||
resp = true;
|
||||
|
@ -280,7 +307,7 @@ int32_t ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, uint8_t endpoint
|
|||
if (LST_SINGLE <= bulbtype) {
|
||||
// extend bri value if set to max
|
||||
if (254 <= bri) { bri = 255; }
|
||||
ZigbeeHueDimmer(shortaddr, bri);
|
||||
ZigbeeHueDimmer(shortaddr, ep, bri);
|
||||
}
|
||||
resp = true;
|
||||
}
|
||||
|
@ -304,7 +331,7 @@ int32_t ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, uint8_t endpoint
|
|||
resp = true;
|
||||
uint16_t xi = x * 65536.0f;
|
||||
uint16_t yi = y * 65536.0f;
|
||||
ZigbeeHueXY(shortaddr, xi, yi);
|
||||
ZigbeeHueXY(shortaddr, ep, xi, yi);
|
||||
}
|
||||
bool huesat_changed = false;
|
||||
|
||||
|
@ -342,7 +369,7 @@ int32_t ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, uint8_t endpoint
|
|||
huesat_changed = true;
|
||||
}
|
||||
if (huesat_changed) {
|
||||
ZigbeeHueHS(shortaddr, hue, sat);
|
||||
ZigbeeHueHS(shortaddr, ep, hue, sat);
|
||||
}
|
||||
resp = true;
|
||||
}
|
||||
|
@ -358,7 +385,7 @@ int32_t ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, uint8_t endpoint
|
|||
device_id, PSTR("ct"), ct);
|
||||
response += buf;
|
||||
if ((LST_COLDWARM == bulbtype) || (LST_RGBW <= bulbtype)) {
|
||||
ZigbeeHueCT(shortaddr, ct);
|
||||
ZigbeeHueCT(shortaddr, ep, ct);
|
||||
}
|
||||
resp = true;
|
||||
}
|
||||
|
|
|
@ -972,7 +972,7 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const SBuffer &buf) {
|
|||
);
|
||||
// query the state of the bulb (for Alexa)
|
||||
uint32_t wait_ms = 2000; // wait for 2s
|
||||
Z_Query_Bulb(nwkAddr, wait_ms);
|
||||
Z_Query_Bulb(nwkAddr, 0xFF, wait_ms); // 0xFF means iterate on all endpoints
|
||||
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
// Continue the discovery process and auto-binding only if the device was unknown or if PermitJoin is ongoing
|
||||
|
@ -2118,24 +2118,39 @@ int32_t Z_Load_Data(uint8_t value) {
|
|||
return 0; // continue
|
||||
}
|
||||
|
||||
static void Z_Query_Bulb_inner(uint16_t shortaddr, uint8_t ep, uint32_t &wait_ms) {
|
||||
const uint32_t inter_message_ms = 100; // wait 100ms between messages
|
||||
if (ep == 0) { ep = zigbee_devices.findFirstEndpoint(shortaddr); }
|
||||
if (ep) {
|
||||
if (0 <= zigbee_devices.getHueBulbtype(shortaddr, ep)) {
|
||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, wait_ms, 0x0006, ep, Z_CAT_READ_CLUSTER, 0 /* value */, &Z_ReadAttrCallback);
|
||||
wait_ms += inter_message_ms;
|
||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, wait_ms, 0x0008, ep, Z_CAT_READ_CLUSTER, 0 /* value */, &Z_ReadAttrCallback);
|
||||
wait_ms += inter_message_ms;
|
||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, wait_ms, 0x0300, ep, Z_CAT_READ_CLUSTER, 0 /* value */, &Z_ReadAttrCallback);
|
||||
wait_ms += inter_message_ms;
|
||||
zigbee_devices.setTimer(shortaddr, 0, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, 0, ep, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable);
|
||||
wait_ms += 1000; // wait 1 second between devices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Query the state of a bulb (light) if its type allows it
|
||||
//
|
||||
void Z_Query_Bulb(uint16_t shortaddr, uint32_t &wait_ms) {
|
||||
const uint32_t inter_message_ms = 100; // wait 100ms between messages
|
||||
|
||||
if (0 <= zigbee_devices.getHueBulbtype(shortaddr)) {
|
||||
uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||
|
||||
if (endpoint) { // send only if we know the endpoint
|
||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, wait_ms, 0x0006, endpoint, Z_CAT_READ_CLUSTER, 0 /* value */, &Z_ReadAttrCallback);
|
||||
wait_ms += inter_message_ms;
|
||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, wait_ms, 0x0008, endpoint, Z_CAT_READ_CLUSTER, 0 /* value */, &Z_ReadAttrCallback);
|
||||
wait_ms += inter_message_ms;
|
||||
zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, wait_ms, 0x0300, endpoint, Z_CAT_READ_CLUSTER, 0 /* value */, &Z_ReadAttrCallback);
|
||||
wait_ms += inter_message_ms;
|
||||
zigbee_devices.setTimer(shortaddr, 0, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, 0, endpoint, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable);
|
||||
wait_ms += 1000; // wait 1 second between devices
|
||||
// ep==0 is default endpoint
|
||||
// ep==0xFF iterates on all endpoints
|
||||
void Z_Query_Bulb(uint16_t shortaddr, uint8_t ep, uint32_t &wait_ms) {
|
||||
if (ep != 0xFF) {
|
||||
Z_Query_Bulb_inner(shortaddr, ep, wait_ms); // try a single endpoint
|
||||
} else {
|
||||
// iterate on all endpoints
|
||||
const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
|
||||
if (!device.valid()) { return; }
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
ep = device.endpoints[i];
|
||||
if (ep == 0) { break; }
|
||||
Z_Query_Bulb_inner(shortaddr, ep, wait_ms); // try a single endpoint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2173,7 +2188,7 @@ int32_t Z_Query_Bulbs(uint8_t value) {
|
|||
uint32_t wait_ms = 1000; // start with 1.0 s delay
|
||||
for (uint32_t i = 0; i < zigbee_devices.devicesSize(); i++) {
|
||||
const Z_Device &device = zigbee_devices.devicesAt(i);
|
||||
Z_Query_Bulb(device.shortaddr, wait_ms);
|
||||
Z_Query_Bulb(device.shortaddr, 0xFF, wait_ms); // 0xFF means all endpoints
|
||||
}
|
||||
}
|
||||
return 0; // continue
|
||||
|
|
|
@ -1218,7 +1218,7 @@ void CmndZbModelId(void) {
|
|||
// Specify, read or erase a Light type for Hue/Alexa integration
|
||||
void CmndZbLight(void) {
|
||||
// Syntax is:
|
||||
// ZbLight <device_id>,<x> - assign a bulb type 0-5
|
||||
// ZbLight <device_id>,<x> - assign a bulb type 0-5, or -1 to remove
|
||||
// ZbLight <device_id> - display the current bulb type and status
|
||||
//
|
||||
// Where <device_id> can be: short_addr, long_addr, device_index, friendly_name
|
||||
|
@ -1226,18 +1226,20 @@ void CmndZbLight(void) {
|
|||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
|
||||
// check if parameters contain a comma ','
|
||||
char *p;
|
||||
strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
char *p = XdrvMailbox.data;
|
||||
char *device_id = strsep(&p, ","); // zigbee identifier
|
||||
char *bulbtype_str = strsep(&p, ","); // friendly name
|
||||
int32_t ep = (p != nullptr) ? strtol(p, nullptr, 10) : 0; // get endpoint number, or `0` if none
|
||||
|
||||
// parse first part, <device_id>
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(device_id, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; }
|
||||
|
||||
if (p) {
|
||||
int8_t bulbtype = strtol(p, nullptr, 10);
|
||||
if (bulbtype_str != nullptr) {
|
||||
int8_t bulbtype = strtol(bulbtype_str, nullptr, 10);
|
||||
if (bulbtype > 5) { bulbtype = 5; }
|
||||
if (bulbtype < -1) { bulbtype = -1; }
|
||||
device.setLightChannels(bulbtype);
|
||||
device.setLightChannels(bulbtype, ep); // assign by default to first endpoint, or 0 if no endpoint known
|
||||
}
|
||||
Z_attribute_list attr_list;
|
||||
device.jsonLightState(attr_list);
|
||||
|
@ -1271,7 +1273,7 @@ void CmndZbOccupancy(void) {
|
|||
|
||||
// check if parameters contain a comma ','
|
||||
char *p;
|
||||
strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
strtok_r(XdrvMailbox.data, ",", &p);
|
||||
|
||||
// parse first part, <device_id>
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered
|
||||
|
|
Loading…
Reference in New Issue