diff --git a/tado/README.md b/tado/README.md index 8144c47d..dd065d92 100644 --- a/tado/README.md +++ b/tado/README.md @@ -2,3 +2,13 @@ Let's you connect to your Tado account. All configured zones will appear in nymea automatically. You will get all relevant data and can set the mode and target temperature. + +## Device Setup + +nymea will connect to your Tado account. After the account is connected all associated devices +will appear automatically. The Tado app is required to create a Tado account and connect the +devices to it. + +More about Tado: +https://www.tado.com + diff --git a/tado/deviceplugintado.cpp b/tado/deviceplugintado.cpp index 684c661c..f9d6088d 100644 --- a/tado/deviceplugintado.cpp +++ b/tado/deviceplugintado.cpp @@ -1,24 +1,30 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Bernhard Trinnes * - * * - * 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 * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "deviceplugintado.h" #include "devices/device.h" @@ -34,11 +40,6 @@ DevicePluginTado::DevicePluginTado() } -DevicePluginTado::~DevicePluginTado() -{ - -} - void DevicePluginTado::startPairing(DevicePairingInfo *info) { info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter the login credentials.")); @@ -53,6 +54,7 @@ void DevicePluginTado::confirmPairing(DevicePairingInfo *info, const QString &us connect(tado, &Tado::homesReceived, this, &DevicePluginTado::onHomesReceived); connect(tado, &Tado::zonesReceived, this, &DevicePluginTado::onZonesReceived); connect(tado, &Tado::zoneStateReceived, this, &DevicePluginTado::onZoneStateReceived); + connect(tado, &Tado::overlayReceived, this, &DevicePluginTado::onOverlayReceived); m_unfinishedTadoAccounts.insert(info->deviceId(), tado); m_unfinishedDevicePairings.insert(info->deviceId(), info); tado->getToken(password); @@ -88,6 +90,7 @@ void DevicePluginTado::setupDevice(DeviceSetupInfo *info) connect(tado, &Tado::homesReceived, this, &DevicePluginTado::onHomesReceived); connect(tado, &Tado::zonesReceived, this, &DevicePluginTado::onZonesReceived); connect(tado, &Tado::zoneStateReceived, this, &DevicePluginTado::onZoneStateReceived); + connect(tado, &Tado::overlayReceived, this, &DevicePluginTado::onOverlayReceived); tado->getToken(password); m_tadoAccounts.insert(device->id(), tado); m_asyncDeviceSetup.insert(tado, info); @@ -106,9 +109,6 @@ void DevicePluginTado::deviceRemoved(Device *device) if (device->deviceClassId() == tadoConnectionDeviceClassId) { Tado *tado = m_tadoAccounts.take(device->id()); tado->deleteLater(); - - } else if (device->deviceClassId() == zoneDeviceClassId) { - } if (myDevices().isEmpty() && m_pluginTimer) { @@ -129,7 +129,6 @@ void DevicePluginTado::postSetupDevice(Device *device) device->setStateValue(tadoConnectionUserDisplayNameStateTypeId, tado->username()); device->setStateValue(tadoConnectionLoggedInStateTypeId, true); device->setStateValue(tadoConnectionConnectedStateTypeId, true); - tado->getHomes(); } else if (device->deviceClassId() == zoneDeviceClassId) { @@ -169,7 +168,8 @@ void DevicePluginTado::executeAction(DeviceActionInfo *info) double temperature = action.param(zoneTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble(); if (temperature <= 0) { - tado->setOverlay(homeId, zoneId, false, 0); + QUuid requestId = tado->setOverlay(homeId, zoneId, false, 0); + m_asyncActions.insert(requestId, info); } else { tado->setOverlay(homeId, zoneId, true, temperature); } @@ -210,7 +210,8 @@ void DevicePluginTado::onAuthenticationStatusChanged(bool authenticated) Tado *tado = static_cast(sender()); if (m_unfinishedTadoAccounts.values().contains(tado) && !authenticated){ - DeviceId id = m_tadoAccounts.key(tado); + DeviceId id = m_unfinishedTadoAccounts.key(tado); + m_unfinishedTadoAccounts.remove(id); DevicePairingInfo *info = m_unfinishedDevicePairings.take(id); info->finish(Device::DeviceErrorSetupFailed); } @@ -238,10 +239,6 @@ void DevicePluginTado::onTokenReceived(Tado::Token token) DevicePairingInfo *info = m_unfinishedDevicePairings.take(id); info->finish(Device::DeviceErrorNoError); } - - if (m_tadoAccounts.values().contains(tado)) { - - } } void DevicePluginTado::onHomesReceived(QList homes) @@ -304,8 +301,6 @@ void DevicePluginTado::onZoneStateReceived(const QString &homeId, const QString } device->setStateValue(zonePowerStateTypeId, (state.heatingPowerPercentage > 0)); - - device->setStateValue(zoneConnectedStateTypeId, state.connected); device->setStateValue(zoneTargetTemperatureStateTypeId, state.settingTemperature); device->setStateValue(zoneTemperatureStateTypeId, state.temperature); @@ -313,3 +308,26 @@ void DevicePluginTado::onZoneStateReceived(const QString &homeId, const QString device->setStateValue(zoneWindowOpenStateTypeId, state.windowOpen); device->setStateValue(zoneTadoModeStateTypeId, state.tadoMode); } + +void DevicePluginTado::onOverlayReceived(const QString &homeId, const QString &zoneId, const Tado::Overlay &overlay) +{ + Tado *tado = static_cast(sender()); + DeviceId parentId = m_tadoAccounts.key(tado); + ParamList params; + params.append(Param(zoneDeviceHomeIdParamTypeId, homeId)); + params.append(Param(zoneDeviceZoneIdParamTypeId, zoneId)); + Device *device = myDevices().filterByParentDeviceId(parentId).findByParams(params); + if (!device) + return; + device->setStateValue(zoneTargetTemperatureStateTypeId, overlay.temperature); + + if (overlay.tadoMode == "MANUAL") { + if (overlay.power) { + device->setStateValue(zoneModeStateTypeId, "Manual"); + } else { + device->setStateValue(zoneModeStateTypeId, "Off"); + } + } else { + device->setStateValue(zoneModeStateTypeId, "Tado"); + } +} diff --git a/tado/deviceplugintado.h b/tado/deviceplugintado.h index 46bdfa83..26972be4 100644 --- a/tado/deviceplugintado.h +++ b/tado/deviceplugintado.h @@ -1,24 +1,30 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2020 Bernhard Trinnes * - * * - * 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 * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef DEVICEPLUGINTADO_H #define DEVICEPLUGINTADO_H @@ -39,8 +45,6 @@ class DevicePluginTado : public DevicePlugin public: explicit DevicePluginTado(); - ~DevicePluginTado(); - void startPairing(DevicePairingInfo *info) override; void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override; void setupDevice(DeviceSetupInfo *info) override; @@ -55,6 +59,7 @@ private: QHash m_tadoAccounts; QHash m_asyncDeviceSetup; + QHash m_asyncActions; private slots: void onPluginTimer(); @@ -65,6 +70,7 @@ private slots: void onHomesReceived(QList homes); void onZonesReceived(const QString &homeId, QList zones); void onZoneStateReceived(const QString &homeId,const QString &zoneId, Tado::ZoneState sate); + void onOverlayReceived(const QString &homeId, const QString &zoneId, const Tado::Overlay &overlay); }; #endif // DEVICEPLUGINTADO_H diff --git a/tado/tado.cpp b/tado/tado.cpp index 4390a5f0..80e60608 100644 --- a/tado/tado.cpp +++ b/tado/tado.cpp @@ -1,24 +1,30 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Bernhard Trinnes * - * * - * 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 * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "tado.h" #include "extern-plugininfo.h" @@ -72,33 +78,47 @@ void Tado::getToken(const QString &password) if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } - if (status == 400 || status == 401) { + if (status == 401) { emit authenticationStatusChanged(false); } qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); - emit authenticationStatusChanged(true); QJsonParseError error; QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { - qDebug(dcTado()) << "Get Token: Recieved invalide JSON object"; + qDebug(dcTado()) << "Get Token: Received invalide JSON object"; return; } - Token token; - QVariantMap obj = data.toVariant().toMap(); - token.accesToken = obj["access_token"].toString(); - m_accessToken = token.accesToken; - token.tokenType = obj["token_type"].toString(); - token.refreshToken = obj["refresh_token"].toString(); - m_refreshToken = token.refreshToken; - token.expires = obj["expires_in"].toInt(); - m_refreshTimer->start((token.expires - 10)*1000); - token.scope = obj["scope"].toString(); - token.jti = obj["jti"].toString(); - emit tokenReceived(token); + if (data.isObject()) { + Token token; + QVariantMap obj = data.toVariant().toMap(); + if (obj.contains("access_token")) { + token.accesToken = obj["access_token"].toString(); + m_accessToken = token.accesToken; + } else { + qCWarning(dcTado()) << "Received response doesnt contain an access token"; + } + + token.tokenType = obj["token_type"].toString(); + token.refreshToken = obj["refresh_token"].toString(); + m_refreshToken = token.refreshToken; + if (obj.contains("expires_in")) { + token.expires = obj["expires_in"].toInt(); + m_refreshTimer->start((token.expires - 10)*1000); + } else { + qCWarning(dcTado()) << "Received response doesn't contain an expire time"; + } + token.scope = obj["scope"].toString(); + token.jti = obj["jti"].toString(); + emit authenticationStatusChanged(true); + emit tokenReceived(token); + } else { + qCWarning(dcTado()) << "Received response isn't an object" << data.toJson(); + emit authenticationStatusChanged(false); + } }); } @@ -119,12 +139,14 @@ void Tado::getHomes() if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } - if (status == 400 || status == 401) { + if (status == 401) { emit authenticationStatusChanged(false); } qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); return; } + emit connectionChanged(true); + emit authenticationStatusChanged(true); QJsonParseError error; QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); @@ -163,12 +185,14 @@ void Tado::getZones(const QString &homeId) if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } - if (status == 400 || status == 401) { + if (status == 401) { emit authenticationStatusChanged(false); } qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); return; } + emit connectionChanged(true); + emit authenticationStatusChanged(true); QJsonParseError error; QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); @@ -207,19 +231,24 @@ void Tado::getZoneState(const QString &homeId, const QString &zoneId) if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } - if (status == 400 || status == 401) { + if (status == 401) { emit authenticationStatusChanged(false); } qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); return; } + emit connectionChanged(true); + emit authenticationStatusChanged(true); + QJsonParseError error; QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qDebug(dcTado()) << "Get Token: Recieved invalide JSON object"; return; } + + qDebug(dcTado()) << "Get zone stat" << data; ZoneState state; QVariantMap map = data.toVariant().toMap(); state.tadoMode = map["tadoMode"].toString(); @@ -244,8 +273,9 @@ void Tado::getZoneState(const QString &homeId, const QString &zoneId) state.overlayIsSet = true; QVariantMap overlayMap = map["overlay"].toMap(); state.overlayType = map["overlayType"].toString(); - state.overlaySettingPower = (overlayMap["settings"].toMap().value("power").toString() == "ON"); - state.overlaySettingTemperature = overlayMap["settings"].toMap().value("temperature").toDouble(); + qCDebug(dcTado()) << "Overlay power" << overlayMap["setting"].toMap().value("power").toString() << overlayMap["setting"].toMap().value("temperature").toDouble(); + state.overlaySettingPower = (overlayMap["setting"].toMap().value("power").toString() == "ON"); + state.overlaySettingTemperature = overlayMap["setting"].toMap().value("temperature").toDouble(); } else { state.overlayIsSet = false; } @@ -253,26 +283,13 @@ void Tado::getZoneState(const QString &homeId, const QString &zoneId) }); } -void Tado::setOverlay(const QString &homeId, const QString &zoneId, bool power, double targetTemperature) +QUuid Tado::setOverlay(const QString &homeId, const QString &zoneId, bool power, double targetTemperature) { + QUuid requestId = QUuid::createUuid(); QNetworkRequest request; request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/overlay")); request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json;charset=utf-8"); request.setRawHeader("Authorization", "Bearer " + m_accessToken.toLocal8Bit()); - /*QJsonDocument doc; - QJsonObject obj; - QJsonObject setting; - setting.insert("power", "ON"); - QJsonObject temperature; - temperature.insert("celsius", targetTemperature); - //temperature.insert("fahrenheit", (targetTemperature * (9.0/5.0)) + 32.0); - setting.insert("type", "HEATING"); - setting.insert("temperature", temperature); - obj.insert("setting", setting); - QJsonObject termination; - termination.insert("type", "MANUAL"); - obj.insert("termination", termination); - doc.setObject(obj);*/ QByteArray body; QByteArray powerString; @@ -282,23 +299,30 @@ void Tado::setOverlay(const QString &homeId, const QString &zoneId, bool power, powerString = "OFF"; body.append("{\"setting\":{\"type\":\"HEATING\",\"power\":\""+ powerString + "\",\"temperature\":{\"celsius\":" + QVariant(targetTemperature).toByteArray() + "}},\"termination\":{\"type\":\"MANUAL\"}}"); + qCDebug(dcTado()) << "Sending request" << body; QNetworkReply *reply = m_networkManager->put(request, body); - connect(reply, &QNetworkReply::finished, this, [reply, this] { + connect(reply, &QNetworkReply::finished, this, [homeId, zoneId, requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { + emit requestExecuted(requestId, false); if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } - if (status == 400 || status == 401) { + if (status == 401) { //Unauthorized emit authenticationStatusChanged(false); + } else if (status == 422) { //Unprocessable Entity + qCWarning(dcTado()) << "Unprocessable Entity, probably a value out of range"; + } else { + qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); } - qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); return; } + emit authenticationStatusChanged(true); + emit connectionChanged(true); + emit requestExecuted(requestId, true); QJsonParseError error; QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); @@ -307,32 +331,72 @@ void Tado::setOverlay(const QString &homeId, const QString &zoneId, bool power, return; } QVariantMap map = data.toVariant().toMap(); - qCDebug(dcTado()) << map["type"].toString(); + + Overlay overlay; + QVariantMap settingsMap = map["setting"].toMap(); + overlay.zoneType = settingsMap["type"].toString(); + overlay.power = (settingsMap["power"].toString() == "ON"); + overlay.temperature = settingsMap["temperature"].toMap().value("celsius").toDouble(); + QVariantMap terminationMap = map["termination"].toMap(); + overlay.terminationType = terminationMap["type"].toString(); + + overlay.tadoMode = map["type"].toString(); + emit overlayReceived(homeId, zoneId, overlay); }); + return requestId; } -void Tado::deleteOverlay(const QString &homeId, const QString &zoneId) +QUuid Tado::deleteOverlay(const QString &homeId, const QString &zoneId) { + QUuid requestId = QUuid::createUuid(); QNetworkRequest request; request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/overlay")); request.setRawHeader("Authorization", "Bearer " + m_accessToken.toLocal8Bit()); QNetworkReply *reply = m_networkManager->deleteResource(request); - connect(reply, &QNetworkReply::finished, this, [reply, this] { + connect(reply, &QNetworkReply::finished, this, [homeId, zoneId, requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status < 200 || status > 210 || reply->error() != QNetworkReply::NoError) { + emit requestExecuted(requestId ,false); if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } - if (status == 400 || status == 401) { + if (status == 401) { //Unauthorized emit authenticationStatusChanged(false); + } else if (status == 422) { //Unprocessable Entity + qCWarning(dcTado()) << "Unprocessable Entity, probably a value out of range"; + } else { + qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); } qCWarning(dcTado()) << "Request error:" << status << reply->errorString(); return; } + emit authenticationStatusChanged(true); + emit connectionChanged(true); + emit requestExecuted(requestId, true); + + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qDebug(dcTado()) << "Get Token: Recieved invalide JSON object"; + return; + } + QVariantMap map = data.toVariant().toMap(); + + Overlay overlay; + QVariantMap settingsMap = map["setting"].toMap(); + overlay.zoneType = settingsMap["type"].toString(); + overlay.power = (settingsMap["power"].toString() == "ON"); + overlay.temperature = settingsMap["temperature"].toMap().value("celsius").toDouble(); + QVariantMap terminationMap = map["termination"].toMap(); + overlay.terminationType = terminationMap["type"].toString(); + + overlay.tadoMode = map["type"].toString(); + emit overlayReceived(homeId, zoneId, overlay); }); + return requestId; } void Tado::onRefreshTimer() diff --git a/tado/tado.h b/tado/tado.h index 50f21c67..22320428 100644 --- a/tado/tado.h +++ b/tado/tado.h @@ -1,24 +1,30 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Bernhard Trinnes * - * * - * 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 * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef TADO_H #define TADO_H @@ -28,6 +34,7 @@ #include #include +#include class Tado : public QObject { @@ -48,6 +55,15 @@ public: QString type; }; + struct Overlay { + bool power; + double temperature; + QString zoneType; + QString terminationType; + QString tadoMode; + }; + + struct ZoneState { bool connected; bool power; @@ -81,8 +97,8 @@ public: void getZones(const QString &homeId); void getZoneState(const QString &homeId, const QString &zoneId); - void setOverlay(const QString &homeId, const QString &zoneId, bool power, double targetTemperature); - void deleteOverlay(const QString &homeId, const QString &zoneId); + QUuid setOverlay(const QString &homeId, const QString &zoneId, bool power, double targetTemperature); + QUuid deleteOverlay(const QString &homeId, const QString &zoneId); private: QByteArray m_baseAuthorizationUrl = "https://auth.tado.com/oauth/token"; @@ -99,12 +115,14 @@ private: signals: void connectionChanged(bool connected); void authenticationStatusChanged(bool authenticated); + void requestExecuted(QUuid requestId, bool success); void tokenReceived(Token token); - void homesReceived(QList homes); void zonesReceived(const QString &homeId, QList zones); void zoneStateReceived(const QString &homeId,const QString &zoneId, ZoneState sate); + void overlayReceived(const QString &homeId, const QString &zoneId, const Overlay &overlay); + private slots: void onRefreshTimer();