PhilipsHue: Add support for the hue indoor motion sensor

This commit is contained in:
Michael Zanetti 2019-06-11 02:37:57 +02:00
parent b5a1a84ab5
commit 4778e3fc9a
7 changed files with 430 additions and 146 deletions

View File

@ -322,11 +322,44 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device)
return Device::DeviceSetupStatusSuccess; return Device::DeviceSetupStatusSuccess;
} }
// Hue Motion sensor
if (device->deviceClassId() == motionSensorDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue motion sensor" << device->params();
HueIndoorSensor *motionSensor = new HueIndoorSensor(this);
motionSensor->setTimeout(device->setting(motionSensorSettingsTimeoutParamTypeId).toUInt());
motionSensor->setUuid(device->paramValue(motionSensorDeviceUuidParamTypeId).toString());
motionSensor->setModelId(device->paramValue(motionSensorDeviceModelIdParamTypeId).toString());
motionSensor->setTemperatureSensorId(device->paramValue(motionSensorDeviceSensorIdTemperatureParamTypeId).toInt());
motionSensor->setTemperatureSensorUuid(device->paramValue(motionSensorDeviceSensorUuidTemperatureParamTypeId).toString());
motionSensor->setPresenceSensorId(device->paramValue(motionSensorDeviceSensorIdPresenceParamTypeId).toInt());
motionSensor->setPresenceSensorUuid(device->paramValue(motionSensorDeviceSensorUuidPresenceParamTypeId).toString());
motionSensor->setLightSensorId(device->paramValue(motionSensorDeviceSensorIdLightParamTypeId).toInt());
motionSensor->setLightSensorUuid(device->paramValue(motionSensorDeviceSensorUuidLightParamTypeId).toString());
connect(motionSensor, &HueMotionSensor::reachableChanged, this, &DevicePluginPhilipsHue::onMotionSensorReachableChanged);
connect(motionSensor, &HueMotionSensor::batteryLevelChanged, this, &DevicePluginPhilipsHue::onMotionSensorBatteryLevelChanged);
connect(motionSensor, &HueMotionSensor::temperatureChanged, this, &DevicePluginPhilipsHue::onMotionSensorTemperatureChanged);
connect(motionSensor, &HueMotionSensor::presenceChanged, this, &DevicePluginPhilipsHue::onMotionSensorPresenceChanged);
connect(motionSensor, &HueMotionSensor::lightIntensityChanged, this, &DevicePluginPhilipsHue::onMotionSensorLightIntensityChanged);
connect(device, &Device::settingChanged, motionSensor, [motionSensor](const ParamTypeId &paramTypeId, const QVariant &value){
if (paramTypeId == motionSensorSettingsTimeoutParamTypeId) {
motionSensor->setTimeout(value.toUInt());
}
});
m_motionSensors.insert(motionSensor, device);
return Device::DeviceSetupStatusSuccess;
}
// Hue Outdoor sensor // Hue Outdoor sensor
if (device->deviceClassId() == outdoorSensorDeviceClassId) { if (device->deviceClassId() == outdoorSensorDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue Outdoor sensor" << device->params(); qCDebug(dcPhilipsHue) << "Setup Hue Outdoor sensor" << device->params();
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this); HueMotionSensor *outdoorSensor = new HueOutdoorSensor(this);
outdoorSensor->setTimeout(device->setting(outdoorSensorSettingsTimeoutParamTypeId).toUInt());
outdoorSensor->setUuid(device->paramValue(outdoorSensorDeviceUuidParamTypeId).toString()); outdoorSensor->setUuid(device->paramValue(outdoorSensorDeviceUuidParamTypeId).toString());
outdoorSensor->setModelId(device->paramValue(outdoorSensorDeviceModelIdParamTypeId).toString()); outdoorSensor->setModelId(device->paramValue(outdoorSensorDeviceModelIdParamTypeId).toString());
outdoorSensor->setTemperatureSensorId(device->paramValue(outdoorSensorDeviceSensorIdTemperatureParamTypeId).toInt()); outdoorSensor->setTemperatureSensorId(device->paramValue(outdoorSensorDeviceSensorIdTemperatureParamTypeId).toInt());
@ -336,13 +369,19 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device)
outdoorSensor->setLightSensorId(device->paramValue(outdoorSensorDeviceSensorIdLightParamTypeId).toInt()); outdoorSensor->setLightSensorId(device->paramValue(outdoorSensorDeviceSensorIdLightParamTypeId).toInt());
outdoorSensor->setLightSensorUuid(device->paramValue(outdoorSensorDeviceSensorUuidLightParamTypeId).toString()); outdoorSensor->setLightSensorUuid(device->paramValue(outdoorSensorDeviceSensorUuidLightParamTypeId).toString());
connect(outdoorSensor, &HueOutdoorSensor::reachableChanged, this, &DevicePluginPhilipsHue::onOutdoorSensorReachableChanged); connect(outdoorSensor, &HueMotionSensor::reachableChanged, this, &DevicePluginPhilipsHue::onMotionSensorReachableChanged);
connect(outdoorSensor, &HueOutdoorSensor::batteryLevelChanged, this, &DevicePluginPhilipsHue::onOutdoorSensorBatteryLevelChanged); connect(outdoorSensor, &HueMotionSensor::batteryLevelChanged, this, &DevicePluginPhilipsHue::onMotionSensorBatteryLevelChanged);
connect(outdoorSensor, &HueOutdoorSensor::temperatureChanged, this, &DevicePluginPhilipsHue::onOutdoorSensorTemperatureChanged); connect(outdoorSensor, &HueMotionSensor::temperatureChanged, this, &DevicePluginPhilipsHue::onMotionSensorTemperatureChanged);
connect(outdoorSensor, &HueOutdoorSensor::presenceChanged, this, &DevicePluginPhilipsHue::onOutdoorSensorPresenceChanged); connect(outdoorSensor, &HueMotionSensor::presenceChanged, this, &DevicePluginPhilipsHue::onMotionSensorPresenceChanged);
connect(outdoorSensor, &HueOutdoorSensor::lightIntensityChanged, this, &DevicePluginPhilipsHue::onOutdoorSensorLightIntensityChanged); connect(outdoorSensor, &HueMotionSensor::lightIntensityChanged, this, &DevicePluginPhilipsHue::onMotionSensorLightIntensityChanged);
m_outdoorSensors.insert(outdoorSensor, device); connect(device, &Device::settingChanged, outdoorSensor, [outdoorSensor](const ParamTypeId &paramTypeId, const QVariant &value){
if (paramTypeId == outdoorSensorSettingsTimeoutParamTypeId) {
outdoorSensor->setTimeout(value.toUInt());
}
});
m_motionSensors.insert(outdoorSensor, device);
return Device::DeviceSetupStatusSuccess; return Device::DeviceSetupStatusSuccess;
} }
@ -384,8 +423,8 @@ void DevicePluginPhilipsHue::deviceRemoved(Device *device)
} }
if (device->deviceClassId() == outdoorSensorDeviceClassId) { if (device->deviceClassId() == outdoorSensorDeviceClassId) {
HueOutdoorSensor *outdoorSensor = m_outdoorSensors.key(device); HueMotionSensor *outdoorSensor = m_motionSensors.key(device);
m_outdoorSensors.remove(outdoorSensor); m_motionSensors.remove(outdoorSensor);
outdoorSensor->deleteLater(); outdoorSensor->deleteLater();
} }
} }
@ -856,41 +895,41 @@ void DevicePluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
emitEvent(Event(id, m_remotes.value(remote)->id(), ParamList() << param)); emitEvent(Event(id, m_remotes.value(remote)->id(), ParamList() << param));
} }
void DevicePluginPhilipsHue::onOutdoorSensorReachableChanged(bool reachable) void DevicePluginPhilipsHue::onMotionSensorReachableChanged(bool reachable)
{ {
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender()); HueMotionSensor *sensor = static_cast<HueMotionSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor); Device *sensorDevice = m_motionSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorConnectedStateTypeId, reachable); sensorDevice->setStateValue(sensor->connectedStateTypeId(), reachable);
} }
void DevicePluginPhilipsHue::onOutdoorSensorBatteryLevelChanged(int batteryLevel) void DevicePluginPhilipsHue::onMotionSensorBatteryLevelChanged(int batteryLevel)
{ {
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender()); HueMotionSensor *sensor = static_cast<HueMotionSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor); Device *sensorDevice = m_motionSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorBatteryLevelStateTypeId, batteryLevel); sensorDevice->setStateValue(sensor->batteryLevelStateTypeId(), batteryLevel);
sensorDevice->setStateValue(outdoorSensorBatteryCriticalStateTypeId, (batteryLevel < 5)); sensorDevice->setStateValue(sensor->batteryCriticalStateTypeId(), (batteryLevel < 5));
} }
void DevicePluginPhilipsHue::onOutdoorSensorTemperatureChanged(double temperature) void DevicePluginPhilipsHue::onMotionSensorTemperatureChanged(double temperature)
{ {
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender()); HueMotionSensor *sensor = static_cast<HueMotionSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor); Device *sensorDevice = m_motionSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorTemperatureStateTypeId, temperature); sensorDevice->setStateValue(sensor->temperatureStateTypeId(), temperature);
} }
void DevicePluginPhilipsHue::onOutdoorSensorPresenceChanged(bool presence) void DevicePluginPhilipsHue::onMotionSensorPresenceChanged(bool presence)
{ {
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender()); HueMotionSensor *sensor = static_cast<HueMotionSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor); Device *sensorDevice = m_motionSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorIsPresentStateTypeId, presence); sensorDevice->setStateValue(sensor->isPresentStateTypeId(), presence);
if (presence) sensorDevice->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t()); if (presence) sensorDevice->setStateValue(sensor->lastSeenTimeStateTypeId(), QDateTime::currentDateTime().toTime_t());
} }
void DevicePluginPhilipsHue::onOutdoorSensorLightIntensityChanged(double lightIntensity) void DevicePluginPhilipsHue::onMotionSensorLightIntensityChanged(double lightIntensity)
{ {
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender()); HueMotionSensor *sensor = static_cast<HueMotionSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor); Device *sensorDevice = m_motionSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorLightIntensityStateTypeId, lightIntensity); sensorDevice->setStateValue(sensor->lightIntensityStateTypeId(), lightIntensity);
} }
void DevicePluginPhilipsHue::refreshLight(Device *device) void DevicePluginPhilipsHue::refreshLight(Device *device)
@ -1103,7 +1142,7 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
// Create sensors if not already added // Create sensors if not already added
QVariantMap sensorsMap = jsonDoc.toVariant().toMap(); QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
QHash<QString, HueOutdoorSensor *> outdoorSensors; QHash<QString, HueMotionSensor *> motionSensors;
foreach (const QString &sensorId, sensorsMap.keys()) { foreach (const QString &sensorId, sensorsMap.keys()) {
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap(); QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
@ -1132,7 +1171,8 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
descriptor.setParams(params); descriptor.setParams(params);
emit autoDevicesAppeared(tapDeviceClassId, {descriptor}); emit autoDevicesAppeared(tapDeviceClassId, {descriptor});
qCDebug(dcPhilipsHue()) << "Found hue tap:" << sensorMap << tapDeviceClassId; qCDebug(dcPhilipsHue()) << "Found hue tap:" << sensorMap << tapDeviceClassId;
} else if (model == "SML002") {
} else if (model == "SML001" || model == "SML002") {
// Get the base uuid from this sensor // Get the base uuid from this sensor
QString baseUuid = HueDevice::getBaseUuid(uuid); QString baseUuid = HueDevice::getBaseUuid(uuid);
@ -1140,52 +1180,69 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
if (sensorMap.value("type").toString() == "ZLLTemperature") { if (sensorMap.value("type").toString() == "ZLLTemperature") {
qCDebug(dcPhilipsHue()) << "Found temperature sensor from OurdoorSensor:" << baseUuid << sensorMap; qCDebug(dcPhilipsHue()) << "Found temperature sensor from OurdoorSensor:" << baseUuid << sensorMap;
// Check if we haven outdoor sensor for this temperature sensor // Check if we haven outdoor sensor for this temperature sensor
if (outdoorSensors.keys().contains(baseUuid)) { if (motionSensors.contains(baseUuid)) {
HueOutdoorSensor *outdoorSensor = outdoorSensors.value(baseUuid); HueMotionSensor *motionSensor = motionSensors.value(baseUuid);
outdoorSensor->setTemperatureSensorUuid(uuid); motionSensor->setTemperatureSensorUuid(uuid);
outdoorSensor->setTemperatureSensorId(sensorId.toInt()); motionSensor->setTemperatureSensorId(sensorId.toInt());
} else { } else {
// Create an outdoor sensor // Create an outdoor sensor
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this); HueMotionSensor *motionSensor = nullptr;
outdoorSensor->setModelId(model); if (model == "SML001") {
outdoorSensor->setUuid(baseUuid); motionSensor = new HueIndoorSensor(this);
outdoorSensor->setTemperatureSensorUuid(uuid); } else {
outdoorSensor->setTemperatureSensorId(sensorId.toInt()); motionSensor = new HueOutdoorSensor(this);
outdoorSensors.insert(baseUuid, outdoorSensor); }
motionSensor->setModelId(model);
motionSensor->setUuid(baseUuid);
motionSensor->setTemperatureSensorUuid(uuid);
motionSensor->setTemperatureSensorId(sensorId.toInt());
motionSensors.insert(baseUuid, motionSensor);
} }
} }
if (sensorMap.value("type").toString() == "ZLLPresence") { if (sensorMap.value("type").toString() == "ZLLPresence") {
qCDebug(dcPhilipsHue()) << "Found presence sensor from OurdoorSensor:" << baseUuid << sensorMap; qCDebug(dcPhilipsHue()) << "Found presence sensor from OurdoorSensor:" << baseUuid << sensorMap;
// Check if we haven outdoor sensor for this presence sensor // Check if we haven outdoor sensor for this presence sensor
if (outdoorSensors.keys().contains(baseUuid)) { if (motionSensors.contains(baseUuid)) {
HueOutdoorSensor *outdoorSensor = outdoorSensors.value(baseUuid); HueMotionSensor *motionSensor = motionSensors.value(baseUuid);
outdoorSensor->setPresenceSensorUuid(uuid); motionSensor->setPresenceSensorUuid(uuid);
outdoorSensor->setPresenceSensorId(sensorId.toInt()); motionSensor->setPresenceSensorId(sensorId.toInt());
} else { } else {
// Create an outdoor sensor // Create an outdoor sensor
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this); HueMotionSensor *motionSensor = nullptr;
outdoorSensor->setUuid(baseUuid); if (model == "SML001") {
outdoorSensor->setPresenceSensorUuid(uuid); motionSensor = new HueIndoorSensor(this);
outdoorSensor->setPresenceSensorId(sensorId.toInt()); } else {
outdoorSensors.insert(baseUuid, outdoorSensor); motionSensor = new HueOutdoorSensor(this);
}
motionSensor->setModelId(model);
motionSensor->setUuid(baseUuid);
motionSensor->setPresenceSensorUuid(uuid);
motionSensor->setPresenceSensorId(sensorId.toInt());
motionSensors.insert(baseUuid, motionSensor);
} }
} }
if (sensorMap.value("type").toString() == "ZLLLightLevel") { if (sensorMap.value("type").toString() == "ZLLLightLevel") {
qCDebug(dcPhilipsHue()) << "Found light sensor from OurdoorSensor:" << sensorMap; qCDebug(dcPhilipsHue()) << "Found light sensor from OurdoorSensor:" << sensorMap;
// Check if we haven outdoor sensor for this light sensor // Check if we haven outdoor sensor for this light sensor
if (outdoorSensors.keys().contains(baseUuid)) { if (motionSensors.contains(baseUuid)) {
HueOutdoorSensor *outdoorSensor = outdoorSensors.value(baseUuid); HueMotionSensor *motionSensor = motionSensors.value(baseUuid);
outdoorSensor->setLightSensorUuid(uuid); motionSensor->setLightSensorUuid(uuid);
outdoorSensor->setLightSensorId(sensorId.toInt()); motionSensor->setLightSensorId(sensorId.toInt());
} else { } else {
// Create an outdoor sensor // Create an outdoor sensor
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this); HueMotionSensor *motionSensor = nullptr;
outdoorSensor->setUuid(baseUuid); if (model == "SML001") {
outdoorSensor->setLightSensorUuid(uuid); motionSensor = new HueIndoorSensor(this);
outdoorSensor->setLightSensorId(sensorId.toInt()); } else {
outdoorSensors.insert(baseUuid, outdoorSensor); motionSensor = new HueOutdoorSensor(this);
}
motionSensor->setModelId(model);
motionSensor->setUuid(baseUuid);
motionSensor->setLightSensorUuid(uuid);
motionSensor->setLightSensorId(sensorId.toInt());
motionSensors.insert(baseUuid, motionSensor);
} }
} }
} else { } else {
@ -1194,28 +1251,43 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
} }
// Create outdoor sensors if there are any new sensors found // Create outdoor sensors if there are any new sensors found
foreach (HueOutdoorSensor *outdoorSensor, outdoorSensors.values()) { foreach (HueMotionSensor *motionSensor, motionSensors.values()) {
QString baseUuid = outdoorSensors.key(outdoorSensor); QString baseUuid = motionSensors.key(motionSensor);
if (outdoorSensor->isValid()) { if (motionSensor->isValid()) {
DeviceDescriptor descriptor(outdoorSensorDeviceClassId, "Philips Hue Outdoor sensor", baseUuid, device->id()); if (motionSensor->modelId() == "SML001") {
ParamList params; DeviceDescriptor descriptor(motionSensorDeviceClassId, tr("Philips Hue Motion sensor"), baseUuid, device->id());
params.append(Param(outdoorSensorDeviceUuidParamTypeId, outdoorSensor->uuid())); ParamList params;
params.append(Param(outdoorSensorDeviceModelIdParamTypeId, outdoorSensor->modelId())); params.append(Param(motionSensorDeviceUuidParamTypeId, motionSensor->uuid()));
params.append(Param(outdoorSensorDeviceSensorUuidTemperatureParamTypeId, outdoorSensor->temperatureSensorUuid())); params.append(Param(motionSensorDeviceModelIdParamTypeId, motionSensor->modelId()));
params.append(Param(outdoorSensorDeviceSensorIdTemperatureParamTypeId, outdoorSensor->temperatureSensorId())); params.append(Param(motionSensorDeviceSensorUuidTemperatureParamTypeId, motionSensor->temperatureSensorUuid()));
params.append(Param(outdoorSensorDeviceSensorUuidPresenceParamTypeId, outdoorSensor->presenceSensorUuid())); params.append(Param(motionSensorDeviceSensorIdTemperatureParamTypeId, motionSensor->temperatureSensorId()));
params.append(Param(outdoorSensorDeviceSensorIdPresenceParamTypeId, outdoorSensor->presenceSensorId())); params.append(Param(motionSensorDeviceSensorUuidPresenceParamTypeId, motionSensor->presenceSensorUuid()));
params.append(Param(outdoorSensorDeviceSensorUuidLightParamTypeId, outdoorSensor->lightSensorUuid())); params.append(Param(motionSensorDeviceSensorIdPresenceParamTypeId, motionSensor->presenceSensorId()));
params.append(Param(outdoorSensorDeviceSensorIdLightParamTypeId, outdoorSensor->lightSensorId())); params.append(Param(motionSensorDeviceSensorUuidLightParamTypeId, motionSensor->lightSensorUuid()));
descriptor.setParams(params); params.append(Param(motionSensorDeviceSensorIdLightParamTypeId, motionSensor->lightSensorId()));
descriptor.setParams(params);
qCDebug(dcPhilipsHue()) << "Found new Outdoor sensor" << baseUuid << outdoorSensorDeviceClassId; qCDebug(dcPhilipsHue()) << "Found new motion sensor" << baseUuid << outdoorSensorDeviceClassId;
emit autoDevicesAppeared(outdoorSensorDeviceClassId, {descriptor}); emit autoDevicesAppeared(motionSensorDeviceClassId, {descriptor});
} else if (motionSensor->modelId() == "SML002") {
DeviceDescriptor descriptor(outdoorSensorDeviceClassId, tr("Philips Hue Outdoor sensor"), baseUuid, device->id());
ParamList params;
params.append(Param(outdoorSensorDeviceUuidParamTypeId, motionSensor->uuid()));
params.append(Param(outdoorSensorDeviceModelIdParamTypeId, motionSensor->modelId()));
params.append(Param(outdoorSensorDeviceSensorUuidTemperatureParamTypeId, motionSensor->temperatureSensorUuid()));
params.append(Param(outdoorSensorDeviceSensorIdTemperatureParamTypeId, motionSensor->temperatureSensorId()));
params.append(Param(outdoorSensorDeviceSensorUuidPresenceParamTypeId, motionSensor->presenceSensorUuid()));
params.append(Param(outdoorSensorDeviceSensorIdPresenceParamTypeId, motionSensor->presenceSensorId()));
params.append(Param(outdoorSensorDeviceSensorUuidLightParamTypeId, motionSensor->lightSensorUuid()));
params.append(Param(outdoorSensorDeviceSensorIdLightParamTypeId, motionSensor->lightSensorId()));
descriptor.setParams(params);
qCDebug(dcPhilipsHue()) << "Found new outdoor sensor" << baseUuid << outdoorSensorDeviceClassId;
emit autoDevicesAppeared(outdoorSensorDeviceClassId, {descriptor});
}
} }
// Clean up // Clean up
outdoorSensors.remove(baseUuid); motionSensors.remove(baseUuid);
outdoorSensor->deleteLater(); motionSensor->deleteLater();
} }
} }
@ -1353,9 +1425,9 @@ void DevicePluginPhilipsHue::processSensorsRefreshResponse(Device *device, const
} }
// Outdoor sensors // Outdoor sensors
foreach (HueOutdoorSensor *outdoorSensor, m_outdoorSensors.keys()) { foreach (HueMotionSensor *motionSensor, m_motionSensors.keys()) {
if (outdoorSensor->hasSensor(sensorId.toInt()) && m_outdoorSensors.value(outdoorSensor)->parentId() == device->id()) { if (motionSensor->hasSensor(sensorId.toInt()) && m_motionSensors.value(motionSensor)->parentId() == device->id()) {
outdoorSensor->updateStates(sensorMap); motionSensor->updateStates(sensorMap);
} }
} }
} }
@ -1535,12 +1607,10 @@ void DevicePluginPhilipsHue::bridgeReachableChanged(Device *device, const bool &
} }
} }
foreach (HueOutdoorSensor *outdoorSensor, m_outdoorSensors.keys()) { foreach (HueMotionSensor *motionSensor, m_motionSensors.keys()) {
if (m_outdoorSensors.value(outdoorSensor)->parentId() == device->id()) { if (m_motionSensors.value(motionSensor)->parentId() == device->id()) {
outdoorSensor->setReachable(false); motionSensor->setReachable(false);
if (m_outdoorSensors.value(outdoorSensor)->deviceClassId() == outdoorSensorDeviceClassId) { m_motionSensors.value(motionSensor)->setStateValue(motionSensor->connectedStateTypeId(), false);
m_outdoorSensors.value(outdoorSensor)->setStateValue(outdoorSensorConnectedStateTypeId, false);
}
} }
} }
} }
@ -1607,6 +1677,16 @@ bool DevicePluginPhilipsHue::sensorAlreadyAdded(const QString &uuid)
return true; return true;
} }
} }
// Motion sensor consits out of 3 sensors
if (device->deviceClassId() == motionSensorDeviceClassId) {
if (device->paramValue(motionSensorDeviceSensorUuidLightParamTypeId).toString() == uuid) {
return true;
} else if (device->paramValue(motionSensorDeviceSensorUuidPresenceParamTypeId).toString() == uuid) {
return true;
} else if (device->paramValue(motionSensorDeviceSensorUuidTemperatureParamTypeId).toString() == uuid) {
return true;
}
}
} }
return false; return false;

