mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 16:08:39 -05:00
660 lines
28 KiB
C++
660 lines
28 KiB
C++
///////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2022 Jon Beniston, M7RCE <jon@beniston.com> //
|
|
// //
|
|
// 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();
|
|
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);
|
|
}
|
|
}
|
|
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";
|
|
}
|
|
}
|