Try add a generic thermostat

This commit is contained in:
Michael Zanetti 2020-11-07 00:27:57 +01:00
parent 5b533ab77f
commit 3cdc3414da
4 changed files with 140 additions and 32 deletions

View File

@ -8,6 +8,62 @@
"displayName": "nymea", "displayName": "nymea",
"id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
"thingClasses": [ "thingClasses": [
{
"id": "ca9af6cf-2d15-4d54-ba07-3d2ce03445b8",
"name": "thermostat",
"displayName": "Zigbee Thermostat",
"createMethods": ["auto"],
"interfaces": ["thermostat", "wirelessconnectable"],
"paramTypes": [
{
"id": "f38746d8-0084-43a3-b645-3ec743ea5fbc",
"name": "ieeeAddress",
"displayName": "IEEE adress",
"type": "QString",
"defaultValue": "00:00:00:00:00:00:00:00"
},
{
"id": "4a92b536-de4c-4701-8117-9bb26dd51c3e",
"name": "networkUuid",
"displayName": "Zigbee network UUID",
"type": "QString",
"defaultValue": ""
}
],
"stateTypes": [
{
"id": "88ad3957-2912-4de1-b53d-b360565dd361",
"name": "targetTemperature",
"displayName": "Target temperature",
"displayNameEvent": "Target temperature changed",
"type": "double",
"unit": "DegreeCelsius",
"minValue": 0,
"maxValue": 50,
"defaultValue": 0
},
{
"id": "e9fb2b10-96da-4b70-afda-46e948399af8",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected/disconnected",
"type": "bool",
"cached": false,
"defaultValue": false
},
{
"id": "8f0512ab-ced2-4dcb-90fe-aaa532efd0dd",
"name": "signalStrength",
"displayName": "Signal strength",
"displayNameEvent": "Signal strength changed",
"defaultValue": 0,
"maxValue": 100,
"minValue": 0,
"type": "uint",
"unit": "Percentage"
}
]
}
] ]
} }
] ]

View File

