Add Hue Outdoor sensor

master
Simon Stürz 2019-03-18 16:22:13 +01:00 committed by Michael Zanetti
parent 61cdae6c79
commit c4c19c6558
8 changed files with 661 additions and 31 deletions

View File

@ -110,7 +110,9 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceC
DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device)
{
// Update the name on the bridge if the user changes the device name
connect(device, &Device::nameChanged, this, &DevicePluginPhilipsHue::onDeviceNameChanged);
// hue bridge
if (device->deviceClassId() == bridgeDeviceClassId) {
// unconfigured bridges (from pairing)
@ -118,7 +120,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
if (b->hostAddress().toString() == device->paramValue(bridgeDeviceHostParamTypeId).toString()) {
m_unconfiguredBridges.removeAll(b);
qCDebug(dcPhilipsHue) << "Setup unconfigured Hue Bridge" << b->name();
// set data which was not known during discovery
// Set data which was not known during discovery
device->setParamValue(bridgeDeviceApiKeyParamTypeId, b->apiKey());
device->setParamValue(bridgeDeviceZigbeeChannelParamTypeId, b->zigbeeChannel());
device->setParamValue(bridgeDeviceMacParamTypeId, b->macAddress());
@ -129,7 +131,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
}
}
// loaded bridge
// Loaded bridge
qCDebug(dcPhilipsHue) << "Setup Hue Bridge" << device->params();
HueBridge *bridge = new HueBridge(this);
@ -144,7 +146,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
return DeviceManager::DeviceSetupStatusSuccess;
}
// hue color light
// Hue color light
if (device->deviceClassId() == colorLightDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue color light" << device->params();
@ -165,7 +167,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
return DeviceManager::DeviceSetupStatusSuccess;
}
// hue color temperature light
// Hue color temperature light
if (device->deviceClassId() == colorTemperatureLightDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue color temperature light" << device->params();
@ -186,7 +188,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
return DeviceManager::DeviceSetupStatusSuccess;
}
// hue white light
// Hue white light
if (device->deviceClassId() == dimmableLightDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue white light" << device->params();
@ -207,7 +209,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
return DeviceManager::DeviceSetupStatusSuccess;
}
// hue remote
// Hue remote
if (device->deviceClassId() == remoteDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue remote" << device->params() << device->deviceClassId();
@ -227,7 +229,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
return DeviceManager::DeviceSetupStatusSuccess;
}
// hue tap
// Hue tap
if (device->deviceClassId() == tapDeviceClassId) {
HueRemote *hueTap = new HueRemote(this);
hueTap->setName(device->name());
@ -241,6 +243,31 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
return DeviceManager::DeviceSetupStatusSuccess;
}
// Hue Outdoor sensor
if (device->deviceClassId() == outdoorSensorDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue Outdoor sensor" << device->params();
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this);
outdoorSensor->setUuid(device->paramValue(outdoorSensorDeviceUuidParamTypeId).toString());
outdoorSensor->setModelId(device->paramValue(outdoorSensorDeviceModelIdParamTypeId).toString());
outdoorSensor->setTemperatureSensorId(device->paramValue(outdoorSensorDeviceSensorIdTemperatureParamTypeId).toInt());
outdoorSensor->setTemperatureSensorUuid(device->paramValue(outdoorSensorDeviceSensorUuidTemperatureParamTypeId).toString());
outdoorSensor->setPresenceSensorId(device->paramValue(outdoorSensorDeviceSensorIdPresenceParamTypeId).toInt());
outdoorSensor->setPresenceSensorUuid(device->paramValue(outdoorSensorDeviceSensorUuidPresenceParamTypeId).toString());
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);
m_outdoorSensors.insert(outdoorSensor, device);
return DeviceManager::DeviceSetupStatusSuccess;
}
qCWarning(dcPhilipsHue()) << "Unhandled setupDevice call" << device->deviceClassId();
return DeviceManager::DeviceSetupStatusFailure;
@ -276,6 +303,12 @@ void DevicePluginPhilipsHue::deviceRemoved(Device *device)
m_remotes.remove(remote);
remote->deleteLater();
}
if (device->deviceClassId() == outdoorSensorDeviceClassId) {
HueOutdoorSensor *outdoorSensor = m_outdoorSensors.key(device);
m_outdoorSensors.remove(outdoorSensor);
outdoorSensor->deleteLater();
}
}
DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params, const QString &secret)
@ -283,7 +316,6 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::confirmPairing(const Pa
Q_UNUSED(secret)
qCDebug(dcPhilipsHue()) << "Confirming pairing for transactionId" << pairingTransactionId;
if (deviceClassId != bridgeDeviceClassId)
return DeviceManager::DeviceSetupStatusFailure;
@ -313,7 +345,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady()
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// qCDebug(dcPhilipsHue()) << "Hue reply:" << status << reply->error() << reply->errorString();
// qCDebug(dcPhilipsHue()) << "Hue reply:" << status << reply->error() << reply->errorString();
// create user finished
if (m_pairingRequests.contains(reply)) {
@ -463,6 +495,7 @@ void DevicePluginPhilipsHue::onDeviceNameChanged()
if (m_lights.values().contains(device)) {
setLightName(device);
}
if (m_remotes.values().contains(device)) {
setRemoteName(device);
}
@ -472,7 +505,7 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
{
qCDebug(dcPhilipsHue) << "Execute action" << action.actionTypeId() << action.params();
// color light
// Color light
if (device->deviceClassId() == colorLightDeviceClassId) {
HueLight *light = m_lights.key(device);
@ -521,7 +554,7 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
return DeviceManager::DeviceErrorActionTypeNotFound;
}
// color temperature light
// Color temperature light
if (device->deviceClassId() == colorTemperatureLightDeviceClassId) {
HueLight *light = m_lights.key(device);
@ -558,7 +591,7 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
return DeviceManager::DeviceErrorActionTypeNotFound;
}
// dimmable light
// Dimmable light
if (device->deviceClassId() == dimmableLightDeviceClassId) {
HueLight *light = m_lights.key(device);
@ -589,6 +622,7 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
return DeviceManager::DeviceErrorActionTypeNotFound;
}
// Hue bridge
if (device->deviceClassId() == bridgeDeviceClassId) {
HueBridge *bridge = m_bridges.key(device);
if (!device->stateValue(bridgeConnectedStateTypeId).toBool()) {
@ -664,7 +698,7 @@ void DevicePluginPhilipsHue::remoteStateChanged()
}
}
void DevicePluginPhilipsHue::onRemoteButtonEvent(const int &buttonCode)
void DevicePluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
{
HueRemote *remote = static_cast<HueRemote *>(sender());
@ -734,6 +768,43 @@ void DevicePluginPhilipsHue::onRemoteButtonEvent(const int &buttonCode)
emitEvent(Event(id, m_remotes.value(remote)->id(), ParamList() << param));
}
void DevicePluginPhilipsHue::onOutdoorSensorReachableChanged(bool reachable)
{
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorConnectedStateTypeId, reachable);
}
void DevicePluginPhilipsHue::onOutdoorSensorBatteryLevelChanged(int batteryLevel)
{
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorBatteryLevelStateTypeId, batteryLevel);
sensorDevice->setStateValue(outdoorSensorBatteryCriticalStateTypeId, (batteryLevel < 5));
}
void DevicePluginPhilipsHue::onOutdoorSensorTemperatureChanged(double temperature)
{
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorTemperatureStateTypeId, temperature);
}
void DevicePluginPhilipsHue::onOutdoorSensorPresenceChanged(bool presence)
{
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorIsPresentStateTypeId, presence);
if (presence) sensorDevice->setStateValue(outdoorSensorLastSeenTimeStateTypeId, QDateTime::currentSecsSinceEpoch());
}
void DevicePluginPhilipsHue::onOutdoorSensorLightIntensityChanged(double lightIntensity)
{
HueOutdoorSensor *sensor = static_cast<HueOutdoorSensor *>(sender());
Device *sensorDevice = m_outdoorSensors.value(sensor);
sensorDevice->setStateValue(outdoorSensorLightIntensityStateTypeId, lightIntensity);
}
void DevicePluginPhilipsHue::onUpnpDiscoveryFinished()
{
qCDebug(dcPhilipsHue()) << "Upnp discovery finished";
@ -800,7 +871,7 @@ void DevicePluginPhilipsHue::refreshLight(Device *device)
void DevicePluginPhilipsHue::refreshBridge(Device *device)
{
HueBridge *bridge = m_bridges.key(device);
// qCDebug(dcPhilipsHue()) << "refreshing bridge";
// qCDebug(dcPhilipsHue()) << "refreshing bridge";
QNetworkRequest request(QUrl("http://" + bridge->hostAddress().toString() + "/api/" + bridge->apiKey() + "/config"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
@ -812,7 +883,7 @@ void DevicePluginPhilipsHue::refreshBridge(Device *device)
void DevicePluginPhilipsHue::refreshLights(HueBridge *bridge)
{
Device *device = m_bridges.value(bridge);
// qCDebug(dcPhilipsHue()) << "refreshing lights";
// qCDebug(dcPhilipsHue()) << "refreshing lights";
QNetworkRequest request(QUrl("http://" + bridge->hostAddress().toString() + "/api/" + bridge->apiKey() + "/lights"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
@ -824,7 +895,7 @@ void DevicePluginPhilipsHue::refreshLights(HueBridge *bridge)
void DevicePluginPhilipsHue::refreshSensors(HueBridge *bridge)
{
Device *device = m_bridges.value(bridge);
// qCDebug(dcPhilipsHue()) << "refreshing sensors";
// qCDebug(dcPhilipsHue()) << "refreshing sensors";
QNetworkRequest request(QUrl("http://" + bridge->hostAddress().toString() + "/api/" + bridge->apiKey() + "/sensors"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
@ -899,7 +970,7 @@ void DevicePluginPhilipsHue::processNUpnpResponse(const QByteArray &data)
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
// Check JSON error
if (error.error != QJsonParseError::NoError) {
qCWarning(dcPhilipsHue) << "N-UPNP discovery JSON error in response" << error.errorString();
return;
@ -929,13 +1000,13 @@ void DevicePluginPhilipsHue::processBridgeLightDiscoveryResponse(Device *device,
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
// Check JSON error
if (error.error != QJsonParseError::NoError) {
qCWarning(dcPhilipsHue) << "Bridge light discovery json error in response" << error.errorString();
return;
}
// check response error
// Check response error
if (data.contains("error")) {
if (!jsonDoc.toVariant().toList().isEmpty()) {
qCWarning(dcPhilipsHue) << "Failed to discover Hue Bridge lights:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
@ -945,7 +1016,7 @@ void DevicePluginPhilipsHue::processBridgeLightDiscoveryResponse(Device *device,
return;
}
// create Lights if not already added
// Create Lights if not already added
QList<DeviceDescriptor> colorLightDescriptors;
QList<DeviceDescriptor> colorTemperatureLightDescriptors;
QList<DeviceDescriptor> dimmableLightDescriptors;
@ -1008,13 +1079,13 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
// Check JSON error
if (error.error != QJsonParseError::NoError) {
qCWarning(dcPhilipsHue) << "Bridge sensor discovery json error in response" << error.errorString();
return;
}
// check response error
// Check response error
if (data.contains("error")) {
if (!jsonDoc.toVariant().toList().isEmpty()) {
qCWarning(dcPhilipsHue) << "Failed to discover Hue Bridge sensors:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
@ -1024,11 +1095,12 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
return;
}
// create sensors if not already added
// Create sensors if not already added
QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
foreach (QString sensorId, sensorsMap.keys()) {
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
QHash<QString, HueOutdoorSensor *> outdoorSensors;
foreach (const QString &sensorId, sensorsMap.keys()) {
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
QString uuid = sensorMap.value("uniqueid").toString();
QString model = sensorMap.value("modelid").toString();
@ -1054,10 +1126,91 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
descriptor.setParams(params);
emit autoDevicesAppeared(tapDeviceClassId, {descriptor});
qCDebug(dcPhilipsHue()) << "Found hue tap:" << sensorMap << tapDeviceClassId;
} else if (model == "SML002") {
// Get the base uuid from this sensor
QString baseUuid = HueDevice::getBaseUuid(uuid);
// Temperature sensor
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());
} 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);
}
}
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());
} else {
// Create an outdoor sensor
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this);
outdoorSensor->setUuid(baseUuid);
outdoorSensor->setPresenceSensorUuid(uuid);
outdoorSensor->setPresenceSensorId(sensorId.toInt());
outdoorSensors.insert(baseUuid, outdoorSensor);
}
}
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());
} else {
// Create an outdoor sensor
HueOutdoorSensor *outdoorSensor = new HueOutdoorSensor(this);
outdoorSensor->setUuid(baseUuid);
outdoorSensor->setLightSensorUuid(uuid);
outdoorSensor->setLightSensorId(sensorId.toInt());
outdoorSensors.insert(baseUuid, outdoorSensor);
}
}
} else {
qCDebug(dcPhilipsHue()) << "Found unknown sensor:" << model;
}
}
// 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});
}
// Clean up
outdoorSensors.remove(baseUuid);
outdoorSensor->deleteLater();
}
}
void DevicePluginPhilipsHue::processLightRefreshResponse(Device *device, const QByteArray &data)
@ -1102,6 +1255,8 @@ void DevicePluginPhilipsHue::processBridgeRefreshResponse(Device *device, const
return;
}
//qCDebug(dcPhilipsHue()) << "Bridge refresh response" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
QVariantMap configMap = jsonDoc.toVariant().toMap();
// mark bridge as reachable
@ -1183,11 +1338,20 @@ void DevicePluginPhilipsHue::processSensorsRefreshResponse(Device *device, const
QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
foreach (const QString &sensorId, sensorsMap.keys()) {
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
// Remotes
foreach (HueRemote *remote, m_remotes.keys()) {
if (remote->id() == sensorId.toInt() && m_remotes.value(remote)->parentId() == device->id()) {
remote->updateStates(sensorMap.value("state").toMap(), sensorMap.value("config").toMap());
}
}
// Outdoor sensors
foreach (HueOutdoorSensor *outdoorSensor, m_outdoorSensors.keys()) {
if (outdoorSensor->hasSensor(sensorId.toInt()) && m_outdoorSensors.value(outdoorSensor)->parentId() == device->id()) {
outdoorSensor->updateStates(sensorMap);
}
}
}
}
@ -1214,8 +1378,6 @@ void DevicePluginPhilipsHue::processSetNameResponse(Device *device, const QByteA
return;
}
//emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
if (device->deviceClassId() == colorLightDeviceClassId || device->deviceClassId() == dimmableLightDeviceClassId)
refreshLight(device);
@ -1366,9 +1528,17 @@ 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);
}
}
}
}
}
}
Device* DevicePluginPhilipsHue::bridgeForBridgeId(const QString &id)
@ -1408,17 +1578,32 @@ bool DevicePluginPhilipsHue::lightAlreadyAdded(const QString &uuid)
bool DevicePluginPhilipsHue::sensorAlreadyAdded(const QString &uuid)
{
foreach (Device *device, myDevices()) {
// Hue remote
if (device->deviceClassId() == remoteDeviceClassId) {
if (device->paramValue(remoteDeviceUuidParamTypeId).toString() == uuid) {
return true;
}
}
// Hue tap
if (device->deviceClassId() == tapDeviceClassId) {
if (device->paramValue(tapDeviceUuidParamTypeId).toString() == uuid) {
return true;
}
}
// Outdoor sensor consits out of 3 sensors
if (device->deviceClassId() == outdoorSensorDeviceClassId) {
if (device->paramValue(outdoorSensorDeviceSensorUuidLightParamTypeId).toString() == uuid) {
return true;
} else if (device->paramValue(outdoorSensorDeviceSensorUuidPresenceParamTypeId).toString() == uuid) {
return true;
} else if (device->paramValue(outdoorSensorDeviceSensorUuidTemperatureParamTypeId).toString() == uuid) {
return true;
}
}
}
return false;
}

