Add door lock to generic zigbee things
This commit is contained in:
parent
f906769f60
commit
c7ffbfda15
@ -198,6 +198,116 @@
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "doorLock",
|
||||
"displayName": "Door lock",
|
||||
"id": "34cb3d09-dd9f-4b95-95d0-30a1cd94adac",
|
||||
"setupMethod": "JustAdd",
|
||||
"createMethods": [ "Auto" ],
|
||||
"interfaces": [ "simpleclosable", "batterylevel", "wirelessconnectable" ],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "484bf80f-5d20-4029-b05e-6b4c9fbefd69",
|
||||
"name": "ieeeAddress",
|
||||
"displayName": "IEEE adress",
|
||||
"type": "QString",
|
||||
"defaultValue": "00:00:00:00:00:00:00:00"
|
||||
},
|
||||
{
|
||||
"id": "4d50cbd3-f297-421c-9938-65ec0bb4bd34",
|
||||
"name": "networkUuid",
|
||||
"displayName": "Zigbee network UUID",
|
||||
"type": "QString",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "ebf17460-4a37-461f-aa24-e0a9a4238c63",
|
||||
"name": "endpointId",
|
||||
"displayName": "Endpoint ID",
|
||||
"type": "uint",
|
||||
"defaultValue": 1
|
||||
},
|
||||
{
|
||||
"id": "1b177eb8-a13f-4975-92a7-a6bf54670c8f",
|
||||
"name": "manufacturer",
|
||||
"displayName": "Manufacturer",
|
||||
"type": "QString",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "b13f86a7-dc65-4ed6-860c-cdb099f90916",
|
||||
"name": "model",
|
||||
"displayName": "Model",
|
||||
"type": "QString",
|
||||
"defaultValue": ""
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "206b0508-b477-4aa2-b420-aba2259fb6e6",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"cached": false,
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "6c8f8db5-464c-408a-9c65-4e8096663019",
|
||||
"name": "signalStrength",
|
||||
"displayName": "Signal strength",
|
||||
"displayNameEvent": "Signal strength changed",
|
||||
"defaultValue": 0,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"type": "uint",
|
||||
"unit": "Percentage"
|
||||
},
|
||||
{
|
||||
"id": "9e27850b-99d8-40df-9bc7-4b3c7c01faf8",
|
||||
"name": "version",
|
||||
"displayName": "Version",
|
||||
"displayNameEvent": "Version changed",
|
||||
"type": "QString",
|
||||
"cached": true,
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "568e5bdd-47f3-4ccb-a1d8-ff3a5ea87ad8",
|
||||
"name": "batteryLevel",
|
||||
"displayName": "Battery",
|
||||
"displayNameEvent": "Battery changed",
|
||||
"type": "int",
|
||||
"unit": "Percentage",
|
||||
"defaultValue": 0,
|
||||
"minValue": 0,
|
||||
"maxValue": 100
|
||||
},
|
||||
{
|
||||
"id": "89abea26-b772-4258-9b56-e026b80c2028",
|
||||
"name": "batteryCritical",
|
||||
"displayName": "Battery critical",
|
||||
"displayNameEvent": "Battery critical changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "6e112e3b-080f-47e4-8e2b-453029f0eacb",
|
||||
"name": "open",
|
||||
"displayName": "Unlock door"
|
||||
},
|
||||
{
|
||||
"id": "c26e1908-25d0-4475-8f82-5aaf034640f1",
|
||||
"name": "close",
|
||||
"displayName": "Lock door"
|
||||
}
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -41,27 +41,35 @@ IntegrationPluginZigbeeGeneric::IntegrationPluginZigbeeGeneric()
|
||||
{
|
||||
m_ieeeAddressParamTypeIds[thermostatThingClassId] = thermostatThingIeeeAddressParamTypeId;
|
||||
m_ieeeAddressParamTypeIds[powerSocketThingClassId] = powerSocketThingIeeeAddressParamTypeId;
|
||||
m_ieeeAddressParamTypeIds[doorLockThingClassId] = doorLockThingIeeeAddressParamTypeId;
|
||||
|
||||
m_networkUuidParamTypeIds[thermostatThingClassId] = thermostatThingNetworkUuidParamTypeId;
|
||||
m_networkUuidParamTypeIds[powerSocketThingClassId] = powerSocketThingNetworkUuidParamTypeId;
|
||||
m_networkUuidParamTypeIds[doorLockThingClassId] = doorLockThingNetworkUuidParamTypeId;
|
||||
|
||||
m_endpointIdParamTypeIds[thermostatThingClassId] = thermostatThingEndpointIdParamTypeId;
|
||||
m_endpointIdParamTypeIds[powerSocketThingClassId] = powerSocketThingEndpointIdParamTypeId;
|
||||
m_endpointIdParamTypeIds[doorLockThingClassId] = doorLockThingEndpointIdParamTypeId;
|
||||
|
||||
m_manufacturerIdParamTypeIds[thermostatThingClassId] = thermostatThingManufacturerParamTypeId;
|
||||
m_manufacturerIdParamTypeIds[powerSocketThingClassId] = powerSocketThingManufacturerParamTypeId;
|
||||
m_manufacturerIdParamTypeIds[doorLockThingClassId] = doorLockThingManufacturerParamTypeId;
|
||||
|
||||
m_modelIdParamTypeIds[thermostatThingClassId] = thermostatThingModelParamTypeId;
|
||||
m_modelIdParamTypeIds[powerSocketThingClassId] = powerSocketThingModelParamTypeId;
|
||||
m_modelIdParamTypeIds[doorLockThingClassId] = doorLockThingModelParamTypeId;
|
||||
|
||||
m_connectedStateTypeIds[thermostatThingClassId] = thermostatConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[powerSocketThingClassId] = powerSocketConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[doorLockThingClassId] = doorLockConnectedStateTypeId;
|
||||
|
||||
m_signalStrengthStateTypeIds[thermostatThingClassId] = thermostatSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[powerSocketThingClassId] = powerSocketSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[doorLockThingClassId] = doorLockSignalStrengthStateTypeId;
|
||||
|
||||
m_versionStateTypeIds[thermostatThingClassId] = thermostatVersionStateTypeId;
|
||||
m_versionStateTypeIds[powerSocketThingClassId] = powerSocketVersionStateTypeId;
|
||||
m_versionStateTypeIds[doorLockThingClassId] = doorLockVersionStateTypeId;
|
||||
}
|
||||
|
||||
QString IntegrationPluginZigbeeGeneric::name() const
|
||||
@ -74,6 +82,8 @@ bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &n
|
||||
bool handled = false;
|
||||
foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
|
||||
qCDebug(dcZigbeeGeneric()) << "Checking node endpoint:" << endpoint->endpointId() << endpoint->deviceId();
|
||||
|
||||
// Check thermostat
|
||||
if (endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation &&
|
||||
endpoint->deviceId() == Zigbee::HomeAutomationDeviceThermostat) {
|
||||
qCDebug(dcZigbeeGeneric()) << "Handeling thermostat endpoint for" << node << endpoint;
|
||||
@ -81,6 +91,7 @@ bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &n
|
||||
handled = true;
|
||||
}
|
||||
|
||||
// Check on/off plug
|
||||
if ((endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileLightLink &&
|
||||
endpoint->deviceId() == Zigbee::LightLinkDevice::LightLinkDeviceOnOffPlugin) ||
|
||||
(endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation &&
|
||||
@ -90,6 +101,20 @@ bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &n
|
||||
createThing(powerSocketThingClassId, networkUuid, node, endpoint);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
// Check door lock
|
||||
if (endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceDoorLock) {
|
||||
if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration) ||
|
||||
!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdDoorLock)) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Endpoint claims to be a door lock, but the appropriate input clusters could not be found" << node << endpoint;
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "Handeling door lock endpoint for" << node << endpoint;
|
||||
createThing(doorLockThingClassId, networkUuid, node, endpoint);
|
||||
// Initialize bindings and cluster attributes
|
||||
initializeDoorLock(node, endpoint);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
@ -229,6 +254,44 @@ void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
if (thing->thingClassId() == doorLockThingClassId) {
|
||||
|
||||
// Get battery level changes
|
||||
ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster<ZigbeeClusterPowerConfiguration>(ZigbeeClusterLibrary::ClusterIdPowerConfiguration);
|
||||
if (!powerCluster) {
|
||||
qCWarning(dcZigbeeGeneric()) << "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(doorLockBatteryLevelStateTypeId, powerCluster->batteryPercentage());
|
||||
thing->setStateValue(doorLockBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0));
|
||||
}
|
||||
|
||||
connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){
|
||||
qCDebug(dcZigbeeGeneric()) << "Battery percentage changed" << percentage << "%" << thing;
|
||||
thing->setStateValue(doorLockBatteryLevelStateTypeId, percentage);
|
||||
thing->setStateValue(doorLockBatteryCriticalStateTypeId, (percentage < 10.0));
|
||||
});
|
||||
}
|
||||
|
||||
// Get door state changes
|
||||
ZigbeeClusterDoorLock *doorLockCluster = endpoint->inputCluster<ZigbeeClusterDoorLock>(ZigbeeClusterLibrary::ClusterIdDoorLock);
|
||||
if (!doorLockCluster) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Could not find door lock cluster on" << thing << endpoint;
|
||||
} else {
|
||||
// Only set the initial state if the attribute already exists
|
||||
if (doorLockCluster->hasAttribute(ZigbeeClusterDoorLock::AttributeDoorState)) {
|
||||
qCDebug(dcZigbeeGeneric()) << thing << doorLockCluster->doorState();
|
||||
// TODO: check if we can use smart lock and set appropriate state
|
||||
}
|
||||
|
||||
connect(doorLockCluster, &ZigbeeClusterDoorLock::lockStateChanged, thing, [=](ZigbeeClusterDoorLock::LockState lockState){
|
||||
qCDebug(dcZigbeeGeneric()) << thing << "lock state changed" << lockState;
|
||||
// TODO: check if we can use smart lock and set appropriate state
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
@ -303,6 +366,50 @@ void IntegrationPluginZigbeeGeneric::executeAction(ThingActionInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
if (thing->thingClassId() == doorLockThingClassId) {
|
||||
if (info->action().actionTypeId() == doorLockOpenActionTypeId) {
|
||||
ZigbeeClusterDoorLock *doorLockCluster = endpoint->inputCluster<ZigbeeClusterDoorLock>(ZigbeeClusterLibrary::ClusterIdDoorLock);
|
||||
if (!doorLockCluster) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Could not find door lock cluster for" << thing << "in" << m_thingNodes.value(thing);
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the command trough the network
|
||||
ZigbeeClusterReply *reply = doorLockCluster->unlockDoor();
|
||||
connect(reply, &ZigbeeClusterReply::finished, this, [reply, info](){
|
||||
// Note: reply will be deleted automatically
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
} else {
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->action().actionTypeId() == doorLockCloseActionTypeId) {
|
||||
ZigbeeClusterDoorLock *doorLockCluster = endpoint->inputCluster<ZigbeeClusterDoorLock>(ZigbeeClusterLibrary::ClusterIdDoorLock);
|
||||
if (!doorLockCluster) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Could not find door lock cluster for" << thing << "in" << m_thingNodes.value(thing);
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the command trough the network
|
||||
ZigbeeClusterReply *reply = doorLockCluster->lockDoor();
|
||||
connect(reply, &ZigbeeClusterReply::finished, this, [reply, info](){
|
||||
// Note: reply will be deleted automatically
|
||||
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
} else {
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorUnsupportedFeature);
|
||||
}
|
||||
|
||||
@ -342,3 +449,85 @@ void IntegrationPluginZigbeeGeneric::createThing(const ThingClassId &thingClassI
|
||||
descriptor.setParams(params);
|
||||
emit autoThingsAppeared({descriptor});
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeGeneric::initializeDoorLock(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint)
|
||||
{
|
||||
qCDebug(dcZigbeeGeneric()) << "Read power configuration cluster attributes" << node;
|
||||
ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining});
|
||||
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
|
||||
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Failed to read power configuration cluster attributes" << readAttributeReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "Read power configuration cluster attributes finished successfully";
|
||||
}
|
||||
|
||||
// Bind the cluster to the coordinator
|
||||
qCDebug(dcZigbeeGeneric()) << "Bind power configuration cluster to coordinator IEEE address";
|
||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
|
||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Failed to bind power cluster to coordinator" << zdoReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "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 = 60; // for production use 300;
|
||||
reportingConfig.maxReportingInterval = 120; // for production use 2700;
|
||||
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
|
||||
|
||||
qCDebug(dcZigbeeGeneric()) << "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(dcZigbeeGeneric()) << "Failed to configure power cluster attribute reporting" << reportingReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
|
||||
}
|
||||
|
||||
// Configure door lock attribute reporting and read initial values
|
||||
qCDebug(dcZigbeeGeneric()) << "Read door lock cluster attributes" << node;
|
||||
ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdDoorLock)->readAttributes({ZigbeeClusterDoorLock::AttributeDoorState, ZigbeeClusterDoorLock::AttributeLockType});
|
||||
connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){
|
||||
if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Failed to read door lock attributes" << readAttributeReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "Read door lock cluster attributes finished successfully";
|
||||
}
|
||||
|
||||
// Bind the cluster to the coordinator
|
||||
qCDebug(dcZigbeeGeneric()) << "Bind door lock cluster to coordinator IEEE address";
|
||||
ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdDoorLock, hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01);
|
||||
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){
|
||||
if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Failed to door lock cluster to coordinator" << zdoReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "Bind door lock cluster to coordinator finished successfully";
|
||||
}
|
||||
|
||||
// Configure attribute reporting for lock state
|
||||
ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig;
|
||||
reportingConfig.attributeId = ZigbeeClusterDoorLock::AttributeLockState;
|
||||
reportingConfig.dataType = Zigbee::Enum8;
|
||||
reportingConfig.minReportingInterval = 60;
|
||||
reportingConfig.maxReportingInterval = 120;
|
||||
reportingConfig.reportableChange = ZigbeeDataType(static_cast<quint8>(1)).data();
|
||||
|
||||
qCDebug(dcZigbeeGeneric()) << "Configure attribute reporting for door lock cluster to coordinator";
|
||||
ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdDoorLock)->configureReporting({reportingConfig});
|
||||
connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){
|
||||
if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) {
|
||||
qCWarning(dcZigbeeGeneric()) << "Failed to door lock cluster attribute reporting" << reportingReply->error();
|
||||
} else {
|
||||
qCDebug(dcZigbeeGeneric()) << "Attribute reporting configuration finished for door lock cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -73,6 +73,8 @@ private:
|
||||
ZigbeeNodeEndpoint *findEndpoint(Thing *thing);
|
||||
void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
|
||||
void initializeDoorLock(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint);
|
||||
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINZIGBEEGENERIC_H
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user