mirror of https://github.com/nymea/nymea.git
add coap to awattar plugin
parent
8ff4af2c16
commit
dfd8186c19
|
|
@ -3,9 +3,11 @@ include(../../plugins.pri)
|
|||
TARGET = $$qtLibraryTarget(guh_devicepluginawattar)
|
||||
|
||||
SOURCES += \
|
||||
devicepluginawattar.cpp
|
||||
devicepluginawattar.cpp \
|
||||
heatpump.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginawattar.h
|
||||
devicepluginawattar.h \
|
||||
heatpump.h
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,23 @@ DeviceManager::DeviceSetupStatus DevicePluginAwattar::setupDevice(Device *device
|
|||
return DeviceManager::DeviceSetupStatusAsync;
|
||||
}
|
||||
|
||||
void DevicePluginAwattar::startMonitoringAutoDevices()
|
||||
{
|
||||
QHostAddress rplAddress = QHostAddress(configuration().paramValue("RPL address").toString());
|
||||
|
||||
if (rplAddress.isNull()) {
|
||||
qCWarning(dcAwattar) << "Invalid RPL address" << configuration().paramValue("RPL address").toString();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcAwattar) << "Search heat pump" << rplAddress.toString();
|
||||
|
||||
QNetworkRequest request(QUrl(QString("http://[%1]").arg(rplAddress.toString())));
|
||||
QNetworkReply *reply = networkManagerGet(request);
|
||||
|
||||
m_searchPumpReplies.append(reply);
|
||||
}
|
||||
|
||||
void DevicePluginAwattar::deviceRemoved(Device *device)
|
||||
{
|
||||
Q_UNUSED(device)
|
||||
|
|
@ -173,7 +190,20 @@ void DevicePluginAwattar::networkManagerReplyReady(QNetworkReply *reply)
|
|||
}
|
||||
|
||||
processUserData(device, jsonDoc.toVariant().toMap());
|
||||
} else if (m_searchPumpReplies.contains(reply)) {
|
||||
|
||||
m_searchPumpReplies.removeAll(reply);
|
||||
|
||||
// check HTTP status code
|
||||
if (status != 200) {
|
||||
qCWarning(dcAwattar) << "Search pump reply HTTP error:" << status << reply->errorString();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
processPumpSearchData(reply->readAll());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
|
|
@ -185,6 +215,21 @@ void DevicePluginAwattar::guhTimer()
|
|||
}
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginAwattar::executeAction(Device *device, const Action &action)
|
||||
{
|
||||
Q_UNUSED(device)
|
||||
|
||||
if (action.actionTypeId() == ledPowerActionTypeId) {
|
||||
foreach (HeatPump *pump, m_heatPumps) {
|
||||
if (!pump->reachable())
|
||||
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
||||
|
||||
pump->setLed(action.param("led power").value().toBool());
|
||||
}
|
||||
}
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
void DevicePluginAwattar::processPriceData(Device *device, const QVariantMap &data, const bool &fromSetup)
|
||||
{
|
||||
if (!data.contains("data")) {
|
||||
|
|
@ -304,7 +349,38 @@ void DevicePluginAwattar::processUserData(Device *device, const QVariantMap &dat
|
|||
break;
|
||||
}
|
||||
|
||||
// todo: send sg mode to 6LoWPAN node
|
||||
foreach (HeatPump *pump, m_heatPumps) {
|
||||
pump->setSgMode(sgMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginAwattar::processPumpSearchData(const QByteArray &data)
|
||||
{
|
||||
//qCDebug(dcAwattar) << "Search result:" << endl << data;
|
||||
|
||||
QList<QByteArray> lines = data.split('\n');
|
||||
foreach (const QByteArray &line, lines) {
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
// remove the '/128' from the address
|
||||
QHostAddress pumpAddress(QString(data.left(line.length() - 4)));
|
||||
if (!pumpAddress.isNull()) {
|
||||
qCDebug(dcAwattar) << "Found heat pump at" << pumpAddress.toString();
|
||||
|
||||
// check if we already created this heat pump
|
||||
if (heatPumpExists(pumpAddress))
|
||||
continue;
|
||||
|
||||
HeatPump *pump = new HeatPump(pumpAddress, this);
|
||||
connect(pump, SIGNAL(reachableChanged()), this, SLOT(onHeatPumpReachableChanged()));
|
||||
|
||||
m_heatPumps.append(pump);
|
||||
|
||||
} else {
|
||||
qCWarning(dcAwattar) << "Could not read pump address" << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -335,3 +411,22 @@ void DevicePluginAwattar::updateDevice(Device *device)
|
|||
QNetworkReply *priceReply = requestPriceData(device->paramValue("token").toString());
|
||||
m_updatePrice.insert(priceReply, device);
|
||||
}
|
||||
|
||||
bool DevicePluginAwattar::heatPumpExists(const QHostAddress &pumpAddress)
|
||||
{
|
||||
foreach (HeatPump *pump, m_heatPumps) {
|
||||
if (pump->address() == pumpAddress) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DevicePluginAwattar::onHeatPumpReachableChanged()
|
||||
{
|
||||
HeatPump *pump = static_cast<HeatPump *>(sender());
|
||||
|
||||
foreach (Device *device, myDevices()) {
|
||||
device->setStateValue(reachableStateTypeId, pump->reachable());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#define DEVICEPLUGINAWATTAR_H
|
||||
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "heatpump.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QDebug>
|
||||
|
|
@ -39,26 +40,35 @@ public:
|
|||
DeviceManager::HardwareResources requiredHardware() const override;
|
||||
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||
|
||||
void startMonitoringAutoDevices() override;
|
||||
|
||||
void deviceRemoved(Device *device) override;
|
||||
void networkManagerReplyReady(QNetworkReply *reply) override;
|
||||
|
||||
void guhTimer() override;
|
||||
|
||||
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||
|
||||
private:
|
||||
QHash<QNetworkReply *, Device *> m_asyncSetup;
|
||||
QHash<QNetworkReply *, Device *> m_updatePrice;
|
||||
QHash<QNetworkReply *, Device *> m_updateUserData;
|
||||
QList<QNetworkReply *> m_searchPumpReplies;
|
||||
|
||||
QList<HeatPump *> m_heatPumps;
|
||||
|
||||
void processPriceData(Device *device, const QVariantMap &data, const bool &fromSetup = false);
|
||||
void processUserData(Device *device, const QVariantMap &data);
|
||||
void processPumpSearchData(const QByteArray &data);
|
||||
|
||||
QNetworkReply *requestPriceData(const QString& token);
|
||||
QNetworkReply *requestUserData(const QString& token, const QString &userId);
|
||||
|
||||
void updateDevice(Device *device);
|
||||
bool heatPumpExists(const QHostAddress &pumpAddress);
|
||||
|
||||
private slots:
|
||||
void onTimeout();
|
||||
void onHeatPumpReachableChanged();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@
|
|||
"name": "aWATTar",
|
||||
"idName": "Awattar",
|
||||
"id": "9c261c33-d44e-461e-8ec1-68803cb73f12",
|
||||
"paramTypes": [
|
||||
{
|
||||
"name": "RPL address",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine",
|
||||
"defaultValue": "fdaa:e9b8:d03a::ff:fe00:1"
|
||||
}
|
||||
],
|
||||
"vendors": [
|
||||
{
|
||||
"name": "aWATTar",
|
||||
|
|
@ -85,6 +93,13 @@
|
|||
"unit": "EuroPerMegaWattHour",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "1c9d139a-6618-4a39-bc83-37f80942017d",
|
||||
"idName": "reachable",
|
||||
"name": "pump reachable",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "b83d3533-aeae-4a9b-95d8-28466bf6c0cf",
|
||||
"idName": "sgMode",
|
||||
|
|
@ -98,6 +113,19 @@
|
|||
],
|
||||
"defaultValue": "1 - Off"
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "5be2f57f-a22d-4766-856a-a31481bcf6d6",
|
||||
"idName": "ledPower",
|
||||
"name": "led power",
|
||||
"paramTypes": [
|
||||
{
|
||||
"name": "power",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2016 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 "heatpump.h"
|
||||
#include "coap/corelinkparser.h"
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
HeatPump::HeatPump(QHostAddress address, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_address(address),
|
||||
m_reachable(false),
|
||||
m_sgMode(1)
|
||||
{
|
||||
m_coap = new Coap(this);
|
||||
|
||||
connect(m_coap, SIGNAL(replyFinished(CoapReply*)), this, SLOT(onReplyFinished(CoapReply*)));
|
||||
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(m_address.toString());
|
||||
url.setPath("/.well-known/core");
|
||||
|
||||
qCDebug(dcAwattar) << "Discover pump resources on" << url.toString();
|
||||
m_discoverReplies.append(m_coap->get(CoapRequest(url)));
|
||||
}
|
||||
|
||||
QHostAddress HeatPump::address() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
bool HeatPump::reachable() const
|
||||
{
|
||||
return m_reachable;
|
||||
}
|
||||
|
||||
void HeatPump::setSgMode(const int &sgMode)
|
||||
{
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(m_address.toString());
|
||||
url.setPath("/a/sg_mode");
|
||||
|
||||
m_sgModeReplies.append(m_coap->post(CoapRequest(url), QByteArray::number(sgMode)));
|
||||
}
|
||||
|
||||
void HeatPump::setLed(const bool &power)
|
||||
{
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(m_address.toString());
|
||||
url.setPath("/a/led");
|
||||
|
||||
if (power) {
|
||||
m_ledReplies.append(m_coap->post(CoapRequest(url), "mode=on"));
|
||||
} else {
|
||||
m_ledReplies.append(m_coap->post(CoapRequest(url), "mode=off"));
|
||||
}
|
||||
}
|
||||
|
||||
void HeatPump::setReachable(const bool &reachable)
|
||||
{
|
||||
m_reachable = reachable;
|
||||
emit reachableChanged();
|
||||
}
|
||||
|
||||
void HeatPump::onReplyFinished(CoapReply *reply)
|
||||
{
|
||||
if (m_discoverReplies.contains(reply)) {
|
||||
m_discoverReplies.removeAll(reply);
|
||||
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcAwattar()) << "CoAP resource discovery reply error" << reply->errorString();
|
||||
setReachable(false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcAwattar) << "Discovered successfully the resources";
|
||||
CoreLinkParser parser(reply->payload());
|
||||
foreach (const CoreLink &link, parser.links()) {
|
||||
qCDebug(dcAwattar) << link << endl;
|
||||
}
|
||||
|
||||
} else if (m_sgModeReplies.contains(reply)) {
|
||||
m_sgModeReplies.removeAll(reply);
|
||||
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
if (reachable())
|
||||
qCWarning(dcAwattar()) << "CoAP sg-mode reply error" << reply->errorString();
|
||||
|
||||
setReachable(false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reachable())
|
||||
qCDebug(dcAwattar) << "Set sg-mode successfully.";
|
||||
|
||||
} else if (m_ledReplies.contains(reply)) {
|
||||
m_ledReplies.removeAll(reply);
|
||||
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
if (reachable())
|
||||
qCWarning(dcAwattar()) << "CoAP set led power reply error" << reply->errorString();
|
||||
|
||||
setReachable(false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcAwattar) << "Set led power successfully.";
|
||||
|
||||
} else {
|
||||
// unhandled reply
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcAwattar()) << "CoAP reply error" << reply->errorString();
|
||||
setReachable(false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcAwattar) << reply;
|
||||
}
|
||||
|
||||
// the reply had no error until now, so make sure the resource is reachable
|
||||
setReachable(true);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2016 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 HEATPUMP_H
|
||||
#define HEATPUMP_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
|
||||
|
||||
#include "coap/coap.h"
|
||||
#include "coap/coapreply.h"
|
||||
#include "coap/coaprequest.h"
|
||||
|
||||
class HeatPump : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HeatPump(QHostAddress address, QObject *parent = 0);
|
||||
|
||||
QHostAddress address() const;
|
||||
bool reachable() const;
|
||||
|
||||
void setSgMode(const int &sgMode);
|
||||
void setLed(const bool &power);
|
||||
|
||||
private:
|
||||
QHostAddress m_address;
|
||||
bool m_reachable;
|
||||
int m_sgMode;
|
||||
|
||||
Coap *m_coap;
|
||||
|
||||
QList<CoapReply *> m_discoverReplies;
|
||||
QList<CoapReply *> m_sgModeReplies;
|
||||
QList<CoapReply *> m_ledReplies;
|
||||
|
||||
void setReachable(const bool &reachable);
|
||||
|
||||
private slots:
|
||||
void onReplyFinished(CoapReply *reply);
|
||||
|
||||
signals:
|
||||
void reachableChanged();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // HEATPUMP_H
|
||||
Loading…
Reference in New Issue