View File

@ -30,6 +30,7 @@
#include "hueremote.h"
#include "pairinginfo.h"
#include "plugintimer.h"
#include "hueoutdoorsensor.h"
#include "network/networkaccessmanager.h"
#include "network/upnp/upnpdiscovery.h"
@ -58,7 +59,14 @@ public slots:
private slots:
void lightStateChanged();
void remoteStateChanged();
void onRemoteButtonEvent(const int &buttonCode);
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);
private slots:
void onUpnpDiscoveryFinished();
@ -91,6 +99,7 @@ private:
QHash<HueBridge *, Device *> m_bridges;
QHash<HueLight *, Device *> m_lights;
QHash<HueRemote *, Device *> m_remotes;
QHash<HueOutdoorSensor *, Device *> m_outdoorSensors;
void refreshLight(Device *device);
void refreshBridge(Device *device);

View File

@ -702,6 +702,137 @@
]
}
]
},
{
"id": "32dc6390-600f-4eb4-b349-cc2d6796a82a",
"name": "outdoorSensor",
"displayName": "Hue Outdoor Sensor",
"deviceIcon": "MotionDetectors",
"interfaces": ["presencesensor", "temperaturesensor", "lightsensor", "batterylevel", "connectable"],
"basicTags": [ "Device", "Sensor" ],
"createMethods": ["auto"],
"paramTypes": [
{
"id": "3ca8632d-7bd1-45a9-86af-c856e006c334",
"name": "modelId",
"displayName": "Model id",
"type" : "QString",
"readOnly": true
},
{
"id": "4a15f861-cad6-464a-b250-08793c68ae30",
"name": "uuid",
"displayName": "Uuid",
"type" : "QString",
"readOnly": true
},
{
"id": "c732fefd-ca6b-4e27-a6d2-11595c4aab3e",
"name": "sensorIdTemperature",
"displayName": "Temperature sensor id",
"type" : "int",
"readOnly": true
},
{
"id": "2fdb34e8-25ca-4c5d-85c9-9a12bd48dbed",
"name": "sensorUuidTemperature",
"displayName": "Temperature sensor uuid",
"type" : "QString",
"readOnly": true
},
{
"id": "3ca82a24-5eca-4285-83c2-f862d387c3bc",
"name": "sensorIdPresence",
"displayName": "Presence sensor id",
"type" : "int",
"readOnly": true
},
{
"id": "7d55ed97-3a32-41e9-9112-8cc5b44aab23",
"name": "sensorUuidPresence",
"displayName": "Presence sensor uuid",
"type" : "QString",
"readOnly": true
},
{
"id": "22a164fc-fa6e-427a-9a60-7a1872901fd6",
"name": "sensorIdLight",
"displayName": "Light sensor id",
"type" : "int",
"readOnly": true
},
{
"id": "db678144-de2b-4767-a2f6-9ada8377b96c",
"name": "sensorUuidLight",
"displayName": "Light sensor uuid",
"type" : "QString",
"readOnly": true
}
],
"stateTypes": [
{
"id": "9fe43e6b-3c29-43a9-bb96-3b80eacc10db",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachable changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "19b18531-61e5-4998-89d1-765d740e24eb",
"name": "batteryLevel",
"displayName": "battery",
"displayNameEvent": "Battery changed",
"type": "int",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100
},
{
"id": "617aa352-789c-46e7-bf55-7455b1e5018e",
"name": "batteryCritical",
"displayName": "battery critical",
"displayNameEvent": "Battery critical changed",
"type": "bool",
"defaultValue": false
},
{
"id": "88f5b708-65bb-41a7-885f-01be46074713",
"name": "temperature",
"displayName": "Temperature",
"displayNameEvent": "Temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0
},
{
"id": "4fb12c06-981c-4c42-b55c-46bdfe68681a",
"name": "lightIntensity",
"displayName": "Ambient light",
"displayNameEvent": "Ambient light changed",
"unit": "Lux",
"type": "double",
"defaultValue": 0
},
{
"id": "680f79cf-c17c-4ffd-96fa-a5b286e2c117",
"name": "isPresent",
"displayName": "Is present",
"displayNameEvent": "Is present changed",
"type": "bool",
"defaultValue": false
},
{
"id": "6fa16fb2-053c-4c3c-a39b-9548c1b15089",
"name": "lastSeenTime",
"displayName": "Last seen time",
"displayNameEvent": "Last seen time changed",
"type": "int",
"unit": "UnixTime",
"defaultValue": 0
}
]
}
]
}

