From 220e307d8d019198f9af58269e77b7a06f5b6a4f Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 3 Apr 2021 18:34:17 +0200 Subject: [PATCH 1/5] ZigbeeGeneric: Add support for ZigBee door/window sensors --- .../integrationpluginzigbeegeneric.cpp | 228 +++++++++++++----- .../integrationpluginzigbeegeneric.h | 13 +- .../integrationpluginzigbeegeneric.json | 94 +++++++- 3 files changed, 263 insertions(+), 72 deletions(-) diff --git a/zigbeegeneric/integrationpluginzigbeegeneric.cpp b/zigbeegeneric/integrationpluginzigbeegeneric.cpp index 6c3ef5b0..8d04e9ec 100644 --- a/zigbeegeneric/integrationpluginzigbeegeneric.cpp +++ b/zigbeegeneric/integrationpluginzigbeegeneric.cpp @@ -37,49 +37,76 @@ #include -QHash batteryLevelStateTypeIds = { +static QHash batteryLevelStateTypeIds = { {thermostatThingClassId, thermostatBatteryLevelStateTypeId}, - {doorLockThingClassId, doorLockBatteryLevelStateTypeId} + {doorLockThingClassId, doorLockBatteryLevelStateTypeId}, + {doorSensorThingClassId, doorSensorBatteryLevelStateTypeId} }; -QHash batteryCriticalStateTypeIds = { +static QHash batteryCriticalStateTypeIds = { {thermostatThingClassId, thermostatBatteryCriticalStateTypeId}, - {doorLockThingClassId, doorLockBatteryCriticalStateTypeId} + {doorLockThingClassId, doorLockBatteryCriticalStateTypeId}, + {doorSensorThingClassId, doorSensorBatteryCriticalStateTypeId} }; +static QHash ieeeAddressParamTypeIds = { + {thermostatThingClassId, thermostatThingIeeeAddressParamTypeId}, + {powerSocketThingClassId, powerSocketThingIeeeAddressParamTypeId}, + {doorLockThingClassId, doorLockThingIeeeAddressParamTypeId}, + {doorSensorThingClassId, doorSensorThingIeeeAddressParamTypeId} +}; + +static QHash networkUuidParamTypeIds = { + {thermostatThingClassId, thermostatThingNetworkUuidParamTypeId}, + {powerSocketThingClassId, powerSocketThingNetworkUuidParamTypeId}, + {doorLockThingClassId, doorLockThingNetworkUuidParamTypeId}, + {doorSensorThingClassId, doorSensorThingNetworkUuidParamTypeId} +}; + +static QHash endpointIdParamTypeIds = { + {thermostatThingClassId, thermostatThingEndpointIdParamTypeId}, + {powerSocketThingClassId, powerSocketThingEndpointIdParamTypeId}, + {doorLockThingClassId, doorLockThingEndpointIdParamTypeId}, + {doorSensorThingClassId, doorSensorThingEndpointIdParamTypeId} +}; + +static QHash modelIdParamTypeIds = { + {thermostatThingClassId, thermostatThingManufacturerParamTypeId}, + {powerSocketThingClassId, powerSocketThingManufacturerParamTypeId}, + {doorLockThingClassId, doorLockThingManufacturerParamTypeId}, + {doorSensorThingClassId, doorSensorThingManufacturerParamTypeId} +}; + +static QHash manufacturerIdParamTypeIds = { + {thermostatThingClassId, thermostatThingModelParamTypeId}, + {powerSocketThingClassId, powerSocketThingModelParamTypeId}, + {doorLockThingClassId, doorLockThingModelParamTypeId}, + {doorSensorThingClassId, doorSensorThingModelParamTypeId} +}; + +static QHash connectedStateTypeIds = { + {thermostatThingClassId, thermostatConnectedStateTypeId}, + {powerSocketThingClassId, powerSocketConnectedStateTypeId}, + {doorLockThingClassId, doorLockConnectedStateTypeId}, + {doorSensorThingClassId, doorSensorConnectedStateTypeId} +}; + +static QHash signalStrengthStateTypeIds = { + {thermostatThingClassId, thermostatSignalStrengthStateTypeId}, + {powerSocketThingClassId, powerSocketSignalStrengthStateTypeId}, + {doorLockThingClassId, doorLockSignalStrengthStateTypeId}, + {doorSensorThingClassId, doorSensorSignalStrengthStateTypeId} +}; + +static QHash versionStateTypeIds = { + {thermostatThingClassId, thermostatVersionStateTypeId}, + {powerSocketThingClassId, powerSocketVersionStateTypeId}, + {doorLockThingClassId, doorLockVersionStateTypeId} +}; + + 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 @@ -127,10 +154,50 @@ bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &n qCDebug(dcZigbeeGeneric()) << "Handling door lock endpoint for" << node << endpoint; createThing(doorLockThingClassId, networkUuid, node, endpoint); // Initialize bindings and cluster attributes - initializeDoorLock(node, endpoint); + initDoorLock(node, endpoint); handled = true; } } + + // Security sensors + if (endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceIsaZone) { + qCInfo(dcZigbeeGeneric()) << "ISA Zone device found!"; + // We need to read the Type cluster to determine what this actually is... + ZigbeeClusterIasZone *iasZoneCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdIasZone); + ZigbeeClusterReply *reply = iasZoneCluster->readAttributes({ZigbeeClusterIasZone::AttributeZoneType}); + connect(reply, &ZigbeeClusterReply::finished, this, [=](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeGeneric()) << "Reading IAS Zone type attribute finished with error" << reply->error(); + return; + } + + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (attributeStatusRecords.count() != 1 || attributeStatusRecords.first().attributeId != ZigbeeClusterIasZone::AttributeZoneType) { + qCWarning(dcZigbeeGeneric()) << "Unexpected reply in reading IAS Zone device type:" << attributeStatusRecords; + return; + } + ZigbeeClusterLibrary::ReadAttributeStatusRecord iasZoneTypeRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeGeneric()) << "IAS Zone device type:" << iasZoneTypeRecord.dataType.toUInt16(); + switch (iasZoneTypeRecord.dataType.toUInt16()) { + case ZigbeeClusterIasZone::ZoneTypeContactSwitch: + qCInfo(dcZigbeeGeneric()) << "Creating contact switch thing"; + createThing(doorSensorThingClassId, networkUuid, node, endpoint); + break; + default: + qCWarning(dcZigbeeGeneric()) << "Unhandled IAS Zone device type:" << "0x" + QString::number(iasZoneTypeRecord.dataType.toUInt16(), 16); + + } + + }); + + + + + +// createThing(doorSensorThingClassId, networkUuid, node, endpoint); +// initDoorSensor(node, endpoint); + handled = true; + } } return handled; @@ -157,9 +224,9 @@ void IntegrationPluginZigbeeGeneric::init() void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); - QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid(); + QUuid networkUuid = thing->paramValue(networkUuidParamTypeIds.value(thing->thingClassId())).toUuid(); qCDebug(dcZigbeeGeneric()) << "Nework uuid:" << networkUuid; - ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_ieeeAddressParamTypeIds.value(thing->thingClassId())).toString()); + ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(ieeeAddressParamTypeIds.value(thing->thingClassId())).toString()); ZigbeeNode *node = m_thingNodes.value(thing); if (!node) { node = hardwareManager()->zigbeeResource()->claimNode(this, networkUuid, zigbeeAddress); @@ -180,21 +247,21 @@ void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info) } // Update connected state - thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), node->reachable()); + thing->setStateValue(connectedStateTypeIds.value(thing->thingClassId()), node->reachable()); connect(node, &ZigbeeNode::reachableChanged, thing, [thing, this](bool reachable){ - thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), reachable); + thing->setStateValue(connectedStateTypeIds.value(thing->thingClassId()), reachable); }); // Update signal strength - thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), qRound(node->lqi() * 100.0 / 255.0)); + thing->setStateValue(signalStrengthStateTypeIds.value(thing->thingClassId()), qRound(node->lqi() * 100.0 / 255.0)); connect(node, &ZigbeeNode::lqiChanged, thing, [this, thing](quint8 lqi){ uint signalStrength = qRound(lqi * 100.0 / 255.0); qCDebug(dcZigbeeGeneric()) << thing << "signal strength changed" << signalStrength << "%"; - thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength); + thing->setStateValue(signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength); }); // Set the version - thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpoint->softwareBuildId()); + thing->setStateValue(versionStateTypeIds.value(thing->thingClassId()), endpoint->softwareBuildId()); if (batteryLevelStateTypeIds.contains(thing->thingClassId())) { connectToPowerConfigurationCluster(thing, endpoint); @@ -302,6 +369,23 @@ void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info) } } + if (thing->thingClassId() == doorSensorThingClassId) { + ZigbeeClusterIasZone *iasZoneCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdIasZone); + if (!iasZoneCluster) { + qCWarning(dcZigbeeGeneric()) << "Could not find IAS zone cluster on" << thing << endpoint; + } else { + if (iasZoneCluster->hasAttribute(ZigbeeClusterIasZone::AttributeZoneStatus)) { + qCDebug(dcZigbeeGeneric()) << thing << iasZoneCluster->zoneStatus(); + ZigbeeClusterIasZone::ZoneStatusFlags zoneStatus = iasZoneCluster->zoneStatus(); + thing->setStateValue(doorSensorClosedStateTypeId, !zoneStatus.testFlag(ZigbeeClusterIasZone::ZoneStatusAlarm1) && !zoneStatus.testFlag(ZigbeeClusterIasZone::ZoneStatusAlarm2)); + } + connect(iasZoneCluster, &ZigbeeClusterIasZone::zoneStatusChanged, thing, [=](ZigbeeClusterIasZone::ZoneStatusFlags zoneStatus, quint8 extendedStatus, quint8 zoneId, quint16 delays) { + qCDebug(dcZigbeeGeneric()) << "Zone status changed to:" << zoneStatus << extendedStatus << zoneId << delays; + thing->setStateValue(doorSensorClosedStateTypeId, !zoneStatus.testFlag(ZigbeeClusterIasZone::ZoneStatusAlarm1) && !zoneStatus.testFlag(ZigbeeClusterIasZone::ZoneStatusAlarm2)); + }); + } + } + info->finish(Thing::ThingErrorNoError); } @@ -460,7 +544,7 @@ void IntegrationPluginZigbeeGeneric::thingRemoved(Thing *thing) { ZigbeeNode *node = m_thingNodes.take(thing); if (node) { - QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid(); + QUuid networkUuid = thing->paramValue(networkUuidParamTypeIds.value(thing->thingClassId())).toUuid(); hardwareManager()->zigbeeResource()->removeNodeFromNetwork(networkUuid, node); } } @@ -473,7 +557,7 @@ ZigbeeNodeEndpoint *IntegrationPluginZigbeeGeneric::findEndpoint(Thing *thing) return nullptr; } - quint8 endpointId = thing->paramValue(m_endpointIdParamTypeIds.value(thing->thingClassId())).toUInt(); + quint8 endpointId = thing->paramValue(endpointIdParamTypeIds.value(thing->thingClassId())).toUInt(); return node->getEndpoint(endpointId); } @@ -484,11 +568,11 @@ void IntegrationPluginZigbeeGeneric::createThing(const ThingClassId &thingClassI descriptor.setTitle(QString("%1 (%2 - %3)").arg(deviceClassName).arg(endpoint->manufacturerName()).arg(endpoint->modelIdentifier())); ParamList params; - params.append(Param(m_networkUuidParamTypeIds[thingClassId], networkUuid.toString())); - params.append(Param(m_ieeeAddressParamTypeIds[thingClassId], node->extendedAddress().toString())); - params.append(Param(m_endpointIdParamTypeIds[thingClassId], endpoint->endpointId())); - params.append(Param(m_modelIdParamTypeIds[thingClassId], endpoint->modelIdentifier())); - params.append(Param(m_manufacturerIdParamTypeIds[thingClassId], endpoint->manufacturerName())); + params.append(Param(networkUuidParamTypeIds[thingClassId], networkUuid.toString())); + params.append(Param(ieeeAddressParamTypeIds[thingClassId], node->extendedAddress().toString())); + params.append(Param(endpointIdParamTypeIds[thingClassId], endpoint->endpointId())); + params.append(Param(modelIdParamTypeIds[thingClassId], endpoint->modelIdentifier())); + params.append(Param(manufacturerIdParamTypeIds[thingClassId], endpoint->manufacturerName())); descriptor.setParams(params); emit autoThingsAppeared({descriptor}); } @@ -510,7 +594,7 @@ void IntegrationPluginZigbeeGeneric::initSimplePowerSocket(ZigbeeNode *node, Zig }); } -void IntegrationPluginZigbeeGeneric::initializeDoorLock(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) +void IntegrationPluginZigbeeGeneric::initDoorLock(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) { bindPowerConfigurationCluster(node, endpoint); @@ -564,15 +648,8 @@ void IntegrationPluginZigbeeGeneric::initThermostat(ZigbeeNode *node, ZigbeeNode reportingOccupiedHeatingSetpointConfig.maxReportingInterval = 2700; reportingOccupiedHeatingSetpointConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); - ZigbeeClusterLibrary::AttributeReportingConfiguration reportingBatteryPercentageConfig; - reportingBatteryPercentageConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; - reportingBatteryPercentageConfig.dataType = Zigbee::Uint8; - reportingBatteryPercentageConfig.minReportingInterval = 300; - reportingBatteryPercentageConfig.maxReportingInterval = 2700; - reportingBatteryPercentageConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); - qCDebug(dcZigbeeGeneric()) << "Configuring attribute reporting for thermostat cluster"; - ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingOccupiedHeatingSetpointConfig, reportingBatteryPercentageConfig}); + ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdThermostat)->configureReporting({reportingOccupiedHeatingSetpointConfig}); connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeeGeneric()) << "Failed to configure thermostat cluster attribute reporting" << reportingReply->error(); @@ -583,6 +660,39 @@ void IntegrationPluginZigbeeGeneric::initThermostat(ZigbeeNode *node, ZigbeeNode }); } +void IntegrationPluginZigbeeGeneric::initDoorSensor(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) +{ + bindPowerConfigurationCluster(node, endpoint); + + qCDebug(dcZigbeeGeneric()) << "Binding IAS custer"; + ZigbeeDeviceObjectReply *bindIasClusterReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdIasZone, + hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); + connect(bindIasClusterReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (bindIasClusterReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeeGeneric()) << "Failed to bind IAS zone cluster" << bindIasClusterReply->error(); + } else { + qCDebug(dcZigbeeGeneric()) << "Binding IAS zone cluster finished successfully"; + } + + ZigbeeClusterLibrary::AttributeReportingConfiguration reportingStatusConfig; + reportingStatusConfig.attributeId = ZigbeeClusterIasZone::AttributeZoneStatus; + reportingStatusConfig.dataType = Zigbee::Int16; + reportingStatusConfig.minReportingInterval = 300; + reportingStatusConfig.maxReportingInterval = 2700; + reportingStatusConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); + + qCDebug(dcZigbeeGeneric()) << "Configuring attribute reporting for thermostat cluster"; + ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdIasZone)->configureReporting({reportingStatusConfig}); + connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ + if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeGeneric()) << "Failed to configure IAS Zone cluster status attribute reporting" << reportingReply->error(); + } else { + qCDebug(dcZigbeeGeneric()) << "Attribute reporting configuration finished for IAS Zone cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + } + }); + }); +} + void IntegrationPluginZigbeeGeneric::bindPowerConfigurationCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) { ZigbeeDeviceObjectReply *bindPowerReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, diff --git a/zigbeegeneric/integrationpluginzigbeegeneric.h b/zigbeegeneric/integrationpluginzigbeegeneric.h index 51ccbc03..05f179a5 100644 --- a/zigbeegeneric/integrationpluginzigbeegeneric.h +++ b/zigbeegeneric/integrationpluginzigbeegeneric.h @@ -59,23 +59,14 @@ public: private: QHash m_thingNodes; - QHash m_ieeeAddressParamTypeIds; - QHash m_networkUuidParamTypeIds; - QHash m_endpointIdParamTypeIds; - QHash m_modelIdParamTypeIds; - QHash m_manufacturerIdParamTypeIds; - - QHash m_connectedStateTypeIds; - QHash m_signalStrengthStateTypeIds; - QHash m_versionStateTypeIds; - // Get the endpoint for the given thing ZigbeeNodeEndpoint *findEndpoint(Thing *thing); void createThing(const ThingClassId &thingClassId, const QUuid &networkUuid, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); void initSimplePowerSocket(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); - void initializeDoorLock(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); + void initDoorLock(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); void initThermostat(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); + void initDoorSensor(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); void bindPowerConfigurationCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); diff --git a/zigbeegeneric/integrationpluginzigbeegeneric.json b/zigbeegeneric/integrationpluginzigbeegeneric.json index f5767c2c..2647cde2 100644 --- a/zigbeegeneric/integrationpluginzigbeegeneric.json +++ b/zigbeegeneric/integrationpluginzigbeegeneric.json @@ -342,9 +342,99 @@ "name": "close", "displayName": "Lock door" } + ] + }, + { + "id": "fd43b442-1764-4005-acaf-9075e6d11e3a", + "name": "doorSensor", + "displayName": "Door sensor", + "createMethods": ["auto"], + "interfaces": ["closablesensor", "batterylevel", "wirelessconnectable"], + "paramTypes": [ + { + "id": "98d4265d-99b7-4849-97ec-a7eae3b275ff", + "name": "ieeeAddress", + "displayName": "IEEE adress", + "type": "QString", + "defaultValue": "00:00:00:00:00:00:00:00" + }, + { + "id": "260cb70b-7cb9-46b9-b6f3-0d4810a016b7", + "name": "networkUuid", + "displayName": "Zigbee network UUID", + "type": "QString", + "defaultValue": "" + }, + { + "id": "e265b17c-e4f4-4bea-b299-a6a3d94a6e7a", + "name": "endpointId", + "displayName": "Endpoint ID", + "type": "uint", + "defaultValue": 1 + }, + { + "id": "193922e4-2c74-4748-a319-9e5b2f2607b4", + "name": "manufacturer", + "displayName": "Manufacturer", + "type": "QString", + "defaultValue": "" + }, + { + "id": "74ddad9e-6849-4b7a-a356-971e77e5195b", + "name": "model", + "displayName": "Model", + "type": "QString", + "defaultValue": "" + } ], - "eventTypes": [ - + "stateTypes": [ + { + "id": "2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44", + "name": "closed", + "displayName": "Closed", + "displayNameEvent": "Opened or closed", + "type": "bool", + "defaultValue": false + }, + { + "id": "3c120c1c-0093-4c5e-8d7e-8892e4ce21b3", + "name": "batteryLevel", + "displayName": "Battery level", + "displayNameEvent": "Battery level changed", + "type": "int", + "minValue": 0, + "maxValue": 100, + "unit": "Percentage", + "defaultValue": 0 + }, + { + "id": "9628450e-5580-4f30-8af7-f1c3093dcfb7", + "name": "batteryCritical", + "displayName": "Battery critical", + "displayNameEvent": "Battery critical changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected or disconnected", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "a1bf9c90-6e12-4513-a82a-a1d15351f140", + "name": "signalStrength", + "displayName": "Signal strength", + "displayNameEvent": "Signal strength changed", + "type": "uint", + "minValue": 0, + "maxValue": 100, + "unit": "Percentage", + "defaultValue": 0 + } ] } ] From 6efbe86fac11a1cef218fb7608b98498d4c3534b Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 3 Apr 2021 18:36:56 +0200 Subject: [PATCH 2/5] Update README and translations --- zigbeegeneric/README.md | 4 + ...343be-9fd6-4015-9ff5-38542651c534-en_US.ts | 263 ++++++++++++------ 2 files changed, 176 insertions(+), 91 deletions(-) diff --git a/zigbeegeneric/README.md b/zigbeegeneric/README.md index 171ae337..3f3fab6c 100644 --- a/zigbeegeneric/README.md +++ b/zigbeegeneric/README.md @@ -22,6 +22,10 @@ Simple on/off power sockets. Radiator thermostats that follow the ZigBee specification. +### Door/window sensors + +Door/window that follow the ZigBee IAS Zone specification. + ## Requirements * A compatible ZigBee controller and a running ZigBee network in nymea. You can find more information about supported controllers and ZigBee network configurations [here](https://nymea.io/documentation/users/usage/configuration#zigbee). diff --git a/zigbeegeneric/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts b/zigbeegeneric/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts index 6e494165..799a029c 100644 --- a/zigbeegeneric/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts +++ b/zigbeegeneric/translations/6a4343be-9fd6-4015-9ff5-38542651c534-en_US.ts @@ -4,10 +4,10 @@ ZigbeeGeneric - - - - + + + + Battery The name of the ParamType (ThingClass: doorLock, EventType: batteryLevel, ID: {568e5bdd-47f3-4ccb-a1d8-ff3a5ea87ad8}) ---------- @@ -19,8 +19,8 @@ The name of the StateType ({3a733e99-850b-4c56-b058-d39850ef2fee}) of ThingClass - - + + Battery changed The name of the EventType ({568e5bdd-47f3-4ccb-a1d8-ff3a5ea87ad8}) of ThingClass doorLock ---------- @@ -28,12 +28,18 @@ The name of the EventType ({3a733e99-850b-4c56-b058-d39850ef2fee}) of ThingClass - - - - + + + + + + Battery critical - The name of the ParamType (ThingClass: doorLock, EventType: batteryCritical, ID: {89abea26-b772-4258-9b56-e026b80c2028}) + The name of the ParamType (ThingClass: doorSensor, EventType: batteryCritical, ID: {9628450e-5580-4f30-8af7-f1c3093dcfb7}) +---------- +The name of the StateType ({9628450e-5580-4f30-8af7-f1c3093dcfb7}) of ThingClass doorSensor +---------- +The name of the ParamType (ThingClass: doorLock, EventType: batteryCritical, ID: {89abea26-b772-4258-9b56-e026b80c2028}) ---------- The name of the StateType ({89abea26-b772-4258-9b56-e026b80c2028}) of ThingClass doorLock ---------- @@ -43,23 +49,56 @@ The name of the StateType ({5cec4399-ba7c-4c78-8c30-c91040ad99cf}) of ThingClass - - + + + Battery critical changed - The name of the EventType ({89abea26-b772-4258-9b56-e026b80c2028}) of ThingClass doorLock + The name of the EventType ({9628450e-5580-4f30-8af7-f1c3093dcfb7}) of ThingClass doorSensor +---------- +The name of the EventType ({89abea26-b772-4258-9b56-e026b80c2028}) of ThingClass doorLock ---------- The name of the EventType ({5cec4399-ba7c-4c78-8c30-c91040ad99cf}) of ThingClass thermostat - - - - - - + + + Battery level + The name of the ParamType (ThingClass: doorSensor, EventType: batteryLevel, ID: {3c120c1c-0093-4c5e-8d7e-8892e4ce21b3}) +---------- +The name of the StateType ({3c120c1c-0093-4c5e-8d7e-8892e4ce21b3}) of ThingClass doorSensor + + + + + Battery level changed + The name of the EventType ({3c120c1c-0093-4c5e-8d7e-8892e4ce21b3}) of ThingClass doorSensor + + + + + + Closed + The name of the ParamType (ThingClass: doorSensor, EventType: closed, ID: {2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44}) +---------- +The name of the StateType ({2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44}) of ThingClass doorSensor + + + + + + + + + + + Connected - The name of the ParamType (ThingClass: doorLock, EventType: connected, ID: {206b0508-b477-4aa2-b420-aba2259fb6e6}) + The name of the ParamType (ThingClass: doorSensor, EventType: connected, ID: {4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e}) +---------- +The name of the StateType ({4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e}) of ThingClass doorSensor +---------- +The name of the ParamType (ThingClass: doorLock, EventType: connected, ID: {206b0508-b477-4aa2-b420-aba2259fb6e6}) ---------- The name of the StateType ({206b0508-b477-4aa2-b420-aba2259fb6e6}) of ThingClass doorLock ---------- @@ -73,8 +112,8 @@ The name of the StateType ({e9fb2b10-96da-4b70-afda-46e948399af8}) of ThingClass - - + + Connected changed The name of the EventType ({206b0508-b477-4aa2-b420-aba2259fb6e6}) of ThingClass doorLock ---------- @@ -82,14 +121,20 @@ The name of the EventType ({b5abd47e-95f1-4e35-94fa-be87c396073a}) of ThingClass - + + Connected or disconnected + The name of the EventType ({4fae59a7-fe89-4bc7-bc04-fc18e94b5c3e}) of ThingClass doorSensor + + + + Connected/disconnected The name of the EventType ({e9fb2b10-96da-4b70-afda-46e948399af8}) of ThingClass thermostat - - + + Cooling on The name of the ParamType (ThingClass: thermostat, EventType: coolingOn, ID: {c77a3d3f-46c7-4026-b9ab-02ab88077cc4}) ---------- @@ -97,14 +142,14 @@ The name of the StateType ({c77a3d3f-46c7-4026-b9ab-02ab88077cc4}) of ThingClass - + Cooling turned on The name of the EventType ({c77a3d3f-46c7-4026-b9ab-02ab88077cc4}) of ThingClass thermostat - - + + Current temperature The name of the ParamType (ThingClass: thermostat, EventType: temperature, ID: {497af03a-a893-438c-aba2-1bf3ecfc66c5}) ---------- @@ -112,23 +157,32 @@ The name of the StateType ({497af03a-a893-438c-aba2-1bf3ecfc66c5}) of ThingClass - + Current temperature changed The name of the EventType ({497af03a-a893-438c-aba2-1bf3ecfc66c5}) of ThingClass thermostat - + Door lock The name of the ThingClass ({34cb3d09-dd9f-4b95-95d0-30a1cd94adac}) - - - + + Door sensor + The name of the ThingClass ({fd43b442-1764-4005-acaf-9075e6d11e3a}) + + + + + + + Endpoint ID - The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {ebf17460-4a37-461f-aa24-e0a9a4238c63}) + The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {e265b17c-e4f4-4bea-b299-a6a3d94a6e7a}) +---------- +The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {ebf17460-4a37-461f-aa24-e0a9a4238c63}) ---------- The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {c7cbda61-2b84-4f2f-a40d-bcbe0efad08c}) ---------- @@ -136,8 +190,8 @@ The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {138a529d-1d - - + + Heating on The name of the ParamType (ThingClass: thermostat, EventType: heatingOn, ID: {88d5dda1-b8f6-49f1-a55a-20415f9157b3}) ---------- @@ -145,17 +199,20 @@ The name of the StateType ({88d5dda1-b8f6-49f1-a55a-20415f9157b3}) of ThingClass - + Heating turned on The name of the EventType ({88d5dda1-b8f6-49f1-a55a-20415f9157b3}) of ThingClass thermostat - - - + + + + IEEE adress - The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {484bf80f-5d20-4029-b05e-6b4c9fbefd69}) + The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {98d4265d-99b7-4849-97ec-a7eae3b275ff}) +---------- +The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {484bf80f-5d20-4029-b05e-6b4c9fbefd69}) ---------- The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {1db22159-08a3-43d0-b515-7b34211b1d04}) ---------- @@ -163,23 +220,26 @@ The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {f38746d8-00 - + Identify The name of the ActionType ({4e3b1430-d98e-4f05-bae6-301dac34bd4b}) of ThingClass powerSocket - + Lock door The name of the ActionType ({c26e1908-25d0-4475-8f82-5aaf034640f1}) of ThingClass doorLock - - - + + + + Manufacturer - The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {1b177eb8-a13f-4975-92a7-a6bf54670c8f}) + The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {193922e4-2c74-4748-a319-9e5b2f2607b4}) +---------- +The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {1b177eb8-a13f-4975-92a7-a6bf54670c8f}) ---------- The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {8daa4709-1dc1-4717-a529-b78e32002b59}) ---------- @@ -187,11 +247,14 @@ The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {ae76acb0-40 - - - + + + + Model - The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {b13f86a7-dc65-4ed6-860c-cdb099f90916}) + The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {74ddad9e-6849-4b7a-a356-971e77e5195b}) +---------- +The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {b13f86a7-dc65-4ed6-860c-cdb099f90916}) ---------- The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {ad03bc04-857a-43a9-8bea-a3c9db24461a}) ---------- @@ -199,9 +262,15 @@ The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {4262cfc6-4b - - - + + Opened or closed + The name of the EventType ({2fb8e0a0-52f2-4c1d-b1c9-c7a295a83b44}) of ThingClass doorSensor + + + + + + Power The name of the ParamType (ThingClass: powerSocket, ActionType: power, ID: {2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) ---------- @@ -211,38 +280,44 @@ The name of the StateType ({2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) of ThingClass - + Power changed The name of the EventType ({2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) of ThingClass powerSocket - + Power socket The name of the ThingClass ({800a8df8-06cb-4d93-8334-944fcce9651a}) - + Set power The name of the ActionType ({2c8268b9-d76b-415a-b2e9-6bfeabd98a76}) of ThingClass powerSocket - + Set target temperature The name of the ActionType ({88ad3957-2912-4de1-b53d-b360565dd361}) of ThingClass thermostat - - - - - - + + + + + + + + Signal strength - The name of the ParamType (ThingClass: doorLock, EventType: signalStrength, ID: {6c8f8db5-464c-408a-9c65-4e8096663019}) + The name of the ParamType (ThingClass: doorSensor, EventType: signalStrength, ID: {a1bf9c90-6e12-4513-a82a-a1d15351f140}) +---------- +The name of the StateType ({a1bf9c90-6e12-4513-a82a-a1d15351f140}) of ThingClass doorSensor +---------- +The name of the ParamType (ThingClass: doorLock, EventType: signalStrength, ID: {6c8f8db5-464c-408a-9c65-4e8096663019}) ---------- The name of the StateType ({6c8f8db5-464c-408a-9c65-4e8096663019}) of ThingClass doorLock ---------- @@ -256,11 +331,14 @@ The name of the StateType ({8f0512ab-ced2-4dcb-90fe-aaa532efd0dd}) of ThingClass - - - + + + + Signal strength changed - The name of the EventType ({6c8f8db5-464c-408a-9c65-4e8096663019}) of ThingClass doorLock + The name of the EventType ({a1bf9c90-6e12-4513-a82a-a1d15351f140}) of ThingClass doorSensor +---------- +The name of the EventType ({6c8f8db5-464c-408a-9c65-4e8096663019}) of ThingClass doorLock ---------- The name of the EventType ({21889797-32c0-4f1b-903d-8af71981882b}) of ThingClass powerSocket ---------- @@ -268,9 +346,9 @@ The name of the EventType ({8f0512ab-ced2-4dcb-90fe-aaa532efd0dd}) of ThingClass - - - + + + Target temperature The name of the ParamType (ThingClass: thermostat, ActionType: targetTemperature, ID: {88ad3957-2912-4de1-b53d-b360565dd361}) ---------- @@ -280,24 +358,24 @@ The name of the StateType ({88ad3957-2912-4de1-b53d-b360565dd361}) of ThingClass - + Target temperature changed The name of the EventType ({88ad3957-2912-4de1-b53d-b360565dd361}) of ThingClass thermostat - + Unlock door The name of the ActionType ({6e112e3b-080f-47e4-8e2b-453029f0eacb}) of ThingClass doorLock - - - - - - + + + + + + Version The name of the ParamType (ThingClass: doorLock, EventType: version, ID: {9e27850b-99d8-40df-9bc7-4b3c7c01faf8}) ---------- @@ -313,9 +391,9 @@ The name of the StateType ({c8bd12d2-b425-4422-9e0e-a65542a47b70}) of ThingClass - - - + + + Version changed The name of the EventType ({9e27850b-99d8-40df-9bc7-4b3c7c01faf8}) of ThingClass doorLock ---------- @@ -325,23 +403,26 @@ The name of the EventType ({c8bd12d2-b425-4422-9e0e-a65542a47b70}) of ThingClass - + Zigbee Generic The name of the plugin ZigbeeGeneric ({6a4343be-9fd6-4015-9ff5-38542651c534}) - + Zigbee Thermostat The name of the ThingClass ({ca9af6cf-2d15-4d54-ba07-3d2ce03445b8}) - - - + + + + Zigbee network UUID - The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {4d50cbd3-f297-421c-9938-65ec0bb4bd34}) + The name of the ParamType (ThingClass: doorSensor, Type: thing, ID: {260cb70b-7cb9-46b9-b6f3-0d4810a016b7}) +---------- +The name of the ParamType (ThingClass: doorLock, Type: thing, ID: {4d50cbd3-f297-421c-9938-65ec0bb4bd34}) ---------- The name of the ParamType (ThingClass: powerSocket, Type: thing, ID: {26e92d1d-bc2f-4ccd-ad1f-d6d6189d2609}) ---------- @@ -349,7 +430,7 @@ The name of the ParamType (ThingClass: thermostat, Type: thing, ID: {4a92b536-de - + nymea The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6}) From 16c460d291ae1e25e66d6b0572dbd403578e690f Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 3 Apr 2021 22:41:34 +0200 Subject: [PATCH 3/5] Update to new battery interface --- zigbeegeneric/integrationpluginzigbeegeneric.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zigbeegeneric/integrationpluginzigbeegeneric.json b/zigbeegeneric/integrationpluginzigbeegeneric.json index 2647cde2..f7d1e232 100644 --- a/zigbeegeneric/integrationpluginzigbeegeneric.json +++ b/zigbeegeneric/integrationpluginzigbeegeneric.json @@ -349,7 +349,7 @@ "name": "doorSensor", "displayName": "Door sensor", "createMethods": ["auto"], - "interfaces": ["closablesensor", "batterylevel", "wirelessconnectable"], + "interfaces": ["closablesensor", "battery", "wirelessconnectable"], "paramTypes": [ { "id": "98d4265d-99b7-4849-97ec-a7eae3b275ff", From b2ab548f31125d99d3ae93179d5ee128e4f7beba Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 4 Apr 2021 22:57:12 +0200 Subject: [PATCH 4/5] cleanup --- zigbeegeneric/integrationpluginzigbeegeneric.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/zigbeegeneric/integrationpluginzigbeegeneric.cpp b/zigbeegeneric/integrationpluginzigbeegeneric.cpp index 8d04e9ec..67500bd0 100644 --- a/zigbeegeneric/integrationpluginzigbeegeneric.cpp +++ b/zigbeegeneric/integrationpluginzigbeegeneric.cpp @@ -190,12 +190,6 @@ bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &n }); - - - - -// createThing(doorSensorThingClassId, networkUuid, node, endpoint); -// initDoorSensor(node, endpoint); handled = true; } } From ff420fd30384a523f93e6367c3fe4fce502beabe Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 5 Apr 2021 20:54:32 +0200 Subject: [PATCH 5/5] bind addtributes --- zigbeegeneric/integrationpluginzigbeegeneric.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/zigbeegeneric/integrationpluginzigbeegeneric.cpp b/zigbeegeneric/integrationpluginzigbeegeneric.cpp index 67500bd0..0947d148 100644 --- a/zigbeegeneric/integrationpluginzigbeegeneric.cpp +++ b/zigbeegeneric/integrationpluginzigbeegeneric.cpp @@ -182,6 +182,7 @@ bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &n case ZigbeeClusterIasZone::ZoneTypeContactSwitch: qCInfo(dcZigbeeGeneric()) << "Creating contact switch thing"; createThing(doorSensorThingClassId, networkUuid, node, endpoint); + initDoorSensor(node, endpoint); break; default: qCWarning(dcZigbeeGeneric()) << "Unhandled IAS Zone device type:" << "0x" + QString::number(iasZoneTypeRecord.dataType.toUInt16(), 16);