Hue: Add support for scenes and cleanup removed devices
This commit is contained in:
parent
b14927fc4b
commit
2bf23fca65
@ -834,6 +834,115 @@ void IntegrationPluginPhilipsHue::executeAction(ThingActionInfo *info)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginPhilipsHue::browseThing(BrowseResult *result)
|
||||||
|
{
|
||||||
|
Thing *bridgeThing = result->thing();
|
||||||
|
HueBridge* bridge = m_bridges.key(bridgeThing);
|
||||||
|
|
||||||
|
QNetworkRequest request(QUrl("http://" + bridge->hostAddress().toString() + "/api/" + bridge->apiKey() + "/scenes"));
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
QNetworkReply* reply = hardwareManager()->networkManager()->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
|
connect(reply, &QNetworkReply::finished, result, [result, reply]() {
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcPhilipsHue()) << "Error fetching scenes";
|
||||||
|
result->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
if (error.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(dcPhilipsHue()) << "Error parsing json from hue bridge" << data;
|
||||||
|
result->finish(Thing::ThingErrorHardwareFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcPhilipsHue()) << "Scenes reply:" << qUtf8Printable(jsonDoc.toJson());
|
||||||
|
QVariantMap scenesMap = jsonDoc.toVariant().toMap();
|
||||||
|
foreach (const QString &sceneId, scenesMap.keys()) {
|
||||||
|
QVariantMap scene = scenesMap.value(sceneId).toMap();
|
||||||
|
BrowserItem item(sceneId, scene.value("name").toString(), false, true);
|
||||||
|
item.setIcon(BrowserItem::BrowserIconFavorites);
|
||||||
|
result->addItem(item);
|
||||||
|
}
|
||||||
|
result->finish(Thing::ThingErrorNoError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginPhilipsHue::browserItem(BrowserItemResult *result)
|
||||||
|
{
|
||||||
|
Thing *bridgeThing = result->thing();
|
||||||
|
HueBridge* bridge = m_bridges.key(bridgeThing);
|
||||||
|
|
||||||
|
QNetworkRequest request(QUrl("http://" + bridge->hostAddress().toString() + "/api/" + bridge->apiKey() + "/scenes"));
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
QNetworkReply* reply = hardwareManager()->networkManager()->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
|
connect(reply, &QNetworkReply::finished, result, [result, reply]() {
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcPhilipsHue()) << "Error fetching scenes";
|
||||||
|
result->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
if (error.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(dcPhilipsHue()) << "Error parsing json from hue bridge" << data;
|
||||||
|
result->finish(Thing::ThingErrorHardwareFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcPhilipsHue()) << "Scenes reply:" << qUtf8Printable(jsonDoc.toJson());
|
||||||
|
QVariantMap scenesMap = jsonDoc.toVariant().toMap();
|
||||||
|
QVariantMap scene = scenesMap.value(result->itemId()).toMap();
|
||||||
|
BrowserItem item(result->itemId(), scene.value("name").toString(), false, true);
|
||||||
|
item.setIcon(BrowserItem::BrowserIconFavorites);
|
||||||
|
result->finish(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginPhilipsHue::executeBrowserItem(BrowserActionInfo *info)
|
||||||
|
{
|
||||||
|
Thing *bridgeThing = info->thing()->parentId().isNull() ? info->thing() : myThings().findById(info->thing()->parentId());
|
||||||
|
HueBridge* bridge = m_bridges.key(bridgeThing);
|
||||||
|
|
||||||
|
QUrl url = QUrl(QString("http://%1/api/%2/groups/%3/action")
|
||||||
|
.arg(bridge->hostAddress().toString())
|
||||||
|
.arg(bridge->apiKey())
|
||||||
|
.arg("0")
|
||||||
|
);
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
|
||||||
|
QVariantMap payload;
|
||||||
|
payload.insert("scene", info->browserAction().itemId());
|
||||||
|
|
||||||
|
qCDebug(dcPhilipsHue()) << "Recalling scene" << url.toString();
|
||||||
|
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
QNetworkReply* reply = hardwareManager()->networkManager()->put(request, QJsonDocument::fromVariant(payload).toJson());
|
||||||
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
|
connect(reply, &QNetworkReply::finished, info, [info, reply]() {
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcPhilipsHue()) << "Error fetching scenes";
|
||||||
|
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
if (error.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(dcPhilipsHue()) << "Error parsing json from hue bridge" << data;
|
||||||
|
info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcPhilipsHue()) << "Set scene reply:" << qUtf8Printable(jsonDoc.toJson());
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void IntegrationPluginPhilipsHue::lightStateChanged()
|
void IntegrationPluginPhilipsHue::lightStateChanged()
|
||||||
{
|
{
|
||||||
HueLight *light = static_cast<HueLight *>(sender());
|
HueLight *light = static_cast<HueLight *>(sender());
|
||||||
@ -1113,12 +1222,20 @@ void IntegrationPluginPhilipsHue::processBridgeLightDiscoveryResponse(Thing *thi
|
|||||||
ThingDescriptors descriptors;
|
ThingDescriptors descriptors;
|
||||||
|
|
||||||
QVariantMap lightsMap = jsonDoc.toVariant().toMap();
|
QVariantMap lightsMap = jsonDoc.toVariant().toMap();
|
||||||
|
QList<HueLight*> lightsToRemove = m_lights.keys();
|
||||||
foreach (QString lightId, lightsMap.keys()) {
|
foreach (QString lightId, lightsMap.keys()) {
|
||||||
QVariantMap lightMap = lightsMap.value(lightId).toMap();
|
QVariantMap lightMap = lightsMap.value(lightId).toMap();
|
||||||
|
|
||||||
QString uuid = lightMap.value("uniqueid").toString();
|
QString uuid = lightMap.value("uniqueid").toString();
|
||||||
QString model = lightMap.value("modelid").toString();
|
QString model = lightMap.value("modelid").toString();
|
||||||
|
|
||||||
|
foreach (HueLight *light, lightsToRemove) {
|
||||||
|
if (light->uuid() == uuid) {
|
||||||
|
lightsToRemove.removeAll(light);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lightAlreadyAdded(uuid))
|
if (lightAlreadyAdded(uuid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1160,6 +1277,13 @@ void IntegrationPluginPhilipsHue::processBridgeLightDiscoveryResponse(Thing *thi
|
|||||||
if (!descriptors.isEmpty()) {
|
if (!descriptors.isEmpty()) {
|
||||||
emit autoThingsAppeared(descriptors);
|
emit autoThingsAppeared(descriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (HueLight *light, lightsToRemove) {
|
||||||
|
Thing *lightThing = m_lights.value(light);
|
||||||
|
if (lightThing->parentId() == thing->id()) {
|
||||||
|
emit autoThingDisappeared(lightThing->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginPhilipsHue::processBridgeSensorDiscoveryResponse(Thing *thing, const QByteArray &data)
|
void IntegrationPluginPhilipsHue::processBridgeSensorDiscoveryResponse(Thing *thing, const QByteArray &data)
|
||||||
@ -1186,12 +1310,27 @@ void IntegrationPluginPhilipsHue::processBridgeSensorDiscoveryResponse(Thing *th
|
|||||||
// Create sensors if not already added
|
// Create sensors if not already added
|
||||||
QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
|
QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
|
||||||
QHash<QString, HueMotionSensor *> motionSensors;
|
QHash<QString, HueMotionSensor *> motionSensors;
|
||||||
|
QList<HueRemote*> remotesToRemove = m_remotes.keys();
|
||||||
|
QList<HueMotionSensor*> sensorsToRemove = m_motionSensors.keys();
|
||||||
foreach (const QString &sensorId, sensorsMap.keys()) {
|
foreach (const QString &sensorId, sensorsMap.keys()) {
|
||||||
|
|
||||||
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
|
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
|
||||||
QString uuid = sensorMap.value("uniqueid").toString();
|
QString uuid = sensorMap.value("uniqueid").toString();
|
||||||
QString model = sensorMap.value("modelid").toString();
|
QString model = sensorMap.value("modelid").toString();
|
||||||
|
|
||||||
|
foreach (HueRemote* remote, remotesToRemove) {
|
||||||
|
if (remote->uuid() == uuid) {
|
||||||
|
remotesToRemove.removeAll(remote);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (HueMotionSensor* sensor, sensorsToRemove) {
|
||||||
|
if (sensor->uuid() == uuid.split("-").first()) {
|
||||||
|
sensorsToRemove.removeAll(sensor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sensorAlreadyAdded(uuid))
|
if (sensorAlreadyAdded(uuid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1332,6 +1471,22 @@ void IntegrationPluginPhilipsHue::processBridgeSensorDiscoveryResponse(Thing *th
|
|||||||
motionSensors.remove(baseUuid);
|
motionSensors.remove(baseUuid);
|
||||||
motionSensor->deleteLater();
|
motionSensor->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (HueRemote* remote, remotesToRemove) {
|
||||||
|
Thing *remoteThing = m_remotes.value(remote);
|
||||||
|
if (remoteThing->parentId() == thing->id()) {
|
||||||
|
qCDebug(dcPhilipsHue()) << "Hue remote disappeared from bridge";
|
||||||
|
emit autoThingDisappeared(remoteThing->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (HueMotionSensor* sensor, sensorsToRemove) {
|
||||||
|
Thing *sensorThing = m_motionSensors.value(sensor);
|
||||||
|
if (sensorThing->parentId() == thing->id()) {
|
||||||
|
qCDebug(dcPhilipsHue()) << "Hue motion sensor disappeared from bridge";
|
||||||
|
emit autoThingDisappeared(sensorThing->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginPhilipsHue::processLightRefreshResponse(Thing *thing, const QByteArray &data)
|
void IntegrationPluginPhilipsHue::processLightRefreshResponse(Thing *thing, const QByteArray &data)
|
||||||
@ -1402,6 +1557,8 @@ void IntegrationPluginPhilipsHue::processBridgeRefreshResponse(Thing *thing, con
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
discoverBridgeDevices(m_bridges.key(thing));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginPhilipsHue::processLightsRefreshResponse(Thing *thing, const QByteArray &data)
|
void IntegrationPluginPhilipsHue::processLightsRefreshResponse(Thing *thing, const QByteArray &data)
|
||||||
|
|||||||
@ -63,6 +63,10 @@ public:
|
|||||||
void thingRemoved(Thing *thing) override;
|
void thingRemoved(Thing *thing) override;
|
||||||
void executeAction(ThingActionInfo *info) override;
|
void executeAction(ThingActionInfo *info) override;
|
||||||
|
|
||||||
|
void browseThing(BrowseResult *result) override;
|
||||||
|
void browserItem(BrowserItemResult *result) override;
|
||||||
|
void executeBrowserItem(BrowserActionInfo *info) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void lightStateChanged();
|
void lightStateChanged();
|
||||||
void remoteStateChanged();
|
void remoteStateChanged();
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"interfaces": ["gateway"],
|
"interfaces": ["gateway"],
|
||||||
"createMethods": ["discovery"],
|
"createMethods": ["discovery"],
|
||||||
"setupMethod": "pushButton",
|
"setupMethod": "pushButton",
|
||||||
|
"browsable": true,
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "1845975b-1184-4440-bc0d-73d53a9f683c",
|
"id": "1845975b-1184-4440-bc0d-73d53a9f683c",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user