fixed state update

master
Boernsman 2020-01-03 20:16:51 +01:00
parent d47214ac14
commit 5c28eaf871
5 changed files with 265 additions and 149 deletions

View File

@ -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

View File

@ -1,24 +1,30 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* *
* 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 *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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<Tado*>(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<Tado::Home> 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<Tado*>(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");
}
}

View File

@ -1,24 +1,30 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2020 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* *
* 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 *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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<DeviceId, Tado*> m_tadoAccounts;
QHash<Tado *, DeviceSetupInfo *> m_asyncDeviceSetup;
QHash<QUuid, DeviceActionInfo *> m_asyncActions;
private slots:
void onPluginTimer();
@ -65,6 +70,7 @@ private slots:
void onHomesReceived(QList<Tado::Home> homes);
void onZonesReceived(const QString &homeId, QList<Tado::Zone> 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

View File

@ -1,24 +1,30 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* *
* 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 *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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()

View File

@ -1,24 +1,30 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* *
* 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 *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 <QObject>
#include <QTimer>
#include <QUuid>
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<Home> homes);
void zonesReceived(const QString &homeId, QList<Zone> 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();