Add zigbee develco plugin containing IO Module
parent
80d1a3798b
commit
e733644d6a
|
|
@ -0,0 +1 @@
|
|||
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginzigbeedevelco.so
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Develco ZigBee
|
||||
|
||||
This plugin allows to interact with ZigBee devices from [Develco](https://www.develcoproducts.com/).
|
||||
|
||||
## Supported Things
|
||||
|
||||
In order to bring a ZigBee device into the nymea ZigBee network, the network needs to be opened for joining before you perform the device pairing instructions. The joining process can take up to 30 seconds. If the device does not show up, please restart the pairing process.
|
||||
|
||||
### IO Module
|
||||
|
||||
The [Develco IO Module](https://www.develcoproducts.com/products/smart-relays/io-module/) is fully supported.
|
||||
|
||||
**Pairing instructions**: Open the ZigBee network for joining. Press and hold the reset button of the IO module until the LED blinks constanly.
|
||||
|
||||
## Requirements
|
||||
|
||||
* A compatible ZigBee controller and a running ZigBee network in nymea. You can find more information about supported controllers and ZigBee network configurations [here](https://nymea.io/documentation/users/usage/configuration#zigbee).
|
||||
|
||||
|
|
@ -0,0 +1,643 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
*
|
||||
* Copyright 2013 - 2021, 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 "integrationpluginzigbeedevelco.h"
|
||||
#include "plugininfo.h"
|
||||
#include "hardware/zigbee/zigbeehardwareresource.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <zigbeeutils.h>
|
||||
|
||||
IntegrationPluginZigbeeDevelco::IntegrationPluginZigbeeDevelco()
|
||||
{
|
||||
m_ieeeAddressParamTypeIds[ioModuleThingClassId] = ioModuleThingIeeeAddressParamTypeId;
|
||||
|
||||
m_networkUuidParamTypeIds[ioModuleThingClassId] = ioModuleThingNetworkUuidParamTypeId;
|
||||
|
||||
m_connectedStateTypeIds[ioModuleThingClassId] = ioModuleConnectedStateTypeId;
|
||||
|
||||
m_signalStrengthStateTypeIds[ioModuleThingClassId] = ioModuleSignalStrengthStateTypeId;
|
||||
}
|
||||
|
||||
QString IntegrationPluginZigbeeDevelco::name() const
|
||||
{
|
||||
return "Develco";
|
||||
}
|
||||
|
||||
bool IntegrationPluginZigbeeDevelco::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
|
||||
{
|
||||
// Filter for develco manufacturer code
|
||||
if (node->nodeDescriptor().manufacturerCode != Zigbee::Develco)
|
||||
return false;
|
||||
|
||||
bool handled = false;
|
||||
if (node->modelName() == "IOMZB-110" || node->modelName() == "DIOZB-110") {
|
||||
if (node->hasEndpoint(IO_MODULE_EP_INPUT1) && node->hasEndpoint(IO_MODULE_EP_INPUT2) &&
|
||||
node->hasEndpoint(IO_MODULE_EP_INPUT3) && node->hasEndpoint(IO_MODULE_EP_INPUT4) &&
|
||||
node->hasEndpoint(IO_MODULE_EP_OUTPUT1 && node->hasEndpoint(IO_MODULE_EP_OUTPUT2))) {
|
||||
qCDebug(dcZigbeeDevelco()) << "Found IO module" << node << networkUuid.toString();
|
||||
initIoModule(node);
|
||||
createThing(ioModuleThingClassId, networkUuid, node);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid)
|
||||
{
|
||||
Q_UNUSED(networkUuid)
|
||||
Thing *thing = m_thingNodes.key(node);
|
||||
if (thing) {
|
||||
qCDebug(dcZigbeeDevelco()) << 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 IntegrationPluginZigbeeDevelco::init()
|
||||
{
|
||||
hardwareManager()->zigbeeResource()->registerHandler(this, ZigbeeHardwareResource::HandlerTypeVendor);
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
qCDebug(dcZigbeeDevelco()) << "Setup" << info->thing();
|
||||
|
||||
// Get the node for this thing
|
||||
Thing *thing = info->thing();
|
||||
QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
|
||||
ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_ieeeAddressParamTypeIds.value(thing->thingClassId())).toString());
|
||||
ZigbeeNode *node = m_thingNodes.value(thing);
|
||||
if (!node) {
|
||||
node = hardwareManager()->zigbeeResource()->claimNode(this, networkUuid, zigbeeAddress);
|
||||
if (!node) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Coud not find zigbee node for" << thing;
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_thingNodes.insert(thing, node);
|
||||
|
||||
// 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(dcZigbeeDevelco()) << thing << "signal strength changed" << signalStrength << "%";
|
||||
thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength);
|
||||
});
|
||||
|
||||
if (thing->thingClassId() == ioModuleThingClassId) {
|
||||
// Set the version from the manufacturer specific attribute in base cluster
|
||||
ZigbeeNodeEndpoint *primaryEndpoint = node->getEndpoint(IO_MODULE_EP_INPUT1);
|
||||
if (!primaryEndpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to set up IO module" << thing << ". Could not find endpoint for version parsing.";
|
||||
info->finish(Thing::ThingErrorSetupFailed);
|
||||
return;
|
||||
}
|
||||
if (primaryEndpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
|
||||
ZigbeeCluster *basicCluster = primaryEndpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdBasic);
|
||||
if (basicCluster->hasAttribute(DEVELCO_ATTRIBUTE_SW_VERSION)) {
|
||||
thing->setStateValue(ioModuleVersionStateTypeId, parseDevelcoVersionString(primaryEndpoint));
|
||||
} else {
|
||||
readDevelcoFirmwareVersion(node, primaryEndpoint);
|
||||
}
|
||||
|
||||
connect(basicCluster, &ZigbeeCluster::attributeChanged, this, [=](const ZigbeeClusterAttribute &attribute){
|
||||
if (attribute.id() == DEVELCO_ATTRIBUTE_SW_VERSION) {
|
||||
thing->setStateValue(ioModuleVersionStateTypeId, parseDevelcoVersionString(primaryEndpoint));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle reachable state from node
|
||||
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), node->reachable());
|
||||
connect(node, &ZigbeeNode::reachableChanged, thing, [=](bool reachable){
|
||||
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), reachable);
|
||||
if (reachable) {
|
||||
readDevelcoFirmwareVersion(node, node->getEndpoint(IO_MODULE_EP_INPUT1));
|
||||
readIoModuleOutputPowerStates(thing);
|
||||
readIoModuleInputPowerStates(thing);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Output 1
|
||||
ZigbeeNodeEndpoint *output1Endpoint = node->getEndpoint(IO_MODULE_EP_OUTPUT1);
|
||||
if (!output1Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for output 1 on" << thing << node;
|
||||
} else {
|
||||
ZigbeeClusterOnOff *onOffCluster = output1Endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
||||
if (!onOffCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find On/Off cluster on" << thing << node << output1Endpoint;
|
||||
} else {
|
||||
if (onOffCluster->hasAttribute(ZigbeeClusterOnOff::AttributeOnOff)) {
|
||||
thing->setStateValue(ioModuleOutput1StateTypeId, onOffCluster->power());
|
||||
}
|
||||
connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){
|
||||
qCDebug(dcZigbeeDevelco()) << thing << "output 1 power changed to" << power;
|
||||
thing->setStateValue(ioModuleOutput1StateTypeId, power);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Output 2
|
||||
ZigbeeNodeEndpoint *output2Endpoint = node->getEndpoint(IO_MODULE_EP_OUTPUT2);
|
||||
if (!output2Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for output 2 on" << thing << node;
|
||||
} else {
|
||||
ZigbeeClusterOnOff *onOffCluster = output2Endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
||||
if (!onOffCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find On/Off cluster on" << thing << node << output2Endpoint;
|
||||
} else {
|
||||
if (onOffCluster->hasAttribute(ZigbeeClusterOnOff::AttributeOnOff)) {
|
||||
thing->setStateValue(ioModuleOutput2StateTypeId, onOffCluster->power());
|
||||
}
|
||||
connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){
|
||||
qCDebug(dcZigbeeDevelco()) << thing << "output 2 power changed to" << power;
|
||||
thing->setStateValue(ioModuleOutput2StateTypeId, power);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Input 1
|
||||
ZigbeeNodeEndpoint *input1Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT1);
|
||||
if (!input1Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 1 on" << thing << node;
|
||||
} else {
|
||||
ZigbeeClusterBinaryInput *binaryInputCluster = input1Endpoint->inputCluster<ZigbeeClusterBinaryInput>(ZigbeeClusterLibrary::ClusterIdBinaryInput);
|
||||
if (!binaryInputCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find BinaryInput cluster on" << thing << node << input1Endpoint;
|
||||
} else {
|
||||
if (binaryInputCluster->hasAttribute(ZigbeeClusterLibrary::ClusterIdBinaryInput)) {
|
||||
thing->setStateValue(ioModuleInput1StateTypeId, binaryInputCluster->presentValue());
|
||||
}
|
||||
connect(binaryInputCluster, &ZigbeeClusterBinaryInput::presentValueChanged, thing, [thing](bool presentValue){
|
||||
qCDebug(dcZigbeeDevelco()) << thing << "input 1 changed to" << presentValue;
|
||||
thing->setStateValue(ioModuleInput1StateTypeId, presentValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Input 2
|
||||
ZigbeeNodeEndpoint *input2Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT2);
|
||||
if (!input2Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 2 on" << thing << node;
|
||||
} else {
|
||||
ZigbeeClusterBinaryInput *binaryInputCluster = input2Endpoint->inputCluster<ZigbeeClusterBinaryInput>(ZigbeeClusterLibrary::ClusterIdBinaryInput);
|
||||
if (!binaryInputCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find BinaryInput cluster on" << thing << node << input2Endpoint;
|
||||
} else {
|
||||
if (binaryInputCluster->hasAttribute(ZigbeeClusterLibrary::ClusterIdBinaryInput)) {
|
||||
thing->setStateValue(ioModuleInput2StateTypeId, binaryInputCluster->presentValue());
|
||||
}
|
||||
connect(binaryInputCluster, &ZigbeeClusterBinaryInput::presentValueChanged, thing, [thing](bool presentValue){
|
||||
qCDebug(dcZigbeeDevelco()) << thing << "input 2 changed to" << presentValue;
|
||||
thing->setStateValue(ioModuleInput2StateTypeId, presentValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Input 3
|
||||
ZigbeeNodeEndpoint *input3Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT3);
|
||||
if (!input3Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 3 on" << thing << node;
|
||||
} else {
|
||||
ZigbeeClusterBinaryInput *binaryInputCluster = input3Endpoint->inputCluster<ZigbeeClusterBinaryInput>(ZigbeeClusterLibrary::ClusterIdBinaryInput);
|
||||
if (!binaryInputCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find BinaryInput cluster on" << thing << node << input3Endpoint;
|
||||
} else {
|
||||
if (binaryInputCluster->hasAttribute(ZigbeeClusterLibrary::ClusterIdBinaryInput)) {
|
||||
thing->setStateValue(ioModuleInput3StateTypeId, binaryInputCluster->presentValue());
|
||||
}
|
||||
connect(binaryInputCluster, &ZigbeeClusterBinaryInput::presentValueChanged, thing, [thing](bool presentValue){
|
||||
qCDebug(dcZigbeeDevelco()) << thing << "input 3 changed to" << presentValue;
|
||||
thing->setStateValue(ioModuleInput3StateTypeId, presentValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Input 4
|
||||
ZigbeeNodeEndpoint *input4Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT4);
|
||||
if (!input4Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 4 on" << thing << node;
|
||||
} else {
|
||||
ZigbeeClusterBinaryInput *binaryInputCluster = input4Endpoint->inputCluster<ZigbeeClusterBinaryInput>(ZigbeeClusterLibrary::ClusterIdBinaryInput);
|
||||
if (!binaryInputCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find BinaryInput cluster on" << thing << node << input4Endpoint;
|
||||
} else {
|
||||
if (binaryInputCluster->hasAttribute(ZigbeeClusterLibrary::ClusterIdBinaryInput)) {
|
||||
thing->setStateValue(ioModuleInput4StateTypeId, binaryInputCluster->presentValue());
|
||||
}
|
||||
connect(binaryInputCluster, &ZigbeeClusterBinaryInput::presentValueChanged, thing, [thing](bool presentValue){
|
||||
qCDebug(dcZigbeeDevelco()) << thing << "input 4 changed to" << presentValue;
|
||||
thing->setStateValue(ioModuleInput4StateTypeId, presentValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::postSetupThing(Thing *thing)
|
||||
{
|
||||
if (thing->thingClassId() == ioModuleThingClassId) {
|
||||
if (m_thingNodes.value(thing)->reachable()) {
|
||||
readIoModuleOutputPowerStates(thing);
|
||||
readIoModuleInputPowerStates(thing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::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;
|
||||
}
|
||||
|
||||
if (thing->thingClassId() == ioModuleThingClassId) {
|
||||
// Identify
|
||||
if (info->action().actionTypeId() == ioModuleAlertActionTypeId) {
|
||||
ZigbeeNodeEndpoint *primaryEndpoint = node->getEndpoint(IO_MODULE_EP_INPUT1);
|
||||
if (!primaryEndpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for execute action on" << thing << node;
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
ZigbeeClusterIdentify *identifyCluster = primaryEndpoint->inputCluster<ZigbeeClusterIdentify>(ZigbeeClusterLibrary::ClusterIdIdentify);
|
||||
if (!identifyCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "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;
|
||||
}
|
||||
|
||||
// Output 1
|
||||
if (info->action().actionTypeId() == ioModuleOutput1ActionTypeId) {
|
||||
bool power = info->action().paramValue(ioModuleOutput1ActionOutput1ParamTypeId).toBool();
|
||||
qCDebug(dcZigbeeDevelco()) << "Set output 1 power of" << thing << "to" << power;
|
||||
|
||||
ZigbeeNodeEndpoint *output1Endpoint = node->getEndpoint(IO_MODULE_EP_OUTPUT1);
|
||||
if (!output1Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for output 1 on" << thing << node;
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
} else {
|
||||
ZigbeeClusterOnOff *onOffCluster = output1Endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
||||
if (!onOffCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find On/Off cluster on" << thing << node << output1Endpoint;
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
} else {
|
||||
ZigbeeClusterReply *reply = (power ? onOffCluster->commandOn() : onOffCluster->commandOff());
|
||||
connect(reply, &ZigbeeClusterReply::finished, info, [=](){
|
||||
// Note: reply will be deleted automatically
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to set power for output 1 on" << thing << reply->error();
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
} else {
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
qCDebug(dcZigbeeDevelco()) << "Set power on output 1 finished successfully for" << thing;
|
||||
thing->setStateValue(ioModuleOutput1StateTypeId, power);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output 2
|
||||
if (info->action().actionTypeId() == ioModuleOutput2ActionTypeId) {
|
||||
bool power = info->action().paramValue(ioModuleOutput2ActionOutput2ParamTypeId).toBool();
|
||||
qCDebug(dcZigbeeDevelco()) << "Set output 2 power of" << thing << "to" << power;
|
||||
|
||||
ZigbeeNodeEndpoint *output2Endpoint = node->getEndpoint(IO_MODULE_EP_OUTPUT2);
|
||||
if (!output2Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for output 2 on" << thing << node;
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
} else {
|
||||
ZigbeeClusterOnOff *onOffCluster = output2Endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
||||
if (!onOffCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find On/Off cluster on" << thing << node << output2Endpoint;
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
} else {
|
||||
ZigbeeClusterReply *reply = (power ? onOffCluster->commandOn() : onOffCluster->commandOff());
|
||||
connect(reply, &ZigbeeClusterReply::finished, info, [=](){
|
||||
// Note: reply will be deleted automatically
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to set power for output 2 on" << thing << reply->error();
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
} else {
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
qCDebug(dcZigbeeDevelco()) << "Set power on output 2 finished successfully for" << thing;
|
||||
thing->setStateValue(ioModuleOutput2StateTypeId, power);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorUnsupportedFeature);
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::thingRemoved(Thing *thing)
|
||||
{
|
||||
ZigbeeNode *node = m_thingNodes.take(thing);
|
||||
if (node) {
|
||||
QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
|
||||
hardwareManager()->zigbeeResource()->removeNodeFromNetwork(networkUuid, node);
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node)
|
||||
{
|
||||
ThingDescriptor descriptor(thingClassId);
|
||||
QString deviceClassName = supportedThings().findById(thingClassId).displayName();
|
||||
descriptor.setTitle(QString("%1 (%2 - %3)").arg(deviceClassName, node->manufacturerName(), node->modelName()));
|
||||
|
||||
ParamList params;
|
||||
params.append(Param(m_networkUuidParamTypeIds[thingClassId], networkUuid.toString()));
|
||||
params.append(Param(m_ieeeAddressParamTypeIds[thingClassId], node->extendedAddress().toString()));
|
||||
descriptor.setParams(params);
|
||||
emit autoThingsAppeared({descriptor});
|
||||
}
|
||||
|
||||
QString IntegrationPluginZigbeeDevelco::parseDevelcoVersionString(ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
QString versionString;
|
||||
ZigbeeCluster *basicCluster = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdBasic);
|
||||
if (!basicCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find basic cluster on" << endpoint << "for version parsing";
|
||||
return versionString;
|
||||
}
|
||||
|
||||
if (!basicCluster->hasAttribute(DEVELCO_ATTRIBUTE_SW_VERSION)) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find manufacturer specific develco software version attribute in basic cluster on" << endpoint;
|
||||
return versionString;
|
||||
}
|
||||
|
||||
ZigbeeClusterAttribute versionAttribute = basicCluster->attribute(DEVELCO_ATTRIBUTE_SW_VERSION);
|
||||
// 1 Byte octet string length, 3 byte version infromation
|
||||
if (versionAttribute.dataType().data().length() < 4 || versionAttribute.dataType().data().at(0) != 3) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to parse version string from manufacturer specific develco software version attribute" << versionAttribute;
|
||||
return versionString;
|
||||
}
|
||||
|
||||
int majorVersion = static_cast<int>(versionAttribute.dataType().data().at(1));
|
||||
int minorVersion = static_cast<int>(versionAttribute.dataType().data().at(2));
|
||||
int patchVersion = static_cast<int>(versionAttribute.dataType().data().at(3));
|
||||
versionString = QString("%1.%2.%3").arg(majorVersion).arg(minorVersion).arg(patchVersion);
|
||||
//qCDebug(dcZigbeeDevelco()) << versionAttribute << ZigbeeUtils::convertByteArrayToHexString(versionAttribute.dataType().data()) << versionString;
|
||||
|
||||
return versionString;
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::initIoModule(ZigbeeNode *node)
|
||||
{
|
||||
qCDebug(dcZigbeeDevelco()) << "Start initializing IO Module" << node;
|
||||
readDevelcoFirmwareVersion(node, node->getEndpoint(IO_MODULE_EP_INPUT1));
|
||||
configureOnOffPowerReporting(node, node->getEndpoint(IO_MODULE_EP_OUTPUT1));
|
||||
configureOnOffPowerReporting(node, node->getEndpoint(IO_MODULE_EP_OUTPUT1));
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::configureOnOffPowerReporting(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
qCDebug(dcZigbeeDevelco()) << "Bind on/off cluster to coordinator IEEE address" << node << endpoint;
|
||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
|
||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to bind on/off cluster to coordinator" << zdoReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeDevelco()) << "Bind on/off cluster to coordinator finished successfully";
|
||||
}
|
||||
|
||||
// Configure attribute reporting for lock state
|
||||
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
|
||||
reportingConfig.attributeId = ZigbeeClusterOnOff::AttributeOnOff;
|
||||
reportingConfig.dataType = Zigbee::Bool;
|
||||
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
|
||||
|
||||
qCDebug(dcZigbeeDevelco()) << "Configure attribute reporting for on/off cluster" << node << endpoint;
|
||||
ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdOnOff)->configureReporting({reportingConfig});
|
||||
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
|
||||
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed configure attribute reporting on on/off cluster" << reportingReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeDevelco()) << "Attribute reporting configuration finished for on/off cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::configureBinaryInputReporting(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
qCDebug(dcZigbeeDevelco()) << "Bind binary input cluster to coordinator IEEE address" << node << endpoint;
|
||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdBinaryInput, hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
|
||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to bind binary input cluster to coordinator" << zdoReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeDevelco()) << "Bind binary input cluster to coordinator finished successfully";
|
||||
}
|
||||
|
||||
// Configure attribute reporting for lock state
|
||||
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
|
||||
reportingConfig.attributeId = ZigbeeClusterBinaryInput::AttributePresentValue;
|
||||
reportingConfig.dataType = Zigbee::Bool;
|
||||
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
|
||||
|
||||
qCDebug(dcZigbeeDevelco()) << "Configure attribute reporting for binary input cluster" << node << endpoint;
|
||||
ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdBinaryInput)->configureReporting({reportingConfig});
|
||||
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
|
||||
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed configure attribute reporting on binary input cluster" << reportingReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeDevelco()) << "Attribute reporting configuration finished for on binary input cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::readDevelcoFirmwareVersion(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
// Read manufacturer specific basic cluster attribute 0x8000
|
||||
ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(ZigbeeClusterLibrary::ClusterIdBasic);
|
||||
if (!basicCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find basic cluster for manufacturer specific attribute reading on" << node << endpoint;
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to read the color capabilities
|
||||
ZigbeeClusterReply *reply = basicCluster->readAttributes({DEVELCO_ATTRIBUTE_SW_VERSION}, Zigbee::Develco);
|
||||
connect(reply, &ZigbeeClusterReply::finished, node, [=](){
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to read manufacturer specific version attribute on" << node << endpoint << basicCluster;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeDevelco()) << "Reading develco manufacturer specific version attributes finished successfully";
|
||||
});
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::readOnOffPowerAttribute(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
qCDebug(dcZigbeeDevelco()) << "Reading power states of" << node << "on" << endpoint;
|
||||
|
||||
ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
||||
if (!onOffCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find On/Off cluster on" << node << endpoint;
|
||||
} else {
|
||||
ZigbeeClusterReply *reply = onOffCluster->readAttributes({ZigbeeClusterOnOff::AttributeOnOff});
|
||||
connect(reply, &ZigbeeClusterReply::finished, node, [=](){
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to read On/Off power attribute from" << node << endpoint << onOffCluster;
|
||||
}
|
||||
// Will be updated trough the attribute changed signal
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::readBinaryInputPresentValueAttribute(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
ZigbeeClusterBinaryInput *binaryInputCluster = endpoint->inputCluster<ZigbeeClusterBinaryInput>(ZigbeeClusterLibrary::ClusterIdBinaryInput);
|
||||
if (!binaryInputCluster) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find BinaryInput cluster on" << node << endpoint;
|
||||
} else {
|
||||
ZigbeeClusterReply *reply = binaryInputCluster->readAttributes({ZigbeeClusterBinaryInput::AttributePresentValue});
|
||||
connect(reply, &ZigbeeClusterReply::finished, node, [=](){
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Failed to read binary input value attribute from" << node << endpoint << binaryInputCluster;
|
||||
}
|
||||
// Will be updated trough the attribute changed signal
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::readIoModuleOutputPowerStates(Thing *thing)
|
||||
{
|
||||
ZigbeeNode *node = m_thingNodes.value(thing);
|
||||
if (!node) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find zigbee node for" << thing;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeDevelco()) << "Start reading power states of" << thing << node;
|
||||
|
||||
// Read output 1 power state
|
||||
ZigbeeNodeEndpoint *output1Endpoint = node->getEndpoint(IO_MODULE_EP_OUTPUT1);
|
||||
if (!output1Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for output 1 on" << thing << node;
|
||||
} else {
|
||||
readOnOffPowerAttribute(node, output1Endpoint);
|
||||
}
|
||||
|
||||
// Read output 2 power state
|
||||
ZigbeeNodeEndpoint *output2Endpoint = node->getEndpoint(IO_MODULE_EP_OUTPUT2);
|
||||
if (!output2Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for output 2 on" << thing << node;
|
||||
} else {
|
||||
readOnOffPowerAttribute(node, output2Endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeDevelco::readIoModuleInputPowerStates(Thing *thing)
|
||||
{
|
||||
ZigbeeNode *node = m_thingNodes.value(thing);
|
||||
if (!node) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find zigbee node for" << thing;
|
||||
return;
|
||||
}
|
||||
|
||||
// Read input 1 state
|
||||
ZigbeeNodeEndpoint *input1Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT1);
|
||||
if (!input1Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 1 on" << thing << node;
|
||||
} else {
|
||||
readBinaryInputPresentValueAttribute(node, input1Endpoint);
|
||||
}
|
||||
|
||||
// Read input 2 state
|
||||
ZigbeeNodeEndpoint *input2Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT2);
|
||||
if (!input2Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 2 on" << thing << node;
|
||||
} else {
|
||||
readBinaryInputPresentValueAttribute(node, input2Endpoint);
|
||||
}
|
||||
|
||||
// Read input 3 state
|
||||
ZigbeeNodeEndpoint *input3Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT3);
|
||||
if (!input3Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 3 on" << thing << node;
|
||||
} else {
|
||||
readBinaryInputPresentValueAttribute(node, input3Endpoint);
|
||||
}
|
||||
|
||||
// Read input 4 state
|
||||
ZigbeeNodeEndpoint *input4Endpoint = node->getEndpoint(IO_MODULE_EP_INPUT4);
|
||||
if (!input4Endpoint) {
|
||||
qCWarning(dcZigbeeDevelco()) << "Could not find endpoint for input 4 on" << thing << node;
|
||||
} else {
|
||||
readBinaryInputPresentValueAttribute(node, input4Endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 INTEGRATIONPLUGINZIGBEEDEVELCO_H
|
||||
#define INTEGRATIONPLUGINZIGBEEDEVELCO_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "hardware/zigbee/zigbeehandler.h"
|
||||
#include "plugintimer.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include <zigbeereply.h>
|
||||
|
||||
/* IO Module
|
||||
*
|
||||
* https://www.develcoproducts.com/media/1967/iomzb-110-technical-manual-io-module.pdf
|
||||
*
|
||||
* Profile 0xC0C9 (Develco Products private profile)
|
||||
* Endpoints:
|
||||
* - 0x70 Simple sensor: input 1
|
||||
* - 0x71 Simple sensor: input 2
|
||||
* - 0x72 Simple sensor: input 3
|
||||
* - 0x74 Simple sensor: input 4
|
||||
* - 0x75 On/Off Output : relay 1
|
||||
* - 0x76 On/Off Output : relay 2
|
||||
*/
|
||||
#define IO_MODULE_EP_INPUT1 0x70
|
||||
#define IO_MODULE_EP_INPUT2 0x71
|
||||
#define IO_MODULE_EP_INPUT3 0x72
|
||||
#define IO_MODULE_EP_INPUT4 0x73
|
||||
#define IO_MODULE_EP_OUTPUT1 0x74
|
||||
#define IO_MODULE_EP_OUTPUT2 0x75
|
||||
|
||||
|
||||
/* Develco manufacturer specific Basic cluster attributes
|
||||
* 0x8000 Primary SW version
|
||||
* 0x8010 Primary Bootloader SW version
|
||||
* 0x8020 Primary HW version
|
||||
* 0x8030 Primary HW name
|
||||
* 0x8050 Primary SW version 3rd party
|
||||
*/
|
||||
#define DEVELCO_ATTRIBUTE_SW_VERSION 0x8000
|
||||
#define DEVELCO_ATTRIBUTE_BOOTLOADER_VERSION 0x8010
|
||||
#define DEVELCO_ATTRIBUTE_HARDWARE_VERSION 0x8020
|
||||
#define DEVELCO_ATTRIBUTE_HARDWARE_NAME 0x8030
|
||||
#define DEVELCO_ATTRIBUTE_3RD_PARTY_SW_VERSION 0x8050
|
||||
|
||||
|
||||
class IntegrationPluginZigbeeDevelco: public IntegrationPlugin, public ZigbeeHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginzigbeedevelco.json")
|
||||
Q_INTERFACES(IntegrationPlugin)
|
||||
|
||||
public:
|
||||
explicit IntegrationPluginZigbeeDevelco();
|
||||
|
||||
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 postSetupThing(Thing *thing) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
||||
private:
|
||||
QHash<Thing*, ZigbeeNode*> m_thingNodes;
|
||||
|
||||
QHash<ThingClassId, ParamTypeId> m_ieeeAddressParamTypeIds;
|
||||
QHash<ThingClassId, ParamTypeId> m_networkUuidParamTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_signalStrengthStateTypeIds;
|
||||
|
||||
// Get the endpoint for the given thing
|
||||
void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node);
|
||||
|
||||
QString parseDevelcoVersionString(ZigbeeNodeEndpoint *endpoint);
|
||||
|
||||
void initIoModule(ZigbeeNode *node);
|
||||
void configureOnOffPowerReporting(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
void configureBinaryInputReporting(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
|
||||
void readDevelcoFirmwareVersion(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
void readOnOffPowerAttribute(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
void readBinaryInputPresentValueAttribute(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
|
||||
void readIoModuleOutputPowerStates(Thing *thing);
|
||||
void readIoModuleInputPowerStates(Thing *thing);
|
||||
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINZIGBEEDEVELCO_H
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
{
|
||||
"name": "ZigbeeDevelco",
|
||||
"displayName": "Zigbee Develco",
|
||||
"id": "1b9e976d-e842-40e1-9fad-87d71a69c721",
|
||||
"vendors": [
|
||||
{
|
||||
"name": "develco",
|
||||
"displayName": "Develco",
|
||||
"id": "e4b36f3e-ccdc-4a88-8968-39025c3ec742",
|
||||
"thingClasses": [
|
||||
{
|
||||
"id": "3fb419ef-795d-4f4d-b801-e7eaff16cdb0",
|
||||
"name": "ioModule",
|
||||
"displayName": "IO Module",
|
||||
"createMethods": ["auto"],
|
||||
"interfaces": ["wirelessconnectable", "alert"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "d9a3afa7-c460-43e7-bc84-c8b5ff1adf44",
|
||||
"name": "ieeeAddress",
|
||||
"displayName": "IEEE adress",
|
||||
"type": "QString",
|
||||
"defaultValue": "00:00:00:00:00:00:00:00"
|
||||
},
|
||||
{
|
||||
"id": "f4c83d2b-06e1-4206-98b7-e3ace79ff447",
|
||||
"name": "networkUuid",
|
||||
"displayName": "Zigbee network UUID",
|
||||
"type": "QString",
|
||||
"defaultValue": ""
|
||||
}
|
||||
],
|
||||
"settingsTypes": [
|
||||
{
|
||||
"id": "c2806b97-bf94-4ad2-ae22-5b5d7d1eaf5a",
|
||||
"name": "impulseDuration",
|
||||
"displayName": "Impulse duration",
|
||||
"type": "uint",
|
||||
"unit": "MilliSeconds",
|
||||
"defaultValue": 100,
|
||||
"minValue": 10
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "16d5ebb7-21d1-4294-98a6-ca06eea8e3a3",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"cached": false,
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "0e09e6a6-8b3f-4b63-acb1-ac04ab31957a",
|
||||
"name": "signalStrength",
|
||||
"displayName": "Signal strength",
|
||||
"displayNameEvent": "Signal strength changed",
|
||||
"defaultValue": 0,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"type": "uint",
|
||||
"unit": "Percentage"
|
||||
},
|
||||
{
|
||||
"id": "f28c9a61-b8ab-419c-bd85-58692df26ac7",
|
||||
"name": "version",
|
||||
"displayName": "Version",
|
||||
"displayNameEvent": "Version changed",
|
||||
"type": "QString",
|
||||
"cached": true,
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "aaeda2c6-439a-452a-b829-45d6249bdee6",
|
||||
"name": "output1",
|
||||
"displayName": "Output 1",
|
||||
"displayNameEvent": "Output 1 changed",
|
||||
"displayNameAction": "Set output 1",
|
||||
"type": "bool",
|
||||
"writable": true,
|
||||
"defaultValue": false,
|
||||
"ioType": "digitalOutput"
|
||||
},
|
||||
{
|
||||
"id": "105cf314-35b5-4a8b-8e6d-d011009f97ff",
|
||||
"name": "output2",
|
||||
"displayName": "Output 2",
|
||||
"displayNameEvent": "Output 2 changed",
|
||||
"displayNameAction": "Set output 2",
|
||||
"type": "bool",
|
||||
"writable": true,
|
||||
"defaultValue": false,
|
||||
"ioType": "digitalOutput"
|
||||
},
|
||||
{
|
||||
"id": "bc23c7e8-f4ad-47c4-b938-f9af2dbd3393",
|
||||
"name": "input1",
|
||||
"displayName": "Input 1",
|
||||
"displayNameEvent": "Input 1 changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"ioType": "digitalInput"
|
||||
},
|
||||
{
|
||||
"id": "065b0dc0-6d31-40ec-b356-02fea57e2fe1",
|
||||
"name": "input2",
|
||||
"displayName": "Input 2",
|
||||
"displayNameEvent": "Input 2 changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"ioType": "digitalInput"
|
||||
},
|
||||
{
|
||||
"id": "8f2b052a-30b7-49aa-a8d4-503cb0b9b66b",
|
||||
"name": "input3",
|
||||
"displayName": "Input 3",
|
||||
"displayNameEvent": "Input 3 changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"ioType": "digitalInput"
|
||||
},
|
||||
{
|
||||
"id": "caef986c-da13-4ef3-ab81-316244c7be1e",
|
||||
"name": "input4",
|
||||
"displayName": "Input 4",
|
||||
"displayNameEvent": "Input 4 changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"ioType": "digitalInput"
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "62c5562a-8bdf-49b4-8e1d-f27442b2b360",
|
||||
"name": "alert",
|
||||
"displayName": "Identify"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"title": "ZigBee Develco",
|
||||
"tagline": "Connect and control native ZigBee devices from Develco.",
|
||||
"icon": "zigbee.svg",
|
||||
"stability": "consumer",
|
||||
"offline": true,
|
||||
"technologies": [
|
||||
"zigbee"
|
||||
],
|
||||
"categories": [
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="96"
|
||||
height="96"
|
||||
id="svg4874"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
viewBox="0 0 96 96.000001"
|
||||
sodipodi:docname="zigbee_.svg">
|
||||
<defs
|
||||
id="defs4876" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8.7812489"
|
||||
inkscape:cx="10.528112"
|
||||
inkscape:cy="41.064759"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g4780"
|
||||
showgrid="true"
|
||||
showborder="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="2880"
|
||||
inkscape:window-height="1663"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="76"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5451"
|
||||
empspacing="8" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="8,-8.0000001"
|
||||
id="guide4063"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="4,-8.0000001"
|
||||
id="guide4065"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,88.000001"
|
||||
id="guide4067"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,92.000001"
|
||||
id="guide4069"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="104,4"
|
||||
id="guide4071"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,8.0000001"
|
||||
id="guide4073"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="92,-8.0000001"
|
||||
id="guide4075"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="88,-8.0000001"
|
||||
id="guide4077"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,84.000001"
|
||||
id="guide4074"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="12,-8.0000001"
|
||||
id="guide4076"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,12"
|
||||
id="guide4078"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="84,-9.0000001"
|
||||
id="guide4080"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="48,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4170"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="-8,48"
|
||||
orientation="0,1"
|
||||
id="guide4172"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4879">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(67.857146,-78.50504)">
|
||||
<g
|
||||
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||
id="g4845"
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="next01.png"
|
||||
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||
id="g4778"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||
id="g4780"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 418.41067,377.27822 c -2.47698,-9.19 -6.3325,-9.76 -10.1,-11.048 -5.65022,5.45 -41.7365,40.432 -41.7365,40.432 0,0 -2.35494,-21.802 2.0068,-46.974 -0.058,0.002 -0.096,0.004 -0.152,0.006 6.22646,-3.99 13.61138,-6.332 21.55452,-6.332 22.10074,0 40.01582,17.908 40.01582,40 0,11.268 -4.67784,21.43 -12.17882,28.7 1.92676,-11.678 3.36934,-34.48 0.59024,-44.784 z"
|
||||
id="path2"
|
||||
style="fill:#808080;fill-opacity:1;stroke-width:2.00039554" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 363.40291,411.91422 c 0.69428,3.964 4.2637,8.424 10.6082,9.414 2.47898,-2.874 41.03022,-39.988 41.03022,-39.988 0.84834,14.016 0.93038,29.138 -1.72868,44.474 -6.5726,4.732 -14.61378,7.548 -23.32922,7.548 -22.10074,0 -40.01582,-17.908 -40.01582,-40 0,-12.346 5.6022,-23.378 14.39568,-30.716 -1.05042,7.744 -3.92954,32.202 -0.96038,49.268 z"
|
||||
id="path4"
|
||||
style="fill:#808080;fill-opacity:1;stroke-width:2.00039554" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
|
@ -0,0 +1,12 @@
|
|||
include(../plugins.pri)
|
||||
|
||||
PKGCONFIG += nymea-zigbee
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginzigbeedevelco.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginzigbeedevelco.h
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue