From e9c4a744091933e1a6774eab73b4ff345a8acee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 09:16:40 +0100 Subject: [PATCH] Add generic color light --- ...ntegrationpluginzigbee-generic-lights.json | 130 ++++++++ .../integrationpluginzigbeegenericlights.cpp | 305 ++++++++++++++++++ .../integrationpluginzigbeegenericlights.h | 6 + 3 files changed, 441 insertions(+) diff --git a/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json b/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json index b7266a54..3c43370f 100644 --- a/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json +++ b/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json @@ -335,6 +335,136 @@ ], "eventTypes": [ + ] + }, + { + "name": "colorLight", + "displayName": "Color Light", + "id": "8d157281-73c0-4d2c-96a0-572d26e9dd4f", + "setupMethod": "JustAdd", + "createMethods": [ "Auto" ], + "interfaces": [ "colorlight", "alert", "wirelessconnectable" ], + "paramTypes": [ + { + "id": "03afaef5-0f68-494e-9153-745ca878f894", + "name": "ieeeAddress", + "displayName": "IEEE address", + "type": "QString", + "defaultValue": "00:00:00:00:00:00:00:00" + }, + { + "id": "e409e8fe-9afa-407d-94fd-ec40f88f60f1", + "name": "networkUuid", + "displayName": "Zigbee network UUID", + "type": "QString", + "defaultValue": "" + }, + { + "id": "be14c4fe-5a19-4d0c-a546-2b68162ca707", + "name": "endpointId", + "displayName": "Endpoint ID", + "type": "uint", + "defaultValue": 1 + }, + { + "id": "787d0c2e-c475-4426-a0ba-fe8ec89b1a4d", + "name": "manufacturer", + "displayName": "Manufacturer", + "type": "QString", + "defaultValue": "" + }, + { + "id": "a1ef07bf-260a-48cc-b7cb-423cbbf860af", + "name": "model", + "displayName": "Model", + "type": "QString", + "defaultValue": "" + } + ], + "stateTypes": [ + { + "id": "bc56076a-cfa3-4f93-bbf5-2fe9b067cdc3", + "name": "connected", + "displayName": "Available", + "displayNameEvent": "Available changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "62789a2c-c6e6-47b4-b022-29a2d183f690", + "name": "signalStrength", + "displayName": "Signal strength", + "displayNameEvent": "Signal strength changed", + "defaultValue": 0, + "maxValue": 100, + "minValue": 0, + "type": "uint", + "unit": "Percentage" + }, + { + "id": "084b8268-4ae6-482d-b42b-67a57b5a7147", + "name": "version", + "displayName": "Version", + "displayNameEvent": "Version changed", + "type": "QString", + "cached": true, + "defaultValue": "" + }, + { + "id": "16cfb549-5347-4dc9-b5de-e4028cb4dddd", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Set power", + "type": "bool", + "defaultValue": false, + "writable": true + }, + { + "id": "7329b2eb-fb7e-4098-a551-c3ff24fc2962", + "name": "brightness", + "displayName": "Brightness", + "displayNameEvent": "Brightness changed", + "displayNameAction": "Set brightness", + "maxValue": 100, + "minValue": 0, + "type": "int", + "defaultValue": 100, + "writable": true + }, + { + "id": "c2817667-afd0-434b-b0a3-e020d2c90082", + "name": "colorTemperature", + "displayName": "Color temperature scaled", + "displayNameEvent": "Color temperature scaled changed", + "displayNameAction": "Set color temperature scaled", + "defaultValue": 100, + "minValue": 0, + "maxValue": 200, + "type": "int", + "writable": true + }, + { + "id": "51e8e6da-426c-4812-9c00-70f1356190dc", + "name": "color", + "displayName": "color", + "displayNameEvent": "color changed", + "displayNameAction": "Set color", + "type": "QColor", + "defaultValue": "#000000", + "writable": true + } + ], + "actionTypes": [ + { + "id": "062fa97d-50b6-48ee-ab74-03701e4c7220", + "name": "alert", + "displayName": "Identify" + } + ], + "eventTypes": [ + ] } ] diff --git a/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp b/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp index d3f5441f..1165a4ce 100644 --- a/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp +++ b/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp @@ -35,42 +35,52 @@ #include +#include + IntegrationPluginZigbeeGenericLights::IntegrationPluginZigbeeGenericLights() { // Common thing params map m_ieeeAddressParamTypeIds[onOffLightThingClassId] = onOffLightThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[dimmableLightThingClassId] = dimmableLightThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightThingIeeeAddressParamTypeId; + m_ieeeAddressParamTypeIds[colorLightThingClassId] = colorLightThingIeeeAddressParamTypeId; m_networkUuidParamTypeIds[onOffLightThingClassId] = onOffLightThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[dimmableLightThingClassId] = dimmableLightThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightThingNetworkUuidParamTypeId; + m_networkUuidParamTypeIds[colorLightThingClassId] = colorLightThingNetworkUuidParamTypeId; m_endpointIdParamTypeIds[onOffLightThingClassId] = onOffLightThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[dimmableLightThingClassId] = dimmableLightThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightThingEndpointIdParamTypeId; + m_endpointIdParamTypeIds[colorLightThingClassId] = colorLightThingEndpointIdParamTypeId; m_manufacturerIdParamTypeIds[onOffLightThingClassId] = onOffLightThingManufacturerParamTypeId; m_manufacturerIdParamTypeIds[dimmableLightThingClassId] = dimmableLightThingManufacturerParamTypeId; m_manufacturerIdParamTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightThingManufacturerParamTypeId; + m_manufacturerIdParamTypeIds[colorLightThingClassId] = colorLightThingManufacturerParamTypeId; m_modelIdParamTypeIds[onOffLightThingClassId] = onOffLightThingModelParamTypeId; m_modelIdParamTypeIds[dimmableLightThingClassId] = dimmableLightThingModelParamTypeId; m_modelIdParamTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightThingModelParamTypeId; + m_modelIdParamTypeIds[colorLightThingClassId] = colorLightThingModelParamTypeId; // Common sates map m_connectedStateTypeIds[onOffLightThingClassId] = onOffLightConnectedStateTypeId; m_connectedStateTypeIds[dimmableLightThingClassId] = dimmableLightConnectedStateTypeId; m_connectedStateTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightConnectedStateTypeId; + m_connectedStateTypeIds[colorLightThingClassId] = colorLightConnectedStateTypeId; m_signalStrengthStateTypeIds[onOffLightThingClassId] = onOffLightSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[dimmableLightThingClassId] = dimmableLightSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightSignalStrengthStateTypeId; + m_signalStrengthStateTypeIds[colorLightThingClassId] = colorLightSignalStrengthStateTypeId; m_versionStateTypeIds[onOffLightThingClassId] = onOffLightVersionStateTypeId; m_versionStateTypeIds[dimmableLightThingClassId] = dimmableLightVersionStateTypeId; m_versionStateTypeIds[colorTemperatureLightThingClassId] = colorTemperatureLightVersionStateTypeId; + m_versionStateTypeIds[colorLightThingClassId] = colorLightVersionStateTypeId; } QString IntegrationPluginZigbeeGenericLights::name() const @@ -111,6 +121,15 @@ bool IntegrationPluginZigbeeGenericLights::handleNode(ZigbeeNode *node, const QU createLightThing(colorTemperatureLightThingClassId, networkUuid, node, endpoint); return true; } + + if ((endpoint->profile() == Zigbee::ZigbeeProfileLightLink && endpoint->deviceId() == Zigbee::LightLinkDeviceColourLight) || + (endpoint->profile() == Zigbee::ZigbeeProfileLightLink && endpoint->deviceId() == Zigbee::LightLinkDeviceExtendedColourLight) || + (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceExtendedColourLight)) { + + qCDebug(dcZigbeeGenericLights()) << "Handeling color light for" << node << endpoint; + createLightThing(colorLightThingClassId, networkUuid, node, endpoint); + return true; + } } return false; @@ -340,6 +359,84 @@ void IntegrationPluginZigbeeGenericLights::setupThing(ThingSetupInfo *info) }); } + // Color temperature light + if (thing->thingClassId() == colorLightThingClassId) { + + // Get the on/off cluster + ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdOnOff); + if (!onOffCluster) { + qCWarning(dcZigbeeGenericLights()) << "Could not find on/off cluster for" << thing << "in" << node; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + // Only set the state if the cluster actually has the attribute + if (onOffCluster->hasAttribute(ZigbeeClusterOnOff::AttributeOnOff)) { + thing->setStateValue(colorLightPowerStateTypeId, onOffCluster->power()); + } + + // Update the power state if the node power value changes + connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){ + qCDebug(dcZigbeeGenericLights()) << thing << "power state changed" << power; + thing->setStateValue(colorLightPowerStateTypeId, power); + }); + + + // Get the level cluster + ZigbeeClusterLevelControl *levelCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl); + if (!levelCluster) { + qCWarning(dcZigbeeGenericLights()) << "Could not find level cluster for" << thing << "in" << node; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + // Only set the state if the cluster actually has the attribute + if (levelCluster->hasAttribute(ZigbeeClusterLevelControl::AttributeCurrentLevel)) { + int percentage = qRound(levelCluster->currentLevel() * 100.0 / 255.0); + thing->setStateValue(colorLightBrightnessStateTypeId, percentage); + } + + connect(levelCluster, &ZigbeeClusterLevelControl::currentLevelChanged, thing, [thing](quint8 level){ + int percentage = qRound(level * 100.0 / 255.0); + qCDebug(dcZigbeeGenericLights()) << thing << "level state changed" << level << percentage << "%"; + thing->setStateValue(colorLightBrightnessStateTypeId, percentage); + }); + + + // Get color cluster + ZigbeeClusterColorControl *colorCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdColorControl); + if (!colorCluster) { + qCWarning(dcZigbeeGenericLights()) << "Could not find color cluster for" << thing << "in" << node; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + // Only set the state if the cluster actually has the attribute + if (colorCluster->hasAttribute(ZigbeeClusterColorControl::AttributeColorTemperatureMireds)) { + int mappedValue = mapColorTemperatureToScaledValue(thing, colorCluster->colorTemperatureMireds()); + thing->setStateValue(colorLightColorTemperatureStateTypeId, mappedValue); + } + + connect(colorCluster, &ZigbeeClusterColorControl::colorTemperatureMiredsChanged, thing, [this, thing](quint16 colorTemperatureMired){ + qCDebug(dcZigbeeGenericLights()) << "Actual color temperature is" << colorTemperatureMired << "mireds"; + int mappedValue = mapColorTemperatureToScaledValue(thing, colorTemperatureMired); + qCDebug(dcZigbeeGenericLights()) << "Mapped color temperature is" << mappedValue; + thing->setStateValue(colorLightColorTemperatureStateTypeId, mappedValue); + }); + + // Read the states once the node gets reachable + connect(node, &ZigbeeNode::reachableChanged, thing, [thing, this](bool reachable){ + if (reachable) { + // Note: this will also read the color temperature range if available + readColorCapabilities(thing); + readLightPowerState(thing); + readLightLevelState(thing); + readLightColorXYState(thing); + } + }); + } + + info->finish(Thing::ThingErrorNoError); } @@ -428,6 +525,73 @@ void IntegrationPluginZigbeeGenericLights::executeAction(ThingActionInfo *info) } } + // Color light + if (thing->thingClassId() == colorLightThingClassId) { + if (info->action().actionTypeId() == colorLightAlertActionTypeId) { + executeAlertAction(info, endpoint); + return; + } + + if (info->action().actionTypeId() == colorLightPowerActionTypeId) { + bool power = info->action().param(colorLightPowerActionPowerParamTypeId).value().toBool(); + executePowerAction(info, endpoint, colorLightPowerStateTypeId, power); + return; + } + + if (info->action().actionTypeId() == colorLightBrightnessActionTypeId) { + int brightness = info->action().param(colorLightBrightnessActionBrightnessParamTypeId).value().toInt(); + quint8 level = static_cast(qRound(255.0 * brightness / 100.0)); + executeBrightnessAction(info, endpoint, colorLightPowerStateTypeId, colorLightBrightnessStateTypeId, brightness, level); + return; + } + + if (info->action().actionTypeId() == colorLightColorTemperatureActionTypeId) { + int colorTemperatureScaled = info->action().param(colorLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt(); + if (m_colorCapabilities[thing].testFlag(ZigbeeClusterColorControl::ColorCapabilityColorTemperature)) { + // Native color temperature available + executeColorTemperatureAction(info, endpoint, colorLightColorTemperatureStateTypeId, colorTemperatureScaled); + return; + } + + // Note: there is no color temperature capability, we have to emulate the color using default min/max values + // Convert the scaled value into the min/max color temperature interval + quint16 colorTemperature = mapScaledValueToColorTemperature(thing, colorTemperatureScaled); + qCDebug(dcZigbeeGenericLights()) << "Mapping action value" << colorTemperatureScaled << "to the color temperature in the range of [" << m_colorTemperatureRanges[thing].minValue << "," << m_colorTemperatureRanges[thing].maxValue << "] -->" << colorTemperature << "mired"; + // Note: the color temperature command/attribute is not supported. Using xy colors to interpolate the temperature colors + QColor temperatureColor = ZigbeeUtils::interpolateColorFromColorTemperature(colorTemperature, m_colorTemperatureRanges[thing].minValue, m_colorTemperatureRanges[thing].maxValue); + QPoint temperatureColorXyInt = ZigbeeUtils::convertColorToXYInt(temperatureColor); + qCDebug(dcZigbeeGenericLights()) << "Mapping interpolated value" << temperatureColor << "mired to the xy color" << temperatureColorXyInt; + + // Set color + ZigbeeClusterColorControl *colorCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdColorControl); + if (!colorCluster) { + qCWarning(dcZigbeeGenericLights()) << "Could not find color control cluster for" << thing << "in" << m_thingNodes.value(thing); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + ZigbeeClusterReply *reply = colorCluster->commandMoveToColor(temperatureColorXyInt.x(), temperatureColorXyInt.y(), 2); + connect(reply, &ZigbeeClusterReply::finished, info, [=](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + info->finish(Thing::ThingErrorHardwareFailure); + } else { + qCDebug(dcZigbeeGenericLights()) << "Set color temperature" << colorTemperature << "mired finished successfully" << "(scalled" << colorTemperatureScaled << ")"; + thing->setStateValue(colorLightColorTemperatureStateTypeId, colorTemperatureScaled); + info->finish(Thing::ThingErrorNoError); + } + }); + + return; + } + + if (info->action().actionTypeId() == colorLightColorActionTypeId) { + QColor color = info->action().param(colorLightColorActionColorParamTypeId).value().value(); + QPoint xyColorInt = ZigbeeUtils::convertColorToXYInt(color); + qCDebug(dcZigbeeGenericLights()) << "Set color" << color.toRgb() << xyColorInt; + executeColorAction(info, endpoint, colorLightColorStateTypeId, color); + return; + } + } info->finish(Thing::ThingErrorUnsupportedFeature); @@ -570,6 +734,30 @@ void IntegrationPluginZigbeeGenericLights::executeColorTemperatureAction(ThingAc }); } +void IntegrationPluginZigbeeGenericLights::executeColorAction(ThingActionInfo *info, ZigbeeNodeEndpoint *endpoint, const StateTypeId &colorStateTypeId, const QColor &color) +{ + Thing *thing = info->thing(); + ZigbeeClusterColorControl *colorCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdColorControl); + if (!colorCluster) { + qCWarning(dcZigbeeGenericLights()) << "Could not find color control cluster for" << thing << "in" << m_thingNodes.value(thing); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + // Note: time unit is 1/10 s + QPoint colorXyInt = ZigbeeUtils::convertColorToXYInt(color); + ZigbeeClusterReply *reply = colorCluster->commandMoveToColor(colorXyInt.x(), colorXyInt.y(), 2); + connect(reply, &ZigbeeClusterReply::finished, info, [=](){ + // Note: reply will be deleted automatically + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + info->finish(Thing::ThingErrorHardwareFailure); + } else { + info->finish(Thing::ThingErrorNoError); + thing->setStateValue(colorStateTypeId, color); + } + }); +} + void IntegrationPluginZigbeeGenericLights::readLightPowerState(Thing *thing) { // Get the node @@ -648,6 +836,123 @@ void IntegrationPluginZigbeeGenericLights::readLightColorTemperatureState(Thing }); } +void IntegrationPluginZigbeeGenericLights::readLightColorXYState(Thing *thing) +{ + ZigbeeNodeEndpoint *endpoint = findEndpoint(thing); + if (!endpoint) { + qCWarning(dcZigbeeGenericLights()) << "Failed to read color xy for" << thing << "because the node could not be found"; + return; + } + + // Get the color server cluster from the endpoint + ZigbeeClusterColorControl *colorCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdColorControl); + if (!colorCluster) { + qCWarning(dcZigbeeGenericLights()) << "Failed to read color xy for" << thing << "because the color cluster could not be found on" << endpoint; + return; + } + + ZigbeeClusterReply *reply = colorCluster->readAttributes({ZigbeeClusterColorControl::AttributeCurrentX, ZigbeeClusterColorControl::AttributeCurrentY}); + connect(reply, &ZigbeeClusterReply::finished, thing, [=](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeGenericLights()) << "Failed to read ColorControl cluster attribute" << reply->error(); + return; + } + + // Note: the attribute gets updated internally and the state gets updated with the currentLevelChanged signal + qCDebug(dcZigbeeGenericLights()) << "Reading ColorControl cluster attribute color x and y finished successfully"; + + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (attributeStatusRecords.count() != 2) { + qCWarning(dcZigbeeGenericLights()) << "Did not receive color x and y attribute values from" << thing; + return; + } + + // Parse the attribute status records and calculate the color + quint16 currentX = 0; quint16 currentY = 0; + foreach (const ZigbeeClusterLibrary::ReadAttributeStatusRecord &attributeStatusRecord, attributeStatusRecords) { + qCDebug(dcZigbeeGenericLights()) << "Received read attribute status record" << thing << attributeStatusRecord; + if (attributeStatusRecord.attributeId == ZigbeeClusterColorControl::AttributeCurrentX) { + bool valueOk = false; + currentX = attributeStatusRecord.dataType.toUInt16(&valueOk); + if (!valueOk) { + qCWarning(dcZigbeeGenericLights()) << "Failed to convert color x attribute values from" << thing << attributeStatusRecord; + return; + } + continue; + } + + if (attributeStatusRecord.attributeId == ZigbeeClusterColorControl::AttributeCurrentY) { + bool valueOk = false; + currentY = attributeStatusRecord.dataType.toUInt16(&valueOk); + if (!valueOk) { + qCWarning(dcZigbeeGenericLights()) << "Failed to convert color y attribute values from" << thing << attributeStatusRecord; + return; + } + continue; + } + } + + // Set the current color + QColor color = ZigbeeUtils::convertXYToColor(currentX, currentY); + qCDebug(dcZigbeeGenericLights()) << "Current color" << color.toRgb() << QPoint(currentX, currentY); + thing->setStateValue(colorLightColorStateTypeId, color); + }); +} + +void IntegrationPluginZigbeeGenericLights::readColorCapabilities(Thing *thing) +{ + ZigbeeNodeEndpoint *endpoint = findEndpoint(thing); + if (!endpoint) { + qCWarning(dcZigbeeGenericLights()) << "Failed to read color capabilities for" << thing << "because the node could not be found"; + return; + } + + // Get the color server cluster from the endpoint + ZigbeeClusterColorControl *colorCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdColorControl); + if (!colorCluster) { + qCWarning(dcZigbeeGenericLights()) << "Failed to read color color capabilities for" << thing << "because the color cluster could not be found on" << endpoint; + return; + } + + // Check if we know already the color capabilities for this lamp + if (colorCluster->hasAttribute(ZigbeeClusterColorControl::AttributeColorCapabilities)) { + m_colorCapabilities[thing] = colorCluster->colorCapabilities(); + qCDebug(dcZigbeeGenericLights()) << "Found cached color capabilities for" << thing << colorCluster->colorCapabilities(); + processColorCapabilities(thing); + return; + } + + // We have to read the color capabilities + ZigbeeClusterReply *reply = colorCluster->readAttributes({ZigbeeClusterColorControl::AttributeColorCapabilities}); + connect(reply, &ZigbeeClusterReply::finished, thing, [=](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeGenericLights()) << "Failed to read color capabilitie for" << thing << "because the node could not be found"; + return; + } + + m_colorCapabilities[thing] = colorCluster->colorCapabilities(); + processColorCapabilities(thing); + }); +} + +void IntegrationPluginZigbeeGenericLights::processColorCapabilities(Thing *thing) +{ + // Fetch all information required depending on the capabilities + qCDebug(dcZigbeeGenericLights()) << "Loading information depending on the lamp capabilities" << thing << m_colorCapabilities[thing]; + if (m_colorCapabilities[thing].testFlag(ZigbeeClusterColorControl::ColorCapabilityColorTemperature)) { + qCDebug(dcZigbeeGenericLights()) << "The lamp is capable of native controlling the color temperature"; + + // Read min/max value, otherwise emulate the color temperature using the color map + readColorTemperatureRange(thing); + } else { + qCDebug(dcZigbeeGenericLights()) << "The lamp has no native color temperature capability, emulating them using color map."; + + // TODO: continue with color fetching (xy, hsv, gamut values) + + qCDebug(dcZigbeeGenericLights()) << "Lamp capabilities information complete"; + } +} + void IntegrationPluginZigbeeGenericLights::readColorTemperatureRange(Thing *thing) { ZigbeeNodeEndpoint *endpoint = findEndpoint(thing); diff --git a/zigbee-generic-lights/integrationpluginzigbeegenericlights.h b/zigbee-generic-lights/integrationpluginzigbeegenericlights.h index b8be53fb..f14bb641 100644 --- a/zigbee-generic-lights/integrationpluginzigbeegenericlights.h +++ b/zigbee-generic-lights/integrationpluginzigbeegenericlights.h @@ -78,11 +78,13 @@ private: void executePowerAction(ThingActionInfo *info, ZigbeeNodeEndpoint *endpoint, const StateTypeId &powerStateTypeId, bool power); void executeBrightnessAction(ThingActionInfo *info, ZigbeeNodeEndpoint *endpoint, const StateTypeId &powerStateTypeId, const StateTypeId &brightnessStateTypeId, int brightness, quint8 level); void executeColorTemperatureAction(ThingActionInfo *info, ZigbeeNodeEndpoint *endpoint, const StateTypeId &colorTemperatureStateTypeId, int colorTemperatureScaled); + void executeColorAction(ThingActionInfo *info, ZigbeeNodeEndpoint *endpoint, const StateTypeId &colorStateTypeId, const QColor &color); // Read state values from the node void readLightPowerState(Thing *thing); void readLightLevelState(Thing *thing); void readLightColorTemperatureState(Thing *thing); + void readLightColorXYState(Thing *thing); // Color temperature information handling typedef struct ColorTemperatureRange { @@ -96,6 +98,10 @@ private: int m_maxScaleValue = 200; QHash m_colorTemperatureRanges; + QHash m_colorCapabilities; + + void readColorCapabilities(Thing *thing); + void processColorCapabilities(Thing *thing); void readColorTemperatureRange(Thing *thing); bool readCachedColorTemperatureRange(Thing *thing, ZigbeeClusterColorControl *colorCluster);