@ -37,7 +37,13 @@
IntegrationPluginZigbeeGeneric::IntegrationPluginZigbeeGeneric() IntegrationPluginZigbeeGeneric::IntegrationPluginZigbeeGeneric()
{ {
m_ieeeAddressParamTypeIds[thermostatThingClassId] = thermostatThingIeeeAddressParamTypeId;
m_networkUuidParamTypeIds[thermostatThingClassId] = thermostatThingNetworkUuidParamTypeId;
m_connectedStateTypeIds[thermostatThingClassId] = thermostatConnectedStateTypeId;
m_signalStrengthStateTypeIds[thermostatThingClassId] = thermostatSignalStrengthStateTypeId;
} }
QString IntegrationPluginZigbeeGeneric::name() const QString IntegrationPluginZigbeeGeneric::name() const
@ -47,36 +53,29 @@ QString IntegrationPluginZigbeeGeneric::name() const
bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &networkUuid) bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
{ {
foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { qCDebug(dcZigbeeGeneric()) << "handleNode called for:" << node;
qCDebug(dcZigbeeGeneric) << "Endpoint profile:" << endpoint->profile() << endpoint->deviceId() << networkUuid;
// if ((endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileLightLink && endpoint->deviceId() == Zigbee::LightLinkDevice::LightLinkDeviceOnOff
// (endpoint->profile() == Zigbee::ZigbeeProfile::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceOnOf>
// // Create generic power socket QHash<quint16, ThingClassId> devicesThingClassIdsMap;
// qCDebug(dcZigbee()) << "This device is an power socket"; devicesThingClassIdsMap.insert(Zigbee::HomeAutomationDeviceThermostat, thermostatThingClassId);
// if (myThings().filterByThingClassId(genericPowerSocketThingClassId)
// .filterByParam(genericPowerSocketThingIeeeAddressParamTypeId, node->extendedAddress().toString()) bool handled = false;
// .isEmpty()) {
// qCDebug(dcZigbee()) << "Adding new generic power socket"; foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
// ThingDescriptor descriptor(genericPowerSocketThingClassId);
// QString deviceClassName = supportedThings().findById(genericPowerSocketThingClassId).displayName(); if (devicesThingClassIdsMap.contains(endpoint->deviceId())) {
// descriptor.setTitle(QString("%1 (%2 - %3)").arg(deviceClassName).arg(endpoint->manufacturerName()).arg(endpoint->modelIdentifier())); ThingClassId thingClassId = devicesThingClassIdsMap.value(endpoint->deviceId());
// ParamList params; ThingDescriptor descriptor(thingClassId, endpoint->modelIdentifier(), endpoint->manufacturerName());
// params.append(Param(genericPowerSocketThingIeeeAddressParamTypeId, node->extendedAddress().toString())); ParamList params;
// params.append(Param(genericPowerSocketThingManufacturerParamTypeId, endpoint->manufacturerName())); params << Param(m_ieeeAddressParamTypeIds.value(thingClassId), node->extendedAddress().toString());
// params.append(Param(genericPowerSocketThingModelParamTypeId, endpoint->modelIdentifier())); params << Param(m_networkUuidParamTypeIds.value(thingClassId), networkUuid.toString());
// descriptor.setParams(params); descriptor.setParams(params);
// descriptor.setParentId(networkManagerDevice->id()); emit autoThingsAppeared({descriptor});
// emit autoThingsAppeared({descriptor});
// } else { handled = true;
// qCDebug(dcZigbee()) << "The device for this node has already been created."; }
// }
// return true;
// }
} }
return handled;
return false;
} }
void IntegrationPluginZigbeeGeneric::init() void IntegrationPluginZigbeeGeneric::init()
@ -86,6 +85,53 @@ void IntegrationPluginZigbeeGeneric::init()
void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info) void IntegrationPluginZigbeeGeneric::setupThing(ThingSetupInfo *info)
{ {
if (!hardwareManager()->zigbeeResource()->available()) {
qCWarning(dcZigbeeGeneric()) << "Zigbee is not available. Not setting up" << info->thing()->name();
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
Thing *thing = info->thing();
QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
qCDebug(dcZigbeeGeneric()) << "Nework uuid:" << networkUuid;
ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_ieeeAddressParamTypeIds.value(thing->thingClassId())).toString());
ZigbeeNode *node = hardwareManager()->zigbeeResource()->getNode(networkUuid, zigbeeAddress);
if (!node) {
qCWarning(dcZigbeeGeneric()) << "Zigbee node for" << info->thing()->name() << "not found.´";
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01);
if (!endpoint) {
qCWarning(dcZigbeeGeneric()) << "Zigbee endpoint 1 not found on" << thing->name();
info->finish(Thing::ThingErrorSetupFailed);
return;
}
// Update connected state
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), hardwareManager()->zigbeeResource()->networkState(networkUuid) == ZigbeeNetwork::StateRunning);
connect(hardwareManager()->zigbeeResource(), &ZigbeeHardwareResource::networkStateChanged, thing, [thing, this](const QUuid &networkUuid, ZigbeeNetwork::State state){
if (thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid() == networkUuid) {
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), state == ZigbeeNetwork::StateRunning);
}
});
// Update signal strength
thing->setStateValue(m_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);
});
// Type specific setup
if (thing->thingClassId() == thermostatThingClassId) {
// TODO: Thermostat cluster is missing
// ZigbeeClusterThermostat *thermostatCluster = endpoint->inputCluster<ZigbeeClusterThermostat>(ZigbeeClusterLibrary::ClusterIdThermostat);
}
info->finish(Thing::ThingErrorNoError); info->finish(Thing::ThingErrorNoError);
} }

View File

@ -56,6 +56,12 @@ public:
void thingRemoved(Thing *thing) override; void thingRemoved(Thing *thing) override;
private: private:
QHash<ThingClassId, ParamTypeId> m_ieeeAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_networkUuidParamTypeIds;
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
QHash<ThingClassId, StateTypeId> m_signalStrengthStateTypeIds;
}; };
#endif // INTEGRATIONPLUGINZIGBEEGENERIC_H #endif // INTEGRATIONPLUGINZIGBEEGENERIC_H

View File

