add netatmo plugin

add OAuth2
pull/135/head
Simon Stürz 2015-10-13 18:41:35 +02:00 committed by Michael Zanetti
parent 550f8a29f4
commit 2693b1c8bd
20 changed files with 1005 additions and 19 deletions

View File

@ -20,3 +20,4 @@ usr/lib/guh/plugins/libguh_devicepluginudpcommander.so
usr/lib/guh/plugins/libguh_devicepluginkodi.so
usr/lib/guh/plugins/libguh_devicepluginelgato.so
usr/lib/guh/plugins/libguh_devicepluginawattar.so
usr/lib/guh/plugins/libguh_devicepluginnetatmo.so

View File

@ -257,12 +257,16 @@
\li 36
\li The value of the \l{Param} has unit \tt {[\%]} \unicode{0x2192} percentage.
\row
\li Types::UnitEuro
\li Types::UnitPartsPerMillion
\li 37
\li The value of the \l{Param} has unit \tt {[ppm]} \unicode{0x2192} parts per million.
\row
\li Types::UnitEuro
\li 38
\li The value of the \l{Param} has unit \tt {[€]} \unicode{0x2192} euro.
\row
\li Types::UnitDollar
\li 38
\li 39
\li The value of the \l{Param} has unit \tt {[\$]} \unicode{0x2192} dollar.
\endtable

View File

@ -2,7 +2,7 @@
GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"')
# define protocol versions
JSON_PROTOCOL_VERSION=31
JSON_PROTOCOL_VERSION=32
REST_API_VERSION=1
DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" \

View File

@ -16,11 +16,13 @@ contains(DEFINES, BLUETOOTH_LE) {
bluetooth/bluetoothlowenergydevice.h \
}
SOURCES += plugin/device.cpp \
SOURCES += devicemanager.cpp \
loggingcategories.cpp \
guhsettings.cpp \
plugin/device.cpp \
plugin/deviceclass.cpp \
plugin/deviceplugin.cpp \
plugin/devicedescriptor.cpp \
devicemanager.cpp \
hardware/gpio.cpp \
hardware/gpiomonitor.cpp \
hardware/radio433/radio433.cpp \
@ -31,6 +33,8 @@ SOURCES += plugin/device.cpp \
network/upnpdiscovery/upnpdevice.cpp \
network/upnpdiscovery/upnpdevicedescriptor.cpp \
network/upnpdiscovery/upnpdiscoveryrequest.cpp \
network/networkmanager.cpp \
network/oauth2.cpp \
types/action.cpp \
types/actiontype.cpp \
types/state.cpp \
@ -45,14 +49,15 @@ SOURCES += plugin/device.cpp \
types/ruleaction.cpp \
types/ruleactionparam.cpp \
types/statedescriptor.cpp \
loggingcategories.cpp \
guhsettings.cpp \
HEADERS += plugin/device.h \
HEADERS += devicemanager.h \
typeutils.h \
loggingcategories.h \
guhsettings.h \
plugin/device.h \
plugin/deviceclass.h \
plugin/deviceplugin.h \
plugin/devicedescriptor.h \
devicemanager.h \
hardware/gpio.h \
hardware/gpiomonitor.h \
hardware/radio433/radio433.h \
@ -63,6 +68,8 @@ HEADERS += plugin/device.h \
network/upnpdiscovery/upnpdevice.h \
network/upnpdiscovery/upnpdevicedescriptor.h \
network/upnpdiscovery/upnpdiscoveryrequest.h \
network/networkmanager.h \
network/oauth2.h \
types/action.h \
types/actiontype.h \
types/state.h \
@ -77,9 +84,6 @@ HEADERS += plugin/device.h \
types/ruleaction.h \
types/ruleactionparam.h \
types/statedescriptor.h \
typeutils.h \
loggingcategories.h \
guhsettings.h \
# install files for libguh-dev

View File