View File

@ -115,6 +115,22 @@ bool HueDevice::reachable() const
void HueDevice::setReachable(const bool &reachable)
{
if (m_reachable == reachable)
return;
m_reachable = reachable;
emit reachableChanged(m_reachable);
}
QString HueDevice::getBaseUuid(const QString &uuid)
{
// Example: the hue gives uuid's starting with a mac address, followd by an id
// "00:17:88:01:06:44:36:86-02-0406" -> "00:17:88:01:06:44:36:86"
int dashIndex = uuid.indexOf("-");
if (dashIndex < 0) {
return uuid;
}
return uuid.left(dashIndex);
}

View File

@ -62,6 +62,8 @@ public:
bool reachable() const;
void setReachable(const bool &reachable);
static QString getBaseUuid(const QString &uuid);
private:
int m_id;
QString m_name;
@ -73,6 +75,10 @@ private:
QString m_softwareVersion;
bool m_reachable;
signals:
void reachableChanged(bool reachable);
};
#endif // HUEDEVICE_H

View File

@ -0,0 +1,185 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Simon Stürz <simon.stuerz@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "hueoutdoorsensor.h"
#include "extern-plugininfo.h"
HueOutdoorSensor::HueOutdoorSensor(QObject *parent) :
HueDevice(parent)
{
}
QString HueOutdoorSensor::uuid() const
{
return m_uuid;
}
void HueOutdoorSensor::setUuid(const QString &uuid)
{
m_uuid = uuid;
}
int HueOutdoorSensor::temperatureSensorId() const
{
return m_temperatureSensorId;
}
void HueOutdoorSensor::setTemperatureSensorId(int sensorId)
{
m_temperatureSensorId = sensorId;
}
QString HueOutdoorSensor::temperatureSensorUuid() const
{
return m_temperatureSensorUuid;
}
void HueOutdoorSensor::setTemperatureSensorUuid(const QString &temperatureSensorUuid)
{
m_temperatureSensorUuid = temperatureSensorUuid;
}
int HueOutdoorSensor::presenceSensorId() const
{
return m_presenceSensorId;
}
void HueOutdoorSensor::setPresenceSensorId(int sensorId)
{
m_presenceSensorId = sensorId;
}
QString HueOutdoorSensor::presenceSensorUuid() const
{
return m_presenceSensorUuid;
}
void HueOutdoorSensor::setPresenceSensorUuid(const QString &presenceSensorUuid)
{
m_presenceSensorUuid = presenceSensorUuid;
}
int HueOutdoorSensor::lightSensorId() const
{
return m_lightSensorId;
}
void HueOutdoorSensor::setLightSensorId(int sensorId)
{
m_lightSensorId = sensorId;
}
QString HueOutdoorSensor::lightSensorUuid() const
{
return m_lightSensorUuid;
}
void HueOutdoorSensor::setLightSensorUuid(const QString &lightSensorUuid)
{
m_lightSensorUuid = lightSensorUuid;
}
double HueOutdoorSensor::temperature() const
{
return m_temperature;
}
double HueOutdoorSensor::lightIntensity() const
{
return m_lightIntensity;
}
bool HueOutdoorSensor::present() const
{
return m_presence;
}
int HueOutdoorSensor::batteryLevel() const
{
return m_batteryLevel;
}
void HueOutdoorSensor::updateStates(const QVariantMap &sensorMap)
{
//qCDebug(dcPhilipsHue()) << "Outdoor sensor: Process sensor map" << qUtf8Printable(QJsonDocument::fromVariant(sensorMap).toJson(QJsonDocument::Indented));
// Config
QVariantMap configMap = sensorMap.value("config").toMap();
if (configMap.contains("reachable")) {
setReachable(configMap.value("reachable", false).toBool());
}
if (configMap.contains("battery")) {
int batteryLevel = configMap.value("battery", 0).toInt();
if (m_batteryLevel != batteryLevel) {
m_batteryLevel = batteryLevel;
emit batteryLevelChanged(m_batteryLevel);
}
}
// If temperature sensor
QVariantMap stateMap = sensorMap.value("state").toMap();
if (sensorMap.value("uniqueid").toString() == m_temperatureSensorUuid) {
double temperature = stateMap.value("temperature", 0).toInt() / 100.0;
if (m_temperature != temperature) {
m_temperature = temperature;
emit temperatureChanged(m_temperature);
qCDebug(dcPhilipsHue) << "Outdoor 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 light sensor
if (sensorMap.value("uniqueid").toString() == m_lightSensorUuid) {
int lightIntensity = stateMap.value("lightlevel", 0).toInt();
if (m_lightIntensity != lightIntensity) {
m_lightIntensity = lightIntensity;
emit lightIntensityChanged(m_lightIntensity);
qCDebug(dcPhilipsHue) << "Outdoor sensor light intensity changed" << m_lightIntensity;
}
}
}
bool HueOutdoorSensor::isValid()
{
return !m_temperatureSensorUuid.isEmpty() && !m_presenceSensorUuid.isEmpty() && !m_lightSensorUuid.isEmpty();
}
bool HueOutdoorSensor::hasSensor(int sensorId)
{
return m_temperatureSensorId == sensorId || m_presenceSensorId == sensorId || m_lightSensorId == sensorId;
}
bool HueOutdoorSensor::hasSensor(const QString &sensorUuid)
{
return m_temperatureSensorUuid == sensorUuid || m_presenceSensorUuid == sensorUuid || m_lightSensorUuid == sensorUuid;
}

View File

@ -0,0 +1,96 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Simon Stürz <simon.stuerz@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef HUEOUTDOORSENSOR_H
#define HUEOUTDOORSENSOR_H
#include <QObject>
#include "huedevice.h"
class HueOutdoorSensor : public HueDevice
{
Q_OBJECT
public:
explicit HueOutdoorSensor(QObject *parent = nullptr);
QString uuid() const;
void setUuid(const QString &uuid);
int temperatureSensorId() const;
void setTemperatureSensorId(int sensorId);
QString temperatureSensorUuid() const;
void setTemperatureSensorUuid(const QString &temperatureSensorUuid);
int presenceSensorId() const;
void setPresenceSensorId(int sensorId);
QString presenceSensorUuid() const;
void setPresenceSensorUuid(const QString &presenceSensorUuid);
int lightSensorId() const;
void setLightSensorId(int sensorId);
QString lightSensorUuid() const;
void setLightSensorUuid(const QString &lightSensorUuid);
double temperature() const;
double lightIntensity() const;
bool present() const;
int batteryLevel() const;
void updateStates(const QVariantMap &sensorMap);
bool isValid();
bool hasSensor(int sensorId);
bool hasSensor(const QString &sensorUuid);
private:
// Params
QString m_uuid;
int m_temperatureSensorId;
QString m_temperatureSensorUuid;
int m_presenceSensorId;
QString m_presenceSensorUuid;
int m_lightSensorId;
QString m_lightSensorUuid;
// States
QString m_lastUpdate;
double m_temperature = 0;
double m_lightIntensity = 0;
bool m_presence = false;
int m_batteryLevel = 0;
signals:
void temperatureChanged(double temperature);
void lightIntensityChanged(double lightIntensity);
void presenceChanged(bool presence);
void batteryLevelChanged(int batteryLevel);
};
#endif // HUEOUTDOORSENSOR_H

View File

@ -12,7 +12,8 @@ SOURCES += \
huelight.cpp \
pairinginfo.cpp \
hueremote.cpp \
huedevice.cpp
huedevice.cpp \
hueoutdoorsensor.cpp
HEADERS += \
devicepluginphilipshue.h \
@ -23,7 +24,8 @@ HEADERS += \
huelight.h \
pairinginfo.h \
hueremote.h \
huedevice.h
huedevice.h \
hueoutdoorsensor.h