diff --git a/debian/control b/debian/control
index 0bfec247..570617f8 100644
--- a/debian/control
+++ b/debian/control
@@ -1150,22 +1150,6 @@ Description: nymea.io zigbee plugin for develco things
This package will install the nymea.io plugin for Develco
-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},
@@ -1198,6 +1182,22 @@ 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-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-philipshue
Architecture: any
Depends: ${shlibs:Depends},
@@ -1214,6 +1214,15 @@ Description: nymea.io zigbee plugin for Philips Hue devices
This package will install the nymea.io plugin for Philips Hue zigbee devices
+Package: nymea-plugin-zigbee-remotes
+Architecture: any
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libnymea-zigbee1,
+ nymea-plugins-translations,
+Description: nymea.io plugin for various zigbee remote controls.
+
+
Package: nymea-plugin-zigbee-tradfri
Architecture: any
Depends: ${shlibs:Depends},
diff --git a/debian/nymea-plugin-zigbee-remotes.install.in b/debian/nymea-plugin-zigbee-remotes.install.in
new file mode 100644
index 00000000..1fb765c7
--- /dev/null
+++ b/debian/nymea-plugin-zigbee-remotes.install.in
@@ -0,0 +1 @@
+usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginzigbeeremotes.so
diff --git a/nymea-plugins.pro b/nymea-plugins.pro
index a8f3990e..dc33f4e7 100644
--- a/nymea-plugins.pro
+++ b/nymea-plugins.pro
@@ -78,6 +78,7 @@ PLUGIN_DIRS = \
zigbeegenericlights \
zigbeelumi \
zigbeephilipshue \
+ zigbeeremotes \
zigbeetradfri \
diff --git a/zigbeeremotes/README.md b/zigbeeremotes/README.md
new file mode 100644
index 00000000..f5ead779
--- /dev/null
+++ b/zigbeeremotes/README.md
@@ -0,0 +1,17 @@
+# ZigBee remotes
+
+This plugin contains a collection of various Zigbee remote controls.
+
+## Supported Things
+
+### JUNG ZLL5004m
+
+The JUNG ZLL5004m is a battery powered wall switch with 8 buttons. The top row acts as on/off on press as well as dimming up and down on longpress.
+The other 6 buttons recall scenes.
+To connect the device to nymea, start with factory resetting the remote by pressing and holding buttons 5 and 6 (3rd row, left and right) down simultaneously
+until the remote starts blinking, then press the off button. Then permit new devices to join the ZigBee network and press and hold button 2 and 7 (top-right
+and bottom-left) until the remote starts blinking.
+After the remote has joined the nymea network, the remote can also be directly linked to light bulbs by holding it close to a light bulb and pressing and
+holding buttons 1 and 8 (top-left and bottom-right) until the remote and the light start blinking. The remotes buttons will now control the light directly
+as well as sending its button presses to nymea for further processing.
+
diff --git a/zigbeeremotes/integrationpluginzigbeeremotes.cpp b/zigbeeremotes/integrationpluginzigbeeremotes.cpp
new file mode 100644
index 00000000..7aad49bf
--- /dev/null
+++ b/zigbeeremotes/integrationpluginzigbeeremotes.cpp
@@ -0,0 +1,291 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+*
+* 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 "integrationpluginzigbeeremotes.h"
+#include "plugininfo.h"
+#include "hardware/zigbee/zigbeehardwareresource.h"
+
+#include
+
+
+IntegrationPluginZigbeeRemotes::IntegrationPluginZigbeeRemotes()
+{
+}
+
+QString IntegrationPluginZigbeeRemotes::name() const
+{
+ return "Remotes";
+}
+
+void IntegrationPluginZigbeeRemotes::init()
+{
+ hardwareManager()->zigbeeResource()->registerHandler(this, ZigbeeHardwareResource::HandlerTypeVendor);
+}
+
+bool IntegrationPluginZigbeeRemotes::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
+{
+ qCDebug(dcZigbeeRemotes) << "Evaluating node:" << node << node->nodeDescriptor().manufacturerCode << node->modelName();
+ bool handled = false;
+ // "Insta" remote (JUNG ZLL 5004)
+ if (node->nodeDescriptor().manufacturerCode == 0x117A && node->modelName() == " Remote") {
+ ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01);
+ if (!endpoint) {
+ qCWarning(dcZigbeeRemotes()) << "Device claims to be an Insta remote but does not provide endpoint 1";
+ return false;
+ }
+
+ createThing(instaThingClassId, networkUuid, node, endpoint);
+
+ // Nothing to be done here... The device does not support battery level updates and will send all the commands
+ // to the coordinator unconditionally, no need to bind any clusters...
+
+ handled = true;
+ }
+
+ return handled;
+}
+
+void IntegrationPluginZigbeeRemotes::handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid)
+{
+ Q_UNUSED(networkUuid)
+ Thing *thing = m_thingNodes.key(node);
+ if (thing) {
+ qCDebug(dcZigbeeRemotes()) << node << "for" << thing << "has left the network.";
+ emit autoThingDisappeared(thing->id());
+
+ // Removing it from our map to prevent a loop that would ask the zigbee network to remove this node (see thingRemoved())
+ m_thingNodes.remove(thing);
+ }
+}
+
+void IntegrationPluginZigbeeRemotes::setupThing(ThingSetupInfo *info)
+{
+ Thing *thing = info->thing();
+ QUuid networkUuid = thing->paramValue("networkUuid").toUuid();
+ qCDebug(dcZigbeeRemotes()) << "Nework uuid:" << networkUuid;
+ ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue("ieeeAddress").toString());
+ ZigbeeNode *node = m_thingNodes.value(thing);
+ if (!node) {
+ node = hardwareManager()->zigbeeResource()->claimNode(this, networkUuid, zigbeeAddress);
+ }
+
+ if (!node) {
+ qCWarning(dcZigbeeRemotes()) << "Zigbee node for" << info->thing()->name() << "not found.";
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+ m_thingNodes.insert(thing, node);
+
+ // Update connected state
+ thing->setStateValue("connected", node->reachable());
+ connect(node, &ZigbeeNode::reachableChanged, thing, [thing](bool reachable){
+ thing->setStateValue("connected", reachable);
+ });
+
+ // Update signal strength
+ thing->setStateValue("signalStrength", qRound(node->lqi() * 100.0 / 255.0));
+ connect(node, &ZigbeeNode::lqiChanged, thing, [thing](quint8 lqi){
+ uint signalStrength = qRound(lqi * 100.0 / 255.0);
+ qCDebug(dcZigbeeRemotes()) << thing << "signal strength changed" << signalStrength << "%";
+ thing->setStateValue("signalStrength", signalStrength);
+ });
+
+ // Type specific setup
+ if (thing->thingClassId() == instaThingClassId) {
+ ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01);
+
+ ZigbeeClusterOnOff *onOffCluster = endpoint->outputCluster(ZigbeeClusterLibrary::ClusterIdOnOff);
+ ZigbeeClusterLevelControl *levelControlCluster = endpoint->outputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl);
+ ZigbeeClusterScenes *scenesCluster = endpoint->outputCluster(ZigbeeClusterLibrary::ClusterIdScenes);
+ if (!onOffCluster || !levelControlCluster || !scenesCluster) {
+ qCWarning(dcZigbeeRemotes()) << "Could not find all of the needed clusters for" << thing->name() << "in" << m_thingNodes.value(thing) << "on endpoint" << endpoint->endpointId();
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+ return;
+ }
+ connect(onOffCluster, &ZigbeeClusterOnOff::commandSent, this, [=](ZigbeeClusterOnOff::Command command, const QByteArray ¶meters){
+ qCDebug(dcZigbeeRemotes()) << "OnOff command received:" << command << parameters;
+ switch (command) {
+ case ZigbeeClusterOnOff::CommandOn:
+ thing->emitEvent(instaPressedEventTypeId, {Param(instaPressedEventButtonNameParamTypeId, "ON")});
+ break;
+ case ZigbeeClusterOnOff::CommandOffWithEffect:
+ thing->emitEvent(instaPressedEventTypeId, {Param(instaPressedEventButtonNameParamTypeId, "OFF")});
+ break;
+ default:
+ qCWarning(dcZigbeeRemotes()) << "Unhandled command from Insta Remote:" << command << parameters.toHex();
+ }
+ });
+ connect(levelControlCluster, &ZigbeeClusterLevelControl::commandStepSent, this, [=](bool withOnOff, ZigbeeClusterLevelControl::StepMode stepMode, quint8 stepSize, quint16 transitionTime){
+ qCDebug(dcZigbeeRemotes()) << "Level command received" << withOnOff << stepMode << stepSize << transitionTime;
+ thing->emitEvent(instaPressedEventTypeId, {Param(instaPressedEventButtonNameParamTypeId, stepMode == ZigbeeClusterLevelControl::StepModeUp ? "+" : "-")});
+ });
+ connect(scenesCluster, &ZigbeeClusterScenes::commandSent, this, [=](ZigbeeClusterScenes::Command command, quint16 groupId, quint8 sceneId){
+ qCDebug(dcZigbeeRemotes()) << "Scenes command received:" << command << groupId << sceneId;
+ thing->emitEvent(instaPressedEventTypeId, {Param(instaPressedEventButtonNameParamTypeId, QString::number(sceneId))});
+ });
+
+
+ // The device also supports setting saturation, color and color temperature. However, it's quite funky to
+ // actually get there on the device and that mode seems to be only enabled if there are bindings to
+ // actual lamps. Once it's bound to lamps, pressing on and off simultaneously will start cycling through the bound
+ // lights and during that mode, the color/saturation/temperature will act on the currently selected lamp only.
+ // After some seconds without button press, it will revert back to the default mode where it sends all commands
+ // to the coordinator *and* all the bound lights simultaneously.
+ // So, in order to get that working we'd need to fake a like and somehow allow binding that via touch-link from a key-combo on the device.
+
+ // Not supporting that here... A user may still additionally bind the device to a lamp and use that feature with the remote....
+
+ info->finish(Thing::ThingErrorNoError);
+ return;
+ }
+
+ info->finish(Thing::ThingErrorNoError);
+}
+
+void IntegrationPluginZigbeeRemotes::thingRemoved(Thing *thing)
+{
+ ZigbeeNode *node = m_thingNodes.take(thing);
+ if (node) {
+ QUuid networkUuid = thing->paramValue("networkUuid").toUuid();
+ hardwareManager()->zigbeeResource()->removeNodeFromNetwork(networkUuid, node);
+ }
+}
+
+void IntegrationPluginZigbeeRemotes::createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
+{
+ ThingDescriptor descriptor(thingClassId);
+ ThingClass thingClass = supportedThings().findById(thingClassId);
+ descriptor.setTitle(QString("%1 (%2 - %3)").arg(thingClass.displayName()).arg(endpoint->manufacturerName()).arg(endpoint->modelIdentifier()));
+
+ ParamList params;
+ params.append(Param(thingClass.paramTypes().findByName("networkUuid").id(), networkUuid.toString()));
+ params.append(Param(thingClass.paramTypes().findByName("ieeeAddress").id(), node->extendedAddress().toString()));
+ descriptor.setParams(params);
+ emit autoThingsAppeared({descriptor});
+}
+
+void IntegrationPluginZigbeeRemotes::bindPowerConfigurationCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
+{
+ ZigbeeDeviceObjectReply *bindPowerReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration,
+ hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
+ connect(bindPowerReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
+ if (bindPowerReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
+ qCWarning(dcZigbeeRemotes()) << "Failed to bind power configuration cluster" << bindPowerReply->error();
+ } else {
+ qCDebug(dcZigbeeRemotes()) << "Binding power configuration cluster finished successfully";
+ }
+
+ ZigbeeClusterLibrary::AttributeReportingConfiguration batteryPercentageConfig;
+ batteryPercentageConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining;
+ batteryPercentageConfig.dataType = Zigbee::Uint8;
+ batteryPercentageConfig.minReportingInterval = 300;
+ batteryPercentageConfig.maxReportingInterval = 2700;
+ batteryPercentageConfig.reportableChange = ZigbeeDataType(static_cast(1)).data();
+
+ qCDebug(dcZigbeeRemotes()) << "Configuring attribute reporting for power configuration cluster";
+ ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({batteryPercentageConfig});
+ connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
+ if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
+ qCWarning(dcZigbeeRemotes()) << "Failed to configure power configuration cluster attribute reporting" << reportingReply->error();
+ } else {
+ qCDebug(dcZigbeeRemotes()) << "Attribute reporting configuration finished for power configuration cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
+ }
+ });
+ });
+}
+
+void IntegrationPluginZigbeeRemotes::bindOnOffCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
+{
+ ZigbeeDeviceObjectReply *bindOnOffClusterReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff,
+ hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
+ connect(bindOnOffClusterReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
+ if (bindOnOffClusterReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
+ qCWarning(dcZigbeeRemotes()) << "Failed to bind on/off cluster" << bindOnOffClusterReply->error();
+ } else {
+ qCDebug(dcZigbeeRemotes()) << "Bound on/off cluster successfully";
+ }
+ });
+}
+
+void IntegrationPluginZigbeeRemotes::bindLevelControlCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
+{
+ ZigbeeDeviceObjectReply *bindLevelControlClusterReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl,
+ hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
+ connect(bindLevelControlClusterReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
+ if (bindLevelControlClusterReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
+ qCWarning(dcZigbeeRemotes()) << "Failed to bind level control cluster" << bindLevelControlClusterReply->error();
+ } else {
+ qCDebug(dcZigbeeRemotes()) << "Bound level control cluster successfully";
+ }
+ });
+}
+
+void IntegrationPluginZigbeeRemotes::bindScenesCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
+{
+ ZigbeeDeviceObjectReply *bindScenesClusterReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdScenes,
+ hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
+ connect(bindScenesClusterReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
+ if (bindScenesClusterReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
+ qCWarning(dcZigbeeRemotes()) << "Failed to bind on/off cluster" << bindScenesClusterReply->error();
+ } else {
+ qCDebug(dcZigbeeRemotes()) << "Bound on/off cluster successfully";
+ }
+ });
+}
+
+void IntegrationPluginZigbeeRemotes::connectToPowerConfigurationCluster(Thing *thing, ZigbeeNodeEndpoint *endpoint)
+{
+ // Get battery level changes
+ ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
+ if (powerCluster) {
+ // If the power cluster attributes are already available, read values now
+ if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) {
+ thing->setStateValue("batteryLevel", powerCluster->batteryPercentage());
+ thing->setStateValue("batteryCritical", (powerCluster->batteryPercentage() < 10.0));
+ }
+ // Refresh power cluster attributes in any case
+ ZigbeeClusterReply *reply = powerCluster->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining});
+ connect(reply, &ZigbeeClusterReply::finished, thing, [=](){
+ if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
+ qCWarning(dcZigbeeRemotes()) << "Reading power configuration cluster attributes finished with error" << reply->error();
+ return;
+ }
+ thing->setStateValue("batteryLevel", powerCluster->batteryPercentage());
+ thing->setStateValue("batteryCritical", (powerCluster->batteryPercentage() < 10.0));
+ });
+
+ // Connect to battery level changes
+ connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){
+ thing->setStateValue("batteryLevel", percentage);
+ thing->setStateValue("batteryCritical", (percentage < 10.0));
+ });
+ }
+}
diff --git a/zigbeeremotes/integrationpluginzigbeeremotes.h b/zigbeeremotes/integrationpluginzigbeeremotes.h
new file mode 100644
index 00000000..0afc9fe3
--- /dev/null
+++ b/zigbeeremotes/integrationpluginzigbeeremotes.h
@@ -0,0 +1,73 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 INTEGRATIONPLUGINZIGBEEREMOTES_H
+#define INTEGRATIONPLUGINZIGBEEREMOTES_H
+
+#include "integrations/integrationplugin.h"
+#include "hardware/zigbee/zigbeehandler.h"
+#include "plugintimer.h"
+
+#include "extern-plugininfo.h"
+
+#include
+
+class IntegrationPluginZigbeeRemotes: public IntegrationPlugin, public ZigbeeHandler
+{
+ Q_OBJECT
+
+ Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginzigbeeremotes.json")
+ Q_INTERFACES(IntegrationPlugin)
+
+public:
+ explicit IntegrationPluginZigbeeRemotes();
+
+ 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 thingRemoved(Thing *thing) override;
+
+private:
+ QHash m_thingNodes;
+
+ void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
+
+ void bindPowerConfigurationCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
+ void bindOnOffCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
+ void bindLevelControlCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
+ void bindScenesCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
+
+ void connectToPowerConfigurationCluster(Thing *thing, ZigbeeNodeEndpoint *endpoint);
+};
+
+#endif // INTEGRATIONPLUGINZIGBEEREMOTES_H
diff --git a/zigbeeremotes/integrationpluginzigbeeremotes.json b/zigbeeremotes/integrationpluginzigbeeremotes.json
new file mode 100644
index 00000000..aa2255f6
--- /dev/null
+++ b/zigbeeremotes/integrationpluginzigbeeremotes.json
@@ -0,0 +1,75 @@
+{
+ "name": "ZigbeeRemotes",
+ "displayName": "Zigbee remotes",
+ "id": "d0184b49-6e6d-42fe-92e1-e2ede67ca7df",
+ "vendors": [
+ {
+ "name": "jung",
+ "displayName": "JUNG GmbH",
+ "id": "521ade0c-fad5-49a9-99f5-e2bc124c01a5",
+ "thingClasses": [
+ {
+ "id": "f81ad8c0-29e3-4284-ad3a-393e11c2cc37",
+ "name": "insta",
+ "displayName": "JUNG ZLL 5004",
+ "createMethods": ["auto"],
+ "interfaces": ["multibutton", "wirelessconnectable"],
+ "paramTypes": [
+ {
+ "id": "93da9fd8-9068-476c-8ff3-53fe51a11808",
+ "name": "ieeeAddress",
+ "displayName": "IEEE adress",
+ "type": "QString",
+ "defaultValue": "00:00:00:00:00:00:00:00"
+ },
+ {
+ "id": "4b425f78-0300-49bc-8c89-cdf651940da4",
+ "name": "networkUuid",
+ "displayName": "Zigbee network UUID",
+ "type": "QString",
+ "defaultValue": ""
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "bf6d6426-a967-4084-86bf-4edd2d074316",
+ "name": "connected",
+ "displayName": "Connected",
+ "displayNameEvent": "Connected or disconnected",
+ "type": "bool",
+ "defaultValue": false,
+ "cached": false
+ },
+ {
+ "id": "3859cc17-b534-4e00-be3b-6fbdb67ed0fe",
+ "name": "signalStrength",
+ "displayName": "Signal strength",
+ "displayNameEvent": "Signal strength changed",
+ "type": "uint",
+ "minValue": 0,
+ "maxValue": 100,
+ "unit": "Percentage",
+ "defaultValue": 0
+ }
+ ],
+ "eventTypes": [
+ {
+ "id": "407d2e3e-4aca-4021-a79b-4b896e9c2440",
+ "name": "pressed",
+ "displayName": "Pressed",
+ "paramTypes": [
+ {
+ "id": "135a1871-ea74-45fd-ac26-5d8ca21586a3",
+ "name": "buttonName",
+ "displayName": "Button",
+ "type": "QString",
+ "allowedValues": ["OFF", "ON", "+", "-", "1", "2", "3", "4", "5", "6"]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/zigbeeremotes/meta.json b/zigbeeremotes/meta.json
new file mode 100644
index 00000000..c3b0679f
--- /dev/null
+++ b/zigbeeremotes/meta.json
@@ -0,0 +1,13 @@
+{
+ "title": "ZigBee remotes",
+ "tagline": "A plugin for various zigbee remotes.",
+ "icon": "zigbee.svg",
+ "stability": "consumer",
+ "offline": true,
+ "technologies": [
+ "zigbee"
+ ],
+ "categories": [
+ "socket"
+ ]
+}
diff --git a/zigbeeremotes/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts b/zigbeeremotes/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts
new file mode 100644
index 00000000..799a029c
--- /dev/null
+++ b/zigbeeremotes/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts
@@ -0,0 +1,439 @@
+
+
+
+
+ ZigbeeGeneric
+
+
+
+
+
+ Battery
+ The name of the ParamType (ThingClass: doorLock, EventType: batteryLevel, ID: {568e5bdd-47f3-4ccb-a1d8-ff3a5ea87ad8})
+----------
+The name of the StateType ({568e5bdd-47f3-4ccb-a1d8-ff3a5ea87ad8}) of ThingClass doorLock
+----------
+The name of the ParamType (ThingClass: thermostat, EventType: batteryLevel, ID: {3a733e99-850b-4c56-b058-d39850ef2fee})
+----------
+The name of the StateType ({3a733e99-850b-4c56-b058-d39850ef2fee}) of ThingClass thermostat
+
+
+
+
+
+ Battery changed
+ The name of the EventType ({568e5bdd-47f3-4ccb-a1d8-ff3a5ea87ad8}) of ThingClass doorLock
+----------
+The name of the EventType ({3a733e99-850b-4c56-b058-d39850ef2fee}) of ThingClass thermostat
+
+
+
+
+
+
+
+
+
+ Battery critical
+ The name of the ParamType (ThingClass: doorSensor, EventType: batteryCritical, ID: {9628450e-5580-4f30-8af7-f1c3093dcfb7})
+----------
+The name of the StateType ({9628450e-5580-4f30-8af7-f1c3093dcfb7}) of ThingClass doorSensor
+----------
+The name of the ParamType (ThingClass: doorLock, EventType: batteryCritical, ID: {89abea26-b772-4258-9b56-e026b80c2028})
+----------
+The name of the StateType ({89abea26-b772-4258-9b56-e026b80c2028}) of ThingClass doorLock
+----------
+The name of the ParamType (ThingClass: thermostat, EventType: batteryCritical, ID: {5cec4399-ba7c-4c78-8c30-c91040ad99cf})
+----------
+The name of the StateType ({5cec4399-ba7c-4c78-8c30-c91040ad99cf}) of ThingClass thermostat
+
+
+
+
+
+
+ Battery critical changed
+ The name of the EventType ({9628450e-5580-4f30-8af7-f1c3093dcfb7}) of ThingClass doorSensor
+----------
+The name of the EventType ({89abea26-b772-4258-9b56-e026b80c2028}) of ThingClass doorLock
+----------
+The name of the EventType ({5cec4399-ba7c-4c78-8c30-c91040ad99cf}) of ThingClass thermostat
+
+
+
+
+
+ Battery level
+ The name of the ParamType (ThingClass: doorSensor, EventType: batteryLevel, ID: {3c120c1c-0093-4c5e-8d7e-8892e4ce21b3})
+----------
+The name of the StateType ({3c120c1c-0093-4c5e-8d7e-8892e4ce21b3}) of ThingClass doorSensor
+
+
+
+
+ Battery level changed
+ The name of the EventType ({3c120c1c-0093-4c5e-8d7e-8892e4ce21b3}) of ThingClass doorSensor
+
+
+
+
+
+ Closed
+ The name of the ParamType (ThingClass: doorSensor, EventType: closed, ID: {2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44})
+----------
+The name of the StateType ({2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44}) of ThingClass doorSensor
+
+
+
+
+
+
+
+
+
+
+
+ Connected
+ The name of the ParamType (ThingClass: doorSensor, EventType: connected, ID: {4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e})
+----------
+The name of the StateType ({4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e}) of ThingClass doorSensor
+----------
+The name of the ParamType (ThingClass: doorLock, EventType: connected, ID: {206b0508-b477-4aa2-b420-aba2259fb6e6})
+----------
+The name of the StateType ({206b0508-b477-4aa2-b420-aba2259fb6e6}) of ThingClass doorLock
+----------
+The name of the ParamType (ThingClass: powerSocket, EventType: connected, ID: {b5abd47e-95f1-4e35-94fa-be87c396073a})
+----------
+The name of the StateType ({b5abd47e-95f1-4e35-94fa-be87c396073a}) of ThingClass powerSocket
+----------
+The name of the ParamType (ThingClass: thermostat, EventType: connected, ID: {e9fb2b10-96da-4b70-afda-46e948399af8})
+----------
+The name of the StateType ({e9fb2b10-96da-4b70-afda-46e948399af8}) of ThingClass thermostat
+
+
+
+
+
+ Connected changed
+ The name of the EventType ({206b0508-b477-4aa2-b420-aba2259fb6e6}) of ThingClass doorLock
+----------
+The name of the EventType ({b5abd47e-95f1-4e35-94fa-be87c396073a}) of ThingClass powerSocket
+
+
+
+
+ Connected or disconnected
+ The name of the EventType ({4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e}) of ThingClass doorSensor
+
+
+
+
+ Connected/disconnected
+ The name of the EventType ({e9fb2b10-96da-4b70-afda-46e948399af8}) of ThingClass thermostat
+
+
+
+
+
+ Cooling on
+ The name of the ParamType (ThingClass: thermostat, EventType: coolingOn, ID: {c77a3d3f-46c7-4026-b9ab-02ab88077cc4})
+----------
+The name of the StateType ({c77a3d3f-46c7-4026-b9ab-02ab88077cc4}) of ThingClass thermostat
+
+
+
+
+ Cooling turned on
+ The name of the EventType ({c77a3d3f-46c7-4026-b9ab-02ab88077cc4}) of ThingClass thermostat
+
+
+
+
+
+ Current temperature
+ The name of the ParamType (ThingClass: thermostat, EventType: temperature, ID: {497af03a-a893-438c-aba2-1bf3ecfc66c5})
+----------
+The name of the StateType ({497af03a-a893-438c-aba2-1bf3ecfc66c5}) of ThingClass thermostat
+
+
+
+
+ Current temperature changed
+ The name of the EventType ({497af03a-a893-438c-aba2-1bf3ecfc66c5}) of ThingClass thermostat
+
+
+
+
+ Door lock
+ The name of the ThingClass ({34cb3d09-dd9f-4b95-95d0-30a1cd94adac})
+
+
+
+
+ Door sensor
+ The name of the ThingClass ({fd43b442-1764-4005-acaf-9075e6d11e3a})
+
+
+
+
+
+
+
+ Endpoint ID
+ The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {e265b17c-e4f4-4bea-b299-a6a3d94a6e7a})
+----------
+The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {ebf17460-4a37-461f-aa24-e0a9a4238c63})
+----------
+The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {c7cbda61-2b84-4f2f-a40d-bcbe0efad08c})
+----------
+The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {138a529d-1d85-410a-9d83-93ebc9a5f8ca})
+
+
+
+
+
+ Heating on
+ The name of the ParamType (ThingClass: thermostat, EventType: heatingOn, ID: {88d5dda1-b8f6-49f1-a55a-20415f9157b3})
+----------
+The name of the StateType ({88d5dda1-b8f6-49f1-a55a-20415f9157b3}) of ThingClass thermostat
+
+
+
+
+ Heating turned on
+ The name of the EventType ({88d5dda1-b8f6-49f1-a55a-20415f9157b3}) of ThingClass thermostat
+
+
+
+
+
+
+
+ IEEE adress
+ The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {98d4265d-99b7-4849-97ec-a7eae3b275ff})
+----------
+The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {484bf80f-5d20-4029-b05e-6b4c9fbefd69})
+----------
+The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {1db22159-08a3-43d0-b515-7b34211b1d04})
+----------
+The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {f38746d8-0084-43a3-b645-3ec743ea5fbc})
+
+
+
+
+ Identify
+ The name of the ActionType ({4e3b1430-d98e-4f05-bae6-301dac34bd4b}) of ThingClass powerSocket
+
+
+
+
+ Lock door
+ The name of the ActionType ({c26e1908-25d0-4475-8f82-5aaf034640f1}) of ThingClass doorLock
+
+
+
+
+
+
+
+ Manufacturer
+ The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {193922e4-2c74-4748-a319-9e5b2f2607b4})
+----------
+The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {1b177eb8-a13f-4975-92a7-a6bf54670c8f})
+----------
+The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {8daa4709-1dc1-4717-a529-b78e32002b59})
+----------
+The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {ae76acb0-40f4-440b-8ae7-16969fe6c91a})
+
+
+
+
+
+
+
+ Model
+ The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {74ddad9e-6849-4b7a-a356-971e77e5195b})
+----------
+The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {b13f86a7-dc65-4ed6-860c-cdb099f90916})
+----------
+The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {ad03bc04-857a-43a9-8bea-a3c9db24461a})
+----------
+The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {4262cfc6-4b04-49fd-af2b-765afca53b0b})
+
+
+
+
+ Opened or closed
+ The name of the EventType ({2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44}) of ThingClass doorSensor
+
+
+
+
+
+
+ Power
+ The name of the ParamType (ThingClass: powerSocket, ActionType: power, ID: {2c8268b9-d76b-415a-b2e9-6bfeabd98a76})
+----------
+The name of the ParamType (ThingClass: powerSocket, EventType: power, ID: {2c8268b9-d76b-415a-b2e9-6bfeabd98a76})
+----------
+The name of the StateType ({2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) of ThingClass powerSocket
+
+
+
+
+ Power changed
+ The name of the EventType ({2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) of ThingClass powerSocket
+
+
+
+
+ Power socket
+ The name of the ThingClass ({800a8df8-06cb-4d93-8334-944fcce9651a})
+
+
+
+
+ Set power
+ The name of the ActionType ({2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) of ThingClass powerSocket
+
+
+
+
+ Set target temperature
+ The name of the ActionType ({88ad3957-2912-4de1-b53d-b360565dd361}) of ThingClass thermostat
+
+
+
+
+
+
+
+
+
+
+
+ Signal strength
+ The name of the ParamType (ThingClass: doorSensor, EventType: signalStrength, ID: {a1bf9c90-6e12-4513-a82a-a1d15351f140})
+----------
+The name of the StateType ({a1bf9c90-6e12-4513-a82a-a1d15351f140}) of ThingClass doorSensor
+----------
+The name of the ParamType (ThingClass: doorLock, EventType: signalStrength, ID: {6c8f8db5-464c-408a-9c65-4e8096663019})
+----------
+The name of the StateType ({6c8f8db5-464c-408a-9c65-4e8096663019}) of ThingClass doorLock
+----------
+The name of the ParamType (ThingClass: powerSocket, EventType: signalStrength, ID: {21889797-32c0-4f1b-903d-8af71981882b})
+----------
+The name of the StateType ({21889797-32c0-4f1b-903d-8af71981882b}) of ThingClass powerSocket
+----------
+The name of the ParamType (ThingClass: thermostat, EventType: signalStrength, ID: {8f0512ab-ced2-4dcb-90fe-aaa532efd0dd})
+----------
+The name of the StateType ({8f0512ab-ced2-4dcb-90fe-aaa532efd0dd}) of ThingClass thermostat
+
+
+
+
+
+
+
+ Signal strength changed
+ The name of the EventType ({a1bf9c90-6e12-4513-a82a-a1d15351f140}) of ThingClass doorSensor
+----------
+The name of the EventType ({6c8f8db5-464c-408a-9c65-4e8096663019}) of ThingClass doorLock
+----------
+The name of the EventType ({21889797-32c0-4f1b-903d-8af71981882b}) of ThingClass powerSocket
+----------
+The name of the EventType ({8f0512ab-ced2-4dcb-90fe-aaa532efd0dd}) of ThingClass thermostat
+
+
+
+
+
+
+ Target temperature
+ The name of the ParamType (ThingClass: thermostat, ActionType: targetTemperature, ID: {88ad3957-2912-4de1-b53d-b360565dd361})
+----------
+The name of the ParamType (ThingClass: thermostat, EventType: targetTemperature, ID: {88ad3957-2912-4de1-b53d-b360565dd361})
+----------
+The name of the StateType ({88ad3957-2912-4de1-b53d-b360565dd361}) of ThingClass thermostat
+
+
+
+
+ Target temperature changed
+ The name of the EventType ({88ad3957-2912-4de1-b53d-b360565dd361}) of ThingClass thermostat
+
+
+
+
+ Unlock door
+ The name of the ActionType ({6e112e3b-080f-47e4-8e2b-453029f0eacb}) of ThingClass doorLock
+
+
+
+
+
+
+
+
+
+ Version
+ The name of the ParamType (ThingClass: doorLock, EventType: version, ID: {9e27850b-99d8-40df-9bc7-4b3c7c01faf8})
+----------
+The name of the StateType ({9e27850b-99d8-40df-9bc7-4b3c7c01faf8}) of ThingClass doorLock
+----------
+The name of the ParamType (ThingClass: powerSocket, EventType: version, ID: {41c74445-4d2d-46dc-8a63-c98f1df8e742})
+----------
+The name of the StateType ({41c74445-4d2d-46dc-8a63-c98f1df8e742}) of ThingClass powerSocket
+----------
+The name of the ParamType (ThingClass: thermostat, EventType: version, ID: {c8bd12d2-b425-4422-9e0e-a65542a47b70})
+----------
+The name of the StateType ({c8bd12d2-b425-4422-9e0e-a65542a47b70}) of ThingClass thermostat
+
+
+
+
+
+
+ Version changed
+ The name of the EventType ({9e27850b-99d8-40df-9bc7-4b3c7c01faf8}) of ThingClass doorLock
+----------
+The name of the EventType ({41c74445-4d2d-46dc-8a63-c98f1df8e742}) of ThingClass powerSocket
+----------
+The name of the EventType ({c8bd12d2-b425-4422-9e0e-a65542a47b70}) of ThingClass thermostat
+
+
+
+
+ Zigbee Generic
+ The name of the plugin ZigbeeGeneric ({6a4343be-9fd6-4015-9ff5-38542651c534})
+
+
+
+
+ Zigbee Thermostat
+ The name of the ThingClass ({ca9af6cf-2d15-4d54-ba07-3d2ce03445b8})
+
+
+
+
+
+
+
+ Zigbee network UUID
+ The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {260cb70b-7cb9-46b9-b6f3-0d4810a016b7})
+----------
+The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {4d50cbd3-f297-421c-9938-65ec0bb4bd34})
+----------
+The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {26e92d1d-bc2f-4ccd-ad1f-d6d6189d2609})
+----------
+The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {4a92b536-de4c-4701-8117-9bb26dd51c3e})
+
+
+
+
+ nymea
+ The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6})
+
+
+
+
diff --git a/zigbeeremotes/zigbee.svg b/zigbeeremotes/zigbee.svg
new file mode 100644
index 00000000..5366feb6
--- /dev/null
+++ b/zigbeeremotes/zigbee.svg
@@ -0,0 +1,179 @@
+
+
+
+
diff --git a/zigbeeremotes/zigbeeremotes.pro b/zigbeeremotes/zigbeeremotes.pro
new file mode 100644
index 00000000..008765b2
--- /dev/null
+++ b/zigbeeremotes/zigbeeremotes.pro
@@ -0,0 +1,12 @@
+include(../plugins.pri)
+
+PKGCONFIG += nymea-zigbee
+
+SOURCES += \
+ integrationpluginzigbeeremotes.cpp
+
+HEADERS += \
+ integrationpluginzigbeeremotes.h
+
+
+