@ -25,9 +25,10 @@ Q_LOGGING_CATEGORY(dcDeviceManager, "DeviceManager")
Q_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine")
Q_LOGGING_CATEGORY(dcHardware, "Hardware")
Q_LOGGING_CATEGORY(dcConnection, "Connection")
Q_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
Q_LOGGING_CATEGORY(dcTcpServer, "TcpServer")
Q_LOGGING_CATEGORY(dcWebServer, "WebServer")
Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer")
Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc")
Q_LOGGING_CATEGORY(dcRest, "Rest")
Q_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer")
Q_LOGGING_CATEGORY(dcOAuth2, "OAuth2")

View File

@ -29,11 +29,12 @@ Q_DECLARE_LOGGING_CATEGORY(dcDeviceManager)
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine)
Q_DECLARE_LOGGING_CATEGORY(dcHardware)
Q_DECLARE_LOGGING_CATEGORY(dcConnection)
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
Q_DECLARE_LOGGING_CATEGORY(dcRest)
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
Q_DECLARE_LOGGING_CATEGORY(dcTcpServer)
Q_DECLARE_LOGGING_CATEGORY(dcWebServer)
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer)
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
Q_DECLARE_LOGGING_CATEGORY(dcRest)
Q_DECLARE_LOGGING_CATEGORY(dcOAuth2)
#endif // LOGGINGCATEGORYS_H

265
libguh/network/oauth2.cpp Normal file
View File

@ -0,0 +1,265 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "oauth2.h"
#include "loggingcategories.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QJsonDocument>
OAuth2::OAuth2(QString clientId, QString clientSecret, QObject *parent) :
QObject(parent),
m_clientId(clientId),
m_clientSecret(clientSecret),
m_authenticated(false)
{
m_networkManager = new QNetworkAccessManager(this);
connect(m_networkManager, &QNetworkAccessManager::finished, this, &OAuth2::replyFinished);
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
connect(m_timer, &QTimer::timeout, this, &OAuth2::refreshTimeout);
}
QUrl OAuth2::url() const
{
return m_url;
}
void OAuth2::setUrl(const QUrl &url)
{
m_url = url;
}
QUrlQuery OAuth2::query() const
{
return m_query;
}
void OAuth2::setQuery(const QUrlQuery &query)
{
m_query = query;
}
QString OAuth2::username() const
{
return m_username;
}
void OAuth2::setUsername(const QString &username)
{
m_username = username;
}
QString OAuth2::password() const
{
return m_password;
}
void OAuth2::setPassword(const QString &password)
{
m_password = password;
}
QString OAuth2::clientId() const
{
return m_clientId;
}
void OAuth2::setClientId(const QString &clientId)
{
m_clientId = clientId;
}
QString OAuth2::clientSecret() const
{
return m_clientSecret;
}
void OAuth2::setClientSecret(const QString clientSecret)
{
m_clientSecret = clientSecret;
}
QString OAuth2::scope() const
{
return m_scope;
}
void OAuth2::setScope(const QString &scope)
{
m_scope = scope;
}
QString OAuth2::token() const
{
return m_token;
}
bool OAuth2::authenticated() const
{
return m_authenticated;
}
void OAuth2::startAuthentication()
{
qCDebug(dcOAuth2) << "Start authentication" << m_username;
QUrlQuery query;
query.addQueryItem("grant_type", "password");
query.addQueryItem("client_id", m_clientId);
query.addQueryItem("client_secret", m_clientSecret);
query.addQueryItem("username", m_username);
query.addQueryItem("password", m_password);
query.addQueryItem("scope", m_scope);
setQuery(query);
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
m_tokenRequests.append(m_networkManager->post(request, m_query.toString().toUtf8()));
}
void OAuth2::setAuthenticated(const bool &authenticated)
{
if (authenticated) {
qCDebug(dcOAuth2) << "Authenticated successfully" << m_username;
} else {
qCWarning(dcOAuth2) << "Authentication failed" << m_username;
}
m_authenticated = authenticated;
emit authenticationChanged();
}
void OAuth2::setToken(const QString &token)
{
m_token = token;
emit tokenChanged();
}
void OAuth2::replyFinished(QNetworkReply *reply)
{
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// token request
if (m_tokenRequests.contains(reply)) {
QByteArray data = reply->readAll();
m_tokenRequests.removeAll(reply);
// check HTTP status code
if (status != 200) {
qCWarning(dcOAuth2) << "Request token reply HTTP error:" << status << reply->errorString();
qCWarning(dcOAuth2) << data;
setAuthenticated(false);
reply->deleteLater();
return;
}
// check JSON
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcOAuth2) << "Request token reply JSON error:" << error.errorString();
setAuthenticated(false);
reply->deleteLater();
return;
}
if (!jsonDoc.toVariant().toMap().contains("access_token")) {
qCWarning(dcOAuth2) << "Could not get access token" << jsonDoc.toJson();
setAuthenticated(false);
reply->deleteLater();
return;
}
setToken(jsonDoc.toVariant().toMap().value("access_token").toString());
setAuthenticated(true);
if (jsonDoc.toVariant().toMap().contains("expires_in") && jsonDoc.toVariant().toMap().contains("refresh_token")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toString();
qCDebug(dcOAuth2) << "Token will be refreshed in" << expireTime << "[s]";
m_timer->start((expireTime - 20) * 1000);
}
} else if (m_refreshTokenRequests.contains(reply)) {
QByteArray data = reply->readAll();
m_refreshTokenRequests.removeAll(reply);
// check HTTP status code
if (status != 200) {
qCWarning(dcOAuth2) << "Refresh token reply HTTP error:" << status << reply->errorString();
qCWarning(dcOAuth2) << data;
setAuthenticated(false);
reply->deleteLater();
return;
}
// check JSON
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcOAuth2) << "Refresh token reply JSON error:" << error.errorString();
setAuthenticated(false);
reply->deleteLater();
return;
}
if (!jsonDoc.toVariant().toMap().contains("access_token")) {
qCWarning(dcOAuth2) << "Could not get access token after refresh" << jsonDoc.toJson();
setAuthenticated(false);
reply->deleteLater();
return;
}
setToken(jsonDoc.toVariant().toMap().value("access_token").toString());
qCDebug(dcOAuth2) << "Token refreshed successfully";
if (jsonDoc.toVariant().toMap().contains("expires_in") && jsonDoc.toVariant().toMap().contains("refresh_token")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toString();
qCDebug(dcOAuth2) << "Token will be refreshed in" << expireTime << "[s]";
m_timer->start((expireTime - 20) * 1000);
}
if (!authenticated())
setAuthenticated(true);
}
reply->deleteLater();
}
void OAuth2::refreshTimeout()
{
qCDebug(dcOAuth2) << "Refresh authentication token for" << m_username;
QUrlQuery query;
query.addQueryItem("grant_type", "refresh_token");
query.addQueryItem("refresh_token", m_refreshToken);
query.addQueryItem("client_id", m_clientId);
query.addQueryItem("client_secret", m_clientSecret);
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
m_refreshTokenRequests.append(m_networkManager->post(request, query.toString().toUtf8()));
}

