diff --git a/plugins/deviceplugins/awattar/devicepluginawattar.cpp b/plugins/deviceplugins/awattar/devicepluginawattar.cpp index 16f2ed08..94b354b2 100644 --- a/plugins/deviceplugins/awattar/devicepluginawattar.cpp +++ b/plugins/deviceplugins/awattar/devicepluginawattar.cpp @@ -78,9 +78,7 @@ #include #include -DevicePluginAwattar::DevicePluginAwattar() : - m_device(0), - m_setupRetry(0) +DevicePluginAwattar::DevicePluginAwattar() { } @@ -102,20 +100,19 @@ DeviceManager::DeviceSetupStatus DevicePluginAwattar::setupDevice(Device *device m_token = device->paramValue("token").toString(); m_userUuid = device->paramValue("user uuid").toString(); - connectionTest(); + return DeviceManager::DeviceSetupStatusSuccess; +} - return DeviceManager::DeviceSetupStatusAsync; +void DevicePluginAwattar::postSetupDevice(Device *device) +{ + Q_UNUSED(device) + guhTimer(); } void DevicePluginAwattar::deviceRemoved(Device *device) { Q_UNUSED(device) - - foreach (HeatPump *pump, m_heatPumps) { - qCDebug(dcAwattar) << "Delete pump" << pump->address().toString(); - pump->deleteLater(); - } - + qDeleteAll(m_heatPumps); m_device = 0; } @@ -123,54 +120,13 @@ void DevicePluginAwattar::networkManagerReplyReady(QNetworkReply *reply) { int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (m_asyncSetup.contains(reply)) { - - m_asyncSetup.removeAll(reply); - - // check HTTP status code - if (status != 200) { - qCWarning(dcAwattar) << "Setup reply HTTP error:" << status << reply->errorString(); - if (m_setupRetry == 3) { - emit deviceSetupFinished(m_device, DeviceManager::DeviceSetupStatusFailure); - m_setupRetry = 0; - reply->deleteLater(); - return; - } else { - m_setupRetry++; - reply->deleteLater(); - - // retry in 1 sec - qCWarning(dcAwattar) << "Retry to connect" << m_setupRetry << "/ 3"; - QTimer::singleShot(2000, this, SLOT(connectionTest())); - return; - } - } - - // check JSON file - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcAwattar) << "Setup reply JSON error:" << error.errorString(); - emit deviceSetupFinished(m_device, DeviceManager::DeviceSetupStatusFailure); - reply->deleteLater(); - return; - } - - Q_UNUSED(jsonDoc) - - emit deviceSetupFinished(m_device, DeviceManager::DeviceSetupStatusSuccess); - - // get data - searchHeatPumps(); - updateData(); - - } else if (m_updatePrice.contains(reply)) { - + if (m_updatePrice.contains(reply)) { m_updatePrice.removeAll(reply); // check HTTP status code if (status != 200) { qCWarning(dcAwattar) << "Update reply HTTP error:" << status << reply->errorString(); + setOnlineStatus(false); reply->deleteLater(); return; } @@ -180,6 +136,7 @@ void DevicePluginAwattar::networkManagerReplyReady(QNetworkReply *reply) QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qCWarning(dcAwattar) << "Update reply JSON error:" << error.errorString(); + setOnlineStatus(false); reply->deleteLater(); return; } @@ -190,12 +147,12 @@ void DevicePluginAwattar::networkManagerReplyReady(QNetworkReply *reply) m_updateUserData.append(requestUserData(m_token, m_userUuid)); } else if (m_updateUserData.contains(reply)) { - m_updateUserData.removeAll(reply); // check HTTP status code if (status != 200) { qCWarning(dcAwattar) << "Update user data reply HTTP error:" << status << reply->errorString(); + setOnlineStatus(false); reply->deleteLater(); return; } @@ -205,14 +162,15 @@ void DevicePluginAwattar::networkManagerReplyReady(QNetworkReply *reply) QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qCWarning(dcAwattar) << "Update user data reply JSON error:" << error.errorString(); + setOnlineStatus(false); reply->deleteLater(); return; } + setOnlineStatus(true); processUserData(jsonDoc.toVariant().toMap()); } else if (m_searchPumpReplies.contains(reply)) { - m_searchPumpReplies.removeAll(reply); // check HTTP status code @@ -230,7 +188,7 @@ void DevicePluginAwattar::networkManagerReplyReady(QNetworkReply *reply) void DevicePluginAwattar::guhTimer() { - if (!m_device) + if (m_device.isNull()) return; updateData(); @@ -239,7 +197,7 @@ void DevicePluginAwattar::guhTimer() DeviceManager::DeviceError DevicePluginAwattar::executeAction(Device *device, const Action &action) { - if (!m_device || m_device != device) + if (m_device.isNull() || m_device != device) return DeviceManager::DeviceErrorHardwareNotAvailable; if (action.actionTypeId() == sgSyncModeActionTypeId) { @@ -276,9 +234,50 @@ DeviceManager::DeviceError DevicePluginAwattar::executeAction(Device *device, co return DeviceManager::DeviceErrorActionTypeNotFound; } +QNetworkReply *DevicePluginAwattar::requestPriceData(const QString &token) +{ + QByteArray data = QString(token + ":").toUtf8().toBase64(); + QString header = "Basic " + data; + QNetworkRequest request(QUrl("https://api.awattar.com/v1/marketdata")); + request.setRawHeader("Authorization", header.toLocal8Bit()); + request.setSslConfiguration(QSslConfiguration::defaultConfiguration()); + return networkManagerGet(request); +} + +QNetworkReply *DevicePluginAwattar::requestUserData(const QString &token, const QString &userId) +{ + QByteArray data = QString(token + ":").toUtf8().toBase64(); + QString header = "Basic " + data; + + QNetworkRequest request(QUrl(QString("https://api.awattar.com/v1/devices/%1/actuators").arg(userId))); + request.setRawHeader("Authorization", header.toLocal8Bit()); + request.setSslConfiguration(QSslConfiguration::defaultConfiguration()); + return networkManagerGet(request); +} + +void DevicePluginAwattar::updateData() +{ + m_updatePrice.append(requestPriceData(m_token)); +} + +void DevicePluginAwattar::searchHeatPumps() +{ + QHostAddress rplAddress = QHostAddress(configuration().paramValue("RPL address").toString()); + + if (rplAddress.isNull()) { + qCWarning(dcAwattar) << "Invalid RPL address" << configuration().paramValue("RPL address").toString(); + return; + } + + QNetworkRequest request(QUrl(QString("http://[%1]").arg(rplAddress.toString()))); + QNetworkReply *reply = networkManagerGet(request); + + m_searchPumpReplies.append(reply); +} + void DevicePluginAwattar::processPriceData(const QVariantMap &data) { - if (!m_device) + if (m_device.isNull()) return; QVariantList dataElements = data.value("data").toList(); @@ -343,7 +342,7 @@ void DevicePluginAwattar::processPriceData(const QVariantMap &data) void DevicePluginAwattar::processUserData(const QVariantMap &data) { - if (!m_device) + if (m_device.isNull()) return; QVariantList dataElements = data.value("data").toList(); @@ -384,66 +383,22 @@ void DevicePluginAwattar::processPumpSearchData(const QByteArray &data) // remove the '/128' from the address QHostAddress pumpAddress(QString(data.left(line.length() - 4))); - if (!pumpAddress.isNull()) { + if (pumpAddress.isNull()) + continue; - // check if we already created this heat pump - if (heatPumpExists(pumpAddress)) - continue; - - qCDebug(dcAwattar) << "Found heat pump at" << pumpAddress.toString(); - - HeatPump *pump = new HeatPump(pumpAddress, this); - connect(pump, SIGNAL(reachableChanged()), this, SLOT(onHeatPumpReachableChanged())); - - m_heatPumps.append(pump); - - } else { + // check if we already created this heat pump + if (heatPumpExists(pumpAddress)) { qCWarning(dcAwattar) << "Could not read pump address" << line; + continue; } + + qCDebug(dcAwattar) << "New heat pump found at" << pumpAddress.toString(); + QPointer pump = new HeatPump(pumpAddress, this); + connect(pump, &HeatPump::reachableChanged, this, &DevicePluginAwattar::onHeatPumpReachableChanged); + m_heatPumps.append(pump); } } -QNetworkReply *DevicePluginAwattar::requestPriceData(const QString &token) -{ - QByteArray data = QString(token + ":").toUtf8().toBase64(); - QString header = "Basic " + data; - QNetworkRequest request(QUrl("https://api.awattar.com/v1/marketdata")); - request.setRawHeader("Authorization", header.toLocal8Bit()); - request.setSslConfiguration(QSslConfiguration::defaultConfiguration()); - return networkManagerGet(request); -} - -QNetworkReply *DevicePluginAwattar::requestUserData(const QString &token, const QString &userId) -{ - QByteArray data = QString(token + ":").toUtf8().toBase64(); - QString header = "Basic " + data; - - QNetworkRequest request(QUrl(QString("https://api.awattar.com/v1/devices/%1/actuators").arg(userId))); - request.setRawHeader("Authorization", header.toLocal8Bit()); - request.setSslConfiguration(QSslConfiguration::defaultConfiguration()); - return networkManagerGet(request); -} - -void DevicePluginAwattar::updateData() -{ - m_updatePrice.append(requestPriceData(m_token)); -} - -void DevicePluginAwattar::searchHeatPumps() -{ - QHostAddress rplAddress = QHostAddress(configuration().paramValue("RPL address").toString()); - - if (rplAddress.isNull()) { - qCWarning(dcAwattar) << "Invalid RPL address" << configuration().paramValue("RPL address").toString(); - return; - } - - QNetworkRequest request(QUrl(QString("http://[%1]").arg(rplAddress.toString()))); - QNetworkReply *reply = networkManagerGet(request); - - m_searchPumpReplies.append(reply); -} - void DevicePluginAwattar::setSgMode(const int &sgMode) { switch (sgMode) { @@ -465,15 +420,24 @@ void DevicePluginAwattar::setSgMode(const int &sgMode) } foreach (HeatPump *pump, m_heatPumps) { - if (pump->reachable()) { - pump->setSgMode(sgMode); - } + pump->setSgMode(sgMode); } } +void DevicePluginAwattar::setOnlineStatus(const bool &online) +{ + if (m_device.isNull()) + return; + + m_device->setStateValue(onlineStateTypeId, online); +} + bool DevicePluginAwattar::heatPumpExists(const QHostAddress &pumpAddress) { - foreach (HeatPump *pump, m_heatPumps) { + foreach (QPointer pump, m_heatPumps) { + if (pump.isNull()) + continue; + if (pump->address() == pumpAddress) { return true; } @@ -481,11 +445,6 @@ bool DevicePluginAwattar::heatPumpExists(const QHostAddress &pumpAddress) return false; } -void DevicePluginAwattar::connectionTest() -{ - m_asyncSetup.append(requestUserData(m_token, m_userUuid)); -} - void DevicePluginAwattar::onHeatPumpReachableChanged() { HeatPump *pump = static_cast(sender()); @@ -501,7 +460,7 @@ void DevicePluginAwattar::onHeatPumpReachableChanged() } } - foreach (Device *device, myDevices()) { - device->setStateValue(reachableStateTypeId, reachable); - } + if (m_device) + m_device->setStateValue(reachableStateTypeId, reachable); + } diff --git a/plugins/deviceplugins/awattar/devicepluginawattar.h b/plugins/deviceplugins/awattar/devicepluginawattar.h index f7dddf64..264ce8bf 100644 --- a/plugins/deviceplugins/awattar/devicepluginawattar.h +++ b/plugins/deviceplugins/awattar/devicepluginawattar.h @@ -27,6 +27,7 @@ #include #include #include +#include class DevicePluginAwattar : public DevicePlugin { @@ -39,33 +40,27 @@ public: DeviceManager::HardwareResources requiredHardware() const override; DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; - + void postSetupDevice(Device *device) override; void deviceRemoved(Device *device) override; void networkManagerReplyReady(QNetworkReply *reply) override; void guhTimer() override; - DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; private: - Device *m_device; - QList m_heatPumps; + QPointer m_device; + QList > m_heatPumps; - QList m_asyncSetup; - QList m_searchPumpReplies; - QList m_updatePrice; - QList m_updateUserData; + QList > m_searchPumpReplies; + QList > m_updatePrice; + QList > m_updateUserData; QString m_token; QString m_userUuid; - int m_setupRetry; int m_autoSgMode; int m_manualSgMode; - void processPriceData(const QVariantMap &data); - void processUserData(const QVariantMap &data); - void processPumpSearchData(const QByteArray &data); QNetworkReply *requestPriceData(const QString& token); QNetworkReply *requestUserData(const QString& token, const QString &userId); @@ -73,12 +68,15 @@ private: void updateData(); void searchHeatPumps(); - void setSgMode(const int &sgMode); + void processPriceData(const QVariantMap &data); + void processUserData(const QVariantMap &data); + void processPumpSearchData(const QByteArray &data); + void setSgMode(const int &sgMode); + void setOnlineStatus(const bool &online); bool heatPumpExists(const QHostAddress &pumpAddress); private slots: - void connectionTest(); void onHeatPumpReachableChanged(); }; diff --git a/plugins/deviceplugins/awattar/devicepluginawattar.json b/plugins/deviceplugins/awattar/devicepluginawattar.json index f4f22e32..a7034184 100644 --- a/plugins/deviceplugins/awattar/devicepluginawattar.json +++ b/plugins/deviceplugins/awattar/devicepluginawattar.json @@ -88,6 +88,13 @@ "unit": "EuroCentPerKiloWattHour", "defaultValue": 0 }, + { + "id": "470b9b88-17f3-42e3-9250-cc181984eafe", + "idName": "online", + "name": "online", + "type": "bool", + "defaultValue": false + }, { "id": "1c9d139a-6618-4a39-bc83-37f80942017d", "idName": "reachable", diff --git a/plugins/deviceplugins/awattar/heatpump.cpp b/plugins/deviceplugins/awattar/heatpump.cpp index 10d7a949..30a178de 100644 --- a/plugins/deviceplugins/awattar/heatpump.cpp +++ b/plugins/deviceplugins/awattar/heatpump.cpp @@ -30,7 +30,6 @@ HeatPump::HeatPump(QHostAddress address, QObject *parent) : m_sgMode(0) { m_coap = new Coap(this); - connect(m_coap, SIGNAL(replyFinished(CoapReply*)), this, SLOT(onReplyFinished(CoapReply*))); QUrl url; @@ -63,6 +62,7 @@ void HeatPump::setSgMode(const int &sgMode) if (m_sgMode != sgMode) { m_sgMode = sgMode; qCDebug(dcAwattar) << "Setting sg-mode to" << sgMode; + // Note: always try to set sg-mode, to make sure the pump is still reachable (like a ping) } QUrl url; @@ -75,6 +75,7 @@ void HeatPump::setSgMode(const int &sgMode) CoapReply *reply = m_coap->post(CoapRequest(url), payload); if (reply->error() != CoapReply::NoError) { qCWarning(dcAwattar()) << "Could not set sg mode" << reply->errorString(); + setReachable(false); reply->deleteLater(); return; } @@ -82,33 +83,12 @@ void HeatPump::setSgMode(const int &sgMode) m_sgModeReplies.append(reply); } -void HeatPump::setLed(const bool &power) -{ - QUrl url; - url.setScheme("coap"); - url.setHost(m_address.toString()); - url.setPath("/a/led"); - - QByteArray data; - if (power) { - data = QString("mode=1").toUtf8(); - } else { - data = QString("mode=0").toUtf8(); - } - - CoapReply *reply = m_coap->post(CoapRequest(url), data); - if (reply->error() != CoapReply::NoError) { - qCWarning(dcAwattar()) << "Could not set led" << reply->errorString(); - reply->deleteLater(); - return; - } - m_ledReplies.append(reply); -} - void HeatPump::setReachable(const bool &reachable) { - m_reachable = reachable; - emit reachableChanged(); + if (m_reachable != reachable) { + m_reachable = reachable; + emit reachableChanged(); + } } void HeatPump::onReplyFinished(CoapReply *reply) @@ -125,6 +105,7 @@ void HeatPump::onReplyFinished(CoapReply *reply) if (reply->statusCode() != CoapPdu::Content) { qCWarning(dcAwattar()) << "Resource discovery status code:" << reply; + setReachable(false); reply->deleteLater(); return; } @@ -149,6 +130,7 @@ void HeatPump::onReplyFinished(CoapReply *reply) if (reply->statusCode() != CoapPdu::Content) { qCWarning(dcAwattar()) << "Set sg-mode status code error:" << reply; + setReachable(false); reply->deleteLater(); return; } @@ -156,42 +138,6 @@ void HeatPump::onReplyFinished(CoapReply *reply) 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; - } - - if (reply->statusCode() != CoapPdu::Content) { - qCWarning(dcAwattar()) << "Set LED status code error:" << reply; - 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; - } - - if (reply->statusCode() != CoapPdu::Content) { - qCWarning(dcAwattar()) << "Unknown reply" << reply; - reply->deleteLater(); - return; - } - - qCDebug(dcAwattar) << reply; } // the reply had no error until now, so make sure the resource is reachable diff --git a/plugins/deviceplugins/awattar/heatpump.h b/plugins/deviceplugins/awattar/heatpump.h index 6316d340..0facf532 100644 --- a/plugins/deviceplugins/awattar/heatpump.h +++ b/plugins/deviceplugins/awattar/heatpump.h @@ -39,8 +39,6 @@ public: bool reachable() const; void setSgMode(const int &sgMode); - void setLed(const bool &power); - private: QHostAddress m_address; bool m_reachable; @@ -50,7 +48,6 @@ private: QList m_discoverReplies; QList m_sgModeReplies; - QList m_ledReplies; void setReachable(const bool &reachable);