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",
"id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
"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()
{
m_ieeeAddressParamTypeIds[thermostatThingClassId] = thermostatThingIeeeAddressParamTypeId;
m_networkUuidParamTypeIds[thermostatThingClassId] = thermostatThingNetworkUuidParamTypeId;
m_connectedStateTypeIds[thermostatThingClassId] = thermostatConnectedStateTypeId;
m_signalStrengthStateTypeIds[thermostatThingClassId] = thermostatSignalStrengthStateTypeId;
}
QString IntegrationPluginZigbeeGeneric::name() const
@ -47,36 +53,29 @@ QString IntegrationPluginZigbeeGeneric::name() const
bool IntegrationPluginZigbeeGeneric::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
{
foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
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>
qCDebug(dcZigbeeGeneric()) << "handleNode called for:" << node;
// // Create generic power socket
// qCDebug(dcZigbee()) << "This device is an power socket";
// if (myThings().filterByThingClassId(genericPowerSocketThingClassId)
// .filterByParam(genericPowerSocketThingIeeeAddressParamTypeId, node->extendedAddress().toString())
// .isEmpty()) {
// qCDebug(dcZigbee()) << "Adding new generic power socket";
// ThingDescriptor descriptor(genericPowerSocketThingClassId);
// QString deviceClassName = supportedThings().findById(genericPowerSocketThingClassId).displayName();
// descriptor.setTitle(QString("%1 (%2 - %3)").arg(deviceClassName).arg(endpoint->manufacturerName()).arg(endpoint->modelIdentifier()));
// ParamList params;
// params.append(Param(genericPowerSocketThingIeeeAddressParamTypeId, node->extendedAddress().toString()));
// params.append(Param(genericPowerSocketThingManufacturerParamTypeId, endpoint->manufacturerName()));
// params.append(Param(genericPowerSocketThingModelParamTypeId, endpoint->modelIdentifier()));
// descriptor.setParams(params);
// descriptor.setParentId(networkManagerDevice->id());
// emit autoThingsAppeared({descriptor});
// } else {
// qCDebug(dcZigbee()) << "The device for this node has already been created.";
// }
// return true;
// }
QHash<quint16, ThingClassId> devicesThingClassIdsMap;
devicesThingClassIdsMap.insert(Zigbee::HomeAutomationDeviceThermostat, thermostatThingClassId);
bool handled = false;
foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
if (devicesThingClassIdsMap.contains(endpoint->deviceId())) {
ThingClassId thingClassId = devicesThingClassIdsMap.value(endpoint->deviceId());
ThingDescriptor descriptor(thingClassId, endpoint->modelIdentifier(), endpoint->manufacturerName());
ParamList params;
params << Param(m_ieeeAddressParamTypeIds.value(thingClassId), node->extendedAddress().toString());
params << Param(m_networkUuidParamTypeIds.value(thingClassId), networkUuid.toString());
descriptor.setParams(params);
emit autoThingsAppeared({descriptor});
handled = true;
}
}
return false;
return handled;
}
void IntegrationPluginZigbeeGeneric::init()
@ -86,6 +85,53 @@ void IntegrationPluginZigbeeGeneric::init()
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);
}

View File

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

View File

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