Add tradfri range extender and fix motion sensor. Start implementing hue outdoor sensor
This commit is contained in:
parent
10cc4ed8db
commit
cb2a6f9f4c
@ -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": [
|
||||||
|
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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": [
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user