From 10cc4ed8db231f9fa719886485ce2597920d1cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 26 Nov 2020 18:22:55 +0100 Subject: [PATCH] Add philips hue zigbee plugin with hue dimmer switch support --- debian/control | 18 + .../nymea-plugin-zigbee-philipshue.install.in | 1 + nymea-plugins.pro | 1 + .../integrationpluginzigbee-philipshue.json | 107 ++++++ .../integrationpluginzigbeephilipshue.cpp | 321 ++++++++++++++++++ .../integrationpluginzigbeephilipshue.h | 76 +++++ ...340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts | 1 + zigbee-philipshue/zigbee-philipshue.pro | 9 + .../integrationpluginzigbeetradfri.cpp | 12 +- 9 files changed, 540 insertions(+), 6 deletions(-) create mode 100644 debian/nymea-plugin-zigbee-philipshue.install.in create mode 100644 zigbee-philipshue/integrationpluginzigbee-philipshue.json create mode 100644 zigbee-philipshue/integrationpluginzigbeephilipshue.cpp create mode 100644 zigbee-philipshue/integrationpluginzigbeephilipshue.h create mode 100644 zigbee-philipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts create mode 100644 zigbee-philipshue/zigbee-philipshue.pro diff --git a/debian/control b/debian/control index 4fc83b76..f06ac686 100644 --- a/debian/control +++ b/debian/control @@ -1061,6 +1061,23 @@ Description: nymea.io zigbee plugin for different generic recognizable lights . This package will install the nymea.io plugin for generic recognizable lights + +Package: nymea-plugin-zigbee-philipshue +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea-zigbee1, + nymea-plugins-translations, +Description: nymea.io zigbee plugin for Philips Hue devices + The nymea daemon is a plugin based IoT (Internet of Things) server. The + server works like a translator for devices, things and services and + allows them to interact. + With the powerful rule engine you are able to connect any device available + in the system and create individual scenes and behaviors for your environment. + . + This package will install the nymea.io plugin for Philips Hue zigbee devices + + Package: nymea-plugin-zigbee-tradfri Architecture: any Depends: ${shlibs:Depends}, @@ -1149,6 +1166,7 @@ Architecture: all Depends: nymea-plugin-zigbee-lumi, nymea-plugin-zigbee-generic, nymea-plugin-zigbee-generic-lights, + nymea-plugin-zigbee-philipshue, nymea-plugin-zigbee-tradfri Description: Zigbee plugins for nymea IoT server - meta package for all zigbee replated plugins The nymea daemon is a plugin based IoT (Internet of Things) server. The diff --git a/debian/nymea-plugin-zigbee-philipshue.install.in b/debian/nymea-plugin-zigbee-philipshue.install.in new file mode 100644 index 00000000..365ee14a --- /dev/null +++ b/debian/nymea-plugin-zigbee-philipshue.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginzigbee-philipshue.so diff --git a/nymea-plugins.pro b/nymea-plugins.pro index bb7c08e1..a2782cdb 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -67,6 +67,7 @@ PLUGIN_DIRS = \ zigbee-generic \ zigbee-generic-lights \ zigbee-lumi \ + zigbee-philipshue \ zigbee-tradfri \ diff --git a/zigbee-philipshue/integrationpluginzigbee-philipshue.json b/zigbee-philipshue/integrationpluginzigbee-philipshue.json new file mode 100644 index 00000000..c64dbaad --- /dev/null +++ b/zigbee-philipshue/integrationpluginzigbee-philipshue.json @@ -0,0 +1,107 @@ +{ + "name": "ZigbeePhilipsHue", + "displayName": "Zigbee Philips Hue", + "id": "0ca340b7-061a-42e6-ab7d-d7b4fd235d02", + "vendors": [ + { + "id": "0ae1e001-2aa6-47ed-b8c0-334c3728a68f", + "name": "philips", + "displayName": "Philips", + "thingClasses": [ + { + "name": "dimmerSwitch", + "displayName": "Hue dimmer switch", + "id": "b2711164-a848-4715-8ddf-33ca86f9f4cf", + "setupMethod": "JustAdd", + "createMethods": [ "Auto" ], + "interfaces": [ "multibutton", "batterylevel", "wirelessconnectable" ], + "paramTypes": [ + { + "id": "b221cad1-ef2e-4192-8168-11d0205a43da", + "name": "ieeeAddress", + "displayName": "IEEE adress", + "type": "QString", + "defaultValue": "00:00:00:00:00:00:00:00" + }, + { + "id": "d2bb97ee-caed-4776-8931-9fc0a04e4e8f", + "name": "networkUuid", + "displayName": "Zigbee network UUID", + "type": "QString", + "defaultValue": "" + } + ], + "stateTypes": [ + { + "id": "5ac101b2-4bb7-4b5c-8493-08b1ae7ca0c1", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "5a6e325e-a6ee-4a36-b429-f5d8c8adb80b", + "name": "signalStrength", + "displayName": "Signal strength", + "displayNameEvent": "Signal strength changed", + "defaultValue": 0, + "maxValue": 100, + "minValue": 0, + "type": "uint", + "unit": "Percentage" + }, + { + "id": "12139630-668a-4ad8-96fa-781028e9eced", + "name": "version", + "displayName": "Version", + "displayNameEvent": "Version changed", + "type": "QString", + "cached": true, + "defaultValue": "" + }, + { + "id": "3e28e0b3-fe23-4293-8876-8384def6c4fb", + "name": "batteryLevel", + "displayName": "Battery", + "displayNameEvent": "Battery changed", + "type": "int", + "unit": "Percentage", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100 + }, + { + "id": "4223a3bc-9616-4ed2-ae50-704b9df62d0e", + "name": "batteryCritical", + "displayName": "Battery critical", + "displayNameEvent": "Battery critical changed", + "type": "bool", + "defaultValue": false + } + ], + "actionTypes": [ + + ], + "eventTypes": [ + { + "id": "33bb5816-8479-4995-99e2-cb0443886003", + "name": "pressed", + "displayName": "Button pressed", + "paramTypes": [ + { + "id": "c086a247-838f-49c0-b1e4-2ae1ed181b55", + "name": "buttonName", + "displayName": "Button name", + "type": "QString", + "allowedValues": ["ON", "OFF", "DIM UP", "DIM DOWN"] + } + ] + } + ] + } + ] + } + ] +} diff --git a/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp b/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp new file mode 100644 index 00000000..5364546a --- /dev/null +++ b/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp @@ -0,0 +1,321 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io + +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "integrationpluginzigbeephilipshue.h" +#include "plugininfo.h" +#include "hardware/zigbee/zigbeehardwareresource.h" + +IntegrationPluginZigbeePhilipsHue::IntegrationPluginZigbeePhilipsHue() +{ + m_ieeeAddressParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingIeeeAddressParamTypeId; + + m_networkUuidParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingNetworkUuidParamTypeId; + + m_connectedStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchConnectedStateTypeId; + + m_signalStrengthStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchSignalStrengthStateTypeId; + + m_versionStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchVersionStateTypeId; + +} + +QString IntegrationPluginZigbeePhilipsHue::name() const +{ + return "Philips Hue"; +} + +bool IntegrationPluginZigbeePhilipsHue::handleNode(ZigbeeNode *node, const QUuid &networkUuid) +{ + // Make sure this is from Philips 0x100b + if (node->nodeDescriptor().manufacturerCode != Zigbee::Philips) + return false; + + bool handled = false; + + if (node->endpoints().count() == 2 && node->hasEndpoint(0x01) && node->hasEndpoint(0x02)) { + ZigbeeNodeEndpoint *endpointOne = node->getEndpoint(0x01); + ZigbeeNodeEndpoint *endpoinTwo = node->getEndpoint(0x02); + + // Dimmer switch + if (endpointOne->profile() == Zigbee::ZigbeeProfileLightLink && + endpointOne->deviceId() == Zigbee::LightLinkDeviceNonColourSceneController + && endpoinTwo->profile() == Zigbee::ZigbeeProfileHomeAutomation && + endpoinTwo->deviceId() == Zigbee::HomeAutomationDeviceSimpleSensor) { + + qCDebug(dcZigbeePhilipsHue()) << "Handeling Hue dimmer switch" << node << endpointOne << endpoinTwo; + createThing(dimmerSwitchThingClassId, networkUuid, node); + initDimmerSwitch(node); + return true; + } + } + + return handled; +} + +void IntegrationPluginZigbeePhilipsHue::handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid) +{ + Q_UNUSED(networkUuid) + + if (m_thingNodes.values().contains(node)) { + Thing *thing = m_thingNodes.key(node); + qCDebug(dcZigbeePhilipsHue()) << node << "for" << thing << "has left the network."; + m_thingNodes.remove(thing); + emit autoThingDisappeared(thing->id()); + } +} + +void IntegrationPluginZigbeePhilipsHue::init() +{ + hardwareManager()->zigbeeResource()->registerHandler(this, ZigbeeHardwareResource::HandlerTypeVendor); +} + +void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid(); + ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_ieeeAddressParamTypeIds.value(thing->thingClassId())).toString()); + ZigbeeNode *node = hardwareManager()->zigbeeResource()->claimNode(this, networkUuid, zigbeeAddress); + if (!node) { + qCWarning(dcZigbeePhilipsHue()) << "Zigbee node for" << info->thing()->name() << "not found."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + m_thingNodes.insert(thing, node); + + // Update connected state + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), node->reachable()); + connect(node, &ZigbeeNode::reachableChanged, thing, [thing, this](bool reachable){ + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), reachable); + }); + + // Update signal strength + thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), qRound(node->lqi() * 100.0 / 255.0)); + connect(node, &ZigbeeNode::lqiChanged, thing, [this, thing](quint8 lqi){ + uint signalStrength = qRound(lqi * 100.0 / 255.0); + qCDebug(dcZigbeePhilipsHue()) << thing << "signal strength changed" << signalStrength << "%"; + thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength); + }); + + + // Thing specific setup + if (thing->thingClassId() == dimmerSwitchThingClassId) { + ZigbeeNodeEndpoint *endpointZll = node->getEndpoint(0x01); + ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02); + + // Set the version + thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointZll->softwareBuildId()); + + + // Receive on/off commands + ZigbeeClusterOnOff *onOffCluster = endpointZll->outputCluster(ZigbeeClusterLibrary::ClusterIdOnOff); + if (!onOffCluster) { + qCWarning(dcZigbeePhilipsHue()) << "Could not find on/off client cluster on" << thing << endpointZll; + } else { + connect(onOffCluster, &ZigbeeClusterOnOff::commandSent, thing, [=](ZigbeeClusterOnOff::Command command){ + if (command == ZigbeeClusterOnOff::CommandOn) { + qCDebug(dcZigbeePhilipsHue()) << thing << "pressed ON"; + emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "ON"))); + } else { + qCWarning(dcZigbeePhilipsHue()) << thing << "unhandled command received" << command; + } + }); + + connect(onOffCluster, &ZigbeeClusterOnOff::commandOffWithEffectSent, thing, [=](ZigbeeClusterOnOff::Effect effect, quint8 effectVariant){ + qCDebug(dcZigbeePhilipsHue()) << thing << "OFF button pressed" << effect << effectVariant; + emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "OFF"))); + }); + } + + // Receive level control commands + ZigbeeClusterLevelControl *levelCluster = endpointZll->outputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl); + if (!levelCluster) { + qCWarning(dcZigbeePhilipsHue()) << "Could not find level client cluster on" << thing << endpointZll; + } else { + connect(levelCluster, &ZigbeeClusterLevelControl::commandStepSent, thing, [=](ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transitionTime){ + qCDebug(dcZigbeePhilipsHue()) << thing << "level button pressed" << fadeMode << stepSize << transitionTime; + switch (fadeMode) { + case ZigbeeClusterLevelControl::FadeModeUp: + qCDebug(dcZigbeePhilipsHue()) << thing << "DIM UP pressed"; + emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "DIM UP"))); + break; + case ZigbeeClusterLevelControl::FadeModeDown: + qCDebug(dcZigbeePhilipsHue()) << thing << "DIM DOWN pressed"; + emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "DIM DOWN"))); + break; + } + }); + } + + // Get battery level changes + ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->inputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration); + if (!powerCluster) { + qCWarning(dcZigbeePhilipsHue()) << "Could not find power configuration cluster on" << thing << endpointHa; + } else { + // Only set the initial state if the attribute already exists + if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) { + thing->setStateValue(dimmerSwitchBatteryLevelStateTypeId, powerCluster->batteryPercentage()); + thing->setStateValue(dimmerSwitchBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0)); + } + + connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){ + qCDebug(dcZigbeePhilipsHue()) << "Battery percentage changed" << percentage << "%" << thing; + thing->setStateValue(dimmerSwitchBatteryLevelStateTypeId, percentage); + thing->setStateValue(dimmerSwitchBatteryCriticalStateTypeId, (percentage < 10.0)); + }); + } + + } + + info->finish(Thing::ThingErrorNoError); +} + +void IntegrationPluginZigbeePhilipsHue::executeAction(ThingActionInfo *info) +{ + info->finish(Thing::ThingErrorUnsupportedFeature); +} + +void IntegrationPluginZigbeePhilipsHue::thingRemoved(Thing *thing) +{ + ZigbeeNode *node = m_thingNodes.take(thing); + if (node) { + QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid(); + hardwareManager()->zigbeeResource()->removeNodeFromNetwork(networkUuid, node); + } +} + +void IntegrationPluginZigbeePhilipsHue::createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node) +{ + ThingDescriptor descriptor(thingClassId); + QString deviceClassName = supportedThings().findById(thingClassId).displayName(); + descriptor.setTitle(deviceClassName); + + ParamList params; + params.append(Param(m_networkUuidParamTypeIds[thingClassId], networkUuid.toString())); + params.append(Param(m_ieeeAddressParamTypeIds[thingClassId], node->extendedAddress().toString())); + descriptor.setParams(params); + emit autoThingsAppeared({descriptor}); +} + +void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node) +{ + ZigbeeNodeEndpoint *endpointZll = node->getEndpoint(0x01); + ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02); + + // Get the current configured bindings for this node + ZigbeeReply *reply = node->removeAllBindings(); + connect(reply, &ZigbeeReply::finished, node, [=](){ + if (reply->error() != ZigbeeReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to remove all bindings for initialization of" << node; + } + + // Read battery, bind and configure attribute reporting for battery + if (!endpointHa->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpointHa; + return; + } + + qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes" << node; + ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); + connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){ + if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error(); + //emit nodeInitialized(node); + return; + } + + qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully"; + + // Bind the cluster to the coordinator + qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator IEEE address"; + ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, + hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster to coordinator" << zdoReply->error(); + return; + } + qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator finished successfully"; + + // Configure attribute rporting for battery remaining (0.5 % changes = 1) + ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; + reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; + reportingConfig.dataType = Zigbee::Uint8; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; + reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); + + qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for power configuration cluster to coordinator"; + ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); + connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ + if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error(); + return; + } + + qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + + qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator"; + ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpointZll->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind on/off cluster to coordinator" << zdoReply->error(); + return; + } + qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator finished successfully"; + + qCDebug(dcZigbeePhilipsHue()) << "Bind power level cluster to coordinator"; + ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpointZll->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, 0x0000); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind level cluster to coordinator" << zdoReply->error(); + return; + } + qCDebug(dcZigbeePhilipsHue()) << "Bind level cluster to coordinator finished successfully"; + + qCDebug(dcZigbeePhilipsHue()) << "Read binding table from node" << node; + ZigbeeReply *reply = node->readBindingTableEntries(); + connect(reply, &ZigbeeReply::finished, node, [=](){ + if (reply->error() != ZigbeeReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to read binding table from" << node; + } else { + foreach (const ZigbeeDeviceProfile::BindingTableListRecord &binding, node->bindingTableRecords()) { + qCDebug(dcZigbeePhilipsHue()) << node << binding; + } + } + }); + }); + }); + }); + }); + }); + }); +} + diff --git a/zigbee-philipshue/integrationpluginzigbeephilipshue.h b/zigbee-philipshue/integrationpluginzigbeephilipshue.h new file mode 100644 index 00000000..974b6128 --- /dev/null +++ b/zigbee-philipshue/integrationpluginzigbeephilipshue.h @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef INTEGRATIONPLUGINZIGBEEPHILIPSHUE_H +#define INTEGRATIONPLUGINZIGBEEPHILIPSHUE_H + +#include "integrations/integrationplugin.h" +#include "hardware/zigbee/zigbeehandler.h" +#include "plugintimer.h" + +#include + +class IntegrationPluginZigbeePhilipsHue: public IntegrationPlugin, public ZigbeeHandler +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginzigbee-philipshue.json") + Q_INTERFACES(IntegrationPlugin) + +public: + explicit IntegrationPluginZigbeePhilipsHue(); + + QString name() const override; + bool handleNode(ZigbeeNode *node, const QUuid &networkUuid) override; + void handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid) override; + + void init() override; + void setupThing(ThingSetupInfo *info) override; + void executeAction(ThingActionInfo *info) override; + void thingRemoved(Thing *thing) override; + +private: + PluginTimer *m_presenceTimer = nullptr; + QHash m_thingNodes; + + QHash m_ieeeAddressParamTypeIds; + QHash m_networkUuidParamTypeIds; + + QHash m_connectedStateTypeIds; + QHash m_signalStrengthStateTypeIds; + QHash m_versionStateTypeIds; + + void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node); + + void initDimmerSwitch(ZigbeeNode *node); + +}; + +#endif // INTEGRATIONPLUGINZIGBEEPHILIPSHUE_H diff --git a/zigbee-philipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts b/zigbee-philipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts new file mode 100644 index 00000000..dcd02922 --- /dev/null +++ b/zigbee-philipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zigbee-philipshue/zigbee-philipshue.pro b/zigbee-philipshue/zigbee-philipshue.pro new file mode 100644 index 00000000..945859b8 --- /dev/null +++ b/zigbee-philipshue/zigbee-philipshue.pro @@ -0,0 +1,9 @@ +include(../plugins.pri) + +PKGCONFIG += nymea-zigbee + +SOURCES += \ + integrationpluginzigbeephilipshue.cpp + +HEADERS += \ + integrationpluginzigbeephilipshue.h diff --git a/zigbee-tradfri/integrationpluginzigbeetradfri.cpp b/zigbee-tradfri/integrationpluginzigbeetradfri.cpp index 107a64a9..d49633af 100644 --- a/zigbee-tradfri/integrationpluginzigbeetradfri.cpp +++ b/zigbee-tradfri/integrationpluginzigbeetradfri.cpp @@ -394,8 +394,8 @@ void IntegrationPluginZigbeeTradfri::initOnOffSwitch(ZigbeeNode *node, ZigbeeNod ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 60;//300; - reportingConfig.maxReportingInterval = 120;//2700; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); qCDebug(dcZigbeeTradfri()) << "Configure attribute reporting for power configuration cluster to coordinator"; @@ -487,8 +487,8 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 60;//300; - reportingConfig.maxReportingInterval = 120;//2700; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); qCDebug(dcZigbeeTradfri()) << "Configure attribute reporting for power configuration cluster to coordinator"; @@ -585,8 +585,8 @@ void IntegrationPluginZigbeeTradfri::initPowerConfigurationCluster(ZigbeeNode *n ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 60;//300; - reportingConfig.maxReportingInterval = 120;//2700; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); qCDebug(dcZigbeeTradfri()) << "Configure attribute reporting for power configuration cluster to coordinator";