Finish hue outdoor sensor presence detection with settings timout and refresh mechanism

This commit is contained in:
Simon Stürz 2020-11-28 17:04:14 +01:00
parent cb2a6f9f4c
commit ddfaa7a6b8
4 changed files with 159 additions and 82 deletions

View File

@ -124,6 +124,17 @@
"defaultValue": "" "defaultValue": ""
} }
], ],
"settingsTypes": [
{
"id": "4576f68f-7856-48f8-a3fd-2c9e7f968537",
"name": "timeout",
"displayName": "Time period",
"type": "uint",
"unit": "Seconds",
"defaultValue": 60,
"minValue": 10
}
],
"stateTypes": [ "stateTypes": [
{ {
"id": "0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d", "id": "0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d",
@ -179,7 +190,7 @@
"displayName": "Present", "displayName": "Present",
"displayNameEvent": "Present changed", "displayNameEvent": "Present changed",
"type": "bool", "type": "bool",
"defaultValue": true, "defaultValue": false,
"ioType": "digitalInput" "ioType": "digitalInput"
}, },
{ {

View File

@ -33,6 +33,8 @@
#include "plugininfo.h" #include "plugininfo.h"
#include "hardware/zigbee/zigbeehardwareresource.h" #include "hardware/zigbee/zigbeehardwareresource.h"
#include <math.h>
IntegrationPluginZigbeePhilipsHue::IntegrationPluginZigbeePhilipsHue() IntegrationPluginZigbeePhilipsHue::IntegrationPluginZigbeePhilipsHue()
{ {
m_ieeeAddressParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingIeeeAddressParamTypeId;
@ -235,34 +237,30 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info)
if (!occupancyCluster) { if (!occupancyCluster) {
qCWarning(dcZigbeePhilipsHue()) << "Occupancy cluster not found on" << thing; qCWarning(dcZigbeePhilipsHue()) << "Occupancy cluster not found on" << thing;
} else { } else {
if (occupancyCluster->hasAttribute(ZigbeeClusterOccupancySensing::AttributeOccupancy)) { if (!m_presenceTimer) {
thing->setStateValue(outdoorSensorIsPresentStateTypeId, occupancyCluster->occupied()); m_presenceTimer = hardwareManager()->pluginTimerManager()->registerTimer(1);
thing->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
} }
connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [thing](bool occupancy){ connect(m_presenceTimer, &PluginTimer::timeout, thing, [thing](){
qCDebug(dcZigbeePhilipsHue()) << "occupancy changed" << occupancy; if (thing->stateValue(outdoorSensorIsPresentStateTypeId).toBool()) {
// Only change the state if the it changed to true, it will be disabled by the timer int timeout = thing->setting(outdoorSensorSettingsTimeoutParamTypeId).toInt();
if (occupancy) { QDateTime lastSeenTime = QDateTime::fromMSecsSinceEpoch(thing->stateValue(outdoorSensorLastSeenTimeStateTypeId).toULongLong() * 1000);
thing->setStateValue(outdoorSensorIsPresentStateTypeId, occupancy); if (lastSeenTime.addSecs(timeout) < QDateTime::currentDateTime()) {
//m_presenceTimer->start(); qCDebug(dcZigbeePhilipsHue()) << thing << "Presence timeout";
thing->setStateValue(outdoorSensorIsPresentStateTypeId, false);
}
} }
thing->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
}); });
// if (!m_presenceTimer) { connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [=](bool occupancy){
// m_presenceTimer = hardwareManager()->pluginTimerManager()->registerTimer(1); qCDebug(dcZigbeePhilipsHue()) << thing << "occupancy cluster changed" << occupancy;
// } // Only change the state if the it changed to true, it will be disabled by the timer
if (occupancy) {
// connect(m_presenceTimer, &PluginTimer::timeout, thing, [thing](){ thing->setStateValue(outdoorSensorIsPresentStateTypeId, true);
// if (thing->stateValue(outdoorSensorIsPresentStateTypeId).toBool()) { thing->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
// int timeout = thing->setting(outdoorSensorSettingsTimeoutParamTypeId).toInt(); m_presenceTimer->start();
// 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); ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpointHa->inputCluster<ZigbeeClusterTemperatureMeasurement>(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement);
@ -280,6 +278,24 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info)
}); });
} }
ZigbeeClusterIlluminanceMeasurment *illuminanceCluster = endpointHa->inputCluster<ZigbeeClusterIlluminanceMeasurment>(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement);
if (!illuminanceCluster) {
qCWarning(dcZigbeePhilipsHue()) << "Could not find the illuminance measurement server cluster on" << thing << endpointHa;
} else {
// Only set the state if the cluster actually has the attribute
if (illuminanceCluster->hasAttribute(ZigbeeClusterIlluminanceMeasurment::AttributeMeasuredValue)) {
int convertedValue = pow(10, illuminanceCluster->illuminance() / 10000) - 1;
qCDebug(dcZigbeePhilipsHue()) << thing << "illuminance" << illuminanceCluster->illuminance() << "-->" << convertedValue << "lux";
thing->setStateValue(outdoorSensorLightIntensityStateTypeId, convertedValue);
}
connect(illuminanceCluster, &ZigbeeClusterIlluminanceMeasurment::illuminanceChanged, thing, [thing](quint16 illuminance){
int convertedValue = pow(10, illuminance / 10000) - 1;
qCDebug(dcZigbeePhilipsHue()) << thing << "illuminance changed" << illuminance << "-->" << convertedValue << "lux";
thing->setStateValue(outdoorSensorLightIntensityStateTypeId, convertedValue);
});
}
} }
@ -410,7 +426,6 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node)
void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node) void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(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
@ -426,6 +441,7 @@ void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node)
return; return;
} }
// Init power configuration cluster
qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes" << node; qCDebug(dcZigbeePhilipsHue()) << "Read 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, [=](){
@ -435,7 +451,6 @@ void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node)
qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully"; qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully";
} }
// Bind the cluster to the coordinator // Bind the cluster to the coordinator
qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator IEEE address"; qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator IEEE address";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration,
@ -465,36 +480,6 @@ void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node)
} }
// 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 // Init temperature measurment cluster
qCDebug(dcZigbeePhilipsHue()) << "Bind temperature cluster to coordinator IEEE address"; qCDebug(dcZigbeePhilipsHue()) << "Bind temperature cluster to coordinator IEEE address";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement, ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement,
@ -521,8 +506,6 @@ void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node)
qCDebug(dcZigbeePhilipsHue()) << "Read temperature cluster attributes finished successfully"; qCDebug(dcZigbeePhilipsHue()) << "Read temperature cluster attributes finished successfully";
} }
// Configure attribute reporting
// Configure attribute reporting for temperature // Configure attribute reporting for temperature
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
reportingConfig.attributeId = ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue; reportingConfig.attributeId = ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue;
@ -540,9 +523,92 @@ void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node)
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for temperature cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for temperature cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
} }
// Init illuminance measurment cluster
qCDebug(dcZigbeePhilipsHue()) << "Bind illuminance measurement cluster to coordinator IEEE address";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement,
hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to bind illuminance measurement cluster to coordinator" << zdoReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Bind illuminance measurement cluster to coordinator finished successfully";
}
// Read current illuminance
if (!endpointHa->hasInputCluster(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement)) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the illuminance measurement cluster because the cluster could not be found" << node << endpointHa;
return;
}
qCDebug(dcZigbeePhilipsHue()) << "Read illuminance measurement cluster attributes" << node;
ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement)->readAttributes({ZigbeeClusterIlluminanceMeasurment::AttributeMeasuredValue});
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to read illuminance measurement cluster attributes" << readAttributeReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Read illuminance measurement cluster attributes finished successfully";
}
// Configure attribute reporting
// Configure attribute reporting for temperature
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
reportingConfig.attributeId = ZigbeeClusterIlluminanceMeasurment::AttributeMeasuredValue;
reportingConfig.dataType = Zigbee::Uint16;
reportingConfig.minReportingInterval = 300;
reportingConfig.maxReportingInterval = 600;
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint16>(1)).data();
qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for illuminance measurement cluster to coordinator";
ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement)->configureReporting({reportingConfig});
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to configure illuminance measurement cluster attribute reporting" << reportingReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for illuminance measurement cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
}
// Init occupancy sensing cluster
qCDebug(dcZigbeePhilipsHue()) << "Bind occupancy sensing 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 sensing cluster to coordinator" << zdoReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Bind occupancy sensing cluster to coordinator finished successfully";
}
qCDebug(dcZigbeePhilipsHue()) << "Read occupancy sensing cluster attributes" << node;
ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdOccupancySensing)->readAttributes({ZigbeeClusterOccupancySensing::AttributeOccupancy, ZigbeeClusterOccupancySensing::AttributeOccupancySensorType});
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeePhilipsHue()) << "Failed to read occupancy sensing cluster attributes" << readAttributeReply->error();
} else {
qCDebug(dcZigbeePhilipsHue()) << "Read occupancy sensing cluster attributes finished successfully";
}
// Configure attribute reporting for temperature
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
reportingConfig.attributeId = ZigbeeClusterOccupancySensing::AttributeOccupancy;
reportingConfig.dataType = Zigbee::BitMap8;
reportingConfig.minReportingInterval = 0;
reportingConfig.maxReportingInterval = 300;
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);
}
});
});
});
});
}); });
}); });
}); });

View File

@ -332,7 +332,7 @@
"displayName": "Present", "displayName": "Present",
"displayNameEvent": "Present changed", "displayNameEvent": "Present changed",
"type": "bool", "type": "bool",
"defaultValue": true, "defaultValue": false,
"ioType": "digitalInput" "ioType": "digitalInput"
}, },
{ {

View File

@ -591,7 +591,7 @@ void IntegrationPluginZigbeeTradfri::initMotionSensor(ZigbeeNode *node, ZigbeeNo
qCDebug(dcZigbeeTradfri()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); qCDebug(dcZigbeeTradfri()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator"; qCDebug(dcZigbeeTradfri()) << "Bind on/off cluster to coordinator";
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {