From 220e307d8d019198f9af58269e77b7a06f5b6a4f Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 3 Apr 2021 18:34:17 +0200 Subject: [PATCH] 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 + } ] } ]