99
libguh/network/oauth2.h Normal file
View File

@ -0,0 +1,99 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef OAUTH2_H
#define OAUTH2_H
#include <QObject>
#include <QString>
#include <QTimer>
#include <QUrl>
#include <QUrlQuery>
#include <QNetworkAccessManager>
#include <QNetworkReply>
// OAuth 2.0 - Resource Owner Password Credentials Grant: http://tools.ietf.org/html/rfc6749#section-4.3
class OAuth2 : public QObject
{
Q_OBJECT
public:
explicit OAuth2(QString clientId, QString clientSecret, QObject *parent = 0);
QUrl url() const;
void setUrl(const QUrl &url);
QUrlQuery query() const;
void setQuery(const QUrlQuery &query);
QString username() const;
void setUsername(const QString &username);
QString password() const;
void setPassword(const QString &password);
QString clientId() const;
void setClientId(const QString &clientId);
QString clientSecret() const;
void setClientSecret(const QString clientSecret);
QString scope() const;
void setScope(const QString &scope);
QString token() const;
bool authenticated() const;
void startAuthentication();
private:
QNetworkAccessManager *m_networkManager;
QTimer *m_timer;
QList<QNetworkReply *> m_tokenRequests;
QList<QNetworkReply *> m_refreshTokenRequests;
QUrl m_url;
QUrlQuery m_query;
QString m_username;
QString m_password;
QString m_clientId;
QString m_clientSecret;
QString m_scope;
QString m_token;
QString m_refreshToken;
bool m_authenticated;
void setAuthenticated(const bool &authenticated);
void setToken(const QString &token);
private slots:
void replyFinished(QNetworkReply *reply);
void refreshTimeout();
signals:
void authenticationChanged();
void tokenChanged();
};
#endif // OAUTH2_H

