Add tradfri range extender and fix motion sensor. Start implementing hue outdoor sensor

This commit is contained in:
Simon Stürz 2020-11-28 14:27:31 +01:00
parent 10cc4ed8db
commit cb2a6f9f4c
6 changed files with 528 additions and 136 deletions

View File

@ -100,6 +100,122 @@
] ]
} }
] ]
},
{
"name": "outdoorSensor",
"displayName": "Hue outdoor sensor",
"id": "031c45d1-e782-4f91-9f05-259d6b81c7ef",
"setupMethod": "JustAdd",
"createMethods": [ "Auto" ],
"interfaces": [ "presencesensor", "lightsensor", "temperaturesensor", "batterylevel", "wirelessconnectable" ],
"paramTypes": [
{
"id": "a866df99-7e2a-40e1-b82e-529c03846d5e",
"name": "ieeeAddress",
"displayName": "IEEE adress",
"type": "QString",
"defaultValue": "00:00:00:00:00:00:00:00"
},
{
"id": "99f4ff28-6d61-4e96-bfc4-c32aa05bb256",
"name": "networkUuid",
"displayName": "Zigbee network UUID",
"type": "QString",
"defaultValue": ""
}
],
"stateTypes": [
{
"id": "0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"cached": false,
"defaultValue": false
},
{
"id": "d4f85c34-896a-4bab-af71-8b80d9889815",
"name": "signalStrength",
"displayName": "Signal strength",
"displayNameEvent": "Signal strength changed",
"defaultValue": 0,
"maxValue": 100,
"minValue": 0,
"type": "uint",
"unit": "Percentage"
},
{
"id": "18cb67e1-220f-41d7-9145-1816fc5d38d0",
"name": "version",
"displayName": "Version",
"displayNameEvent": "Version changed",
"type": "QString",
"cached": true,
"defaultValue": ""
},
{
"id": "00a4450b-d2fe-4e2b-92c8-1ab3a98d1628",
"name": "batteryLevel",
"displayName": "Battery",
"displayNameEvent": "Battery changed",
"type": "int",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100
},
{
"id": "9341f65a-b0aa-4648-82eb-e8400779f817",
"name": "batteryCritical",
"displayName": "Battery critical",
"displayNameEvent": "Battery critical changed",
"type": "bool",
"defaultValue": false
},
{
"id": "66e3b840-4f4c-4f4a-a71a-69fb751f2a3b",
"name": "isPresent",
"displayName": "Present",
"displayNameEvent": "Present changed",
"type": "bool",
"defaultValue": true,
"ioType": "digitalInput"
},
{
"id": "128777a9-75e7-4cc6-b196-691d2ffddbc9",
"name": "lastSeenTime",
"displayName": "Last seen time",
"displayNameEvent": "Last seen time changed",
"type": "int",
"unit": "UnixTime",
"defaultValue": 0
},
{
"id": "8077e335-1d18-4e3f-9b5e-6f71af4a33b1",
"name": "lightIntensity",
"displayName": "Light intensity",
"displayNameEvent": "Light intensity changed",
"type": "double",
"unit": "Lux",
"defaultValue": 0
},
{
"id": "978f069c-57c0-4e73-a81b-c593bc2e7624",
"name": "temperature",
"displayName": "Temperature",
"displayNameEvent": "Temperature changed",
"type": "double",
"unit": "DegreeCelsius",
"defaultValue": 0.0
}
],
"actionTypes": [
],
"eventTypes": [
]
} }
] ]
} }

View File

