/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2015 Simon Stürz * * * * This file is part of nymea. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 library; If not, see * * . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "devicepluginawattar.h" #include "devices/device.h" #include "plugininfo.h" #include "hardwaremanager.h" #include "network/networkaccessmanager.h" #include #include #include DevicePluginAwattar::DevicePluginAwattar() { } DevicePluginAwattar::~DevicePluginAwattar() { } Device::DeviceSetupStatus DevicePluginAwattar::setupDevice(Device *device) { qCDebug(dcAwattar) << "Setup device" << device->name() << device->params(); QString userUuid = device->paramValue(awattarDeviceUserUuidParamTypeId).toString(); QString token = device->paramValue(awattarDeviceTokenParamTypeId).toString(); if (token.isEmpty() || userUuid.isEmpty()) { qCWarning(dcAwattar) << "Missing token oder user uuid."; return Device::DeviceSetupStatusFailure; } if (!m_pluginTimer) { m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60 * 60); connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginAwattar::onPluginTimer); } requestPriceData(device, true); return Device::DeviceSetupStatusAsync; } void DevicePluginAwattar::deviceRemoved(Device *device) { Q_UNUSED(device) if (m_pluginTimer && myDevices().isEmpty()) { hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer); } } void DevicePluginAwattar::onPluginTimer() { foreach (Device *device, myDevices()) { requestPriceData(device); } } void DevicePluginAwattar::requestPriceData(Device* device, bool setupInProgress) { QString token = device->paramValue(awattarDeviceTokenParamTypeId).toString(); 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()); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, device, [this, reply, device, setupInProgress](){ reply->deleteLater(); // check HTTP status code int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (status != 200) { qCWarning(dcAwattar) << "Update reply HTTP error:" << status << reply->errorString(); if (setupInProgress) { emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure); } else { device->setStateValue(awattarConnectedStateTypeId, false); } return; } // check JSON file QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qCWarning(dcAwattar) << "Update reply JSON error:" << error.errorString(); if (setupInProgress) { emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure); } else { device->setStateValue(awattarConnectedStateTypeId, false); } return; } emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess); device->setStateValue(awattarConnectedStateTypeId, true); processPriceData(device, jsonDoc.toVariant().toMap()); }); } void DevicePluginAwattar::processPriceData(Device *device, const QVariantMap &data) { QVariantList dataElements = data.value("data").toList(); QDateTime currentTime = QDateTime::currentDateTime(); double sum = 0; double count = 0; double averagePrice = 0; double currentPrice = 0; int deviation = 0; double maxPrice = -1000; double minPrice = 1000; foreach (QVariant element, dataElements) { QVariantMap elementMap = element.toMap(); QDateTime startTime = QDateTime::fromMSecsSinceEpoch(elementMap.value("start_timestamp").toLongLong()); QDateTime endTime = QDateTime::fromMSecsSinceEpoch(elementMap.value("end_timestamp").toLongLong()); double price = elementMap.value("marketprice").toDouble(); // check interval [-12h < x < + 12h] if ((startTime >= currentTime.addSecs(-3600 * 12) && endTime <= currentTime ) || (endTime <= currentTime.addSecs(3600 * 12) && startTime >= currentTime )) { sum += price; count++; if (price > maxPrice) maxPrice = price; if (price < minPrice) minPrice = price; } if (currentTime >= startTime && currentTime <= endTime) { currentPrice = price; sum += price; count++; if (price > maxPrice) maxPrice = price; if (price < minPrice) minPrice = price; device->setStateValue(awattarCurrentMarketPriceStateTypeId, currentPrice / 10.0); device->setStateValue(awattarValidUntilStateTypeId, endTime.toLocalTime().toTime_t()); } } // calculate averagePrice and mean deviation averagePrice = sum / count; if (currentPrice <= averagePrice) { deviation = -1 * qRound(100 + (-100 * (currentPrice - minPrice) / (averagePrice - minPrice))); } else { deviation = qRound(-100 * (averagePrice - currentPrice) / (maxPrice - averagePrice)); } device->setStateValue(awattarAveragePriceStateTypeId, averagePrice / 10.0); device->setStateValue(awattarLowestPriceStateTypeId, minPrice / 10.0); device->setStateValue(awattarHighestPriceStateTypeId, maxPrice / 10.0); device->setStateValue(awattarAverageDeviationStateTypeId, deviation); }