View File

@ -29,8 +29,10 @@
#include "huelight.h" #include "huelight.h"
#include "hueremote.h" #include "hueremote.h"
#include "pairinginfo.h" #include "pairinginfo.h"
#include "huemotionsensor.h"
#include "huemotionsensor.h"
#include "plugintimer.h" #include "plugintimer.h"
#include "hueoutdoorsensor.h"
#include "network/networkaccessmanager.h" #include "network/networkaccessmanager.h"
#include "network/upnp/upnpdiscovery.h" #include "network/upnp/upnpdiscovery.h"
@ -61,12 +63,12 @@ private slots:
void remoteStateChanged(); void remoteStateChanged();
void onRemoteButtonEvent(int buttonCode); void onRemoteButtonEvent(int buttonCode);
// Outdoor sensor // Motion sensor
void onOutdoorSensorReachableChanged(bool reachable); void onMotionSensorReachableChanged(bool reachable);
void onOutdoorSensorBatteryLevelChanged(int batteryLevel); void onMotionSensorBatteryLevelChanged(int batteryLevel);
void onOutdoorSensorTemperatureChanged(double temperature); void onMotionSensorTemperatureChanged(double temperature);
void onOutdoorSensorPresenceChanged(bool presence); void onMotionSensorPresenceChanged(bool presence);
void onOutdoorSensorLightIntensityChanged(double lightIntensity); void onMotionSensorLightIntensityChanged(double lightIntensity);
private slots: private slots:
void networkManagerReplyReady(); void networkManagerReplyReady();
@ -105,7 +107,7 @@ private:
QHash<HueBridge *, Device *> m_bridges; QHash<HueBridge *, Device *> m_bridges;
QHash<HueLight *, Device *> m_lights; QHash<HueLight *, Device *> m_lights;
QHash<HueRemote *, Device *> m_remotes; QHash<HueRemote *, Device *> m_remotes;
QHash<HueOutdoorSensor *, Device *> m_outdoorSensors; QHash<HueMotionSensor *, Device *> m_motionSensors;
void refreshLight(Device *device); void refreshLight(Device *device);
void refreshBridge(Device *device); void refreshBridge(Device *device);

