From e3ea65e8fada6c5ddb052f340855ee18eb897643 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 17 Jan 2021 18:51:22 +0100 Subject: [PATCH] Zigbee add RGB and RGBb to ZbInfo --- tasmota/xdrv_23_zigbee_2_devices.ino | 5 ++ tasmota/xdrv_23_zigbee_2a_devices_impl.ino | 4 + tasmota/xdrv_23_zigbee_5_converters.ino | 100 ++++++++++++++------- 3 files changed, 75 insertions(+), 34 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index d2515cd14..47247ddd5 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -236,6 +236,11 @@ public: inline void setX(uint16_t _x) { x = _x; } inline void setY(uint16_t _y) { y = _y; } + void toRGBAttributes(Z_attribute_list & attr_list) const ; + static void toRGBAttributesHSB(Z_attribute_list & attr_list, uint16_t hue, uint8_t sat, uint8_t brightness); + static void toRGBAttributesXYB(Z_attribute_list & attr_list, uint16_t x, uint16_t y, uint8_t brightness); + static void toRGBAttributesRGBb(Z_attribute_list & attr_list, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness); + static const Z_Data_Type type = Z_Data_Type::Z_Light; // 12 bytes uint8_t colormode; // 0x00: Hue/Sat, 0x01: XY, 0x02: CT | 0xFF not set, default 0x01 diff --git a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino index ec7d773e4..ffb5a72df 100644 --- a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino +++ b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino @@ -695,6 +695,9 @@ void Z_Device::jsonAddDataAttributes(Z_attribute_list & attr_list) const { // show internal data - mostly last known values for (auto & data_elt : data) { data_elt.toAttributes(attr_list); + if (data_elt.getType() == Z_Data_Type::Z_Light) { // since we don't have virtual methods, do an explicit test + ((Z_Data_Light&)data_elt).toRGBAttributes(attr_list); + } } } // Add "BatteryPercentage", "LastSeen", "LastSeenEpoch", "LinkQuality" @@ -728,6 +731,7 @@ void Z_Device::jsonLightState(Z_attribute_list & attr_list) const { if (light.validHue()) { attr_list.findOrCreateAttribute(PSTR("Hue")).setUInt(light.getHue()); } + light.toRGBAttributes(attr_list); } attr_list.addAttributePMEM(PSTR("Light")).setInt(light_mode); } diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 1f47204a0..674f6fdd0 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -509,8 +509,6 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = { { Zuint16, Cx0300, 0x003A, Z_(ColorPointBX), Cm1, 0 }, { Zuint16, Cx0300, 0x003B, Z_(ColorPointBY), Cm1, 0 }, { Zuint8, Cx0300, 0x003C, Z_(ColorPointBIntensity), Cm1, 0 }, - { Zoctstr, Cx0300, 0xFFF0, Z_(RGB), Cm1, 0 }, // synthetic argument to show color as RGB (converted from HueSat or XY) - { Zoctstr, Cx0300, 0xFFF1, Z_(RGBb), Cm1, 0 }, // synthetic argument to show color as RGB including last known brightness // Illuminance Measurement cluster { Zuint16, Cx0400, 0x0000, Z_(Illuminance), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_PIR, illuminance) }, // Illuminance (in Lux) @@ -1340,45 +1338,27 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) { case 0x03000003: // X case 0x03000004: // Y { // generate synthetic RGB - const Z_attribute * attr_rgb = attr_list.findAttribute(0x0300, 0xFFF0); + const Z_attribute * attr_rgb = attr_list.findAttribute(PSTR("RGB")); if (attr_rgb == nullptr) { // make sure we didn't already computed it - uint8_t r,g,b; - bool is_rgb = false; + uint8_t brightness = 255; + if (device.valid()) { + const Z_Data_Light & light = device.data.find(_srcendpoint); + if ((&light != nullptr) && (light.validDimmer())) { + // Dimmer has a valid value + brightness = changeUIntScale(light.getDimmer(), 0, 254, 0, 255); // range is 0..255 + } + } + const Z_attribute * attr_hue = attr_list.findAttribute(0x0300, 0x0000); const Z_attribute * attr_sat = attr_list.findAttribute(0x0300, 0x0001); const Z_attribute * attr_x = attr_list.findAttribute(0x0300, 0x0003); const Z_attribute * attr_y = attr_list.findAttribute(0x0300, 0x0004); if (attr_hue && attr_sat) { uint8_t sat = changeUIntScale(attr_sat->getUInt(), 0, 254, 0, 255); - HsToRgb(attr_hue->getUInt(), sat, &r, &g, &b); - is_rgb = true; - } else if (attr_x && attr_y) { - XyToRgb(attr_x->getUInt() / 65535.0f, attr_y->getUInt() / 65535.0f, &r, &g, &b); - is_rgb = true; - } - if (is_rgb) { - SBuffer rgb(3); - rgb.add8(r); - rgb.add8(g); - rgb.add8(b); - attr_list.addAttribute(0x0300, 0xFFF0).setBuf(rgb, 0, 3); - - // do we know ZbData for this bulb - uint8_t brightness = 255; - if (device.valid()) { - const Z_Data_Light & light = device.data.find(_srcendpoint); - if (light.validDimmer()) { - // Dimmer has a valid value - brightness = changeUIntScale(light.getDimmer(), 0, 254, 0, 255); // range is 0..255 - } - } - r = changeUIntScale(r, 0, 255, 0, brightness); - g = changeUIntScale(g, 0, 255, 0, brightness); - b = changeUIntScale(b, 0, 255, 0, brightness); - rgb.set8(0, r); - rgb.set8(1, g); - rgb.set8(2, b); - attr_list.addAttribute(0x0300, 0xFFF1).setBuf(rgb, 0, 3); + uint16_t hue = changeUIntScale(attr_hue->getUInt(), 0, 254, 0, 360); + Z_Data_Light::toRGBAttributesHSB(attr_list, hue, sat, brightness); + } else if (attr_x && attr_y) { + Z_Data_Light::toRGBAttributesXYB(attr_list, attr_x->getUInt(), attr_y->getUInt(), brightness); } } } @@ -2232,6 +2212,58 @@ void Z_Data::toAttributes(Z_attribute_list & attr_list) const { } } +// Add both attributes RGB and RGBb based on the inputs +// r,g,b are expected to be 100% brightness +// brightness is expected 0..255 +void Z_Data_Light::toRGBAttributesRGBb(Z_attribute_list & attr_list, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) { + SBuffer rgb(3); + rgb.add8(r); + rgb.add8(g); + rgb.add8(b); + attr_list.addAttribute(PSTR("RGB"), true).setBuf(rgb, 0, 3); + // now blend with brightness + r = changeUIntScale(r, 0, 255, 0, brightness); + g = changeUIntScale(g, 0, 255, 0, brightness); + b = changeUIntScale(b, 0, 255, 0, brightness); + rgb.set8(0, r); + rgb.set8(1, g); + rgb.set8(2, b); + attr_list.addAttribute(PSTR("RGBb"), true).setBuf(rgb, 0, 3); +} + +// Convert from Hue/Sat + Brightness to RGB+RGBb +// sat: 0..255 +// hue: 0..359 +// brightness: 0..255 +void Z_Data_Light::toRGBAttributesHSB(Z_attribute_list & attr_list, uint16_t hue, uint8_t sat, uint8_t brightness) { + uint8_t r,g,b; + HsToRgb(hue, sat, &r, &g, &b); + Z_Data_Light::toRGBAttributesRGBb(attr_list, r, g, b, brightness); +} + +// Convert X/Y to RGB and RGBb +// X: 0..65535 +// Y: 0..65535 +// brightness: 0..255 +void Z_Data_Light::toRGBAttributesXYB(Z_attribute_list & attr_list, uint16_t x, uint16_t y, uint8_t brightness) { + uint8_t r,g,b; + XyToRgb(x / 65535.0f, y / 65535.0f, &r, &g, &b); + Z_Data_Light::toRGBAttributesRGBb(attr_list, r, g, b, brightness); +} + +void Z_Data_Light::toRGBAttributes(Z_attribute_list & attr_list) const { + uint8_t brightness = 255; + if (validDimmer()) { + brightness = changeUIntScale(getDimmer(), 0, 254, 0, 255); // range is 0..255 + } + if (validHue() && validSat()) { + uint8_t sat = changeUIntScale(getSat(), 0, 254, 0, 255); + Z_Data_Light::toRGBAttributesHSB(attr_list, getHue(), sat, brightness); + } else if (validX() && validY()) { + Z_Data_Light::toRGBAttributesXYB(attr_list, getX(), getY(), brightness); + } +} + // // Check if this device needs Battery reporting // This is useful for IKEA or Philips devices that tend to drain battery quickly when Battery reporting is set