diff --git a/debian/control b/debian/control
index e1975c7a..770c31f1 100644
--- a/debian/control
+++ b/debian/control
@@ -6,6 +6,7 @@ Build-depends: libboblight-dev,
debhelper (>= 0.0.0),
libnymea1-dev (>= 0.17),
libnymea-mqtt-dev,
+ libnymea-zigbee-dev,
libqt5serialport5-dev,
libqt5websockets5-dev,
nymea-dev-tools:native,
@@ -1013,6 +1014,54 @@ Description: nymea.io plugin to connect to your Tado account
This package will install the nymea.io plugin for Tado
+Package: nymea-plugin-zigbee-lumi
+Architecture: any
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libnymea-zigbee1,
+ nymea-plugins-translations,
+Description: nymea.io zigbee plugin for lumi/aquara/xiaomi things
+ 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 Lumi
+
+
+Package: nymea-plugin-zigbee-generic
+Architecture: any
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libnymea-zigbee1,
+ nymea-plugins-translations,
+Description: nymea.io zigbee plugin for different generic recognizable 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 generic recognizable zigbee devices
+
+
+Package: nymea-plugin-zigbee-generic-lights
+Architecture: any
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libnymea-zigbee1,
+ nymea-plugins-translations,
+Description: nymea.io zigbee plugin for different generic recognizable lights
+ 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 generic recognizable lights
+
+
Package: nymea-plugins-translations
Section: misc
Architecture: all
@@ -1079,6 +1128,21 @@ Description: Plugins for nymea IoT server - the default plugin collection
.
This package will install the default nymea plugins.
+Package: nymea-plugins-zigbee
+Section: libs
+Architecture: all
+Depends: nymea-plugin-zigbee-lumi,
+ nymea-plugin-zigbee-generic,
+ nymea-plugin-zigbee-generic-lights
+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
+ 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 all nymea zigbee related plugins.
+
Package: nymea-plugins-maker
Section: libs
@@ -1125,6 +1189,7 @@ Package: nymea-plugins-all
Section: libs
Architecture: all
Depends: nymea-plugins,
+ nymea-plugins-zigbee,
nymea-plugin-simulation,
nymea-plugin-snapd,
nymea-plugins-maker,
diff --git a/debian/nymea-plugin-zigbee-generic-lights.install.in b/debian/nymea-plugin-zigbee-generic-lights.install.in
new file mode 100644
index 00000000..c02aec29
--- /dev/null
+++ b/debian/nymea-plugin-zigbee-generic-lights.install.in
@@ -0,0 +1 @@
+usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginzigbee-generic-lights.so
diff --git a/debian/nymea-plugin-zigbee-generic.install.in b/debian/nymea-plugin-zigbee-generic.install.in
new file mode 100644
index 00000000..c01e09e0
--- /dev/null
+++ b/debian/nymea-plugin-zigbee-generic.install.in
@@ -0,0 +1 @@
+usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginzigbee-generic.so
diff --git a/debian/nymea-plugin-zigbee-lumi.install.in b/debian/nymea-plugin-zigbee-lumi.install.in
new file mode 100644
index 00000000..357171e5
--- /dev/null
+++ b/debian/nymea-plugin-zigbee-lumi.install.in
@@ -0,0 +1 @@
+usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginzigbee-lumi.so
diff --git a/nymea-plugins.pro b/nymea-plugins.pro
index 5c1f18c6..13b45998 100644
--- a/nymea-plugins.pro
+++ b/nymea-plugins.pro
@@ -65,6 +65,7 @@ PLUGIN_DIRS = \
wemo \
ws2812fx \
zigbee-generic \
+ zigbee-generic-lights \
zigbee-lumi \
diff --git a/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json b/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json
new file mode 100644
index 00000000..b1185b55
--- /dev/null
+++ b/zigbee-generic-lights/integrationpluginzigbee-generic-lights.json
@@ -0,0 +1,110 @@
+{
+ "name": "ZigbeeGenericLights",
+ "displayName": "Zigbee Generic Lights",
+ "id": "ee67f87d-d4cc-4223-a9f3-79e47c0267e0",
+ "vendors": [
+ {
+ "name": "nymea",
+ "displayName": "nymea",
+ "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
+ "thingClasses": [
+ {
+ "name": "onOffLight",
+ "displayName": "On/Off Light",
+ "id": "7fbc3165-e618-4dc0-8255-8dac2cc08dfa",
+ "setupMethod": "JustAdd",
+ "createMethods": [ "Auto" ],
+ "interfaces": [ "light", "alert", "wirelessconnectable" ],
+ "paramTypes": [
+ {
+ "id": "1b434d5d-4fe4-439c-b842-3483e8e24820",
+ "name": "ieeeAddress",
+ "displayName": "IEEE address",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "b3e298de-140c-4d3d-be81-0a9792359275",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ },
+ {
+ "id": "fd8a6ae6-202b-4634-824f-8d4b187430fa",
+ "name": "endpointId",
+ "displayName": "Endpoint ID",
+ "type": "uint",
+ "defaultValue": 1
+ },
+ {
+ "id": "acb5e910-ed8b-4968-972e-5fc57f466b8a",
+ "name": "manufacturer",
+ "displayName": "Manufacturer",
+ "type": "QString",
+ "defaultValue": ""
+ },
+ {
+ "id": "3d942b2d-302a-4c42-8cf5-be2865736736",
+ "name": "model",
+ "displayName": "Model",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "7548ac08-4ea1-4dcd-98b9-9d58bbc06ab7",
+ "name": "connected",
+ "displayName": "Available",
+ "displayNameEvent": "Available changed",
+ "type": "bool",
+ "cached": false,
+ "defaultValue": false
+ },
+ {
+ "id": "5857943e-ed90-4321-966e-b56eddaf2441",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "defaultValue": 0,
+ "maxValue": 100,
+ "minValue": 0,
+ "type": "uint",
+ "unit": "Percentage"
+ },
+ {
+ "id": "f5b5e0b3-2c34-4ccc-baef-8e29b84e7a2b",
+ "name": "version",
+ "displayName": "Version",
+ "displayNameEvent": "Version changed",
+ "type": "QString",
+ "cached": true,
+ "defaultValue": ""
+ },
+ {
+ "id": "ae03155c-f17f-4d9f-bb40-157a8cb1f83c",
+ "name": "power",
+ "displayName": "Power",
+ "displayNameEvent": "Power changed",
+ "displayNameAction": "Set power",
+ "type": "bool",
+ "defaultValue": false,
+ "writable": true
+ }
+ ],
+ "actionTypes": [
+ {
+ "id": "9388290d-5db2-484a-a702-53a0d842d412",
+ "name": "alert",
+ "displayName": "Identify"
+ }
+ ],
+ "eventTypes": [
+
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp b/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp
new file mode 100644
index 00000000..7b7209ab
--- /dev/null
+++ b/zigbee-generic-lights/integrationpluginzigbeegenericlights.cpp
@@ -0,0 +1,261 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+*
+* 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 "integrationpluginzigbeegenericlights.h"
+#include "plugininfo.h"
+#include "hardware/zigbee/zigbeehardwareresource.h"
+
+#include
+
+IntegrationPluginZigbeeGenericLights::IntegrationPluginZigbeeGenericLights()
+{
+ m_ieeeAddressParamTypeIds[onOffLightThingClassId] = onOffLightThingIeeeAddressParamTypeId;
+
+ m_networkUuidParamTypeIds[onOffLightThingClassId] = onOffLightThingNetworkUuidParamTypeId;
+
+ m_endpointIdParamTypeIds[onOffLightThingClassId] = onOffLightThingEndpointIdParamTypeId;
+
+ m_connectedStateTypeIds[onOffLightThingClassId] = onOffLightConnectedStateTypeId;
+
+ m_signalStrengthStateTypeIds[onOffLightThingClassId] = onOffLightSignalStrengthStateTypeId;
+
+ m_versionStateTypeIds[onOffLightThingClassId] = onOffLightVersionStateTypeId;
+}
+
+QString IntegrationPluginZigbeeGenericLights::name() const
+{
+ return "Generic lights";
+}
+
+bool IntegrationPluginZigbeeGenericLights::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
+{
+ foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
+ if ((endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileLightLink &&
+ endpoint->deviceId() == Zigbee::LightLinkDevice::LightLinkDeviceOnOffLight) ||
+ (endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation &&
+ endpoint->deviceId() == Zigbee::HomeAutomationDeviceOnOffLight)) {
+
+ ThingDescriptor descriptor(onOffLightThingClassId);
+ QString deviceClassName = supportedThings().findById(onOffLightThingClassId).displayName();
+ descriptor.setTitle(QString("%1 (%2 - %3)").arg(deviceClassName).arg(endpoint->manufacturerName()).arg(endpoint->modelIdentifier()));
+ qCDebug(dcZigbeeGenericLights()) << "Handeling generic on/off light" << descriptor.title();
+
+ ParamList params;
+ params.append(Param(onOffLightThingNetworkUuidParamTypeId, networkUuid.toString()));
+ params.append(Param(onOffLightThingIeeeAddressParamTypeId, node->extendedAddress().toString()));
+ params.append(Param(onOffLightThingEndpointIdParamTypeId, endpoint->endpointId()));
+ params.append(Param(onOffLightThingModelParamTypeId, endpoint->modelIdentifier()));
+ params.append(Param(onOffLightThingManufacturerParamTypeId, endpoint->manufacturerName()));
+ descriptor.setParams(params);
+ emit autoThingsAppeared({descriptor});
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void IntegrationPluginZigbeeGenericLights::handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid)
+{
+ Q_UNUSED(networkUuid)
+
+ if (m_thingNodes.values().contains(node)) {
+ Thing *thing = m_thingNodes.key(node);
+ qCDebug(dcZigbeeGenericLights()) << node << "for" << thing << "has left the network.";
+ m_thingNodes.remove(thing);
+ emit autoThingDisappeared(thing->id());
+ }
+}
+
+void IntegrationPluginZigbeeGenericLights::init()
+{
+ hardwareManager()->zigbeeResource()->registerHandler(this, ZigbeeHardwareResource::HandlerTypeCatchAll);
+}
+
+void IntegrationPluginZigbeeGenericLights::setupThing(ThingSetupInfo *info)
+{
+ Thing *thing = info->thing();
+
+ // Get the node for this 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()->getNode(networkUuid, zigbeeAddress);
+ if (!node) {
+ qCWarning(dcZigbeeGenericLights()) << "Zigbee node for" << info->thing()->name() << "not found.´";
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+
+ // Store the node thing association for removing
+ m_thingNodes.insert(thing, node);
+
+ // Get the endpoint for this thing
+ ZigbeeNodeEndpoint *endpoint = findEndpoint(thing);
+ if (!endpoint) {
+ qCWarning(dcZigbeeGenericLights()) << "Unable to get the endpoint from node" << node << "for" << thing;
+ info->finish(Thing::ThingErrorSetupFailed);
+ return;
+ }
+
+ // General thing setup
+
+ // 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(dcZigbeeGenericLights()) << thing << "signal strength changed" << signalStrength << "%";
+ thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength);
+ });
+
+ // Set the version
+ thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpoint->softwareBuildId());
+
+ // Thing specific setup
+ if (thing->thingClassId() == onOffLightThingClassId) {
+
+ 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;
+ }
+
+ connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){
+ qCDebug(dcZigbeeGenericLights()) << thing << "power state changed" << power;
+ thing->setStateValue(onOffLightPowerStateTypeId, power);
+ });
+
+ }
+
+ info->finish(Thing::ThingErrorNoError);
+}
+
+void IntegrationPluginZigbeeGenericLights::executeAction(ThingActionInfo *info)
+{
+ if (!hardwareManager()->zigbeeResource()->available()) {
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+
+ // Get the node
+ Thing *thing = info->thing();
+ ZigbeeNode *node = m_thingNodes.value(thing);
+ if (!node->reachable()) {
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+
+ // Get the endpoint
+ ZigbeeNodeEndpoint *endpoint = findEndpoint(thing);
+ if (!endpoint) {
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+
+ if (thing->thingClassId() == onOffLightThingClassId) {
+
+ if (info->action().actionTypeId() == onOffLightAlertActionTypeId) {
+ // Get the identify server cluster from the endpoint
+ ZigbeeClusterIdentify *identifyCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdIdentify);
+ if (!identifyCluster) {
+ qCWarning(dcZigbeeGenericLights()) << "Could not find identify cluster for" << thing << "in" << node;
+ info->finish(Thing::ThingErrorHardwareFailure);
+ return;
+ }
+
+ // Send the command trough the network
+ ZigbeeClusterReply *reply = identifyCluster->identify(2);
+ connect(reply, &ZigbeeClusterReply::finished, this, [reply, info](){
+ // Note: reply will be deleted automatically
+ if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
+ info->finish(Thing::ThingErrorHardwareFailure);
+ } else {
+ info->finish(Thing::ThingErrorNoError);
+ }
+ });
+ return;
+ }
+
+ if (info->action().actionTypeId() == onOffLightPowerActionTypeId) {
+ // Get the identify server cluster from the endpoint
+ 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;
+ }
+
+ // Send the command trough the network
+ bool power = info->action().param(onOffLightPowerActionPowerParamTypeId).value().toBool();
+ ZigbeeClusterReply *reply = (power ? onOffCluster->commandOn() : onOffCluster->commandOff());
+ connect(reply, &ZigbeeClusterReply::finished, thing, [reply, info, power, thing](){
+ // Note: reply will be deleted automatically
+ if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
+ info->finish(Thing::ThingErrorHardwareFailure);
+ } else {
+ info->finish(Thing::ThingErrorNoError);
+ thing->setStateValue(onOffLightPowerStateTypeId, power);
+ }
+ });
+ return;
+ }
+ }
+
+ info->finish(Thing::ThingErrorUnsupportedFeature);
+}
+
+void IntegrationPluginZigbeeGenericLights::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);
+ }
+}
+
+ZigbeeNodeEndpoint *IntegrationPluginZigbeeGenericLights::findEndpoint(Thing *thing)
+{
+ ZigbeeNode *node = m_thingNodes.value(thing);
+ if (!node) {
+ qCWarning(dcZigbeeGenericLights()) << "Could not find the node for" << thing;
+ return nullptr;
+ }
+
+ quint8 endpointId = thing->paramValue(m_endpointIdParamTypeIds.value(thing->thingClassId())).toUInt();
+ return node->getEndpoint(endpointId);
+}
diff --git a/zigbee-generic-lights/integrationpluginzigbeegenericlights.h b/zigbee-generic-lights/integrationpluginzigbeegenericlights.h
new file mode 100644
index 00000000..6854b65f
--- /dev/null
+++ b/zigbee-generic-lights/integrationpluginzigbeegenericlights.h
@@ -0,0 +1,71 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 INTEGRATIONPLUGINZIGBEEGENERICLIGHTS_H
+#define INTEGRATIONPLUGINZIGBEEGENERICLIGHTS_H
+
+#include "integrations/integrationplugin.h"
+#include "hardware/zigbee/zigbeehandler.h"
+
+class IntegrationPluginZigbeeGenericLights: public IntegrationPlugin, public ZigbeeHandler
+{
+ Q_OBJECT
+
+ Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginzigbee-generic-lights.json")
+ Q_INTERFACES(IntegrationPlugin)
+
+public:
+ explicit IntegrationPluginZigbeeGenericLights();
+
+ 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:
+ QHash m_ieeeAddressParamTypeIds;
+ QHash m_networkUuidParamTypeIds;
+ QHash m_endpointIdParamTypeIds;
+
+ QHash m_connectedStateTypeIds;
+ QHash m_signalStrengthStateTypeIds;
+ QHash m_versionStateTypeIds;
+
+ QHash m_thingNodes;
+
+ ZigbeeNodeEndpoint *findEndpoint(Thing *thing);
+
+};
+
+#endif // INTEGRATIONPLUGINZIGBEEGENERICLIGHTS_H
diff --git a/zigbee-generic-lights/zigbee-generic-lights.pro b/zigbee-generic-lights/zigbee-generic-lights.pro
new file mode 100644
index 00000000..5561cbf7
--- /dev/null
+++ b/zigbee-generic-lights/zigbee-generic-lights.pro
@@ -0,0 +1,9 @@
+include(../plugins.pri)
+
+PKGCONFIG += nymea-zigbee
+
+SOURCES += \
+ integrationpluginzigbeegenericlights.cpp
+
+HEADERS += \
+ integrationpluginzigbeegenericlights.h
diff --git a/zigbee-lumi/integrationpluginzigbeelumi.cpp b/zigbee-lumi/integrationpluginzigbeelumi.cpp
index 90ae8a13..ed1e33be 100644
--- a/zigbee-lumi/integrationpluginzigbeelumi.cpp
+++ b/zigbee-lumi/integrationpluginzigbeelumi.cpp
@@ -141,10 +141,10 @@ void IntegrationPluginZigbeeLumi::handleRemoveNode(ZigbeeNode *node, const QUuid
{
Q_UNUSED(networkUuid)
- if (m_nodeThings.values().contains(node)) {
- Thing *thing = m_nodeThings.key(node);
- qCDebug(dcZigbeeLumi()) << "Node for" << thing << node << "has left the network. Removing thing";
- m_nodeThings.remove(thing);
+ if (m_thingNodes.values().contains(node)) {
+ Thing *thing = m_thingNodes.key(node);
+ qCDebug(dcZigbeeLumi()) << node << "for" << thing << "has left the network.";
+ m_thingNodes.remove(thing);
emit autoThingDisappeared(thing->id());
}
}
@@ -157,10 +157,10 @@ void IntegrationPluginZigbeeLumi::init()
void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
- QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
- qCDebug(dcZigbeeLumi()) << "Nework uuid:" << networkUuid;
- ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_zigbeeAddressParamTypeIds.value(thing->thingClassId())).toString());
+ // Get the node for this thing
+ QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
+ ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_zigbeeAddressParamTypeIds.value(thing->thingClassId())).toString());
ZigbeeNode *node = hardwareManager()->zigbeeResource()->getNode(networkUuid, zigbeeAddress);
if (!node) {
qCWarning(dcZigbeeLumi()) << "Zigbee node for" << info->thing()->name() << "not found.´";
@@ -175,16 +175,14 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
info->finish(Thing::ThingErrorSetupFailed);
return;
}
-
- m_nodeThings.insert(thing, node);
- // General signals and states
+ // Store the node thing association for removing
+ m_thingNodes.insert(thing, node);
+
// Update connected state
- thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), hardwareManager()->zigbeeResource()->networkState(networkUuid) == ZigbeeNetwork::StateRunning);
- connect(hardwareManager()->zigbeeResource(), &ZigbeeHardwareResource::networkStateChanged, thing, [thing, this](const QUuid &networkUuid, ZigbeeNetwork::State state){
- if (thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid() == networkUuid) {
- thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), state == ZigbeeNetwork::StateRunning);
- }
+ 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
@@ -198,7 +196,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
// Set the version
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpoint->softwareBuildId());
-
+ // Thing specific setup
if (thing->thingClassId() == lumiMagnetSensorThingClassId) {
ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdOnOff);
if (onOffCluster) {
@@ -461,7 +459,7 @@ void IntegrationPluginZigbeeLumi::executeAction(ThingActionInfo *info)
void IntegrationPluginZigbeeLumi::thingRemoved(Thing *thing)
{
- ZigbeeNode *node = m_nodeThings.take(thing);
+ ZigbeeNode *node = m_thingNodes.take(thing);
if (node) {
QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
hardwareManager()->zigbeeResource()->removeNodeFromNetwork(networkUuid, node);
diff --git a/zigbee-lumi/integrationpluginzigbeelumi.h b/zigbee-lumi/integrationpluginzigbeelumi.h
index 17670aac..03ebce89 100644
--- a/zigbee-lumi/integrationpluginzigbeelumi.h
+++ b/zigbee-lumi/integrationpluginzigbeelumi.h
@@ -66,7 +66,7 @@ private:
QHash m_knownLumiDevices;
- QHash m_nodeThings;
+ QHash m_thingNodes;
PluginTimer *m_presenceTimer = nullptr;
};