@ -36,15 +36,19 @@
IntegrationPluginZigbeePhilipsHue::IntegrationPluginZigbeePhilipsHue() IntegrationPluginZigbeePhilipsHue::IntegrationPluginZigbeePhilipsHue()
{ {
m_ieeeAddressParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingIeeeAddressParamTypeId;
m_ieeeAddressParamTypeIds[outdoorSensorThingClassId] = outdoorSensorThingIeeeAddressParamTypeId;
m_networkUuidParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingNetworkUuidParamTypeId;
m_networkUuidParamTypeIds[outdoorSensorThingClassId] = outdoorSensorThingNetworkUuidParamTypeId;
m_connectedStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchConnectedStateTypeId; m_connectedStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchConnectedStateTypeId;
m_connectedStateTypeIds[outdoorSensorThingClassId] = outdoorSensorConnectedStateTypeId;
m_signalStrengthStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchSignalStrengthStateTypeId;
m_signalStrengthStateTypeIds[outdoorSensorThingClassId] = outdoorSensorSignalStrengthStateTypeId;
m_versionStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchVersionStateTypeId; m_versionStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchVersionStateTypeId;
m_versionStateTypeIds[outdoorSensorThingClassId] = outdoorSensorVersionStateTypeId;
} }
QString IntegrationPluginZigbeePhilipsHue::name() const QString IntegrationPluginZigbeePhilipsHue::name() const
@ -66,8 +70,8 @@ bool IntegrationPluginZigbeePhilipsHue::handleNode(ZigbeeNode *node, const QUuid
// Dimmer switch // Dimmer switch
if (endpointOne->profile() == Zigbee::ZigbeeProfileLightLink && if (endpointOne->profile() == Zigbee::ZigbeeProfileLightLink &&
endpointOne->deviceId() == Zigbee::LightLinkDeviceNonColourSceneController endpointOne->deviceId() == Zigbee::LightLinkDeviceNonColourSceneController &&
&& endpoinTwo->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoinTwo->profile() == Zigbee::ZigbeeProfileHomeAutomation &&
endpoinTwo->deviceId() == Zigbee::HomeAutomationDeviceSimpleSensor) { endpoinTwo->deviceId() == Zigbee::HomeAutomationDeviceSimpleSensor) {
qCDebug(dcZigbeePhilipsHue()) << "Handeling Hue dimmer switch" << node << endpointOne << endpoinTwo; qCDebug(dcZigbeePhilipsHue()) << "Handeling Hue dimmer switch" << node << endpointOne << endpoinTwo;
@ -75,6 +79,18 @@ bool IntegrationPluginZigbeePhilipsHue::handleNode(ZigbeeNode *node, const QUuid
initDimmerSwitch(node); initDimmerSwitch(node);
return true; return true;
} }
// Outdoor sensor
if (endpointOne->profile() == Zigbee::ZigbeeProfileLightLink &&
endpointOne->deviceId() == Zigbee::LightLinkDeviceOnOffSensor &&
endpoinTwo->profile() == Zigbee::ZigbeeProfileHomeAutomation &&
endpoinTwo->deviceId() == Zigbee::HomeAutomationDeviceOccupacySensor) {
qCDebug(dcZigbeePhilipsHue()) << "Handeling Hue outdoor sensor" << node << endpointOne << endpoinTwo;
createThing(outdoorSensorThingClassId, networkUuid, node);
initOutdoorSensor(node);
return true;
}
} }
return handled; return handled;
@ -124,7 +140,6 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info)
thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength); thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength);
}); });
// Thing specific setup // Thing specific setup
if (thing->thingClassId() == dimmerSwitchThingClassId) { if (thing->thingClassId() == dimmerSwitchThingClassId) {
ZigbeeNodeEndpoint *endpointZll = node->getEndpoint(0x01); ZigbeeNodeEndpoint *endpointZll = node->getEndpoint(0x01);
@ -133,7 +148,6 @@ 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 // Receive on/off commands
ZigbeeClusterOnOff *onOffCluster = endpointZll->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff); ZigbeeClusterOnOff *onOffCluster = endpointZll->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
if (!onOffCluster) { if (!onOffCluster) {
@ -191,6 +205,81 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info)
thing->setStateValue(dimmerSwitchBatteryCriticalStateTypeId, (percentage < 10.0)); thing->setStateValue(dimmerSwitchBatteryCriticalStateTypeId, (percentage < 10.0));
}); });
} }
}
if (thing->thingClassId() == outdoorSensorThingClassId) {
ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02);
// Set the version
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointHa->softwareBuildId());
// Get battery level changes
ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
if (!powerCluster) {
qCWarning(dcZigbeePhilipsHue()) << "Could not find power configuration cluster on" << thing << endpointHa;
} else {
// Only set the initial state if the attribute already exists
if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) {
thing->setStateValue(outdoorSensorBatteryLevelStateTypeId, powerCluster->batteryPercentage());
thing->setStateValue(outdoorSensorBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0));
}
connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){
qCDebug(dcZigbeePhilipsHue()) << "Battery percentage changed" << percentage << "%" << thing;
thing->setStateValue(outdoorSensorBatteryLevelStateTypeId, percentage);
thing->setStateValue(outdoorSensorBatteryCriticalStateTypeId, (percentage < 10.0));
});
}
ZigbeeClusterOccupancySensing *occupancyCluster = endpointHa->inputCluster<ZigbeeClusterOccupancySensing>(ZigbeeClusterLibrary::ClusterIdOccupancySensing);
if (!occupancyCluster) {
qCWarning(dcZigbeePhilipsHue()) << "Occupancy cluster not found on" << thing;
} else {
if (occupancyCluster->hasAttribute(ZigbeeClusterOccupancySensing::AttributeOccupancy)) {
thing->setStateValue(outdoorSensorIsPresentStateTypeId, occupancyCluster->occupied());
thing->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
}
connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [thing](bool occupancy){
qCDebug(dcZigbeePhilipsHue()) << "occupancy changed" << occupancy;
// Only change the state if the it changed to true, it will be disabled by the timer
if (occupancy) {
thing->setStateValue(outdoorSensorIsPresentStateTypeId, occupancy);
//m_presenceTimer->start();
}
thing->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
});
// if (!m_presenceTimer) {
// m_presenceTimer = hardwareManager()->pluginTimerManager()->registerTimer(1);
// }
// connect(m_presenceTimer, &PluginTimer::timeout, thing, [thing](){
// if (thing->stateValue(outdoorSensorIsPresentStateTypeId).toBool()) {
// int timeout = thing->setting(outdoorSensorSettingsTimeoutParamTypeId).toInt();
// QDateTime lastSeenTime = QDateTime::fromMSecsSinceEpoch(thing->stateValue(lumiMotionSensorLastSeenTimeStateTypeId).toULongLong() * 1000);
// if (lastSeenTime.addSecs(timeout) < QDateTime::currentDateTime()) {
// thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, false);
// }
// }
// });
}
ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpointHa->inputCluster<ZigbeeClusterTemperatureMeasurement>(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement);
if (!temperatureCluster) {
qCWarning(dcZigbeePhilipsHue()) << "Could not find the temperature measurement server cluster on" << thing << endpointHa;
} else {
// Only set the state if the cluster actually has the attribute
if (temperatureCluster->hasAttribute(ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue)) {
thing->setStateValue(outdoorSensorTemperatureStateTypeId, temperatureCluster->temperature());
}
connect(temperatureCluster, &ZigbeeClusterTemperatureMeasurement::temperatureChanged, thing, [thing](double temperature){
qCDebug(dcZigbeePhilipsHue()) << thing << "temperature changed" << temperature << "°C";
thing->setStateValue(outdoorSensorTemperatureStateTypeId, temperature);
});
}
} }
@ -319,3 +408,149 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node)
}); });
} }
void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node)
{
//ZigbeeNodeEndpoint *endpointZll = node->getEndpoint(0x01);
ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02);
// Get the current configured bindings for this node
ZigbeeReply *reply = node->removeAllBindings();
connect(reply, &ZigbeeReply::finished, node, [=](){
if (reply->error() != ZigbeeReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to remove all bindings for initialization of" << node;
}
// Read battery, bind and configure attribute reporting for battery
if (!endpointHa->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpointHa;
return;
}
qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes" << node;
ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining});
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully";
}
// Bind the cluster to the coordinator
qCDebug(dcZigbeePhilipsHue()) << "Bind 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()) << "Bind 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();
qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for power configuration cluster to coordinator";
ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig});
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
}
// Init occupancy sensing cluster
qCDebug(dcZigbeePhilipsHue()) << "Bind occupancy cluster to coordinator IEEE address";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdOccupancySensing,
hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind occupancy cluster to coordinator" << zdoReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Bind occupency cluster to coordinator finished successfully";
}
// Configure attribute reporting for temperature
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
reportingConfig.attributeId = ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue;
reportingConfig.dataType = Zigbee::BitMap8;
reportingConfig.minReportingInterval = 1;
reportingConfig.maxReportingInterval = 10;
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for occupancy cluster to coordinator";
ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdOccupancySensing)->configureReporting({reportingConfig});
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to configure occupancy cluster attribute reporting" << reportingReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for occupancy cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
}
// Init temperature measurment cluster
qCDebug(dcZigbeePhilipsHue()) << "Bind temperature cluster to coordinator IEEE address";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement,
hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind temperature cluster to coordinator" << zdoReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Bind temperature cluster to coordinator finished successfully";
}
// Read current temperature
if (!endpointHa->hasInputCluster(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement)) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the temperature cluster because the cluster could not be found" << node << endpointHa;
return;
}
qCDebug(dcZigbeePhilipsHue()) << "Read temperature cluster attributes" << node;
ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement)->readAttributes({ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue});
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to read temperature cluster attributes" << readAttributeReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Read temperature cluster attributes finished successfully";
}
// Configure attribute reporting
// Configure attribute reporting for temperature
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
reportingConfig.attributeId = ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue;
reportingConfig.dataType = Zigbee::Int16;
reportingConfig.minReportingInterval = 300;
reportingConfig.maxReportingInterval = 600;
reportingConfig.reportableChange = ZigbeeDataType(static_cast<qint16>(10)).data();
qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for temperature cluster to coordinator";
ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement)->configureReporting({reportingConfig});
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to configure temperature cluster attribute reporting" << reportingReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for temperature cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
}
});
});
});
});
});
});
});
});
});
}

