mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			662 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			662 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // Copyright (C) 2022 Jon Beniston, M7RCE                                        //
 | |
| //                                                                               //
 | |
| // This program is free software; you can redistribute it and/or modify          //
 | |
| // it under the terms of the GNU General Public License as published by          //
 | |
| // the Free Software Foundation as version 3 of the License, or                  //
 | |
| // (at your option) any later version.                                           //
 | |
| //                                                                               //
 | |
| // This program 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 General Public License V3 for more details.                               //
 | |
| //                                                                               //
 | |
| // You should have received a copy of the GNU General Public License             //
 | |
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| 
 | |
| #include <QDebug>
 | |
| #include <QUrl>
 | |
| #include <QUrlQuery>
 | |
| #include <QNetworkReply>
 | |
| #include <QJsonDocument>
 | |
| #include <QJsonObject>
 | |
| #include <QRegularExpression>
 | |
| 
 | |
| #include "util/iot/tplink.h"
 | |
| #include "util/simpleserializer.h"
 | |
| 
 | |
| const QString TPLinkCommon::m_url = "https://wap.tplinkcloud.com";
 | |
| 
 | |
| TPLinkCommon::TPLinkCommon(const QString& username, const QString &password) :
 | |
|     m_loggedIn(false),
 | |
|     m_outstandingRequest(false),
 | |
|     m_username(username),
 | |
|     m_password(password),
 | |
|     m_networkManager(nullptr)
 | |
| {
 | |
| }
 | |
| 
 | |
| void TPLinkCommon::login()
 | |
| {
 | |
|     QUrl url(m_url);
 | |
| 
 | |
|     QNetworkRequest request(url);
 | |
|     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 | |
|     QJsonObject params {
 | |
|         {"appType", "Kasa_Android"},
 | |
|         {"cloudUserName", m_username},
 | |
|         {"cloudPassword", m_password},
 | |
|         {"terminalUUID", "9cc4653e-338f-48e4-b8ca-6ed3f67631e4"}
 | |
|     };
 | |
|     QJsonObject object {
 | |
|         {"method", "login"},
 | |
|         {"params", params}
 | |
|     };
 | |
|     QJsonDocument document;
 | |
|     document.setObject(object);
 | |
| 
 | |
|     m_networkManager->post(request, document.toJson());
 | |
| }
 | |
| 
 | |
| void TPLinkCommon::handleLoginReply(QNetworkReply* reply, QString &errorMessage)
 | |