View File

@ -671,6 +671,18 @@
"readOnly": true "readOnly": true
} }
], ],
"settingsTypes": [
{
"id": "21d461b2-b4dd-4a70-b3d5-aaedc88605a4",
"name": "timeout",
"displayName": "Time period",
"type": "uint",
"unit": "Seconds",
"defaultValue": 10,
"minValue": 10
}
],
"stateTypes": [ "stateTypes": [
{ {
"id": "9fe43e6b-3c29-43a9-bb96-3b80eacc10db", "id": "9fe43e6b-3c29-43a9-bb96-3b80eacc10db",
@ -735,6 +747,147 @@
"defaultValue": 0 "defaultValue": 0
} }
] ]
},
{
"id": "25b79fff-4b88-4af8-b06c-2fe246238790",
"name": "motionSensor",
"displayName": "Hue Motion Sensor",
"interfaces": ["presencesensor", "temperaturesensor", "lightsensor", "batterylevel", "connectable"],
"createMethods": ["auto"],
"paramTypes": [
{
"id": "9cb488b7-a76f-4389-a6b5-b36250246f2b",
"name": "modelId",
"displayName": "Model id",
"type" : "QString",
"readOnly": true
},
{
"id": "3e9aad4c-1dff-42c0-bbd4-cdd8635c01a7",
"name": "uuid",
"displayName": "Uuid",
"type" : "QString",
"readOnly": true
},
{
"id": "c9e81e29-f8d4-4370-ada2-f48b32def1fe",
"name": "sensorIdTemperature",
"displayName": "Temperature sensor id",
"type" : "int",
"readOnly": true
},
{
"id": "aa29b5f1-5589-4fa9-bbd4-8869723c037c",
"name": "sensorUuidTemperature",
"displayName": "Temperature sensor uuid",
"type" : "QString",
"readOnly": true
},
{
"id": "337b2c6c-e3bf-495c-943c-b45fa08add37",
"name": "sensorIdPresence",
"displayName": "Presence sensor id",
"type" : "int",
"readOnly": true
},
{
"id": "3829bddb-e722-4724-be36-3a8402738581",
"name": "sensorUuidPresence",
"displayName": "Presence sensor uuid",
"type" : "QString",
"readOnly": true
},
{
"id": "04fba73e-730e-437a-b6f2-10df21296af5",
"name": "sensorIdLight",
"displayName": "Light sensor id",
"type" : "int",
"readOnly": true
},
{
"id": "171cc2e7-7a95-4116-986c-66d75e3e23eb",
"name": "sensorUuidLight",
"displayName": "Light sensor uuid",
"type" : "QString",
"readOnly": true
}
],
"settingsTypes": [
{
"id": "beedc4af-c107-4c53-be25-fd01a349fd35",
"name": "timeout",
"displayName": "Time period",
"type": "uint",
"unit": "Seconds",
"defaultValue": 10,
"minValue": 10
}
],
"stateTypes": [
{
"id": "19c28b69-a9c2-4908-8255-7681f72c2d92",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachable changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "ac463b30-24af-4352-84da-19a3ffc906bd",
"name": "batteryLevel",
"displayName": "Battery",
"displayNameEvent": "Battery changed",
"type": "int",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100
},
{
"id": "d7c4e143-6f03-411e-a12e-dd22806270fd",
"name": "batteryCritical",
"displayName": "Battery critical",
"displayNameEvent": "Battery critical changed",
"type": "bool",
"defaultValue": false
},
{
"id": "63ee79f7-702b-48c1-86cf-8ddebb78bae6",
"name": "temperature",
"displayName": "Temperature",
"displayNameEvent": "Temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0
},
{
"id": "064f48c1-f86d-4a0a-bdae-3420123dff3f",
"name": "lightIntensity",
"displayName": "Ambient light",
"displayNameEvent": "Ambient light changed",
"unit": "Lux",
"type": "double",
"defaultValue": 0
},
{
"id": "e38ee39c-c77f-40b5-b122-4efc411da0ed",
"name": "isPresent",
"displayName": "Person is present",
"displayNameEvent": "Person is present changed",
"type": "bool",
"defaultValue": false
},
{
"id": "ef2e564e-2443-448f-bcd9-f85a1126ee6a",
"name": "lastSeenTime",
"displayName": "Last seen time",
"displayNameEvent": "Last seen time changed",
"type": "int",
"unit": "UnixTime",
"defaultValue": 0
}
]
} }
] ]
} }

