diff --git a/nymea-plugins.pro b/nymea-plugins.pro
index 1194d487..5c1f18c6 100644
--- a/nymea-plugins.pro
+++ b/nymea-plugins.pro
@@ -64,6 +64,8 @@ PLUGIN_DIRS = \
wakeonlan \
wemo \
ws2812fx \
+ zigbee-generic \
+ zigbee-lumi \
message(============================================)
diff --git a/zigbee-generic/integrationpluginzigbee-generic.json b/zigbee-generic/integrationpluginzigbee-generic.json
new file mode 100644
index 00000000..b5a16145
--- /dev/null
+++ b/zigbee-generic/integrationpluginzigbee-generic.json
@@ -0,0 +1,14 @@
+{
+ "name": "ZigbeeGeneric",
+ "displayName": "Zigbee Generic",
+ "id": "6a4343be-9fd6-4015-9ff5-38542651c534",
+ "vendors": [
+ {
+ "name": "nymea",
+ "displayName": "nymea",
+ "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
+ "thingClasses": [
+ ]
+ }
+ ]
+}
diff --git a/zigbee-generic/integrationpluginzigbeegeneric.cpp b/zigbee-generic/integrationpluginzigbeegeneric.cpp
new file mode 100644
index 00000000..08921540
--- /dev/null
+++ b/zigbee-generic/integrationpluginzigbeegeneric.cpp
@@ -0,0 +1,100 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+*
+* 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 "integrationpluginzigbeegeneric.h"
+#include "plugininfo.h"
+#include "hardware/zigbee/zigbeehardwareresource.h"
+
+#include
+
+IntegrationPluginZigbeeGeneric::IntegrationPluginZigbeeGeneric()
+{
+
+}
+
+QString IntegrationPluginZigbeeGeneric::name() const
+{
+ return "Generic";
+}
+
+bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
+{
+ foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
+ qCDebug(dcZigbeeGeneric) << "Endpoint profile:" << endpoint->profile() << endpoint->deviceId() << networkUuid;
+// if ((endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileLightLink && endpoint->deviceId() == Zigbee::LightLinkDevice::LightLinkDeviceOnOff
+// (endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceOnOf>
+
+// // Create generic power socket
+// qCDebug(dcZigbee()) << "This device is an power socket";
+// if (myThings().filterByThingClassId(genericPowerSocketThingClassId)
+// .filterByParam(genericPowerSocketThingIeeeAddressParamTypeId, node->extendedAddress().toString())
+// .isEmpty()) {
+// qCDebug(dcZigbee()) << "Adding new generic power socket";
+// ThingDescriptor descriptor(genericPowerSocketThingClassId);
+// QString deviceClassName = supportedThings().findById(genericPowerSocketThingClassId).displayName();
+// descriptor.setTitle(QString("%1 (%2 - %3)").arg(deviceClassName).arg(endpoint->manufacturerName()).arg(endpoint->modelIdentifier()));
+// ParamList params;
+// params.append(Param(genericPowerSocketThingIeeeAddressParamTypeId, node->extendedAddress().toString()));
+// params.append(Param(genericPowerSocketThingManufacturerParamTypeId, endpoint->manufacturerName()));
+// params.append(Param(genericPowerSocketThingModelParamTypeId, endpoint->modelIdentifier()));
+// descriptor.setParams(params);
+// descriptor.setParentId(networkManagerDevice->id());
+// emit autoThingsAppeared({descriptor});
+// } else {
+// qCDebug(dcZigbee()) << "The device for this node has already been created.";
+// }
+// return true;
+// }
+ }
+
+
+ return false;
+}
+
+void IntegrationPluginZigbeeGeneric::init()
+{
+ hardwareManager()->zigbeeResource()->registerHandler(this, ZigbeeHardwareResource::HandlerTypeCatchAll);
+}
+
+void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info)
+{
+ info->finish(Thing::ThingErrorNoError);
+}
+
+void IntegrationPluginZigbeeGeneric::executeAction(ThingActionInfo *info)
+{
+ info->finish(Thing::ThingErrorUnsupportedFeature);
+}
+
+void IntegrationPluginZigbeeGeneric::thingRemoved(Thing *thing)
+{
+ Q_UNUSED(thing)
+}
diff --git a/zigbee-generic/integrationpluginzigbeegeneric.h b/zigbee-generic/integrationpluginzigbeegeneric.h
new file mode 100644
index 00000000..a678b50a
--- /dev/null
+++ b/zigbee-generic/integrationpluginzigbeegeneric.h
@@ -0,0 +1,61 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 INTEGRATIONPLUGINZIGBEEGENERIC_H
+#define INTEGRATIONPLUGINZIGBEEGENERIC_H
+
+#include "integrations/integrationplugin.h"
+#include "hardware/zigbee/zigbeehandler.h"
+#include "plugintimer.h"
+
+#include
+
+class IntegrationPluginZigbeeGeneric: public IntegrationPlugin, public ZigbeeHandler
+{
+ Q_OBJECT
+
+ Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginzigbee-generic.json")
+ Q_INTERFACES(IntegrationPlugin)
+
+public:
+ explicit IntegrationPluginZigbeeGeneric();
+
+ QString name() const override;
+ bool handleNode(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:
+};
+
+#endif // INTEGRATIONPLUGINZIGBEEGENERIC_H
diff --git a/zigbee-generic/zigbee-generic.pro b/zigbee-generic/zigbee-generic.pro
new file mode 100644
index 00000000..23192648
--- /dev/null
+++ b/zigbee-generic/zigbee-generic.pro
@@ -0,0 +1,12 @@
+include(../plugins.pri)
+
+PKGCONFIG += nymea-zigbee
+
+SOURCES += \
+ integrationpluginzigbeegeneric.cpp
+
+HEADERS += \
+ integrationpluginzigbeegeneric.h
+
+
+
diff --git a/zigbee-lumi/integrationpluginzigbee-lumi.json b/zigbee-lumi/integrationpluginzigbee-lumi.json
new file mode 100644
index 00000000..927efef4
--- /dev/null
+++ b/zigbee-lumi/integrationpluginzigbee-lumi.json
@@ -0,0 +1,434 @@
+{
+ "name": "ZigbeeLumi",
+ "displayName": "Zigbee Lumi",
+ "id": "4a6e97da-0e4b-4731-8bfe-c93d806a9383",
+ "vendors": [
+ {
+ "name": "lumi",
+ "displayName": "Lumi",
+ "id": "f58dac98-0ba1-408f-946a-25d452080baa",
+ "thingClasses": [
+ {
+ "name": "lumiHTSensor",
+ "displayName": "Temperature humidity sensor",
+ "id": "dfabab0e-d483-43f8-82c6-720899e70c86",
+ "setupMethod": "JustAdd",
+ "createMethods": [ "Auto" ],
+ "interfaces": [ "temperaturesensor", "humiditysensor", "wirelessconnectable" ],
+ "paramTypes": [
+ {
+ "id": "bd0b2bf2-2ec3-497f-9679-a63850101257",
+ "name": "ieeeAddress",
+ "displayName": "IEEE adress",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "2daebedb-d272-4553-a410-91feff69ff7a",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "eb09e3f4-44ea-4ca9-9eac-9a693595fe37",
+ "name": "connected",
+ "displayName": "Available",
+ "displayNameEvent": "Available changed",
+ "type": "bool",
+ "cached": false,
+ "defaultValue": false
+ },
+ {
+ "id": "0cb72e84-01c4-4041-9aee-1dabf26a062e",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "defaultValue": 0,
+ "maxValue": 100,
+ "minValue": 0,
+ "type": "uint",
+ "unit": "Percentage"
+ },
+ {
+ "id": "968ff8bb-b852-48d8-bde2-28cfa810b20e",
+ "name": "version",
+ "displayName": "Version",
+ "displayNameEvent": "Version changed",
+ "type": "QString",
+ "cached": true,
+ "defaultValue": ""
+ },
+ {
+ "id": "152b475e-6bd8-4e6f-8765-0636c0bc8e9d",
+ "name": "temperature",
+ "displayName": "Temperature",
+ "displayNameEvent": "Temperature changed",
+ "type": "double",
+ "unit": "DegreeCelsius",
+ "defaultValue": 0.0
+ },
+ {
+ "id": "e6559d9e-2c64-485d-bb2b-8a9aec0ac656",
+ "name": "humidity",
+ "displayName": "Humidity",
+ "displayNameEvent": "Humidity changed",
+ "maxValue": 100,
+ "minValue": 0,
+ "unit": "Percentage",
+ "type": "double",
+ "defaultValue": 0.0
+ }
+ ],
+ "actionTypes": [
+ {
+ "id": "ce853c00-d175-45bc-a3d9-3c8c93d88099",
+ "name": "removeFromNetwork",
+ "displayName": "Remove from network"
+ },
+ {
+ "id": "4a9d9427-52cf-4c13-9b71-496145b18476",
+ "name": "test1",
+ "displayName": "Test 1"
+ }
+ ],
+ "eventTypes": [
+
+ ]
+ },
+ {
+ "name": "lumiMagnetSensor",
+ "displayName": "Magnet sensor",
+ "id": "b3e30f37-7467-4c66-8694-9fe624aebd10",
+ "setupMethod": "JustAdd",
+ "createMethods": [ "Auto" ],
+ "interfaces": [ "closablesensor", "wirelessconnectable" ],
+ "paramTypes": [
+ {
+ "id": "36d8a40a-7f37-4d59-a0d9-6d4977ea63f3",
+ "name": "ieeeAddress",
+ "displayName": "IEEE adress",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "6a238726-ccd5-484b-ac5d-92649a604f9a",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "76f6c739-73e0-4a36-97c9-043af5854af5",
+ "name": "connected",
+ "displayName": "Available",
+ "displayNameEvent": "Available changed",
+ "type": "bool",
+ "cached": false,
+ "defaultValue": false
+ },
+ {
+ "id": "7fef2f25-91ac-4818-bc7a-e427bdeff438",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "defaultValue": 0,
+ "maxValue": 100,
+ "minValue": 0,
+ "type": "uint",
+ "unit": "Percentage"
+ },
+ {
+ "id": "ac0e4cd1-553b-4e43-b08a-6dd8d617e765",
+ "name": "version",
+ "displayName": "Version",
+ "displayNameEvent": "Version changed",
+ "type": "QString",
+ "cached": true,
+ "defaultValue": ""
+ },
+ {
+ "id": "6fad76ec-9d36-408d-bbf1-00e5d18bf6b0",
+ "name": "closed",
+ "displayName": "Closed",
+ "displayNameEvent": "Closed changed",
+ "type": "bool",
+ "defaultValue": true
+ }
+ ],
+ "actionTypes": [
+ {
+ "id": "2bae0e2d-0c20-475d-a6cd-2e685e6b0626",
+ "name": "removeFromNetwork",
+ "displayName": "Remove from network"
+ }
+ ],
+ "eventTypes": [
+
+ ]
+ },
+ {
+ "name": "lumiButtonSensor",
+ "displayName": "Button sensor",
+ "id": "42c1edba-cc5f-4eb9-84f8-1b0d47a6f95e",
+ "setupMethod": "JustAdd",
+ "createMethods": [ "Auto" ],
+ "interfaces": [ "longpressbutton", "wirelessconnectable" ],
+ "paramTypes": [
+ {
+ "id": "929eb2be-6d8f-46b7-8cc9-896e7e2c494a",
+ "name": "ieeeAddress",
+ "displayName": "IEEE adress",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "de153a5e-c7bd-4815-aa08-21d093b296d7",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "f0da4762-4778-4b3b-ba68-466ff504a3d3",
+ "name": "connected",
+ "displayName": "Available",
+ "displayNameEvent": "Available changed",
+ "type": "bool",
+ "cached": false,
+ "defaultValue": false
+ },
+ {
+ "id": "6e9de8ee-cb28-4f7d-a0f6-fe9e64df0463",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "defaultValue": 0,
+ "maxValue": 100,
+ "minValue": 0,
+ "type": "uint",
+ "unit": "Percentage"
+ },
+ {
+ "id": "11d03ab4-7450-4caf-81ec-0b2b73e56b08",
+ "name": "version",
+ "displayName": "Version",
+ "displayNameEvent": "Version changed",
+ "type": "QString",
+ "cached": true,
+ "defaultValue": ""
+ }
+ ],
+ "actionTypes": [
+ {
+ "id": "65b43aad-1784-4e85-ad5a-ce01cc5757bd",
+ "name": "removeFromNetwork",
+ "displayName": "Remove from network"
+ }
+ ],
+ "eventTypes": [
+ {
+ "id": "2515e40a-8146-4f11-8d79-2be9e20224e5",
+ "name": "pressed",
+ "displayName": "Pressed"
+ },
+ {
+ "id": "6e9dda9f-e51b-48c4-9839-01aa33085e2c",
+ "name": "longPressed",
+ "displayName": "Long pressed"
+ }
+ ]
+ },
+ {
+ "name": "lumiMotionSensor",
+ "displayName": "Motion sensor",
+ "id": "b5530192-0891-4934-88a2-7338b069be24",
+ "setupMethod": "JustAdd",
+ "createMethods": [ "Auto" ],
+ "interfaces": [ "presencesensor", "lightsensor", "wirelessconnectable" ],
+ "paramTypes": [
+ {
+ "id": "3a44ed47-5a70-4052-9a14-78f9033eab85",
+ "name": "ieeeAddress",
+ "displayName": "IEEE adress",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "bc0c78f6-ed88-4ae3-8e1e-2190374391af",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "settingsTypes": [
+ {
+ "id": "4aeb84fa-e3ef-495e-8754-a5f6c3aa934a",
+ "name": "timeout",
+ "displayName": "Time period",
+ "type": "uint",
+ "unit": "Seconds",
+ "defaultValue": 10,
+ "minValue": 10
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "007e2fe5-80d5-4f98-941d-b458b555965a",
+ "name": "connected",
+ "displayName": "Available",
+ "displayNameEvent": "Available changed",
+ "type": "bool",
+ "cached": false,
+ "defaultValue": false
+ },
+ {
+ "id": "c5913170-e377-484b-a330-c5d5b590fee2",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "defaultValue": 0,
+ "maxValue": 100,
+ "minValue": 0,
+ "type": "uint",
+ "unit": "Percentage"
+ },
+ {
+ "id": "d1337b3b-0dfb-4505-90f1-e5b2b45be9bd",
+ "name": "version",
+ "displayName": "Version",
+ "displayNameEvent": "Version changed",
+ "type": "QString",
+ "cached": true,
+ "defaultValue": ""
+ },
+ {
+ "id": "fed7582b-c057-42ab-b7c0-d562a2e7917c",
+ "name": "isPresent",
+ "displayName": "Present",
+ "displayNameEvent": "Present changed",
+ "type": "bool",
+ "defaultValue": true
+ },
+ {
+ "id": "021ce190-a775-40e0-b19b-c6307c73e343",
+ "name": "lastSeenTime",
+ "displayName": "Last seen time",
+ "displayNameEvent": "Last seen time changed",
+ "type": "int",
+ "unit": "UnixTime",
+ "defaultValue": 0
+ },
+ {
+ "id": "eb3fb43e-a9bb-4498-880b-464cbb752ff6",
+ "name": "lightIntensity",
+ "displayName": "Light intensity",
+ "displayNameEvent": "Light intensity changed",
+ "type": "double",
+ "unit": "Lux",
+ "defaultValue": 0
+ }
+ ],
+ "actionTypes": [
+ {
+ "id": "2797c499-ca7f-4cf6-a732-c8e3cd580e56",
+ "name": "removeFromNetwork",
+ "displayName": "Remove from network"
+ }
+ ],
+ "eventTypes": [
+
+ ]
+ },
+ {
+ "name": "lumiWaterSensor",
+ "displayName": "Water sensor",
+ "id": "e8e18bbe-27bb-4fd7-98fc-f5cef3b5f213",
+ "setupMethod": "JustAdd",
+ "createMethods": [ "Auto" ],
+ "interfaces": [ "sensor", "battery", "wirelessconnectable" ],
+ "paramTypes": [
+ {
+ "id": "e12453e7-5fc3-4549-b4fc-8b85f78607c6",
+ "name": "ieeeAddress",
+ "displayName": "IEEE adress",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "4c67bab4-da84-407a-8d8d-84a5c373d585",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "03fc0e4d-dcd9-41dc-8aac-dbe735f11ef7",
+ "name": "connected",
+ "displayName": "Available",
+ "displayNameEvent": "Available changed",
+ "type": "bool",
+ "cached": false,
+ "defaultValue": false
+ },
+ {
+ "id": "b3bba018-b9d0-47a8-a2cf-d8d2d6fcecce",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "defaultValue": 0,
+ "maxValue": 100,
+ "minValue": 0,
+ "type": "uint",
+ "unit": "Percentage"
+ },
+ {
+ "id": "bae1014f-67f5-4dcc-b36f-e15eb43afd6e",
+ "name": "version",
+ "displayName": "Version",
+ "displayNameEvent": "Version changed",
+ "type": "QString",
+ "cached": true,
+ "defaultValue": ""
+ },
+ {
+ "id": "e43532a7-cbee-446e-9e4a-aff88026ad1a",
+ "name": "waterDetected",
+ "displayName": "Water detected",
+ "displayNameEvent": "Water detected changed",
+ "type": "bool",
+ "defaultValue": true
+ },
+ {
+ "id": "72aa617c-88cc-4992-a1a2-400b5e19106e",
+ "name": "batteryCritical",
+ "displayName": "Battery critical",
+ "displayNameEvent": "Battery critical changed",
+ "type": "bool",
+ "defaultValue": false
+ }
+ ],
+ "actionTypes": [
+ {
+ "id": "ed085bda-5608-419d-88e2-81ebcb9f26e1",
+ "name": "removeFromNetwork",
+ "displayName": "Remove from network"
+ }
+ ],
+ "eventTypes": [
+
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/zigbee-lumi/integrationpluginzigbeelumi.cpp b/zigbee-lumi/integrationpluginzigbeelumi.cpp
new file mode 100644
index 00000000..4a019298
--- /dev/null
+++ b/zigbee-lumi/integrationpluginzigbeelumi.cpp
@@ -0,0 +1,286 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+*
+* 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 "integrationpluginzigbeelumi.h"
+#include "plugininfo.h"
+#include "hardware/zigbee/zigbeehardwareresource.h"
+
+#include
+
+#include
+
+IntegrationPluginZigbeeLumi::IntegrationPluginZigbeeLumi()
+{
+ m_networkUuidParamTypeIds[lumiHTSensorThingClassId] = lumiHTSensorThingNetworkUuidParamTypeId;
+ m_networkUuidParamTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorThingNetworkUuidParamTypeId;
+ m_networkUuidParamTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorThingNetworkUuidParamTypeId;
+ m_networkUuidParamTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorThingNetworkUuidParamTypeId;
+ m_networkUuidParamTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorThingNetworkUuidParamTypeId;
+
+ m_zigbeeAddressParamTypeIds[lumiHTSensorThingClassId] = lumiHTSensorThingIeeeAddressParamTypeId;
+ m_zigbeeAddressParamTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorThingIeeeAddressParamTypeId;
+ m_zigbeeAddressParamTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorThingIeeeAddressParamTypeId;
+ m_zigbeeAddressParamTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorThingIeeeAddressParamTypeId;
+ m_zigbeeAddressParamTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorThingIeeeAddressParamTypeId;
+
+ m_connectedStateTypeIds[lumiHTSensorThingClassId] = lumiHTSensorConnectedStateTypeId;
+ m_connectedStateTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorConnectedStateTypeId;
+ m_connectedStateTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorConnectedStateTypeId;
+ m_connectedStateTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorConnectedStateTypeId;
+ m_connectedStateTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorConnectedStateTypeId;
+
+ m_signalStrengthStateTypeIds[lumiHTSensorThingClassId] = lumiHTSensorSignalStrengthStateTypeId;
+ m_signalStrengthStateTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorSignalStrengthStateTypeId;
+ m_signalStrengthStateTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorSignalStrengthStateTypeId;
+ m_signalStrengthStateTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorSignalStrengthStateTypeId;
+ m_signalStrengthStateTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorSignalStrengthStateTypeId;
+
+}
+
+QString IntegrationPluginZigbeeLumi::name() const
+{
+ return "Lumi";
+}
+
+bool IntegrationPluginZigbeeLumi::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
+{
+ // Check if this is Lumi
+ // Note: Lumi / Xiaomi / Aquara devices are not in the specs, so no enum here
+ if (node->nodeDescriptor().manufacturerCode != 0x1037) {
+ return false;
+ }
+
+ foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
+ // Get the model identifier if present from the first endpoint. Also this is out of spec
+ if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
+ qCWarning(dcZigbeeLumi()) << "This lumi device does not have the basic input cluster yet.";
+ continue;
+ }
+
+ QHash knownLumiDevices;
+ knownLumiDevices.insert("lumi.sensor_ht", lumiHTSensorThingClassId);
+ knownLumiDevices.insert("lumi.sensor_magnet", lumiMagnetSensorThingClassId);
+ knownLumiDevices.insert("lumi.sensor_switch", lumiButtonSensorThingClassId);
+ knownLumiDevices.insert("lumi.sensor_motion", lumiMotionSensorThingClassId);
+ knownLumiDevices.insert("lumi.sensor_water", lumiWaterSensorThingClassId);
+
+ ThingClassId thingClassId;
+ foreach (const QString &knownLumi, knownLumiDevices.keys()) {
+ if (endpoint->modelIdentifier().startsWith(knownLumi)) {
+ thingClassId = knownLumiDevices.value(knownLumi);
+ break;
+ }
+ }
+ if (thingClassId.isNull()) {
+ qCWarning(dcZigbeeLumi()) << "Unhandled Lumi device:" << endpoint->modelIdentifier();
+ return false;
+ }
+
+ ThingDescriptor descriptor(thingClassId, supportedThings().findById(thingClassId).displayName());
+ ParamList params;
+ params << Param(m_networkUuidParamTypeIds.value(thingClassId), networkUuid.toString());
+ params << Param(m_zigbeeAddressParamTypeIds.value(thingClassId), node->extendedAddress().toString());
+ descriptor.setParams(params);
+ emit autoThingsAppeared({descriptor});
+
+ return true;
+ }
+
+ return false;
+}
+
+void IntegrationPluginZigbeeLumi::init()
+{
+ hardwareManager()->zigbeeResource()->registerHandler(this);
+}
+
+void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
+{
+ if (!hardwareManager()->zigbeeResource()->available()) {
+ qCWarning(dcZigbeeLumi()) << "Zigbee is not available. Not setting up" << info->thing()->name();
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+ 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());
+ ZigbeeNode *node = hardwareManager()->zigbeeResource()->getNode(networkUuid, zigbeeAddress);
+ if (!node) {
+ qCWarning(dcZigbeeLumi()) << "Zigbee node for" << info->thing()->name() << "not found.´";
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+
+ ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01);
+ if (!endpoint) {
+ qCWarning(dcZigbeeLumi()) << "Zigbee endpoint 1 not found on" << thing->name();
+ info->finish(Thing::ThingErrorSetupFailed);
+ return;
+ }
+
+ // 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);
+ }
+ });
+
+ // 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(dcZigbeeLumi()) << thing << "signal strength changed" << signalStrength << "%";
+ thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength);
+ });
+
+
+ if (thing->thingClassId() == lumiMagnetSensorThingClassId) {
+ ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdOnOff);
+ if (onOffCluster) {
+ thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !onOffCluster->powered());
+ connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){
+ qCDebug(dcZigbeeLumi()) << thing << "state changed" << (power ? "closed" : "open");
+ thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !power);
+ });
+ } else {
+ qCWarning(dcZigbeeLumi()) << "Could not find the OnOff input cluster on" << thing << endpoint;
+ }
+ }
+
+ if (thing->thingClassId() == lumiMotionSensorThingClassId) {
+ ZigbeeClusterOccupancySensing *occupancyCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdOccupancySensing);
+ if (occupancyCluster) {
+ thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancyCluster->occupancy());
+ connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [thing](bool occupancy){
+ qCDebug(dcZigbeeLumi()) << "occupancy changed" << occupancy;
+ thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancy);
+ thing->setStateValue(lumiMotionSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
+ });
+
+ if (!m_presenceTimer) {
+ m_presenceTimer = hardwareManager()->pluginTimerManager()->registerTimer(1);
+ }
+
+ connect(m_presenceTimer, &PluginTimer::timeout, thing, [thing](){
+ if (thing->stateValue(lumiMotionSensorIsPresentStateTypeId).toBool()) {
+ int timeout = thing->setting(lumiMotionSensorSettingsTimeoutParamTypeId).toInt();
+ QDateTime lastSeenTime = QDateTime::fromMSecsSinceEpoch(thing->stateValue(lumiMotionSensorLastSeenTimeStateTypeId).toULongLong() * 1000);
+ if (lastSeenTime.addSecs(timeout) < QDateTime::currentDateTime()) {
+ thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, false);
+ }
+ }
+ });
+
+ } else {
+ qCWarning(dcZigbeeLumi()) << "Occupancy cluster not found on" << thing->name();
+ }
+
+ ZigbeeClusterIlluminanceMeasurment *illuminanceCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement);
+ if (illuminanceCluster) {
+ thing->setStateValue(lumiHTSensorTemperatureStateTypeId, illuminanceCluster->illuminance());
+ connect(illuminanceCluster, &ZigbeeClusterIlluminanceMeasurment::illuminanceChanged, thing, [thing](quint16 illuminance){
+ thing->setStateValue(lumiMotionSensorLightIntensityStateTypeId, illuminance);
+ });
+ } else {
+ qCWarning(dcZigbeeLumi()) << "Illuminance cluster not found on" << thing->name();
+ }
+ }
+
+ if (thing->thingClassId() == lumiHTSensorThingClassId) {
+ ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement);
+ if (temperatureCluster) {
+ thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperatureCluster->temperature());
+ connect(temperatureCluster, &ZigbeeClusterTemperatureMeasurement::temperatureChanged, thing, [thing](double temperature){
+ thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperature);
+ });
+ } else {
+ qCWarning(dcZigbeeLumi()) << "Could not find the temperature measurement server cluster on" << thing << endpoint;
+ }
+
+ ZigbeeClusterRelativeHumidityMeasurement *humidityCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement);
+ if (humidityCluster) {
+ thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidityCluster->humidity());
+ connect(humidityCluster, &ZigbeeClusterRelativeHumidityMeasurement::humidityChanged, thing, [thing](double humidity){
+ thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidity);
+ });
+ } else {
+ qCWarning(dcZigbeeLumi()) << "Could not find the relative humidity measurement server cluster on" << thing << endpoint;
+ }
+ }
+
+ info->finish(Thing::ThingErrorNoError);
+
+
+
+// if (thing->thingClassId() == lumiButtonSensorThingClassId) {
+// qCDebug(dcZigbee()) << "Lumi button sensor" << thing;
+// ZigbeeAddress ieeeAddress(thing->paramValue(lumiButtonSensorThingIeeeAddressParamTypeId).toString());
+// ZigbeeNetwork *network = findParentNetwork(thing);
+// LumiButtonSensor *sensor = new LumiButtonSensor(network, ieeeAddress, thing, this);
+// connect(sensor, &LumiButtonSensor::buttonPressed, this, [this, thing](){
+// qCDebug(dcZigbee()) << thing << "clicked event";
+// emit emitEvent(Event(lumiButtonSensorPressedEventTypeId, thing->id()));
+// });
+// connect(sensor, &LumiButtonSensor::buttonLongPressed, this, [this, thing](){
+// qCDebug(dcZigbee()) << thing << "long pressed event";
+// emit emitEvent(Event(lumiButtonSensorLongPressedEventTypeId, thing->id()));
+// });
+
+// m_zigbeeDevices.insert(thing, sensor);
+// info->finish(Thing::ThingErrorNoError);
+// return;
+// }
+
+
+// if (thing->thingClassId() == lumiWaterSensorThingClassId) {
+// qCDebug(dcZigbee()) << "Lumi water sensor" << thing;
+// ZigbeeAddress ieeeAddress(thing->paramValue(lumiWaterSensorThingIeeeAddressParamTypeId).toString());
+// ZigbeeNetwork *network = findParentNetwork(thing);
+// LumiWaterSensor *sensor = new LumiWaterSensor(network, ieeeAddress, thing, this);
+// m_zigbeeDevices.insert(thing, sensor);
+// info->finish(Thing::ThingErrorNoError);
+// return;
+// }
+
+// info->finish(Thing::ThingErrorThingClassNotFound);
+}
+
+void IntegrationPluginZigbeeLumi::executeAction(ThingActionInfo *info)
+{
+ info->finish(Thing::ThingErrorUnsupportedFeature);
+}
+
+void IntegrationPluginZigbeeLumi::thingRemoved(Thing *thing)
+{
+ Q_UNUSED(thing)
+}
diff --git a/zigbee-lumi/integrationpluginzigbeelumi.h b/zigbee-lumi/integrationpluginzigbeelumi.h
new file mode 100644
index 00000000..e2fed597
--- /dev/null
+++ b/zigbee-lumi/integrationpluginzigbeelumi.h
@@ -0,0 +1,68 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 INTEGRATIONPLUGINZIGBEELUMI_H
+#define INTEGRATIONPLUGINZIGBEELUMI_H
+
+#include "integrations/integrationplugin.h"
+#include "hardware/zigbee/zigbeehandler.h"
+#include "plugintimer.h"
+
+#include
+
+class IntegrationPluginZigbeeLumi: public IntegrationPlugin, public ZigbeeHandler
+{
+ Q_OBJECT
+
+ Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginzigbee-lumi.json")
+ Q_INTERFACES(IntegrationPlugin)
+
+public:
+ explicit IntegrationPluginZigbeeLumi();
+
+ QString name() const override;
+ bool handleNode(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_networkUuidParamTypeIds;
+ QHash m_zigbeeAddressParamTypeIds;
+
+ QHash m_connectedStateTypeIds;
+ QHash m_signalStrengthStateTypeIds;
+
+ PluginTimer *m_presenceTimer = nullptr;
+};
+
+#endif // INTEGRATIONPLUGINZIGBEELUMI_H
diff --git a/zigbee-lumi/zigbee-lumi.pro b/zigbee-lumi/zigbee-lumi.pro
new file mode 100644
index 00000000..e4e53c79
--- /dev/null
+++ b/zigbee-lumi/zigbee-lumi.pro
@@ -0,0 +1,12 @@
+include(../plugins.pri)
+
+PKGCONFIG += nymea-zigbee
+
+SOURCES += \
+ integrationpluginzigbeelumi.cpp \
+
+HEADERS += \
+ integrationpluginzigbeelumi.h \
+
+
+