| {
 | |
|     if (reply)
 | |
|     {
 | |
|         if (!reply->error())
 | |
|         {
 | |
|             QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
 | |
|             if (document.isObject())
 | |
|             {
 | |
|                 //qDebug() << "Received " << document;
 | |
|                 if (!m_loggedIn)
 | |
|                 {
 | |
|                     QJsonObject obj = document.object();
 | |
|                     if (obj.contains(QStringLiteral("error_code")))
 | |
|                     {
 | |
|                         int errorCode = obj.value(QStringLiteral("error_code")).toInt();
 | |
|                         if (!errorCode)
 | |
|                         {
 | |
|                             if (obj.contains(QStringLiteral("result")))
 | |
|                             {
 | |
|                                 QJsonObject result = obj.value(QStringLiteral("result")).toObject();
 | |
|                                 if (result.contains(QStringLiteral("token")))
 | |
|                                 {
 | |
|                                     m_loggedIn = true;
 | |
|                                     m_token = result.value(QStringLiteral("token")).toString();
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     qDebug() << "TPLinkDevice::handleReply: Object doesn't contain a token: " << result;
 | |
|                                 }
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 qDebug() << "TPLinkDevice::handleReply: Object doesn't contain a result object: " << obj;
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             qDebug() << "TPLinkDevice::handleReply: Non-zero error_code while logging in: " << errorCode;
 | |
|                             if (obj.contains(QStringLiteral("msg")))
 | |
|                             {
 | |
|                                 QString msg = obj.value(QStringLiteral("msg")).toString();
 | |
|                                 qDebug() << "TPLinkDevice::handleReply: Error message: " << msg;
 | |
|                                 // Typical msg is "Incorrect email or password"
 | |
|                                 errorMessage = QString("TP-Link: Failed to log in. %1").arg(msg);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 errorMessage = QString("TP-Link: Failed to log in. Error code: %1").arg(errorCode);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         qDebug() << "TPLinkDevice::handleReply: Object doesn't contain an error_code: " << obj;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 qDebug() << "TPLinkDevice::handleReply: Document is not an object: " << document;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             qDebug() << "TPLinkDevice::handleReply: error: " << reply->error();
 | |
|         }
 | |
|         reply->deleteLater();
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         qDebug() << "TPLinkDevice::handleReply: reply is null";
 | |
|     }
 | |
| 
 | |
|     if (!m_loggedIn && errorMessage.isEmpty()) {
 | |
|         errorMessage = "TP-Link: Failed to log in.";
 | |
|     }
 | |
| }
 | |
| 
 | |
| TPLinkDevice::TPLinkDevice(const QString& username, const QString &password, const QString &deviceId, DeviceDiscoverer::DeviceInfo *info) :
 | |
|     Device(info),
 | |
|     TPLinkCommon(username, password),
 | |
|     m_deviceId(deviceId)
 | |
| {
 | |
|     m_networkManager = new QNetworkAccessManager();
 | |
|     QObject::connect(
 | |
|         m_networkManager,
 | |
|         &QNetworkAccessManager::finished,
 | |
|         this,
 | |
|         &TPLinkDevice::handleReply
 | |
|     );
 | |
|     login();
 | |
| }
 | |
| 
 | |
| TPLinkDevice::~TPLinkDevice()
 | |
| {
 | |
|     QObject::disconnect(
 | |
|         m_networkManager,
 | |
|         &QNetworkAccessManager::finished,
 | |
|         this,
 | |
|         &TPLinkDevice::handleReply
 | |
|     );
 | |
|     delete m_networkManager;
 | |
| }
 | |
| 
 | |
| void TPLinkDevice::getState()
 | |
| {
 | |
|     if (!m_loggedIn)
 | |
|     {
 | |
|         m_outstandingRequest = true;
 | |
|         return;
 | |
|     }
 | |
|     QUrl url(m_url);
 | |
| 
 | |
|     QNetworkRequest request(url);
 | |
|     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 | |
|     QJsonObject system;
 | |
|     system.insert("get_sysinfo", QJsonValue());
 | |
|     QJsonObject emeter;
 | |
|     emeter.insert("get_realtime", QJsonValue());
 | |
|     QJsonObject requestData {
 | |
|         {"system", system},
 | |
|         {"emeter", emeter}
 | |
|     };
 | |
|     QJsonObject params {
 | |
|         {"deviceId", m_deviceId},
 | |
|         {"requestData", requestData},
 | |
|         {"token", m_token}
 | |
|     };
 | |
|     QJsonObject object {
 | |
|         {"method", "passthrough"},
 | |
|         {"params", params}
 | |
|     };
 | |
|     QJsonDocument document;
 | |
|     document.setObject(object);
 | |
| 
 | |
|     QNetworkReply *reply = m_networkManager->post(request, document.toJson());
 | |
| 
 | |
|     recordGetRequest(reply);
 | |
| }
 | |
| 
 | |
| void TPLinkDevice::setState(const QString &controlId, bool state)
 | |
| {
 | |
|     if (!m_loggedIn)
 | |
|     {
 | |
|         // Should we queue these and apply after logged in?
 | |
|         qDebug() << "TPLinkDevice::setState: Unable to set state for " << controlId << " to " << state << " as not yet logged in";
 | |
|         return;
 | |
|     }
 | |
|     QUrl url(m_url);
 | |
| 
 | |
|     QNetworkRequest request(url);
 | |
|     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 | |
|     QJsonObject stateObj {
 | |
|         {"state", (int)state}
 | |
|     };
 | |
|     QJsonObject system {
 | |
|         {"set_relay_state", stateObj}
 | |
|     };
 | |
|     QJsonObject requestData {
 | |
|         {"system", system}
 | |
|     };
 | |
|     if (controlId != "switch") {
 | |
|         QJsonArray childIds {
 | |
|             controlId
 | |
|         };
 | |
|         QJsonObject context {
 | |
|             {"child_ids", childIds}
 | |
|         };
 | |
|         requestData.insert("context", QJsonValue(context));
 | |
|     }
 | |
|     QJsonObject params {
 | |
|         {"deviceId", m_deviceId},
 | |
|         {"requestData", requestData},
 | |
|         {"token", m_token}
 | |
|     };
 | |
|     QJsonObject object {
 | |
|         {"method", "passthrough"},
 | |
|         {"params", params}
 | |
|     };
 | |
|     QJsonDocument document;
 | |
|     document.setObject(object);
 | |
| 
 | |
|     m_networkManager->post(request, document.toJson());
 | |
| 
 | |
|     recordSetRequest(controlId);
 | |
| }
 | |
| 
 | |
| void TPLinkDevice::handleReply(QNetworkReply* reply)
 | |
| {
 | |
|     if (!m_loggedIn)
 | |
|     {
 | |
|         QString errorMessage;
 | |
|         TPLinkCommon::handleLoginReply(reply, errorMessage);
 | |
|         if (!errorMessage.isEmpty())
 | |
|         {
 | |
|             emit error(errorMessage);
 | |
|         }
 | |
|         else if (m_outstandingRequest)
 | |
|         {
 | |
|             m_outstandingRequest = true;
 | |
|             getState();
 | |
|         }
 | |
|     }
 | |
|     else if (reply)
 | |
|     {
 | |
|         if (!reply->error())
 | |
|         {
 | |
|             QByteArray data = reply->readAll();
 | |
|             QJsonParseError error;
 | |
|             QJsonDocument document = QJsonDocument::fromJson(data, &error);
 | |
|             if (!document.isNull())
 | |
|             {
 | |
|                 if (document.isObject())
 | |
|                 {
 | |
|                     //qDebug() << "Received " << document;
 | |
|                     QJsonObject obj = document.object();
 | |
|                     if (obj.contains(QStringLiteral("result")))
 | |
|                     {
 | |
|                         QJsonObject resultObj = obj.value(QStringLiteral("result")).toObject();
 | |
|                         QHash<QString, QVariant> status;
 | |
| 
 | |
|                         if (resultObj.contains(QStringLiteral("responseData")))
 | |
|                         {
 | |
|                             QJsonObject responseDataObj = resultObj.value(QStringLiteral("responseData")).toObject();
 | |
|                             if (responseDataObj.contains(QStringLiteral("system")))
 | |
|                             {
 | |
|                                 QJsonObject systemObj = responseDataObj.value(QStringLiteral("system")).toObject();
 | |
|                                 if (systemObj.contains(QStringLiteral("get_sysinfo")))
 | |
|                                 {
 | |
|                                     QJsonObject sysInfoObj = systemObj.value(QStringLiteral("get_sysinfo")).toObject();
 | |
|                                     if (sysInfoObj.contains(QStringLiteral("child_num")))
 | |
|                                     {
 | |
|                                         QJsonArray children = sysInfoObj.value(QStringLiteral("children")).toArray();
 | |
|                                         for (auto childRef : children)
 | |
|                                         {
 | |
|                                             QJsonObject childObj = childRef.toObject();
 | |
|                                             if (childObj.contains(QStringLiteral("state")) && childObj.contains(QStringLiteral("id")))
 | |
|                                             {
 | |
|                                                 QString id = childObj.value(QStringLiteral("id")).toString();
 | |
|                                                 if (getAfterSet(reply, id))
 | |
|                                                 {
 | |
|                                                     int state = childObj.value(QStringLiteral("state")).toInt();
 | |
|                                                     status.insert(id, state); // key should match id in discoverer
 | |
|                                                 }
 | |
|                                             }
 | |
|                                         }
 | |
|                                     }
 | |
|                                     else if (sysInfoObj.contains(QStringLiteral("relay_state")))
 | |
|                                     {
 | |
|                                         if (getAfterSet(reply, "switch"))
 | |
|                                         {
 | |
|                                             int state = sysInfoObj.value(QStringLiteral("relay_state")).toInt();
 | |
|                                             status.insert("switch", state); // key should match id in discoverer
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                             // KP115 has emeter, but KP105 doesn't
 | |
|                             if (responseDataObj.contains(QStringLiteral("emeter")))
 | |
|                             {
 | |
|                                 QJsonObject emeterObj = responseDataObj.value(QStringLiteral("emeter")).toObject();
 | |
|                                 if (emeterObj.contains(QStringLiteral("get_realtime")))
 | |
|                                 {
 | |
|                                     QJsonObject realtimeObj = emeterObj.value(QStringLiteral("get_realtime")).toObject();
 | |
|                                     if (realtimeObj.contains(QStringLiteral("current_ma")))
 | |
|                                     {
 | |
|                                         double current = realtimeObj.value(QStringLiteral("current_ma")).toDouble();
 | |
|                                         status.insert("current", current / 1000.0);
 | |
|                                     }
 | |
|                                     if (realtimeObj.contains(QStringLiteral("voltage_mv")))
 | |
|                                     {
 | |
|                                         double voltage = realtimeObj.value(QStringLiteral("voltage_mv")).toDouble();
 | |
|                                         status.insert("voltage", voltage / 1000.0);
 | |
|                                     }
 | |
|                                     if (realtimeObj.contains(QStringLiteral("power_mw")))
 | |
|                                     {
 | |
|                                         double power = realtimeObj.value(QStringLiteral("power_mw")).toDouble();
 | |
|                                         status.insert("power", power / 1000.0);
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         emit deviceUpdated(status);
 | |
|                     }
 | |
|                     else if (obj.contains(QStringLiteral("error_code")))
 | |
|                     {
 | |
|                         // If a device isn't available, we can get:
 | |
|                         //    {"error_code":-20002,"msg":"Request timeout"}
 | |
|                         //    {"error_code":-20571,"msg":"Device is offline"}
 | |
|                         int errorCode = obj.value(QStringLiteral("error_code")).toInt();
 | |
|                         QString msg = obj.value(QStringLiteral("msg")).toString();
 | |
|                         qDebug() << "TPLinkDevice::handleReply: Error code: " << errorCode << " " << msg;
 | |
| 
 | |
|                         emit deviceUnavailable();
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         qDebug() << "TPLinkDevice::handleReply: Object doesn't contain a result or error_code: " << obj;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     qDebug() << "TPLinkDevice::handleReply: Document is not an object: " << document;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 qDebug() << "TPLinkDevice::handleReply: Error parsing JSON: " << error.errorString() << " at offset " << error.offset;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             qDebug() << "TPLinkDevice::handleReply: error: " << reply->error();
 | |
|         }
 | |
|         removeGetRequest(reply);
 | |
|         reply->deleteLater();
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         qDebug() << "TPLinkDevice::handleReply: reply is null";
 | |
|     }
 | |
| }
 | |
| 
 | |
| TPLinkDeviceDiscoverer::TPLinkDeviceDiscoverer(const QString& username, const QString &password) :
 | |
|     TPLinkCommon(username, password)
 | |
| {
 | |
|     m_networkManager = new QNetworkAccessManager();
 | |
|     QObject::connect(
 | |
|         m_networkManager,
 | |
|         &QNetworkAccessManager::finished,
 | |
|         this,
 | |
|         &TPLinkDeviceDiscoverer::handleReply
 | |
|     );
 | |
|     login();
 | |
| }
 | |
| 
 | |
| TPLinkDeviceDiscoverer::~TPLinkDeviceDiscoverer()
 | |
| {
 | |
|     QObject::disconnect(
 | |
|         m_networkManager,
 | |
|         &QNetworkAccessManager::finished,
 | |
|         this,
 | |
|         &TPLinkDeviceDiscoverer::handleReply
 | |
|     );
 | |
|     delete m_networkManager;
 | |
| }
 | |
| 
 | |
| void TPLinkDeviceDiscoverer::getDevices()
 | |
| {
 | |
|     if (!m_loggedIn)
 | |
|     {
 | |
|         m_outstandingRequest = true;
 | |
|         return;
 | |
|     }
 | |
|     QUrl url(m_url);
 | |
| 
 | |
|     QNetworkRequest request(url);
 | |
|     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 | |
|     QJsonObject params {
 | |
|         {"token", m_token}
 | |
|     };
 | |
|     QJsonObject object {
 | |
|         {"method", "getDeviceList"},
 | |
|         {"params", params}
 | |
|     };
 | |
|     QJsonDocument document;
 | |
|     document.setObject(object);
 | |
| 
 | |
|     m_networkManager->post(request, document.toJson());
 | |
| }
 | |
| 
 | |
| void TPLinkDeviceDiscoverer::getState(const QString &deviceId)
 | |
| {
 | |
|     QUrl url(m_url);
 | |
| 
 | |
|     QNetworkRequest request(url);
 | |
|     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 | |
|     QJsonObject system;
 | |
|     system.insert("get_sysinfo", QJsonValue());
 | |
|     QJsonObject emeter;
 | |
|     emeter.insert("get_realtime", QJsonValue());
 | |
|     QJsonObject requestData {
 | |
|         {"system", system},
 | |
|         {"emeter", emeter}
 | |
|     };
 | |
|     QJsonObject params {
 | |
|         {"deviceId", deviceId},
 | |
|         {"requestData", requestData},
 | |
|         {"token", m_token}
 | |
|     };
 | |
|     QJsonObject object {
 | |
|         {"method", "passthrough"},
 | |
|         {"params", params}
 | |
|     };
 | |
|     QJsonDocument document;
 | |
|     document.setObject(object);
 | |
| 
 | |
|     m_getStateReplies.insert(m_networkManager->post(request, document.toJson()), deviceId);
 | |
| }
 | |
| 
 | |
| void TPLinkDeviceDiscoverer::handleReply(QNetworkReply* reply)
 | |
| {
 | |
|     if (!m_loggedIn)
 | |
|     {
 | |
|         QString errorMessage;
 | |
|         TPLinkCommon::handleLoginReply(reply, errorMessage);
 | |
|         if (!errorMessage.isEmpty())
 | |
|         {
 | |
|             emit error(errorMessage);
 | |
|         }
 | |
|         else if (m_outstandingRequest)
 | |
|         {
 | |
|             m_outstandingRequest = false;
 | |
|             getDevices();
 | |
|         }
 | |
|     }
 | |
|     else if (reply)
 | |
|     {
 | |
|         if (!reply->error())
 | |
|         {
 | |
|             QByteArray data = reply->readAll();
 | |
|             QJsonParseError error;
 | |
|             QJsonDocument document = QJsonDocument::fromJson(data, &error);
 | |
|             if (!document.isNull())
 | |
|             {
 | |
|                 if (document.isObject())
 | |
|                 {
 | |
|                     //qDebug() << "Received " << document;
 | |
|                     QJsonObject obj = document.object();
 | |
| 
 | |
|                     if (m_getStateReplies.contains(reply))
 | |
|                     {
 | |
|                         // Reply for getState
 | |
|                         m_getStateReplies.remove(reply);
 | |
|                         QJsonObject resultObj = obj.value(QStringLiteral("result")).toObject();
 | |
|                         if (resultObj.contains(QStringLiteral("responseData")))
 | |
|                         {
 | |
|                             QJsonObject responseDataObj = resultObj.value(QStringLiteral("responseData")).toObject();
 | |
|                             if (responseDataObj.contains(QStringLiteral("system")))
 | |
|                             {
 | |
|                                 DeviceInfo info;
 | |
|                                 QJsonObject systemObj = responseDataObj.value(QStringLiteral("system")).toObject();
 | |
|                                 if (systemObj.contains(QStringLiteral("get_sysinfo")))
 | |
|                                 {
 | |
|                                     QJsonObject sysInfoObj = systemObj.value(QStringLiteral("get_sysinfo")).toObject();
 | |
|                                     if (sysInfoObj.contains(QStringLiteral("alias"))) {
 | |
|                                         info.m_name = sysInfoObj.value(QStringLiteral("alias")).toString();
 | |
|                                     }
 | |
|                                     if (sysInfoObj.contains(QStringLiteral("model"))) {
 | |
|                                         info.m_model = sysInfoObj.value(QStringLiteral("model")).toString();
 | |
|                                     }
 | |
|                                     if (sysInfoObj.contains(QStringLiteral("deviceId"))) {
 | |
|                                         info.m_id = sysInfoObj.value(QStringLiteral("deviceId")).toString();
 | |
|                                     }
 | |
|                                     if (sysInfoObj.contains(QStringLiteral("child_num")))
 | |
|                                     {
 | |
|                                         QJsonArray children = sysInfoObj.value(QStringLiteral("children")).toArray();
 | |
|                                         int child = 1;
 | |
|                                         for (auto childRef : children)
 | |
|                                         {
 | |
|                                             QJsonObject childObj = childRef.toObject();
 | |
|                                             ControlInfo *controlInfo = new ControlInfo();
 | |
|                                             controlInfo->m_id = childObj.value(QStringLiteral("id")).toString();
 | |
|                                             if (childObj.contains(QStringLiteral("alias"))) {
 | |
|                                                 controlInfo->m_name = childObj.value(QStringLiteral("alias")).toString();
 | |
|                                             }
 | |
|                                             controlInfo->m_type = DeviceDiscoverer::BOOL;
 | |
|                                             info.m_controls.append(controlInfo);
 | |
|                                             child++;
 | |
|                                         }
 | |
|                                     }
 | |
|                                     else if (sysInfoObj.contains(QStringLiteral("relay_state")))
 | |
|                                     {
 | |
|                                         ControlInfo *controlInfo = new ControlInfo();
 | |
|                                         controlInfo->m_id = "switch";
 | |
|                                         if (sysInfoObj.contains(QStringLiteral("alias"))) {
 | |
|                                             controlInfo->m_name = sysInfoObj.value(QStringLiteral("alias")).toString();
 | |
|                                         }
 | |
|                                         controlInfo->m_type = DeviceDiscoverer::BOOL;
 | |
|                                         info.m_controls.append(controlInfo);
 | |
|                                     }
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     qDebug() << "TPLinkDeviceDiscoverer::handleReply: get_sysinfo missing";
 | |
|                                 }
 | |
|                                 // KP115 has energy meter, but KP105 doesn't. KP105 will have emeter object, but without get_realtime sub-object
 | |
|                                 if (responseDataObj.contains(QStringLiteral("emeter")))
 | |
|                                 {
 | |
|                                     QJsonObject emeterObj = responseDataObj.value(QStringLiteral("emeter")).toObject();
 | |
|                                     if (emeterObj.contains(QStringLiteral("get_realtime")))
 | |
|                                     {
 | |
|                                         QJsonObject realtimeObj = emeterObj.value(QStringLiteral("get_realtime")).toObject();
 | |
|                                         if (realtimeObj.contains(QStringLiteral("current_ma")))
 | |
|                                         {
 | |
|                                             SensorInfo *currentSensorInfo = new SensorInfo();
 | |
|                                             currentSensorInfo->m_name = "Current";
 | |
|                                             currentSensorInfo->m_id = "current";
 | |
|                                             currentSensorInfo->m_type = DeviceDiscoverer::FLOAT;
 | |
|                                             currentSensorInfo->m_units = "A";
 | |
|                                             info.m_sensors.append(currentSensorInfo);
 | |
|                                         }
 | |
|                                         if (realtimeObj.contains(QStringLiteral("voltage_mv")))
 | |
|                                         {
 | |
|                                             SensorInfo *voltageSensorInfo = new SensorInfo();
 | |
|                                             voltageSensorInfo->m_name = "Voltage";
 | |
|                                             voltageSensorInfo->m_id = "voltage";
 | |
|                                             voltageSensorInfo->m_type = DeviceDiscoverer::FLOAT;
 | |
|                                             voltageSensorInfo->m_units = "V";
 | |
|                                             info.m_sensors.append(voltageSensorInfo);
 | |
|                                         }
 | |
|                                         if (realtimeObj.contains(QStringLiteral("power_mw")))
 | |
|                                         {
 | |
|                                             SensorInfo *powerSensorInfo = new SensorInfo();
 | |
|                                             powerSensorInfo->m_name = "Power";
 | |
|                                             powerSensorInfo->m_id = "power";
 | |
|                                             powerSensorInfo->m_type = DeviceDiscoverer::FLOAT;
 | |
|                                             powerSensorInfo->m_units = "W";
 | |
|                                             info.m_sensors.append(powerSensorInfo);
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                                 if (info.m_controls.size() > 0) {
 | |
|                                     m_devices.append(info);
 | |
|                                 } else {
 | |
|                                     qDebug() << "TPLinkDeviceDiscoverer::handleReply: No controls in info";
 | |
|                                 }
 | |
| 
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             qDebug() << "TPLinkDeviceDiscoverer::handleReply: No responseData";
 | |
|                         }
 | |
| 
 | |
|                         if (m_getStateReplies.size() == 0)
 | |
|                         {
 | |
|                             emit deviceList(m_devices);
 | |
|                             m_devices.clear();
 | |
|                         }
 | |
| 
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         // Reply for getDevice
 | |
|                         if (obj.contains(QStringLiteral("result")))
 | |
|                         {
 | |
|                             QJsonObject resultObj = obj.value(QStringLiteral("result")).toObject();
 | |
|                             if (resultObj.contains(QStringLiteral("deviceList")))
 | |
|                             {
 | |
|                                 QJsonArray deviceArray = resultObj.value(QStringLiteral("deviceList")).toArray();
 | |
|                                 for (auto deviceRef : deviceArray)
 | |
|                                 {
 | |
|                                     QJsonObject deviceObj = deviceRef.toObject();
 | |
|                                     if (deviceObj.contains(QStringLiteral("deviceId")) && deviceObj.contains(QStringLiteral("deviceType")))
 | |
|                                     {
 | |
|                                         // In order to discover what controls and sensors a device has, we need to get sysinfo
 | |
|                                         getState(deviceObj.value(QStringLiteral("deviceId")).toString());
 | |
|                                     }
 | |
|                                     else
 | |
|                                     {
 | |
|                                         qDebug() << "TPLinkDeviceDiscoverer::handleReply: deviceList element doesn't contain a deviceId: " << deviceObj;
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 qDebug() << "TPLinkDeviceDiscoverer::handleReply: result doesn't contain a deviceList: " << resultObj;
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             qDebug() << "TPLinkDeviceDiscoverer::handleReply: Object doesn't contain a result: " << obj;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     qDebug() << "TPLinkDeviceDiscoverer::handleReply: Document is not an object: " << document;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 qDebug() << "TPLinkDeviceDiscoverer::handleReply: Error parsing JSON: " << error.errorString() << " at offset " << error.offset;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             qDebug() << "TPLinkDeviceDiscoverer::handleReply: error: " << reply->error();
 | |
|         }
 | |
|         reply->deleteLater();
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         qDebug() << "TPLinkDeviceDiscoverer::handleReply: reply is null";
 | |
|     }
 | |
| }
 |