View File

@ -33,7 +33,7 @@ class HueDevice : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit HueDevice(QObject *parent = 0); explicit HueDevice(QObject *parent = nullptr);
int id() const; int id() const;
void setId(const int &id); void setId(const int &id);

View File

@ -20,106 +20,109 @@
* * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "hueoutdoorsensor.h" #include "huemotionsensor.h"
#include "extern-plugininfo.h" #include "extern-plugininfo.h"
HueOutdoorSensor::HueOutdoorSensor(QObject *parent) : HueMotionSensor::HueMotionSensor(QObject *parent) :
HueDevice(parent) HueDevice(parent)
{ {
m_timeout.setInterval(10000);
connect(&m_timeout, &QTimer::timeout, this, [this](){
if (m_presence) {
qCDebug(dcPhilipsHue) << "Motion sensor timeout reached" << m_timeout.interval();
m_presence = false;
emit presenceChanged(m_presence);
}
});
} }
QString HueOutdoorSensor::uuid() const void HueMotionSensor::setTimeout(int timeout)
{ {
return m_uuid; // The sensor keeps emitting presence = true for 10 secs, let's subtract that time from the timeout to compensate
m_timeout.setInterval((timeout - 9)* 1000);
} }
void HueOutdoorSensor::setUuid(const QString &uuid) int HueMotionSensor::temperatureSensorId() const
{
m_uuid = uuid;
}
int HueOutdoorSensor::temperatureSensorId() const
{ {
return m_temperatureSensorId; return m_temperatureSensorId;
} }
void HueOutdoorSensor::setTemperatureSensorId(int sensorId) void HueMotionSensor::setTemperatureSensorId(int sensorId)
{ {
m_temperatureSensorId = sensorId; m_temperatureSensorId = sensorId;
} }
QString HueOutdoorSensor::temperatureSensorUuid() const QString HueMotionSensor::temperatureSensorUuid() const
{ {
return m_temperatureSensorUuid; return m_temperatureSensorUuid;
} }
void HueOutdoorSensor::setTemperatureSensorUuid(const QString &temperatureSensorUuid) void HueMotionSensor::setTemperatureSensorUuid(const QString &temperatureSensorUuid)
{ {
m_temperatureSensorUuid = temperatureSensorUuid; m_temperatureSensorUuid = temperatureSensorUuid;
} }
int HueOutdoorSensor::presenceSensorId() const int HueMotionSensor::presenceSensorId() const
{ {
return m_presenceSensorId; return m_presenceSensorId;
} }
void HueOutdoorSensor::setPresenceSensorId(int sensorId) void HueMotionSensor::setPresenceSensorId(int sensorId)
{ {
m_presenceSensorId = sensorId; m_presenceSensorId = sensorId;
} }
QString HueOutdoorSensor::presenceSensorUuid() const QString HueMotionSensor::presenceSensorUuid() const
{ {
return m_presenceSensorUuid; return m_presenceSensorUuid;
} }
void HueOutdoorSensor::setPresenceSensorUuid(const QString &presenceSensorUuid) void HueMotionSensor::setPresenceSensorUuid(const QString &presenceSensorUuid)
{ {
m_presenceSensorUuid = presenceSensorUuid; m_presenceSensorUuid = presenceSensorUuid;
} }
int HueOutdoorSensor::lightSensorId() const int HueMotionSensor::lightSensorId() const
{ {
return m_lightSensorId; return m_lightSensorId;
} }
void HueOutdoorSensor::setLightSensorId(int sensorId) void HueMotionSensor::setLightSensorId(int sensorId)
{ {
m_lightSensorId = sensorId; m_lightSensorId = sensorId;
} }
QString HueOutdoorSensor::lightSensorUuid() const QString HueMotionSensor::lightSensorUuid() const
{ {
return m_lightSensorUuid; return m_lightSensorUuid;
} }
void HueOutdoorSensor::setLightSensorUuid(const QString &lightSensorUuid) void HueMotionSensor::setLightSensorUuid(const QString &lightSensorUuid)
{ {
m_lightSensorUuid = lightSensorUuid; m_lightSensorUuid = lightSensorUuid;
} }
double HueOutdoorSensor::temperature() const double HueMotionSensor::temperature() const
{ {
return m_temperature; return m_temperature;
} }
double HueOutdoorSensor::lightIntensity() const double HueMotionSensor::lightIntensity() const
{ {
return m_lightIntensity; return m_lightIntensity;
} }
bool HueOutdoorSensor::present() const bool HueMotionSensor::present() const
{ {
return m_presence; return m_presence;
} }
int HueOutdoorSensor::batteryLevel() const int HueMotionSensor::batteryLevel() const
{ {
return m_batteryLevel; return m_batteryLevel;
} }
void HueOutdoorSensor::updateStates(const QVariantMap &sensorMap) void HueMotionSensor::updateStates(const QVariantMap &sensorMap)
{ {
//qCDebug(dcPhilipsHue()) << "Outdoor sensor: Process sensor map" << qUtf8Printable(QJsonDocument::fromVariant(sensorMap).toJson(QJsonDocument::Indented)); //qCDebug(dcPhilipsHue()) << "Outdoor sensor: Process sensor map" << qUtf8Printable(QJsonDocument::fromVariant(sensorMap).toJson(QJsonDocument::Indented));
@ -144,17 +147,21 @@ void HueOutdoorSensor::updateStates(const QVariantMap &sensorMap)
if (m_temperature != temperature) { if (m_temperature != temperature) {
m_temperature = temperature; m_temperature = temperature;
emit temperatureChanged(m_temperature); emit temperatureChanged(m_temperature);
qCDebug(dcPhilipsHue) << "Outdoor sensor temperature changed" << m_temperature; qCDebug(dcPhilipsHue) << "Motion sensor temperature changed" << m_temperature;
} }
} }
// If presence sensor // If presence sensor
if (sensorMap.value("uniqueid").toString() == m_presenceSensorUuid) { if (sensorMap.value("uniqueid").toString() == m_presenceSensorUuid) {
bool presence = stateMap.value("presence", false).toBool(); bool presence = stateMap.value("presence", false).toBool();
if (m_presence != presence) { if (presence) {
m_presence = presence; if (!m_presence) {
emit presenceChanged(m_presence); m_presence = true;
qCDebug(dcPhilipsHue) << "Outdoor sensor presence changed" << presence; emit presenceChanged(m_presence);
qCDebug(dcPhilipsHue) << "Motion sensor presence changed" << presence;
}
qCDebug(dcPhilipsHue) << "Motion sensor restarting timeout" << m_timeout.interval();
m_timeout.start();
} }
} }
@ -169,17 +176,17 @@ void HueOutdoorSensor::updateStates(const QVariantMap &sensorMap)
} }
} }
bool HueOutdoorSensor::isValid() bool HueMotionSensor::isValid()
{ {
return !m_temperatureSensorUuid.isEmpty() && !m_presenceSensorUuid.isEmpty() && !m_lightSensorUuid.isEmpty(); return !m_temperatureSensorUuid.isEmpty() && !m_presenceSensorUuid.isEmpty() && !m_lightSensorUuid.isEmpty();
} }
bool HueOutdoorSensor::hasSensor(int sensorId) bool HueMotionSensor::hasSensor(int sensorId)
{ {
return m_temperatureSensorId == sensorId || m_presenceSensorId == sensorId || m_lightSensorId == sensorId; return m_temperatureSensorId == sensorId || m_presenceSensorId == sensorId || m_lightSensorId == sensorId;
} }
bool HueOutdoorSensor::hasSensor(const QString &sensorUuid) bool HueMotionSensor::hasSensor(const QString &sensorUuid)
{ {
return m_temperatureSensorUuid == sensorUuid || m_presenceSensorUuid == sensorUuid || m_lightSensorUuid == sensorUuid; return m_temperatureSensorUuid == sensorUuid || m_presenceSensorUuid == sensorUuid || m_lightSensorUuid == sensorUuid;
} }