View File

@ -760,6 +760,8 @@ Types::Unit DevicePlugin::unitStringToUnit(const QString &unitString) const
return Types::UnitEuroPerMegaWattHour;
} else if (unitString == "Percentage") {
return Types::UnitPercentage;
} else if (unitString == "PartsPerMillion") {
return Types::UnitPartsPerMillion;
} else if (unitString == "Euro") {
return Types::UnitEuro;
} else if (unitString == "Dollar") {

View File

@ -115,6 +115,7 @@ public:
UnitKiloWattHour,
UnitEuroPerMegaWattHour,
UnitPercentage,
UnitPartsPerMillion,
UnitEuro,
UnitDollar
};

View File

@ -44,7 +44,7 @@
\note If a \l{StateType} has the parameter \tt{"writable": {...}}, an \l{ActionType} with the same uuid and \l{ParamType}{ParamTypes}
will be created automatically.
\quotefile plugins/deviceplugins/udpcommander/devicepluginawattar.json
\quotefile plugins/deviceplugins/awattar/devicepluginawattar.json
*/
#include "devicepluginawattar.h"

View File

@ -20,6 +20,7 @@ SUBDIRS += elro \
kodi \
elgato \
awattar \
netatmo \

View File

@ -1,6 +1,7 @@
{
"name": "Elgato",
"id": "c5c03ad4-bfdb-444a-8eca-2c234c46cc27",
"idName": "Elgato",
"vendors": [
{
"name": "Elgato",

View File

@ -0,0 +1,218 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*!
\page netatmo.html
\title netatmo
\ingroup plugins
\ingroup network
This plugin allows to receive data from you netatmo weather station.
\chapter Plugin properties
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
and \l{Vendor}{Vendors} of this \l{DevicePlugin}.
Each \l{DeviceClass} has a list of \l{ParamType}{paramTypes}, \l{ActionType}{actionTypes}, \l{StateType}{stateTypes}
and \l{EventType}{eventTypes}. The \l{DeviceClass::CreateMethod}{createMethods} parameter describes how the \l{Device}
will be created in the system. A device can have more than one \l{DeviceClass::CreateMethod}{CreateMethod}.
The \l{DeviceClass::SetupMethod}{setupMethod} describes the setup method of the \l{Device}.
The detailed implementation of each \l{DeviceClass} can be found in the source code.
\note If a \l{StateType} has the parameter \tt{"writable": {...}}, an \l{ActionType} with the same uuid and \l{ParamType}{ParamTypes}
will be created automatically.
\quotefile plugins/deviceplugins/netatmo/devicepluginnetatmo.json
*/
#include "devicepluginnetatmo.h"
#include "plugin/device.h"
#include "plugininfo.h"
#include <QUrlQuery>
#include <QJsonDocument>
DevicePluginNetatmo::DevicePluginNetatmo()
{
}
DeviceManager::HardwareResources DevicePluginNetatmo::requiredHardware() const
{
return DeviceManager::HardwareResourceNetworkManager | DeviceManager::HardwareResourceTimer;
}
DeviceManager::DeviceSetupStatus DevicePluginNetatmo::setupDevice(Device *device)
{
if (device->deviceClassId() == connectionDeviceClassId) {
qCDebug(dcNetatmo) << "Setup netatmo connection";
OAuth2 *authentication = new OAuth2("561c015d49c75f0d1cce6e13", "GuvKkdtu7JQlPD47qTTepRR9hQ0CUPAj4Tae3Ohcq", this);
authentication->setUrl(QUrl("https://api.netatmo.net/oauth2/token"));
authentication->setUsername(device->paramValue("username").toString());
authentication->setPassword(device->paramValue("password").toString());
authentication->setScope("read_station read_thermostat write_thermostat");
m_authentications.insert(authentication, device);
m_asyncSetups.append(device);
connect(authentication, &OAuth2::authenticationChanged, this, &DevicePluginNetatmo::onAuthenticationChanged);
authentication->startAuthentication();
return DeviceManager::DeviceSetupStatusAsync;
} else if (device->deviceClassId() == indoorDeviceClassId) {
qCDebug(dcNetatmo) << "Setup netatmo indoor base station" << device->params();
NetatmoBaseStation *indoor = new NetatmoBaseStation(device->paramValue("name").toString(),
device->paramValue("mac address").toString(),
device->paramValue("connection id").toString(), this);
connect(indoor, &NetatmoBaseStation::statesChanged, this, &DevicePluginNetatmo::onIndoorStatesChanged);
return DeviceManager::DeviceSetupStatusSuccess;
}
return DeviceManager::DeviceSetupStatusFailure;
}
void DevicePluginNetatmo::deviceRemoved(Device *device)
{
OAuth2 * authentication = m_authentications.key(device);
m_authentications.remove(authentication);
authentication->deleteLater();
}
void DevicePluginNetatmo::networkManagerReplyReady(QNetworkReply *reply)
{
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// update values request
if (m_refreshRequest.keys().contains(reply)) {
Device *device = m_refreshRequest.take(reply);
// check HTTP status code
if (status != 200) {
qCWarning(dcNetatmo) << "Device list reply HTTP error:" << status << reply->errorString();
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure);
reply->deleteLater();
return;
}
// check JSON file
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcNetatmo) << "Device list reply JSON error:" << error.errorString();
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure);
reply->deleteLater();
return;
}
qCDebug(dcNetatmo) << jsonDoc.toJson();
processRefreshData(jsonDoc.toVariant().toMap(), device->id().toString());
}
reply->deleteLater();
}
void DevicePluginNetatmo::guhTimer()
{
foreach (Device *device, myDevices()) {
if (device->deviceClassId() == connectionDeviceClassId) {
OAuth2 *authentication = m_authentications.key(device);
// TODO: check if authenticated
refreshData(device, authentication->token());
}
}
}
void DevicePluginNetatmo::refreshData(Device *device, const QString &token)
{
QUrlQuery query;
query.addQueryItem("access_token", token);
QUrl url("https://api.netatmo.com/api/devicelist");
url.setQuery(query);
QNetworkReply *reply = networkManagerGet(QNetworkRequest(url));
m_refreshRequest.insert(reply, device);
}
void DevicePluginNetatmo::processRefreshData(const QVariantMap &data, const QString &connectionId)
{
if (data.contains("body")) {
if (data.value("body").toMap().contains("devices")) {
QVariantList deviceList = data.value("body").toMap().value("devices").toList();
//QVariantList modulesList = data.value("body").toMap().value("modules").toList();
// check devices
foreach (QVariant deviceVariant, deviceList) {
QVariantMap deviceMap = deviceVariant.toMap();
// we support currently only NAMain devices
if (deviceMap.value("type").toString() == "NAMain") {
NetatmoBaseStation *indoor = findIndoorDevice(deviceMap.value("_id").toString());
// check if we have to create the device (auto)
if (!indoor) {
DeviceDescriptor descriptor(indoorDeviceClassId, "Indoor Station", deviceMap.value("station_name").toString());
ParamList params;
params.append(Param("name", deviceMap.value("station_name").toString()));
params.append(Param("mac address", deviceMap.value("_id").toString()));
params.append(Param("connection id", connectionId));
descriptor.setParams(params);
emit autoDevicesAppeared(indoorDeviceClassId, QList<DeviceDescriptor>() << descriptor);
} else {
indoor->updateStates(deviceMap);
}
}
}
}
}
}
NetatmoBaseStation *DevicePluginNetatmo::findIndoorDevice(const QString &macAddress)
{
foreach (NetatmoBaseStation *bs, m_indoorDevices.keys()) {
if (bs->macAddress() == macAddress) {
return bs;
}
}
return 0;
}
void DevicePluginNetatmo::onAuthenticationChanged()
{
OAuth2 *authentication = static_cast<OAuth2 *>(sender());
Device *device = m_authentications.value(authentication);
// check if this is was a setup athentication
if (m_asyncSetups.contains(device)) {
m_asyncSetups.removeAll(device);
if (authentication->authenticated()) {
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
refreshData(device, authentication->token());
} else {
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure);
m_authentications.remove(authentication);
authentication->deleteLater();
}
}
}

