update hue plugin

This commit is contained in:
Simon Stürz 2015-06-17 10:55:22 +02:00 committed by Michael Zanetti
parent 5ac6509a6a
commit 05306f5c90
16 changed files with 1195 additions and 873 deletions

View File

@ -2,7 +2,7 @@
GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"')
# define JSON protocol version
JSON_PROTOCOL_VERSION=25
JSON_PROTOCOL_VERSION=26
DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" JSON_PROTOCOL_VERSION=\\\"$${JSON_PROTOCOL_VERSION}\\\"
@ -25,4 +25,3 @@ enable433gpio {
top_srcdir=$$PWD
top_builddir=$$shadowed($$PWD)

View File

@ -624,11 +624,22 @@ DeviceManager::DeviceError DeviceManager::removeConfiguredDevice(const DeviceId
m_configuredDevices.removeAll(device);
m_devicePlugins.value(device->pluginId())->deviceRemoved(device);
m_pluginTimerUsers.removeAll(device);
if (m_pluginTimerUsers.isEmpty()) {
m_pluginTimer.stop();
// check if this plugin still needs the guhTimer call
bool pluginNeedsTimer = false;
foreach (Device* d, m_configuredDevices) {
if (d->pluginId() == device->pluginId()) {
pluginNeedsTimer = true;
break;
}
}
// if this plugin doesn't need any longer the guhTimer call
if (!pluginNeedsTimer) {
m_pluginTimerUsers.removeAll(plugin(device->pluginId()));
if (m_pluginTimerUsers.isEmpty()) {
m_pluginTimer.stop();
}
}
device->deleteLater();
QSettings settings(m_settingsFile);
@ -929,7 +940,9 @@ void DeviceManager::slotDeviceSetupFinished(Device *device, DeviceManager::Devic
// Additionally fire off one event to initialize stuff
QTimer::singleShot(0, this, SLOT(timerEvent()));
}
m_pluginTimerUsers.append(device);
if (!m_pluginTimerUsers.contains(plugin)) {
m_pluginTimerUsers.append(plugin);
}
}
// if this is a async device edit result
@ -1123,10 +1136,8 @@ void DeviceManager::upnpNotifyReceived(const QByteArray &notifyData)
void DeviceManager::timerEvent()
{
foreach (Device *device, m_configuredDevices) {
DeviceClass deviceClass = m_supportedDevices.value(device->deviceClassId());
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (plugin && plugin->requiredHardware().testFlag(HardwareResourceTimer)) {
foreach (DevicePlugin *plugin, m_pluginTimerUsers) {
if (plugin->requiredHardware().testFlag(HardwareResourceTimer)) {
plugin->guhTimer();
}
}
@ -1175,7 +1186,9 @@ DeviceManager::DeviceSetupStatus DeviceManager::setupDevice(Device *device)
// Additionally fire off one event to initialize stuff
QTimer::singleShot(0, this, SLOT(timerEvent()));
}
m_pluginTimerUsers.append(device);
if (!m_pluginTimerUsers.contains(plugin)) {
m_pluginTimerUsers.append(plugin);
}
}
connect(device, SIGNAL(stateValueChanged(QUuid,QVariant)), this, SLOT(slotDeviceStateValueChanged(QUuid,QVariant)));

View File

@ -158,7 +158,7 @@ private:
QHash<VendorId, Vendor> m_supportedVendors;
QHash<VendorId, QList<DeviceClassId> > m_vendorDeviceMap;
QHash<DeviceClassId, DeviceClass> m_supportedDevices;
QList<Device*> m_configuredDevices;
QList<Device *> m_configuredDevices;
QHash<DeviceDescriptorId, DeviceDescriptor> m_discoveredDevices;
QHash<PluginId, DevicePlugin*> m_devicePlugins;
@ -168,15 +168,15 @@ private:
// Hardware Resources
Radio433* m_radio433;
QTimer m_pluginTimer;
QList<Device*> m_pluginTimerUsers;
QList<DevicePlugin *> m_pluginTimerUsers;
NetworkManager *m_networkManager;
QHash<QUuid, QPair<DeviceClassId, ParamList> > m_pairingsJustAdd;
QHash<QUuid, QPair<DeviceClassId, DeviceDescriptorId> > m_pairingsDiscovery;
QList<Device*> m_asyncDeviceEdit;
QList<Device *> m_asyncDeviceEdit;
QList<DevicePlugin*> m_discoveringPlugins;
QList<DevicePlugin *> m_discoveringPlugins;
friend class DevicePlugin;
};

View File

@ -247,7 +247,13 @@ QList<DeviceClass> DevicePlugin::supportedDevices() const
actionType.setName("set " + st.value("name").toString());
// Note: fields already checked in StateType
ParamType paramType(st.value("name").toString(), t, st.value("defaultValue").toVariant());
// states don't have allowed values
if (st.contains("allowedValues")) {
QVariantList allowedValues;
foreach (const QJsonValue &allowedTypesJson, st.value("allowedValues").toArray()) {
allowedValues.append(allowedTypesJson.toVariant());
}
paramType.setAllowedValues(allowedValues);
}
// states don't have input types
paramType.setUnit(unitStringToUnit(st.value("unit").toString()));
paramType.setLimits(st.value("minValue").toVariant(), st.value("maxValue").toVariant());
@ -667,6 +673,8 @@ Types::Unit DevicePlugin::unitStringToUnit(const QString &unitString) const
return Types::UnitDegreeCelsius;
} else if (unitString == "DegreeKelvin") {
return Types::UnitDegreeKelvin;
} else if (unitString == "Mired") {
return Types::UnitMired;
} else if (unitString == "MilliBar") {
return Types::UnitMilliBar;
} else if (unitString == "Bar") {

View File

@ -89,6 +89,7 @@ public:
UnitRadiant,
UnitDegreeCelsius,
UnitDegreeKelvin,
UnitMired,
UnitMilliBar,
UnitBar,
UnitPascal,

View File

@ -47,15 +47,15 @@
#include "devicepluginphilipshue.h"
#include "plugin/device.h"
#include "devicemanager.h"
#include "plugin/device.h"
#include "types/param.h"
#include "huebridgeconnection.h"
#include "plugininfo.h"
#include <QDebug>
#include <QStringList>
#include <QColor>
#include <QJsonDocument>
VendorId hueVendorId = VendorId("");
@ -74,26 +74,11 @@ StateTypeId hueReachableStateTypeId = StateTypeId("15794d26-fde8-4a61-8f83-d7830
DevicePluginPhilipsHue::DevicePluginPhilipsHue()
{
m_bridge = new HueBridgeConnection(this);
connect(m_bridge, &HueBridgeConnection::createUserFinished, this, &DevicePluginPhilipsHue::createUserFinished);
connect(m_bridge, &HueBridgeConnection::getFinished, this, &DevicePluginPhilipsHue::getFinished);
}
DeviceManager::HardwareResources DevicePluginPhilipsHue::requiredHardware() const
{
return DeviceManager::HardwareResourceTimer | DeviceManager::HardwareResourceUpnpDisovery;
}
void DevicePluginPhilipsHue::startMonitoringAutoDevices()
{
// TODO: We could call the bridge to discover new light bulbs here maybe?
// Although we maybe want to think of a user triggered approach to do such things.
}
QList<ParamType> DevicePluginPhilipsHue::configurationDescription() const
{
QList<ParamType> params;
return params;
return DeviceManager::HardwareResourceTimer | DeviceManager::HardwareResourceUpnpDisovery | DeviceManager::HardwareResourceNetworkManager;
}
DeviceManager::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params)
@ -106,208 +91,462 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceC
DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device)
{
Light *light = nullptr;
// hue bridge
if (device->deviceClassId() == hueBridgeDeviceClassId) {
// unconfigured bridges (from pairing)
foreach (HueBridge *b, m_unconfiguredBridges) {
if (b->username() == device->paramValue("username").toString()) {
m_unconfiguredBridges.removeOne(b);
// Lets see if this a a newly added device... In which case its hue id number is not set, well, -1...
if (device->paramValue("number").toInt() == -1) {
if (m_unconfiguredLights.count() > 0) {
light = m_unconfiguredLights.takeFirst();
device->setParamValue("number", light->id());
device->setParamValue("name", QString("Hue light %1").arg(light->id()));
} else {
// this shouldn't ever happen
qWarning() << "Device not configured yet and no discovered devices around. This should not happen.";
return DeviceManager::DeviceSetupStatusFailure;
// set data which was not known during discovery
device->setParamValue("name", b->name());
device->setParamValue("zigbee channel", b->zigbeeChannel());
device->setParamValue("api version", b->apiVersion());
device->setParamValue("mac address", b->macAddress());
device->setStateValue(bridgeReachableStateTypeId, true);
m_bridges.insert(b, device);
// now add the child lights from this bridge as auto device
QList<DeviceDescriptor> descriptors;
foreach (HueLight *light, b->lights()) {
DeviceDescriptor descriptor(hueLightDeviceClassId, "Philips Hue Light", light->name());
ParamList params;
params.append(Param("name", light->name()));
params.append(Param("username", light->username()));
params.append(Param("bridge", device->id().toString()));
params.append(Param("host address", light->hostAddress().toString()));
params.append(Param("model id", light->modelId()));
params.append(Param("light id", light->lightId()));
descriptor.setParams(params);
descriptors.append(descriptor);
}
emit autoDevicesAppeared(hueLightDeviceClassId, descriptors);
return DeviceManager::DeviceSetupStatusSuccess;
}
}
} else {
// In this case it most likely comes from the config. Just read all values from there...
light = new Light(QHostAddress(device->paramValue("ip").toString()), device->paramValue("username").toString(), device->paramValue("number").toInt());
// loaded bridge
HueBridge *bridge = new HueBridge(device->paramValue("username").toString(),
QHostAddress(device->paramValue("host address").toString()));
bridge->setApiVersion(device->paramValue("api version").toString());
bridge->setMacAddress(device->paramValue("mac address").toString());
bridge->setName(device->paramValue("name").toString());
bridge->setZigbeeChannel(device->paramValue("zigbee channel").toInt());
m_bridges.insert(bridge, device);
return DeviceManager::DeviceSetupStatusSuccess;
}
connect(light, &Light::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged);
light->refresh();
// hue lights
if (device->deviceClassId() == hueLightDeviceClassId) {
m_lights.insert(light, device);
m_asyncSetups.insert(light, device);
HueLight *hueLight = 0;
// If we have more unconfigured lights around, lets add them as auto devices
QList<DeviceDescriptor> descriptorList;
while (!m_unconfiguredLights.isEmpty()) {
Light *light = m_unconfiguredLights.takeFirst();
DeviceDescriptor descriptor(hueDeviceClassId, light->name());
ParamList params;
params.append(Param("name", light->name()));
params.append(Param("number", light->id()));
params.append(Param("ip", light->ip().toString()));
params.append(Param("username", light->username()));
descriptor.setParams(params);
descriptorList.append(descriptor);
}
if (!descriptorList.isEmpty()) {
metaObject()->invokeMethod(this, "autoDevicesAppeared", Qt::QueuedConnection, Q_ARG(DeviceClassId, hueDeviceClassId), Q_ARG(QList<DeviceDescriptor>, descriptorList));
// check if this is a unconfigured light
for (int i = 0; i < m_unconfiguredLights.count(); i++) {
if (m_unconfiguredLights.at(i)->username() == device->paramValue("username").toString()) {
hueLight = m_unconfiguredLights.takeAt(i);
break;
}
}
// check if this is a light from settings
if (hueLight == 0) {
hueLight = new HueLight(device->paramValue("light id").toInt(),
QHostAddress(device->paramValue("host address").toString()),
device->paramValue("name").toString(),
device->paramValue("username").toString(),
device->paramValue("model id").toString(),
DeviceId(device->paramValue("bridge").toString()),
this);
connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged);
}
device->setName(hueLight->name());
m_lights.insert(hueLight, device);
refreshLight(device);
}
return DeviceManager::DeviceSetupStatusAsync;
return DeviceManager::DeviceSetupStatusSuccess;
}
void DevicePluginPhilipsHue::deviceRemoved(Device *device)
{
if (!m_lights.values().contains(device)) {
return;
}
Light *light = m_lights.key(device);
m_lights.remove(light);
light->deleteLater();
Q_UNUSED(device)
}
void DevicePluginPhilipsHue::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList)
{
foreach (const UpnpDeviceDescriptor &descriptor, upnpDeviceDescriptorList) {
qDebug() << descriptor;
}
QList<DeviceDescriptor> deviceDescriptors;
foreach (const UpnpDeviceDescriptor &upnpDevice, upnpDeviceDescriptorList) {
if (upnpDevice.modelDescription().contains("Philips")) {
DeviceDescriptor descriptor(hueDeviceClassId, "Philips hue bridge", upnpDevice.hostAddress().toString());
DeviceDescriptor descriptor(hueBridgeDeviceClassId, "Philips Hue Bridge", upnpDevice.hostAddress().toString());
ParamList params;
params.append(Param("ip", upnpDevice.hostAddress().toString()));
params.append(Param("name", QString()));
params.append(Param("host address", upnpDevice.hostAddress().toString()));
params.append(Param("username", "guh-" + QUuid::createUuid().toString().remove(QRegExp("[\\{\\}]*")).remove(QRegExp("\\-[0-9a-f\\-]*"))));
params.append(Param("number", -1));
params.append(Param("mac address", QString()));
params.append(Param("api version", QString()));
params.append(Param("zigbee channel", -1));
descriptor.setParams(params);
deviceDescriptors.append(descriptor);
}
}
emit devicesDiscovered(hueDeviceClassId, deviceDescriptors);
emit devicesDiscovered(hueBridgeDeviceClassId, deviceDescriptors);
}
DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params)
{
Q_UNUSED(deviceClassId)
Param ipParam;
foreach (const Param &param, params) {
if (param.name() == "ip") {
ipParam = param;
}
}
if (!ipParam.isValid()) {
qWarning() << "Missing parameter: ip";
return DeviceManager::DeviceSetupStatusFailure;
}
Param usernameParam;
foreach (const Param &param, params) {
if (param.name() == "username") {
usernameParam = param;
}
}
if (!usernameParam.isValid()) {
qWarning() << "Missing parameter: username";
if (deviceClassId != hueBridgeDeviceClassId) {
return DeviceManager::DeviceSetupStatusFailure;
}
int id = m_bridge->createUser(QHostAddress(ipParam.value().toString()), usernameParam.value().toString());
PairingInfo pi;
pi.pairingTransactionId = pairingTransactionId;
pi.ipParam = ipParam;
pi.usernameParam = usernameParam;
m_pairings.insert(id, pi);
PairingInfo pairingInfo;
pairingInfo.pairingTransactionId = pairingTransactionId;
pairingInfo.host = QHostAddress(params.paramValue("host address").toString());
pairingInfo.username = params.paramValue("username").toString();
QVariantMap createUserParams;
createUserParams.insert("devicetype", "guh");
createUserParams.insert("username", pairingInfo.username);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(createUserParams);
QNetworkRequest request(QUrl("http://" + pairingInfo.host.toString() + "/api"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *reply = networkManagerPost(request, jsonDoc.toJson());
m_pairingRequests.insert(reply, pairingInfo);
return DeviceManager::DeviceSetupStatusAsync;
}
void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
{
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// create user finished
if (m_pairingRequests.keys().contains(reply)) {
PairingInfo pairingInfo = m_pairingRequests.take(reply);
// check HTTP status code
if (status != 200) {
qWarning() << "Request error:" << status << reply->errorString();
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
processPairingResponse(pairingInfo, data);
} else if (m_informationRequests.keys().contains(reply)) {
PairingInfo pairingInfo = m_informationRequests.take(reply);
// check HTTP status code
if (status != 200) {
qWarning() << "Request error:" << status << reply->errorString();
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
processInformationResponse(pairingInfo, data);
} else if (m_lightRefreshRequests.keys().contains(reply)) {
Device *device = m_lightRefreshRequests.take(reply);
// check HTTP status code
if (status != 200) {
qWarning() << "Refresh Hue Light request error:" << status << reply->errorString();
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
processLightRefreshResponse(device, data);
} else if (m_bridgeRefreshRequests.keys().contains(reply)) {
Device *device = m_bridgeRefreshRequests.take(reply);
// check HTTP status code
if (status != 200) {
qWarning() << "Refresh Hue Bridge request error:" << status << reply->errorString();
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
processBridgeRefreshResponse(device, data);
} else if (m_asyncActions.keys().contains(reply)) {
QPair<Device *, ActionId> actionInfo = m_asyncActions.take(reply);
// check HTTP status code
if (status != 200) {
qWarning() << "Refresh Hue Light request error:" << status << reply->errorString();
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
processActionResponse(actionInfo.first, actionInfo.second, data);
}
reply->deleteLater();
}
void DevicePluginPhilipsHue::guhTimer()
{
foreach (Light *light, m_lights.keys()) {
light->refresh();
foreach (Device *device, m_bridges.values()) {
refreshBridge(device);
}
}
DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const Action &action)
{
Light *light = m_lights.key(device);
if (!light) {
return DeviceManager::DeviceErrorDeviceNotFound;
if (device->deviceClassId() == hueLightDeviceClassId) {
HueLight *light = m_lights.key(device);
if (!light->reachable()) {
return DeviceManager::DeviceErrorHardwareNotAvailable;
}
if (action.actionTypeId() == huePowerActionTypeId) {
QPair<QNetworkRequest, QByteArray> request = light->createSetPowerRequest(action.param("power").value().toBool());
m_asyncActions.insert(networkManagerPut(request.first, request.second),QPair<Device *, ActionId>(device, action.id()));
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == hueColorActionTypeId) {
QPair<QNetworkRequest, QByteArray> request = light->createSetColorRequest(action.param("color").value().value<QColor>());
m_asyncActions.insert(networkManagerPut(request.first, request.second),QPair<Device *, ActionId>(device, action.id()));
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == hueBrightnessActionTypeId) {
QPair<QNetworkRequest, QByteArray> request = light->createSetBrightnessRequest(percentageToBrightness(action.param("brightness").value().toInt()));
m_asyncActions.insert(networkManagerPut(request.first, request.second),QPair<Device *, ActionId>(device, action.id()));
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == hueEffectActionTypeId) {
QPair<QNetworkRequest, QByteArray> request = light->createSetEffectRequest(action.param("effect").value().toString());
m_asyncActions.insert(networkManagerPut(request.first, request.second),QPair<Device *, ActionId>(device, action.id()));
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == hueAlertActionTypeId) {
QPair<QNetworkRequest, QByteArray> request = light->createFlashRequest(action.param("alert").value().toString());
m_asyncActions.insert(networkManagerPut(request.first, request.second),QPair<Device *, ActionId>(device, action.id()));
return DeviceManager::DeviceErrorAsync;
} else if (action.actionTypeId() == hueTemperatureActionTypeId) {
QPair<QNetworkRequest, QByteArray> request = light->createSetTemperatureRequest(action.param("color temperature").value().toInt());
m_asyncActions.insert(networkManagerPut(request.first, request.second),QPair<Device *, ActionId>(device, action.id()));
return DeviceManager::DeviceErrorAsync;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
if (!light->reachable()) {
qWarning() << "Hue Bulb not reachable";
return DeviceManager::DeviceErrorHardwareNotAvailable;
}
if (device->deviceClassId() == hueBridgeDeviceClassId) {
if (action.actionTypeId() == hueColorActionTypeId) {
light->setColor(action.param("color").value().value<QColor>());
} else if (action.actionTypeId() == huePowerActionTypeId) {
light->setOn(action.param("power").value().toBool());
} else if (action.actionTypeId() == hueBrightnessActionTypeId) {
light->setBri(percentageToBrightness(action.param("brightness").value().toInt()));
return DeviceManager::DeviceErrorActionTypeNotFound;
}
return DeviceManager::DeviceErrorNoError;
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
void DevicePluginPhilipsHue::createUserFinished(int id, const QVariant &response)
void DevicePluginPhilipsHue::lightStateChanged()
{
qDebug() << "createuser response" << response;
HueLight *light = static_cast<HueLight *>(sender());
PairingInfo pairingInfo = m_pairings.take(id);
if (response.toMap().contains("error")) {
qDebug() << "Failed to pair Hue bridge:" << response.toMap().value("error").toMap().value("description");
Device *device = m_lights.value(light);
if (!device)
return;
device->setStateValue(hueReachableStateTypeId, light->reachable());
device->setStateValue(hueColorStateTypeId, QVariant::fromValue(light->color()));
device->setStateValue(huePowerStateTypeId, light->power());
device->setStateValue(hueBrightnessStateTypeId, brightnessToPercentage(light->brightness()));
device->setStateValue(hueTemperatureStateTypeId, light->ct());
device->setStateValue(hueEffectStateTypeId, light->effect());
device->setStateValue(hueAlertStateTypeId, light->alert());
}
void DevicePluginPhilipsHue::refreshLight(Device *device)
{
HueLight *light = m_lights.key(device);
QNetworkRequest request(QUrl("http://" + light->hostAddress().toString() + "/api/" + light->username() + "/lights/" + QString::number(light->lightId())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *reply = networkManagerGet(request);
m_lightRefreshRequests.insert(reply, device);
}
void DevicePluginPhilipsHue::refreshBridge(Device *device)
{
HueBridge *bridge = m_bridges.key(device);
QNetworkRequest request(QUrl("http://" + bridge->hostAddress().toString() + "/api/" + bridge->username() + "/lights/"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *reply = networkManagerGet(request);
m_bridgeRefreshRequests.insert(reply, device);
}
void DevicePluginPhilipsHue::processLightRefreshResponse(Device *device, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
if (error.error != QJsonParseError::NoError) {
qWarning() << "Hue Bridge json error in response" << error.errorString();
return;
}
// check pairing error
if (data.contains("error")) {
qWarning() << "Failed to refresh Hue Light:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
return;
}
HueLight *hueLight = m_lights.key(device);
hueLight->setStates(jsonDoc.toVariant().toMap().value("state").toMap());
}
void DevicePluginPhilipsHue::processBridgeRefreshResponse(Device *device, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
if (error.error != QJsonParseError::NoError) {
qWarning() << "Hue Bridge json error in response" << error.errorString();
return;
}
// check pairing error
if (data.contains("error")) {
qWarning() << "Failed to refresh Hue Bridge:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
return;
}
QVariantMap lightsMap = jsonDoc.toVariant().toMap();
foreach (const QString &lightId, lightsMap.keys()) {
QVariantMap lightMap = lightsMap.value(lightId).toMap();
// get the light of this bridge
foreach (HueLight *light, m_lights.keys()) {
if (light->lightId() == lightId.toInt() && light->bridgeId() == device->id()) {
light->setStates(lightMap.value("state").toMap());
}
}
}
}
void DevicePluginPhilipsHue::processPairingResponse(const DevicePluginPhilipsHue::PairingInfo &pairingInfo, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
if (error.error != QJsonParseError::NoError) {
qWarning() << "Hue Bridge json error in response" << error.errorString();
emit pairingFinished(pairingInfo.pairingTransactionId, DeviceManager::DeviceSetupStatusFailure);
return;
}
// Paired successfully, check how many lightbulbs there are
int getLightsId = m_bridge->get(QHostAddress(pairingInfo.ipParam.value().toString()), pairingInfo.usernameParam.value().toString(), "lights", this, "getLightsFinished");
m_pairings.insert(getLightsId, pairingInfo);
}
void DevicePluginPhilipsHue::getLightsFinished(int id, const QVariant &params)
{
qDebug() << "getlightsfinished" << params;
PairingInfo pairingInfo = m_pairings.take(id);
if (params.toMap().count() == 0) {
qWarning() << "No light bulbs found on this hue bridge... Cannot proceed with pairing.";
// check pairing error
if (data.contains("error")) {
qWarning() << "Failed to pair Hue Bridge:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
emit pairingFinished(pairingInfo.pairingTransactionId, DeviceManager::DeviceSetupStatusFailure);
return;
}
// Store a list of all known Lights
foreach (const QString &lightId, params.toMap().keys()) {
Light *light = new Light(QHostAddress(pairingInfo.ipParam.value().toString()), pairingInfo.usernameParam.value().toString(), lightId.toInt(), this);
m_unconfiguredLights.insert(lightId.toInt(), light);
// Paired successfully, check bridge/light information
QNetworkRequest request(QUrl("http://" + pairingInfo.host.toString() + "/api/" + pairingInfo.username + ""));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *reply = networkManagerGet(request);
m_informationRequests.insert(reply, pairingInfo);
}
void DevicePluginPhilipsHue::processInformationResponse(const DevicePluginPhilipsHue::PairingInfo &pairingInfo, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// check JSON error
if (error.error != QJsonParseError::NoError) {
qWarning() << "Hue Bridge json error in response" << error.errorString();
emit pairingFinished(pairingInfo.pairingTransactionId, DeviceManager::DeviceSetupStatusFailure);
return;
}
QVariantMap response = jsonDoc.toVariant().toMap();
// check json error
if (response.contains("error")) {
qWarning() << "Failed to get information from Hue Bridge:" << response.value("error").toMap().value("description").toString();
emit pairingFinished(pairingInfo.pairingTransactionId, DeviceManager::DeviceSetupStatusFailure);
return;
}
// create Bridge
HueBridge *bridge = new HueBridge(pairingInfo.username, pairingInfo.host);
bridge->setApiVersion(response.value("config").toMap().value("apiversion").toString());
bridge->setMacAddress(response.value("config").toMap().value("mac").toString());
bridge->setName(response.value("config").toMap().value("name").toString());
bridge->setZigbeeChannel(response.value("config").toMap().value("zigbeechannel").toInt());
m_unconfiguredBridges.append(bridge);
// create Lights
QVariantMap lightsMap = response.value("lights").toMap();
foreach (QString lightId, lightsMap.keys()) {
QVariantMap lightMap = lightsMap.value(lightId).toMap();
HueLight *hueLight = new HueLight(lightId.toInt(),
bridge->hostAddress(),
lightMap.value("name").toString(),
pairingInfo.username,
lightMap.value("modelid").toString(),
DeviceId(),
this);
hueLight->setStates(lightMap.value("state").toMap());
bridge->addLight(hueLight);
m_unconfiguredLights.append(hueLight);
connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged);
}
emit pairingFinished(pairingInfo.pairingTransactionId, DeviceManager::DeviceSetupStatusSuccess);
}
void DevicePluginPhilipsHue::getFinished(int id, const QVariant &params)
void DevicePluginPhilipsHue::processActionResponse(Device *device, const ActionId actionId, const QByteArray &data)
{
qDebug() << "got lights" << params << id;
}
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
void DevicePluginPhilipsHue::lightStateChanged()
{
Light *light = static_cast<Light*>(sender());
Device *device;
if (m_asyncSetups.contains(light)) {
device = m_asyncSetups.take(light);
device->setName(light->name());
device->setParamValue("name", light->name());
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
} else {
device = m_lights.value(light);
}
if (!device) {
// check JSON error
if (error.error != QJsonParseError::NoError) {
qWarning() << "Hue Bridge json error in response" << error.errorString();
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorHardwareNotAvailable);
return;
}
device->setStateValue(hueReachableStateTypeId, light->reachable());
device->setStateValue(hueColorStateTypeId, QVariant::fromValue(light->color()));
device->setStateValue(huePowerStateTypeId, light->on());
device->setStateValue(hueBrightnessStateTypeId, brightnessToPercentage(light->bri()));
// check pairing error
if (data.contains("error")) {
qWarning() << "Failed to execute Hue action:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorHardwareNotAvailable);
return;
}
m_lights.key(device)->processActionResponse(jsonDoc.toVariant().toList());
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
}
int DevicePluginPhilipsHue::brightnessToPercentage(int brightness)

View File

@ -1,6 +1,7 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
@ -22,8 +23,8 @@
#define DEVICEPLUGINPHILIPSHUE_H
#include "plugin/deviceplugin.h"
#include "huebridgeconnection.h"
#include "light.h"
#include "huebridge.h"
#include "huelight.h"
class QNetworkReply;
@ -38,28 +39,21 @@ public:
explicit DevicePluginPhilipsHue();
DeviceManager::HardwareResources requiredHardware() const override;
void startMonitoringAutoDevices() override;
QList<ParamType> configurationDescription() const override;
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
void deviceRemoved(Device *device) override;
void upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList) override;
DeviceManager::DeviceSetupStatus confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList &params) override;
void networkManagerReplyReady(QNetworkReply *reply) override;
void guhTimer() override;
public slots:
DeviceManager::DeviceError executeAction(Device *device, const Action &action);
private slots:
void createUserFinished(int id, const QVariant &params);
void getLightsFinished(int id, const QVariant &params);
void getFinished(int id, const QVariant &params);
void lightStateChanged();
private:
@ -67,17 +61,31 @@ private:
class PairingInfo {
public:
PairingTransactionId pairingTransactionId;
Param ipParam;
Param usernameParam;
QHostAddress host;
QString username;
};
QHash<int, PairingInfo> m_pairings;
HueBridgeConnection *m_bridge;
QHash<QNetworkReply *, PairingInfo> m_pairingRequests;
QHash<QNetworkReply *, PairingInfo> m_informationRequests;
QList<Light*> m_unconfiguredLights;
QHash<Light*, Device*> m_lights;
QList<HueBridge *> m_unconfiguredBridges;
QList<HueLight *> m_unconfiguredLights;
QHash<Light*, Device*> m_asyncSetups;
QHash<QNetworkReply *, Device *> m_lightRefreshRequests;
QHash<QNetworkReply *, Device *> m_bridgeRefreshRequests;
QHash<QNetworkReply *, QPair<Device *, ActionId> > m_asyncActions;
QHash<HueBridge*, Device*> m_bridges;
QHash<HueLight*, Device*> m_lights;
void refreshLight(Device *device);
void refreshBridge(Device *device);
void processLightRefreshResponse(Device *device, const QByteArray &data);
void processBridgeRefreshResponse(Device *device, const QByteArray &data);
void processPairingResponse(const PairingInfo &pairingInfo, const QByteArray &data);
void processInformationResponse(const PairingInfo &pairingInfo, const QByteArray &data);
void processActionResponse(Device *device, const ActionId actionId, const QByteArray &data);
int brightnessToPercentage(int brightness);
int percentageToBrightness(int percentage);

View File

@ -7,12 +7,12 @@
"name": "Philips",
"deviceClasses": [
{
"deviceClassId": "d8f4c397-e05e-47c1-8917-8e72d4d0d47c",
"idName": "hue",
"name": "Hue",
"createMethods": ["discovery", "auto"],
"deviceClassId": "642aa4c7-19aa-45ed-ba06-aa1ae6c9edf7",
"idName": "hueBridge",
"name": "Hue Bridge",
"createMethods": ["discovery"],
"setupMethod": "pushButton",
"pairingInfo": "Please press the button on the Hue bridge and then press OK",
"pairingInfo": "Please press the button on the Hue Bridge before you continue",
"paramTypes": [
{
"name": "name",
@ -20,11 +20,71 @@
"inputType": "TextLine"
},
{
"name": "ip",
"name": "username",
"type" : "QString",
"inputType": "TextLine",
"readOnly": true
},
{
"name": "host address",
"type" : "QString",
"inputType": "IPv4Address",
"readOnly": true
},
{
"name": "mac address",
"type" : "QString",
"inputType": "MacAddress",
"readOnly": true
},
{
"name": "api version",
"type" : "QString",
"readOnly": true
},
{
"name": "zigbee channel",
"type" : "int",
"readOnly": true
}
],
"stateTypes": [
{
"id": "15794d26-fde8-4a61-8f83-d7830534975f",
"idName": "bridgeReachable",
"name": "reachable",
"type": "bool"
}
],
"actionTypes": [
{
"id": "001476ce-2f17-475f-939f-d4234751ef35",
"idName": "searchLamps",
"name": "search new lamps"
}
]
},
{
"deviceClassId": "0edba26c-96ab-44fb-a6a2-c0574d19630e",
"idName": "hueLight",
"name": "Hue Light",
"createMethods": ["auto"],
"paramTypes": [
{
"name": "name",
"type" : "QString",
"inputType": "TextLine"
},
{
"name": "bridge",
"type" : "QString",
"readOnly": true
},
{
"name": "model id",
"type" : "QString",
"readOnly": true
},
{
"name": "username",
"type" : "QString",
@ -32,18 +92,43 @@
"readOnly": true
},
{
"name": "lightId",
"name": "host address",
"type" : "QString",
"inputType": "IPv4Address",
"readOnly": true
},
{
"name": "light id",
"type" : "int",
"readOnly": true
}
],
"stateTypes": [
{
"id": "15794d26-fde8-4a61-8f83-d7830534975f",
"id": "19bb8d10-1b28-4ba3-99b7-a634138dcfde",
"idName": "hueReachable",
"name": "reachable",
"type": "bool"
},
{
"id": "90aaffe5-6a76-47d2-a14a-550f60390245",
"idName": "huePower",
"name": "power",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "c0f4206f-f219-4f06-93c4-4ca515a56f79",
"idName": "hueTemperature",
"name": "color temperature",
"type": "int",
"unit": "Mired",
"writable": true,
"defaultValue": 170,
"minValue": 154,
"maxValue": 500
},
{
"id": "d25423e7-b924-4b20-80b6-77eecc65d089",
"idName": "hueColor",
@ -53,24 +138,41 @@
"writable": true
},
{
"id": "90aaffe5-6a76-47d2-a14a-550f60390245",
"idName": "huePower",
"name": "power",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "90e91f64-a208-468c-a5a2-7f47e08859e2",
"idName": "hueBrightness",
"name": "brightness",
"type": "int",
"unit": "Percentage",
"minValue": 0,
"maxValue": 100,
"unit": "Percentage",
"defaultValue": 0,
"writable": true
},
{
"id": "0b7cdd8d-4db8-4183-abe2-f3c01d1c9afc",
"idName": "hueEffect",
"name": "effect",
"type": "QString",
"defaultValue": "none",
"allowedValues": [
"none",
"color loop"
],
"writable": true
},
{
"id": "acd09e71-3305-451c-910a-bc2d6e1d5144",
"idName": "hueAlert",
"name": "alert",
"type": "QString",
"defaultValue": "none",
"allowedValues": [
"none",
"flash",
"flash 30 seconds"
],
"writable": true
}
]
}

View File

@ -0,0 +1,103 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "huebridge.h"
HueBridge::HueBridge(QString username, QHostAddress hostAddress, QObject *parent) :
QObject(parent),
m_username(username),
m_hostAddress(hostAddress),
m_name(QString()),
m_macAddress(QString()),
m_apiVersion(QString()),
m_zigbeeChannel(-1)
{
}
QString HueBridge::name() const
{
return m_name;
}
void HueBridge::setName(const QString &name)
{
m_name = name;
}
QString HueBridge::username() const
{
return m_username;
}
void HueBridge::setUsername(const QString &username)
{
m_username = username;
}
QHostAddress HueBridge::hostAddress() const
{
return m_hostAddress;
}
void HueBridge::setHostAddress(const QHostAddress &hostAddress)
{
m_hostAddress = hostAddress;
}
QString HueBridge::macAddress() const
{
return m_macAddress;
}
void HueBridge::setMacAddress(const QString &macAddress)
{
m_macAddress = macAddress;
}
QString HueBridge::apiVersion() const
{
return m_apiVersion;
}
void HueBridge::setApiVersion(const QString &apiVersion)
{
m_apiVersion = apiVersion;
}
int HueBridge::zigbeeChannel() const
{
return m_zigbeeChannel;
}
void HueBridge::setZigbeeChannel(const int &zigbeeChannel)
{
m_zigbeeChannel = zigbeeChannel;
}
QList<HueLight *> HueBridge::lights() const
{
return m_lights;
}
void HueBridge::addLight(HueLight *light)
{
m_lights.append(light);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
@ -18,46 +18,55 @@
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef HUEBRIDGECONNECTION_H
#define HUEBRIDGECONNECTION_H
#ifndef HUEBRIDGE_H
#define HUEBRIDGE_H
#include <QObject>
#include <QHostAddress>
#include <QNetworkAccessManager>
#include <QPointer>
class Caller
{
public:
QPointer<QObject> obj;
QString method;
int id;
};
#include "huelight.h"
class HueBridgeConnection : public QObject
class HueBridge : public QObject
{
Q_OBJECT
public:
explicit HueBridgeConnection(QObject *parent = 0);
explicit HueBridge(QString username, QHostAddress hostAddress, QObject *parent = 0);
int createUser(const QHostAddress &address, const QString &username);
QString name() const;
void setName(const QString &name);
int get(const QHostAddress &address, const QString &username, const QString &path, QObject *caller, const QString &methodName);
int put(const QHostAddress &address, const QString &username, const QString &path, const QVariantMap &data, QObject *caller, const QString &methodName);
QString username() const;
void setUsername(const QString &username);
private slots:
void slotCreateUserFinished();
void slotGetFinished();
QHostAddress hostAddress() const;
void setHostAddress(const QHostAddress &hostAddress);
signals:
void createUserFinished(int id, const QVariantMap &map);
void getFinished(int id, const QVariantMap &map);
QString macAddress() const;
void setMacAddress(const QString &macAddress);
QString apiVersion() const;
void setApiVersion(const QString &apiVersion);
int zigbeeChannel() const;
void setZigbeeChannel(const int &zigbeeChannel);
QList<HueLight *> lights() const;
void addLight(HueLight *light);
private:
QNetworkAccessManager *m_nam;
int m_requestCounter;
QHash<QNetworkReply*, int> m_createUserMap;
QHash<QNetworkReply*, Caller> m_requestMap;
QString m_username;
QHostAddress m_hostAddress;
QString m_name;
QString m_macAddress;
QString m_apiVersion;
int m_zigbeeChannel;
QList<HueLight *> m_lights;
signals:
public slots:
};
#endif // HUEBRIDGECONNECTION_H
#endif // HUEBRIDGE_H

View File

@ -1,148 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2013 Michael Zanetti <michael_zanetti@gmx.net> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "huebridgeconnection.h"
#include <QJsonDocument>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
HueBridgeConnection::HueBridgeConnection(QObject *parent) :
QObject(parent)
{
m_nam = new QNetworkAccessManager(this);
}
int HueBridgeConnection::createUser(const QHostAddress &address, const QString &username)
{
QVariantMap createUserParams;
createUserParams.insert("devicetype", "guh");
createUserParams.insert("username", username);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(createUserParams);
QByteArray data = jsonDoc.toJson();
QNetworkRequest request(QUrl("http://" + address.toString() + "/api"));
QNetworkReply *reply = m_nam->post(request, data);
connect(reply, &QNetworkReply::finished, this, &HueBridgeConnection::slotCreateUserFinished);
m_createUserMap.insert(reply, m_requestCounter);
return m_requestCounter++;
}
int HueBridgeConnection::get(const QHostAddress &address, const QString &username, const QString &path, QObject *caller, const QString &methodName)
{
QString baseUrl = "http://" + address.toString() + "/api/" + username + "/";
QUrl url(baseUrl + path);
QNetworkRequest request;
request.setUrl(url);
QNetworkReply *reply = m_nam->get(request);
connect(reply, &QNetworkReply::finished, this, &HueBridgeConnection::slotGetFinished);
Caller c;
c.obj = caller;
c.method = methodName;
c.id = m_requestCounter;
m_requestMap.insert(reply, c);
return m_requestCounter++;
}
int HueBridgeConnection::put(const QHostAddress &address, const QString &username, const QString &path, const QVariantMap &data, QObject *caller, const QString &methodName)
{
QString baseUrl = "http://" + address.toString() + "/api/" + username + "/";
QUrl url(baseUrl + path);
QNetworkRequest request;
request.setUrl(url);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(data);
QByteArray jsonData = jsonDoc.toJson();
//qDebug() << "putting" << url << jsonData;
QNetworkReply *reply = m_nam->put(request, jsonData);
connect(reply, &QNetworkReply::finished, this, &HueBridgeConnection::slotGetFinished);
Caller c;
c.obj = caller;
c.method = methodName;
c.id = m_requestCounter;
m_requestMap.insert(reply, c);
return m_requestCounter++;
}
void HueBridgeConnection::slotCreateUserFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
QByteArray data = reply->readAll();
int id = m_createUserMap.take(reply);
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
qDebug() << jsonDoc.toJson();
if (error.error != QJsonParseError::NoError) {
QVariantMap params;
QVariantMap errorMap;
errorMap.insert("description", "Failed to parse the bridge's response:" + error.errorString());
params.insert("error", errorMap);
emit createUserFinished(id, params);
return;
}
QVariantMap response = jsonDoc.toVariant().toList().first().toMap();
emit createUserFinished(id, response);
}
void HueBridgeConnection::slotGetFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
QByteArray data = reply->readAll();
Caller c = m_requestMap.take(reply);
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
QVariantMap params;
QVariantMap errorMap;
errorMap.insert("description", "Failed to parse the bridge's response:" + error.errorString());
params.insert("error", errorMap);
emit createUserFinished(c.id, params);
return;
}
if (jsonDoc.toJson().contains("error")){
qDebug() << jsonDoc.toJson();
}
QVariant response = jsonDoc.toVariant();
emit getFinished(c.id, response.toMap());
if (c.obj) {
metaObject()->invokeMethod(c.obj.data(), c.method.toLatin1().data(), Q_ARG(int, c.id), Q_ARG(QVariant, response));
}
}

View File

@ -0,0 +1,397 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "huelight.h"
HueLight::HueLight(const int &lightId, const QHostAddress &hostAddress, const QString &name, const QString &username, const QString &modelId, const DeviceId &bridgeId, QObject *parent) :
QObject(parent),
m_lightId(lightId),
m_hostAddress(hostAddress),
m_name(name),
m_username(username),
m_modelId(modelId),
m_bridgeId(bridgeId)
{
}
int HueLight::lightId() const
{
return m_lightId;
}
void HueLight::setLightId(const int &lightId)
{
m_lightId = lightId;
}
DeviceId HueLight::bridgeId() const
{
return m_bridgeId;
}
void HueLight::setBridgeId(const DeviceId &bridgeDeviceId)
{
m_bridgeId = bridgeDeviceId;
}
QHostAddress HueLight::hostAddress() const
{
return m_hostAddress;
}
void HueLight::setHostAddress(const QHostAddress hostAddress)
{
m_hostAddress = hostAddress;
}
QString HueLight::name() const
{
return m_name;
}
void HueLight::setName(const QString &name)
{
m_name = name;
}
QString HueLight::username() const
{
return m_username;
}
void HueLight::setUsername(const QString &username)
{
m_username = username;
}
QString HueLight::modelId() const
{
return m_modelId;
}
void HueLight::setModelId(const QString &modelId)
{
m_modelId = modelId;
}
QString HueLight::type() const
{
return m_type;
}
void HueLight::setType(const QString &type)
{
m_type = type;
}
QString HueLight::softwareVersion() const
{
return m_softwareVersion;
}
void HueLight::setSoftwareVersion(const QString &softwareVersion)
{
m_softwareVersion = softwareVersion;
}
bool HueLight::power() const
{
return m_power;
}
void HueLight::setPower(const bool &power)
{
m_power = power;
}
bool HueLight::reachable() const
{
return m_reachable;
}
void HueLight::setReachable(const bool &reachable)
{
m_reachable = reachable;
}
quint8 HueLight::brightness() const
{
return m_brightness;
}
void HueLight::setBrigtness(const quint8 brightness)
{
m_brightness = brightness;
}
quint16 HueLight::hue() const
{
return m_hue;
}
void HueLight::setHue(const quint16 hue)
{
m_hue = hue;
}
quint8 HueLight::sat() const
{
return m_sat;
}
void HueLight::setSat(const quint8 sat)
{
m_sat = sat;
}
QColor HueLight::color() const
{
return QColor::fromHsv(m_hue * 360 / 65535, m_sat, 255);
}
QPointF HueLight::xy() const
{
return m_xy;
}
void HueLight::setXy(const QPointF &xy)
{
m_xy = xy;
}
quint16 HueLight::ct() const
{
return m_ct;
}
void HueLight::setCt(const quint16 &ct)
{
m_ct = ct;
}
QString HueLight::alert() const
{
return m_alert;
}
void HueLight::setAlert(const QString &alert)
{
m_alert = alert;
}
QString HueLight::effect() const
{
return m_effect;
}
void HueLight::setEffect(const QString &effect)
{
m_effect = effect;
}
HueLight::ColorMode HueLight::colorMode() const
{
return m_colorMode;
}
void HueLight::setColorMode(const HueLight::ColorMode &colorMode)
{
m_colorMode = colorMode;
}
void HueLight::setStates(const QVariantMap &statesMap)
{
// color mode
if (statesMap.value("colormode").toString() == "hs") {
setColorMode(ColorModeHS);
} else if (statesMap.value("colormode").toString() == "ct") {
setColorMode(ColorModeCT);
} else if (statesMap.value("colormode").toString() == "xy") {
setColorMode(ColorModeXY);
}
// effect (none, colorloop)
if (statesMap.value("effect").toString() == "none") {
setEffect("none");
} else if (statesMap.value("effect").toString() == "colorloop") {
setEffect("color loop");
}
// alert (none, select, lselect)
setAlert(statesMap.value("alert").toString());
setBrigtness(statesMap.value("bri").toInt());
setCt(statesMap.value("ct").toInt());
setPower(statesMap.value("on").toBool());
setReachable(statesMap.value("reachable").toBool());
setSat(statesMap.value("sat").toInt());
setHue(statesMap.value("hue").toInt());
setXy(QPointF(statesMap.value("xy").toList().first().toFloat(),statesMap.value("xy").toList().last().toFloat()));
emit stateChanged();
}
void HueLight::processActionResponse(const QVariantList &responseList)
{
foreach (const QVariant &resultVariant, responseList) {
QVariantMap result = resultVariant.toMap();
if (result.contains("success")) {
QVariantMap successMap = result.value("success").toMap();
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/on")) {
m_power = successMap.value("/lights/" + QString::number(m_lightId) + "/state/on").toBool();
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/hue")) {
m_hue = successMap.value("/lights/" + QString::number(m_lightId) + "/state/hue").toInt();
m_colorMode = ColorModeHS;
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/bri")) {
m_brightness = successMap.value("/lights/" + QString::number(m_lightId) + "/state/bri").toInt();
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/sat")) {
m_sat = successMap.value("/lights/" + QString::number(m_lightId) + "/state/sat").toInt();
m_colorMode = ColorModeHS;
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/xy")) {
m_xy = successMap.value("/lights/" + QString::number(m_lightId) + "/state/xy").toPoint();
m_colorMode = ColorModeXY;
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/ct")) {
m_ct = successMap.value("/lights/" + QString::number(m_lightId) + "/state/ct").toInt();
m_colorMode = ColorModeCT;
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/effect")) {
QString effect = successMap.value("/lights/" + QString::number(m_lightId) + "/state/effect").toString();
if (effect == "none") {
setEffect("none");
} else if (effect == "colorloop") {
setEffect("color loop");
}
}
if (successMap.contains("/lights/" + QString::number(m_lightId) + "/state/alert")) {
QString alert = successMap.value("/lights/" + QString::number(m_lightId) + "/state/alert").toString();
if (alert == "none") {
m_alert = "none";
} else if (alert == "select") {
m_alert = "flash";
} else if (alert == "lselect") {
m_alert = "flash 30 seconds";
}
}
}
}
emit stateChanged();
}
QPair<QNetworkRequest, QByteArray> HueLight::createSetPowerRequest(const bool &power)
{
QVariantMap requestMap;
requestMap.insert("on", power);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap);
QNetworkRequest request(QUrl("http://" + hostAddress().toString() + "/api/" + username() +
"/lights/" + QString::number(lightId()) + "/state"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
return QPair<QNetworkRequest, QByteArray>(request, jsonDoc.toJson());
}
QPair<QNetworkRequest, QByteArray> HueLight::createSetColorRequest(const QColor &color)
{
QVariantMap requestMap;
requestMap.insert("hue", color.hue() * 65535 / 360);
requestMap.insert("sat", color.saturation());
requestMap.insert("on", true);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap);
QNetworkRequest request(QUrl("http://" + hostAddress().toString() + "/api/" + username() +
"/lights/" + QString::number(lightId()) + "/state"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
return QPair<QNetworkRequest, QByteArray>(request, jsonDoc.toJson());
}
QPair<QNetworkRequest, QByteArray> HueLight::createSetBrightnessRequest(const int &brightness)
{
QVariantMap requestMap;
requestMap.insert("bri", brightness);
if (brightness == 0) {
requestMap.insert("on", false);
} else {
requestMap.insert("on", true);
}
QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap);
QNetworkRequest request(QUrl("http://" + hostAddress().toString() + "/api/" + username() +
"/lights/" + QString::number(lightId()) + "/state"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
return QPair<QNetworkRequest, QByteArray>(request, jsonDoc.toJson());
}
QPair<QNetworkRequest, QByteArray> HueLight::createSetEffectRequest(const QString &effect)
{
QVariantMap requestMap;
if (effect == "none") {
requestMap.insert("effect", "none");
} else if (effect == "color loop") {
requestMap.insert("effect", "colorloop");
requestMap.insert("on", true);
}
QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap);
QNetworkRequest request(QUrl("http://" + hostAddress().toString() + "/api/" + username() +
"/lights/" + QString::number(lightId()) + "/state"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
return QPair<QNetworkRequest, QByteArray>(request, jsonDoc.toJson());
}
QPair<QNetworkRequest, QByteArray> HueLight::createSetTemperatureRequest(const int &colorTemp)
{
QVariantMap requestMap;
requestMap.insert("ct", colorTemp);
requestMap.insert("on", true);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap);
QNetworkRequest request(QUrl("http://" + hostAddress().toString() + "/api/" + username() +
"/lights/" + QString::number(lightId()) + "/state"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
return QPair<QNetworkRequest, QByteArray>(request, jsonDoc.toJson());
}
QPair<QNetworkRequest, QByteArray> HueLight::createFlashRequest(const QString &alert)
{
QVariantMap requestMap;
if (alert == "none") {
requestMap.insert("alert", "none");
} else if (alert == "flash") {
requestMap.insert("alert", "select");
} else if (alert == "flash 30 seconds") {
requestMap.insert("alert", "lselect");
}
QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap);
QNetworkRequest request(QUrl("http://" + hostAddress().toString() + "/api/" + username() +
"/lights/" + QString::number(lightId()) + "/state"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
return QPair<QNetworkRequest, QByteArray>(request, jsonDoc.toJson());
}

View File

@ -1,6 +1,7 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2013 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
@ -18,122 +19,128 @@
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef LIGHT_H
#define LIGHT_H
#ifndef HUELIGHT_H
#define HUELIGHT_H
#include <QObject>
#include <QPointF>
#include <QDebug>
#include <QColor>
#include <QPoint>
#include <QHostAddress>
#include <QTimer>
#include <QNetworkRequest>
#include <QJsonDocument>
class HueBridgeConnection;
#include "typeutils.h"
#include "types/action.h"
class Light: public QObject
class HueLight : public QObject
{
Q_OBJECT
public:
enum ColorMode {
ColorModeHS,
ColorModeXY,
ColorModeCT
};
Light(const QHostAddress &ip, const QString &username, int id, QObject *parent = 0);
explicit HueLight(const int &lightId, const QHostAddress &hostAddress, const QString &name, const QString &username, const QString &modelId, const DeviceId &bridgeId, QObject *parent = 0);
QHostAddress ip() const;
QString username() const;
int lightId() const;
void setLightId(const int &lightId);
int id() const;
DeviceId bridgeId() const;
void setBridgeId(const DeviceId &bridgeDeviceId);
QHostAddress hostAddress() const;
void setHostAddress(const QHostAddress hostAddress);
QString name() const;
void setName(const QString &name);
QString username() const;
void setUsername(const QString &username);
QString modelId() const;
void setModelId(const QString &modelId);
QString type() const;
void setType(const QString &type);
QString swversion() const;
void setSwversion(const QString &swversion);
QString softwareVersion() const;
void setSoftwareVersion(const QString &softwareVersion);
bool power() const;
void setPower(const bool &power);
// LightInterface implementation
bool on() const;
quint8 bri() const;
quint16 hue() const;
quint8 sat() const;
QColor color() const;
QPointF xy() const;
quint16 ct() const;
QString alert() const;
QString effect() const;
ColorMode colorMode() const;
bool reachable() const;
void setReachable(const bool &reachable);
quint8 brightness() const;
void setBrigtness(const quint8 brightness);
public slots:
void refresh();
quint16 hue() const;
void setHue(const quint16 hue);
void setOn(bool on);
void setBri(quint8 bri);
void setHue(quint16 hue);
void setSat(quint8 sat);
void setColor(const QColor &color);
quint8 sat() const;
void setSat(const quint8 sat);
QColor color() const;
QPointF xy() const;
void setXy(const QPointF &xy);
void setCt(quint16 ct);
quint16 ct() const;
void setCt(const quint16 &ct);
QString alert() const;
void setAlert(const QString &alert);
QString effect() const;
void setEffect(const QString &effect);
signals:
void stateChanged();
ColorMode colorMode() const;
void setColorMode(const ColorMode &colorMode);
private slots:
void responseReceived(int id, const QVariant &response);
void setDescriptionFinished(int id, const QVariant &response);
void setStateFinished(int id, const QVariant &response);
// update states
void setStates(const QVariantMap &statesMap);
void processActionResponse(const QVariantList &responseList);
// create action requests
QPair<QNetworkRequest, QByteArray> createSetPowerRequest(const bool &power);
QPair<QNetworkRequest, QByteArray> createSetColorRequest(const QColor &color);
QPair<QNetworkRequest, QByteArray> createSetBrightnessRequest(const int &brightness);
QPair<QNetworkRequest, QByteArray> createSetEffectRequest(const QString &effect);
QPair<QNetworkRequest, QByteArray> createSetTemperatureRequest(const int &colorTemp);
QPair<QNetworkRequest, QByteArray> createFlashRequest(const QString &alert);
private:
void setReachable(bool reachable);
HueBridgeConnection *m_bridge;
QHostAddress m_ip;
QString m_username;
int m_id;
int m_lightId;
QHostAddress m_hostAddress;
QString m_name;
QString m_username;
QString m_modelId;
DeviceId m_bridgeId;
QString m_type;
QString m_swversion;
QString m_softwareVersion;
bool m_on;
quint8 m_bri;
bool m_power;
bool m_reachable;
quint8 m_brightness;
quint16 m_hue;
quint8 m_sat;
QPointF m_xy;
quint16 m_ct;
QString m_alert;
QString m_effect;
ColorMode m_colormode;
bool m_reachable;
ColorMode m_colorMode;
int m_busyStateChangeId;
bool m_hueDirty;
quint16 m_dirtyHue;
bool m_satDirty;
quint8 m_dirtySat;
bool m_briDirty;
quint8 m_dirtyBri;
bool m_ctDirty;
quint16 m_dirtyCt;
bool m_xyDirty;
QPointF m_dirtyXy;
signals:
void stateChanged();
public slots:
// FIXME: This is needed as sometimes we don't get a reply from the bridge
// Can't use guhtimer right now as that triggers in intervals that aren't
// related to our sending. Perhaps we should create a guhtimeout thing?
QTimer m_busyTimeout;
};
#endif
#endif // HUELIGHT_H

View File

@ -1,421 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2013 Michael Zanetti <michael_zanetti@gmx.net> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "light.h"
#include "huebridgeconnection.h"
#include <QColor>
#include <QDebug>
#include <QGenericMatrix>
Light::Light(const QHostAddress &ip, const QString &username, int id, QObject *parent):
QObject(parent),
m_bridge(new HueBridgeConnection(this)),
m_ip(ip),
m_username(username),
m_id(id),
m_on(false),
m_busyStateChangeId(-1),
m_hueDirty(false),
m_satDirty(false),
m_briDirty(false),
m_ctDirty(false),
m_xyDirty(false)
{
m_busyTimeout.setSingleShot(true);
m_busyTimeout.setInterval(2000);
connect(&m_busyTimeout, &QTimer::timeout, [this]{ setStateFinished(m_busyStateChangeId, QVariant()); });
}
QHostAddress Light::ip() const
{
return m_ip;
}
QString Light::username() const
{
return m_username;
}
int Light::id() const
{
return m_id;
}
QString Light::name() const
{
return m_name;
}
void Light::setName(const QString &name)
{
if (m_name != name) {
QVariantMap params;
params.insert("name", name);
m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id), params, this, "setDescriptionFinished");
}
}
QString Light::modelId() const
{
return m_modelId;
}
void Light::setModelId(const QString &modelId)
{
if (m_modelId != modelId) {
m_modelId = modelId;
}
}
QString Light::type() const
{
return m_type;
}
void Light::setType(const QString &type)
{
if (m_type != type) {
m_type = type;
}
}
QString Light::swversion() const
{
return m_swversion;
}
void Light::setSwversion(const QString &swversion)
{
if (m_swversion != swversion) {
m_swversion = swversion;
}
}
bool Light::on() const
{
return m_on;
}
void Light::setOn(bool on)
{
if (m_on != on) {
QVariantMap params;
params.insert("on", on);
m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
}
}
quint8 Light::bri() const
{
return m_bri;
}
void Light::setBri(quint8 bri)
{
if (m_bri != bri) {
qDebug() << "setting brightness to" << bri << m_busyStateChangeId;
if (m_busyStateChangeId == -1) {
QVariantMap params;
if (bri == 0) {
params.insert("bri", bri);
params.insert("on", false);
} else {
params.insert("bri", bri);
params.insert("on", true);
}
m_busyStateChangeId = m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
m_busyTimeout.start();
} else {
m_dirtyBri = bri;
m_briDirty = true;
}
}
}
quint16 Light::hue() const
{
return m_hue;
}
void Light::setHue(quint16 hue)
{
if (m_hue != hue) {
m_hue = hue;
emit stateChanged();
}
}
quint8 Light::sat() const
{
return m_sat;
}
void Light::setSat(quint8 sat)
{
if (m_sat != sat) {
m_sat = sat;
emit stateChanged();
}
}
QColor Light::color() const
{
return QColor::fromHsv(m_hue * 360 / 65535, m_sat, 255);
}
void Light::setColor(const QColor &color)
{
// Transform from RGB to Hue/Sat
quint16 hue = color.hue() * 65535 / 360;
quint8 sat = color.saturation();
qDebug() << "setting color" << color;
if (m_busyStateChangeId == -1) {
QVariantMap params;
params.insert("hue", hue);
params.insert("sat", sat);
// FIXME: There is a bug in the API that it doesn't report back the set state of "sat"
// Lets just assume it always succeeds
m_sat = sat;
params.insert("on", true);
m_busyStateChangeId = m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
m_busyTimeout.start();
} else {
m_dirtyHue = hue;
m_hueDirty = true;
m_dirtySat = sat;
m_satDirty = true;
}
}
QPointF Light::xy() const
{
return m_xy;
}
void Light::setXy(const QPointF &xy)
{
if (m_xy != xy) {
m_xy = xy;
emit stateChanged();
}
}
quint16 Light::ct() const
{
return m_ct;
}
void Light::setCt(quint16 ct)
{
if (m_busyStateChangeId == -1) {
QVariantMap params;
params.insert("ct", ct);
params.insert("on", true);
m_busyStateChangeId = m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
m_busyTimeout.start();
} else {
m_dirtyCt = ct;
m_ctDirty = true;
}
}
QString Light::alert() const
{
return m_alert;
}
void Light::setAlert(const QString &alert)
{
if (m_alert != alert) {
m_alert = alert;
emit stateChanged();
}
}
QString Light::effect() const
{
return m_effect;
}
void Light::setEffect(const QString &effect)
{
if (m_effect != effect) {
QVariantMap params;
params.insert("effect", effect);
if (effect != "none") {
params.insert("on", true);
}
m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
}
}
Light::ColorMode Light::colorMode() const
{
return m_colormode;
}
bool Light::reachable() const
{
return m_reachable;
}
void Light::refresh()
{
m_bridge->get(m_ip, m_username, "lights/" + QString::number(m_id), this, "responseReceived");
}
void Light::setReachable(bool reachable)
{
if (m_reachable != reachable) {
m_reachable = reachable;
emit stateChanged();
}
}
void Light::responseReceived(int id, const QVariant &response)
{
Q_UNUSED(id)
QVariantMap attributes = response.toMap();
m_name = attributes.value("name").toString();
setModelId(attributes.value("modelid").toString());
setType(attributes.value("type").toString());
setSwversion(attributes.value("swversion").toString());
QVariantMap stateMap = attributes.value("state").toMap();
m_on = stateMap.value("on").toBool();
m_bri = stateMap.value("bri").toInt();
m_hue = stateMap.value("hue").toInt();
m_sat = stateMap.value("sat").toInt();
m_xy = stateMap.value("xy").toPointF();
m_ct = stateMap.value("ct").toInt();
m_alert = stateMap.value("alert").toString();
m_effect = stateMap.value("effect").toString();
QString colorModeString = stateMap.value("colormode").toString();
if (colorModeString == "hs") {
m_colormode = ColorModeHS;
} else if (colorModeString == "xy") {
m_colormode = ColorModeXY;
} else if (colorModeString == "ct") {
m_colormode = ColorModeCT;
}
m_reachable = stateMap.value("reachable").toBool();
emit stateChanged();
//qDebug() << "got light response" << m_modelId << m_type << m_swversion << m_on << m_bri << m_reachable;
}
void Light::setDescriptionFinished(int id, const QVariant &response)
{
Q_UNUSED(id)
QVariantMap result = response.toList().first().toMap();
if (result.contains("success")) {
QVariantMap successMap = result.value("success").toMap();
if (successMap.contains("/lights/" + QString::number(m_id) + "/name")) {
m_name = successMap.value("/lights/" + QString::number(m_id) + "/name").toString();
emit stateChanged();
}
}
}
void Light::setStateFinished(int id, const QVariant &response)
{
foreach (const QVariant &resultVariant, response.toList()) {
QVariantMap result = resultVariant.toMap();
if (result.contains("success")) {
QVariantMap successMap = result.value("success").toMap();
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/on")) {
m_on = successMap.value("/lights/" + QString::number(m_id) + "/state/on").toBool();
}
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/hue")) {
m_hue = successMap.value("/lights/" + QString::number(m_id) + "/state/hue").toInt();
m_colormode = ColorModeHS;
}
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/bri")) {
m_bri = successMap.value("/lights/" + QString::number(m_id) + "/state/bri").toInt();
}
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/sat")) {
m_sat = successMap.value("/lights/" + QString::number(m_id) + "/state/sat").toInt();
m_colormode = ColorModeHS;
}
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/xy")) {
m_xy = successMap.value("/lights/" + QString::number(m_id) + "/state/xy").toPoint();
m_colormode = ColorModeXY;
}
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/ct")) {
m_ct = successMap.value("/lights/" + QString::number(m_id) + "/state/ct").toInt();
m_colormode = ColorModeCT;
}
if (successMap.contains("/lights/" + QString::number(m_id) + "/state/effect")) {
m_effect = successMap.value("/lights/" + QString::number(m_id) + "/state/effect").toString();
}
}
}
emit stateChanged();
if (m_busyStateChangeId == id) {
m_busyTimeout.stop();
m_busyStateChangeId = -1;
if (m_hueDirty || m_satDirty || m_briDirty) {
QVariantMap params;
if (m_hueDirty) {
params.insert("hue", m_dirtyHue);
m_hueDirty = false;
}
if (m_satDirty) {
params.insert("sat", m_dirtySat);
m_satDirty = false;
}
if (m_briDirty) {
params.insert("bri", m_dirtyBri);
m_briDirty = false;
}
// FIXME: There is a bug in the API that it doesn't report back the set state of "sat"
// Lets just assume it always succeeds
m_sat = m_dirtySat;
m_busyStateChangeId = m_bridge->put(QHostAddress(m_ip), m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
m_busyTimeout.start();
} else if(m_ctDirty) {
QVariantMap params;
params.insert("ct", m_dirtyCt);
m_ctDirty = false;
m_busyStateChangeId = m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
m_busyTimeout.start();
} else if (m_xyDirty) {
QVariantMap params;
QVariantList xyList;
xyList << m_dirtyXy.x() << m_dirtyXy.y();
params.insert("xy", xyList);
m_xyDirty = false;
m_busyStateChangeId = m_bridge->put(m_ip, m_username, "lights/" + QString::number(m_id) + "/state", params, this, "setStateFinished");
m_busyTimeout.start();
}
}
}

View File

@ -6,14 +6,18 @@ QT += network
SOURCES += \
devicepluginphilipshue.cpp \
huebridgeconnection.cpp \
light.cpp
#huebridgeconnection.cpp \
#light.cpp \
huebridge.cpp \
huelight.cpp
HEADERS += \
devicepluginphilipshue.h \
huebridgeconnection.h \
light.h \
lightinterface.h
#huebridgeconnection.h \
#light.h \
#lightinterface.h \
huebridge.h \
huelight.h

View File

@ -719,6 +719,7 @@
"UnitRadiant",
"UnitDegreeCelsius",
"UnitDegreeKelvin",
"UnitMired",
"UnitMilliBar",
"UnitBar",
"UnitPascal",