View File

@ -20,21 +20,23 @@
* * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef HUEOUTDOORSENSOR_H #ifndef HUEMOTIONSENSOR_H
#define HUEOUTDOORSENSOR_H #define HUEMOTIONSENSOR_H
#include <QObject> #include <QObject>
#include <QTimer>
#include "extern-plugininfo.h"
#include "huedevice.h" #include "huedevice.h"
class HueOutdoorSensor : public HueDevice class HueMotionSensor : public HueDevice
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit HueOutdoorSensor(QObject *parent = nullptr); explicit HueMotionSensor(QObject *parent = nullptr);
virtual ~HueMotionSensor() = default;
QString uuid() const; void setTimeout(int timeout);
void setUuid(const QString &uuid);
int temperatureSensorId() const; int temperatureSensorId() const;
void setTemperatureSensorId(int sensorId); void setTemperatureSensorId(int sensorId);
@ -65,10 +67,16 @@ public:
bool hasSensor(int sensorId); bool hasSensor(int sensorId);
bool hasSensor(const QString &sensorUuid); bool hasSensor(const QString &sensorUuid);
virtual StateTypeId connectedStateTypeId() const = 0;
virtual StateTypeId temperatureStateTypeId() const = 0;
virtual StateTypeId lightIntensityStateTypeId() const = 0;
virtual StateTypeId isPresentStateTypeId() const = 0;
virtual StateTypeId lastSeenTimeStateTypeId() const = 0;
virtual StateTypeId batteryLevelStateTypeId() const = 0;
virtual StateTypeId batteryCriticalStateTypeId() const = 0;
private: private:
// Params // Params
QString m_uuid;
int m_temperatureSensorId; int m_temperatureSensorId;
QString m_temperatureSensorUuid; QString m_temperatureSensorUuid;
@ -78,6 +86,8 @@ private:
int m_lightSensorId; int m_lightSensorId;
QString m_lightSensorUuid; QString m_lightSensorUuid;
QTimer m_timeout;
// States // States
QString m_lastUpdate; QString m_lastUpdate;
double m_temperature = 0; double m_temperature = 0;
@ -93,4 +103,36 @@ signals:
}; };
#endif // HUEOUTDOORSENSOR_H class HueIndoorSensor: public HueMotionSensor
{
Q_OBJECT
public:
HueIndoorSensor(QObject *parent = nullptr): HueMotionSensor(parent) {}
StateTypeId connectedStateTypeId() const override { return motionSensorConnectedStateTypeId; }
StateTypeId temperatureStateTypeId() const override { return motionSensorTemperatureStateTypeId; }
StateTypeId lightIntensityStateTypeId() const override { return motionSensorLightIntensityStateTypeId; }
StateTypeId isPresentStateTypeId() const override { return motionSensorIsPresentStateTypeId; }
StateTypeId lastSeenTimeStateTypeId() const override { return motionSensorLastSeenTimeStateTypeId; }
StateTypeId batteryLevelStateTypeId() const override { return motionSensorBatteryLevelStateTypeId; }
StateTypeId batteryCriticalStateTypeId() const override { return motionSensorBatteryCriticalStateTypeId; }
};
class HueOutdoorSensor: public HueMotionSensor
{
Q_OBJECT
public:
HueOutdoorSensor(QObject *parent = nullptr): HueMotionSensor(parent) {}
StateTypeId connectedStateTypeId() const override { return outdoorSensorTemperatureStateTypeId; }
StateTypeId temperatureStateTypeId() const override { return outdoorSensorTemperatureStateTypeId; }
StateTypeId lightIntensityStateTypeId() const override { return outdoorSensorLightIntensityStateTypeId; }
StateTypeId isPresentStateTypeId() const override { return outdoorSensorIsPresentStateTypeId; }
StateTypeId lastSeenTimeStateTypeId() const override { return outdoorSensorLastSeenTimeStateTypeId; }
StateTypeId batteryLevelStateTypeId() const override { return outdoorSensorBatteryLevelStateTypeId; }
StateTypeId batteryCriticalStateTypeId() const override { return outdoorSensorBatteryCriticalStateTypeId; }
};
#endif // HUEMOTIONSENSOR_H

View File

@ -10,10 +10,10 @@ SOURCES += \
#light.cpp \ #light.cpp \
huebridge.cpp \ huebridge.cpp \
huelight.cpp \ huelight.cpp \
huemotionsensor.cpp \
pairinginfo.cpp \ pairinginfo.cpp \
hueremote.cpp \ hueremote.cpp \
huedevice.cpp \ huedevice.cpp
hueoutdoorsensor.cpp
HEADERS += \ HEADERS += \
devicepluginphilipshue.h \ devicepluginphilipshue.h \
@ -22,10 +22,10 @@ HEADERS += \
#lightinterface.h \ #lightinterface.h \
huebridge.h \ huebridge.h \
huelight.h \ huelight.h \
huemotionsensor.h \
pairinginfo.h \ pairinginfo.h \
hueremote.h \ hueremote.h \
huedevice.h \ huedevice.h
hueoutdoorsensor.h