diff --git a/anel/devicepluginanel.cpp b/anel/devicepluginanel.cpp index 5fb28523..4be20b4c 100644 --- a/anel/devicepluginanel.cpp +++ b/anel/devicepluginanel.cpp @@ -39,6 +39,109 @@ \quotefile plugins/deviceplugins/tasmota/devicepluginanel.json */ +/* +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; // device 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 "devicepluginanel.h" #include "plugininfo.h" #include "plugintimer.h" @@ -46,11 +149,35 @@ #include #include #include +#include DevicePluginAnel::DevicePluginAnel() { - m_connectedStateTypeIdMap.insert(netPwrCtlDeviceClassId, netPwrCtlConnectedStateTypeId); + m_connectedStateTypeIdMap.insert(netPwrCtlHomeDeviceClassId, netPwrCtlHomeConnectedStateTypeId); + m_connectedStateTypeIdMap.insert(netPwrCtlProDeviceClassId, netPwrCtlProConnectedStateTypeId); + m_connectedStateTypeIdMap.insert(netPwrCtlAdvDeviceClassId, netPwrCtlAdvConnectedStateTypeId); + m_connectedStateTypeIdMap.insert(netPwrCtlHutDeviceClassId, netPwrCtlHutConnectedStateTypeId); m_connectedStateTypeIdMap.insert(socketDeviceClassId, socketConnectedStateTypeId); + + m_ipAddressParamTypeIdMap.insert(netPwrCtlHomeDeviceClassId, netPwrCtlHomeDeviceIpAddressParamTypeId); + m_ipAddressParamTypeIdMap.insert(netPwrCtlProDeviceClassId, netPwrCtlProDeviceIpAddressParamTypeId); + m_ipAddressParamTypeIdMap.insert(netPwrCtlAdvDeviceClassId, netPwrCtlAdvDeviceIpAddressParamTypeId); + m_ipAddressParamTypeIdMap.insert(netPwrCtlHutDeviceClassId, netPwrCtlHutDeviceIpAddressParamTypeId); + + m_portParamTypeIdMap.insert(netPwrCtlHomeDeviceClassId, netPwrCtlHomeDevicePortParamTypeId); + m_portParamTypeIdMap.insert(netPwrCtlProDeviceClassId, netPwrCtlProDevicePortParamTypeId); + m_portParamTypeIdMap.insert(netPwrCtlAdvDeviceClassId, netPwrCtlAdvDevicePortParamTypeId); + m_portParamTypeIdMap.insert(netPwrCtlHutDeviceClassId, netPwrCtlHutDevicePortParamTypeId); + + m_userParamTypeIdMap.insert(netPwrCtlHomeDeviceClassId, netPwrCtlHomeDeviceUsernameParamTypeId); + m_userParamTypeIdMap.insert(netPwrCtlProDeviceClassId, netPwrCtlProDeviceUsernameParamTypeId); + m_userParamTypeIdMap.insert(netPwrCtlAdvDeviceClassId, netPwrCtlAdvDeviceUsernameParamTypeId); + m_userParamTypeIdMap.insert(netPwrCtlHutDeviceClassId, netPwrCtlHutDeviceUsernameParamTypeId); + + m_passParamTypeIdMap.insert(netPwrCtlHomeDeviceClassId, netPwrCtlHomeDevicePasswordParamTypeId); + m_passParamTypeIdMap.insert(netPwrCtlProDeviceClassId, netPwrCtlProDevicePasswordParamTypeId); + m_passParamTypeIdMap.insert(netPwrCtlAdvDeviceClassId, netPwrCtlAdvDevicePasswordParamTypeId); + m_passParamTypeIdMap.insert(netPwrCtlHutDeviceClassId, netPwrCtlHutDevicePasswordParamTypeId); } DevicePluginAnel::~DevicePluginAnel() @@ -79,7 +206,7 @@ DeviceManager::DeviceError DevicePluginAnel::discoverDevices(const DeviceClassId return DeviceManager::DeviceErrorHardwareFailure; } - QTimer::singleShot(2000, this, [this, searchSocket](){ + QTimer::singleShot(2000, this, [this, searchSocket, deviceClassId](){ QList descriptorList; while(searchSocket->hasPendingDatagrams()) { char buffer[1024]; @@ -97,9 +224,15 @@ DeviceManager::DeviceError DevicePluginAnel::discoverDevices(const DeviceClassId continue; } qCDebug(dcAnelElektronik()) << "Found NET-CONTROL:" << senderAddress << parts.at(2) << parts.at(3) << senderAddress.protocol(); + + ParamTypeId ipAddressParamTypeId = m_ipAddressParamTypeIdMap.value(deviceClassId); + ParamTypeId portParamTypeId = m_portParamTypeIdMap.value(deviceClassId); + ParamTypeId userParamTypeId = m_userParamTypeIdMap.value(deviceClassId); + ParamTypeId passParamTypeId = m_passParamTypeIdMap.value(deviceClassId); + bool existing = false; foreach (Device *existingDev, myDevices()) { - if (existingDev->deviceClassId() == netPwrCtlDeviceClassId && existingDev->paramValue(netPwrCtlDeviceIpAddressParamTypeId).toString() == senderAddress.toString()) { + if (existingDev->deviceClassId() == deviceClassId && existingDev->paramValue(ipAddressParamTypeId).toString() == senderAddress.toString()) { existing = true; } } @@ -107,16 +240,16 @@ DeviceManager::DeviceError DevicePluginAnel::discoverDevices(const DeviceClassId qCDebug(dcAnelElektronik()) << "Already have device" << senderAddress << "in configured devices. Skipping..."; continue; } - DeviceDescriptor d(netPwrCtlDeviceClassId, parts.at(2), senderAddress.toString()); + DeviceDescriptor d(deviceClassId, parts.at(2), senderAddress.toString()); ParamList params; - params << Param(netPwrCtlDeviceIpAddressParamTypeId, senderAddress.toString()); - params << Param(netPwrCtlDevicePortParamTypeId, parts.at(3).toInt()); - params << Param(netPwrCtlDeviceUsernameParamTypeId, "user7"); - params << Param(netPwrCtlDevicePasswordParamTypeId, "anel"); + params << Param(ipAddressParamTypeId, senderAddress.toString()); + params << Param(portParamTypeId, parts.at(3).toInt()); + params << Param(userParamTypeId, "user7"); + params << Param(passParamTypeId, "anel"); d.setParams(params); descriptorList << d; } - emit devicesDiscovered(netPwrCtlDeviceClassId, descriptorList); + emit devicesDiscovered(deviceClassId, descriptorList); searchSocket->deleteLater(); }); return DeviceManager::DeviceErrorAsync; @@ -124,95 +257,13 @@ DeviceManager::DeviceError DevicePluginAnel::discoverDevices(const DeviceClassId DeviceManager::DeviceSetupStatus DevicePluginAnel::setupDevice(Device *device) { - if (device->deviceClassId() == netPwrCtlDeviceClassId) { -// int sendPort = device->paramValue(netPwrCtlHomeDeviceSendPortParamTypeId).toInt(); -// int receivePort = device->paramValue(netPwrCtlHomeDeviceReceivePortParamTypeId).toInt(); - - - QNetworkRequest request; - request.setUrl(QUrl("http://" + device->paramValue(netPwrCtlDeviceIpAddressParamTypeId).toString() + ":" + device->paramValue(netPwrCtlDevicePortParamTypeId).toString() + "/strg.cfg")); - QString username = device->paramValue(netPwrCtlDeviceUsernameParamTypeId).toString(); - QString password = device->paramValue(netPwrCtlDevicePasswordParamTypeId).toString(); - request.setRawHeader("Authorization", "Basic " + QString("%1:%2").arg(username, 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, device, [this, device, reply](){ - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcAnelElektronik()) << "Error fetching state for" << device->name() << reply->error() << reply->errorString(); - device->setStateValue(netPwrCtlConnectedStateTypeId, false); - emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure); - return; - } - device->setStateValue(netPwrCtlConnectedStateTypeId, true); - - QByteArray data = reply->readAll(); - - QStringList parts = QString(data).split(';'); - - int startIndex = parts.indexOf("end") - 58; - if (startIndex < 0 || !parts.at(startIndex + 1).startsWith("NET-CONTROL")) { - qCWarning(dcAnelElektronik()) << "Bad data from panel:" << data << "Length:" << parts.length(); - emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure); - return; - } - - // At this point we're done with gathering information about the panel. Setup defintely succeeded for the gateway device - emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess); - - // If we haven't set up childs for this gateway yet, let's do it now - foreach (Device *child, myDevices()) { - if (child->parentId() == device->id()) { - // Already have childs for this panel. We're done here - return; - } - } - - // Example reply: - - // NET-PWRCTRL_04.5; // device name - // NET-CONTROL ; // hostname - // 10.10.10.132; // IP - // 255.255.255.0; // Netmask - // 10.10.10.1; // Gateway - // 00:04:A3:0B:0C:3A; // MAC - // 80; // Webcontrol port - // ; // Temp - // H; // Type - // ; // ?? (Skipped by upstream code) - - // Following fields are repeated 1 times each, one for each socket - - // Nr. 1; // Name 1 - // 1; // Stand - // 0; // Dis - // Anfangsstatus; // Info - // ; // TK - - // end; - // NET - Power Control" - - - // 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); - DeviceDescriptor d(socketDeviceClassId, deviceName, device->name(), device->id()); - d.setParams(ParamList() << Param(socketDeviceNumberParamTypeId, i)); - descriptorList << d; - } - emit autoDevicesAppeared(socketDeviceClassId, descriptorList); - }); - - return DeviceManager::DeviceSetupStatusAsync; + if (device->deviceClassId() == netPwrCtlHomeDeviceClassId + || device->deviceClassId() == netPwrCtlProDeviceClassId) { + return setupHomeProDevice(device); + } + if (device->deviceClassId() == netPwrCtlAdvDeviceClassId + || device->deviceClassId() == netPwrCtlHutDeviceClassId) { + return setupAdvDevice(device); } if (device->deviceClassId() == socketDeviceClassId) { @@ -240,14 +291,17 @@ void DevicePluginAnel::deviceRemoved(Device *device) DeviceManager::DeviceError DevicePluginAnel::executeAction(Device *device, const Action &action) { if (device->deviceClassId() == socketDeviceClassId) { - - Device *parentDevice = myDevices().findById(device->parentId()); - if (action.actionTypeId() == socketPowerActionTypeId) { - QUrl url("http://" + parentDevice->paramValue(netPwrCtlDeviceIpAddressParamTypeId).toString() + ":" + parentDevice->paramValue(netPwrCtlDevicePortParamTypeId).toString() + "/ctrl.htm"); + + Device *parentDevice = myDevices().findById(device->parentId()); + + QString ipAddress = parentDevice->paramValue(m_ipAddressParamTypeIdMap.value(parentDevice->deviceClassId())).toString(); + int port = parentDevice->paramValue(m_portParamTypeIdMap.value(parentDevice->deviceClassId())).toInt(); + QString username = parentDevice->paramValue(m_userParamTypeIdMap.value(parentDevice->deviceClassId())).toString(); + QString password = parentDevice->paramValue(m_passParamTypeIdMap.value(parentDevice->deviceClassId())).toString(); + + QUrl url(QString("http://%1:%2/ctrl.htm").arg(ipAddress).arg(port)); QNetworkRequest request(url); - QString username = parentDevice->paramValue(netPwrCtlDeviceUsernameParamTypeId).toString(); - QString password = parentDevice->paramValue(netPwrCtlDevicePasswordParamTypeId).toString(); 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(device->paramValue(socketDeviceNumberParamTypeId).toString(), action.param(socketPowerActionPowerParamTypeId).value().toBool() == true ? "1" : "0").toUtf8(); @@ -270,47 +324,15 @@ DeviceManager::DeviceError DevicePluginAnel::executeAction(Device *device, const void DevicePluginAnel::refreshStates() { foreach (Device *device, myDevices()) { - if (device->deviceClassId() != netPwrCtlDeviceClassId) { - continue; + if (device->deviceClassId() == netPwrCtlHomeDeviceClassId + || device->deviceClassId() == netPwrCtlProDeviceClassId) { + refreshHomePro(device); + } + if (device->deviceClassId() == netPwrCtlAdvDeviceClassId + || device->deviceClassId() == netPwrCtlHutDeviceClassId) { + refreshAdv(device); } - - QUrl url(QUrl("http://" + device->paramValue(netPwrCtlDeviceIpAddressParamTypeId).toString() + ":" + device->paramValue(netPwrCtlDevicePortParamTypeId).toString() + "/strg.cfg")); -// qCDebug(dcAnelElektronik()) << "Fetching state from:" << url.toString(); - - QNetworkRequest request; - request.setUrl(url); - QString username = device->paramValue(netPwrCtlDeviceUsernameParamTypeId).toString(); - QString password = device->paramValue(netPwrCtlDevicePasswordParamTypeId).toString(); - 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, device, [this, device, reply](){ - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcAnelElektronik()) << "Error fetching state for" << device->name(); - setConnectedState(device, 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 + 1).startsWith("NET-CONTROL")) { - qCWarning(dcAnelElektronik()) << "Bad data from Panel" << device->name() << data; - // This happens sometimes as the panel replies with packets we didn't request... Just ignore it... - return; - } - setConnectedState(device, true); - - foreach (Device *child, myDevices()) { - if (child->parentId() == device->id()) { - int number = child->paramValue(socketDeviceNumberParamTypeId).toInt(); - child->setStateValue(socketPowerStateTypeId, parts.value(startIndex + 20 + number).toInt() == 1); - } - } - }); } - } void DevicePluginAnel::setConnectedState(Device *device, bool connected) @@ -322,3 +344,299 @@ void DevicePluginAnel::setConnectedState(Device *device, bool connected) } } } + +DeviceManager::DeviceSetupStatus DevicePluginAnel::setupHomeProDevice(Device *device) +{ + QString ipAddress = device->paramValue(m_ipAddressParamTypeIdMap.value(device->deviceClassId())).toString(); + int port = device->paramValue(m_portParamTypeIdMap.value(device->deviceClassId())).toInt(); + QString username = device->paramValue(m_userParamTypeIdMap.value(device->deviceClassId())).toString(); + QString password = device->paramValue(m_passParamTypeIdMap.value(device->deviceClassId())).toString(); + + 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, device, [this, device, reply](){ + StateTypeId connectedStateTypeId = m_connectedStateTypeIdMap.value(device->deviceClassId()); + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAnelElektronik()) << "Error fetching state for" << device->name() << reply->error() << reply->errorString(); + device->setStateValue(connectedStateTypeId, false); + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure); + return; + } + device->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(); + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure); + return; + } + + // At this point we're done with gathering information about the panel. Setup defintely succeeded for the gateway device + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess); + + // If we haven't set up childs for this gateway yet, let's do it now + foreach (Device *child, myDevices()) { + if (child->parentId() == device->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); + DeviceDescriptor d(socketDeviceClassId, deviceName, device->name(), device->id()); + d.setParams(ParamList() << Param(socketDeviceNumberParamTypeId, i)); + descriptorList << d; + } + emit autoDevicesAppeared(socketDeviceClassId, descriptorList); + }); + + return DeviceManager::DeviceSetupStatusAsync; +} + +DeviceManager::DeviceSetupStatus DevicePluginAnel::setupAdvDevice(Device *device) +{ + QString ipAddress = device->paramValue(m_ipAddressParamTypeIdMap.value(device->deviceClassId())).toString(); + int port = device->paramValue(m_portParamTypeIdMap.value(device->deviceClassId())).toInt(); + QString username = device->paramValue(m_userParamTypeIdMap.value(device->deviceClassId())).toString(); + QString password = device->paramValue(m_passParamTypeIdMap.value(device->deviceClassId())).toString(); + + 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, device, [this, device, reply](){ + StateTypeId connectedStateTypeId = m_connectedStateTypeIdMap.value(device->deviceClassId()); + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAnelElektronik()) << "Error fetching state for" << device->name() << reply->error() << reply->errorString(); + device->setStateValue(connectedStateTypeId, false); + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure); + return; + } + device->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(); + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure); + return; + } + + // At this point we're done with gathering information about the panel. Setup defintely succeeded for the gateway device + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess); + + // If we haven't set up childs for this gateway yet, let's do it now + foreach (Device *child, myDevices()) { + if (child->parentId() == device->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)); + DeviceDescriptor d(socketDeviceClassId, deviceName, device->name(), device->id()); + d.setParams(ParamList() << Param(socketDeviceNumberParamTypeId, i)); + descriptorList << d; + } + emit autoDevicesAppeared(socketDeviceClassId, descriptorList); + }); + + return DeviceManager::DeviceSetupStatusAsync; +} + +void DevicePluginAnel::refreshHomePro(Device *device) +{ + QString ipAddress = device->paramValue(m_ipAddressParamTypeIdMap.value(device->deviceClassId())).toString(); + int port = device->paramValue(m_portParamTypeIdMap.value(device->deviceClassId())).toInt(); + QString username = device->paramValue(m_userParamTypeIdMap.value(device->deviceClassId())).toString(); + QString password = device->paramValue(m_passParamTypeIdMap.value(device->deviceClassId())).toString(); + + 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, device, [this, device, reply](){ + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAnelElektronik()) << "Error fetching state for" << device->name(); + setConnectedState(device, 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" << device->name() << data; + // This happens sometimes when multiple clients are talking to the panel... Just ignore it... + return; + } + setConnectedState(device, true); + + // The temp sensor seems to have a bit of jitter. Reduce sample rate to avoid spamming the log + quint32 samples = device->property("tempSamples").toUInt(); + if (samples % 15 == 0 && device->deviceClassId() == netPwrCtlProDeviceClassId) { + bool ok; + double tempValue = parts.at(startIndex + 7).toDouble(&ok); + if (ok) { + device->setStateValue(netPwrCtlProTemperatureStateTypeId, tempValue); + } else { + qCWarning(dcAnelElektronik()) << "Error reading temperature value from data:" << parts.at(startIndex + 7); + } + } + device->setProperty("tempSamples", ++samples); + + foreach (Device *child, myDevices()) { + if (child->parentId() == device->id()) { + int number = child->paramValue(socketDeviceNumberParamTypeId).toInt(); + child->setStateValue(socketPowerStateTypeId, parts.value(startIndex + 20 + number).toInt() == 1); + } + } + }); +} + +void DevicePluginAnel::refreshAdv(Device *device) +{ + QString ipAddress = device->paramValue(m_ipAddressParamTypeIdMap.value(device->deviceClassId())).toString(); + int port = device->paramValue(m_portParamTypeIdMap.value(device->deviceClassId())).toInt(); + QString username = device->paramValue(m_userParamTypeIdMap.value(device->deviceClassId())).toString(); + QString password = device->paramValue(m_passParamTypeIdMap.value(device->deviceClassId())).toString(); + + 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, device, [this, device, reply](){ + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAnelElektronik()) << "Error fetching state for" << device->name(); + setConnectedState(device, 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" << device->name() << data << "Length:" << parts.length(); + // This happens sometimes when multiple clients are talking to the panel... Just ignore it... + return; + } + setConnectedState(device, true); + + foreach (Device *child, myDevices()) { + if (child->parentId() == device->id()) { + int number = child->paramValue(socketDeviceNumberParamTypeId).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 = device->property("tempSamples").toUInt(); + if (samples % 15 == 0) { + refreshAdvTemp(device); + } + device->setProperty("tempSamples", ++samples); + + }); +} + +void DevicePluginAnel::refreshAdvTemp(Device *device) +{ + QString ipAddress = device->paramValue(m_ipAddressParamTypeIdMap.value(device->deviceClassId())).toString(); + int port = device->paramValue(m_portParamTypeIdMap.value(device->deviceClassId())).toInt(); + QString username = device->paramValue(m_userParamTypeIdMap.value(device->deviceClassId())).toString(); + QString password = device->paramValue(m_passParamTypeIdMap.value(device->deviceClassId())).toString(); + + 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, device, [this, device, reply](){ + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAnelElektronik()) << "Error fetching temp for" << device->name(); + setConnectedState(device, 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" << device->name() << data << "Length:" << parts.length(); + // This happens sometimes when multiple clients are talking to the panel... Just ignore it... + return; + } + + if (device->deviceClassId() == netPwrCtlAdvDeviceClassId) { + bool ok; + double temp = parts.at(7).toDouble(&ok); + if (ok) { + device->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) { + device->setStateValue(netPwrCtlHutTemperatureStateTypeId, temp); + } else { + qCWarning(dcAnelElektronik()) << "Error fetching temperature value:" << data; + } + double humidity = parts.at(14).toDouble(&ok); + if (ok) { + device->setStateValue(netPwrCtlHutHumidityStateTypeId, humidity); + } else { + qCWarning(dcAnelElektronik()) << "Error fetching humidity value:" << data; + } + int lux = parts.at(15).toInt(&ok); + if (ok) { + device->setStateValue(netPwrCtlHutLightIntensityStateTypeId, lux); + } else { + qCWarning(dcAnelElektronik()) << "Error fetching light intensity value:" << data; + } + } + + }); +} diff --git a/anel/devicepluginanel.h b/anel/devicepluginanel.h index 0a8c9b49..7a3c1917 100644 --- a/anel/devicepluginanel.h +++ b/anel/devicepluginanel.h @@ -53,10 +53,21 @@ private slots: private: void setConnectedState(Device *device, bool connected); + DeviceManager::DeviceSetupStatus setupHomeProDevice(Device *device); + DeviceManager::DeviceSetupStatus setupAdvDevice(Device *device); + + void refreshHomePro(Device *device); + void refreshAdv(Device *device); + void refreshAdvTemp(Device *device); + private: PluginTimer *m_pollTimer = nullptr; QHash m_connectedStateTypeIdMap; + QHash m_ipAddressParamTypeIdMap; + QHash m_portParamTypeIdMap; + QHash m_userParamTypeIdMap; + QHash m_passParamTypeIdMap; }; #endif // DEVICEPLUGINANEL_H diff --git a/anel/devicepluginanel.json b/anel/devicepluginanel.json index daa1701d..1537c38e 100644 --- a/anel/devicepluginanel.json +++ b/anel/devicepluginanel.json @@ -10,8 +10,8 @@ "deviceClasses": [ { "id": "d70433ac-9738-49ca-932f-6d3e20bcc6d4", - "name": "netPwrCtl", - "displayName": "NET-PwrCtl", + "name": "netPwrCtlHome", + "displayName": "NET-PwrCtl HOME", "createMethods": ["user", "discovery"], "interfaces": [ "gateway" ], "paramTypes": [ @@ -53,6 +53,188 @@ } ] }, + { + "id": "1492f911-1c09-42ce-b920-084548a689ea", + "name": "netPwrCtlPro", + "displayName": "NET-PwrCtl PRO", + "createMethods": ["user", "discovery"], + "interfaces": [ "gateway", "temperaturesensor" ], + "paramTypes": [ + { + "id": "b1cf9a4f-9c2a-4ab4-a920-46f0b8a8b988", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "31540acc-949f-454f-9987-982e97ce7d21", + "name": "port", + "displayName": "Web control Port", + "type": "int", + "defaultValue": 80 + }, + { + "id": "f9cae7eb-a534-404f-b041-6e5a6720494e", + "name": "username", + "displayName": "Username", + "type": "QString" + }, + { + "id": "dac97153-074a-481a-8057-1936bfb63b6e", + "name": "password", + "displayName": "Password", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "820c54bd-0d4f-4e13-8160-a8efa77c9db5", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "2973ec1e-9c26-45ad-a97b-dd5eccbf650a", + "name": "temperature", + "displayName": "Temperature", + "displayNameEvent": "Temperature changed", + "type": "double", + "defaultValue": 0, + "unit": "DegreeCelsius" + } + ] + }, + { + "id": "99987919-d32d-4d8f-938c-bcf9683003b6", + "name": "netPwrCtlAdv", + "displayName": "NET-PwrCtl ADV", + "createMethods": ["user", "discovery"], + "interfaces": [ "gateway", "temperaturesensor" ], + "paramTypes": [ + { + "id": "5d98ead0-e445-492c-821c-ae169af648e4", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "1913912f-2579-4e8a-9e23-af1de4a2ef72", + "name": "port", + "displayName": "Web control Port", + "type": "int", + "defaultValue": 80 + }, + { + "id": "0eeaa6f0-7232-4d6e-8637-6e21f58a2018", + "name": "username", + "displayName": "Username", + "type": "QString" + }, + { + "id": "14a8c3bd-27a6-440c-a2ba-139fabc870a1", + "name": "password", + "displayName": "Password", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "d143b775-e004-4119-a317-6c508686d473", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "aed7464a-6c36-4858-adb7-776d97c5498e", + "name": "temperature", + "displayName": "Temperature", + "displayNameEvent": "Temperature changed", + "type": "double", + "defaultValue": 0, + "unit": "DegreeCelsius" + } + ] + }, + { + "id": "bc9a90e0-b320-46f1-8d7b-2d24f40af5ea", + "name": "netPwrCtlHut", + "displayName": "NET-PwrCtl HUT", + "createMethods": ["user", "discovery"], + "interfaces": [ "gateway", "temperaturesensor", "humiditysensor", "lightsensor" ], + "paramTypes": [ + { + "id": "fb34919c-3ca0-47b3-a14a-7986b5ce24e2", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "35010dff-dde9-4acf-a60b-cf92b7edc2a5", + "name": "port", + "displayName": "Web control Port", + "type": "int", + "defaultValue": 80 + }, + { + "id": "3bf3db56-4fe4-4c87-a5cd-7c1f1acb6408", + "name": "username", + "displayName": "Username", + "type": "QString" + }, + { + "id": "d5f315b9-99ff-4e69-95c8-97cb81d1e8d7", + "name": "password", + "displayName": "Password", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "3b30c586-4756-4903-8405-b00bc9d34685", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "7689239c-e6c3-48cc-ae90-bd1cad44b631", + "name": "temperature", + "displayName": "Temperature", + "displayNameEvent": "Temperature changed", + "type": "double", + "defaultValue": 0, + "unit": "DegreeCelsius" + }, + { + "id": "6e38c9f7-cdd7-4909-9312-2047812d1883", + "name": "humidity", + "displayName": "Humidity", + "displayNameEvent": "Humidity changed", + "type": "double", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100, + "unit": "Percentage" + }, + { + "id": "60792bc4-fc67-47f6-8c3f-45717a072d59", + "name": "lightIntensity", + "displayName": "Light intensity", + "displayNameEvent": "Light intensity changed", + "type": "double", + "defaultValue": 0, + "unit": "Lux" + } + ] + }, { "id": "9d8da004-a8a1-457f-a8ee-b86133828a49", "name": "socket",