View File

@ -70,6 +70,7 @@ private:
void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node); void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node);
void initDimmerSwitch(ZigbeeNode *node); void initDimmerSwitch(ZigbeeNode *node);
void initOutdoorSensor(ZigbeeNode *node);
}; };

View File

@ -350,6 +350,74 @@
], ],
"eventTypes": [ "eventTypes": [
]
},
{
"name": "signalRepeater",
"displayName": "TRÅDFRI signal repeater",
"id": "ac51f426-195e-472a-837f-4ba7e4666e6e",
"setupMethod": "JustAdd",
"createMethods": [ "Auto" ],
"interfaces": [ "wirelessconnectable" ],
"paramTypes": [
{
"id": "fcaf0646-ef18-4e16-afde-39823437b7f4",
"name": "ieeeAddress",
"displayName": "IEEE adress",
"type": "QString",
"defaultValue": "00:00:00:00:00:00:00:00"
},
{
"id": "5ce9a369-545b-4848-a6d7-6d3bc40779a2",
"name": "networkUuid",
"displayName": "Zigbee network UUID",
"type": "QString",
"defaultValue": ""
},
{
"id": "3ff01f62-83dc-4856-a7f0-5605091845cc",
"name": "endpointId",
"displayName": "Endpoint ID",
"type": "uint",
"defaultValue": 1
}
],
"stateTypes": [
{
"id": "7415ea93-9b72-4740-b3b1-a2ebb73d1db5",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"cached": false,
"defaultValue": false
},
{
"id": "05758f08-33a8-485b-8572-f87021e3af36",
"name": "signalStrength",
"displayName": "Signal strength",
"displayNameEvent": "Signal strength changed",
"defaultValue": 0,
"maxValue": 100,
"minValue": 0,
"type": "uint",
"unit": "Percentage"
},
{
"id": "a7ad66f1-7b4c-4458-8a13-e1bb9467bc17",
"name": "version",
"displayName": "Version",
"displayNameEvent": "Version changed",
"type": "QString",
"cached": true,
"defaultValue": ""
}
],
"actionTypes": [
],
"eventTypes": [
] ]
} }
] ]

