added dyn. api credentials optaining

This commit is contained in:
Boernsman 2020-10-27 13:08:25 +01:00
parent df59d45e83
commit bc2ff5b7be
3 changed files with 125 additions and 39 deletions

View File

@ -63,13 +63,6 @@ void IntegrationPluginTado::confirmPairing(ThingPairingInfo *info, const QString
{ {
qCDebug(dcTado()) << "Confirm pairing" << username << "Network manager available" << hardwareManager()->networkManager()->available(); qCDebug(dcTado()) << "Confirm pairing" << username << "Network manager available" << hardwareManager()->networkManager()->available();
Tado *tado = new Tado(hardwareManager()->networkManager(), username, this); Tado *tado = new Tado(hardwareManager()->networkManager(), username, this);
connect(tado, &Tado::authenticationStatusChanged, this, &IntegrationPluginTado::onAuthenticationStatusChanged);
connect(tado, &Tado::requestExecuted, this, &IntegrationPluginTado::onRequestExecuted);
connect(tado, &Tado::connectionChanged, this, &IntegrationPluginTado::onConnectionChanged);
connect(tado, &Tado::homesReceived, this, &IntegrationPluginTado::onHomesReceived);
connect(tado, &Tado::zonesReceived, this, &IntegrationPluginTado::onZonesReceived);
connect(tado, &Tado::zoneStateReceived, this, &IntegrationPluginTado::onZoneStateReceived);
connect(tado, &Tado::overlayReceived, this, &IntegrationPluginTado::onOverlayReceived);
m_unfinishedTadoAccounts.insert(info->thingId(), tado); m_unfinishedTadoAccounts.insert(info->thingId(), tado);
connect(info, &ThingPairingInfo::aborted, this, [info, tado, this]() { connect(info, &ThingPairingInfo::aborted, this, [info, tado, this]() {
@ -78,13 +71,18 @@ void IntegrationPluginTado::confirmPairing(ThingPairingInfo *info, const QString
tado->deleteLater(); tado->deleteLater();
}); });
connect(tado, &Tado::connectionError, info, [this, info] (QNetworkReply::NetworkError error){ connect(tado, &Tado::connectionError, info, [info] (QNetworkReply::NetworkError error){
if (error != QNetworkReply::NetworkError::NoError){ if (error != QNetworkReply::NetworkError::NoError){
info->finish(Thing::ThingErrorSetupFailed); qCWarning(dcTado()) << "Confirm pairing failed" << error;
info->finish(Thing::ThingErrorSetupFailed, tr("Connection error"));
} }
// info->finish(success) will be called after the token has been received // info->finish(success) will be called after the token has been received
}); });
connect(tado, &Tado::apiCredentialsReceived, info, [password, tado] {
tado->getToken(password);
});
connect(tado, &Tado::tokenReceived, info, [this, info, username, password](Tado::Token token) { connect(tado, &Tado::tokenReceived, info, [this, info, username, password](Tado::Token token) {
Q_UNUSED(token) Q_UNUSED(token)
@ -95,7 +93,7 @@ void IntegrationPluginTado::confirmPairing(ThingPairingInfo *info, const QString
info->finish(Thing::ThingErrorNoError); info->finish(Thing::ThingErrorNoError);
}); });
tado->getToken(password); tado->getApiCredentials();
} }
void IntegrationPluginTado::setupThing(ThingSetupInfo *info) void IntegrationPluginTado::setupThing(ThingSetupInfo *info)
@ -109,7 +107,7 @@ void IntegrationPluginTado::setupThing(ThingSetupInfo *info)
if (m_unfinishedTadoAccounts.contains(thing->id())) { if (m_unfinishedTadoAccounts.contains(thing->id())) {
tado = m_unfinishedTadoAccounts.take(thing->id()); tado = m_unfinishedTadoAccounts.take(thing->id());
m_tadoAccounts.insert(thing->id(), tado); m_tadoAccounts.insert(thing->id(), tado);
return info->finish(Thing::ThingErrorNoError); info->finish(Thing::ThingErrorNoError);
} else { } else {
pluginStorage()->beginGroup(thing->id().toString()); pluginStorage()->beginGroup(thing->id().toString());
QString username = pluginStorage()->value("username").toString(); QString username = pluginStorage()->value("username").toString();
@ -117,14 +115,6 @@ void IntegrationPluginTado::setupThing(ThingSetupInfo *info)
pluginStorage()->endGroup(); pluginStorage()->endGroup();
tado = new Tado(hardwareManager()->networkManager(), username, this); tado = new Tado(hardwareManager()->networkManager(), username, this);
connect(tado, &Tado::authenticationStatusChanged, this, &IntegrationPluginTado::onAuthenticationStatusChanged);
connect(tado, &Tado::requestExecuted, this, &IntegrationPluginTado::onRequestExecuted);
connect(tado, &Tado::connectionChanged, this, &IntegrationPluginTado::onConnectionChanged);
connect(tado, &Tado::homesReceived, this, &IntegrationPluginTado::onHomesReceived);
connect(tado, &Tado::zonesReceived, this, &IntegrationPluginTado::onZonesReceived);
connect(tado, &Tado::zoneStateReceived, this, &IntegrationPluginTado::onZoneStateReceived);
connect(tado, &Tado::overlayReceived, this, &IntegrationPluginTado::onOverlayReceived);
m_tadoAccounts.insert(thing->id(), tado); m_tadoAccounts.insert(thing->id(), tado);
connect(info, &ThingSetupInfo::aborted, [info, this] { connect(info, &ThingSetupInfo::aborted, [info, this] {
if (m_tadoAccounts.contains(info->thing()->id())) { if (m_tadoAccounts.contains(info->thing()->id())) {
@ -133,7 +123,11 @@ void IntegrationPluginTado::setupThing(ThingSetupInfo *info)
} }
}); });
connect(tado, &Tado::tokenReceived, info, [this, info, tado](Tado::Token token) { connect(tado, &Tado::apiCredentialsReceived, info, [password, tado] {
tado->getToken(password);
});
connect(tado, &Tado::tokenReceived, info, [ info](Tado::Token token) {
Q_UNUSED(token) Q_UNUSED(token)
qCDebug(dcTado()) << "Token received, account setup successfull"; qCDebug(dcTado()) << "Token received, account setup successfull";
@ -141,18 +135,7 @@ void IntegrationPluginTado::setupThing(ThingSetupInfo *info)
}); });
connect(tado, &Tado::connectionError, info, [this, info] (QNetworkReply::NetworkError error){ connect(tado, &Tado::connectionError, info, [this, info] (QNetworkReply::NetworkError error){
if (error == QNetworkReply::NetworkError::HostNotFoundError) { if (error != QNetworkReply::NetworkError::NoError){
QTimer::singleShot(2000, info, [info, this] {
pluginStorage()->beginGroup(info->thing()->id().toString());
QString password = pluginStorage()->value("password").toString();
pluginStorage()->endGroup();
if (m_tadoAccounts.contains(info->thing()->id())) {
Tado *tado = m_tadoAccounts.take(info->thing()->id());
tado->getToken(password);
}
});
} else if (error != QNetworkReply::NetworkError::NoError){
if (m_tadoAccounts.contains(info->thing()->id())) { if (m_tadoAccounts.contains(info->thing()->id())) {
Tado *tado = m_tadoAccounts.take(info->thing()->id()); Tado *tado = m_tadoAccounts.take(info->thing()->id());
tado->deleteLater(); tado->deleteLater();
@ -160,15 +143,23 @@ void IntegrationPluginTado::setupThing(ThingSetupInfo *info)
info->finish(Thing::ThingErrorSetupFailed); info->finish(Thing::ThingErrorSetupFailed);
} }
}); });
tado->getToken(password); tado->getApiCredentials();
} }
connect(tado, &Tado::authenticationStatusChanged, this, &IntegrationPluginTado::onAuthenticationStatusChanged);
connect(tado, &Tado::requestExecuted, this, &IntegrationPluginTado::onRequestExecuted);
connect(tado, &Tado::connectionChanged, this, &IntegrationPluginTado::onConnectionChanged);
connect(tado, &Tado::homesReceived, this, &IntegrationPluginTado::onHomesReceived);
connect(tado, &Tado::zonesReceived, this, &IntegrationPluginTado::onZonesReceived);
connect(tado, &Tado::zoneStateReceived, this, &IntegrationPluginTado::onZoneStateReceived);
connect(tado, &Tado::overlayReceived, this, &IntegrationPluginTado::onOverlayReceived);
return;
} else if (thing->thingClassId() == zoneThingClassId) { } else if (thing->thingClassId() == zoneThingClassId) {
qCDebug(dcTado) << "Setup tado thermostat" << thing->params(); qCDebug(dcTado) << "Setup tado thermostat" << thing->params();
return info->finish(Thing::ThingErrorNoError); return info->finish(Thing::ThingErrorNoError);
} else { } else {
return info->finish(Thing::ThingErrorThingClassNotFound);
qCWarning(dcTado()) << "Unhandled thing class in setupDevice"; qCWarning(dcTado()) << "Unhandled thing class in setupDevice";
return info->finish(Thing::ThingErrorThingClassNotFound);
} }
} }

View File

@ -56,6 +56,11 @@ QString Tado::username()
return m_username; return m_username;
} }
bool Tado::apiAvailable()
{
return m_apiAvailable;
}
bool Tado::authenticated() bool Tado::authenticated()
{ {
return m_authenticationStatus; return m_authenticationStatus;
@ -66,8 +71,61 @@ bool Tado::connected()
return m_connectionStatus; return m_connectionStatus;
} }
void Tado::getApiCredentials(const QString &url)
{
QNetworkRequest request;
request.setUrl(url);
QNetworkReply *reply = m_networkManager->get(request);
qCDebug(dcTado()) << "Sending request" << request.url();
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::finished, this, [reply, this] {
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcTado()) << "Request error:" << status << reply->errorString();
return;
}
QRegExp filter;
filter.setPatternSyntax(QRegExp::Wildcard);
filter.setPattern("*tgaRestApiV2Endpoint:*");
QStringList list = QString(reply->readAll()).split('\n');
int index = list.indexOf(filter);
if (index == -1)
return;
m_baseControlUrl = list.value(index).split(": ").last().remove(QRegExp("[,']"));;
qCDebug(dcTado()) << "Received control url" << m_baseControlUrl;
filter.setPattern("*apiEndpoint*");
index = list.indexOf(filter);
if (index == -1)
return;
m_baseAuthorizationUrl = list.value(index).split(": ").last().remove(QRegExp("[,']"))+"/token";
qCDebug(dcTado()) << "Received auth url" << m_baseAuthorizationUrl;
filter.setPattern("*clientId*");
index = list.indexOf(filter);
if (index == -1)
return;
m_clientId = list.value(index).split(": ").last().remove(QRegExp("[,']"));
qCDebug(dcTado()) << "Received client id" << m_clientId;
filter.setPattern("*clientSecret*");
index = list.indexOf(filter);
if (index == -1)
return;
m_clientSecret = list.value(index).split(": ").last().remove(QRegExp("[,']"));
qCDebug(dcTado()) << "Received client secret" << m_clientSecret;
m_apiAvailable = true;
emit apiCredentialsReceived();
});
}
void Tado::getToken(const QString &password) void Tado::getToken(const QString &password)
{ {
if (!m_apiAvailable) {
qCWarning(dcTado()) << "Not sending request, get API credentials firs";
return;
}
QNetworkRequest request; QNetworkRequest request;
request.setUrl(QUrl(m_baseAuthorizationUrl)); request.setUrl(QUrl(m_baseAuthorizationUrl));
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded"); request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");
@ -102,7 +160,7 @@ void Tado::getToken(const QString &password)
QJsonParseError error; QJsonParseError error;
QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) { if (error.error != QJsonParseError::NoError) {
qDebug(dcTado()) << "Get Token: Received invalide JSON object"; qDebug(dcTado()) << "Get Token: Received invalide JSON object:" << data;
return; return;
} }
if (data.isObject()) { if (data.isObject()) {
@ -137,6 +195,11 @@ void Tado::getToken(const QString &password)
void Tado::getHomes() void Tado::getHomes()
{ {
if (!m_apiAvailable) {
qCWarning(dcTado()) << "Not sending request, get API credentials firs";
return;
}
if(m_accessToken.isEmpty()) { if(m_accessToken.isEmpty()) {
qCWarning(dcTado()) << "Not sending request, get the access token first"; qCWarning(dcTado()) << "Not sending request, get the access token first";
return; return;
@ -188,6 +251,16 @@ void Tado::getHomes()
void Tado::getZones(const QString &homeId) void Tado::getZones(const QString &homeId)
{ {
if (!m_apiAvailable) {
qCWarning(dcTado()) << "Not sending request, get API credentials firs";
return;
}
if(m_accessToken.isEmpty()) {
qCWarning(dcTado()) << "Not sending request, get the access token first";
return;
}
QNetworkRequest request; QNetworkRequest request;
request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones")); request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones"));
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded"); request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");
@ -235,10 +308,16 @@ void Tado::getZones(const QString &homeId)
void Tado::getZoneState(const QString &homeId, const QString &zoneId) void Tado::getZoneState(const QString &homeId, const QString &zoneId)
{ {
if (!m_apiAvailable) {
qCWarning(dcTado()) << "Not sending request, get API credentials firs";
return;
}
if(m_accessToken.isEmpty()) { if(m_accessToken.isEmpty()) {
qCWarning(dcTado()) << "Not sending request, get the access token first"; qCWarning(dcTado()) << "Not sending request, get the access token first";
return; return;
} }
QNetworkRequest request; QNetworkRequest request;
request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/state")); request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/state"));
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded"); request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");
@ -307,10 +386,16 @@ void Tado::getZoneState(const QString &homeId, const QString &zoneId)
QUuid 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)
{ {
if (!m_apiAvailable) {
qCWarning(dcTado()) << "Not sending request, get API credentials firs";
return "";
}
if(m_accessToken.isEmpty()) { if(m_accessToken.isEmpty()) {
qCWarning(dcTado()) << "Not sending request, get the access token first"; qCWarning(dcTado()) << "Not sending request, get the access token first";
return ""; return "";
} }
QUuid requestId = QUuid::createUuid(); QUuid requestId = QUuid::createUuid();
QNetworkRequest request; QNetworkRequest request;
request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/overlay")); request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/overlay"));
@ -376,10 +461,16 @@ QUuid Tado::setOverlay(const QString &homeId, const QString &zoneId, bool power,
QUuid Tado::deleteOverlay(const QString &homeId, const QString &zoneId) QUuid Tado::deleteOverlay(const QString &homeId, const QString &zoneId)
{ {
if (!m_apiAvailable) {
qCWarning(dcTado()) << "Not sending request, get API credentials firs";
return "";
}
if(m_accessToken.isEmpty()) { if(m_accessToken.isEmpty()) {
qCWarning(dcTado()) << "Not sending request, get the access token first"; qCWarning(dcTado()) << "Not sending request, get the access token first";
return ""; return "";
} }
QUuid requestId = QUuid::createUuid(); QUuid requestId = QUuid::createUuid();
QNetworkRequest request; QNetworkRequest request;
request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/overlay")); request.setUrl(QUrl(m_baseControlUrl+"/homes/"+homeId+"/zones/"+zoneId+"/overlay"));

View File

@ -93,9 +93,11 @@ public:
void setUsername(const QString &username); void setUsername(const QString &username);
QString username(); QString username();
bool apiAvailable();
bool authenticated(); bool authenticated();
bool connected(); bool connected();
void getApiCredentials(const QString &url = "https://my.tado.com/webapp/env.js");
void getToken(const QString &password); void getToken(const QString &password);
void getHomes(); void getHomes();
void getZones(const QString &homeId); void getZones(const QString &homeId);
@ -105,10 +107,11 @@ public:
QUuid deleteOverlay(const QString &homeId, const QString &zoneId); QUuid deleteOverlay(const QString &homeId, const QString &zoneId);
private: private:
QByteArray m_baseAuthorizationUrl = "https://auth.tado.com/oauth/token"; bool m_apiAvailable = false;
QByteArray m_baseControlUrl = "https://my.tado.com/api/v2"; QString m_baseAuthorizationUrl;
QByteArray m_clientSecret = "4HJGRffVR8xb3XdEUQpjgZ1VplJi6Xgw"; QString m_baseControlUrl;
QByteArray m_clientId = "public-api-preview"; QString m_clientSecret;
QString m_clientId;
NetworkAccessManager *m_networkManager = nullptr; NetworkAccessManager *m_networkManager = nullptr;
QString m_username; QString m_username;
@ -123,6 +126,7 @@ private:
signals: signals:
void connectionChanged(bool connected); void connectionChanged(bool connected);
void apiCredentialsReceived();
void authenticationStatusChanged(bool authenticated); void authenticationStatusChanged(bool authenticated);
void requestExecuted(QUuid requestId, bool success); void requestExecuted(QUuid requestId, bool success);