mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-10-23 14:43:44 +02:00
Add
This commit is contained in:
parent
f5bdc2e8c2
commit
453179ab53
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#include <network/networkdevicediscovery.h>
|
#include <network/networkdevicediscovery.h>
|
||||||
|
|
||||||
|
#include "senecconnection.h"
|
||||||
|
|
||||||
IntegrationPluginSenec::IntegrationPluginSenec()
|
IntegrationPluginSenec::IntegrationPluginSenec()
|
||||||
{
|
{
|
||||||
// Testing the convert methods
|
// Testing the convert methods
|
||||||
@ -52,6 +54,8 @@ IntegrationPluginSenec::IntegrationPluginSenec()
|
|||||||
// QString rawValue = "u8_64"; // 100
|
// QString rawValue = "u8_64"; // 100
|
||||||
// quint8 value = SenecStorageLan::parseUInt8(rawValue);
|
// quint8 value = SenecStorageLan::parseUInt8(rawValue);
|
||||||
// qCWarning(dcSenec()) << rawValue << value;
|
// qCWarning(dcSenec()) << rawValue << value;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IntegrationPluginSenec::~IntegrationPluginSenec()
|
IntegrationPluginSenec::~IntegrationPluginSenec()
|
||||||
@ -107,7 +111,31 @@ void IntegrationPluginSenec::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
|
|
||||||
void IntegrationPluginSenec::startPairing(ThingPairingInfo *info)
|
void IntegrationPluginSenec::startPairing(ThingPairingInfo *info)
|
||||||
{
|
{
|
||||||
info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter username and password for your SENEC.home account."));
|
if (info->thingClassId() == senecConnectionThingClassId) {
|
||||||
|
qCDebug(dcSenec()) << "Start pairing process ...";
|
||||||
|
|
||||||
|
SenecConnection *connection = new SenecConnection(hardwareManager()->networkManager(), this);
|
||||||
|
//m_unfinishedTadoAccounts.insert(info->thingId(), tado);
|
||||||
|
|
||||||
|
connect(info, &ThingPairingInfo::aborted, this, [connection]() {
|
||||||
|
qCWarning(dcSenec()) << "Thing pairing has been aborted, cleaning up...";
|
||||||
|
//m_unfinishedTadoAccounts.remove(info->thingId());
|
||||||
|
connection->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(connection, &SenecConnection::initFinished, info, [info, connection] (bool success) {
|
||||||
|
if (!success) {
|
||||||
|
info->finish(Thing::ThingErrorAuthenticationFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcSenec()) << "Senec server is reachable. Starting the OpenID auth process" << connection->authEndpoint().toString(QUrl::FullyEncodedy);
|
||||||
|
info->setOAuthUrl(connection->authEndpoint());
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
});
|
||||||
|
|
||||||
|
connection->initialize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginSenec::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret)
|
void IntegrationPluginSenec::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret)
|
||||||
|
|||||||
@ -40,6 +40,43 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "290e4abb-d000-43a4-9e23-e298e5c36707",
|
||||||
|
"name": "senecConnection",
|
||||||
|
"displayName": "SENEC connection",
|
||||||
|
"interfaces": ["account"],
|
||||||
|
"createMethods": ["user"],
|
||||||
|
"setupMethod": "oauth",
|
||||||
|
"paramTypes": [
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "1180576a-1de2-4815-b442-877b572ce586",
|
||||||
|
"name": "connected",
|
||||||
|
"displayName": "Connected",
|
||||||
|
"displayNameEvent": "Connected changed",
|
||||||
|
"defaultValue": true,
|
||||||
|
"cached": false,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ff40d5c7-3095-4b3e-9e10-4c0774336764",
|
||||||
|
"name": "loggedIn",
|
||||||
|
"displayName": "Logged in",
|
||||||
|
"displayNameEvent": "Logged in changed",
|
||||||
|
"defaultValue": true,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5d3b2396-6528-47c2-b5a4-f751531bccea",
|
||||||
|
"name": "userDisplayName",
|
||||||
|
"displayName": "User name",
|
||||||
|
"displayNameEvent": "User name changed",
|
||||||
|
"defaultValue": "",
|
||||||
|
"type": "QString"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "345df3b1-d411-4db5-bbb2-3b14eb86c1ba",
|
"id": "345df3b1-d411-4db5-bbb2-3b14eb86c1ba",
|
||||||
"name": "senecStorageLan",
|
"name": "senecStorageLan",
|
||||||
|
|||||||
@ -5,12 +5,14 @@ QT+= network
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationpluginsenec.cpp \
|
integrationpluginsenec.cpp \
|
||||||
senecaccount.cpp \
|
senecaccount.cpp \
|
||||||
|
senecconnection.cpp \
|
||||||
senecdiscovery.cpp \
|
senecdiscovery.cpp \
|
||||||
senecstoragelan.cpp
|
senecstoragelan.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationpluginsenec.h \
|
integrationpluginsenec.h \
|
||||||
senecaccount.h \
|
senecaccount.h \
|
||||||
|
senecconnection.h \
|
||||||
senecdiscovery.h \
|
senecdiscovery.h \
|
||||||
senecstoragelan.h
|
senecstoragelan.h
|
||||||
|
|
||||||
|
|||||||
184
senec/senecconnection.cpp
Normal file
184
senec/senecconnection.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*
|
||||||
|
* Copyright 2013 - 2025, 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
|
||||||
|
* 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 "senecconnection.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
#include <QUrlQuery>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
SenecConnection::SenecConnection(NetworkAccessManager *networkManager, QObject *parent)
|
||||||
|
: QObject{parent},
|
||||||
|
m_networkManager{networkManager}
|
||||||
|
{
|
||||||
|
m_configUrl = QUrl("https://sso.senec.com/realms/senec/.well-known/openid-configuration");
|
||||||
|
m_systemsUrl = QUrl("https://senec-app-systems-proxy.prod.senec.dev");
|
||||||
|
m_measurementsUrl = QUrl("https://senec-app-measurements-proxy.prod.senec.dev");
|
||||||
|
|
||||||
|
m_clientId = QString("endcustomer-app-frontend");
|
||||||
|
m_redirectUrl =/* QString("http://127.0.0.1:8888");*/ QUrl("senec-app-auth://keycloak.prod");
|
||||||
|
m_scopes << "roles" << "meinsenec" << "openid";
|
||||||
|
m_userAgent = QString("nymea (+https://github.com/nymea/nymea)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SenecConnection::initialize()
|
||||||
|
{
|
||||||
|
qCDebug(dcSenec()) << "OpenID: Initialize and get configuration";
|
||||||
|
|
||||||
|
QNetworkRequest request(m_configUrl);
|
||||||
|
request.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent.toUtf8());
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [this, reply, request](){
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcSenec()) << "OpenID: Failed to get configuration" << request.url().toString() << reply->errorString();
|
||||||
|
if (!data.isEmpty())
|
||||||
|
qCWarning(dcSenec()) << "OpenID: Response data:" << qUtf8Printable(data);
|
||||||
|
|
||||||
|
emit initFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qCDebug(dcPushNotifications()) << "OAuth2: Request access token response" << qUtf8Printable(data);
|
||||||
|
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
if (error.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(dcSenec()) << "OpenID: Failed to get configuration. Response data JSON error:" << error.errorString();
|
||||||
|
emit initFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap configMap = jsonDoc.toVariant().toMap();
|
||||||
|
m_authEndpoint = QUrl(configMap.value("authorization_endpoint").toString());
|
||||||
|
|
||||||
|
QUrlQuery queryParams;
|
||||||
|
queryParams.addQueryItem("client_id", m_clientId);
|
||||||
|
queryParams.addQueryItem("redirect_uri", m_redirectUrl.toString());
|
||||||
|
queryParams.addQueryItem("response_type", "code");
|
||||||
|
queryParams.addQueryItem("scope", m_scopes.join("+"));
|
||||||
|
|
||||||
|
// queryParams.addQueryItem("nonce", QUuid::createUuid().toString());
|
||||||
|
// m_codeChallenge = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
||||||
|
|
||||||
|
// queryParams.addQueryItem("code_challenge", m_codeChallenge);
|
||||||
|
// queryParams.addQueryItem("code_challenge_method", "S256");
|
||||||
|
m_authEndpoint.setQuery(queryParams);
|
||||||
|
emit initFinished(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl SenecConnection::authEndpoint() const
|
||||||
|
{
|
||||||
|
return m_authEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void SenecConnection::login(const QString &username, const QString &password)
|
||||||
|
// {
|
||||||
|
// Q_UNUSED(username, password)
|
||||||
|
// QNetworkRequest request(m_configUrl);
|
||||||
|
// request.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent.toUtf8());
|
||||||
|
|
||||||
|
// QNetworkReply *reply = m_networkManager->get(request);
|
||||||
|
// connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
|
// connect(reply, &QNetworkReply::finished, this, [this, reply, request](){
|
||||||
|
|
||||||
|
// QByteArray data = reply->readAll();
|
||||||
|
// if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
// qCWarning(dcSenec()) << "OpenID: Failed to get configuration" << request.url().toString() << reply->errorString();
|
||||||
|
// if (!data.isEmpty())
|
||||||
|
// qCWarning(dcSenec()) << "OpenID: Response data:" << qUtf8Printable(data);
|
||||||
|
|
||||||
|
// // setAuthenticated(false);
|
||||||
|
|
||||||
|
// // // Retry in 30 seconds, maybe we are not online yet
|
||||||
|
// // m_refreshTimer.start(60 * 1000);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //qCDebug(dcPushNotifications()) << "OAuth2: Request access token response" << qUtf8Printable(data);
|
||||||
|
|
||||||
|
// QJsonParseError error;
|
||||||
|
// QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
// if (error.error != QJsonParseError::NoError) {
|
||||||
|
// qCWarning(dcSenec()) << "OpenID: Failed to get configuration. Response data JSON error:" << error.errorString();
|
||||||
|
// //setAuthenticated(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// QVariantMap configMap = jsonDoc.toVariant().toMap();
|
||||||
|
// m_authEndpoint = QUrl(configMap.value("authorization_endpoint").toString());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // QUrl url(m_baseTokenUrl);
|
||||||
|
// // QUrlQuery query;
|
||||||
|
// // query.clear();
|
||||||
|
// // query.addQueryItem("grant_type", "refresh_token");
|
||||||
|
// // query.addQueryItem("refresh_token", refreshToken);
|
||||||
|
// // query.addQueryItem("client_secret", m_clientSecret);
|
||||||
|
|
||||||
|
// // QNetworkRequest request(m_authEndpoint);
|
||||||
|
// // request.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent.toUtf8());
|
||||||
|
// // request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
|
||||||
|
|
||||||
|
// // // QUrlQuery queryParams;
|
||||||
|
// // // queryParams.addQueryItem("client_id", m_clientId);
|
||||||
|
// // // queryParams.addQueryItem("redirect_uri", m_redirectUrl);
|
||||||
|
// // // queryParams.addQueryItem("response_type", "code");
|
||||||
|
// // // queryParams.addQueryItem("scope", m_scopes.join(" "));
|
||||||
|
// // // queryParams.addQueryItem("nonce", QUuid::createUuid().toString());
|
||||||
|
// // // m_codeChallenge = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
||||||
|
|
||||||
|
// // // queryParams.addQueryItem("code_challenge", m_codeChallenge);
|
||||||
|
// // // queryParams.addQueryItem("code_challenge_method", "S256");
|
||||||
|
// // // url.setQuery(queryParams);
|
||||||
|
|
||||||
|
|
||||||
|
// // // QNetworkReply *reply = m_networkManager->post(request, query.toString().toUtf8());
|
||||||
|
// // // connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
|
// // // connect(reply, &QNetworkReply::finished, this, [this, reply](){
|
||||||
|
|
||||||
|
// // redirect_uri: REDIRECT_URI,
|
||||||
|
// // scope: SCOPE,
|
||||||
|
// // code_challenge:,
|
||||||
|
// // code_challenge_method: 'S256',
|
||||||
|
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// });
|
||||||
|
// }
|
||||||
72
senec/senecconnection.h
Normal file
72
senec/senecconnection.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*
|
||||||
|
* Copyright 2013 - 2025, 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
|
||||||
|
* 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 SENECCONNECTION_H
|
||||||
|
#define SENECCONNECTION_H
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <network/networkaccessmanager.h>
|
||||||
|
|
||||||
|
class SenecConnection : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SenecConnection(NetworkAccessManager *networkManager, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
QUrl authEndpoint() const;
|
||||||
|
|
||||||
|
// void login(const QString &username, const QString &password);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void initFinished(bool success);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetworkAccessManager *m_networkManager = nullptr;
|
||||||
|
|
||||||
|
QUrl m_configUrl;
|
||||||
|
QUrl m_systemsUrl;
|
||||||
|
QUrl m_measurementsUrl;
|
||||||
|
|
||||||
|
QString m_clientId;
|
||||||
|
QUrl m_redirectUrl;
|
||||||
|
QStringList m_scopes;
|
||||||
|
QString m_userAgent;
|
||||||
|
|
||||||
|
// Fetch from config url
|
||||||
|
QUrl m_authEndpoint;
|
||||||
|
QString m_codeChallenge;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SENECCONNECTION_H
|
||||||
@ -1,6 +1,6 @@
|
|||||||
include(../plugins.pri)
|
include(../plugins.pri)
|
||||||
|
|
||||||
QT *= serialport
|
QT += serialport
|
||||||
|
|
||||||
PKGCONFIG += libudev
|
PKGCONFIG += libudev
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user