ZigbeePhilipsHue: Add support for the manufacturer specific Remote commands
This commit is contained in:
parent
e7eae3711f
commit
469fa10a19
@ -165,46 +165,36 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info)
|
|||||||
// Set the version
|
// Set the version
|
||||||
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointZll->softwareBuildId());
|
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointZll->softwareBuildId());
|
||||||
|
|
||||||
// Receive on/off commands
|
ZigbeeClusterManufacturerSpecificPhilips *philipsCluster = endpointHa->inputCluster<ZigbeeClusterManufacturerSpecificPhilips>(ZigbeeClusterLibrary::ClusterIdManufacturerSpecificPhilips);
|
||||||
ZigbeeClusterOnOff *onOffCluster = endpointZll->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
if (!philipsCluster) {
|
||||||
if (!onOffCluster) {
|
qCWarning(dcZigbeePhilipsHue()) << "Could not find Manufacturer Specific (Philips) cluster on" << thing << endpointHa;
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Could not find on/off client cluster on" << thing << endpointZll;
|
|
||||||
} else {
|
} else {
|
||||||
connect(onOffCluster, &ZigbeeClusterOnOff::commandSent, thing, [=](ZigbeeClusterOnOff::Command command){
|
connect(philipsCluster, &ZigbeeClusterManufacturerSpecificPhilips::buttonPressed, thing, [=](quint8 button, ZigbeeClusterManufacturerSpecificPhilips::Operation operation) {
|
||||||
if (command == ZigbeeClusterOnOff::CommandOn) {
|
qCDebug(dcZigbeePhilipsHue()) << "Button" << button << operation;
|
||||||
qCDebug(dcZigbeePhilipsHue()) << thing << "pressed ON";
|
QHash<quint8, QString> buttonMap = {
|
||||||
emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "ON")));
|
{1, "ON"},
|
||||||
} else {
|
{2, "DIM UP"},
|
||||||
qCWarning(dcZigbeePhilipsHue()) << thing << "unhandled command received" << command;
|
{3, "DIM DOWN"},
|
||||||
}
|
{4, "OFF"}
|
||||||
});
|
};
|
||||||
|
switch (operation) {
|
||||||
connect(onOffCluster, &ZigbeeClusterOnOff::commandOffWithEffectSent, thing, [=](ZigbeeClusterOnOff::Effect effect, quint8 effectVariant){
|
case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonPress:
|
||||||
qCDebug(dcZigbeePhilipsHue()) << thing << "OFF button pressed" << effect << effectVariant;
|
// This doesn't appear on very quick press/release. But we always get the short release, so let's use that instead
|
||||||
emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "OFF")));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive level control commands
|
|
||||||
ZigbeeClusterLevelControl *levelCluster = endpointZll->outputCluster<ZigbeeClusterLevelControl>(ZigbeeClusterLibrary::ClusterIdLevelControl);
|
|
||||||
if (!levelCluster) {
|
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Could not find level client cluster on" << thing << endpointZll;
|
|
||||||
} else {
|
|
||||||
connect(levelCluster, &ZigbeeClusterLevelControl::commandStepSent, thing, [=](ZigbeeClusterLevelControl::FadeMode fadeMode, quint8 stepSize, quint16 transitionTime){
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << thing << "level button pressed" << fadeMode << stepSize << transitionTime;
|
|
||||||
switch (fadeMode) {
|
|
||||||
case ZigbeeClusterLevelControl::FadeModeUp:
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << thing << "DIM UP pressed";
|
|
||||||
emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "DIM UP")));
|
|
||||||
break;
|
break;
|
||||||
case ZigbeeClusterLevelControl::FadeModeDown:
|
case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonShortRelease:
|
||||||
qCDebug(dcZigbeePhilipsHue()) << thing << "DIM DOWN pressed";
|
thing->emitEvent(dimmerSwitchPressedEventTypeId, ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, buttonMap.value(button)));
|
||||||
emit emitEvent(Event(dimmerSwitchPressedEventTypeId, thing->id(), ParamList() << Param(dimmerSwitchPressedEventButtonNameParamTypeId, "DIM DOWN")));
|
break;
|
||||||
|
case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonHold:
|
||||||
|
thing->emitEvent(dimmerSwitchLongPressedEventTypeId, ParamList() << Param(dimmerSwitchLongPressedEventButtonNameParamTypeId, buttonMap.value(button)));
|
||||||
|
break;
|
||||||
|
case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonLongRelease:
|
||||||
|
// Release after a longpress. But for longpresses we always seem to get the Hold before, so we'll use that.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get battery level changes
|
// Get battery level changes
|
||||||
ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
|
ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
|
||||||
if (!powerCluster) {
|
if (!powerCluster) {
|
||||||
@ -296,7 +286,7 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info)
|
|||||||
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointHa->softwareBuildId());
|
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointHa->softwareBuildId());
|
||||||
|
|
||||||
// Get battery level changes
|
// Get battery level changes
|
||||||
ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
|
ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->outputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
|
||||||
if (!powerCluster) {
|
if (!powerCluster) {
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Could not find power configuration cluster on" << thing << endpointHa;
|
qCWarning(dcZigbeePhilipsHue()) << "Could not find power configuration cluster on" << thing << endpointHa;
|
||||||
} else {
|
} else {
|
||||||
@ -411,7 +401,6 @@ void IntegrationPluginZigbeePhilipsHue::createThing(const ThingClassId &thingCla
|
|||||||
|
|
||||||
void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node)
|
void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node)
|
||||||
{
|
{
|
||||||
ZigbeeNodeEndpoint *endpointZll = node->getEndpoint(0x01);
|
|
||||||
ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02);
|
ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02);
|
||||||
|
|
||||||
// Get the current configured bindings for this node
|
// Get the current configured bindings for this node
|
||||||
@ -429,76 +418,68 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes" << node;
|
qCDebug(dcZigbeePhilipsHue()) << "Reading power configuration cluster attributes" << node;
|
||||||
ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining});
|
ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining});
|
||||||
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
|
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
|
||||||
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error();
|
qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error();
|
||||||
} else {
|
} else {
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully";
|
qCDebug(dcZigbeePhilipsHue()) << "Reading power configuration cluster attributes finished successfully";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Bind the cluster to the coordinator
|
||||||
|
qCDebug(dcZigbeePhilipsHue()) << "Binding power configuration cluster to coordinator IEEE address";
|
||||||
|
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration,
|
||||||
|
hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
|
||||||
|
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||||
|
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||||
|
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster to coordinator" << zdoReply->error();
|
||||||
|
} else {
|
||||||
|
qCDebug(dcZigbeePhilipsHue()) << "Binding power configuration cluster to coordinator finished successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure attribute rporting for battery remaining (0.5 % changes = 1)
|
||||||
|
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
|
||||||
|
reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining;
|
||||||
|
reportingConfig.dataType = Zigbee::Uint8;
|
||||||
|
reportingConfig.minReportingInterval = 300;
|
||||||
|
reportingConfig.maxReportingInterval = 2700;
|
||||||
|
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
|
||||||
|
|
||||||
// Bind the cluster to the coordinator
|
qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for power configuration cluster to coordinator";
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator IEEE address";
|
ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig});
|
||||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration,
|
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
|
||||||
hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
|
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error();
|
||||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster to coordinator" << zdoReply->error();
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator finished successfully";
|
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Configure attribute rporting for battery remaining (0.5 % changes = 1)
|
|
||||||
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
|
|
||||||
reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining;
|
|
||||||
reportingConfig.dataType = Zigbee::Uint8;
|
|
||||||
reportingConfig.minReportingInterval = 300;
|
|
||||||
reportingConfig.maxReportingInterval = 2700;
|
|
||||||
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
|
|
||||||
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for power configuration cluster to coordinator";
|
|
||||||
ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig});
|
qCDebug(dcZigbeePhilipsHue()) << "Binding Manufacturer specific cluster to coordinator";
|
||||||
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
|
zdoReply = node->deviceObject()->requestBindGroupAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdManufacturerSpecificPhilips, 0x0000);
|
||||||
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error();
|
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||||
} else {
|
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind manufacturer specific cluster to coordinator" << zdoReply->error();
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
|
} else {
|
||||||
|
qCDebug(dcZigbeePhilipsHue()) << "Binding manufacturer specific cluster to coordinator finished successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcZigbeePhilipsHue()) << "Reading binding table from node" << node;
|
||||||
|
ZigbeeReply *reply = node->readBindingTableEntries();
|
||||||
|
connect(reply, &ZigbeeReply::finished, node, [=](){
|
||||||
|
if (reply->error() != ZigbeeReply::ErrorNoError) {
|
||||||
|
qCWarning(dcZigbeePhilipsHue()) << "Failed to read binding table from" << node;
|
||||||
|
} else {
|
||||||
|
foreach (const ZigbeeDeviceProfile::BindingTableListRecord &binding, node->bindingTableRecords()) {
|
||||||
|
qCDebug(dcZigbeePhilipsHue()) << node << binding;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator";
|
|
||||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindGroupAddress(endpointZll->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000);
|
|
||||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
|
||||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind on/off cluster to coordinator" << zdoReply->error();
|
|
||||||
} else {
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator finished successfully";
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Bind power level cluster to coordinator";
|
|
||||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindGroupAddress(endpointZll->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, 0x0000);
|
|
||||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
|
||||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind level cluster to coordinator" << zdoReply->error();
|
|
||||||
} else {
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Bind level cluster to coordinator finished successfully";
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << "Read binding table from node" << node;
|
|
||||||
ZigbeeReply *reply = node->readBindingTableEntries();
|
|
||||||
connect(reply, &ZigbeeReply::finished, node, [=](){
|
|
||||||
if (reply->error() != ZigbeeReply::ErrorNoError) {
|
|
||||||
qCWarning(dcZigbeePhilipsHue()) << "Failed to read binding table from" << node;
|
|
||||||
} else {
|
|
||||||
foreach (const ZigbeeDeviceProfile::BindingTableListRecord &binding, node->bindingTableRecords()) {
|
|
||||||
qCDebug(dcZigbeePhilipsHue()) << node << binding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
#include "integrations/integrationplugin.h"
|
#include "integrations/integrationplugin.h"
|
||||||
#include "hardware/zigbee/zigbeehandler.h"
|
#include "hardware/zigbee/zigbeehandler.h"
|
||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
class IntegrationPluginZigbeePhilipsHue: public IntegrationPlugin, public ZigbeeHandler
|
class IntegrationPluginZigbeePhilipsHue: public IntegrationPlugin, public ZigbeeHandler
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
"id": "b2711164-a848-4715-8ddf-33ca86f9f4cf",
|
"id": "b2711164-a848-4715-8ddf-33ca86f9f4cf",
|
||||||
"setupMethod": "JustAdd",
|
"setupMethod": "JustAdd",
|
||||||
"createMethods": [ "Auto" ],
|
"createMethods": [ "Auto" ],
|
||||||
"interfaces": [ "multibutton", "battery", "wirelessconnectable" ],
|
"interfaces": [ "longpressmultibutton", "battery", "wirelessconnectable" ],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "b221cad1-ef2e-4192-8168-11d0205a43da",
|
"id": "b221cad1-ef2e-4192-8168-11d0205a43da",
|
||||||
@ -88,7 +88,7 @@
|
|||||||
{
|
{
|
||||||
"id": "33bb5816-8479-4995-99e2-cb0443886003",
|
"id": "33bb5816-8479-4995-99e2-cb0443886003",
|
||||||
"name": "pressed",
|
"name": "pressed",
|
||||||
"displayName": "Button pressed",
|
"displayName": "Pressed",
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "c086a247-838f-49c0-b1e4-2ae1ed181b55",
|
"id": "c086a247-838f-49c0-b1e4-2ae1ed181b55",
|
||||||
@ -98,6 +98,20 @@
|
|||||||
"allowedValues": ["ON", "OFF", "DIM UP", "DIM DOWN"]
|
"allowedValues": ["ON", "OFF", "DIM UP", "DIM DOWN"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1a0be168-c9cb-44be-bca3-14c389f18e9f",
|
||||||
|
"name": "longPressed",
|
||||||
|
"displayName": "Long pressed",
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "046877e7-8e1c-489b-ac5f-8f0242c27b68",
|
||||||
|
"name": "buttonName",
|
||||||
|
"displayName": "Button name",
|
||||||
|
"type": "QString",
|
||||||
|
"allowedValues": ["ON", "OFF", "DIM UP", "DIM DOWN"]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user