@ -167,7 +167,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
if (thing->thingClassId() == lumiMagnetSensorThingClassId) { if (thing->thingClassId() == lumiMagnetSensorThingClassId) {
ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff); ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
if (onOffCluster) { if (onOffCluster) {
thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !onOffCluster->powered()); // thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !onOffCluster->powered());
connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){ connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){
qCDebug(dcZigbeeLumi()) << thing << "state changed" << (power ? "closed" : "open"); qCDebug(dcZigbeeLumi()) << thing << "state changed" << (power ? "closed" : "open");
thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !power); thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !power);
@ -180,7 +180,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
if (thing->thingClassId() == lumiMotionSensorThingClassId) { if (thing->thingClassId() == lumiMotionSensorThingClassId) {
ZigbeeClusterOccupancySensing *occupancyCluster = endpoint->inputCluster<ZigbeeClusterOccupancySensing>(ZigbeeClusterLibrary::ClusterIdOccupancySensing); ZigbeeClusterOccupancySensing *occupancyCluster = endpoint->inputCluster<ZigbeeClusterOccupancySensing>(ZigbeeClusterLibrary::ClusterIdOccupancySensing);
if (occupancyCluster) { if (occupancyCluster) {
thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancyCluster->occupancy()); // thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancyCluster->occupancy());
connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [thing](bool occupancy){ connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [thing](bool occupancy){
qCDebug(dcZigbeeLumi()) << "occupancy changed" << occupancy; qCDebug(dcZigbeeLumi()) << "occupancy changed" << occupancy;
thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancy); thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancy);
@ -207,7 +207,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
ZigbeeClusterIlluminanceMeasurment *illuminanceCluster = endpoint->inputCluster<ZigbeeClusterIlluminanceMeasurment>(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement); ZigbeeClusterIlluminanceMeasurment *illuminanceCluster = endpoint->inputCluster<ZigbeeClusterIlluminanceMeasurment>(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement);
if (illuminanceCluster) { if (illuminanceCluster) {
thing->setStateValue(lumiHTSensorTemperatureStateTypeId, illuminanceCluster->illuminance()); // thing->setStateValue(lumiHTSensorTemperatureStateTypeId, illuminanceCluster->illuminance());
connect(illuminanceCluster, &ZigbeeClusterIlluminanceMeasurment::illuminanceChanged, thing, [thing](quint16 illuminance){ connect(illuminanceCluster, &ZigbeeClusterIlluminanceMeasurment::illuminanceChanged, thing, [thing](quint16 illuminance){
thing->setStateValue(lumiMotionSensorLightIntensityStateTypeId, illuminance); thing->setStateValue(lumiMotionSensorLightIntensityStateTypeId, illuminance);
}); });
@ -219,7 +219,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
if (thing->thingClassId() == lumiHTSensorThingClassId) { if (thing->thingClassId() == lumiHTSensorThingClassId) {
ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpoint->inputCluster<ZigbeeClusterTemperatureMeasurement>(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement); ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpoint->inputCluster<ZigbeeClusterTemperatureMeasurement>(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement);
if (temperatureCluster) { if (temperatureCluster) {
thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperatureCluster->temperature()); // thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperatureCluster->temperature());
connect(temperatureCluster, &ZigbeeClusterTemperatureMeasurement::temperatureChanged, thing, [thing](double temperature){ connect(temperatureCluster, &ZigbeeClusterTemperatureMeasurement::temperatureChanged, thing, [thing](double temperature){
thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperature); thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperature);
}); });
@ -229,7 +229,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
ZigbeeClusterRelativeHumidityMeasurement *humidityCluster = endpoint->inputCluster<ZigbeeClusterRelativeHumidityMeasurement>(ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement); ZigbeeClusterRelativeHumidityMeasurement *humidityCluster = endpoint->inputCluster<ZigbeeClusterRelativeHumidityMeasurement>(ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement);
if (humidityCluster) { if (humidityCluster) {
thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidityCluster->humidity()); // thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidityCluster->humidity());
connect(humidityCluster, &ZigbeeClusterRelativeHumidityMeasurement::humidityChanged, thing, [thing](double humidity){ connect(humidityCluster, &ZigbeeClusterRelativeHumidityMeasurement::humidityChanged, thing, [thing](double humidity){
thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidity); thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidity);
}); });