View File

@ -0,0 +1,67 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICEPLUGINNETATMO_H
#define DEVICEPLUGINNETATMO_H
#include <QHash>
#include <QDebug>
#include <QTimer>
#include "plugin/deviceplugin.h"
#include "network/oauth2.h"
#include "netatmobasestation.h"
class DevicePluginNetatmo : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "devicepluginnetatmo.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginNetatmo();
DeviceManager::HardwareResources requiredHardware() const override;
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
void networkManagerReplyReady(QNetworkReply *reply) override;
void guhTimer() override;
private:
QList<Device *> m_asyncSetups;
QHash<OAuth2 *, Device *> m_authentications;
QHash<NetatmoBaseStation *, Device *> m_indoorDevices;
QHash<QNetworkReply *, Device *> m_refreshRequest;
void refreshData(Device *device, const QString &token);
void processRefreshData(const QVariantMap &data, const QString &connectionId);
NetatmoBaseStation *findIndoorDevice(const QString &macAddress);
private slots:
void onAuthenticationChanged();
void onIndoorStatesChanged();
};
#endif // DEVICEPLUGINNETATMO_H

View File

@ -0,0 +1,141 @@
{
"name": "Netatmo",
"idName": "Netatmo",
"id": "3af70774-4b43-46fe-96a4-22108d4efb1b",
"vendors": [
{
"name": "Netatmo",
"idName": "netatmo",
"id": "31828f6f-c63d-4d44-b2b1-d0f70b3ce933",
"deviceClasses": [
{
"deviceClassId": "728d5a67-27a3-400e-b83c-2765f5196f69",
"name": "Netatmo Connection",
"idName": "connection",
"createMethods": ["user"],
"paramTypes": [
{
"name": "username",
"type": "QString",
"inputType": "TextLine"
},
{
"name": "password",
"type": "QString",
"inputType": "Password"
}
],
"stateType": [
{
"id": "2f79bc1d-27ed-480a-b583-728363c83ea6",
"idName": "available",
"name": "available",
"type": "bool",
"defaultValue": false
}
]
},
{
"deviceClassId": "d79d373c-c992-4d75-bd01-a0f8ab346ac5",
"name": "Indoor Station",
"idName": "indoor",
"createMethods": ["auto"],
"paramTypes": [
{
"name": "name",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
},
{
"name": "mac address",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
},
{
"name": "connection id",
"type": "QString",
"inputType": "TextLine",
"readOnly": true
}
],
"stateTypes": [
{
"id": "50da9f6b-c350-401c-a72e-2e4036f3975d",
"idName": "updateTime",
"name": "last update",
"unit": "UnixTime",
"type": "int",
"defaultValue": 0
},
{
"id": "3cb25538-e463-40ae-92f9-8f34f0c06b92",
"idName": "temperature",
"name": "temperature",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0
},
{
"id": "ae8bb713-8805-4efd-89a1-bca44a1f1690",
"idName": "temperatureMin",
"name": "temperature minimum",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0
},
{
"id": "dd30507e-037b-4c74-bcca-e04b94c7c5fe",
"idName": "temperatureMax",
"name": "temperature maximum",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0
},
{
"id": "e2db5f01-196a-48d1-8874-6b8cbfe0d8c9",
"idName": "humidity",
"name": "humidity",
"unit": "Percentage",
"type": "int",
"defaultValue": 0
},
{
"id": "03b0a7b7-987d-4d3b-b3f0-21d9f92ad326",
"idName": "pressure",
"name": "pressure",
"unit": "MilliBar",
"type": "double",
"defaultValue": 0
},
{
"id": "906cea9d-1daf-4e9c-90b9-e40f43052a34",
"idName": "noise",
"name": "noise",
"unit": "Dezibel",
"type": "int",
"defaultValue": 0
},
{
"id": "e5710bd1-79fa-4bd4-9052-8416aae909b9",
"idName": "co2",
"name": "co2",
"unit": "PartsPerMillion",
"type": "int",
"defaultValue": 0
},
{
"id": "6ea906d4-5740-454d-a730-6fdb9fa0d624",
"idName": "wifiStrength",
"name": "wifi signal strength",
"unit": "Percentage",
"type": "int",
"defaultValue": 0
}
]
}
]
}
]
}

