diff --git a/philipshue/devicepluginphilipshue.cpp b/philipshue/devicepluginphilipshue.cpp index a83c5020..5021c18c 100644 --- a/philipshue/devicepluginphilipshue.cpp +++ b/philipshue/devicepluginphilipshue.cpp @@ -74,18 +74,35 @@ void DevicePluginPhilipsHue::init() } -Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +void DevicePluginPhilipsHue::discoverDevices(DeviceDiscoveryInfo *info) { - Q_UNUSED(params) - Q_UNUSED(deviceClassId) + // We're starting a UpnpDiscovery and a NUpnpDiscovery. + // For that, we create a tracking object holding pointers to both of those discoveries. + // Both discoveries add their results to a temporary list. + // Once a discovery is finished, it will remove itself from the tracking object. + // When both discoveries are gone from the tracking object, the results are processed + // deduped (a bridge can be found on both discovieries) and handed over to the DeviceDiscoveryInfo. + // Tracking object DiscoveryJob *discovery = new DiscoveryJob(); + m_discoveries.insert(info, discovery); + + // clean up the discovery job when the DeviceDiscoveryInfo is destroyed (either finished or cancelled) + connect(info, &DeviceDiscoveryInfo::destroyed, this, [this, info](){ + delete m_discoveries.take(info); + }); + qCDebug(dcPhilipsHue()) << "Starting UPnP discovery..."; UpnpDiscoveryReply *upnpReply = hardwareManager()->upnpDiscovery()->discoverDevices("libhue:idl"); discovery->upnpReply = upnpReply; - connect(upnpReply, &UpnpDiscoveryReply::finished, this, [this, upnpReply, discovery](){ - upnpReply->deleteLater(); + // Always clean up the upnp discovery + connect(upnpReply, &UpnpDiscoveryReply::finished, upnpReply, &UpnpDiscoveryReply::deleteLater); + + // Process results if info is still around + connect(upnpReply, &UpnpDiscoveryReply::finished, info, [this, upnpReply, discovery](){ + + // Indicate we're done... discovery->upnpReply = nullptr; if (upnpReply->error() != UpnpDiscoveryReply::UpnpDiscoveryReplyErrorNoError) { @@ -105,10 +122,6 @@ Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId } params.append(Param(bridgeDeviceHostParamTypeId, upnpDevice.hostAddress().toString())); params.append(Param(bridgeDeviceIdParamTypeId, bridgeId)); - // Not known yet... - params.append(Param(bridgeDeviceApiKeyParamTypeId, QString())); - params.append(Param(bridgeDeviceMacParamTypeId, QString())); - params.append(Param(bridgeDeviceZigbeeChannelParamTypeId, -1)); descriptor.setParams(params); qCDebug(dcPhilipsHue()) << "UPnP: Found Hue bridge:" << bridgeId; discovery->results.append(descriptor); @@ -123,7 +136,12 @@ Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId QNetworkRequest request(QUrl("https://www.meethue.com/api/nupnp")); QNetworkReply *nUpnpReply = hardwareManager()->networkManager()->get(request); discovery->nUpnpReply = nUpnpReply; - connect(nUpnpReply, &QNetworkReply::finished, this, [this, nUpnpReply, discovery](){ + + // Always clean up the network reply + connect(nUpnpReply, &QNetworkReply::finished, nUpnpReply, &QNetworkReply::deleteLater); + + // Process results if info is still around + connect(nUpnpReply, &QNetworkReply::finished, info, [this, nUpnpReply, discovery](){ nUpnpReply->deleteLater(); discovery->nUpnpReply = nullptr; @@ -136,6 +154,7 @@ Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId QJsonDocument jsonDoc = QJsonDocument::fromJson(nUpnpReply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qCWarning(dcPhilipsHue) << "N-UPNP discovery JSON error in response" << error.errorString(); + finishDiscovery(discovery); return; } @@ -150,9 +169,6 @@ Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId } params.append(Param(bridgeDeviceHostParamTypeId, bridgeMap.value("internalipaddress").toString())); params.append(Param(bridgeDeviceIdParamTypeId, bridgeId)); - params.append(Param(bridgeDeviceApiKeyParamTypeId, QString())); - params.append(Param(bridgeDeviceMacParamTypeId, QString())); - params.append(Param(bridgeDeviceZigbeeChannelParamTypeId, -1)); descriptor.setParams(params); qCDebug(dcPhilipsHue()) << "N-UPnP: Found Hue bridge:" << bridgeId; discovery->results.append(descriptor); @@ -160,48 +176,93 @@ Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId finishDiscovery(discovery); }); - - return Device::DeviceErrorAsync; } -Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) +void DevicePluginPhilipsHue::finishDiscovery(DevicePluginPhilipsHue::DiscoveryJob *job) { + if (job->upnpReply || job->nUpnpReply) { + // still pending... + return; + } + QHash results; + foreach (DeviceDescriptor result, job->results) { + // dedupe + QString bridgeId = result.params().paramValue(bridgeDeviceIdParamTypeId).toString(); + if (results.contains(bridgeId)) { + qCDebug(dcPhilipsHue()) << "Discarding duplicate search result" << bridgeId; + continue; + } + Device *dev = bridgeForBridgeId(bridgeId); + if (dev) { + qCDebug(dcPhilipsHue()) << "Bridge already added in system:" << bridgeId; + result.setDeviceId(dev->id()); + } + results.insert(bridgeId, result); + + } + + DeviceDiscoveryInfo *info = m_discoveries.key(job); + + info->addDeviceDescriptors(results.values()); + info->finish(Device::DeviceErrorNoError); +} + +void DevicePluginPhilipsHue::startPairing(DevicePairingInfo *info) +{ + Q_ASSERT_X(info->deviceClassId() == bridgeDeviceClassId, "DevicePluginPhilipsHue::startPairing", "Unexpected device class."); + + info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please press the button on the Hue Bridge within 30 seconds before you continue")); +} + +void DevicePluginPhilipsHue::setupDevice(DeviceSetupInfo *info) +{ + Device *device = info->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) - foreach (HueBridge *b, m_unconfiguredBridges) { - 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 - device->setParamValue(bridgeDeviceApiKeyParamTypeId, b->apiKey()); - device->setParamValue(bridgeDeviceZigbeeChannelParamTypeId, b->zigbeeChannel()); - device->setParamValue(bridgeDeviceMacParamTypeId, b->macAddress()); - m_bridges.insert(b, device); - device->setStateValue(bridgeConnectedStateTypeId, true); - discoverBridgeDevices(b); - return Device::DeviceSetupStatusSuccess; - } - } - // Loaded bridge qCDebug(dcPhilipsHue) << "Setup Hue Bridge" << device->params(); + pluginStorage()->beginGroup(device->id().toString()); + QString apiKey = pluginStorage()->value("apiKey").toString(); + pluginStorage()->endGroup(); + + // For legacy reasons we might not have the api key in the pluginstorage yet. Check if there is a key in the device params. + if (apiKey.isEmpty()) { + qCWarning(dcPhilipsHue()) << "Loading api key from device params!"; + // Used to be in json, not any more. + ParamTypeId bridgeDeviceApiKeyParamTypeId = ParamTypeId("{8bf5776a-d5a6-4600-8b27-481f0d803a8f}"); + apiKey = device->paramValue(bridgeDeviceApiKeyParamTypeId).toString(); + } + + if (apiKey.isEmpty()) { + qCWarning(dcPhilipsHue()) << "Failed to load api key"; + info->finish(Device::DeviceErrorAuthenticationFailure, QT_TR_NOOP("Not authenticated to bridge. Please reconfigure the device.")); + return; + } + HueBridge *bridge = new HueBridge(this); bridge->setId(device->paramValue(bridgeDeviceIdParamTypeId).toString()); - bridge->setApiKey(device->paramValue(bridgeDeviceApiKeyParamTypeId).toString()); + bridge->setApiKey(apiKey); bridge->setHostAddress(QHostAddress(device->paramValue(bridgeDeviceHostParamTypeId).toString())); - bridge->setMacAddress(device->paramValue(bridgeDeviceMacParamTypeId).toString()); - bridge->setZigbeeChannel(device->paramValue(bridgeDeviceZigbeeChannelParamTypeId).toInt()); m_bridges.insert(bridge, device); discoverBridgeDevices(bridge); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } + // At this point we need to have a bridge or we can't continue anyways + HueBridge *bridge = m_bridges.key(myDevices().findById(device->parentId())); + if (!bridge) { + qCWarning(dcPhilipsHue()) << "No hue bridge set up. Cannot continue."; + info->finish(Device::DeviceErrorHardwareNotAvailable); + return; + } + + // Hue color light if (device->deviceClassId() == colorLightDeviceClassId) { qCDebug(dcPhilipsHue) << "Setup Hue color light" << device->params(); @@ -220,7 +281,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) refreshLight(device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } // Hue color temperature light @@ -241,7 +302,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) refreshLight(device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } // Hue white light @@ -287,7 +348,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) m_lights.insert(hueLight, device); refreshLight(device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } // Hue remote @@ -332,7 +393,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) connect(hueRemote, &HueRemote::buttonPressed, this, &DevicePluginPhilipsHue::onRemoteButtonEvent); m_remotes.insert(hueRemote, device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } // Hue tap @@ -346,7 +407,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) connect(hueTap, &HueRemote::buttonPressed, this, &DevicePluginPhilipsHue::onRemoteButtonEvent); m_remotes.insert(hueTap, device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } // Hue Motion sensor @@ -378,7 +439,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) m_motionSensors.insert(motionSensor, device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } // Hue Outdoor sensor @@ -410,12 +471,10 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) m_motionSensors.insert(outdoorSensor, device); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } qCWarning(dcPhilipsHue()) << "Unhandled setupDevice call" << device->deviceClassId(); - - return Device::DeviceSetupStatusFailure; } void DevicePluginPhilipsHue::deviceRemoved(Device *device) @@ -456,31 +515,65 @@ void DevicePluginPhilipsHue::deviceRemoved(Device *device) } } -Device::DeviceSetupStatus DevicePluginPhilipsHue::confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList ¶ms, const QString &secret) +void DevicePluginPhilipsHue::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) { + Q_UNUSED(username) Q_UNUSED(secret) - qCDebug(dcPhilipsHue()) << "Confirming pairing for transactionId" << pairingTransactionId; - if (deviceClassId != bridgeDeviceClassId) - return Device::DeviceSetupStatusFailure; - - PairingInfo *pairingInfo = new PairingInfo(this); - pairingInfo->setPairingTransactionId(pairingTransactionId); - pairingInfo->setHost(QHostAddress(params.paramValue(bridgeDeviceHostParamTypeId).toString())); - QVariantMap deviceTypeParam; deviceTypeParam.insert("devicetype", "nymea"); QJsonDocument jsonDoc = QJsonDocument::fromVariant(deviceTypeParam); - QNetworkRequest request(QUrl("http://" + pairingInfo->host().toString() + "/api")); + QString host = info->params().paramValue(bridgeDeviceHostParamTypeId).toString(); + QNetworkRequest request(QUrl("http://" + host + "/api")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply *reply = hardwareManager()->networkManager()->post(request, jsonDoc.toJson()); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); - m_pairingRequests.insert(reply, pairingInfo); + connect(reply, &QNetworkReply::finished, info, [this, info, reply](){ + if (reply->error() != QNetworkReply::NoError) { + info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("Error connecting to hue bridge.")); + return; + } + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); - return Device::DeviceSetupStatusAsync; + // check JSON error + if (error.error != QJsonParseError::NoError) { + qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); + info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("Received unexpected data from hue bridge.")); + return; + } + + // check response error + if (data.contains("error")) { + if (!jsonDoc.toVariant().toList().isEmpty()) { + qCWarning(dcPhilipsHue) << "Failed to pair Hue Bridge:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString(); + } else { + qCWarning(dcPhilipsHue) << "Failed to pair Hue Bridge: Invalid error message format"; + } + info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("An error happened pairing the hue bridge.")); + return; + } + + QString apiKey = jsonDoc.toVariant().toList().first().toMap().value("success").toMap().value("username").toString(); + + if (apiKey.isEmpty()) { + qCWarning(dcPhilipsHue) << "Failed to pair Hue Bridge: did not get any key from the bridge"; + return info->finish(Device::DeviceErrorAuthenticationFailure, QT_TR_NOOP("The hue bridge has rejected the connection request.")); + } + + qCDebug(dcPhilipsHue) << "Got api key from bridge:" << apiKey; + + // All good. Store the API key + pluginStorage()->beginGroup(info->deviceId().toString()); + pluginStorage()->setValue("apiKey", apiKey); + pluginStorage()->endGroup(); + + info->finish(Device::DeviceErrorNoError); + }); } void DevicePluginPhilipsHue::networkManagerReplyReady() @@ -493,29 +586,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady() // qCDebug(dcPhilipsHue()) << "Hue reply:" << status << reply->error() << reply->errorString(); // create user finished - if (m_pairingRequests.contains(reply)) { - PairingInfo *pairingInfo = m_pairingRequests.take(reply); - - // check HTTP status code - if (status != 200 || reply->error() != QNetworkReply::NoError) { - qCWarning(dcPhilipsHue) << "Request error:" << status << reply->errorString(); - pairingInfo->deleteLater(); - return; - } - processPairingResponse(pairingInfo, reply->readAll()); - - } else if (m_informationRequests.contains(reply)) { - PairingInfo *pairingInfo = m_informationRequests.take(reply); - - // check HTTP status code - if (status != 200 || reply->error() != QNetworkReply::NoError) { - qCWarning(dcPhilipsHue) << "Request error:" << status << reply->errorString(); - pairingInfo->deleteLater(); - return; - } - processInformationResponse(pairingInfo, reply->readAll()); - - } else if (m_bridgeLightsDiscoveryRequests.contains(reply)) { + if (m_bridgeLightsDiscoveryRequests.contains(reply)) { Device *device = m_bridgeLightsDiscoveryRequests.take(reply); // check HTTP status code @@ -598,18 +669,6 @@ void DevicePluginPhilipsHue::networkManagerReplyReady() } processSensorsRefreshResponse(device, reply->readAll()); - } else if (m_asyncActions.contains(reply)) { - QPair actionInfo = m_asyncActions.take(reply); - - // check HTTP status code - if (status != 200 || reply->error() != QNetworkReply::NoError) { - qCWarning(dcPhilipsHue) << "Execute Hue Light action request error:" << status << reply->errorString(); - bridgeReachableChanged(actionInfo.first, false); - emit actionExecutionFinished(actionInfo.second, Device::DeviceErrorHardwareNotAvailable); - return; - } - processActionResponse(actionInfo.first, actionInfo.second, reply->readAll()); - } else if (m_setNameRequests.contains(reply)) { Device *device = m_setNameRequests.take(reply); @@ -637,151 +696,71 @@ void DevicePluginPhilipsHue::onDeviceNameChanged() } } -void DevicePluginPhilipsHue::finishDiscovery(DevicePluginPhilipsHue::DiscoveryJob *job) +void DevicePluginPhilipsHue::executeAction(DeviceActionInfo *info) { - if (job->upnpReply || job->nUpnpReply) { - // still pending... - return; - } - QHash results; - foreach (DeviceDescriptor result, job->results) { - // dedupe - QString bridgeId = result.params().paramValue(bridgeDeviceIdParamTypeId).toString(); - if (results.contains(bridgeId)) { - qCDebug(dcPhilipsHue()) << "Discarding duplicate search result" << bridgeId; - continue; - } - Device *dev = bridgeForBridgeId(bridgeId); - if (dev) { - qCDebug(dcPhilipsHue()) << "Bridge already added in system:" << bridgeId; - result.setDeviceId(dev->id()); - } - results.insert(bridgeId, result); + Device *device = info->device(); + Action action = info->action(); - } - emit devicesDiscovered(bridgeDeviceClassId, results.values()); - delete job; -} - -Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const Action &action) -{ qCDebug(dcPhilipsHue) << "Execute action" << action.actionTypeId() << action.params(); - // Color light - if (device->deviceClassId() == colorLightDeviceClassId) { + QNetworkReply *reply = nullptr; + + // lights + if (device->deviceClassId() == colorLightDeviceClassId || + device->deviceClassId() == colorTemperatureLightDeviceClassId || + device->deviceClassId() == dimmableLightDeviceClassId) { + HueLight *light = m_lights.key(device); if (!light->reachable()) { qCWarning(dcPhilipsHue) << "Light" << light->name() << "not reachable"; - return Device::DeviceErrorHardwareNotAvailable; + return info->finish(Device::DeviceErrorHardwareNotAvailable); } if (action.actionTypeId() == colorLightPowerActionTypeId) { QPair request = light->createSetPowerRequest(action.param(colorLightPowerActionPowerParamTypeId).value().toBool()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorLightColorActionTypeId) { QPair request = light->createSetColorRequest(action.param(colorLightColorActionColorParamTypeId).value().value()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply,QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorLightBrightnessActionTypeId) { QPair request = light->createSetBrightnessRequest(percentageToBrightness(action.param(colorLightBrightnessActionBrightnessParamTypeId).value().toInt())); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorLightEffectActionTypeId) { QPair request = light->createSetEffectRequest(action.param(colorLightEffectActionEffectParamTypeId).value().toString()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorLightAlertActionTypeId) { QPair request = light->createFlashRequest(action.param(colorLightAlertActionAlertParamTypeId).value().toString()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorLightColorTemperatureActionTypeId) { QPair request = light->createSetTemperatureRequest(action.param(colorLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } - return Device::DeviceErrorActionTypeNotFound; - } - - // Color temperature light - if (device->deviceClassId() == colorTemperatureLightDeviceClassId) { - HueLight *light = m_lights.key(device); - - if (!light->reachable()) { - qCWarning(dcPhilipsHue) << "Light" << light->name() << "not reachable"; - return Device::DeviceErrorHardwareNotAvailable; - } - - if (action.actionTypeId() == colorTemperatureLightPowerActionTypeId) { + // Color temperature light + else if (action.actionTypeId() == colorTemperatureLightPowerActionTypeId) { QPair request = light->createSetPowerRequest(action.param(colorTemperatureLightPowerActionPowerParamTypeId).value().toBool()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorTemperatureLightBrightnessActionTypeId) { QPair request = light->createSetBrightnessRequest(percentageToBrightness(action.param(colorTemperatureLightBrightnessActionBrightnessParamTypeId).value().toInt())); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorTemperatureLightAlertActionTypeId) { QPair request = light->createFlashRequest(action.param(colorTemperatureLightAlertActionAlertParamTypeId).value().toString()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == colorTemperatureLightColorTemperatureActionTypeId) { QPair request = light->createSetTemperatureRequest(action.param(colorTemperatureLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } - return Device::DeviceErrorActionTypeNotFound; - } - - // Dimmable light - if (device->deviceClassId() == dimmableLightDeviceClassId) { - HueLight *light = m_lights.key(device); - - if (!light->reachable()) { - qCWarning(dcPhilipsHue) << "Light" << light->name() << "not reachable"; - return Device::DeviceErrorHardwareNotAvailable; - } - - if (action.actionTypeId() == dimmableLightPowerActionTypeId) { + // Dimmable light + else if (action.actionTypeId() == dimmableLightPowerActionTypeId) { QPair request = light->createSetPowerRequest(action.param(dimmableLightPowerActionPowerParamTypeId).value().toBool()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == dimmableLightBrightnessActionTypeId) { QPair request = light->createSetBrightnessRequest(percentageToBrightness(action.param(dimmableLightBrightnessActionBrightnessParamTypeId).value().toInt())); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == dimmableLightAlertActionTypeId) { QPair request = light->createFlashRequest(action.param(dimmableLightAlertActionAlertParamTypeId).value().toString()); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } - return Device::DeviceErrorActionTypeNotFound; } // Hue bridge @@ -789,28 +768,64 @@ Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const HueBridge *bridge = m_bridges.key(device); if (!device->stateValue(bridgeConnectedStateTypeId).toBool()) { qCWarning(dcPhilipsHue) << "Bridge" << bridge->hostAddress().toString() << "not reachable"; - return Device::DeviceErrorHardwareNotAvailable; + return info->finish(Device::DeviceErrorHardwareNotAvailable); } if (action.actionTypeId() == bridgeSearchNewDevicesActionTypeId) { searchNewDevices(bridge, action.param(bridgeSearchNewDevicesActionSerialParamTypeId).value().toString()); - return Device::DeviceErrorNoError; + return info->finish(Device::DeviceErrorNoError); } else if (action.actionTypeId() == bridgeCheckForUpdatesActionTypeId) { QPair request = bridge->createCheckUpdatesRequest(); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } else if (action.actionTypeId() == bridgeUpgradeActionTypeId) { QPair request = bridge->createUpgradeRequest(); - QNetworkReply *reply = hardwareManager()->networkManager()->put(request.first, request.second); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_asyncActions.insert(reply, QPair(device, action.id())); - return Device::DeviceErrorAsync; + reply = hardwareManager()->networkManager()->put(request.first, request.second); } - return Device::DeviceErrorActionTypeNotFound; } - return Device::DeviceErrorDeviceClassNotFound; + + if (!reply) { + qCWarning(dcPhilipsHue()) << "Unhandled Hue action! Plugin bug!"; + Q_ASSERT_X(false, "HuePlugin", "Unhandled action"); + info->finish(Device::DeviceErrorUnsupportedFeature); + return; + } + + // Always clean up the reply when it finishes + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + + // Handle response if info is still around + connect(reply, &QNetworkReply::finished, info, [this, info, reply](){ + if (reply->error() != QNetworkReply::NoError) { + info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("Error sending command to hue bridge.")); + return; + } + + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + + if (error.error != QJsonParseError::NoError) { + qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); + info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("Received unexpected data from hue bridge.")); + return; + } + + if (data.contains("error")) { + if (!jsonDoc.toVariant().toList().isEmpty()) { + qCWarning(dcPhilipsHue) << "Failed to execute Hue action:" << jsonDoc.toJson(); //jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString(); + } else { + qCWarning(dcPhilipsHue) << "Failed to execute Hue action: Invalid error message format"; + } + info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("An unexpected error happened when sending the command to the hue bridge.")); + return; + } + + if (info->device()->deviceClassId() != bridgeDeviceClassId) { + m_lights.key(info->device())->processActionResponse(jsonDoc.toVariant().toList()); + } + + info->finish(Device::DeviceErrorNoError); + }); } void DevicePluginPhilipsHue::lightStateChanged() @@ -1089,9 +1104,7 @@ void DevicePluginPhilipsHue::processBridgeLightDiscoveryResponse(Device *device, } // Create Lights if not already added - QList colorLightDescriptors; - QList colorTemperatureLightDescriptors; - QList dimmableLightDescriptors; + DeviceDescriptors descriptors; QVariantMap lightsMap = jsonDoc.toVariant().toMap(); foreach (QString lightId, lightsMap.keys()) { @@ -1111,7 +1124,7 @@ void DevicePluginPhilipsHue::processBridgeLightDiscoveryResponse(Device *device, params.append(Param(dimmableLightDeviceUuidParamTypeId, uuid)); params.append(Param(dimmableLightDeviceLightIdParamTypeId, lightId)); descriptor.setParams(params); - dimmableLightDescriptors.append(descriptor); + descriptors.append(descriptor); qCDebug(dcPhilipsHue) << "Found new dimmable light" << lightMap.value("name").toString() << model; } else if (lightMap.value("type").toString() == "Color temperature light") { @@ -1122,7 +1135,7 @@ void DevicePluginPhilipsHue::processBridgeLightDiscoveryResponse(Device *device, params.append(Param(colorTemperatureLightDeviceUuidParamTypeId, uuid)); params.append(Param(colorTemperatureLightDeviceLightIdParamTypeId, lightId)); descriptor.setParams(params); - colorTemperatureLightDescriptors.append(descriptor); + descriptors.append(descriptor); qCDebug(dcPhilipsHue) << "Found new color temperature light" << lightMap.value("name").toString() << model; } else { @@ -1133,17 +1146,14 @@ void DevicePluginPhilipsHue::processBridgeLightDiscoveryResponse(Device *device, params.append(Param(colorLightDeviceUuidParamTypeId, uuid)); params.append(Param(colorLightDeviceLightIdParamTypeId, lightId)); descriptor.setParams(params); - colorLightDescriptors.append(descriptor); + descriptors.append(descriptor); qCDebug(dcPhilipsHue) << "Found new color light" << lightMap.value("name").toString() << model; } } - if (!colorLightDescriptors.isEmpty()) - emit autoDevicesAppeared(colorLightDeviceClassId, colorLightDescriptors); - if (!colorTemperatureLightDescriptors.isEmpty()) - emit autoDevicesAppeared(colorTemperatureLightDeviceClassId, colorTemperatureLightDescriptors); - if (!dimmableLightDescriptors.isEmpty()) - emit autoDevicesAppeared(dimmableLightDeviceClassId, dimmableLightDescriptors); + if (!descriptors.isEmpty()) { + emit autoDevicesAppeared(descriptors); + } } void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device, const QByteArray &data) @@ -1187,7 +1197,7 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device params.append(Param(remoteDeviceUuidParamTypeId, uuid)); params.append(Param(remoteDeviceSensorIdParamTypeId, sensorId)); descriptor.setParams(params); - emit autoDevicesAppeared(remoteDeviceClassId, {descriptor}); + emit autoDevicesAppeared({descriptor}); qCDebug(dcPhilipsHue) << "Found new remote" << sensorMap.value("name").toString() << model; } else if (sensorMap.value("type").toString() == "ZGPSwitch") { DeviceDescriptor descriptor(tapDeviceClassId, sensorMap.value("name").toString(), "Philips Hue Tap", device->id()); @@ -1196,7 +1206,7 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device params.append(Param(tapDeviceModelIdParamTypeId, model)); params.append(Param(tapDeviceSensorIdParamTypeId, sensorId)); descriptor.setParams(params); - emit autoDevicesAppeared(tapDeviceClassId, {descriptor}); + emit autoDevicesAppeared({descriptor}); qCDebug(dcPhilipsHue()) << "Found hue tap:" << sensorMap << tapDeviceClassId; } else if (model == "SML001" || model == "SML002") { @@ -1294,7 +1304,7 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device params.append(Param(motionSensorDeviceSensorIdLightParamTypeId, motionSensor->lightSensorId())); descriptor.setParams(params); qCDebug(dcPhilipsHue()) << "Found new motion sensor" << baseUuid << motionSensorDeviceClassId; - emit autoDevicesAppeared(motionSensorDeviceClassId, {descriptor}); + emit autoDevicesAppeared({descriptor}); } else if (motionSensor->modelId() == "SML002") { DeviceDescriptor descriptor(outdoorSensorDeviceClassId, tr("Philips Hue Outdoor sensor"), baseUuid, device->id()); ParamList params; @@ -1308,7 +1318,7 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device params.append(Param(outdoorSensorDeviceSensorIdLightParamTypeId, motionSensor->lightSensorId())); descriptor.setParams(params); qCDebug(dcPhilipsHue()) << "Found new outdoor sensor" << baseUuid << outdoorSensorDeviceClassId; - emit autoDevicesAppeared(outdoorSensorDeviceClassId, {descriptor}); + emit autoDevicesAppeared({descriptor}); } } @@ -1468,7 +1478,6 @@ void DevicePluginPhilipsHue::processSetNameResponse(Device *device, const QByteA // check JSON error if (error.error != QJsonParseError::NoError) { qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); - emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure); return; } @@ -1479,7 +1488,6 @@ void DevicePluginPhilipsHue::processSetNameResponse(Device *device, const QByteA } else { qCWarning(dcPhilipsHue) << "Failed to set name of Hue: Invalid error message format"; } - emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure); return; } @@ -1488,119 +1496,6 @@ void DevicePluginPhilipsHue::processSetNameResponse(Device *device, const QByteA } -void DevicePluginPhilipsHue::processPairingResponse(PairingInfo *pairingInfo, const QByteArray &data) -{ - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); - - // check JSON error - if (error.error != QJsonParseError::NoError) { - qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); - emit pairingFinished(pairingInfo->pairingTransactionId(), Device::DeviceSetupStatusFailure); - pairingInfo->deleteLater(); - return; - } - - // check response error - if (data.contains("error")) { - if (!jsonDoc.toVariant().toList().isEmpty()) { - qCWarning(dcPhilipsHue) << "Failed to pair Hue Bridge:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString(); - } else { - qCWarning(dcPhilipsHue) << "Failed to pair Hue Bridge: Invalid error message format"; - } - emit pairingFinished(pairingInfo->pairingTransactionId(), Device::DeviceSetupStatusFailure); - pairingInfo->deleteLater(); - return; - } - - pairingInfo->setApiKey(jsonDoc.toVariant().toList().first().toMap().value("success").toMap().value("username").toString()); - - qCDebug(dcPhilipsHue) << "Got api key from bridge:" << pairingInfo->apiKey(); - - if (pairingInfo->apiKey().isEmpty()) { - qCWarning(dcPhilipsHue) << "Failed to pair Hue Bridge: did not get any key from the bridge"; - emit pairingFinished(pairingInfo->pairingTransactionId(), Device::DeviceSetupStatusFailure); - pairingInfo->deleteLater(); - return; - } - - // Paired successfully, check bridge information - QNetworkRequest request(QUrl("http://" + pairingInfo->host().toString() + "/api/" + pairingInfo->apiKey() + "/config")); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QNetworkReply *reply = hardwareManager()->networkManager()->get(request); - connect(reply, &QNetworkReply::finished, this, &DevicePluginPhilipsHue::networkManagerReplyReady); - m_informationRequests.insert(reply, pairingInfo); -} - -void DevicePluginPhilipsHue::processInformationResponse(PairingInfo *pairingInfo, const QByteArray &data) -{ - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); - - // check JSON error - if (error.error != QJsonParseError::NoError) { - qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); - emit pairingFinished(pairingInfo->pairingTransactionId(), Device::DeviceSetupStatusFailure); - pairingInfo->deleteLater(); - return; - } - - QVariantMap response = jsonDoc.toVariant().toMap(); - - // check response error - if (response.contains("error")) { - qCWarning(dcPhilipsHue) << "Failed to get information from Hue Bridge:" << response.value("error").toMap().value("description").toString(); - emit pairingFinished(pairingInfo->pairingTransactionId(), Device::DeviceSetupStatusFailure); - pairingInfo->deleteLater(); - return; - } - - // create Bridge - HueBridge *bridge = new HueBridge(this); - bridge->setId(response.value("bridgeid").toString()); - bridge->setApiKey(pairingInfo->apiKey()); - bridge->setHostAddress(pairingInfo->host()); - bridge->setApiVersion(response.value("apiversion").toString()); - bridge->setSoftwareVersion(response.value("swversion").toString()); - bridge->setMacAddress(response.value("mac").toString()); - bridge->setName(response.value("name").toString()); - bridge->setZigbeeChannel(response.value("zigbeechannel").toInt()); - - m_unconfiguredBridges.append(bridge); - - emit pairingFinished(pairingInfo->pairingTransactionId(), Device::DeviceSetupStatusSuccess); - pairingInfo->deleteLater(); -} - -void DevicePluginPhilipsHue::processActionResponse(Device *device, const ActionId actionId, const QByteArray &data) -{ - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); - - // check JSON error - if (error.error != QJsonParseError::NoError) { - qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); - emit actionExecutionFinished(actionId, Device::DeviceErrorHardwareFailure); - return; - } - - // check response error - if (data.contains("error")) { - if (!jsonDoc.toVariant().toList().isEmpty()) { - qCWarning(dcPhilipsHue) << "Failed to execute Hue action:" << jsonDoc.toJson(); //jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString(); - } else { - qCWarning(dcPhilipsHue) << "Failed to execute Hue action: Invalid error message format"; - } - emit actionExecutionFinished(actionId, Device::DeviceErrorHardwareFailure); - return; - } - - if (device->deviceClassId() != bridgeDeviceClassId) - m_lights.key(device)->processActionResponse(jsonDoc.toVariant().toList()); - - emit actionExecutionFinished(actionId, Device::DeviceErrorNoError); -} - void DevicePluginPhilipsHue::bridgeReachableChanged(Device *device, const bool &reachable) { if (reachable) { diff --git a/philipshue/devicepluginphilipshue.h b/philipshue/devicepluginphilipshue.h index 5dc275ab..bc5d0334 100644 --- a/philipshue/devicepluginphilipshue.h +++ b/philipshue/devicepluginphilipshue.h @@ -28,7 +28,6 @@ #include "huebridge.h" #include "huelight.h" #include "hueremote.h" -#include "pairinginfo.h" #include "huemotionsensor.h" #include "huemotionsensor.h" @@ -50,13 +49,12 @@ public: ~DevicePluginPhilipsHue(); void init() override; - Device::DeviceSetupStatus setupDevice(Device *device) override; - Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; + void discoverDevices(DeviceDiscoveryInfo *info) override; + void startPairing(DevicePairingInfo *info) override; + void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override; + void setupDevice(DeviceSetupInfo *info) override; void deviceRemoved(Device *device) override; - Device::DeviceSetupStatus confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList ¶ms, const QString &secret) override; - -public slots: - Device::DeviceError executeAction(Device *device, const Action &action); + void executeAction(DeviceActionInfo *info) override; private slots: void lightStateChanged(); @@ -79,18 +77,15 @@ private: public: UpnpDiscoveryReply* upnpReply; QNetworkReply* nUpnpReply; - QList results; + DeviceDescriptors results; }; + QHash m_discoveries; void finishDiscovery(DiscoveryJob* job); PluginTimer *m_pluginTimer1Sec = nullptr; PluginTimer *m_pluginTimer5Sec = nullptr; PluginTimer *m_pluginTimer15Sec = nullptr; - QHash m_pairingRequests; - QHash m_informationRequests; - - QList m_unconfiguredBridges; QList m_unconfiguredLights; QHash m_lightRefreshRequests; @@ -129,8 +124,6 @@ private: void processLightsRefreshResponse(Device *device, const QByteArray &data); void processSensorsRefreshResponse(Device *device, const QByteArray &data); void processSetNameResponse(Device *device, const QByteArray &data); - void processPairingResponse(PairingInfo *pairingInfo, const QByteArray &data); - void processInformationResponse(PairingInfo *pairingInfo, const QByteArray &data); void processActionResponse(Device *device, const ActionId actionId, const QByteArray &data); void bridgeReachableChanged(Device *device, const bool &reachable); diff --git a/philipshue/devicepluginphilipshue.json b/philipshue/devicepluginphilipshue.json index c4e02e27..59d7bcb2 100644 --- a/philipshue/devicepluginphilipshue.json +++ b/philipshue/devicepluginphilipshue.json @@ -15,16 +15,7 @@ "interfaces": ["gateway"], "createMethods": ["discovery"], "setupMethod": "pushButton", - "pairingInfo": "Please press the button on the Hue Bridge within 30 seconds before you continue", "paramTypes": [ - { - "id": "8bf5776a-d5a6-4600-8b27-481f0d803a8f", - "name": "apiKey", - "displayName": "api key", - "type" : "QString", - "inputType": "TextLine", - "readOnly": true - }, { "id": "1845975b-1184-4440-bc0d-73d53a9f683c", "name": "host", @@ -33,34 +24,12 @@ "inputType": "IPv4Address", "readOnly": true }, - { - "id": "2c67203d-a308-45ec-9a08-fc4183c06ff8", - "name": "mac", - "displayName": "mac address", - "type" : "QString", - "inputType": "MacAddress", - "readOnly": true - }, { "id": "a496feb0-3b7b-46cb-a63a-e063447d6b1d", "name": "id", "displayName": "id", "type" : "QString", "readOnly": true - }, - { - "id": "ea228c4d-975c-4b43-9445-7c9a907c29d6", - "name": "softwareVersion", - "displayName": "software version", - "type" : "QString", - "readOnly": true - }, - { - "id": "53170394-956c-4511-b3a8-2c8a502ef1ed", - "name": "zigbeeChannel", - "displayName": "zigbee channel", - "type" : "int", - "readOnly": true } ], "stateTypes": [ @@ -70,7 +39,8 @@ "displayName": "reachable", "displayNameEvent": "reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "7a230e89-c4ce-4276-90e0-6a9ddb890603", @@ -172,7 +142,8 @@ "displayName": "reachable", "displayNameEvent": "reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "90aaffe5-6a76-47d2-a14a-550f60390245", @@ -300,7 +271,8 @@ "displayName": "reachable", "displayNameEvent": "reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "4e579f6a-e4b3-4876-804a-9fcc066f90f9", @@ -403,7 +375,8 @@ "displayName": "reachable", "displayNameEvent": "reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "5995ecb7-b5e5-4f6a-b4d6-33c93497e5fb", @@ -494,7 +467,8 @@ "displayName": "reachable", "displayNameEvent": "reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "683e493a-9796-4d5e-b0e3-61cb178d5819", @@ -590,7 +564,8 @@ "displayName": "reachable", "displayNameEvent": "reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false } ], "eventTypes": [ @@ -693,7 +668,8 @@ "displayName": "Reachable", "displayNameEvent": "Reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "19b18531-61e5-4998-89d1-765d740e24eb", @@ -834,7 +810,8 @@ "displayName": "Reachable", "displayNameEvent": "Reachable changed", "defaultValue": false, - "type": "bool" + "type": "bool", + "cached": false }, { "id": "ac463b30-24af-4352-84da-19a3ffc906bd", diff --git a/philipshue/pairinginfo.cpp b/philipshue/pairinginfo.cpp deleted file mode 100644 index 24dd9ac7..00000000 --- a/philipshue/pairinginfo.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * * - * 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 * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "pairinginfo.h" - -PairingInfo::PairingInfo(QObject *parent) : - QObject(parent) -{ -} - -PairingTransactionId PairingInfo::pairingTransactionId() const -{ - return m_pairingTransactionId; -} - -void PairingInfo::setPairingTransactionId(const PairingTransactionId &pairingTransactionId) -{ - m_pairingTransactionId = pairingTransactionId; -} - -QHostAddress PairingInfo::host() const -{ - return m_host; -} - -void PairingInfo::setHost(const QHostAddress &host) -{ - m_host = host; -} - -QString PairingInfo::apiKey() const -{ - return m_apiKey; -} - -void PairingInfo::setApiKey(const QString &apiKey) -{ - m_apiKey = apiKey; -} diff --git a/philipshue/pairinginfo.h b/philipshue/pairinginfo.h deleted file mode 100644 index 17931120..00000000 --- a/philipshue/pairinginfo.h +++ /dev/null @@ -1,52 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * * - * 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 * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef PAIRINGINFO_H -#define PAIRINGINFO_H - -#include -#include - -#include "typeutils.h" - -class PairingInfo : public QObject -{ - Q_OBJECT -public: - explicit PairingInfo(QObject *parent = 0); - - PairingTransactionId pairingTransactionId() const; - void setPairingTransactionId(const PairingTransactionId &pairingTransactionId); - - QHostAddress host() const; - void setHost(const QHostAddress &host); - - QString apiKey() const; - void setApiKey(const QString &apiKey); - -private: - PairingTransactionId m_pairingTransactionId; - QHostAddress m_host; - QString m_apiKey; -}; - -#endif // PAIRINGINFO_H diff --git a/philipshue/philipshue.pro b/philipshue/philipshue.pro index d666a866..ca6d60a6 100644 --- a/philipshue/philipshue.pro +++ b/philipshue/philipshue.pro @@ -11,7 +11,6 @@ SOURCES += \ huebridge.cpp \ huelight.cpp \ huemotionsensor.cpp \ - pairinginfo.cpp \ hueremote.cpp \ huedevice.cpp @@ -23,7 +22,6 @@ HEADERS += \ huebridge.h \ huelight.h \ huemotionsensor.h \ - pairinginfo.h \ hueremote.h \ huedevice.h