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

View File

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

View File

@ -671,6 +671,18 @@
"readOnly": true
}
],
"settingsTypes": [
{
"id": "21d461b2-b4dd-4a70-b3d5-aaedc88605a4",
"name": "timeout",
"displayName": "Time period",
"type": "uint",
"unit": "Seconds",
"defaultValue": 10,
"minValue": 10
}
],
"stateTypes": [
{
"id": "9fe43e6b-3c29-43a9-bb96-3b80eacc10db",
@ -735,6 +747,147 @@
"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
public:
explicit HueDevice(QObject *parent = 0);
explicit HueDevice(QObject *parent = nullptr);
int id() const;
void setId(const int &id);

View File

@ -20,106 +20,109 @@
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "hueoutdoorsensor.h"
#include "huemotionsensor.h"
#include "extern-plugininfo.h"
HueOutdoorSensor::HueOutdoorSensor(QObject *parent) :
HueMotionSensor::HueMotionSensor(QObject *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)
{
m_uuid = uuid;
}
int HueOutdoorSensor::temperatureSensorId() const
int HueMotionSensor::temperatureSensorId() const
{
return m_temperatureSensorId;
}
void HueOutdoorSensor::setTemperatureSensorId(int sensorId)
void HueMotionSensor::setTemperatureSensorId(int sensorId)
{
m_temperatureSensorId = sensorId;
}
QString HueOutdoorSensor::temperatureSensorUuid() const
QString HueMotionSensor::temperatureSensorUuid() const
{
return m_temperatureSensorUuid;
}
void HueOutdoorSensor::setTemperatureSensorUuid(const QString &temperatureSensorUuid)
void HueMotionSensor::setTemperatureSensorUuid(const QString &temperatureSensorUuid)
{
m_temperatureSensorUuid = temperatureSensorUuid;
}
int HueOutdoorSensor::presenceSensorId() const
int HueMotionSensor::presenceSensorId() const
{
return m_presenceSensorId;
}
void HueOutdoorSensor::setPresenceSensorId(int sensorId)
void HueMotionSensor::setPresenceSensorId(int sensorId)
{
m_presenceSensorId = sensorId;
}
QString HueOutdoorSensor::presenceSensorUuid() const
QString HueMotionSensor::presenceSensorUuid() const
{
return m_presenceSensorUuid;
}
void HueOutdoorSensor::setPresenceSensorUuid(const QString &presenceSensorUuid)
void HueMotionSensor::setPresenceSensorUuid(const QString &presenceSensorUuid)
{
m_presenceSensorUuid = presenceSensorUuid;
}
int HueOutdoorSensor::lightSensorId() const
int HueMotionSensor::lightSensorId() const
{
return m_lightSensorId;
}
void HueOutdoorSensor::setLightSensorId(int sensorId)
void HueMotionSensor::setLightSensorId(int sensorId)
{
m_lightSensorId = sensorId;
}
QString HueOutdoorSensor::lightSensorUuid() const
QString HueMotionSensor::lightSensorUuid() const
{
return m_lightSensorUuid;
}
void HueOutdoorSensor::setLightSensorUuid(const QString &lightSensorUuid)
void HueMotionSensor::setLightSensorUuid(const QString &lightSensorUuid)
{
m_lightSensorUuid = lightSensorUuid;
}
double HueOutdoorSensor::temperature() const
double HueMotionSensor::temperature() const
{
return m_temperature;
}
double HueOutdoorSensor::lightIntensity() const
double HueMotionSensor::lightIntensity() const
{
return m_lightIntensity;
}
bool HueOutdoorSensor::present() const
bool HueMotionSensor::present() const
{
return m_presence;
}
int HueOutdoorSensor::batteryLevel() const
int HueMotionSensor::batteryLevel() const
{
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));
@ -144,17 +147,21 @@ void HueOutdoorSensor::updateStates(const QVariantMap &sensorMap)
if (m_temperature != temperature) {
m_temperature = 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 (sensorMap.value("uniqueid").toString() == m_presenceSensorUuid) {
bool presence = stateMap.value("presence", false).toBool();
if (m_presence != presence) {
m_presence = presence;
emit presenceChanged(m_presence);
qCDebug(dcPhilipsHue) << "Outdoor sensor presence changed" << presence;
if (presence) {
if (!m_presence) {
m_presence = true;
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();
}
bool HueOutdoorSensor::hasSensor(int sensorId)
bool HueMotionSensor::hasSensor(int 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;
}

View File

@ -20,21 +20,23 @@
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef HUEOUTDOORSENSOR_H
#define HUEOUTDOORSENSOR_H
#ifndef HUEMOTIONSENSOR_H
#define HUEMOTIONSENSOR_H
#include <QObject>
#include <QTimer>
#include "extern-plugininfo.h"
#include "huedevice.h"
class HueOutdoorSensor : public HueDevice
class HueMotionSensor : public HueDevice
{
Q_OBJECT
public:
explicit HueOutdoorSensor(QObject *parent = nullptr);
explicit HueMotionSensor(QObject *parent = nullptr);
virtual ~HueMotionSensor() = default;
QString uuid() const;
void setUuid(const QString &uuid);
void setTimeout(int timeout);
int temperatureSensorId() const;
void setTemperatureSensorId(int sensorId);
@ -65,10 +67,16 @@ public:
bool hasSensor(int sensorId);
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:
// Params
QString m_uuid;
int m_temperatureSensorId;
QString m_temperatureSensorUuid;
@ -78,6 +86,8 @@ private:
int m_lightSensorId;
QString m_lightSensorUuid;
QTimer m_timeout;
// States
QString m_lastUpdate;
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 \
huebridge.cpp \
huelight.cpp \
huemotionsensor.cpp \
pairinginfo.cpp \
hueremote.cpp \
huedevice.cpp \
hueoutdoorsensor.cpp
huedevice.cpp
HEADERS += \
devicepluginphilipshue.h \
@ -22,10 +22,10 @@ HEADERS += \
#lightinterface.h \
huebridge.h \
huelight.h \
huemotionsensor.h \
pairinginfo.h \
hueremote.h \
huedevice.h \
hueoutdoorsensor.h
huedevice.h