View File

@ -0,0 +1,13 @@
include(../../plugins.pri)
TARGET = $$qtLibraryTarget(guh_devicepluginnetatmo)
SOURCES += \
devicepluginnetatmo.cpp \
netatmobasestation.cpp
HEADERS += \
devicepluginnetatmo.h \
netatmobasestation.h

View File

@ -0,0 +1,94 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "netatmobasestation.h"
NetatmoBaseStation::NetatmoBaseStation(const QString &name, const QString &macAddress, const QString &connectionId, QObject *parent) :
QObject(parent),
m_name(name),
m_macAddress(macAddress),
m_connectionId(connectionId)
{
}
QString NetatmoBaseStation::name() const
{
return m_name;
}
QString NetatmoBaseStation::macAddress() const
{
return m_macAddress;
}
QString NetatmoBaseStation::connectionId() const
{
return m_connectionId;
}
int NetatmoBaseStation::lastUpdate() const
{
return m_lastUpdate;
}
double NetatmoBaseStation::temperature() const
{
return m_temperature;
}
double NetatmoBaseStation::minTemperature() const
{
return m_minTemperature;
}
double NetatmoBaseStation::maxTemperature() const
{
return m_maxTemperature;
}
double NetatmoBaseStation::pressure() const
{
return m_pressure;
}
int NetatmoBaseStation::humidity() const
{
return m_humidity;
}
int NetatmoBaseStation::noise() const
{
return m_noise;
}
int NetatmoBaseStation::co2() const
{
return m_co2;
}
int NetatmoBaseStation::wifiStrength() const
{
return m_wifiStrength;
}
void NetatmoBaseStation::updateStates(const QVariantMap &data)
{
Q_UNUSED(data)
}

