diff --git a/philipshue/bridgeconnection.cpp b/philipshue/bridgeconnection.cpp index bd01097c..4db4f9c4 100644 --- a/philipshue/bridgeconnection.cpp +++ b/philipshue/bridgeconnection.cpp @@ -138,6 +138,13 @@ void BridgeConnection::discoverBridgeDevices() //m_bridgeSensorsDiscoveryRequests.insert(reply, device); } +void BridgeConnection::checkForUpdates() +{ + QPair request = m_bridge->createCheckUpdatesRequest(); + QNetworkReply *reply = m_hardwareManager->networkManager()->put(request.first, request.second); + connect(reply, &QNetworkReply::finished, this, &BridgeConnection::networkManagerReplyReady); +} + void BridgeConnection::searchNewDevices(const QString &serialNumber) { qCDebug(dcPhilipsHue) << "Discover bridge devices" << m_bridge->hostAddress(); @@ -148,7 +155,7 @@ void BridgeConnection::searchNewDevices(const QString &serialNumber) //m_bridgeSearchDevicesRequests.insert(reply, device); } -void BridgeConnection::setPower(const QString &uuid, bool power) +QUuid BridgeConnection::setPower(const QString &uuid, bool power) { HueLight *light = m_lights.value(uuid); QPair request = light->createSetPowerRequest(power); @@ -156,7 +163,7 @@ void BridgeConnection::setPower(const QString &uuid, bool power) connect(reply, &QNetworkReply::finished, this, &BridgeConnection::networkManagerReplyReady); } -void BridgeConnection::setBrightness(const QString &uuid, quint8 percent) +QUuid BridgeConnection::setBrightness(const QString &uuid, quint8 percent) { HueLight *light = m_lights.value(uuid); QPair request = light->createSetBrightnessRequest(percent); @@ -164,7 +171,7 @@ void BridgeConnection::setBrightness(const QString &uuid, quint8 percent) connect(reply, &QNetworkReply::finished, this, &BridgeConnection::networkManagerReplyReady); } -void BridgeConnection::setColor(const QString &uuid, QColor color) +QUuid BridgeConnection::setColor(const QString &uuid, QColor color) { HueLight *light = m_lights.value(uuid); QPair request = light->createSetColorRequest(color); @@ -172,7 +179,7 @@ void BridgeConnection::setColor(const QString &uuid, QColor color) connect(reply, &QNetworkReply::finished, this, &BridgeConnection::networkManagerReplyReady); } -void BridgeConnection::setEffect(const QString &uuid, const QString &effect) +QUuid BridgeConnection::setEffect(const QString &uuid, const QString &effect) { HueLight *light = m_lights.value(uuid); QPair request = light->createSetEffectRequest(effect); @@ -198,9 +205,9 @@ void BridgeConnection::setFlash(const QString &uuid, const QString &mode) -void BridgeConnection::setLightName(const QString &uuid, const QString &name) +QUuid BridgeConnection::setLightName(const QString &deviceUuid, const QString &name) { - HueLight *light = m_lights.value(uuid); + HueLight *light = m_lights.value(deviceUuid); QVariantMap requestMap; requestMap.insert("name", name); @@ -212,15 +219,16 @@ void BridgeConnection::setLightName(const QString &uuid, const QString &name) QNetworkReply *reply = m_hardwareManager->networkManager()->put(request,jsonDoc.toJson()); connect(reply, &QNetworkReply::finished, this, &BridgeConnection::networkManagerReplyReady); - //m_setNameRequests.insert(reply, device); + QUuid actionUuid = scheduleActionRequest(request); // needs request, device uuid, request type + return actionUuid; } void BridgeConnection::setRemoteName(const QString &uuid, const QString &name) { - HueRemote *remote = m_remotes.balue(uuid); + HueRemote *remote = m_remotes.value(uuid); QVariantMap requestMap; - requestMap.insert("name", device->name()); + requestMap.insert("name", name); QJsonDocument jsonDoc = QJsonDocument::fromVariant(requestMap); QNetworkRequest request(QUrl("http://" + remote->hostAddress().toString() + "/api/" + remote->apiKey() + @@ -229,10 +237,16 @@ void BridgeConnection::setRemoteName(const QString &uuid, const QString &name) QNetworkReply *reply = m_hardwareManager->networkManager()->put(request,jsonDoc.toJson()); connect(reply, &QNetworkReply::finished, this, &BridgeConnection::networkManagerReplyReady); - //m_setNameRequests.insert(reply, device); + if (!m_setNameRequests) { + m_setNameRequests = reply; + } else { + m_setNameRequests->abort(); + m_setNameRequests->deleteLater(); + m_setNameRequests = reply; + } } -void BridgeConnection::processLightRefreshResponse(QString uuid, const QByteArray &data) +void BridgeConnection::processLightRefreshResponse(const QByteArray &data) { QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); @@ -429,46 +443,11 @@ void BridgeConnection::processBridgeLightDiscoveryResponse(const QByteArray &dat QString uuid = lightMap.value("uniqueid").toString(); QString model = lightMap.value("modelid").toString(); - if (lightAlreadyAdded(uuid)) - continue; - HueLight *light = new HueLight(); - light->modelId(model) - - - if (lightMap.value("type").toString() == "Dimmable light") { - DeviceDescriptor descriptor(dimmableLightDeviceClassId, lightMap.value("name").toString(), "Philips Hue White Light", device->id()); - ParamList params; - params.append(Param(dimmableLightDeviceModelIdParamTypeId, model)); - params.append(Param(dimmableLightDeviceTypeParamTypeId, lightMap.value("type").toString())); - params.append(Param(dimmableLightDeviceUuidParamTypeId, uuid)); - params.append(Param(dimmableLightDeviceLightIdParamTypeId, lightId)); - descriptor.setParams(params); - dimmableLightDescriptors.append(descriptor); - - qCDebug(dcPhilipsHue) << "Found new dimmable light" << lightMap.value("name").toString() << model; - } else if (lightMap.value("type").toString() == "Color temperature light") { - DeviceDescriptor descriptor(colorTemperatureLightDeviceClassId, lightMap.value("name").toString(), "Philips Hue Color Temperature Light", device->id()); - ParamList params; - params.append(Param(colorTemperatureLightDeviceModelIdParamTypeId, model)); - params.append(Param(colorTemperatureLightDeviceTypeParamTypeId, lightMap.value("type").toString())); - params.append(Param(colorTemperatureLightDeviceUuidParamTypeId, uuid)); - params.append(Param(colorTemperatureLightDeviceLightIdParamTypeId, lightId)); - descriptor.setParams(params); - colorTemperatureLightDescriptors.append(descriptor); - - qCDebug(dcPhilipsHue) << "Found new color temperature light" << lightMap.value("name").toString() << model; - } else { - DeviceDescriptor descriptor(colorLightDeviceClassId, lightMap.value("name").toString(), "Philips Hue Color Light", device->id()); - ParamList params; - params.append(Param(colorLightDeviceModelIdParamTypeId, model)); - params.append(Param(colorLightDeviceTypeParamTypeId, lightMap.value("type").toString())); - params.append(Param(colorLightDeviceUuidParamTypeId, uuid)); - params.append(Param(colorLightDeviceLightIdParamTypeId, lightId)); - descriptor.setParams(params); - colorLightDescriptors.append(descriptor); - qCDebug(dcPhilipsHue) << "Found new color light" << lightMap.value("name").toString() << model; - } + light->setModelId(model); + light->setType(lightMap.value("type").toString()); + light->setUuid(uuid); + //light->setId(lightId); } if (!lights.isEmpty()) @@ -597,11 +576,11 @@ void BridgeConnection::processBridgeSensorDiscoveryResponse(const QByteArray &da } if (!remotes.isEmpty()) { - emit remotesDiscovered(remotes); + emit remoteDiscovered(remotes); } if (!motionSensors.isEmpty()) { - emit motionSensorsDiscovered(motionSensors); + emit motionSensorDiscovered(motionSensors); } } @@ -655,12 +634,12 @@ void BridgeConnection::processInformationResponse(PairingInfo *pairingInfo, cons { QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + pairingInfo->deleteLater(); // 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(); + emit pairingFinished(false); return; } @@ -669,29 +648,13 @@ void BridgeConnection::processInformationResponse(PairingInfo *pairingInfo, cons // 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(); + emit pairingFinished(false); 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(); + emit pairingFinished(true); } -void BridgeConnection::processActionResponse(Device *device, const ActionId actionId, const QByteArray &data) +void BridgeConnection::processActionResponse(const QUuid actionUuid, const QByteArray &data) { QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); @@ -699,7 +662,7 @@ void BridgeConnection::processActionResponse(Device *device, const ActionId acti // check JSON error if (error.error != QJsonParseError::NoError) { qCWarning(dcPhilipsHue) << "Hue Bridge json error in response" << error.errorString(); - emit actionExecutionFinished(actionId, Device::DeviceErrorHardwareFailure); + emit actionFailed(actionUuid, error.errorString()); return; } @@ -707,17 +670,14 @@ void BridgeConnection::processActionResponse(Device *device, const ActionId acti 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(); + emit actionFailed(actionUuid, "Failed to execute Hue action:"); } else { qCWarning(dcPhilipsHue) << "Failed to execute Hue action: Invalid error message format"; + emit actionFailed(actionUuid, "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); + emit actionExecuted(actionUuid); } void BridgeConnection::networkManagerReplyReady() @@ -822,17 +782,17 @@ void BridgeConnection::networkManagerReplyReady() } processSensorsRefreshResponse(reply->readAll()); - } else if (m_asyncActions.contains(reply)) { - QPair actionInfo = m_asyncActions.take(reply); + } else if (m_actionRequests.contains(reply)) { + QUuid actionUuid = m_actionRequests.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(false); - //emit actionExecutionFinished(actionInfo.second, Device::DeviceErrorHardwareNotAvailable); + emit actionFailed(actionUuid, reply->errorString()); return; } - processActionResponse(actionInfo.second, reply->readAll()); + processActionResponse(actionUuid, reply->readAll()); } else if (reply == m_setNameRequests) { @@ -859,6 +819,14 @@ int BridgeConnection::percentageToBrightness(int percentage) return qRound((255.0 * percentage) / 100.0); } +QUuid BridgeConnection::scheduleActionRequest(QNetworkRequest *request) +{ + QUuid actionUuid; + request->url(); + m_actionRequests.insert(request); + return actionUuid; +} + void BridgeConnection::abortRequests(QHash requestList, Device *device) { foreach (QNetworkReply* reply, requestList.keys()) { diff --git a/philipshue/bridgeconnection.h b/philipshue/bridgeconnection.h index 74f98a10..edfceadb 100644 --- a/philipshue/bridgeconnection.h +++ b/philipshue/bridgeconnection.h @@ -52,34 +52,34 @@ public: void discoverBridgeDevices(); void searchNewDevices(const QString &serialNumber); - //light actions - void setPower(const QString &uuid, bool power); - void setBrightness(const QString &uuid, quint8 percent); - void setColor(const QString &uuid, QColor percent); - void setEffect(const QString &uuid, const QString &effect); - void setFlash(const QString &uuid, const QString &flashMode); - void setTemperature(const QString &uuid, quint16 temperature); + //light action - the uuid is to track if the actions has been executed + QUuid setPower(const QString &uuid, bool power); + QUuid setBrightness(const QString &uuid, quint8 percent); + QUuid setColor(const QString &uuid, QColor percent); + QUuid setEffect(const QString &uuid, const QString &effect); + QUuid setFlash(const QString &uuid, const QString &flashMode); + QUuid setTemperature(const QString &uuid, quint16 temperature); - void setLightName(const QString &uuid, const QString &name); - void setRemoteName(const QString &uuid, const QString &name); + QUuid setLightName(const QString &uuid, const QString &name); + QUuid setRemoteName(const QString &uuid, const QString &name); -private slots: - void lightStateChanged(); - void remoteStateChanged(); - void onRemoteButtonEvent(int buttonCode); - - - // Motion sensor + void refreshLight(const QString &uuid); // + void refreshBridge(); + void refreshLights(); + void refreshSensors(); signals: - //Devices discovered + void pairingFinished(bool successful); + + //Devices discovered void lightDiscovered(QHash); void remoteDiscovered(QHash); void motionSensorDiscovered(QHash); - // Light Device Events void lightStateChanged(); + void remoteStateChanged(); + void onRemoteButtonEvent(int buttonCode); void motionSensorReachableChanged(bool reachable); void motionSensorBatteryLevelChanged(int batteryLevel); @@ -90,6 +90,9 @@ signals: void networkManagerReplyReady(); void onDeviceNameChanged(); + void actionExecuted(QUuid actionUuid); + void actionFailed(const QUuid &uuid, const QString &error); + private: HardwareManager *m_hardwareManager = nullptr; @@ -100,6 +103,8 @@ private: QHash m_pairingRequests; QHash m_informationRequests; + QHash m_actionRequests; + QNetworkReply *m_lightRefreshRequests; QNetworkReply *m_setNameRequests; QNetworkReply *m_bridgeRefreshRequests; @@ -109,18 +114,11 @@ private: QNetworkReply *m_bridgeSensorsDiscoveryRequests; QNetworkReply *m_bridgeSearchDevicesRequests; - QHash > m_asyncActions; - HueBridge *m_bridge; QHash m_lights; QHash m_remotes; QHash m_motionSensors; - void refreshLight(const QString &uuid); // - void refreshBridge(); - void refreshLights(); - void refreshSensors(); - void processBridgeLightDiscoveryResponse(const QByteArray &data); void processBridgeSensorDiscoveryResponse(const QByteArray &data); void processLightRefreshResponse(const QByteArray &data); @@ -130,17 +128,17 @@ private: void processSetNameResponse(const QByteArray &data); void processPairingResponse(PairingInfo *pairingInfo, const QByteArray &data); void processInformationResponse(PairingInfo *pairingInfo, const QByteArray &data); - void processActionResponse(const ActionId actionId, const QByteArray &data); + void processActionResponse(const QUuid actionUuid, const QByteArray &data); void bridgeReachableChanged(const bool &reachable); - bool lightAlreadyAdded(const QString &uuid); - bool sensorAlreadyAdded(const QString &uuid); + //bool lightAlreadyAdded(const QString &uuid); + //bool sensorAlreadyAdded(const QString &uuid); int brightnessToPercentage(int brightness); int percentageToBrightness(int percentage); - void abortRequests(QHash requestList); + QUuid scheduleActionRequest(QNetworkRequest *request); }; #endif // BRIDGECONNECTION_H diff --git a/philipshue/devicepluginphilipshue.cpp b/philipshue/devicepluginphilipshue.cpp index 967f0673..ae5d8532 100644 --- a/philipshue/devicepluginphilipshue.cpp +++ b/philipshue/devicepluginphilipshue.cpp @@ -39,7 +39,6 @@ DevicePluginPhilipsHue::DevicePluginPhilipsHue() { - } Device::DeviceError DevicePluginPhilipsHue::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) @@ -137,7 +136,7 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) // hue bridge if (device->deviceClassId() == bridgeDeviceClassId) { // unconfigured bridges (from pairing) - foreach (HueBridge *b, m_unconfiguredBridges) { + /*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(); @@ -147,15 +146,14 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) device->setParamValue(bridgeDeviceMacParamTypeId, b->macAddress()); m_bridgeConnections.insert(device->id(), ); device->setStateValue(bridgeConnectedStateTypeId, true); - discoverBridgeDevices(b); + //discoverBridgeDevices(); return Device::DeviceSetupStatusSuccess; } - } + }*/ // Loaded bridge qCDebug(dcPhilipsHue) << "Setup Hue Bridge" << device->params(); - HueBridge *bridge = new HueBridge(this); bridge->setId(device->paramValue(bridgeDeviceIdParamTypeId).toString()); bridge->setApiKey(device->paramValue(bridgeDeviceApiKeyParamTypeId).toString()); @@ -173,21 +171,11 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) // Hue color light if (device->deviceClassId() == colorLightDeviceClassId) { qCDebug(dcPhilipsHue) << "Setup Hue color light" << device->params(); + BridgeConnection *bridge = m_bridgeConnections.value(device->parentId()); + if (!bridge) + return Device::DeviceSetupStatusFailure; - BridgeConnection *bridge = m_bridgeConnections; - HueLight *hueLight = new HueLight(this); - hueLight->setHostAddress(bridge->hostAddress()); - hueLight->setApiKey(bridge->apiKey()); - hueLight->setId(device->paramValue(colorLightDeviceLightIdParamTypeId).toInt()); - hueLight->setModelId(device->paramValue(colorLightDeviceModelIdParamTypeId).toString()); - hueLight->setUuid(device->paramValue(colorLightDeviceUuidParamTypeId).toString()); - hueLight->setType(device->paramValue(colorLightDeviceTypeParamTypeId).toString()); - - connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged); - m_lights.insert(hueLight, device); - - refreshLight(device); - + bridge->refreshLight(device->paramValue(colorLightDeviceUuidParamTypeId).toString()); return Device::DeviceSetupStatusSuccess; } @@ -195,20 +183,11 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) if (device->deviceClassId() == colorTemperatureLightDeviceClassId) { qCDebug(dcPhilipsHue) << "Setup Hue color temperature light" << device->params(); - HueBridge *bridge = m_bridges.key(myDevices().findById(device->parentId())); - HueLight *hueLight = new HueLight(this); - hueLight->setHostAddress(bridge->hostAddress()); - hueLight->setApiKey(bridge->apiKey()); - hueLight->setId(device->paramValue(colorTemperatureLightDeviceLightIdParamTypeId).toInt()); - hueLight->setModelId(device->paramValue(colorTemperatureLightDeviceModelIdParamTypeId).toString()); - hueLight->setUuid(device->paramValue(colorTemperatureLightDeviceUuidParamTypeId).toString()); - hueLight->setType(device->paramValue(colorTemperatureLightDeviceTypeParamTypeId).toString()); - - connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged); - m_lights.insert(hueLight, device); - - refreshLight(device); + BridgeConnection *bridge = m_bridgeConnections.value(device->parentId()); + if (!bridge) + return Device::DeviceSetupStatusFailure; + bridge->refreshLight(device->paramValue(colorTemperatureLightDeviceUuidParamTypeId).toString()); return Device::DeviceSetupStatusSuccess; } @@ -216,11 +195,6 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) if (device->deviceClassId() == dimmableLightDeviceClassId) { qCDebug(dcPhilipsHue) << "Setup Hue white light" << device->params(); - HueBridge *bridge = m_bridges.key(myDevices().findById(device->parentId())); - HueLight *hueLight = new HueLight(this); - hueLight->setHostAddress(bridge->hostAddress()); - hueLight->setApiKey(bridge->apiKey()); - // Migrate device parameters after changing param type UUIDs in 0.14. QMap migrationMap; migrationMap.insert("095a463b-f59e-46b1-989a-a71f9cbe3e30", dimmableLightDeviceModelIdParamTypeId); @@ -245,16 +219,11 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) device->setParams(migratedParams); // Migration done - hueLight->setModelId(device->paramValue(dimmableLightDeviceModelIdParamTypeId).toString()); - hueLight->setType(device->paramValue(dimmableLightDeviceTypeParamTypeId).toString()); - hueLight->setUuid(device->paramValue(dimmableLightDeviceUuidParamTypeId).toString()); - hueLight->setId(device->paramValue(dimmableLightDeviceLightIdParamTypeId).toInt()); - - connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged); - - m_lights.insert(hueLight, device); - refreshLight(device); + BridgeConnection *bridge = m_bridgeConnections.value(device->parentId()); + if (!bridge) + return Device::DeviceSetupStatusFailure; + bridge->refreshLight(device->paramValue(dimmableLightDeviceUuidParamTypeId).toString()); return Device::DeviceSetupStatusSuccess; } @@ -262,11 +231,6 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) if (device->deviceClassId() == remoteDeviceClassId) { qCDebug(dcPhilipsHue) << "Setup Hue remote" << device->params() << device->deviceClassId(); - BridgeConnection *bridge = m_bridgeConnections.value(device->parentId()); - HueRemote *hueRemote = new HueRemote(this); - hueRemote->setHostAddress(bridge->hostAddress()); - hueRemote->setApiKey(bridge->apiKey()); - // Migrate device parameters after changing param type UUIDs in 0.14. QMap migrationMap; migrationMap.insert("095a463b-f59e-46b1-989a-a71f9cbe3e30", remoteDeviceModelIdParamTypeId); @@ -388,40 +352,10 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *device) void DevicePluginPhilipsHue::deviceRemoved(Device *device) { - abortRequests(m_lightRefreshRequests, device); - abortRequests(m_setNameRequests, device); - abortRequests(m_bridgeRefreshRequests, device); - abortRequests(m_lightsRefreshRequests, device); - abortRequests(m_sensorsRefreshRequests, device); - abortRequests(m_bridgeLightsDiscoveryRequests, device); - abortRequests(m_bridgeSensorsDiscoveryRequests, device); - abortRequests(m_bridgeSearchDevicesRequests, device); - if (device->deviceClassId() == bridgeDeviceClassId) { - HueBridge *bridge = m_bridges.key(device); - m_bridges.remove(bridge); + BridgeConnection *bridge = m_bridgeConnections.take(device->id()); bridge->deleteLater(); } - - if (device->deviceClassId() == colorLightDeviceClassId - || device->deviceClassId() == colorTemperatureLightDeviceClassId - || device->deviceClassId() == dimmableLightDeviceClassId) { - HueLight *light = m_lights.key(device); - m_lights.remove(light); - light->deleteLater(); - } - - if (device->deviceClassId() == remoteDeviceClassId || device->deviceClassId() == tapDeviceClassId) { - HueRemote *remote = m_remotes.key(device); - m_remotes.remove(remote); - remote->deleteLater(); - } - - if (device->deviceClassId() == outdoorSensorDeviceClassId) { - HueMotionSensor *outdoorSensor = m_motionSensors.key(device); - m_motionSensors.remove(outdoorSensor); - outdoorSensor->deleteLater(); - } } Device::DeviceSetupStatus DevicePluginPhilipsHue::confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList ¶ms, const QString &secret) @@ -454,15 +388,49 @@ Device::DeviceSetupStatus DevicePluginPhilipsHue::confirmPairing(const PairingTr void DevicePluginPhilipsHue::onDeviceNameChanged() { Device *device = static_cast(sender()); - if (m_lights.values().contains(device)) { - setLightName(device); - } + BridgeConnection *bridge = m_bridgeConnections.value(device->parentId()); + if (!bridge) + return; - if (m_remotes.values().contains(device)) { - setRemoteName(device); + if (device->deviceClassId() == colorLightDeviceClassId) { + bridge->setLightName(device->paramValue(colorLightDeviceUuidParamTypeId).toString(), device->name()); + } + if (device->deviceClassId() == colorTemperatureLightDeviceClassId) { + bridge->setLightName(device->paramValue(colorTemperatureLightDeviceUuidParamTypeId).toString(), device->name()); + } + if (device->deviceClassId() == dimmableLightDeviceClassId) { + bridge->setLightName(device->paramValue(dimmableLightDeviceUuidParamTypeId).toString(), device->name()); + } + if (device->deviceClassId() == remoteDeviceClassId) { + bridge->setLightName(device->paramValue(remoteDeviceUuidParamTypeId).toString(), device->name()); + } + if (device->deviceClassId() == tapDeviceClassId) { + bridge->setLightName(device->paramValue(tapDeviceUuidParamTypeId).toString(), device->name()); + } + if (device->deviceClassId() == outdoorSensorDeviceClassId) { + bridge->setLightName(device->paramValue(outdoorSensorDeviceUuidParamTypeId).toString(), device->name()); } } +void DevicePluginPhilipsHue::onActionExecuted(const QUuid &uuid) +{ + if (m_asyncActions.contains(uuid)) { + ActionId asyncAction = m_asyncActions.take(uuid); + emit actionExecutionFinished(asyncAction, Device::DeviceErrorNoError); + } +} + + +void DevicePluginPhilipsHue::onActionFailed(const QUuid &uuid, const QString &error) +{ + if (m_asyncActions.contains(uuid)) { + qWarning(dcPhilipsHue()) << "Action failed: " << error; + ActionId asyncAction = m_asyncActions.take(uuid); + emit actionExecutionFinished(asyncAction, Device::DeviceErrorHardwareNotAvailable); + } +} + + void DevicePluginPhilipsHue::finishDiscovery(DevicePluginPhilipsHue::DiscoveryJob *job) { if (job->upnpReply || job->nUpnpReply) { @@ -489,6 +457,37 @@ void DevicePluginPhilipsHue::finishDiscovery(DevicePluginPhilipsHue::DiscoveryJo delete job; } +Device *DevicePluginPhilipsHue::getDeviceByHueDeviceUuid(const QString &uuid) +{ + foreach(Device* device, myDevices()) { + if (device->deviceClassId() == colorLightDeviceClassId) { + if(device->paramValue(colorLightDeviceUuidParamTypeId).toString() == uuid) + return device; + } + if (device->deviceClassId() == colorTemperatureLightDeviceClassId) { + if(device->paramValue(colorTemperatureLightDeviceUuidParamTypeId).toString() == uuid) + return device; + } + if (device->deviceClassId() == dimmableLightDeviceClassId) { + if(device->paramValue(dimmableLightDeviceUuidParamTypeId).toString() == uuid) + return device; + } + if (device->deviceClassId() == remoteDeviceClassId) { + if(device->paramValue(remoteDeviceUuidParamTypeId).toString() == uuid) + return device; + } + if (device->deviceClassId() == tapDeviceClassId) { + if(device->paramValue(tapDeviceUuidParamTypeId).toString() == uuid) + return device; + } + if (device->deviceClassId() == outdoorSensorDeviceClassId) { + if(device->paramValue(outdoorSensorDeviceUuidParamTypeId).toString() == uuid) + return device; + } + } + return nullptr; +} + Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const Action &action) { qCDebug(dcPhilipsHue) << "Execute action" << action.actionTypeId() << action.params(); @@ -506,28 +505,28 @@ Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const if (action.actionTypeId() == colorLightPowerActionTypeId) { //get bridge - bridge->setPower(uuid, action.param(colorLightPowerActionPowerParamTypeId).value().toBool()) - //m_asyncActions.insert(device, action.id()); - return Device::DeviceErrorAsync; + QUuid actionUuid = bridge->setPower(uuid, action.param(colorLightPowerActionPowerParamTypeId).value().toBool()); + m_asyncActions.insert(actionUuid, action.id()); + return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorLightColorActionTypeId) { - bridge->setColor(uuid, action.param(colorLightColorActionColorParamTypeId).value().value()); - //m_asyncActions.insert(reply,QPair(device, action.id())); + QUuid actionUuid = bridge->setColor(uuid, action.param(colorLightColorActionColorParamTypeId).value().value()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorLightBrightnessActionTypeId) { - bridge->setBrightness(uuid, action.param(colorLightBrightnessActionBrightnessParamTypeId).value().toInt()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setBrightness(uuid, action.param(colorLightBrightnessActionBrightnessParamTypeId).value().toInt()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorLightEffectActionTypeId) { - bridge->setEffect(uuid, action.param(colorLightEffectActionEffectParamTypeId).value().toString()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setEffect(uuid, action.param(colorLightEffectActionEffectParamTypeId).value().toString()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorLightAlertActionTypeId) { - bridge->setFlash(uuid, action.param(colorLightAlertActionAlertParamTypeId).value().toString()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setFlash(uuid, action.param(colorLightAlertActionAlertParamTypeId).value().toString()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorLightColorTemperatureActionTypeId) { - bridge->setTemperature(uuid, action.param(colorLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setTemperature(uuid, action.param(colorLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } return Device::DeviceErrorActionTypeNotFound; @@ -544,20 +543,20 @@ Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const }*/ //TODO if (action.actionTypeId() == colorTemperatureLightPowerActionTypeId) { - bridge->setTemperature(uuid, action.param(colorTemperatureLightPowerActionPowerParamTypeId).value().toBool()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setTemperature(uuid, action.param(colorTemperatureLightPowerActionPowerParamTypeId).value().toBool()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorTemperatureLightBrightnessActionTypeId) { - bridge->setBrightness(uuid, action.param(colorTemperatureLightBrightnessActionBrightnessParamTypeId).value().toInt()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setBrightness(uuid, action.param(colorTemperatureLightBrightnessActionBrightnessParamTypeId).value().toInt()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorTemperatureLightAlertActionTypeId) { - bridge->setFlash(uuid, action.param(colorTemperatureLightAlertActionAlertParamTypeId).value().toString()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setFlash(uuid, action.param(colorTemperatureLightAlertActionAlertParamTypeId).value().toString()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == colorTemperatureLightColorTemperatureActionTypeId) { - bridge->setTemperature(uuid, action.param(colorTemperatureLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setTemperature(uuid, action.param(colorTemperatureLightColorTemperatureActionColorTemperatureParamTypeId).value().toInt()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } return Device::DeviceErrorActionTypeNotFound; @@ -575,18 +574,16 @@ Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const }*/ //TODO if (action.actionTypeId() == dimmableLightPowerActionTypeId) { - bridge->setPower(uuid, 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())); + QUuid actionUuid = bridge->setPower(uuid, action.param(dimmableLightPowerActionPowerParamTypeId).value().toBool()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == dimmableLightBrightnessActionTypeId) { - bridge->setBrightness(uuid, action.param(dimmableLightBrightnessActionBrightnessParamTypeId).value().toInt()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setBrightness(uuid, action.param(dimmableLightBrightnessActionBrightnessParamTypeId).value().toInt()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } else if (action.actionTypeId() == dimmableLightAlertActionTypeId) { - bridge->setFlash(uuid, action.param(dimmableLightAlertActionAlertParamTypeId).value().toString()); - //m_asyncActions.insert(reply, QPair(device, action.id())); + QUuid actionUuid = bridge->setFlash(uuid, action.param(dimmableLightAlertActionAlertParamTypeId).value().toString()); + m_asyncActions.insert(actionUuid, action.id()); return Device::DeviceErrorAsync; } return Device::DeviceErrorActionTypeNotFound; @@ -602,7 +599,7 @@ Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const } if (action.actionTypeId() == bridgeSearchNewDevicesActionTypeId) { - bridge->searchNewDevices(action.param(bridgeSearchNewDevicesActionSerialParamTypeId).value().toString()); + QUuid actionUuid = bridge->searchNewDevices(action.param(bridgeSearchNewDevicesActionSerialParamTypeId).value().toString()); return Device::DeviceErrorNoError; } else if (action.actionTypeId() == bridgeCheckForUpdatesActionTypeId) { QPair request = bridge->createCheckUpdatesRequest(); @@ -622,6 +619,26 @@ Device::DeviceError DevicePluginPhilipsHue::executeAction(Device *device, const return Device::DeviceErrorDeviceClassNotFound; } +void DevicePluginPhilipsHue::onPairingFinished(bool successful) +{ + if(successful) { + //BridgeConnection *bridge = static_cast(sender()); + + // 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); + } +} + void DevicePluginPhilipsHue::onLightsDiscovered(QHash lights) { BridgeConnection *bridge = static_cast(sender()); @@ -632,22 +649,22 @@ void DevicePluginPhilipsHue::onLightsDiscovered(QHash light QList colorTemperatureLightDescriptors; QList dimmableLightDescriptors; + foreach (HueLight *light, lights.values()) { - foreach (HueLight *light, lights.keys()) { - + QString uuid = lights.key(light); if (lightAlreadyAdded(uuid)) continue; if (light->type() == "Dimmable light") { DeviceDescriptor descriptor(dimmableLightDeviceClassId, light->name(), "Philips Hue White Light", parentDeviceId); ParamList params; - params.append(Param(dimmableLightDeviceModelIdParamTypeId, model)); + params.append(Param(dimmableLightDeviceModelIdParamTypeId, light->modelId())); params.append(Param(dimmableLightDeviceTypeParamTypeId, light->type())); params.append(Param(dimmableLightDeviceUuidParamTypeId, uuid)); - params.append(Param(dimmableLightDeviceLightIdParamTypeId, lightId)); + params.append(Param(dimmableLightDeviceLightIdParamTypeId, light->id())); descriptor.setParams(params); dimmableLightDescriptors.append(descriptor); - qCDebug(dcPhilipsHue) << "Found new dimmable light" << light->name() << light->modelId(); + qCDebug(dcPhilipsHue) << "Found new dimmable light" << light->name(); } else if (light->type() == "Color temperature light") { DeviceDescriptor descriptor(colorTemperatureLightDeviceClassId, light->name(), "Philips Hue Color Temperature Light", parentDeviceId); @@ -659,7 +676,7 @@ void DevicePluginPhilipsHue::onLightsDiscovered(QHash light descriptor.setParams(params); colorTemperatureLightDescriptors.append(descriptor); - qCDebug(dcPhilipsHue) << "Found new color temperature light" << light->name() << model; + qCDebug(dcPhilipsHue) << "Found new color temperature light" << light->name(); } else { DeviceDescriptor descriptor(colorLightDeviceClassId, light->name(), "Philips Hue Color Light", parentDeviceId); ParamList params; @@ -669,7 +686,7 @@ void DevicePluginPhilipsHue::onLightsDiscovered(QHash light params.append(Param(colorLightDeviceLightIdParamTypeId, light->id())); descriptor.setParams(params); colorLightDescriptors.append(descriptor); - qCDebug(dcPhilipsHue) << "Found new color light" << light->name() << model; + qCDebug(dcPhilipsHue) << "Found new color light" << light->name(); } } @@ -687,7 +704,7 @@ void DevicePluginPhilipsHue::onRemotesDiscovered(QHash rem DeviceId parentDeviceId = m_bridgeConnections.key(bridge); foreach (HueRemote *remote, remotes.values()) { - QString baseUuid = motionSensors.key(motionSensor); + QString uuid = remotes.key(remote); if (sensorAlreadyAdded(uuid)) continue; @@ -703,7 +720,7 @@ void DevicePluginPhilipsHue::onRemotesDiscovered(QHash rem } if (remote->type() == "ZGPSwitch") { - DeviceDescriptor descriptor(tapDeviceClassId, remote->name(), "Philips Hue Tap", device->id()); + DeviceDescriptor descriptor(tapDeviceClassId, remote->name(), "Philips Hue Tap", parentDeviceId); ParamList params; params.append(Param(tapDeviceUuidParamTypeId, remote->uuid())); params.append(Param(tapDeviceModelIdParamTypeId, remote->modelId())); @@ -716,16 +733,18 @@ void DevicePluginPhilipsHue::onRemotesDiscovered(QHash rem void DevicePluginPhilipsHue::onMotionSensorDiscovered(QHash motionSensors) { + BridgeConnection *bridge = static_cast(sender()); + DeviceId parentDeviceId = m_bridgeConnections.key(bridge); // Create outdoor sensors if there are any new sensors found foreach (HueMotionSensor *motionSensor, motionSensors.values()) { - QString baseUuid = motionSensors.key(motionSensor); + QString uuid = motionSensors.key(motionSensor); if (sensorAlreadyAdded(uuid)) continue; if (motionSensor->isValid()) { if (motionSensor->modelId() == "SML001") { - DeviceDescriptor descriptor(motionSensorDeviceClassId, tr("Philips Hue Motion sensor"), baseUuid, device->id()); + DeviceDescriptor descriptor(motionSensorDeviceClassId, tr("Philips Hue Motion sensor"), uuid, parentDeviceId); ParamList params; params.append(Param(motionSensorDeviceUuidParamTypeId, motionSensor->uuid())); params.append(Param(motionSensorDeviceModelIdParamTypeId, motionSensor->modelId())); @@ -736,10 +755,10 @@ void DevicePluginPhilipsHue::onMotionSensorDiscovered(QHashlightSensorUuid())); params.append(Param(motionSensorDeviceSensorIdLightParamTypeId, motionSensor->lightSensorId())); descriptor.setParams(params); - qCDebug(dcPhilipsHue()) << "Found new motion sensor" << baseUuid << outdoorSensorDeviceClassId; + qCDebug(dcPhilipsHue()) << "Found new motion sensor" << uuid << outdoorSensorDeviceClassId; emit autoDevicesAppeared(motionSensorDeviceClassId, {descriptor}); } else if (motionSensor->modelId() == "SML002") { - DeviceDescriptor descriptor(outdoorSensorDeviceClassId, tr("Philips Hue Outdoor sensor"), baseUuid, device->id()); + DeviceDescriptor descriptor(outdoorSensorDeviceClassId, tr("Philips Hue Outdoor sensor"), uuid, parentDeviceId); ParamList params; params.append(Param(outdoorSensorDeviceUuidParamTypeId, motionSensor->uuid())); params.append(Param(outdoorSensorDeviceModelIdParamTypeId, motionSensor->modelId())); @@ -750,20 +769,18 @@ void DevicePluginPhilipsHue::onMotionSensorDiscovered(QHashlightSensorUuid())); params.append(Param(outdoorSensorDeviceSensorIdLightParamTypeId, motionSensor->lightSensorId())); descriptor.setParams(params); - qCDebug(dcPhilipsHue()) << "Found new outdoor sensor" << baseUuid << outdoorSensorDeviceClassId; + qCDebug(dcPhilipsHue()) << "Found new outdoor sensor" << uuid << outdoorSensorDeviceClassId; emit autoDevicesAppeared(outdoorSensorDeviceClassId, {descriptor}); } } } } -void DevicePluginPhilipsHue::lightStateChanged() +void DevicePluginPhilipsHue::onLightStateChanged(const QString &uuid) { - HueLight *light = static_cast(sender()); - - Device *device = m_lights.value(light); + Device *device = getDeviceByHueDeviceUuid(uuid); if (!device) { - qCWarning(dcPhilipsHue) << "Could not find device for light" << light->name(); + qCWarning(dcPhilipsHue) << "Could not find device for light" << uuid; return; } @@ -786,7 +803,7 @@ void DevicePluginPhilipsHue::lightStateChanged() } } -void DevicePluginPhilipsHue::remoteStateChanged() +void DevicePluginPhilipsHue::onRemoteStateChanged() { HueRemote *remote = static_cast(sender()); @@ -891,6 +908,7 @@ void DevicePluginPhilipsHue::onMotionSensorTemperatureChanged(double temperature void DevicePluginPhilipsHue::onMotionSensorPresenceChanged(bool presence) { HueMotionSensor *sensor = static_cast(sender()); + myDevices().filterByParam() Device *sensorDevice = m_motionSensors.value(sensor); sensorDevice->setStateValue(sensor->isPresentStateTypeId(), presence); if (presence) sensorDevice->setStateValue(sensor->lastSeenTimeStateTypeId(), QDateTime::currentDateTime().toTime_t()); diff --git a/philipshue/devicepluginphilipshue.h b/philipshue/devicepluginphilipshue.h index 56c56745..6856c613 100644 --- a/philipshue/devicepluginphilipshue.h +++ b/philipshue/devicepluginphilipshue.h @@ -56,6 +56,7 @@ public: Device::DeviceError executeAction(Device *device, const Action &action) override; private slots: + void onPairingFinished(bool successful); //Devices discovered void onLightsDiscovered(QHash remotes); @@ -78,6 +79,9 @@ private slots: void onDeviceNameChanged(); + void onActionExecuted(const QUuid &uuid); + void onActionFailed(const QUuid &uuid, const QString &error); + private: class DiscoveryJob { public: @@ -87,7 +91,6 @@ private: }; void finishDiscovery(DiscoveryJob* job); - QHash m_pairingRequests; QHash m_informationRequests; QHash m_bridgeConnections; @@ -95,7 +98,9 @@ private: QList m_unconfiguredBridges; QList m_unconfiguredLights; - QHash > m_asyncActions; + QHash m_asyncActions; + + Device *getDeviceByHueDeviceUuid(const QString &uuid); bool lightAlreadyAdded(const QString &uuid); bool sensorAlreadyAdded(const QString &uuid); diff --git a/philipshue/huemotionsensor.h b/philipshue/huemotionsensor.h index 5b832ad5..e75f3cf0 100644 --- a/philipshue/huemotionsensor.h +++ b/philipshue/huemotionsensor.h @@ -50,8 +50,8 @@ public: QString presenceSensorUuid() const; void setPresenceSensorUuid(const QString &presenceSensorUuid); - int sensorId() const; - void setSensorId(int sensorId); + int lightSensorId() const; + void setLightSensorId(int sensorId); QString lightSensorUuid() const; void setLightSensorUuid(const QString &lightSensorUuid); diff --git a/philipshue/hueremote.h b/philipshue/hueremote.h index 26525201..46ab1ebc 100644 --- a/philipshue/hueremote.h +++ b/philipshue/hueremote.h @@ -56,8 +56,8 @@ public: int battery() const; void setBattery(const int &battery); - int remoteSensorId() const; - void setRemoteSensorId(int sensorId); + int remoteId() const; + void setRemoteId(int sensorId); void updateStates(const QVariantMap &statesMap, const QVariantMap &configMap);