diff --git a/sma/integrationpluginsma.cpp b/sma/integrationpluginsma.cpp index 142fa7d5..184ab7d5 100644 --- a/sma/integrationpluginsma.cpp +++ b/sma/integrationpluginsma.cpp @@ -73,12 +73,10 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info) void IntegrationPluginSma::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); - - if (!m_sunnyWebBoxCommunication) { - m_sunnyWebBoxCommunication = new SunnyWebBoxCommunication(hardwareManager()->networkManager(), this); - } + qCDebug(dcSma()) << "Setup thing" << thing->name(); if (!m_refreshTimer) { + qCDebug(dcSma()) << "Starting refresh timer"; m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(30); connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginSma::onRefreshTimer); } @@ -93,15 +91,23 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info) return; } } - SunnyWebBox *sunnyWebBox = new SunnyWebBox(m_sunnyWebBoxCommunication, QHostAddress(thing->paramValue(sunnyWebBoxThingHostParamTypeId).toString()), this); - connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived); - connect(sunnyWebBox, &SunnyWebBox::devicesReceived, this, &IntegrationPluginSma::onDevicesReceived); - connect(sunnyWebBox, &SunnyWebBox::processDataReceived, this, &IntegrationPluginSma::onProcessDataReceived); - connect(sunnyWebBox, &SunnyWebBox::parameterChannelsReceived, this, &IntegrationPluginSma::onParameterChannelsReceived); - m_sunnyWebBoxes.insert(thing, sunnyWebBox); - connect(info, &ThingSetupInfo::aborted, this, [thing, this] { m_sunnyWebBoxes.remove(thing);}); + if (m_sunnyWebBoxes.contains(thing)) { + qCDebug(dcSma()) << "Setup after reconfiguration, cleaning up..."; + m_sunnyWebBoxes.take(thing)->deleteLater(); + } + SunnyWebBox *sunnyWebBox = new SunnyWebBox(hardwareManager()->networkManager(), QHostAddress(thing->paramValue(sunnyWebBoxThingHostParamTypeId).toString()), this); + connect(info, &ThingSetupInfo::aborted, sunnyWebBox, &SunnyWebBox::deleteLater); + connect(sunnyWebBox, &SunnyWebBox::destroyed, this, [thing, this] { m_sunnyWebBoxes.remove(thing);}); QString requestId = sunnyWebBox->getPlantOverview(); - m_asyncSetup.insert(requestId, info); + connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, info, [sunnyWebBox, info, this] { + qCDebug(dcSma()) << "Received plant overview, finishing setup"; + info->finish(Thing::ThingErrorNoError); + connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived); + connect(sunnyWebBox, &SunnyWebBox::devicesReceived, this, &IntegrationPluginSma::onDevicesReceived); + connect(sunnyWebBox, &SunnyWebBox::processDataReceived, this, &IntegrationPluginSma::onProcessDataReceived); + connect(sunnyWebBox, &SunnyWebBox::parameterChannelsReceived, this, &IntegrationPluginSma::onParameterChannelsReceived); + m_sunnyWebBoxes.insert(info->thing(), sunnyWebBox); + }); return info->finish(Thing::ThingErrorNoError); } else if (thing->thingClassId() == inverterThingClassId) { @@ -127,6 +133,7 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info) void IntegrationPluginSma::postSetupThing(Thing *thing) { + qCDebug(dcSma()) << "Post setup thing" << thing->name(); if (thing->thingClassId() == sunnyWebBoxThingClassId) { SunnyWebBox *sunnyWebBox = m_sunnyWebBoxes.value(thing); if (!sunnyWebBox) @@ -167,9 +174,10 @@ void IntegrationPluginSma::thingRemoved(Thing *thing) m_sunnyWebBoxes.take(thing)->deleteLater(); } - if (myThings().filterByThingClassId(sunnyWebBoxThingClassId).isEmpty()) { - m_sunnyWebBoxCommunication->deleteLater(); - m_sunnyWebBoxCommunication = nullptr; + if (myThings().isEmpty()) { + qCDebug(dcSma()) << "Stopping timer"; + hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer); + m_refreshTimer = nullptr; } } @@ -210,7 +218,6 @@ void IntegrationPluginSma::onDevicesReceived(const QString &messageId, QListfinish(Thing::ThingErrorNoError); } - Thing *thing = m_sunnyWebBoxes.key(static_cast(sender())); if (!thing) return; @@ -254,16 +261,6 @@ void IntegrationPluginSma::onParameterChannelsReceived(const QString &messageId, qCDebug(dcSma()) << "Parameter channels received" << deviceKey << parameterChannels; } -SunnyWebBox * IntegrationPluginSma::createSunnyWebBoxConnection(Thing *thing) -{ - SunnyWebBox *sunnyWebBox = new SunnyWebBox(m_sunnyWebBoxCommunication, QHostAddress(thing->paramValue(sunnyWebBoxThingHostParamTypeId).toString()), this); - m_sunnyWebBoxes.insert(thing, sunnyWebBox); - connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived); - connect(sunnyWebBox, &SunnyWebBox::parameterChannelsReceived, this, &IntegrationPluginSma::onParameterChannelsReceived); - //connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived); - return sunnyWebBox; -} - void IntegrationPluginSma::setupChild(ThingSetupInfo *info, Thing *parentThing) { Q_UNUSED(info) diff --git a/sma/integrationpluginsma.h b/sma/integrationpluginsma.h index 8d445d31..4f3b30cd 100644 --- a/sma/integrationpluginsma.h +++ b/sma/integrationpluginsma.h @@ -71,7 +71,6 @@ private: QHash m_asyncActions; SunnyWebBoxCommunication *m_sunnyWebBoxCommunication = nullptr; - SunnyWebBox *createSunnyWebBoxConnection(Thing *thing); void setupChild(ThingSetupInfo *info, Thing *parentThing); void getData(Thing *thing); }; diff --git a/sma/sma.pro b/sma/sma.pro index fcf5dcec..168f97f3 100644 --- a/sma/sma.pro +++ b/sma/sma.pro @@ -6,13 +6,11 @@ QT += \ SOURCES += \ integrationpluginsma.cpp \ sunnywebbox.cpp \ - sunnywebboxcommunication.cpp \ host.cpp \ discovery.cpp HEADERS += \ integrationpluginsma.h \ sunnywebbox.h \ - sunnywebboxcommunication.h \ host.h \ discovery.h diff --git a/sma/sunnywebbox.cpp b/sma/sunnywebbox.cpp index c687affb..bc9968b6 100644 --- a/sma/sunnywebbox.cpp +++ b/sma/sunnywebbox.cpp @@ -35,37 +35,42 @@ #include "QJsonObject" #include "QJsonArray" -SunnyWebBox::SunnyWebBox(SunnyWebBoxCommunication *communication, const QHostAddress &hostAddress, QObject *parrent) : +SunnyWebBox::SunnyWebBox(NetworkAccessManager *networkAccessManager, const QHostAddress &hostAddress, QObject *parrent) : QObject(parrent), m_hostAddresss(hostAddress), - m_communication(communication) + m_networkManager(networkAccessManager) { + qCDebug(dcSma()) << "SunnyWebBox: Creating Sunny Web Box connection"; //TODO connect communication with socket state; - connect(m_communication, &SunnyWebBoxCommunication::messageReceived, this, &SunnyWebBox::onMessageReceived); +} + +SunnyWebBox::~SunnyWebBox() +{ + qCDebug(dcSma()) << "SunnyWebBox: Deleting Sunny Web Box connection"; } QString SunnyWebBox::getPlantOverview() { - return m_communication->sendMessage(m_hostAddresss, "GetPlantOverview"); + return sendMessage(m_hostAddresss, "GetPlantOverview"); } QString SunnyWebBox::getDevices() { - return m_communication->sendMessage(m_hostAddresss, "GetDevices"); + return sendMessage(m_hostAddresss, "GetDevices"); } QString SunnyWebBox::getProcessDataChannels(const QString &deviceId) { QJsonObject params; params["device"] = deviceId; - return m_communication->sendMessage(m_hostAddresss, "GetProcessDataChannels", params); + return sendMessage(m_hostAddresss, "GetProcessDataChannels", params); } QString SunnyWebBox::getProcessData(const QStringList &deviceKeys) { QJsonObject params; params["device"] = deviceKeys.first(); - return m_communication->sendMessage(m_hostAddresss, "GetProcessData", params); + return sendMessage(m_hostAddresss, "GetProcessData", params); } QString SunnyWebBox::getParameterChannels(const QString &deviceKey) @@ -76,7 +81,7 @@ QString SunnyWebBox::getParameterChannels(const QString &deviceKey) deviceObj["key"] = deviceKey; devicesArray.append(deviceObj); paramsObj["devices"] = devicesArray; - return m_communication->sendMessage(m_hostAddresss, "GetParameterChannels", paramsObj); + return sendMessage(m_hostAddresss, "GetParameterChannels", paramsObj); } QString SunnyWebBox::getParameters(const QStringList &deviceKeys) @@ -87,7 +92,7 @@ QString SunnyWebBox::getParameters(const QStringList &deviceKeys) deviceObj["key"] = deviceKeys.first(); //TODO devicesArray.append(deviceObj); paramsObj["devices"] = devicesArray; - return m_communication->sendMessage(m_hostAddresss, "GetParameter", paramsObj); + return sendMessage(m_hostAddresss, "GetParameter", paramsObj); } QString SunnyWebBox::setParameters(const QString &deviceKey, const QHash &channels) @@ -106,11 +111,12 @@ QString SunnyWebBox::setParameters(const QString &deviceKey, const QHashsendMessage(m_hostAddresss, "SetParameter", paramsObj); + return sendMessage(m_hostAddresss, "SetParameter", paramsObj); } void SunnyWebBox::setHostAddress(const QHostAddress &address) { + qCDebug(dcSma()) << "SunnyWebBox: Setting host address to" << address.toString(); m_hostAddresss = address; } @@ -119,12 +125,8 @@ QHostAddress SunnyWebBox::hostAddress() return m_hostAddresss; } -void SunnyWebBox::onMessageReceived(const QHostAddress &address, const QString &messageId, const QString &messageType, const QVariantMap &result) +void SunnyWebBox::parseMessage(const QString &messageId, const QString &messageType, const QVariantMap &result) { - if (address != m_hostAddresss) { - return; - } - if (messageType == "GetPlantOverview") { Overview overview; QVariantList overviewList = result.value("overview").toList(); @@ -215,3 +217,70 @@ void SunnyWebBox::onMessageReceived(const QHostAddress &address, const QString & qCWarning(dcSma()) << "Unknown message type" << messageType; } } + +QString SunnyWebBox::sendMessage(const QHostAddress &address, const QString &procedure) +{ + return sendMessage(address, procedure, QJsonObject()); +} + +QString SunnyWebBox::sendMessage(const QHostAddress &address, const QString &procedure, const QJsonObject ¶ms) +{ + QString requestId = QUuid::createUuid().toString().remove('{').remove('-').left(14); + + QJsonDocument doc; + QJsonObject obj; + obj["format"] = "JSON"; + obj["id"] = requestId; + obj["proc"] = procedure; + obj["version"] = "1.0"; + + if (!params.isEmpty()) { + obj.insert("params", params); + } + doc.setObject(obj); + + QUrl url; + url.setHost(address.toString()); + url.setPath("/rpc"); + url.setPort(80); + url.setScheme("http"); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + QByteArray data = doc.toJson(QJsonDocument::JsonFormat::Compact); + data.prepend("RPC="); + QNetworkReply *reply = m_networkManager->post(request, data); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, this, [this, address, requestId, reply]{ + + //int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + QByteArray data = reply->readAll(); + qCDebug(dcSma()) << "Received reply" << data; + + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcSma()) << "Could not parse JSON" << error.errorString(); + return; + } + if (!doc.isObject()) { + qCWarning(dcSma()) << "JSON is not an Object"; + return; + } + QVariantMap map = doc.toVariant().toMap(); + if (map["version"] != "1.0") { + qCWarning(dcSma()) << "API version not supported" << map["version"]; + return; + } + + if (map.contains("proc") && map.contains("result")) { + QString requestType = map["proc"].toString(); + QString requestId = map["id"].toString(); + QVariantMap result = map.value("result").toMap(); + parseMessage(requestId, requestType, result); + } else { + qCWarning(dcSma()) << "Missing proc or result value"; + } + }); + return requestId; +} + diff --git a/sma/sunnywebbox.h b/sma/sunnywebbox.h index ef20e0c4..51d0076b 100644 --- a/sma/sunnywebbox.h +++ b/sma/sunnywebbox.h @@ -73,7 +73,8 @@ public: double value; }; - explicit SunnyWebBox(SunnyWebBoxCommunication *communication, const QHostAddress &hostAddress, QObject *parrent = 0); + explicit SunnyWebBox(NetworkAccessManager *networkAccessManager, const QHostAddress &hostAddress, QObject *parrent = 0); + ~SunnyWebBox(); QString getPlantOverview(); // Returns an object with the following plant data: PAC, E-TODAY, E-TOTAL, MODE, ERROR QString getDevices(); //Returns a hierarchical list of all detected plant devices. @@ -89,10 +90,11 @@ public: private: QHostAddress m_hostAddresss; - SunnyWebBoxCommunication *m_communication = nullptr; + NetworkAccessManager *m_networkManager = nullptr; -public slots: - void onMessageReceived(const QHostAddress &address, const QString &messageId, const QString &messageType, const QVariantMap &result); + QString sendMessage(const QHostAddress &address, const QString &procedure); + QString sendMessage(const QHostAddress &address, const QString &procedure, const QJsonObject ¶ms); + void parseMessage(const QString &messageId, const QString &messageType, const QVariantMap &result); signals: void connectedChanged(bool connected); diff --git a/sma/sunnywebboxcommunication.cpp b/sma/sunnywebboxcommunication.cpp index 38882fd7..9e19e32d 100644 --- a/sma/sunnywebboxcommunication.cpp +++ b/sma/sunnywebboxcommunication.cpp @@ -42,6 +42,7 @@ SunnyWebBoxCommunication::SunnyWebBoxCommunication(NetworkAccessManager *network QObject(parent), m_networkManager(networkAccessManager) { + qCDebug(dcSma()) << "Creating SunnyWebBoxCommunictaion"; m_udpSocket = new QUdpSocket(this); m_udpSocket->bind(QHostAddress::Any, m_port); @@ -63,51 +64,7 @@ SunnyWebBoxCommunication::SunnyWebBoxCommunication(NetworkAccessManager *network }); } -QString SunnyWebBoxCommunication::sendMessage(const QHostAddress &address, const QString &procedure) -{ - QString requestId = QUuid::createUuid().toString().remove('{').remove('-').left(14); - QJsonDocument doc; - QJsonObject obj; - obj["format"] = "JSON"; - obj["id"] = requestId; - obj["proc"] = procedure; - obj["version"] = "1.0"; - doc.setObject(obj); - - QUrl url; - url.setHost(address.toString()); - url.setPath("/rpc"); - url.setScheme("http"); - QNetworkRequest request(url); - request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); - QByteArray data = doc.toJson(QJsonDocument::JsonFormat::Compact); - - QNetworkReply *reply = m_networkManager->post(request, data); - connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); - connect(reply, &QNetworkReply::finished, this, [this, address, requestId, reply]{ - - //int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - QByteArray data = reply->readAll(); - qCDebug(dcSma()) << "Received reply" << data; - datagramReceived(address, data); - }); - - /* if(!m_messageResponsePending) { - qCDebug(dcSma()) << "Send message" << data << address << m_port; - m_udpSocket->writeDatagram(data, address, m_port); - m_messageResponsePending = true; - } else { - if (m_messageQueue[address].length() < 40) { - qCDebug(dcSma()) << "Adding message to queue" << data << address << m_port; - m_messageQueue[address].append(data); - } else { - qCWarning(dcSma()) << "Message queue overflow"; - return ""; - } - }*/ - return requestId; -} QString SunnyWebBoxCommunication::sendMessage(const QHostAddress &address, const QString &procedure, const QJsonObject ¶ms) {