mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-07-20 01:02:46 +02:00
added custom ssdp discovery
This commit is contained in:
parent
e335524421
commit
6d956ce808
@ -25,11 +25,11 @@
|
||||
#include "devices/device.h"
|
||||
#include "types/param.h"
|
||||
#include "plugininfo.h"
|
||||
#include "network/upnp/upnpdiscovery.h"
|
||||
#include "network/upnp/upnpdiscoveryreply.h"
|
||||
#include "ssdp.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QColor>
|
||||
#include <QRgb>
|
||||
|
||||
DevicePluginYeelight::DevicePluginYeelight()
|
||||
{
|
||||
@ -44,70 +44,157 @@ void DevicePluginYeelight::discoverDevices(DeviceDiscoveryInfo *info)
|
||||
m_discoveries.insert(info, discovery);
|
||||
|
||||
qCDebug(dcYeelight()) << "Starting UPnP discovery...";
|
||||
UpnpDiscoveryReply *upnpReply = hardwareManager()->upnpDiscovery()->discoverDevices("wifi_bulb");
|
||||
discovery->upnpReply = upnpReply;
|
||||
// Always clean up the upnp discovery
|
||||
connect(upnpReply, &UpnpDiscoveryReply::finished, upnpReply, &UpnpDiscoveryReply::deleteLater);
|
||||
Ssdp *ssdp = new Ssdp(this);
|
||||
ssdp->enable();
|
||||
ssdp->discover();
|
||||
connect(ssdp, &Ssdp::discovered, this,[info, this](const QString &address, int port, int id, const QString &model) {
|
||||
|
||||
// Process results if info is still around
|
||||
connect(upnpReply, &UpnpDiscoveryReply::finished, info, [this, upnpReply, discovery](){
|
||||
|
||||
// Indicate we're done...
|
||||
discovery->upnpReply = nullptr;
|
||||
|
||||
if (upnpReply->error() != UpnpDiscoveryReply::UpnpDiscoveryReplyErrorNoError) {
|
||||
qCWarning(dcYeelight()) << "Upnp discovery error" << upnpReply->error();
|
||||
}
|
||||
|
||||
foreach (const UpnpDeviceDescriptor &upnpDevice, upnpReply->deviceDescriptors()) {
|
||||
if (upnpDevice.modelDescription().contains("color")) {
|
||||
DeviceDescriptor descriptor(bridgeDeviceClassId, "Yeelight Color Bulb", upnpDevice.hostAddress().toString());
|
||||
ParamList params;
|
||||
QString bridgeId = upnpDevice.serialNumber().toLower();
|
||||
foreach (Device *existingDevice, myDevices()) {
|
||||
if (existingDevice->paramValue(bridgeDeviceIdParamTypeId).toString() == bridgeId) {
|
||||
descriptor.setDeviceId(existingDevice->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
params.append(Param(bridgeDeviceHostParamTypeId, upnpDevice.hostAddress().toString()));
|
||||
params.append(Param(bridgeDeviceIdParamTypeId, bridgeId));
|
||||
descriptor.setParams(params);
|
||||
qCDebug(dcYeelight()) << "UPnP: Found Hue bridge:" << bridgeId;
|
||||
discovery->results.append(descriptor);
|
||||
DeviceDescriptor descriptor(colorBulbDeviceClassId, "Yeelight"+ model + "Bulb", address);
|
||||
ParamList params;
|
||||
foreach (Device *existingDevice, myDevices()) {
|
||||
if (existingDevice->paramValue(colorBulbDeviceIdParamTypeId).toString() == id) {
|
||||
descriptor.setDeviceId(existingDevice->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
//finishDiscovery(discovery);
|
||||
params.append(Param(colorBulbDeviceHostParamTypeId, address));
|
||||
params.append(Param(colorBulbDeviceIdParamTypeId, id));
|
||||
params.append(Param(colorBulbDevicePortParamTypeId, port));
|
||||
descriptor.setParams(params);
|
||||
qCDebug(dcYeelight()) << "UPnP: Found Yeelight device:" << id;
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
});
|
||||
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::setupDevice(DeviceSetupInfo *info)
|
||||
{
|
||||
Device *device = info->device();
|
||||
|
||||
if (device->deviceClassId() == colorBulbDeviceClassId) {
|
||||
QHostAddress *address = device->paramValue(colorBulbDeviceAddressParamTypeId).toString();
|
||||
int port;
|
||||
Yeelight *yeelight = new Yeelight(hardwareManager(), address, port, this);
|
||||
QHostAddress address = QHostAddress(device->paramValue(colorBulbDeviceHostParamTypeId).toString());
|
||||
quint16 port = device->paramValue(colorBulbDevicePortParamTypeId).toUInt();
|
||||
Yeelight *yeelight = new Yeelight(hardwareManager()->networkManager(), address, port, this);
|
||||
m_yeelightConnections.insert(device->id(), yeelight);
|
||||
connect(yeelight, &Yeelight::connectionChanged, this, &DevicePluginYeelight::onConnectionChanged);
|
||||
connect(yeelight, &Yeelight::requestExecuted, this, &DevicePluginYeelight::onRequestExecuted);
|
||||
connect(yeelight, &Yeelight::propertyListReceived, this, &DevicePluginYeelight::onPropertyListReceived);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::postSetupDevice(Device *device)
|
||||
{
|
||||
connect(device, &Device::nameChanged, this, &DevicePluginYeelight::onDeviceNameChanged);
|
||||
|
||||
if (device->deviceClassId() == colorBulbDeviceClassId) {
|
||||
}
|
||||
|
||||
if (!m_pluginTimer) {
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() {
|
||||
foreach (Yeelight *yeelight, m_yeelightConnections.values()) {
|
||||
if (yeelight->isConnected()) {
|
||||
QList<Yeelight::Property> properties;
|
||||
properties << Yeelight::Property::Name;
|
||||
properties << Yeelight::Property::Ct;
|
||||
properties << Yeelight::Property::Rgb;
|
||||
properties << Yeelight::Property::Power;
|
||||
properties << Yeelight::Property::Bright;
|
||||
properties << Yeelight::Property::ColorMode;
|
||||
yeelight->getParam(properties);
|
||||
} else {
|
||||
yeelight->connectDevice();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::executeAction(DeviceActionInfo *info)
|
||||
{
|
||||
Device *device = info->device();
|
||||
Action action = info->action();
|
||||
|
||||
if (device->deviceClassId() == colorBulbDeviceClassId) {
|
||||
Yeelight *yeelight = m_yeelightConnections.value(device->id());
|
||||
|
||||
// if (action.actionTypeId() == ) {
|
||||
//}
|
||||
if (action.actionTypeId() == colorBulbPowerActionTypeId) {
|
||||
bool power = action.param(colorBulbPowerActionPowerParamTypeId).value().toBool();
|
||||
yeelight->setPower(power);
|
||||
} else if (action.actionTypeId() == colorBulbBrightnessActionTypeId) {
|
||||
int brightness = action.param(colorBulbBrightnessActionBrightnessParamTypeId).value().toInt();
|
||||
yeelight->setBrightness(brightness);
|
||||
} else if (action.actionTypeId() == colorBulbColorActionColorParamTypeId) {
|
||||
QRgb color = action.param(colorBulbColorActionColorParamTypeId).value().toUInt();
|
||||
yeelight->setRgb(color);
|
||||
} else if (action.actionTypeId() == colorBulbColorTemperatureActionTypeId) {
|
||||
int colorTemperature = action.param(colorBulbColorTemperatureActionColorTemperatureParamTypeId).value().toUInt() * 11.12;
|
||||
yeelight->setColorTemperature(colorTemperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::deviceRemoved(Device *device)
|
||||
{
|
||||
|
||||
if (device->deviceClassId() == colorBulbDeviceClassId){
|
||||
Yeelight *yeelight = m_yeelightConnections.take(device->id());
|
||||
yeelight->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::onDeviceNameChanged()
|
||||
{
|
||||
Device *device = static_cast<Device*>(sender());
|
||||
Yeelight *yeelight = m_yeelightConnections.value(device->id());
|
||||
yeelight->setName(device->name());
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::onConnectionChanged(bool connected)
|
||||
{
|
||||
Yeelight *yeelight = static_cast<Yeelight *>(sender());
|
||||
Device * device = myDevices().findById(m_yeelightConnections.key(yeelight));
|
||||
if(!device)
|
||||
return;
|
||||
|
||||
device->setStateValue(colorBulbConnectedStateTypeId, connected);
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::onRequestExecuted(int requestId, bool success)
|
||||
{
|
||||
if (m_asyncActions.contains(requestId)) {
|
||||
DeviceActionInfo *info = m_asyncActions.take(requestId);
|
||||
if (success) {
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
} else {
|
||||
info->finish(Device::DeviceErrorHardwareFailure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginYeelight::onPropertyListReceived(QVariantList value)
|
||||
{
|
||||
Yeelight *yeelight = static_cast<Yeelight *>(sender());
|
||||
Device * device = myDevices().findById(m_yeelightConnections.key(yeelight));
|
||||
if(!device)
|
||||
return;
|
||||
|
||||
/*
|
||||
* properties << Yeelight::Property::Name;
|
||||
* properties << Yeelight::Property::Ct;
|
||||
* properties << Yeelight::Property::Rgb;
|
||||
* properties << Yeelight::Property::Power;
|
||||
* properties << Yeelight::Property::Bright;
|
||||
* properties << Yeelight::Property::ColorMode;
|
||||
*/
|
||||
|
||||
if(value.length() < 6)
|
||||
return;
|
||||
|
||||
device->setName(value[0].toString());
|
||||
device->setStateValue(colorBulbColorTemperatureStateTypeId, value[1].toInt());
|
||||
device->setStateValue(colorBulbColorStateTypeId, value[2].toString());
|
||||
device->setStateValue(colorBulbPowerStateTypeId, (value[3].toString() == "on"));
|
||||
device->setStateValue(colorBulbBrightnessStateTypeId, value[4].toInt());
|
||||
device->setStateValue(colorBulbColorModeStateTypeId, value[5].toString());
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ public:
|
||||
|
||||
void discoverDevices(DeviceDiscoveryInfo *info) override;
|
||||
void setupDevice(DeviceSetupInfo *info) override;
|
||||
void postSetupDevice(Device *device) override;
|
||||
void executeAction(DeviceActionInfo *info) override;
|
||||
void deviceRemoved(Device *device) override;
|
||||
|
||||
@ -55,15 +56,16 @@ private:
|
||||
};
|
||||
QHash<DeviceDiscoveryInfo*, DiscoveryJob*> m_discoveries;
|
||||
QList<QString> m_usedInterfaces;
|
||||
QTimer *m_reconnectTimer = nullptr;
|
||||
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
QHash<int, DeviceActionInfo *> m_asyncActions;
|
||||
QHash<DeviceId, Yeelight *> m_yeelightConnections;
|
||||
|
||||
private slots:
|
||||
void onReadyRead();
|
||||
void onReconnectTimer();
|
||||
|
||||
signals:
|
||||
|
||||
void onDeviceNameChanged();
|
||||
void onConnectionChanged(bool connected);
|
||||
void onRequestExecuted(int requestId, bool success);
|
||||
void onPropertyListReceived(QVariantList value);
|
||||
};
|
||||
|
||||
#endif // DEVICEPLUGINYEELIGHT_H
|
||||
|
||||
@ -23,6 +23,13 @@
|
||||
"inputType": "IPv4Address",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "99790910-ce6c-4b14-bb1f-f56133522dce",
|
||||
"name": "port",
|
||||
"displayName": "Port",
|
||||
"type" : "int",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "bfe184d2-6e62-4979-8ff2-3fd190903c82",
|
||||
"name": "id",
|
||||
@ -35,8 +42,7 @@
|
||||
{
|
||||
"id": "e80aea31-7ac0-4f71-9650-efb70ea1e768",
|
||||
"name": "default",
|
||||
"displayName": "Set default",
|
||||
"type": "bool"
|
||||
"displayName": "Set default"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
@ -93,6 +99,16 @@
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "6babaf04-0247-447c-b429-d39f3d330f45",
|
||||
"name": "colorMode",
|
||||
"displayName": "Color mode",
|
||||
"displayNameEvent": "Color mode changed",
|
||||
"displayNameAction": "Set color mode",
|
||||
"type": "QString",
|
||||
"defaultValue": "-",
|
||||
"writable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
130
yeelight/ssdp.cpp
Normal file
130
yeelight/ssdp.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
#include "ssdp.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QNetworkInterface>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkConfigurationManager>
|
||||
|
||||
Ssdp::Ssdp(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Ssdp::~Ssdp()
|
||||
{
|
||||
if (m_socket) {
|
||||
m_socket->waitForBytesWritten(1000);
|
||||
m_socket->close();
|
||||
}
|
||||
}
|
||||
|
||||
bool Ssdp::enable()
|
||||
{
|
||||
// Clean up
|
||||
if (m_socket) {
|
||||
delete m_socket;
|
||||
m_socket = nullptr;
|
||||
}
|
||||
|
||||
// Bind udp socket and join multicast group
|
||||
m_socket = new QUdpSocket(this);
|
||||
m_port = 1982;
|
||||
m_host = QHostAddress("239.255.255.250");
|
||||
|
||||
m_socket->setSocketOption(QAbstractSocket::MulticastTtlOption,QVariant(1));
|
||||
m_socket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,QVariant(1));
|
||||
|
||||
if(!m_socket->bind(QHostAddress::AnyIPv4, m_port, QUdpSocket::ShareAddress)){
|
||||
qCWarning(dcYeelight()) << "could not bind to port" << m_port;
|
||||
m_available = false;
|
||||
delete m_socket;
|
||||
m_socket = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_socket->joinMulticastGroup(m_host)){
|
||||
qCWarning(dcYeelight()) << "could not join multicast group" << m_host;
|
||||
m_available = false;
|
||||
delete m_socket;
|
||||
m_socket = nullptr;
|
||||
return false;
|
||||
}
|
||||
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||
connect(m_socket, &QUdpSocket::readyRead, this, &Ssdp::readData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Ssdp::discover()
|
||||
{
|
||||
QByteArray searchMessage = QByteArray("M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: 239.255.255.250:1982\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"ST: wifi_bulb\r\n\r\n");
|
||||
m_socket->writeDatagram(searchMessage, m_host, m_port);
|
||||
}
|
||||
|
||||
|
||||
void Ssdp::error(QAbstractSocket::SocketError error)
|
||||
{
|
||||
qCWarning(dcYeelight()) << "socket error:" << error << m_socket->errorString();
|
||||
}
|
||||
|
||||
void Ssdp::readData()
|
||||
{
|
||||
QByteArray data;
|
||||
quint16 port;
|
||||
QHostAddress hostAddress;
|
||||
QUrl location;
|
||||
int id;
|
||||
QString model;
|
||||
|
||||
// read the answere from the multicast
|
||||
while (m_socket->hasPendingDatagrams()) {
|
||||
data.resize(m_socket->pendingDatagramSize());
|
||||
m_socket->readDatagram(data.data(), data.size(), &hostAddress, &port);
|
||||
}
|
||||
qCDebug(dcYeelight())<< "SSDP message received " << data;
|
||||
|
||||
if (data.contains("NOTIFY") && !QNetworkInterface::allAddresses().contains(hostAddress)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the data contains the HTTP OK header...
|
||||
if (data.contains("HTTP/1.1 200 OK")) {
|
||||
const QStringList lines = QString(data).split("\r\n");
|
||||
foreach (const QString& line, lines) {
|
||||
int separatorIndex = line.indexOf(':');
|
||||
QString key = line.left(separatorIndex).toUpper();
|
||||
QString value = line.mid(separatorIndex+1).trimmed();
|
||||
|
||||
if (key.contains("Location")) {
|
||||
location = QUrl(value);
|
||||
} else if (key.contains("id")) {
|
||||
id = value.toUInt();
|
||||
} else if (key.contains("model")) {
|
||||
|
||||
}
|
||||
}
|
||||
emit discovered(location.host(), location.port(), id, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Ssdp::disable()
|
||||
{
|
||||
if (!m_socket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_socket->waitForBytesWritten();
|
||||
m_socket->close();
|
||||
delete m_socket;
|
||||
m_socket = nullptr;
|
||||
|
||||
m_notificationTimer->stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
47
yeelight/ssdp.h
Normal file
47
yeelight/ssdp.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef SSDP_H
|
||||
#define SSDP_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QUdpSocket>
|
||||
#include <QUrl>
|
||||
#include <QTimer>
|
||||
#include <QUdpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class Ssdp : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Ssdp(QObject *parent = nullptr);
|
||||
~Ssdp();
|
||||
bool enable();
|
||||
void discover();
|
||||
bool disable();
|
||||
private:
|
||||
QUdpSocket *m_socket = nullptr;
|
||||
QHostAddress m_host;
|
||||
quint16 m_port;
|
||||
|
||||
QTimer *m_notificationTimer = nullptr;
|
||||
|
||||
QNetworkAccessManager *m_networkAccessManager = nullptr;
|
||||
|
||||
//QList<UpnpDiscoveryRequest *> m_discoverRequests;
|
||||
// QHash<QNetworkReply*, UpnpDeviceDescriptor> m_informationRequestList;
|
||||
|
||||
bool m_available = false;
|
||||
bool m_enabled = false;
|
||||
|
||||
signals:
|
||||
void discovered(const QString &address, int port, int id, const QString &model);
|
||||
|
||||
private slots:
|
||||
void error(QAbstractSocket::SocketError error);
|
||||
void readData();
|
||||
};
|
||||
|
||||
#endif // SSDP_H
|
||||
@ -28,6 +28,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <QColor>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
Yeelight::Yeelight(NetworkAccessManager *networkManager, const QHostAddress &address, quint16 port, QObject *parent) :
|
||||
@ -38,14 +39,20 @@ Yeelight::Yeelight(NetworkAccessManager *networkManager, const QHostAddress &add
|
||||
{
|
||||
m_socket = new QTcpSocket(this);
|
||||
connect(m_socket, &QTcpSocket::stateChanged, this, &Yeelight::onStateChanged);
|
||||
connect(m_socket, &QTcpSocket::readyRead, this, &Yeelight::onReadyRead);
|
||||
m_socket->connectToHost(address, port);
|
||||
}
|
||||
|
||||
bool Yeelight::connected()
|
||||
bool Yeelight::isConnected()
|
||||
{
|
||||
return m_socket->isOpen();
|
||||
}
|
||||
|
||||
void Yeelight::connectDevice()
|
||||
{
|
||||
m_socket->connectToHost(m_address, m_port);
|
||||
}
|
||||
|
||||
|
||||
int Yeelight::getParam(QList<Yeelight::Property> properties)
|
||||
{
|
||||
@ -62,7 +69,7 @@ int Yeelight::getParam(QList<Yeelight::Property> properties)
|
||||
params.append("ct");
|
||||
break;
|
||||
case Property::Power:
|
||||
params.append("powr");
|
||||
params.append("power");
|
||||
break;
|
||||
case Property::Bright:
|
||||
params.append("bright");
|
||||
@ -132,7 +139,8 @@ int Yeelight::getParam(QList<Yeelight::Property> properties)
|
||||
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
m_socket->write(doc.toJson());
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -146,6 +154,9 @@ int Yeelight::setName(const QString &name)
|
||||
QJsonArray params;
|
||||
params.append(name);
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -161,6 +172,9 @@ int Yeelight::setColorTemperature(int mirad, int msFadeTime)
|
||||
params.append("smooth");
|
||||
params.append(msFadeTime);
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -176,6 +190,9 @@ int Yeelight::setRgb(QRgb color, int msFadeTime)
|
||||
params.append("smooth");
|
||||
params.append(msFadeTime);
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -191,6 +208,9 @@ int Yeelight::setBrightness(int percentage, int msFadeTime)
|
||||
params.append("smooth");
|
||||
params.append(msFadeTime);
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -210,6 +230,9 @@ int Yeelight::setPower(bool power, int msFadeTime)
|
||||
params.append("smooth");
|
||||
params.append(msFadeTime);
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -222,6 +245,9 @@ int Yeelight::setDefault()
|
||||
obj["method"] = "set_default";
|
||||
QJsonArray params;
|
||||
obj["params"] = params;
|
||||
doc.setObject(obj);
|
||||
qCDebug(dcYeelight()) << "Sending request" << doc.toJson();
|
||||
m_socket->write(doc.toJson() + "\r\n");
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@ -229,11 +255,68 @@ void Yeelight::onStateChanged(QAbstractSocket::SocketState state)
|
||||
{
|
||||
switch (state) {
|
||||
case QAbstractSocket::SocketState::ConnectedState:
|
||||
|
||||
emit connectionChanged(true);
|
||||
break;
|
||||
default:
|
||||
emit connectionChanged(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Yeelight::onReadyRead()
|
||||
{
|
||||
QByteArray data = m_socket->readAll();
|
||||
qCDebug(dcYeelight()) << "Message received" << data;
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qDebug(dcYeelight()) << "Recieved invalide JSON object";
|
||||
return;
|
||||
}
|
||||
QVariantMap map = doc.toVariant().toMap();
|
||||
if (map.contains("method")) {
|
||||
if (map["method"] == "props") {
|
||||
QVariantMap params = map["params"].toMap();
|
||||
if (params.contains("power")) {
|
||||
emit notificationReveiced(Property::Power, params["power"]);
|
||||
}
|
||||
if (params.contains("bright")) {
|
||||
emit notificationReveiced(Property::Bright, params["bright"]);
|
||||
}
|
||||
if (params.contains("ct")) {
|
||||
emit notificationReveiced(Property::Ct, params["ct"]);
|
||||
}
|
||||
if (params.contains("rgb")) {
|
||||
emit notificationReveiced(Property::Rgb, params["rgb"]);
|
||||
}
|
||||
if (params.contains("hue")) {
|
||||
emit notificationReveiced(Property::Hue, params["hue"]);
|
||||
}
|
||||
if (params.contains("name")) {
|
||||
emit notificationReveiced(Property::Name, params["name"]);
|
||||
}
|
||||
if (params.contains("color_mode")) {
|
||||
emit notificationReveiced(Property::ColorMode, params["color_mode"]);
|
||||
}
|
||||
if (params.contains("sat")) {
|
||||
emit notificationReveiced(Property::Sat, params["sat"]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int id = map["id"].toInt();
|
||||
QVariantList result = map["result"].toList();
|
||||
if ((result.length() == 1)) {
|
||||
if (result.first().toString() == "ok") {
|
||||
emit requestExecuted(id, true);
|
||||
} else {
|
||||
//TODO parse error
|
||||
//emit errorReceived()
|
||||
}
|
||||
} else {
|
||||
emit propertyListReceived(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -37,6 +37,12 @@ class Yeelight : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ColorMode {
|
||||
RGB = 1,
|
||||
Temperature,
|
||||
HSV
|
||||
};
|
||||
|
||||
enum Property {
|
||||
Power, //on: smart LED is turned on / off: smart LED is turned off
|
||||
Bright, //Brightness percentage. Range 1 ~ 100
|
||||
@ -64,7 +70,8 @@ public:
|
||||
};
|
||||
|
||||
explicit Yeelight(NetworkAccessManager *networkManager, const QHostAddress &address, quint16 port = 55443, QObject *parent = nullptr);
|
||||
bool connected();
|
||||
bool isConnected();
|
||||
void connectDevice();
|
||||
|
||||
int getParam(QList<Property> properties);
|
||||
int setName(const QString &name);
|
||||
@ -79,17 +86,17 @@ private:
|
||||
|
||||
QTcpSocket *m_socket = nullptr;
|
||||
QHostAddress m_address;
|
||||
qint16 m_port;
|
||||
quint16 m_port;
|
||||
NetworkAccessManager *m_networkManager = nullptr;
|
||||
|
||||
private slots:
|
||||
void onRefreshTimeout();
|
||||
void onStateChanged(QAbstractSocket::SocketState state);
|
||||
void onReadyRead();
|
||||
|
||||
signals:
|
||||
void connectionChanged(bool connected);
|
||||
void authenticationStatusChanged(bool authenticated);
|
||||
void requestExecuted(int requestId, bool success);
|
||||
void propertyReceived(Property property, QVariant value);
|
||||
void propertyListReceived(QVariantList value);
|
||||
void notificationReveiced(Property property, QVariant value);
|
||||
};
|
||||
#endif // YEELIGHT_H
|
||||
|
||||
@ -7,7 +7,9 @@ TARGET = $$qtLibraryTarget(nymea_devicepluginyeelight)
|
||||
SOURCES += \
|
||||
devicepluginyeelight.cpp \
|
||||
yeelight.cpp \
|
||||
ssdp.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginyeelight.h \
|
||||
yeelight.h \
|
||||
ssdp.h
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user