Implement and improve lumi zigbee sensors according to library changes
This commit is contained in:
parent
3cdc3414da
commit
1748cdaafe
@ -83,16 +83,97 @@
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lumiWeatherSensor",
|
||||
"displayName": "Weather sensor",
|
||||
"id": "0b582616-0b05-4ac9-8b59-51b66079b571",
|
||||
"setupMethod": "JustAdd",
|
||||
"createMethods": [ "Auto" ],
|
||||
"interfaces": [ "pressuresensor", "temperaturesensor", "humiditysensor", "wirelessconnectable" ],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "ce853c00-d175-45bc-a3d9-3c8c93d88099",
|
||||
"name": "removeFromNetwork",
|
||||
"displayName": "Remove from network"
|
||||
"id": "ef1129e2-bdf8-423e-9c11-fa8b406f960b",
|
||||
"name": "ieeeAddress",
|
||||
"displayName": "IEEE adress",
|
||||
"type": "QString",
|
||||
"defaultValue": "00:00:00:00:00:00:00:00"
|
||||
},
|
||||
{
|
||||
"id": "4a9d9427-52cf-4c13-9b71-496145b18476",
|
||||
"name": "test1",
|
||||
"displayName": "Test 1"
|
||||
"id": "fe4cae8c-195c-4f38-ad88-cebd4adbb337",
|
||||
"name": "networkUuid",
|
||||
"displayName": "Zigbee network UUID",
|
||||
"type": "QString",
|
||||
"defaultValue": ""
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "003f7e37-326b-455d-828b-5a9493b56a69",
|
||||
"name": "connected",
|
||||
"displayName": "Available",
|
||||
"displayNameEvent": "Available changed",
|
||||
"type": "bool",
|
||||
"cached": false,
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "684f642e-08ed-4912-b7a9-597baef400c0",
|
||||
"name": "signalStrength",
|
||||
"displayName": "Signal strength",
|
||||
"displayNameEvent": "Signal strength changed",
|
||||
"defaultValue": 0,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"type": "uint",
|
||||
"unit": "Percentage"
|
||||
},
|
||||
{
|
||||
"id": "cc644362-19ca-489d-8122-4d1bc55f100f",
|
||||
"name": "version",
|
||||
"displayName": "Version",
|
||||
"displayNameEvent": "Version changed",
|
||||
"type": "QString",
|
||||
"cached": true,
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "b1641cec-3bf6-4654-b9c0-b81acb3b4481",
|
||||
"name": "temperature",
|
||||
"displayName": "Temperature",
|
||||
"displayNameEvent": "Temperature changed",
|
||||
"type": "double",
|
||||
"unit": "DegreeCelsius",
|
||||
"defaultValue": 0.0
|
||||
},
|
||||
{
|
||||
"id": "27a1e85a-f654-48d8-905d-05b3e2bc499e",
|
||||
"name": "humidity",
|
||||
"displayName": "Humidity",
|
||||
"displayNameEvent": "Humidity changed",
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"unit": "Percentage",
|
||||
"type": "double",
|
||||
"defaultValue": 0.0
|
||||
},
|
||||
{
|
||||
"id": "7c3861f3-a9db-407e-9459-90a511d7f797",
|
||||
"name": "pressure",
|
||||
"displayName": "Pressure",
|
||||
"displayNameEvent": "Pressure changed",
|
||||
"unit": "MilliBar",
|
||||
"type": "double",
|
||||
"defaultValue": 0.0
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
@ -161,11 +242,7 @@
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "2bae0e2d-0c20-475d-a6cd-2e685e6b0626",
|
||||
"name": "removeFromNetwork",
|
||||
"displayName": "Remove from network"
|
||||
}
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
@ -226,11 +303,6 @@
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "65b43aad-1784-4e85-ad5a-ce01cc5757bd",
|
||||
"name": "removeFromNetwork",
|
||||
"displayName": "Remove from network"
|
||||
}
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
@ -337,11 +409,7 @@
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "2797c499-ca7f-4cf6-a732-c8e3cd580e56",
|
||||
"name": "removeFromNetwork",
|
||||
"displayName": "Remove from network"
|
||||
}
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
@ -418,15 +486,76 @@
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "ed085bda-5608-419d-88e2-81ebcb9f26e1",
|
||||
"name": "removeFromNetwork",
|
||||
"displayName": "Remove from network"
|
||||
}
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lumiVibrationSensor",
|
||||
"displayName": "Vibration sensor",
|
||||
"id": "775be45e-08d8-4ae8-bc95-5721a5317856",
|
||||
"setupMethod": "JustAdd",
|
||||
"createMethods": [ "Auto" ],
|
||||
"interfaces": [ "wirelessconnectable" ],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "324cd9a0-3381-490b-9537-88b65e0093bf",
|
||||
"name": "ieeeAddress",
|
||||
"displayName": "IEEE adress",
|
||||
"type": "QString",
|
||||
"defaultValue": "00:00:00:00:00:00:00:00"
|
||||
},
|
||||
{
|
||||
"id": "4e758a2e-32dc-44d8-872f-f656f30aca82",
|
||||
"name": "networkUuid",
|
||||
"displayName": "Zigbee network UUID",
|
||||
"type": "QString",
|
||||
"defaultValue": ""
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "12970c44-5c59-4c6b-a244-6bc413d32c66",
|
||||
"name": "connected",
|
||||
"displayName": "Available",
|
||||
"displayNameEvent": "Available changed",
|
||||
"type": "bool",
|
||||
"cached": false,
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "eb8bbd63-1f1c-4499-8385-06fbe8e301db",
|
||||
"name": "signalStrength",
|
||||
"displayName": "Signal strength",
|
||||
"displayNameEvent": "Signal strength changed",
|
||||
"defaultValue": 0,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"type": "uint",
|
||||
"unit": "Percentage"
|
||||
},
|
||||
{
|
||||
"id": "8a4aceef-c8ee-487a-946c-20f26fc2d5ed",
|
||||
"name": "version",
|
||||
"displayName": "Version",
|
||||
"displayNameEvent": "Version changed",
|
||||
"type": "QString",
|
||||
"cached": true,
|
||||
"defaultValue": ""
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": "ce98b90b-f4fb-431d-a7c9-534fd2b76ba4",
|
||||
"name": "vibrationDetected",
|
||||
"displayName": "Vibration detected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -44,25 +44,49 @@ IntegrationPluginZigbeeLumi::IntegrationPluginZigbeeLumi()
|
||||
m_networkUuidParamTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorThingNetworkUuidParamTypeId;
|
||||
m_networkUuidParamTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorThingNetworkUuidParamTypeId;
|
||||
m_networkUuidParamTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorThingNetworkUuidParamTypeId;
|
||||
m_networkUuidParamTypeIds[lumiWeatherSensorThingClassId] = lumiWeatherSensorThingNetworkUuidParamTypeId;
|
||||
m_networkUuidParamTypeIds[lumiVibrationSensorThingClassId] = lumiVibrationSensorThingNetworkUuidParamTypeId;
|
||||
|
||||
m_zigbeeAddressParamTypeIds[lumiHTSensorThingClassId] = lumiHTSensorThingIeeeAddressParamTypeId;
|
||||
m_zigbeeAddressParamTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorThingIeeeAddressParamTypeId;
|
||||
m_zigbeeAddressParamTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorThingIeeeAddressParamTypeId;
|
||||
m_zigbeeAddressParamTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorThingIeeeAddressParamTypeId;
|
||||
m_zigbeeAddressParamTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorThingIeeeAddressParamTypeId;
|
||||
m_zigbeeAddressParamTypeIds[lumiWeatherSensorThingClassId] = lumiWeatherSensorThingIeeeAddressParamTypeId;
|
||||
m_zigbeeAddressParamTypeIds[lumiVibrationSensorThingClassId] = lumiVibrationSensorThingIeeeAddressParamTypeId;
|
||||
|
||||
m_connectedStateTypeIds[lumiHTSensorThingClassId] = lumiHTSensorConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[lumiWeatherSensorThingClassId] = lumiWeatherSensorConnectedStateTypeId;
|
||||
m_connectedStateTypeIds[lumiVibrationSensorThingClassId] = lumiVibrationSensorConnectedStateTypeId;
|
||||
|
||||
m_versionStateTypeIds[lumiHTSensorThingClassId] = lumiHTSensorVersionStateTypeId;
|
||||
m_versionStateTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorVersionStateTypeId;
|
||||
m_versionStateTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorVersionStateTypeId;
|
||||
m_versionStateTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorVersionStateTypeId;
|
||||
m_versionStateTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorVersionStateTypeId;
|
||||
m_versionStateTypeIds[lumiWeatherSensorThingClassId] = lumiWeatherSensorVersionStateTypeId;
|
||||
m_versionStateTypeIds[lumiVibrationSensorThingClassId] = lumiVibrationSensorVersionStateTypeId;
|
||||
|
||||
m_signalStrengthStateTypeIds[lumiHTSensorThingClassId] = lumiHTSensorSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[lumiButtonSensorThingClassId] = lumiButtonSensorSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[lumiMagnetSensorThingClassId] = lumiMagnetSensorSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[lumiMotionSensorThingClassId] = lumiMotionSensorSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[lumiWaterSensorThingClassId] = lumiWaterSensorSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[lumiWeatherSensorThingClassId] = lumiWeatherSensorSignalStrengthStateTypeId;
|
||||
m_signalStrengthStateTypeIds[lumiVibrationSensorThingClassId] = lumiVibrationSensorSignalStrengthStateTypeId;
|
||||
|
||||
// Known model identifier
|
||||
m_knownLumiDevices.insert("lumi.sensor_ht", lumiHTSensorThingClassId);
|
||||
m_knownLumiDevices.insert("lumi.sensor_magnet", lumiMagnetSensorThingClassId);
|
||||
m_knownLumiDevices.insert("lumi.sensor_switch", lumiButtonSensorThingClassId);
|
||||
m_knownLumiDevices.insert("lumi.sensor_motion", lumiMotionSensorThingClassId);
|
||||
m_knownLumiDevices.insert("lumi.sensor_wleak", lumiWaterSensorThingClassId);
|
||||
m_knownLumiDevices.insert("lumi.weather", lumiWeatherSensorThingClassId);
|
||||
m_knownLumiDevices.insert("lumi.vibration", lumiVibrationSensorThingClassId);
|
||||
}
|
||||
|
||||
QString IntegrationPluginZigbeeLumi::name() const
|
||||
@ -73,29 +97,25 @@ QString IntegrationPluginZigbeeLumi::name() const
|
||||
bool IntegrationPluginZigbeeLumi::handleNode(ZigbeeNode *node, const QUuid &networkUuid)
|
||||
{
|
||||
// Check if this is Lumi
|
||||
// Note: Lumi / Xiaomi / Aquara devices are not in the specs, so no enum here
|
||||
if (node->nodeDescriptor().manufacturerCode != 0x1037) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: Lumi / Xiaomi / Aquara devices are not in the specs, some older models do not
|
||||
// send the node descriptor or use a inconsistent manufacturer code. We use the manufacturer
|
||||
// name for matching since that has shown to be most constant
|
||||
foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) {
|
||||
// Get the model identifier if present from the first endpoint. Also this is out of spec
|
||||
if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdBasic)) {
|
||||
qCWarning(dcZigbeeLumi()) << "This lumi device does not have the basic input cluster yet.";
|
||||
qCDebug(dcZigbeeLumi()) << "This lumi endpoint does not have the basic input cluster, so we skipp it" << endpoint;
|
||||
continue;
|
||||
}
|
||||
|
||||
QHash<QString, ThingClassId> knownLumiDevices;
|
||||
knownLumiDevices.insert("lumi.sensor_ht", lumiHTSensorThingClassId);
|
||||
knownLumiDevices.insert("lumi.sensor_magnet", lumiMagnetSensorThingClassId);
|
||||
knownLumiDevices.insert("lumi.sensor_switch", lumiButtonSensorThingClassId);
|
||||
knownLumiDevices.insert("lumi.sensor_motion", lumiMotionSensorThingClassId);
|
||||
knownLumiDevices.insert("lumi.sensor_water", lumiWaterSensorThingClassId);
|
||||
// Basic cluster exists, so we should have the manufacturer name
|
||||
if (!endpoint->manufacturerName().toLower().startsWith("lumi")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ThingClassId thingClassId;
|
||||
foreach (const QString &knownLumi, knownLumiDevices.keys()) {
|
||||
foreach (const QString &knownLumi, m_knownLumiDevices.keys()) {
|
||||
if (endpoint->modelIdentifier().startsWith(knownLumi)) {
|
||||
thingClassId = knownLumiDevices.value(knownLumi);
|
||||
thingClassId = m_knownLumiDevices.value(knownLumi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -117,6 +137,18 @@ bool IntegrationPluginZigbeeLumi::handleNode(ZigbeeNode *node, const QUuid &netw
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeLumi::handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid)
|
||||
{
|
||||
Q_UNUSED(networkUuid)
|
||||
|
||||
if (m_nodeThings.values().contains(node)) {
|
||||
Thing *thing = m_nodeThings.key(node);
|
||||
qCDebug(dcZigbeeLumi()) << "Node for" << thing << node << "has left the network. Removing thing";
|
||||
m_nodeThings.remove(thing);
|
||||
emit autoThingDisappeared(thing->id());
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeLumi::init()
|
||||
{
|
||||
hardwareManager()->zigbeeResource()->registerHandler(this);
|
||||
@ -124,15 +156,11 @@ void IntegrationPluginZigbeeLumi::init()
|
||||
|
||||
void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
if (!hardwareManager()->zigbeeResource()->available()) {
|
||||
qCWarning(dcZigbeeLumi()) << "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(dcZigbeeLumi()) << "Nework uuid:" << networkUuid;
|
||||
ZigbeeAddress zigbeeAddress = ZigbeeAddress(thing->paramValue(m_zigbeeAddressParamTypeIds.value(thing->thingClassId())).toString());
|
||||
|
||||
ZigbeeNode *node = hardwareManager()->zigbeeResource()->getNode(networkUuid, zigbeeAddress);
|
||||
if (!node) {
|
||||
qCWarning(dcZigbeeLumi()) << "Zigbee node for" << info->thing()->name() << "not found.´";
|
||||
@ -140,6 +168,7 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the endpoint of interest (0x01) for this device
|
||||
ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01);
|
||||
if (!endpoint) {
|
||||
qCWarning(dcZigbeeLumi()) << "Zigbee endpoint 1 not found on" << thing->name();
|
||||
@ -147,6 +176,9 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
return;
|
||||
}
|
||||
|
||||
m_nodeThings.insert(thing, node);
|
||||
|
||||
// General signals and states
|
||||
// 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){
|
||||
@ -163,11 +195,18 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
thing->setStateValue(m_signalStrengthStateTypeIds.value(thing->thingClassId()), signalStrength);
|
||||
});
|
||||
|
||||
// Set the version
|
||||
thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpoint->softwareBuildId());
|
||||
|
||||
|
||||
if (thing->thingClassId() == lumiMagnetSensorThingClassId) {
|
||||
ZigbeeClusterOnOff *onOffCluster = endpoint->inputCluster<ZigbeeClusterOnOff>(ZigbeeClusterLibrary::ClusterIdOnOff);
|
||||
if (onOffCluster) {
|
||||
// thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !onOffCluster->powered());
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (onOffCluster->hasAttribute(ZigbeeClusterOnOff::AttributeOnOff)) {
|
||||
thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !onOffCluster->power());
|
||||
}
|
||||
|
||||
connect(onOffCluster, &ZigbeeClusterOnOff::powerChanged, thing, [thing](bool power){
|
||||
qCDebug(dcZigbeeLumi()) << thing << "state changed" << (power ? "closed" : "open");
|
||||
thing->setStateValue(lumiMagnetSensorClosedStateTypeId, !power);
|
||||
@ -177,13 +216,23 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (thing->thingClassId() == lumiMotionSensorThingClassId) {
|
||||
ZigbeeClusterOccupancySensing *occupancyCluster = endpoint->inputCluster<ZigbeeClusterOccupancySensing>(ZigbeeClusterLibrary::ClusterIdOccupancySensing);
|
||||
if (occupancyCluster) {
|
||||
// thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancyCluster->occupancy());
|
||||
connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [thing](bool occupancy){
|
||||
if (occupancyCluster->hasAttribute(ZigbeeClusterOccupancySensing::AttributeOccupancy)) {
|
||||
thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancyCluster->occupied());
|
||||
thing->setStateValue(lumiMotionSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
|
||||
}
|
||||
|
||||
connect(occupancyCluster, &ZigbeeClusterOccupancySensing::occupancyChanged, thing, [this, thing](bool occupancy){
|
||||
qCDebug(dcZigbeeLumi()) << "occupancy changed" << occupancy;
|
||||
thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancy);
|
||||
// Only change the state if the it changed to true, it will be disabled by the timer
|
||||
if (occupancy) {
|
||||
thing->setStateValue(lumiMotionSensorIsPresentStateTypeId, occupancy);
|
||||
m_presenceTimer->start();
|
||||
}
|
||||
|
||||
thing->setStateValue(lumiMotionSensorLastSeenTimeStateTypeId, QDateTime::currentMSecsSinceEpoch() / 1000);
|
||||
});
|
||||
|
||||
@ -200,15 +249,19 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
qCWarning(dcZigbeeLumi()) << "Occupancy cluster not found on" << thing->name();
|
||||
}
|
||||
|
||||
ZigbeeClusterIlluminanceMeasurment *illuminanceCluster = endpoint->inputCluster<ZigbeeClusterIlluminanceMeasurment>(ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement);
|
||||
if (illuminanceCluster) {
|
||||
// thing->setStateValue(lumiHTSensorTemperatureStateTypeId, illuminanceCluster->illuminance());
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (illuminanceCluster->hasAttribute(ZigbeeClusterIlluminanceMeasurment::AttributeMeasuredValue)) {
|
||||
thing->setStateValue(lumiMotionSensorLightIntensityStateTypeId, illuminanceCluster->illuminance());
|
||||
}
|
||||
|
||||
connect(illuminanceCluster, &ZigbeeClusterIlluminanceMeasurment::illuminanceChanged, thing, [thing](quint16 illuminance){
|
||||
qCDebug(dcZigbeeLumi()) << thing << "light intensity changed" << illuminance << "lux";
|
||||
thing->setStateValue(lumiMotionSensorLightIntensityStateTypeId, illuminance);
|
||||
});
|
||||
} else {
|
||||
@ -216,11 +269,17 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (thing->thingClassId() == lumiHTSensorThingClassId) {
|
||||
ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpoint->inputCluster<ZigbeeClusterTemperatureMeasurement>(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement);
|
||||
if (temperatureCluster) {
|
||||
// thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperatureCluster->temperature());
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (temperatureCluster->hasAttribute(ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue)) {
|
||||
thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperatureCluster->temperature());
|
||||
}
|
||||
|
||||
connect(temperatureCluster, &ZigbeeClusterTemperatureMeasurement::temperatureChanged, thing, [thing](double temperature){
|
||||
qCDebug(dcZigbeeLumi()) << thing << "temperature changed" << temperature << "°C";
|
||||
thing->setStateValue(lumiHTSensorTemperatureStateTypeId, temperature);
|
||||
});
|
||||
} else {
|
||||
@ -229,8 +288,13 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
|
||||
ZigbeeClusterRelativeHumidityMeasurement *humidityCluster = endpoint->inputCluster<ZigbeeClusterRelativeHumidityMeasurement>(ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement);
|
||||
if (humidityCluster) {
|
||||
// thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidityCluster->humidity());
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (humidityCluster->hasAttribute(ZigbeeClusterRelativeHumidityMeasurement::AttributeMeasuredValue)) {
|
||||
thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidityCluster->humidity());
|
||||
}
|
||||
|
||||
connect(humidityCluster, &ZigbeeClusterRelativeHumidityMeasurement::humidityChanged, thing, [thing](double humidity){
|
||||
qCDebug(dcZigbeeLumi()) << thing << "humidity changed" << humidity << "%";
|
||||
thing->setStateValue(lumiHTSensorHumidityStateTypeId, humidity);
|
||||
});
|
||||
} else {
|
||||
@ -238,41 +302,141 @@ void IntegrationPluginZigbeeLumi::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (thing->thingClassId() == lumiWeatherSensorThingClassId) {
|
||||
ZigbeeClusterTemperatureMeasurement *temperatureCluster = endpoint->inputCluster<ZigbeeClusterTemperatureMeasurement>(ZigbeeClusterLibrary::ClusterIdTemperatureMeasurement);
|
||||
if (temperatureCluster) {
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (temperatureCluster->hasAttribute(ZigbeeClusterTemperatureMeasurement::AttributeMeasuredValue)) {
|
||||
thing->setStateValue(lumiWeatherSensorTemperatureStateTypeId, temperatureCluster->temperature());
|
||||
}
|
||||
|
||||
connect(temperatureCluster, &ZigbeeClusterTemperatureMeasurement::temperatureChanged, thing, [thing](double temperature){
|
||||
qCDebug(dcZigbeeLumi()) << thing << "temperature changed" << temperature << "°C";
|
||||
thing->setStateValue(lumiWeatherSensorTemperatureStateTypeId, temperature);
|
||||
});
|
||||
} else {
|
||||
qCWarning(dcZigbeeLumi()) << "Could not find the temperature measurement server cluster on" << thing << endpoint;
|
||||
}
|
||||
|
||||
ZigbeeClusterRelativeHumidityMeasurement *humidityCluster = endpoint->inputCluster<ZigbeeClusterRelativeHumidityMeasurement>(ZigbeeClusterLibrary::ClusterIdRelativeHumidityMeasurement);
|
||||
if (humidityCluster) {
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (humidityCluster->hasAttribute(ZigbeeClusterRelativeHumidityMeasurement::AttributeMeasuredValue)) {
|
||||
thing->setStateValue(lumiWeatherSensorHumidityStateTypeId, humidityCluster->humidity());
|
||||
}
|
||||
|
||||
connect(humidityCluster, &ZigbeeClusterRelativeHumidityMeasurement::humidityChanged, thing, [thing](double humidity){
|
||||
qCDebug(dcZigbeeLumi()) << thing << "humidity changed" << humidity << "%";
|
||||
thing->setStateValue(lumiWeatherSensorHumidityStateTypeId, humidity);
|
||||
});
|
||||
} else {
|
||||
qCWarning(dcZigbeeLumi()) << "Could not find the relative humidity measurement server cluster on" << thing << endpoint;
|
||||
}
|
||||
|
||||
ZigbeeClusterPressureMeasurement *pressureCluster = endpoint->inputCluster<ZigbeeClusterPressureMeasurement>(ZigbeeClusterLibrary::ClusterIdPressureMeasurement);
|
||||
if (pressureCluster) {
|
||||
// Only set the state if the cluster actually has the attribute
|
||||
if (pressureCluster->hasAttribute(ZigbeeClusterPressureMeasurement::AttributeMeasuredValue)) {
|
||||
thing->setStateValue(lumiWeatherSensorPressureStateTypeId, pressureCluster->pressure() * 101);
|
||||
}
|
||||
|
||||
connect(pressureCluster, &ZigbeeClusterPressureMeasurement::pressureChanged, thing, [thing](double pressure){
|
||||
thing->setStateValue(lumiWeatherSensorPressureStateTypeId, pressure * 101);
|
||||
});
|
||||
} else {
|
||||
qCWarning(dcZigbeeLumi()) << "Could not find the pressure measurement server cluster on" << thing << endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (thing->thingClassId() == lumiWaterSensorThingClassId) {
|
||||
connect(endpoint, &ZigbeeNodeEndpoint::clusterAttributeChanged, this, [thing](ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute){
|
||||
if (cluster->clusterId() == ZigbeeClusterLibrary::ClusterIdIasZone) {
|
||||
if (attribute.id() == ZigbeeClusterIasZone::AttributeZoneState) {
|
||||
bool valueOk = false;
|
||||
ZigbeeClusterIasZone::ZoneStatusFlags zoneStatus = static_cast<ZigbeeClusterIasZone::ZoneStatusFlags>(attribute.dataType().toUInt16(&valueOk));
|
||||
if (!valueOk) {
|
||||
qCWarning(dcZigbeeLumi()) << thing << "failed to convert attribute data to uint16 flag. Not updating the states from" << attribute;
|
||||
} else {
|
||||
qCDebug(dcZigbeeLumi()) << thing << "zone status changed" << zoneStatus;
|
||||
|
||||
// Water detected gets indicated in the Alarm1 flag
|
||||
if (zoneStatus.testFlag(ZigbeeClusterIasZone::ZoneStatusAlarm1)) {
|
||||
thing->setStateValue(lumiWaterSensorWaterDetectedStateTypeId, true);
|
||||
} else {
|
||||
thing->setStateValue(lumiWaterSensorWaterDetectedStateTypeId, false);
|
||||
}
|
||||
|
||||
// Battery alarm
|
||||
if (zoneStatus.testFlag(ZigbeeClusterIasZone::ZoneStatusBattery)) {
|
||||
thing->setStateValue(lumiWaterSensorBatteryCriticalStateTypeId, true);
|
||||
} else {
|
||||
thing->setStateValue(lumiWaterSensorBatteryCriticalStateTypeId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (thing->thingClassId() == lumiVibrationSensorThingClassId) {
|
||||
connect(endpoint, &ZigbeeNodeEndpoint::clusterAttributeChanged, this, [this, thing](ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute){
|
||||
if (cluster->clusterId() == ZigbeeClusterLibrary::ClusterIdDoorLock) {
|
||||
// Note: shoehow the vibration sensor is using the door lock cluster, with undocumented attribitues.
|
||||
// This device is completly out of spec, so we just recognize the vibration trough tests and it looks like
|
||||
// attribute id 85 is the indicator for vibration. The payload contains an unsigned int, but not sure what it indicates yet
|
||||
|
||||
if (attribute.id() == 85) {
|
||||
bool valueOk = false;
|
||||
quint16 value = attribute.dataType().toUInt16(&valueOk);
|
||||
if (!valueOk) {
|
||||
qCWarning(dcZigbeeLumi()) << thing << "failed to convert attribute data to uint16." << attribute;
|
||||
} else {
|
||||
qCDebug(dcZigbeeLumi()) << thing << "vibration attribute changed" << value;
|
||||
emitEvent(Event(lumiVibrationSensorVibrationDetectedEventTypeId, thing->id()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
|
||||
|
||||
// if (thing->thingClassId() == lumiButtonSensorThingClassId) {
|
||||
// qCDebug(dcZigbee()) << "Lumi button sensor" << thing;
|
||||
// ZigbeeAddress ieeeAddress(thing->paramValue(lumiButtonSensorThingIeeeAddressParamTypeId).toString());
|
||||
// ZigbeeNetwork *network = findParentNetwork(thing);
|
||||
// LumiButtonSensor *sensor = new LumiButtonSensor(network, ieeeAddress, thing, this);
|
||||
// connect(sensor, &LumiButtonSensor::buttonPressed, this, [this, thing](){
|
||||
// qCDebug(dcZigbee()) << thing << "clicked event";
|
||||
// emit emitEvent(Event(lumiButtonSensorPressedEventTypeId, thing->id()));
|
||||
// });
|
||||
// connect(sensor, &LumiButtonSensor::buttonLongPressed, this, [this, thing](){
|
||||
// qCDebug(dcZigbee()) << thing << "long pressed event";
|
||||
// emit emitEvent(Event(lumiButtonSensorLongPressedEventTypeId, thing->id()));
|
||||
// });
|
||||
|
||||
// if (thing->thingClassId() == lumiButtonSensorThingClassId) {
|
||||
// qCDebug(dcZigbee()) << "Lumi button sensor" << thing;
|
||||
// ZigbeeAddress ieeeAddress(thing->paramValue(lumiButtonSensorThingIeeeAddressParamTypeId).toString());
|
||||
// ZigbeeNetwork *network = findParentNetwork(thing);
|
||||
// LumiButtonSensor *sensor = new LumiButtonSensor(network, ieeeAddress, thing, this);
|
||||
// connect(sensor, &LumiButtonSensor::buttonPressed, this, [this, thing](){
|
||||
// qCDebug(dcZigbee()) << thing << "clicked event";
|
||||
// emit emitEvent(Event(lumiButtonSensorPressedEventTypeId, thing->id()));
|
||||
// });
|
||||
// connect(sensor, &LumiButtonSensor::buttonLongPressed, this, [this, thing](){
|
||||
// qCDebug(dcZigbee()) << thing << "long pressed event";
|
||||
// emit emitEvent(Event(lumiButtonSensorLongPressedEventTypeId, thing->id()));
|
||||
// });
|
||||
|
||||
// m_zigbeeDevices.insert(thing, sensor);
|
||||
// info->finish(Thing::ThingErrorNoError);
|
||||
// return;
|
||||
// }
|
||||
// m_zigbeeDevices.insert(thing, sensor);
|
||||
// info->finish(Thing::ThingErrorNoError);
|
||||
// return;
|
||||
// }
|
||||
|
||||
|
||||
// if (thing->thingClassId() == lumiWaterSensorThingClassId) {
|
||||
// qCDebug(dcZigbee()) << "Lumi water sensor" << thing;
|
||||
// ZigbeeAddress ieeeAddress(thing->paramValue(lumiWaterSensorThingIeeeAddressParamTypeId).toString());
|
||||
// ZigbeeNetwork *network = findParentNetwork(thing);
|
||||
// LumiWaterSensor *sensor = new LumiWaterSensor(network, ieeeAddress, thing, this);
|
||||
// m_zigbeeDevices.insert(thing, sensor);
|
||||
// info->finish(Thing::ThingErrorNoError);
|
||||
// return;
|
||||
// }
|
||||
// if (thing->thingClassId() == lumiWaterSensorThingClassId) {
|
||||
// qCDebug(dcZigbee()) << "Lumi water sensor" << thing;
|
||||
// ZigbeeAddress ieeeAddress(thing->paramValue(lumiWaterSensorThingIeeeAddressParamTypeId).toString());
|
||||
// ZigbeeNetwork *network = findParentNetwork(thing);
|
||||
// LumiWaterSensor *sensor = new LumiWaterSensor(network, ieeeAddress, thing, this);
|
||||
// m_zigbeeDevices.insert(thing, sensor);
|
||||
// info->finish(Thing::ThingErrorNoError);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// info->finish(Thing::ThingErrorThingClassNotFound);
|
||||
// info->finish(Thing::ThingErrorThingClassNotFound);
|
||||
}
|
||||
|
||||
void IntegrationPluginZigbeeLumi::executeAction(ThingActionInfo *info)
|
||||
@ -282,5 +446,9 @@ void IntegrationPluginZigbeeLumi::executeAction(ThingActionInfo *info)
|
||||
|
||||
void IntegrationPluginZigbeeLumi::thingRemoved(Thing *thing)
|
||||
{
|
||||
Q_UNUSED(thing)
|
||||
ZigbeeNode *node = m_nodeThings.take(thing);
|
||||
if (node) {
|
||||
QUuid networkUuid = thing->paramValue(m_networkUuidParamTypeIds.value(thing->thingClassId())).toUuid();
|
||||
hardwareManager()->zigbeeResource()->removeNodeFromNetwork(networkUuid, node);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ public:
|
||||
|
||||
QString name() const override;
|
||||
bool handleNode(ZigbeeNode *node, const QUuid &networkUuid) override;
|
||||
void handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid) override;
|
||||
|
||||
void init() override;
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
@ -61,6 +62,11 @@ private:
|
||||
|
||||
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_signalStrengthStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_versionStateTypeIds;
|
||||
|
||||
QHash<QString, ThingClassId> m_knownLumiDevices;
|
||||
|
||||
QHash<Thing *, ZigbeeNode *> m_nodeThings;
|
||||
|
||||
PluginTimer *m_presenceTimer = nullptr;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user