View File

@ -39,26 +39,32 @@ IntegrationPluginZigbeeTradfri::IntegrationPluginZigbeeTradfri()
m_ieeeAddressParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingIeeeAddressParamTypeId;
m_ieeeAddressParamTypeIds[remoteThingClassId] = remoteThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[remoteThingClassId] = remoteThingIeeeAddressParamTypeId;
m_ieeeAddressParamTypeIds[motionSensorThingClassId] = motionSensorThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[motionSensorThingClassId] = motionSensorThingIeeeAddressParamTypeId;
m_ieeeAddressParamTypeIds[signalRepeaterThingClassId] = signalRepeaterThingIeeeAddressParamTypeId;
m_networkUuidParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingNetworkUuidParamTypeId;
m_networkUuidParamTypeIds[remoteThingClassId] = remoteThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[remoteThingClassId] = remoteThingNetworkUuidParamTypeId;
m_networkUuidParamTypeIds[motionSensorThingClassId] = motionSensorThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[motionSensorThingClassId] = motionSensorThingNetworkUuidParamTypeId;
m_networkUuidParamTypeIds[signalRepeaterThingClassId] = signalRepeaterThingNetworkUuidParamTypeId;
m_endpointIdParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingEndpointIdParamTypeId;
m_endpointIdParamTypeIds[remoteThingClassId] = remoteThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[remoteThingClassId] = remoteThingEndpointIdParamTypeId;
m_endpointIdParamTypeIds[motionSensorThingClassId] = motionSensorThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[motionSensorThingClassId] = motionSensorThingEndpointIdParamTypeId;
m_endpointIdParamTypeIds[signalRepeaterThingClassId] = signalRepeaterThingEndpointIdParamTypeId;
m_connectedStateTypeIds[onOffSwitchThingClassId] = onOffSwitchConnectedStateTypeId; m_connectedStateTypeIds[onOffSwitchThingClassId] = onOffSwitchConnectedStateTypeId;
m_connectedStateTypeIds[remoteThingClassId] = remoteConnectedStateTypeId; m_connectedStateTypeIds[remoteThingClassId] = remoteConnectedStateTypeId;
m_connectedStateTypeIds[motionSensorThingClassId] = motionSensorConnectedStateTypeId; m_connectedStateTypeIds[motionSensorThingClassId] = motionSensorConnectedStateTypeId;
m_connectedStateTypeIds[signalRepeaterThingClassId] = signalRepeaterConnectedStateTypeId;
m_signalStrengthStateTypeIds[onOffSwitchThingClassId] = onOffSwitchSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[onOffSwitchThingClassId] = onOffSwitchSignalStrengthStateTypeId;
m_signalStrengthStateTypeIds[remoteThingClassId] = remoteSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[remoteThingClassId] = remoteSignalStrengthStateTypeId;
m_signalStrengthStateTypeIds[motionSensorThingClassId] = motionSensorSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[motionSensorThingClassId] = motionSensorSignalStrengthStateTypeId;
m_signalStrengthStateTypeIds[signalRepeaterThingClassId] = signalRepeaterSignalStrengthStateTypeId;
m_versionStateTypeIds[onOffSwitchThingClassId] = onOffSwitchVersionStateTypeId; m_versionStateTypeIds[onOffSwitchThingClassId] = onOffSwitchVersionStateTypeId;
m_versionStateTypeIds[remoteThingClassId] = remoteVersionStateTypeId; m_versionStateTypeIds[remoteThingClassId] = remoteVersionStateTypeId;
m_versionStateTypeIds[motionSensorThingClassId] = motionSensorVersionStateTypeId; m_versionStateTypeIds[motionSensorThingClassId] = motionSensorVersionStateTypeId;
m_versionStateTypeIds[signalRepeaterThingClassId] = signalRepeaterVersionStateTypeId;
} }
QString IntegrationPluginZigbeeTradfri::name() const QString IntegrationPluginZigbeeTradfri::name() const
@ -84,29 +90,20 @@ bool IntegrationPluginZigbeeTradfri::handleNode(ZigbeeNode *node, const QUuid &n
if (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceOnOffSensor) { if (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceOnOffSensor) {
qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI motion sensor" << node << endpoint; qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI motion sensor" << node << endpoint;
createThing(motionSensorThingClassId, networkUuid, node, endpoint); createThing(motionSensorThingClassId, networkUuid, node, endpoint);
initMotionSensor(node, endpoint);
handled = true; handled = true;
} }
if (endpoint->profile() == Zigbee::ZigbeeProfileLightLink && endpoint->deviceId() == Zigbee::LightLinkDeviceNonColourSceneController) { if (endpoint->profile() == Zigbee::ZigbeeProfileLightLink && endpoint->deviceId() == Zigbee::LightLinkDeviceNonColourSceneController) {
qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI remote control" << node << endpoint; qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI remote control" << node << endpoint;
createThing(remoteThingClassId, networkUuid, node, endpoint); createThing(remoteThingClassId, networkUuid, node, endpoint);
// ZigbeeClusterBasic *basicCluster = endpoint->inputCluster<ZigbeeClusterBasic>(ZigbeeClusterLibrary::ClusterIdBasic);
// if (!basicCluster) {
// qCWarning(dcZigbeeTradfri()) << "Failed to find basic cluster for performing factory reset to defaults";
// initRemote(node, endpoint);
// } else {
// ZigbeeClusterReply *zclReply = basicCluster->resetToFactoryDefaults();
// connect(zclReply, &ZigbeeClusterReply::finished, node, [=](){
// if (zclReply->error() != ZigbeeClusterReply::ErrorNoError) {
// qCWarning(dcZigbeeTradfri()) << "Failed to perform factory reset on basic cluster on" << endpoint;
// }
// initRemote(node, endpoint);
// });
// }
initRemote(node, endpoint); initRemote(node, endpoint);
handled = true;
}
if (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceRangeExtender) {
qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI signal repeater" << node << endpoint;
createThing(signalRepeaterThingClassId, networkUuid, node, endpoint);
handled = true; handled = true;
} }
} }
@ -170,6 +167,24 @@ void IntegrationPluginZigbeeTradfri::setupThing(ThingSetupInfo *info)
// Thing specific setup // Thing specific setup
if (thing->thingClassId() == onOffSwitchThingClassId) { if (thing->thingClassId() == onOffSwitchThingClassId) {
// Get battery level changes
ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
if (!powerCluster) {
qCWarning(dcZigbeeTradfri()) << "Could not find power configuration cluster on" << thing << endpoint;
} else {
// Only set the initial state if the attribute already exists
if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) {
thing->setStateValue(onOffSwitchBatteryLevelStateTypeId, powerCluster->batteryPercentage());
thing->setStateValue(onOffSwitchBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0));
}
connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){
qCDebug(dcZigbeeTradfri()) << "Battery percentage changed" << percentage << "%" << thing;
thing->setStateValue(onOffSwitchBatteryLevelStateTypeId, percentage);
thing->setStateValue(onOffSwitchBatteryCriticalStateTypeId, (percentage < 10.0));
});
}
// Receive on/off commands // Receive on/off commands
ZigbeeClusterOnOff *onOffCluster = endpoint->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff); ZigbeeClusterOnOff *onOffCluster = endpoint->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
if (!onOffCluster) { if (!onOffCluster) {
@ -208,7 +223,9 @@ void IntegrationPluginZigbeeTradfri::setupThing(ThingSetupInfo *info)
} }
}); });
} }
}
if (thing->thingClassId() == motionSensorThingClassId) {
// Get battery level changes // Get battery level changes
ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration); ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
if (!powerCluster) { if (!powerCluster) {
@ -216,19 +233,17 @@ void IntegrationPluginZigbeeTradfri::setupThing(ThingSetupInfo *info)
} else { } else {
// Only set the initial state if the attribute already exists // Only set the initial state if the attribute already exists
if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) { if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) {
thing->setStateValue(onOffSwitchBatteryLevelStateTypeId, powerCluster->batteryPercentage()); thing->setStateValue(motionSensorBatteryLevelStateTypeId, powerCluster->batteryPercentage());
thing->setStateValue(onOffSwitchBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0)); thing->setStateValue(motionSensorBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0));
} }
connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){ connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){
qCDebug(dcZigbeeTradfri()) << "Battery percentage changed" << percentage << "%" << thing; qCDebug(dcZigbeeTradfri()) << "Battery percentage changed" << percentage << "%" << thing;
thing->setStateValue(onOffSwitchBatteryLevelStateTypeId, percentage); thing->setStateValue(motionSensorBatteryLevelStateTypeId, percentage);
thing->setStateValue(onOffSwitchBatteryCriticalStateTypeId, (percentage < 10.0)); thing->setStateValue(motionSensorBatteryCriticalStateTypeId, (percentage < 10.0));
}); });
} }
}
if (thing->thingClassId() == motionSensorThingClassId) {
// Create plugintimer if required // Create plugintimer if required
if (!m_presenceTimer) { if (!m_presenceTimer) {
m_presenceTimer = hardwareManager()->pluginTimerManager()->registerTimer(1); m_presenceTimer = hardwareManager()->pluginTimerManager()->registerTimer(1);
@ -255,41 +270,9 @@ void IntegrationPluginZigbeeTradfri::setupThing(ThingSetupInfo *info)
m_presenceTimer->start(); m_presenceTimer->start();
}); });
} }
// Get battery level changes
ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
if (!powerCluster) {
qCWarning(dcZigbeeTradfri()) << "Could not find power configuration cluster on" << thing << endpoint;
} else {
// Only set the initial state if the attribute already exists
if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) {
thing->setStateValue(motionSensorBatteryLevelStateTypeId, powerCluster->batteryPercentage());
thing->setStateValue(motionSensorBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0));
}
connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){
qCDebug(dcZigbeeTradfri()) << "Battery percentage changed" << percentage << "%" << thing;
thing->setStateValue(motionSensorBatteryLevelStateTypeId, percentage);
thing->setStateValue(motionSensorBatteryCriticalStateTypeId, (percentage < 10.0));
});
}
} }
if (thing->thingClassId() == remoteThingClassId) { if (thing->thingClassId() == remoteThingClassId) {
// Receive on/off commands
ZigbeeClusterOnOff *onOffCluster = endpoint->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
if (!onOffCluster) {
qCWarning(dcZigbeeTradfri()) << "Could not find on/off client cluster on" << thing << endpoint;
} else {
connect(onOffCluster, &ZigbeeClusterOnOff::commandSent, thing, [=](ZigbeeClusterOnOff::Command command){
qCDebug(dcZigbeeTradfri()) << thing << "button pressed" << command;
if (command == ZigbeeClusterOnOff::CommandToggle) {
qCDebug(dcZigbeeTradfri()) << thing << "pressed power";
emit emitEvent(Event(remotePressedEventTypeId, thing->id(), ParamList() << Param(remotePressedEventButtonNameParamTypeId, "Power")));
}
});
}
// Get battery level changes // Get battery level changes
ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration); ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
if (!powerCluster) { if (!powerCluster) {
@ -307,6 +290,20 @@ void IntegrationPluginZigbeeTradfri::setupThing(ThingSetupInfo *info)
thing->setStateValue(remoteBatteryCriticalStateTypeId, (percentage < 10.0)); thing->setStateValue(remoteBatteryCriticalStateTypeId, (percentage < 10.0));
}); });
} }
// Receive on/off commands
ZigbeeClusterOnOff *onOffCluster = endpoint->outputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
if (!onOffCluster) {
qCWarning(dcZigbeeTradfri()) << "Could not find on/off client cluster on" << thing << endpoint;
} else {
connect(onOffCluster, &ZigbeeClusterOnOff::commandSent, thing, [=](ZigbeeClusterOnOff::Command command){
qCDebug(dcZigbeeTradfri()) << thing << "button pressed" << command;
if (command == ZigbeeClusterOnOff::CommandToggle) {
qCDebug(dcZigbeeTradfri()) << thing << "pressed power";
emit emitEvent(Event(remotePressedEventTypeId, thing->id(), ParamList() << Param(remotePressedEventButtonNameParamTypeId, "Power")));
}
});
}
} }
info->finish(Thing::ThingErrorNoError); info->finish(Thing::ThingErrorNoError);
@ -538,94 +535,74 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp
}); });
} }
void IntegrationPluginZigbeeTradfri::readBindings(ZigbeeNode *node) void IntegrationPluginZigbeeTradfri::initMotionSensor(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
{ {
qCDebug(dcZigbeeTradfri()) << "Read binding table from node" << node; // Get the current configured bindings for this node
ZigbeeReply *reply = node->readBindingTableEntries(); ZigbeeReply *reply = node->removeAllBindings();
connect(reply, &ZigbeeReply::finished, node, [=](){ connect(reply, &ZigbeeReply::finished, node, [=](){
if (reply->error() != ZigbeeReply::ErrorNoError) { if (reply->error() != ZigbeeReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to read binding table from" << node; qCWarning(dcZigbeeTradfri()) << "Failed to remove all bindings for initialization of" << node;
} else { }
foreach (const ZigbeeDeviceProfile::BindingTableListRecord &binding, node->bindingTableRecords()) {
qCDebug(dcZigbeeTradfri()) << node << binding;
}
}
});
}
void IntegrationPluginZigbeeTradfri::initPowerConfigurationCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) // Read battery, bind and configure attribute reporting for battery
{
if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) {
qCWarning(dcZigbeeTradfri()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpoint;
return;
}
qCDebug(dcZigbeeTradfri()) << "Read power configuration cluster attributes" << node; if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) {
ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); qCWarning(dcZigbeeTradfri()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpoint;
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to read power cluster attributes" << readAttributeReply->error();
//emit nodeInitialized(node);
return; return;
} }
qCDebug(dcZigbeeTradfri()) << "Read power configuration cluster attributes finished successfully"; qCDebug(dcZigbeeTradfri()) << "Read power configuration cluster attributes" << node;
// Bind the cluster to the coordinator ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining});
qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator IEEE address"; connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); qCWarning(dcZigbeeTradfri()) << "Failed to read power cluster attributes" << readAttributeReply->error();
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ //emit nodeInitialized(node);
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to bind power cluster to coordinator" << zdoReply->error();
return; return;
} }
qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator finished successfully";
// Configure attribute rporting for battery remaining (0.5 % changes = 1) qCDebug(dcZigbeeTradfri()) << "Read power configuration cluster attributes finished successfully";
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(dcZigbeeTradfri()) << "Configure attribute reporting for power configuration cluster to coordinator"; // Bind the cluster to the coordinator
ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator IEEE address";
connect(reportingReply, &ZigbeeClusterReply::finished, this, [reportingReply](){ ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration,
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
qCWarning(dcZigbeeTradfri()) << "Failed to configure power cluster attribute reporting" << reportingReply->error(); connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to bind power cluster to coordinator" << zdoReply->error();
return; return;
} }
qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator finished successfully";
qCDebug(dcZigbeeTradfri()) << "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(dcZigbeeTradfri()) << "Configure attribute reporting for power configuration cluster to coordinator";
ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig});
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to configure power cluster attribute reporting" << reportingReply->error();
return;
}
qCDebug(dcZigbeeTradfri()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to bind on/off cluster to coordinator" << zdoReply->error();
return;
}
qCDebug(dcZigbeeTradfri()) << "Bind on/off cluster to coordinator finished successfully";
});
});
}); });
}); });
}); });
} }
void IntegrationPluginZigbeeTradfri::initOnOffCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
{
qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to bind on/off cluster to coordinator" << zdoReply->error();
return;
}
qCDebug(dcZigbeeTradfri()) << "Bind on/off cluster to coordinator finished successfully";
});
}
void IntegrationPluginZigbeeTradfri::initLevelControlCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
{
qCDebug(dcZigbeeTradfri()) << "Bind power level cluster to coordinator";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, 0x0000);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeeTradfri()) << "Failed to bind level cluster to coordinator" << zdoReply->error();
return;
}
qCDebug(dcZigbeeTradfri()) << "Bind level cluster to coordinator finished successfully";
});
}

View File

@ -73,12 +73,7 @@ private:
void initOnOffSwitch(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); void initOnOffSwitch(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
void initRemote(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); void initRemote(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
void initMotionSensor(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
void readBindings(ZigbeeNode *node);
void initPowerConfigurationCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
void initOnOffCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
void initLevelControlCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
}; };