View File

@ -0,0 +1,72 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NETATMOBASESTATION_H
#define NETATMOBASESTATION_H
#include <QObject>
#include <QString>
class NetatmoBaseStation : public QObject
{
Q_OBJECT
public:
explicit NetatmoBaseStation(const QString &name, const QString &macAddress, const QString &connectionId, QObject *parent = 0);
// Params
QString name() const;
QString macAddress() const;
QString connectionId() const;
// States
int lastUpdate() const;
double temperature() const;
double minTemperature() const;
double maxTemperature() const;
double pressure() const;
int humidity() const;
int noise() const;
int co2() const;
int wifiStrength() const;
void updateStates(const QVariantMap &data);
private:
// Params
QString m_name;
QString m_macAddress;
QString m_connectionId;
// States
int m_lastUpdate;
double m_temperature;
double m_minTemperature;
double m_maxTemperature;
double m_pressure;
int m_humidity;
int m_noise;
int m_co2;
int m_wifiStrength;
signals:
void statesChanged();
};
#endif // NETATMOBASESTATION_H

View File

@ -61,14 +61,15 @@ int main(int argc, char *argv[])
s_loggingFilters.insert("Warnings", true);
s_loggingFilters.insert("DeviceManager", true);
s_loggingFilters.insert("RuleEngine", true);
s_loggingFilters.insert("Hardware", false);
s_loggingFilters.insert("Connection", true);
s_loggingFilters.insert("LogEngine", false);
s_loggingFilters.insert("TcpServer", false);
s_loggingFilters.insert("WebServer", true);
s_loggingFilters.insert("WebSocketServer", false);
s_loggingFilters.insert("JsonRpc", false);
s_loggingFilters.insert("Rest", true);
s_loggingFilters.insert("Hardware", false);
s_loggingFilters.insert("LogEngine", false);
s_loggingFilters.insert("OAuth2", false);
QHash<QString, bool> loggingFiltersPlugins;
foreach (const QJsonObject &pluginMetadata, DeviceManager::pluginsMetadata()) {