/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. * This project including source code and documentation is protected by * copyright law, and remains the property of nymea GmbH. All rights, including * reproduction, publication, editing and translation, are reserved. The use of * this project is subject to the terms of a license agreement to be concluded * with nymea GmbH in accordance with the terms of use of nymea GmbH, available * under https://nymea.io/license * * GNU Lesser General Public License Usage * Alternatively, this project may be redistributed and/or modified under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; version 3. This project 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 project. If not, see . * * For any further details and any questions please contact us under * contact@nymea.io or see our FAQ/Licensing Information on * https://nymea.io/license/faq * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Example reply for HOME and PRO: HOME: GET /daten.cfg: Length 13 0: NET-CONTROL ; 1: Mo, 07.01.19 02:24:54; 2: 18; 3: ; 4: 12; 5: 1; 6: Login: user7 10.10.10.128; 7: 4.5 DE; 8: 7648; 9: 0; 10: H; 11: end; 12: NET - Power Control ADV: GET /daten.cfg: Length 11 0: 1546827738; 1: 64; 2: 0; 3: 37; 4: 1; 5: 19789; 6: 5; 7: 24.7; 8: 9; 9: 2; 10: end HUT: GET /daten.cfg: Length 18 0: 1546830796; 1: 93; 2: 41; 3: 194; 4: 1; 5: 12587; 6: 14; 7: 24.7; 8: 9; 9: 2; 10: end; 11: s; 12: 1; 13: 22.90; 14: 44.4; 15: 851; 16: 1; 17: 0.00; HOME/PRO GET strg.cfg: Length 60 0: NET-PWRCTRL_04.5; // thing name 1: NET-CONTROL ; // hostname 2: 10.10.10.132; // IP 3: 255.255.255.0; // Netmask 4: 10.10.10.1; // Gateway 5: 00:04:A3:0B:0C:3A; // MAC 6: 80; // Webcontrol port 7: ; // Temp 8: H; // Type 9: ; // ?? (Skipped by upstream code) Following fields are repeated 8 times each, one for each socket 10: Nr. 1; // Name 1 11: 1; // Stand 12: 0; // Dis 13: Anfangsstatus; // Info 14: ; // TK end; NET - Power Control" ADV: GET /strg.cfg: Length 58 0: Nr.1;0;0;28;K; 5: Nr.2;0;0;28;; 10: Nr.3;1;0;27;; 15: Nr.4;0;0;28;; 20: Nr.5;0;0;28;; 25: Nr.6;0;0;28;; 30: Nr.7;0;0;0;; 35: Nr.8;0;0;28;; 40: end; 41: 0; 42: 0; 43: 0; 44: 1; 45: 0; 46: 0; 47: 0; 48: 1; 49: 10122; 50: 10123; 51: 10124; 52: 8657; 53: 10126; 54: 10127; 55: 10128; 56: 8659; */ #include "integrationpluginanel.h" #include "plugininfo.h" #include "plugintimer.h" #include "discovery.h" #include #include #include #include QHash connectedStateTypeIdMap = { {netPwrCtlHomeThingClassId, netPwrCtlHomeConnectedStateTypeId}, {netPwrCtlProThingClassId, netPwrCtlProConnectedStateTypeId}, {netPwrCtlAdvThingClassId, netPwrCtlAdvConnectedStateTypeId}, {netPwrCtlHutThingClassId, netPwrCtlHutConnectedStateTypeId}, {socketThingClassId, socketConnectedStateTypeId} }; QHash macAddressParamTypeIdMap = { {netPwrCtlHomeThingClassId, netPwrCtlHomeThingMacAddressParamTypeId}, {netPwrCtlProThingClassId, netPwrCtlProThingMacAddressParamTypeId}, {netPwrCtlAdvThingClassId, netPwrCtlAdvThingMacAddressParamTypeId}, {netPwrCtlHutThingClassId, netPwrCtlHutThingMacAddressParamTypeId} }; IntegrationPluginAnel::IntegrationPluginAnel() { } IntegrationPluginAnel::~IntegrationPluginAnel() { } void IntegrationPluginAnel::init() { m_discovery = new Discovery(this); // Every time the discovery finish, we'll check if we need to update cached ip/port connect(m_discovery, &Discovery::finished, this, [=](bool error){ if (error) { return; } foreach (Thing *thing, myThings()) { if (!macAddressParamTypeIdMap.contains(thing->thingClassId())) { continue; } QString macAddress = thing->paramValue(macAddressParamTypeIdMap.value(thing->thingClassId())).toString(); // Upgrading configured things from old version where the MAC param was still holding an IP address instead if (!QHostAddress(macAddress).isNull()) { qCDebug(dcAnelElektronik()) << "Upgrading configuration for:" << thing->name(); foreach (const Discovery::Result &result, m_discovery->results()) { if (result.ipAddress == macAddress) { macAddress = result.macAddress; thing->setParamValue(macAddressParamTypeIdMap.value(thing->thingClassId()), macAddress); } } } if (m_discovery->results().contains(macAddress)) { Discovery::Result result = m_discovery->results().value(macAddress); qCDebug(dcAnelElektronik()) << "Updating IP address for" << thing->name() << "to" << result.ipAddress << ":" << result.port; pluginStorage()->beginGroup(thing->id().toString()); pluginStorage()->setValue("cachedAddress", result.ipAddress); pluginStorage()->setValue("cachedPort", result.port); pluginStorage()->endGroup(); } } }); } void IntegrationPluginAnel::discoverThings(ThingDiscoveryInfo *info) { connect(m_discovery, &Discovery::finished, info, [=](bool error){ if (error) { qCWarning(dcAnelElektronik()) << "Error sending discovery"; //: Error discovering devices info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error sending data to the network.")); return; } foreach (const Discovery::Result &result, m_discovery->results()) { ThingDescriptor d(info->thingClassId(), result.name, result.ipAddress); ParamTypeId macAddressParamTypeId = macAddressParamTypeIdMap.value(info->thingClassId()); ParamList params; params << Param(macAddressParamTypeId, result.macAddress); d.setParams(params); foreach (Thing *existingThing, myThings().filterByThingClassId(info->thingClassId())) { if (existingThing->paramValue(macAddressParamTypeId).toString() == result.macAddress) { qCDebug(dcAnelElektronik()) << "Already have" << result.macAddress << result.ipAddress << "in configured things."; d.setThingId(existingThing->id()); break; } } info->addThingDescriptor(d); } info->finish(Thing::ThingErrorNoError); }); m_discovery->discover(); } void IntegrationPluginAnel::startPairing(ThingPairingInfo *info) { info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter the login credentials for your NET-PWRCTRL device.")); } void IntegrationPluginAnel::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &password) { QString macAddress = info->params().paramValue(macAddressParamTypeIdMap.value(info->thingClassId())).toString(); QString ipAddress = m_discovery->results().value(macAddress).ipAddress; int port = m_discovery->results().value(macAddress).port; QNetworkRequest request; request.setUrl(QUrl(QString("http://%1:%2/strg.cfg").arg(ipAddress).arg(port))); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username).arg(password).toUtf8().toBase64()); qCDebug(dcAnelElektronik()) << "ConfirmPairing fetching:" << request.url() << request.rawHeader("Authorization"); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, info, [=](){ if (reply->error() == QNetworkReply::NoError) { pluginStorage()->beginGroup(info->thingId().toString()); pluginStorage()->setValue("cachedAddress", ipAddress); pluginStorage()->setValue("cachedPort", port); pluginStorage()->setValue("username", username); pluginStorage()->setValue("password", password); pluginStorage()->endGroup(); info->finish(Thing::ThingErrorNoError); } else { //: Error pairing thing info->finish(Thing::ThingErrorAuthenticationFailure, QT_TR_NOOP("Wrong username or password.")); } }); } void IntegrationPluginAnel::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); if (thing->thingClassId() == netPwrCtlHomeThingClassId || thing->thingClassId() == netPwrCtlProThingClassId) { setupHomeProDevice(info); return; } if (thing->thingClassId() == netPwrCtlAdvThingClassId || thing->thingClassId() == netPwrCtlHutThingClassId) { setupAdvDevice(info); return; } if (thing->thingClassId() == socketThingClassId) { qCDebug(dcAnelElektronik()) << "Setting up" << thing->name(); if (!m_pollTimer) { m_pollTimer = hardwareManager()->pluginTimerManager()->registerTimer(2); connect(m_pollTimer, &PluginTimer::timeout, this, &IntegrationPluginAnel::refreshStates); } info->finish(Thing::ThingErrorNoError); return; } qCWarning(dcAnelElektronik) << "Unhandled ThingClass in setupDevice" << thing->thingClassId(); info->finish(Thing::ThingErrorThingClassNotFound); } void IntegrationPluginAnel::postSetupThing(Thing *thing) { Q_UNUSED(thing) if (!m_discoverTimer) { m_discoverTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); connect(m_discoverTimer, &PluginTimer::timeout, m_discovery, &Discovery::discover); } } void IntegrationPluginAnel::thingRemoved(Thing *thing) { qCDebug(dcAnelElektronik) << "Device removed" << thing->name(); if (myThings().isEmpty()) { hardwareManager()->pluginTimerManager()->unregisterTimer(m_pollTimer); m_pollTimer = nullptr; hardwareManager()->pluginTimerManager()->unregisterTimer(m_discoverTimer); m_discoverTimer = nullptr; } } void IntegrationPluginAnel::executeAction(ThingActionInfo *info) { Thing *thing = info->thing(); Action action = info->action(); if (thing->thingClassId() == socketThingClassId) { if (action.actionTypeId() == socketPowerActionTypeId) { Thing *parentDevice = myThings().findById(thing->parentId()); pluginStorage()->beginGroup(parentDevice->id().toString()); QString ipAddress = pluginStorage()->value("cachedAddress").toString(); int port = pluginStorage()->value("cachedPort").toInt(); QString username = pluginStorage()->value("username").toString(); QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); QUrl url(QString("http://%1:%2/ctrl.htm").arg(ipAddress).arg(port)); QNetworkRequest request(url); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username, password).toUtf8().toBase64()); request.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain"); QByteArray data = QString("F%1=%2").arg(thing->paramValue(socketThingNumberParamTypeId).toString(), action.param(socketPowerActionPowerParamTypeId).value().toBool() == true ? "1" : "0").toUtf8(); QNetworkReply *reply = hardwareManager()->networkManager()->post(request, data); qCDebug(dcAnelElektronik()) << "Requesting:" << url.toString() << request.rawHeader("Authorization"); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, info, [reply, info](){ if (reply->error() != QNetworkReply::NoError) { qCWarning(dcAnelElektronik()) << "Execute action failed:" << reply->error() << reply->errorString(); info->finish(Thing::ThingErrorHardwareFailure); return; } qCDebug(dcAnelElektronik()) << "Execute action done."; info->finish(Thing::ThingErrorNoError); }); return; } } info->finish(Thing::ThingErrorThingClassNotFound); } void IntegrationPluginAnel::refreshStates() { foreach (Thing *thing, myThings()) { if (thing->thingClassId() == netPwrCtlHomeThingClassId || thing->thingClassId() == netPwrCtlProThingClassId) { refreshHomePro(thing); } if (thing->thingClassId() == netPwrCtlAdvThingClassId || thing->thingClassId() == netPwrCtlHutThingClassId) { refreshAdv(thing); } } } void IntegrationPluginAnel::setConnectedState(Thing *thing, bool connected) { thing->setStateValue(connectedStateTypeIdMap.value(thing->thingClassId()), connected); foreach (Thing *child, myThings()) { if (child->parentId() == thing->id()) { child->setStateValue(connectedStateTypeIdMap.value(child->thingClassId()), connected); } } } void IntegrationPluginAnel::setupHomeProDevice(ThingSetupInfo *info) { Thing *thing = info->thing(); QString macAddress = thing->paramValue(macAddressParamTypeIdMap.value(thing->thingClassId())).toString(); // Run a discovery and wait for it to finish before setting it up. m_discovery->discover(); connect(m_discovery, &Discovery::finished, info, [=](){ pluginStorage()->beginGroup(thing->id().toString()); QString ipAddress = pluginStorage()->value("cachedAddress").toString(); int port = pluginStorage()->value("cachedPort").toInt(); QString username = pluginStorage()->value("username").toString(); QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); QNetworkRequest request; request.setUrl(QUrl(QString("http://%1:%2/strg.cfg").arg(ipAddress).arg(port))); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username).arg(password).toUtf8().toBase64()); qCDebug(dcAnelElektronik()) << "SetupDevice fetching:" << request.url() << request.rawHeader("Authorization") << username << password; QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, info, [this, info, reply](){ StateTypeId connectedStateTypeId = connectedStateTypeIdMap.value(info->thing()->thingClassId()); if (reply->error() != QNetworkReply::NoError) { qCWarning(dcAnelElektronik()) << "Error fetching state for" << info->thing()->name() << reply->error() << reply->errorString(); info->thing()->setStateValue(connectedStateTypeId, false); //: Error setting up thing info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The thing rejected our connection. Please check the configured network ports.")); return; } info->thing()->setStateValue(connectedStateTypeId, true); QByteArray data = reply->readAll(); QStringList parts = QString(data).split(';'); int startIndex = parts.indexOf("end") - 58; if (startIndex < 0 || !parts.at(startIndex).startsWith("NET-PWRCTRL") || parts.length() < 60) { qCWarning(dcAnelElektronik()) << "Bad data from panel:" << data << "Length:" << parts.length(); //: Error setting up thing info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unexpected data received from NET-PWRCTL device. Perhaps it's running an old firmware?")); return; } // At this point we're done with gathering information about the panel. Setup defintely succeeded for the gateway thing info->finish(Thing::ThingErrorNoError); // If we haven't set up childs for this gateway yet, let's do it now foreach (Thing *child, myThings()) { if (child->parentId() == info->thing()->id()) { // Already have childs for this panel. We're done here return; } } // Lets add the child devices now int childs = -1; QString type = parts.at(startIndex + 8); if (type == "H") { childs = 3; } else { childs = 8; } QList descriptorList; for (int i = 0; i < childs; i++) { QString deviceName = parts.at(startIndex + 10 + i); ThingDescriptor d(socketThingClassId, deviceName, info->thing()->name(), info->thing()->id()); d.setParams(ParamList() << Param(socketThingNumberParamTypeId, i)); descriptorList << d; } emit autoThingsAppeared(descriptorList); }); }); } void IntegrationPluginAnel::setupAdvDevice(ThingSetupInfo *info) { Thing *thing = info->thing(); QString macAddress = thing->paramValue(macAddressParamTypeIdMap.value(thing->thingClassId())).toString(); // Run a discovery and wait for it to finish before trying to connect m_discovery->discover(); connect(m_discovery, &Discovery::finished, info, [=](){ pluginStorage()->beginGroup(thing->id().toString()); QString ipAddress = pluginStorage()->value("cachedAddress").toString(); int port = pluginStorage()->value("cachedPort").toInt(); QString username = pluginStorage()->value("username").toString(); QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); QNetworkRequest request; request.setUrl(QUrl(QString("http://%1:%2/strg.cfg").arg(ipAddress).arg(port))); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username).arg(password).toUtf8().toBase64()); qCDebug(dcAnelElektronik()) << "SetupDevice fetching:" << request.url() << request.rawHeader("Authorization"); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, info, [this, info, reply]() { StateTypeId connectedStateTypeId = connectedStateTypeIdMap.value(info->thing()->thingClassId()); if (reply->error() != QNetworkReply::NoError) { qCWarning(dcAnelElektronik()) << "Error fetching state for" << info->thing()->name() << reply->error() << reply->errorString(); info->thing()->setStateValue(connectedStateTypeId, false); //: Error setting up thing info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The thing rejected our connection. Please check the configured network ports.")); return; } info->thing()->setStateValue(connectedStateTypeId, true); QByteArray data = reply->readAll(); QStringList parts = QString(data).split(';'); int startIndex = parts.indexOf("end") - 40; if (startIndex < 0 || parts.length() < 58) { qCWarning(dcAnelElektronik()) << "Bad data from panel:" << data << "Length:" << parts.length(); //: Error setting up thing info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unexpected data received from NET-PWRCTL device. Perhaps it's running an old firmware?")); return; } // At this point we're done with gathering information about the panel. Setup defintely succeeded for the gateway thing info->finish(Thing::ThingErrorNoError); // If we haven't set up childs for this gateway yet, let's do it now foreach (Thing *child, myThings()) { if (child->parentId() == info->thing()->id()) { // Already have childs for this panel. We're done here return; } } QList descriptorList; for (int i = 0; i < 8; i++) { QString deviceName = parts.at(startIndex + (i * 5)); ThingDescriptor d(socketThingClassId, deviceName, info->thing()->name(), info->thing()->id()); d.setParams(ParamList() << Param(socketThingNumberParamTypeId, i)); descriptorList << d; } emit autoThingsAppeared(descriptorList); }); }); } void IntegrationPluginAnel::refreshHomePro(Thing *thing) { pluginStorage()->beginGroup(thing->id().toString()); QString ipAddress = pluginStorage()->value("cachedAddress").toString(); int port = pluginStorage()->value("cachedPort").toInt(); QString username = pluginStorage()->value("username").toString(); QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); QUrl url(QString("http://%1:%2/strg.cfg").arg(ipAddress).arg(port)); QNetworkRequest request; request.setUrl(url); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username, password).toUtf8().toBase64()); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, thing, [this, thing, reply](){ if (reply->error() != QNetworkReply::NoError) { qCWarning(dcAnelElektronik()) << "Error fetching state for" << thing->name(); setConnectedState(thing, false); return; } QByteArray data = reply->readAll(); // qCDebug(dcAnelElektronik()) << "States reply:" << data; QStringList parts = QString(data).split(';'); int startIndex = parts.indexOf("end") - 58; if (startIndex < 0 || !parts.at(startIndex).startsWith("NET-PWRCTRL")) { qCWarning(dcAnelElektronik()) << "Bad data from Panel" << thing->name() << data; // This happens sometimes when multiple clients are talking to the panel... Just ignore it... return; } setConnectedState(thing, true); // The temp sensor seems to have a bit of jitter. Reduce sample rate to avoid spamming the log quint32 samples = thing->property("tempSamples").toUInt(); if (samples % 15 == 0 && thing->thingClassId() == netPwrCtlProThingClassId) { bool ok; double tempValue = parts.at(startIndex + 7).toDouble(&ok); if (ok) { thing->setStateValue(netPwrCtlProTemperatureStateTypeId, tempValue); } else { qCWarning(dcAnelElektronik()) << "Error reading temperature value from data:" << parts.at(startIndex + 7); } } thing->setProperty("tempSamples", ++samples); foreach (Thing *child, myThings()) { if (child->parentId() == thing->id()) { int number = child->paramValue(socketThingNumberParamTypeId).toInt(); child->setStateValue(socketPowerStateTypeId, parts.value(startIndex + 20 + number).toInt() == 1); } } }); } void IntegrationPluginAnel::refreshAdv(Thing *thing) { pluginStorage()->beginGroup(thing->id().toString()); QString ipAddress = pluginStorage()->value("cachedAddress").toString(); int port = pluginStorage()->value("cachedPort").toInt(); QString username = pluginStorage()->value("username").toString(); QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); QUrl url(QString("http://%1:%2/strg.cfg").arg(ipAddress).arg(port)); QNetworkRequest request; request.setUrl(url); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username, password).toUtf8().toBase64()); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, thing, [this, thing, reply](){ if (reply->error() != QNetworkReply::NoError) { qCWarning(dcAnelElektronik()) << "Error fetching state for" << thing->name(); setConnectedState(thing, false); return; } QByteArray data = reply->readAll(); // qCDebug(dcAnelElektronik()) << "States reply:" << data; QStringList parts = QString(data).split(';'); int startIndex = parts.indexOf("end") - 40; if (startIndex < 0 || parts.count() < 58) { qCWarning(dcAnelElektronik()) << "Bad data from Panel" << thing->name() << data << "Length:" << parts.length(); // This happens sometimes when multiple clients are talking to the panel... Just ignore it... return; } setConnectedState(thing, true); foreach (Thing *child, myThings()) { if (child->parentId() == thing->id()) { int number = child->paramValue(socketThingNumberParamTypeId).toInt(); child->setStateValue(socketPowerStateTypeId, parts.value(startIndex + (number * 5) + 1).toInt() == 1); } } // The temp sensor seems to have a bit of jitter. Reduce sample rate to avoid spamming the log quint32 samples = thing->property("tempSamples").toUInt(); if (samples % 15 == 0) { refreshAdvTemp(thing); } thing->setProperty("tempSamples", ++samples); }); } void IntegrationPluginAnel::refreshAdvTemp(Thing *thing) { pluginStorage()->beginGroup(thing->id().toString()); QString ipAddress = pluginStorage()->value("cachedAddress").toString(); int port = pluginStorage()->value("cachedPort").toInt(); QString username = pluginStorage()->value("username").toString(); QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); QUrl url(QString("http://%1:%2/daten.cfg").arg(ipAddress).arg(port)); QNetworkRequest request; request.setUrl(url); request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username, password).toUtf8().toBase64()); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, thing, [this, thing, reply](){ if (reply->error() != QNetworkReply::NoError) { qCWarning(dcAnelElektronik()) << "Error fetching temp for" << thing->name(); setConnectedState(thing, false); return; } QByteArray data = reply->readAll(); qCDebug(dcAnelElektronik()) << "Temp reply:" << data; QStringList parts = QString(data).split(';'); int startIndex = parts.indexOf("end") - 10; if (startIndex < 0) { qCWarning(dcAnelElektronik()) << "Bad data from Panel" << thing->name() << data << "Length:" << parts.length(); // This happens sometimes when multiple clients are talking to the panel... Just ignore it... return; } if (thing->thingClassId() == netPwrCtlAdvThingClassId) { bool ok; double temp = parts.at(7).toDouble(&ok); if (ok) { thing->setStateValue(netPwrCtlAdvTemperatureStateTypeId, temp); } else { qCWarning(dcAnelElektronik()) << "Error fetching temperature value:" << data; } } else { // HUT if (parts.length() < 18) { qCWarning(dcAnelElektronik()) << "Data too short for HUT device" << data; return; } bool ok; double temp = parts.at(13).toDouble(&ok); if (ok) { thing->setStateValue(netPwrCtlHutTemperatureStateTypeId, temp); } else { qCWarning(dcAnelElektronik()) << "Error fetching temperature value:" << data; } double humidity = parts.at(14).toDouble(&ok); if (ok) { thing->setStateValue(netPwrCtlHutHumidityStateTypeId, humidity); } else { qCWarning(dcAnelElektronik()) << "Error fetching humidity value:" << data; } int lux = parts.at(15).toInt(&ok); if (ok) { thing->setStateValue(netPwrCtlHutLightIntensityStateTypeId, lux); } else { qCWarning(dcAnelElektronik()) << "Error fetching light intensity value:" << data; } } }); }