enabled NOTIFY for UPnP plugins
added reconnect support for LG Smart Tv (pairing) fixed missing uuid from UDAP2.0 device
This commit is contained in:
parent
30f5c44e08
commit
3129d6a15c
@ -184,6 +184,7 @@ DeviceManager::DeviceManager(QObject *parent) :
|
||||
|
||||
m_upnpDiscovery = new UpnpDiscovery(this);
|
||||
connect(m_upnpDiscovery, &UpnpDiscovery::discoveryFinished, this, &DeviceManager::upnpDiscoveryFinished);
|
||||
connect(m_upnpDiscovery, &UpnpDiscovery::upnpNotify, this, &DeviceManager::upnpNotifyReceived);
|
||||
}
|
||||
|
||||
/*! Destructor of the DeviceManager. Each loaded \l{DevicePlugin} will be deleted. */
|
||||
@ -941,6 +942,15 @@ void DeviceManager::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &dev
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceManager::upnpNotifyReceived(const QByteArray ¬ifyData)
|
||||
{
|
||||
foreach (DevicePlugin *devicePlugin, m_devicePlugins) {
|
||||
if (devicePlugin->requiredHardware().testFlag(HardwareResourceUpnpDisovery)) {
|
||||
devicePlugin->upnpNotifyReceived(notifyData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceManager::timerEvent()
|
||||
{
|
||||
foreach (Device *device, m_configuredDevices) {
|
||||
|
||||
@ -132,6 +132,7 @@ private slots:
|
||||
|
||||
void radio433SignalReceived(QList<int> rawData);
|
||||
void upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &deviceDescriptorList, const PluginId &pluginId);
|
||||
void upnpNotifyReceived(const QByteArray ¬ifyData);
|
||||
void timerEvent();
|
||||
|
||||
private:
|
||||
|
||||
@ -28,13 +28,13 @@ UpnpDiscovery::UpnpDiscovery(QObject *parent) :
|
||||
setSocketOption(QAbstractSocket::MulticastTtlOption,QVariant(1));
|
||||
setSocketOption(QAbstractSocket::MulticastLoopbackOption,QVariant(1));
|
||||
|
||||
if(!bind(QHostAddress::AnyIPv4,m_port,QUdpSocket::ShareAddress)){
|
||||
qWarning() << "ERROR: UPnP discovery could not bind to port " << m_port;
|
||||
if(!bind(QHostAddress::AnyIPv4, m_port, QUdpSocket::ShareAddress)){
|
||||
qWarning() << "ERROR: UPnP discovery could not bind to port" << m_port;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!joinMulticastGroup(m_host)){
|
||||
qWarning() << "ERROR: UPnP discovery could not join multicast group " << m_host;
|
||||
qWarning() << "ERROR: UPnP discovery could not join multicast group" << m_host;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ UpnpDiscovery::UpnpDiscovery(QObject *parent) :
|
||||
connect(this,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error(QAbstractSocket::SocketError)));
|
||||
connect(this, &UpnpDiscovery::readyRead, this, &UpnpDiscovery::readData);
|
||||
|
||||
qDebug() << "--> Successfully created UPnPDiscovery.";
|
||||
qDebug() << "--> UPnP discovery created successfully.";
|
||||
}
|
||||
|
||||
bool UpnpDiscovery::discoverDevices(const QString &searchTarget, const QString &userAgent, const PluginId &pluginId)
|
||||
@ -65,6 +65,11 @@ bool UpnpDiscovery::discoverDevices(const QString &searchTarget, const QString &
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
if(state() != BoundState){
|
||||
qDebug() << "ERROR: UPnP not bound to port 1900";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_searchTarget = searchTarget;
|
||||
m_userAgent = userAgent;
|
||||
m_pluginId = pluginId;
|
||||
@ -76,7 +81,8 @@ bool UpnpDiscovery::discoverDevices(const QString &searchTarget, const QString &
|
||||
"ST: " + m_searchTarget.toUtf8() + "\r\n"
|
||||
"USR-AGENT: " + m_userAgent.toUtf8() + "\r\n\r\n");
|
||||
|
||||
writeDatagram(ssdpSearchMessage,m_host,m_port);
|
||||
qDebug() << "--> UPnP discovery called.";
|
||||
writeDatagram(ssdpSearchMessage, m_host, m_port);
|
||||
|
||||
m_timer->start(3000);
|
||||
return true;
|
||||
@ -110,19 +116,25 @@ void UpnpDiscovery::readData()
|
||||
data.resize(pendingDatagramSize());
|
||||
readDatagram(data.data(), data.size(), &hostAddress);
|
||||
}
|
||||
// qDebug() << "-----------------------";
|
||||
|
||||
// qDebug() << "======================";
|
||||
// qDebug() << data;
|
||||
|
||||
if (data.contains("NOTIFY")) {
|
||||
emit upnpNotify(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the data contains the HTTP OK header...
|
||||
if(data.contains("HTTP/1.1 200 OK")){
|
||||
if (data.contains("HTTP/1.1 200 OK")) {
|
||||
const QStringList lines = QString(data).split("\r\n");
|
||||
foreach( const QString& line, lines){
|
||||
foreach (const QString& line, lines) {
|
||||
int separatorIndex = line.indexOf(':');
|
||||
QString key = line.left(separatorIndex).toUpper();
|
||||
QString value = line.mid(separatorIndex+1).trimmed();
|
||||
|
||||
// get location
|
||||
if(key.contains("LOCATION")){
|
||||
if (key.contains("LOCATION")) {
|
||||
location = QUrl(value);
|
||||
}
|
||||
}
|
||||
@ -147,45 +159,48 @@ void UpnpDiscovery::replyFinished(QNetworkReply *reply)
|
||||
|
||||
// parse XML data
|
||||
QXmlStreamReader xml(data);
|
||||
while(!xml.atEnd() && !xml.hasError()){
|
||||
while (!xml.atEnd() && !xml.hasError()) {
|
||||
xml.readNext();
|
||||
if(xml.isStartDocument()){
|
||||
if (xml.isStartDocument()) {
|
||||
continue;
|
||||
}
|
||||
if(xml.isStartElement()){
|
||||
if(xml.name().toString() == "device"){
|
||||
while(!xml.atEnd()){
|
||||
if(xml.name() == "deviceType" && xml.isStartElement()){
|
||||
if (xml.isStartElement()) {
|
||||
if (xml.name().toString() == "device") {
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.name() == "deviceType" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setDeviceType(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "friendlyName" && xml.isStartElement()){
|
||||
if (xml.name() == "friendlyName" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setFriendlyName(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "manufacturer" && xml.isStartElement()){
|
||||
if (xml.name() == "manufacturer" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setManufacturer(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "manufacturerURL" && xml.isStartElement()){
|
||||
if (xml.name() == "manufacturerURL" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setManufacturerURL(QUrl(xml.readElementText()));
|
||||
}
|
||||
if(xml.name() == "modelDescription" && xml.isStartElement()){
|
||||
if (xml.name() == "modelDescription" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setModelDescription(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "modelName" && xml.isStartElement()){
|
||||
if (xml.name() == "modelName" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setModelName(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "modelNumber" && xml.isStartElement()){
|
||||
if (xml.name() == "modelNumber" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setModelNumber(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "modelURL" && xml.isStartElement()){
|
||||
if (xml.name() == "modelURL" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setModelURL(QUrl(xml.readElementText()));
|
||||
}
|
||||
if(xml.name() == "serialNumber" && xml.isStartElement()){
|
||||
if (xml.name() == "serialNumber" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setSerialNumber(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "UDN" && xml.isStartElement()){
|
||||
if (xml.name() == "UDN" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setUuid(xml.readElementText());
|
||||
}
|
||||
if(xml.name() == "UPC" && xml.isStartElement()){
|
||||
if (xml.name() == "uuid" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setUuid(xml.readElementText());
|
||||
}
|
||||
if (xml.name() == "UPC" && xml.isStartElement()) {
|
||||
upnpDeviceDescriptor.setUpc(xml.readElementText());
|
||||
}
|
||||
xml.readNext();
|
||||
@ -198,11 +213,11 @@ void UpnpDiscovery::replyFinished(QNetworkReply *reply)
|
||||
// check if we allready have the device in the list
|
||||
bool isAlreadyInList = false;
|
||||
foreach (UpnpDeviceDescriptor deviceDescriptor, m_deviceList) {
|
||||
if(deviceDescriptor.uuid() == upnpDeviceDescriptor.uuid()){
|
||||
if (deviceDescriptor.uuid() == upnpDeviceDescriptor.uuid()) {
|
||||
isAlreadyInList = true;
|
||||
}
|
||||
}
|
||||
if(!isAlreadyInList){
|
||||
if (!isAlreadyInList) {
|
||||
m_deviceList.append(upnpDeviceDescriptor);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -58,6 +58,7 @@ private:
|
||||
|
||||
signals:
|
||||
void discoveryFinished(const QList<UpnpDeviceDescriptor> &deviceDescriptorList, const PluginId & pluginId);
|
||||
void upnpNotify(const QByteArray ¬ifyMessage);
|
||||
|
||||
private slots:
|
||||
void error(QAbstractSocket::SocketError error);
|
||||
|
||||
@ -525,7 +525,7 @@ bool DevicePlugin::transmitData(int delay, QList<int> rawData, int repetitions)
|
||||
|
||||
void DevicePlugin::upnpDiscover(QString searchTarget, QString userAgent)
|
||||
{
|
||||
if(requiredHardware() == DeviceManager::HardwareResourceUpnpDisovery){
|
||||
if(requiredHardware().testFlag(DeviceManager::HardwareResourceUpnpDisovery)){
|
||||
deviceManager()->m_upnpDiscovery->discoverDevices(searchTarget, userAgent, pluginId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +62,7 @@ public:
|
||||
virtual void radioData(const QList<int> &rawData) {Q_UNUSED(rawData)}
|
||||
virtual void guhTimer() {}
|
||||
virtual void upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList) {Q_UNUSED(upnpDeviceDescriptorList)}
|
||||
virtual void upnpNotifyReceived(const QByteArray ¬ifyData) {Q_UNUSED(notifyData)}
|
||||
|
||||
// Configuration
|
||||
virtual QList<ParamType> configurationDescription() const;
|
||||
|
||||
@ -16,28 +16,6 @@
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*!
|
||||
\page lgsmarttv.html
|
||||
\title LG Smart Tv
|
||||
|
||||
\ingroup plugins
|
||||
\ingroup network
|
||||
|
||||
This plugin allows to interact with \l{http://www.lg.com/us/experience-tvs/smart-tv}{LG Smart Tv's}
|
||||
with the \l{http://developer.lgappstv.com/TV_HELP/index.jsp?topic=%2Flge.tvsdk.references.book%2Fhtml%2FUDAP%2FUDAP%2FLG+UDAP+2+0+Protocol+Specifications.htm}{LG UDAP 2.0 Protocol Specifications}.
|
||||
|
||||
\chapter Plugin properties
|
||||
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
||||
and \l{Vendor}{Vendors} of this \l{DevicePlugin}.
|
||||
|
||||
Each \l{DeviceClass} has a list of \l{ParamType}{paramTypes}, \l{ActionType}{actionTypes}, \l{StateType}{stateTypes}
|
||||
and \l{EventType}{eventTypes}. The \l{DeviceClass::CreateMethod}{createMethods} parameter describes how the \l{Device}
|
||||
will be created in the system. A device can have more than one \l{DeviceClass::CreateMethod}{CreateMethod}.
|
||||
The \l{DeviceClass::SetupMethod}{setupMethod} describes the setup method of the \l{Device}.
|
||||
The detailed implementation of each \l{DeviceClass} can be found in the source code.
|
||||
|
||||
\quotefile plugins/deviceplugins/lgsmarttv/devicepluginlgsmarttv.json
|
||||
*/
|
||||
|
||||
#include "devicepluginlgsmarttv.h"
|
||||
|
||||
@ -47,42 +25,71 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DeviceClassId lgSmartTvDeviceClassId = DeviceClassId("1d41b5a8-74ff-4a12-b365-c7bbe610848f");
|
||||
|
||||
StateTypeId tvReachableStateTypeId = StateTypeId("b056c36b-df87-4177-8d5d-1e7c1e8cdc7a");
|
||||
StateTypeId tv3DModeStateTypeId = StateTypeId("8ad3d77f-d340-495d-8c2a-5569a80e9d36");
|
||||
StateTypeId tvVolumeLevelStateTypeId = StateTypeId("07d39a6e-7eab-42d0-851d-9f3bcd3bbb57");
|
||||
StateTypeId tvMuteStateTypeId = StateTypeId("a6ac9061-3de7-403a-a646-790ca5d73764");
|
||||
StateTypeId tvChannelTypeStateTypeId = StateTypeId("84c86670-77c7-4fc6-9e23-abca066e76aa");
|
||||
StateTypeId tvChannelNameStateTypeId = StateTypeId("265dc5f7-3f4d-4002-a6fe-2a53986bcf1d");
|
||||
StateTypeId tvChannelNumberStateTypeId = StateTypeId("881629a3-4ce2-42ba-8ce6-10d90c383799");
|
||||
StateTypeId tvProgramNameStateTypeId = StateTypeId("3f53e52e-1ad7-40e7-8080-76908e720cac");
|
||||
StateTypeId tvInputSourceIndexStateTypeId = StateTypeId("e895017a-139f-410c-bfb2-4d008104e164");
|
||||
StateTypeId tvInputSourceLabelNameStateTypeId = StateTypeId("58b734ec-2269-4c57-99e1-e1eeee401053");
|
||||
|
||||
ActionTypeId commandVolumeUpActionTypeId = ActionTypeId("ac5d7dcd-dfe8-4a94-9ab9-21b3f804b39e");
|
||||
ActionTypeId commandVolumeDownActionTypeId = ActionTypeId("62b17bec-f461-4ffa-93d1-67a9430d55e1");
|
||||
ActionTypeId commandMuteActionTypeId = ActionTypeId("1aa9d7f0-0f66-4b90-bb72-f6b7b2118221");
|
||||
ActionTypeId commandUnmuteActionTypeId = ActionTypeId("b7e31999-ba67-443d-8e5c-ec104af987bd");
|
||||
ActionTypeId commandChannelUpActionTypeId = ActionTypeId("acd1f6a0-2cfa-4665-9607-cf94245ec5a3");
|
||||
ActionTypeId commandChannelDownActionTypeId = ActionTypeId("6ea66772-0e6d-40b1-978c-a01fb53871dd");
|
||||
ActionTypeId commandPowerOffActionTypeId = ActionTypeId("cbe41134-ff11-4916-815b-3ac289c64090");
|
||||
ActionTypeId commandArrowUpActionTypeId = ActionTypeId("57c483b4-4ddf-4470-828c-8d8767e7a923");
|
||||
ActionTypeId commandArrowDownActionTypeId = ActionTypeId("614cf1af-5cf7-4bb2-885c-4414078d8899");
|
||||
ActionTypeId commandArrowLeftActionTypeId = ActionTypeId("916394dd-7833-4875-8d7a-49d7d24ceeb2");
|
||||
ActionTypeId commandArrowRightActionTypeId = ActionTypeId("01e3df1e-638b-4e14-ba85-660267766062");
|
||||
ActionTypeId commandOkActionTypeId = ActionTypeId("257dfa59-0d38-4e18-a3fc-213809fdb12f");
|
||||
ActionTypeId commandBackActionTypeId = ActionTypeId("ce4184b3-6b8e-4fc3-a4cb-7b8ec72f2ce9");
|
||||
ActionTypeId commandHomeActionTypeId = ActionTypeId("33f941c1-f5fc-4449-b6e3-93eafca493e0");
|
||||
ActionTypeId commandInputSourceActionTypeId = ActionTypeId("9a6e5111-95d3-49ac-8056-249e704b1509");
|
||||
ActionTypeId commandExitActionTypeId = ActionTypeId("d76efdb8-056e-4b39-a839-2ef6d6001b00");
|
||||
ActionTypeId commandInfoActionTypeId = ActionTypeId("9c1290d5-3135-4124-a576-fc7522cffdcf");
|
||||
ActionTypeId commandMyAppsActionTypeId = ActionTypeId("47d65cac-fe75-4c36-9dee-9862c1c1130e");
|
||||
ActionTypeId commandProgramListActionTypeId = ActionTypeId("9aa3a97e-505d-4906-9764-14b6dc4e31e8");
|
||||
|
||||
|
||||
DevicePluginLgSmartTv::DevicePluginLgSmartTv()
|
||||
{
|
||||
m_discovery = new TvDiscovery(this);
|
||||
|
||||
connect(m_discovery,SIGNAL(discoveryDone(QList<TvDevice*>)),this,SLOT(discoveryDone(QList<TvDevice*>)));
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginLgSmartTv::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||
{
|
||||
qDebug() << "should discover devices with params:" << params;
|
||||
|
||||
Q_UNUSED(params);
|
||||
if(deviceClassId != lgSmartTvDeviceClassId){
|
||||
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||
}
|
||||
|
||||
m_discovery->discover(3000);
|
||||
|
||||
upnpDiscover("udap:rootservice","UDAP/2.0");
|
||||
return DeviceManager::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
DeviceManager::DeviceSetupStatus DevicePluginLgSmartTv::setupDevice(Device *device)
|
||||
{
|
||||
|
||||
device->setName("LG Smart Tv (" + device->paramValue("model").toString() + ")");
|
||||
|
||||
TvDevice *tvDevice = new TvDevice(this);
|
||||
tvDevice->setName(device->paramValue("name").toString());
|
||||
tvDevice->setUuid(device->paramValue("uuid").toString());
|
||||
tvDevice->setModelName(device->paramValue("model").toString());
|
||||
tvDevice->setHostAddress(QHostAddress(device->paramValue("host address").toString()));
|
||||
tvDevice->setPort(device->paramValue("port").toInt());
|
||||
tvDevice->setLocation(QUrl(device->paramValue("location").toString()));
|
||||
tvDevice->setUuid(device->paramValue("manufacturer").toString());
|
||||
UpnpDeviceDescriptor upnpDeviceDescriptor;
|
||||
upnpDeviceDescriptor.setFriendlyName(device->paramValue("name").toString());
|
||||
upnpDeviceDescriptor.setUuid(device->paramValue("uuid").toString());
|
||||
upnpDeviceDescriptor.setModelName(device->paramValue("model").toString());
|
||||
upnpDeviceDescriptor.setHostAddress(QHostAddress(device->paramValue("host address").toString()));
|
||||
upnpDeviceDescriptor.setPort(device->paramValue("port").toInt());
|
||||
upnpDeviceDescriptor.setLocation(QUrl(device->paramValue("location").toString()));
|
||||
upnpDeviceDescriptor.setManufacturer(device->paramValue("manufacturer").toString());
|
||||
// key if there is one...
|
||||
TvDevice *tvDevice = new TvDevice(this, upnpDeviceDescriptor);
|
||||
|
||||
// TODO: make dynamic...displayPin setup!!!
|
||||
tvDevice->setKey("539887");
|
||||
tvDevice->setupEventHandler();
|
||||
|
||||
connect(tvDevice, &TvDevice::pairingFinished, this, &DevicePluginLgSmartTv::pairingFinished);
|
||||
@ -90,55 +97,55 @@ DeviceManager::DeviceSetupStatus DevicePluginLgSmartTv::setupDevice(Device *devi
|
||||
connect(tvDevice, &TvDevice::statusChanged, this, &DevicePluginLgSmartTv::statusChanged);
|
||||
|
||||
tvDevice->requestPairing();
|
||||
m_tvList.insert(tvDevice,device);
|
||||
m_tvList.insert(tvDevice, device);
|
||||
|
||||
return DeviceManager::DeviceSetupStatusAsync;
|
||||
}
|
||||
|
||||
DeviceManager::HardwareResources DevicePluginLgSmartTv::requiredHardware() const
|
||||
{
|
||||
return DeviceManager::HardwareResourceTimer;
|
||||
return DeviceManager::HardwareResourceTimer | DeviceManager::HardwareResourceUpnpDisovery;
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginLgSmartTv::executeAction(Device *device, const Action &action)
|
||||
{
|
||||
TvDevice * tvDevice = m_tvList.key(device);
|
||||
|
||||
if(action.actionTypeId() == commandVolumeUpActionTypeId){
|
||||
if (action.actionTypeId() == commandVolumeUpActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::VolUp, action.id());
|
||||
} else if(action.actionTypeId() == commandVolumeDownActionTypeId){
|
||||
} else if(action.actionTypeId() == commandVolumeDownActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::VolDown, action.id());
|
||||
} else if(action.actionTypeId() == commandMuteActionTypeId){
|
||||
} else if(action.actionTypeId() == commandMuteActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Mute, action.id());
|
||||
} else if(action.actionTypeId() == commandChannelUpActionTypeId){
|
||||
} else if(action.actionTypeId() == commandChannelUpActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::ChannelUp, action.id());
|
||||
} else if(action.actionTypeId() == commandChannelDownActionTypeId){
|
||||
} else if(action.actionTypeId() == commandChannelDownActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::ChannelDown, action.id());
|
||||
} else if(action.actionTypeId() == commandPowerOffActionTypeId){
|
||||
} else if(action.actionTypeId() == commandPowerOffActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Power, action.id());
|
||||
} else if(action.actionTypeId() == commandArrowUpActionTypeId){
|
||||
} else if(action.actionTypeId() == commandArrowUpActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Up, action.id());
|
||||
} else if(action.actionTypeId() == commandArrowDownActionTypeId){
|
||||
} else if(action.actionTypeId() == commandArrowDownActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Down, action.id());
|
||||
} else if(action.actionTypeId() == commandArrowLeftActionTypeId){
|
||||
} else if(action.actionTypeId() == commandArrowLeftActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Left, action.id());
|
||||
} else if(action.actionTypeId() == commandArrowRightActionTypeId){
|
||||
} else if(action.actionTypeId() == commandArrowRightActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Right, action.id());
|
||||
} else if(action.actionTypeId() == commandOkActionTypeId){
|
||||
} else if(action.actionTypeId() == commandOkActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Ok, action.id());
|
||||
} else if(action.actionTypeId() == commandBackActionTypeId){
|
||||
} else if(action.actionTypeId() == commandBackActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Back, action.id());
|
||||
} else if(action.actionTypeId() == commandHomeActionTypeId){
|
||||
} else if(action.actionTypeId() == commandHomeActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Home, action.id());
|
||||
} else if(action.actionTypeId() == commandInputSourceActionTypeId){
|
||||
} else if(action.actionTypeId() == commandInputSourceActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::ExternalInput, action.id());
|
||||
} else if(action.actionTypeId() == commandExitActionTypeId){
|
||||
} else if(action.actionTypeId() == commandExitActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Exit, action.id());
|
||||
} else if(action.actionTypeId() == commandInfoActionTypeId){
|
||||
} else if(action.actionTypeId() == commandInfoActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::Info, action.id());
|
||||
} else if(action.actionTypeId() == commandMyAppsActionTypeId){
|
||||
} else if(action.actionTypeId() == commandMyAppsActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::MyApps, action.id());
|
||||
} else if(action.actionTypeId() == commandProgramListActionTypeId){
|
||||
} else if(action.actionTypeId() == commandProgramListActionTypeId) {
|
||||
tvDevice->sendCommand(TvDevice::ProgramList, action.id());
|
||||
} else {
|
||||
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||
@ -146,6 +153,33 @@ DeviceManager::DeviceError DevicePluginLgSmartTv::executeAction(Device *device,
|
||||
return DeviceManager::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
void DevicePluginLgSmartTv::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList)
|
||||
{
|
||||
QList<DeviceDescriptor> deviceDescriptors;
|
||||
foreach (UpnpDeviceDescriptor upnpDeviceDescriptor, upnpDeviceDescriptorList) {
|
||||
DeviceDescriptor descriptor(lgSmartTvDeviceClassId, "Lg Smart Tv", upnpDeviceDescriptor.modelName());
|
||||
ParamList params;
|
||||
params.append(Param("name", upnpDeviceDescriptor.friendlyName()));
|
||||
params.append(Param("uuid", upnpDeviceDescriptor.uuid()));
|
||||
params.append(Param("model", upnpDeviceDescriptor.modelName()));
|
||||
params.append(Param("host address", upnpDeviceDescriptor.hostAddress().toString()));
|
||||
params.append(Param("location", upnpDeviceDescriptor.hostAddress().toString()));
|
||||
params.append(Param("port", upnpDeviceDescriptor.port()));
|
||||
params.append(Param("manufacturer", upnpDeviceDescriptor.manufacturer()));
|
||||
params.append(Param("key", "539887"));
|
||||
descriptor.setParams(params);
|
||||
deviceDescriptors.append(descriptor);
|
||||
}
|
||||
emit devicesDiscovered(lgSmartTvDeviceClassId, deviceDescriptors);
|
||||
}
|
||||
|
||||
void DevicePluginLgSmartTv::upnpNotifyReceived(const QByteArray ¬ifyData)
|
||||
{
|
||||
Q_UNUSED(notifyData);
|
||||
// qDebug() << "######################################";
|
||||
// qDebug() << notifyData;
|
||||
}
|
||||
|
||||
void DevicePluginLgSmartTv::deviceRemoved(Device *device)
|
||||
{
|
||||
if (!m_tvList.values().contains(device)) {
|
||||
@ -153,7 +187,7 @@ void DevicePluginLgSmartTv::deviceRemoved(Device *device)
|
||||
}
|
||||
|
||||
TvDevice *tvDevice= m_tvList.key(device);
|
||||
qDebug() << "remove LG Smart Tv " << tvDevice->modelName();
|
||||
qDebug() << "remove LG SmartTv " << tvDevice->modelName();
|
||||
m_tvList.remove(tvDevice);
|
||||
tvDevice->deleteLater();
|
||||
}
|
||||
@ -165,45 +199,35 @@ void DevicePluginLgSmartTv::guhTimer()
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginLgSmartTv::discoveryDone(QList<TvDevice*> tvList)
|
||||
{
|
||||
QList<DeviceDescriptor> deviceDescriptors;
|
||||
foreach (TvDevice *device, tvList) {
|
||||
DeviceDescriptor descriptor(lgSmartTvDeviceClassId, "Lg Smart Tv", device->modelName());
|
||||
ParamList params;
|
||||
params.append(Param("name", device->name()));
|
||||
params.append(Param("uuid", device->uuid()));
|
||||
params.append(Param("model", device->modelName()));
|
||||
params.append(Param("host address", device->hostAddress().toString()));
|
||||
params.append(Param("location", device->location().toString()));
|
||||
params.append(Param("port", device->port()));
|
||||
params.append(Param("manufacturer", device->manufacturer()));
|
||||
params.append(Param("key", device->key()));
|
||||
descriptor.setParams(params);
|
||||
deviceDescriptors.append(descriptor);
|
||||
}
|
||||
emit devicesDiscovered(lgSmartTvDeviceClassId, deviceDescriptors);
|
||||
}
|
||||
|
||||
void DevicePluginLgSmartTv::pairingFinished(const bool &success)
|
||||
{
|
||||
TvDevice *tvDevice = static_cast<TvDevice*>(sender());
|
||||
Device *device = m_tvList.value(tvDevice);
|
||||
|
||||
if(success){
|
||||
emit deviceSetupFinished(device,DeviceManager::DeviceSetupStatusSuccess);
|
||||
// check if we allready set up this device...
|
||||
foreach (Device *configuredDevice, deviceManager()->findConfiguredDevices(lgSmartTvDeviceClassId)) {
|
||||
if (configuredDevice->paramValue("uuid").toString() == device->paramValue("uuid").toString()) {
|
||||
tvDevice->refresh();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ...otherwise emit deviceSetupFinished with appropriate DeviceError
|
||||
if (success) {
|
||||
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
|
||||
tvDevice->refresh();
|
||||
}else{
|
||||
emit deviceSetupFinished(device,DeviceManager::DeviceSetupStatusFailure);
|
||||
} else {
|
||||
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginLgSmartTv::sendingCommandFinished(const bool &success, const ActionId &actionId)
|
||||
{
|
||||
if(success){
|
||||
emit actionExecutionFinished(actionId,DeviceManager::DeviceErrorNoError);
|
||||
}else{
|
||||
emit actionExecutionFinished(actionId,DeviceManager::DeviceErrorHardwareFailure);
|
||||
if (success) {
|
||||
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
|
||||
} else {
|
||||
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorActionTypeNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,7 +236,7 @@ void DevicePluginLgSmartTv::statusChanged()
|
||||
TvDevice *tvDevice = static_cast<TvDevice*>(sender());
|
||||
Device *device = m_tvList.value(tvDevice);
|
||||
|
||||
device->setStateValue(tvReachableStateTypeId, tvDevice->reachable());
|
||||
device->setStateValue(tvReachableStateTypeId, tvDevice->isReachable());
|
||||
device->setStateValue(tv3DModeStateTypeId, tvDevice->is3DMode());
|
||||
device->setStateValue(tvVolumeLevelStateTypeId, tvDevice->volumeLevel());
|
||||
device->setStateValue(tvMuteStateTypeId, tvDevice->mute());
|
||||
@ -223,5 +247,3 @@ void DevicePluginLgSmartTv::statusChanged()
|
||||
device->setStateValue(tvInputSourceIndexStateTypeId, tvDevice->inputSourceIndex());
|
||||
device->setStateValue(tvInputSourceLabelNameStateTypeId, tvDevice->inputSourceLabelName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -19,8 +19,9 @@
|
||||
#ifndef DEVICEPLUGINLGSMARTTV_H
|
||||
#define DEVICEPLUGINLGSMARTTV_H
|
||||
|
||||
#include "hardware/upnpdiscovery/upnpdevicedescriptor.h"
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "tvdiscovery.h"
|
||||
#include "tvdevice.h"
|
||||
|
||||
class DevicePluginLgSmartTv : public DevicePlugin
|
||||
{
|
||||
@ -32,12 +33,13 @@ class DevicePluginLgSmartTv : public DevicePlugin
|
||||
public:
|
||||
explicit DevicePluginLgSmartTv();
|
||||
|
||||
TvDiscovery *m_discovery;
|
||||
|
||||
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
||||
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||
DeviceManager::HardwareResources requiredHardware() const override;
|
||||
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||
void upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList) override;
|
||||
void upnpNotifyReceived(const QByteArray ¬ifyData);
|
||||
|
||||
void deviceRemoved(Device *device) override;
|
||||
|
||||
@ -46,14 +48,10 @@ public:
|
||||
QHash<TvDevice*, Device*> m_tvList;
|
||||
|
||||
private slots:
|
||||
void discoveryDone(QList<TvDevice *> tvList);
|
||||
void pairingFinished(const bool &success);
|
||||
void sendingCommandFinished(const bool &success, const ActionId &actionId);
|
||||
void statusChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // DEVICEPLUGINLGSMARTTV_H
|
||||
|
||||
@ -6,13 +6,11 @@ QT+= network xml
|
||||
|
||||
SOURCES += \
|
||||
devicepluginlgsmarttv.cpp \
|
||||
tvdiscovery.cpp \
|
||||
tvdevice.cpp \
|
||||
tveventhandler.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginlgsmarttv.h \
|
||||
tvdiscovery.h \
|
||||
tvdevice.h \
|
||||
tveventhandler.h
|
||||
|
||||
|
||||
@ -18,100 +18,18 @@
|
||||
|
||||
#include "tvdevice.h"
|
||||
|
||||
TvDevice::TvDevice(QObject *parent) :
|
||||
QObject(parent)
|
||||
TvDevice::TvDevice(QObject *parent, UpnpDeviceDescriptor upnpDeviceDescriptor) :
|
||||
UpnpDevice(parent, upnpDeviceDescriptor)
|
||||
{
|
||||
m_manager = new QNetworkAccessManager(this);
|
||||
|
||||
// TODO: make dynamic...displayPin setup
|
||||
m_key = "539887";
|
||||
|
||||
m_key = "0";
|
||||
m_pairingStatus = false;
|
||||
m_reachable = false;
|
||||
|
||||
connect(m_manager, &QNetworkAccessManager::finished, this, &TvDevice::replyFinished);
|
||||
}
|
||||
|
||||
void TvDevice::setLocation(const QUrl &location)
|
||||
{
|
||||
m_location = location;
|
||||
}
|
||||
|
||||
QUrl TvDevice::location() const
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
|
||||
void TvDevice::setHostAddress(const QHostAddress &hostAddress)
|
||||
{
|
||||
m_hostAddress = hostAddress;
|
||||
}
|
||||
|
||||
QHostAddress TvDevice::hostAddress() const
|
||||
{
|
||||
return m_hostAddress;
|
||||
}
|
||||
|
||||
void TvDevice::setPort(const int &port)
|
||||
{
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
int TvDevice::port() const
|
||||
{
|
||||
return m_port;
|
||||
}
|
||||
|
||||
void TvDevice::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
QString TvDevice::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void TvDevice::setModelName(const QString &modelName)
|
||||
{
|
||||
m_modelName = modelName;
|
||||
}
|
||||
|
||||
QString TvDevice::modelName() const
|
||||
{
|
||||
return m_modelName;
|
||||
}
|
||||
|
||||
void TvDevice::setManufacturer(const QString &manufacturer)
|
||||
{
|
||||
m_manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
QString TvDevice::manufacturer() const
|
||||
{
|
||||
return m_manufacturer;
|
||||
}
|
||||
|
||||
void TvDevice::setDeviceType(const QString &deviceType)
|
||||
{
|
||||
m_deviceType = deviceType;
|
||||
}
|
||||
|
||||
QString TvDevice::deviceType() const
|
||||
{
|
||||
return m_deviceType;
|
||||
}
|
||||
|
||||
void TvDevice::setUuid(const QString &uuid)
|
||||
{
|
||||
m_uuid = uuid;
|
||||
}
|
||||
|
||||
QString TvDevice::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void TvDevice::setKey(const QString &key)
|
||||
{
|
||||
m_key = key;
|
||||
@ -122,7 +40,7 @@ QString TvDevice::key() const
|
||||
return m_key;
|
||||
}
|
||||
|
||||
bool TvDevice::reachable() const
|
||||
bool TvDevice::isReachable() const
|
||||
{
|
||||
return m_reachable;
|
||||
}
|
||||
@ -179,12 +97,12 @@ QString TvDevice::inputSourceLabelName() const
|
||||
|
||||
void TvDevice::showPairingKey()
|
||||
{
|
||||
QString urlString = "http://" + m_hostAddress.toString() + ":" + QString::number(m_port) + "/udap/api/pairing";
|
||||
QString urlString = "http://" + hostAddress().toString() + ":" + QString::number(port()) + "/udap/api/pairing";
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(urlString));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("text/xml; charset=utf-8"));
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader,QVariant("UDAP/2.0 guh"));
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader,QVariant("UDAP/2.0"));
|
||||
|
||||
QByteArray data = "<?xml version=\"1.0\" encoding=\"utf-8\"?><envelope><api type=\"pairing\"> <name>showKey</name></api></envelope>";
|
||||
|
||||
@ -197,7 +115,7 @@ void TvDevice::requestPairing()
|
||||
emit pairingFinished(false);
|
||||
}
|
||||
|
||||
QString urlString = "http://" + m_hostAddress.toString() + ":" + QString::number(m_port) + "/udap/api/pairing";
|
||||
QString urlString = "http://" + hostAddress().toString() + ":" + QString::number(port()) + "/udap/api/pairing";
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(urlString));
|
||||
@ -211,7 +129,7 @@ void TvDevice::requestPairing()
|
||||
|
||||
void TvDevice::endPairing()
|
||||
{
|
||||
QString urlString = "http://" + m_hostAddress.toString() + ":" + QString::number(m_port) + "/udap/api/pairing";
|
||||
QString urlString = "http://" + hostAddress().toString() + ":" + QString::number(port()) + "/udap/api/pairing";
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(urlString));
|
||||
@ -229,12 +147,12 @@ void TvDevice::sendCommand(TvDevice::RemoteKey key, ActionId actionId)
|
||||
{
|
||||
m_actionId = actionId;
|
||||
|
||||
if(!m_pairingStatus){
|
||||
if(!m_pairingStatus) {
|
||||
requestPairing();
|
||||
return;
|
||||
}
|
||||
|
||||
QString urlString = "http://" + m_hostAddress.toString() + ":" + QString::number(m_port) + "/udap/api/command";
|
||||
QString urlString = "http://" + hostAddress().toString() + ":" + QString::number(port()) + "/udap/api/command";
|
||||
|
||||
QByteArray data;
|
||||
data.append("<?xml version=\"1.0\" encoding=\"utf-8\"?><envelope><api type=\"command\"><name>HandleKeyInput</name><value>");
|
||||
@ -252,21 +170,23 @@ void TvDevice::sendCommand(TvDevice::RemoteKey key, ActionId actionId)
|
||||
void TvDevice::setupEventHandler()
|
||||
{
|
||||
//qDebug() << "set up event handler " << m_hostAddress.toString() << m_port;
|
||||
m_eventHandler = new TvEventHandler(this,m_hostAddress,m_port);
|
||||
m_eventHandler = new TvEventHandler(this,hostAddress(),port());
|
||||
connect(m_eventHandler, &TvEventHandler::eventOccured, this, &TvDevice::eventOccured);
|
||||
}
|
||||
|
||||
void TvDevice::refresh()
|
||||
{
|
||||
if(paired()){
|
||||
if(paired()) {
|
||||
queryChannelInformation();
|
||||
queryVolumeInformation();
|
||||
}else{
|
||||
requestPairing();
|
||||
}
|
||||
}
|
||||
|
||||
void TvDevice::queryVolumeInformation()
|
||||
{
|
||||
QString urlString = "http://" + m_hostAddress.toString() + ":" + QString::number(m_port) + "/udap/api/data?target=volume_info";
|
||||
QString urlString = "http://" + hostAddress().toString() + ":" + QString::number(port()) + "/udap/api/data?target=volume_info";
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(urlString));
|
||||
@ -279,7 +199,7 @@ void TvDevice::queryVolumeInformation()
|
||||
|
||||
void TvDevice::queryChannelInformation()
|
||||
{
|
||||
QString urlString = "http://" + m_hostAddress.toString() + ":" + QString::number(m_port) + "/udap/api/data?target=cur_channel";
|
||||
QString urlString = "http://" + hostAddress().toString() + ":" + QString::number(port()) + "/udap/api/data?target=cur_channel";
|
||||
|
||||
QNetworkRequest deviceRequest;
|
||||
deviceRequest.setUrl(QUrl(urlString));
|
||||
@ -295,13 +215,13 @@ void TvDevice::parseVolumeInformation(const QByteArray &data)
|
||||
//qDebug() << printXmlData(data);
|
||||
QXmlStreamReader xml(data);
|
||||
|
||||
while(!xml.atEnd() && !xml.hasError()){
|
||||
while(!xml.atEnd() && !xml.hasError()) {
|
||||
xml.readNext();
|
||||
|
||||
if(xml.name() == "mute"){
|
||||
if(xml.name() == "mute") {
|
||||
m_mute = QVariant(xml.readElementText()).toBool();
|
||||
}
|
||||
if(xml.name() == "level"){
|
||||
if(xml.name() == "level") {
|
||||
m_volumeLevel = QVariant(xml.readElementText()).toInt();
|
||||
}
|
||||
}
|
||||
@ -313,25 +233,25 @@ void TvDevice::parseChannelInformation(const QByteArray &data)
|
||||
//qDebug() << printXmlData(data);
|
||||
QXmlStreamReader xml(data);
|
||||
|
||||
while(!xml.atEnd() && !xml.hasError()){
|
||||
while(!xml.atEnd() && !xml.hasError()) {
|
||||
xml.readNext();
|
||||
|
||||
if(xml.name() == "chtype"){
|
||||
if(xml.name() == "chtype") {
|
||||
m_channelType = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "major"){
|
||||
if(xml.name() == "major") {
|
||||
m_channelNumber = QVariant(xml.readElementText()).toInt();
|
||||
}
|
||||
if(xml.name() == "chname"){
|
||||
if(xml.name() == "chname") {
|
||||
m_channelName = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "progName"){
|
||||
if(xml.name() == "progName") {
|
||||
m_programName = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "inputSourceIdx"){
|
||||
if(xml.name() == "inputSourceIdx") {
|
||||
m_inputSourceIndex = QVariant(xml.readElementText()).toInt();
|
||||
}
|
||||
if(xml.name() == "labelName"){
|
||||
if(xml.name() == "labelName") {
|
||||
m_inputSourceLabel = xml.readElementText();
|
||||
}
|
||||
}
|
||||
@ -347,11 +267,11 @@ QString TvDevice::printXmlData(QByteArray data)
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
if (!reader.isWhitespace()) {
|
||||
if(!reader.isWhitespace()) {
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
}
|
||||
if(reader.hasError()){
|
||||
if(reader.hasError()) {
|
||||
qDebug() << "ERROR reading XML device information: " << reader.errorString();
|
||||
qDebug() << "--------------------------------------------";
|
||||
}
|
||||
@ -362,56 +282,56 @@ void TvDevice::replyFinished(QNetworkReply *reply)
|
||||
{
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if(status != 200){
|
||||
if(status != 200) {
|
||||
m_reachable = false;
|
||||
}else{
|
||||
} else {
|
||||
m_reachable = true;
|
||||
}
|
||||
|
||||
if(reply == m_showKeyReplay){
|
||||
if(status != 200){
|
||||
qWarning() << "ERROR: could not request to show pairing key on screen " << status;
|
||||
if(reply == m_showKeyReplay) {
|
||||
if(status != 200) {
|
||||
//qWarning() << "ERROR: could not request to show pairing key on screen " << status;
|
||||
}
|
||||
m_showKeyReplay->deleteLater();
|
||||
}
|
||||
if(reply == m_requestPairingReplay){
|
||||
if(status != 200){
|
||||
if(reply == m_requestPairingReplay) {
|
||||
if(status != 200) {
|
||||
m_pairingStatus = false;
|
||||
emit pairingFinished(false);
|
||||
qWarning() << "ERROR: could not pair with device" << status;
|
||||
}else{
|
||||
//qWarning() << "ERROR: could not pair with device" << status;
|
||||
} else {
|
||||
m_pairingStatus = true;
|
||||
qDebug() << "successfully paired with tv " << m_modelName;
|
||||
//qDebug() << "successfully paired with tv " << modelName();
|
||||
emit pairingFinished(true);
|
||||
}
|
||||
m_requestPairingReplay->deleteLater();
|
||||
}
|
||||
|
||||
if(reply == m_finishingPairingReplay){
|
||||
if(status == 200){
|
||||
if(reply == m_finishingPairingReplay) {
|
||||
if(status == 200) {
|
||||
m_pairingStatus = false;
|
||||
qDebug() << "successfully unpaired from tv " << m_modelName;
|
||||
//qDebug() << "successfully unpaired from tv " << modelName();
|
||||
}
|
||||
m_finishingPairingReplay->deleteLater();
|
||||
}
|
||||
|
||||
if(reply == m_sendCommandReplay){
|
||||
if(status != 200){
|
||||
if(reply == m_sendCommandReplay) {
|
||||
if (status != 200) {
|
||||
emit sendCommandFinished(false,m_actionId);
|
||||
qWarning() << "ERROR: could not send comand" << status;
|
||||
}else{
|
||||
} else {
|
||||
m_pairingStatus = true;
|
||||
qDebug() << "successfully sent command to tv " << m_modelName;
|
||||
//qDebug() << "successfully sent command to tv " << modelName();
|
||||
emit sendCommandFinished(true,m_actionId);
|
||||
refresh();
|
||||
}
|
||||
m_sendCommandReplay->deleteLater();
|
||||
}
|
||||
if(reply == m_queryVolumeInformationReplay){
|
||||
if(reply == m_queryVolumeInformationReplay) {
|
||||
parseVolumeInformation(reply->readAll());
|
||||
m_queryVolumeInformationReplay->deleteLater();
|
||||
}
|
||||
if(reply == m_queryChannelInformationReplay){
|
||||
if(reply == m_queryChannelInformationReplay) {
|
||||
parseChannelInformation(reply->readAll());
|
||||
m_queryChannelInformationReplay->deleteLater();
|
||||
}
|
||||
@ -422,17 +342,14 @@ void TvDevice::replyFinished(QNetworkReply *reply)
|
||||
void TvDevice::eventOccured(const QByteArray &data)
|
||||
{
|
||||
// if we got a channel changed event...
|
||||
if(data.contains("ChannelChanged")){
|
||||
if(data.contains("ChannelChanged")) {
|
||||
parseChannelInformation(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// qDebug() << "---------------------------------";
|
||||
// qDebug() << printXmlData(data);
|
||||
|
||||
// if the tv suspends, it will send a byebye message, which means
|
||||
// the pairing will be closed.
|
||||
if(data.contains("api type=\"pairing\"") && data.contains("byebye")){
|
||||
if(data.contains("api type=\"pairing\"") && data.contains("byebye")) {
|
||||
qDebug() << "--> tv ended pairing";
|
||||
m_pairingStatus = false;
|
||||
m_reachable = false;
|
||||
@ -443,13 +360,13 @@ void TvDevice::eventOccured(const QByteArray &data)
|
||||
// check if this is a 3DMode changed event
|
||||
QXmlStreamReader xml(data);
|
||||
|
||||
while(!xml.atEnd() && !xml.hasError()){
|
||||
while(!xml.atEnd() && !xml.hasError()) {
|
||||
xml.readNext();
|
||||
|
||||
if(xml.name() == "name"){
|
||||
if(xml.readElementText() == "3DMode"){
|
||||
if(xml.name() == "name") {
|
||||
if(xml.readElementText() == "3DMode") {
|
||||
xml.readNext();
|
||||
if(xml.name() == "value"){
|
||||
if(xml.name() == "value") {
|
||||
m_is3DMode = QVariant(xml.readElementText()).toBool();
|
||||
}
|
||||
}
|
||||
@ -458,4 +375,3 @@ void TvDevice::eventOccured(const QByteArray &data)
|
||||
|
||||
emit statusChanged();
|
||||
}
|
||||
|
||||
|
||||
@ -33,12 +33,13 @@
|
||||
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "tveventhandler.h"
|
||||
#include "hardware/upnpdiscovery/upnpdevice.h"
|
||||
|
||||
class TvDevice : public QObject
|
||||
class TvDevice : public UpnpDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TvDevice(QObject *parent = 0);
|
||||
explicit TvDevice(QObject *parent = 0, UpnpDeviceDescriptor upnpDeviceDescriptor = UpnpDeviceDescriptor());
|
||||
|
||||
enum RemoteKey{
|
||||
Power = 1,
|
||||
@ -110,37 +111,13 @@ public:
|
||||
};
|
||||
|
||||
// propertys
|
||||
void setLocation(const QUrl &location);
|
||||
QUrl location() const;
|
||||
|
||||
void setHostAddress(const QHostAddress &hostAddress);
|
||||
QHostAddress hostAddress() const;
|
||||
|
||||
void setPort(const int &port);
|
||||
int port() const;
|
||||
|
||||
void setName(const QString &name);
|
||||
QString name() const;
|
||||
|
||||
void setModelName(const QString &modelName);
|
||||
QString modelName() const;
|
||||
|
||||
void setManufacturer(const QString &manufacturer);
|
||||
QString manufacturer() const;
|
||||
|
||||
void setDeviceType(const QString &deviceType);
|
||||
QString deviceType() const;
|
||||
|
||||
void setUuid(const QString &uuid);
|
||||
QString uuid() const;
|
||||
|
||||
void setKey(const QString &key);
|
||||
QString key() const;
|
||||
|
||||
bool paired() const;
|
||||
|
||||
// States
|
||||
bool reachable() const;
|
||||
bool isReachable() const;
|
||||
bool is3DMode() const;
|
||||
int volumeLevel() const;
|
||||
bool mute() const;
|
||||
@ -160,14 +137,6 @@ public:
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
QUrl m_location;
|
||||
QHostAddress m_hostAddress;
|
||||
int m_port;
|
||||
QString m_name;
|
||||
QString m_modelName;
|
||||
QString m_manufacturer;
|
||||
QString m_deviceType;
|
||||
QString m_uuid;
|
||||
QString m_key;
|
||||
bool m_pairingStatus;
|
||||
|
||||
@ -210,8 +179,6 @@ private slots:
|
||||
void replyFinished(QNetworkReply *reply);
|
||||
void eventOccured(const QByteArray &data);
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // TVDEVICE_H
|
||||
|
||||
@ -1,292 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh 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, version 2 of the License. *
|
||||
* *
|
||||
* Guh 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 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tvdiscovery.h"
|
||||
|
||||
TvDiscovery::TvDiscovery(QObject *parent) :
|
||||
QUdpSocket(parent)
|
||||
{
|
||||
m_timeout = new QTimer(this);
|
||||
m_timeout->setSingleShot(true);
|
||||
connect(m_timeout,SIGNAL(timeout()),this,SLOT(discoverTimeout()));
|
||||
|
||||
m_manager = new QNetworkAccessManager(this);
|
||||
connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
|
||||
|
||||
m_port = 1900;
|
||||
m_host = QHostAddress("239.255.255.250");
|
||||
setSocketOption(QAbstractSocket::MulticastTtlOption,QVariant(1));
|
||||
setSocketOption(QAbstractSocket::MulticastLoopbackOption,QVariant(1));
|
||||
bind(QHostAddress::AnyIPv4,m_port,QUdpSocket::ShareAddress);
|
||||
joinMulticastGroup(m_host);
|
||||
connect(this,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error(QAbstractSocket::SocketError)));
|
||||
connect(this,SIGNAL(readyRead()),this,SLOT(readData()));
|
||||
}
|
||||
|
||||
bool TvDiscovery::checkXmlData(QByteArray data)
|
||||
{
|
||||
QByteArray xmlOut;
|
||||
QXmlStreamReader reader(data);
|
||||
QXmlStreamWriter writer(&xmlOut);
|
||||
writer.setAutoFormatting(true);
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
if (!reader.isWhitespace()) {
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
}
|
||||
if(reader.hasError()){
|
||||
qDebug() << "ERROR reading XML device information: " << reader.errorString();
|
||||
qDebug() << "--------------------------------------------";
|
||||
return false;
|
||||
}
|
||||
m_deviceInformationData = xmlOut;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString TvDiscovery::printXmlData(QByteArray data)
|
||||
{
|
||||
QString xmlOut;
|
||||
QXmlStreamReader reader(data);
|
||||
QXmlStreamWriter writer(&xmlOut);
|
||||
writer.setAutoFormatting(true);
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
if (!reader.isWhitespace()) {
|
||||
writer.writeCurrentToken(reader);
|
||||
}
|
||||
}
|
||||
if(reader.hasError()){
|
||||
qDebug() << "ERROR reading XML device information: " << reader.errorString();
|
||||
qDebug() << "--------------------------------------------";
|
||||
}
|
||||
return xmlOut;
|
||||
}
|
||||
|
||||
|
||||
void TvDiscovery::error(QAbstractSocket::SocketError error)
|
||||
{
|
||||
qWarning() << errorString() << error;
|
||||
}
|
||||
|
||||
void TvDiscovery::readData()
|
||||
{
|
||||
QByteArray data;
|
||||
QHostAddress sender;
|
||||
quint16 udpPort;
|
||||
|
||||
// read the answere from the multicast
|
||||
while (hasPendingDatagrams()) {
|
||||
data.resize(pendingDatagramSize());
|
||||
readDatagram(data.data(), data.size(), &sender, &udpPort);
|
||||
}
|
||||
|
||||
if(data.size() > 0){
|
||||
if(data.contains("HTTP/1.1 200 OK")){
|
||||
const QStringList lines = QString(data).split("\r\n");
|
||||
|
||||
QUrl location;
|
||||
QString uuid;
|
||||
QString server;
|
||||
|
||||
foreach( const QString& line, lines){
|
||||
int separatorIndex = line.indexOf(':');
|
||||
QString key = line.left(separatorIndex).toUpper();
|
||||
QString value = line.mid(separatorIndex+1).trimmed();
|
||||
|
||||
// get location
|
||||
if(key.contains("LOCATION")){
|
||||
location = QUrl(value);
|
||||
}
|
||||
|
||||
// get server info
|
||||
if(key.contains("SERVER")){
|
||||
// check if it is a LG Smart Tv with UDAP/2.0 protocoll
|
||||
if(value.contains("UDAP/2.0")){
|
||||
server = value;
|
||||
}
|
||||
}
|
||||
|
||||
// get uuid
|
||||
if(key.contains("USN")){
|
||||
int startIndex = value.indexOf(":");
|
||||
int endIndex = value.indexOf("::");
|
||||
uuid = value.mid(startIndex +1 ,(endIndex - startIndex)-1);
|
||||
}
|
||||
|
||||
if(!location.isEmpty() && !uuid.isEmpty() && !server.isEmpty()){
|
||||
foreach (TvDevice *device, m_tvList) {
|
||||
if(device->uuid() == uuid){
|
||||
return;
|
||||
}
|
||||
}
|
||||
TvDevice *device = new TvDevice(this);
|
||||
device->setLocation(location);
|
||||
device->setHostAddress(sender);
|
||||
device->setUuid(uuid);
|
||||
|
||||
m_tvList.append(device);
|
||||
requestDeviceInformation(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TvDiscovery::discoverTimeout()
|
||||
{
|
||||
emit discoveryDone(m_tvList);
|
||||
}
|
||||
|
||||
void TvDiscovery::requestDeviceInformation(TvDevice *device)
|
||||
{
|
||||
|
||||
QNetworkRequest deviceRequest;
|
||||
deviceRequest.setUrl(device->location());
|
||||
deviceRequest.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("text/xml"));
|
||||
deviceRequest.setHeader(QNetworkRequest::UserAgentHeader,QVariant("UDAP/2.0"));
|
||||
|
||||
m_deviceInformationReplay = m_manager->get(deviceRequest);
|
||||
}
|
||||
|
||||
void TvDiscovery::replyFinished(QNetworkReply *reply)
|
||||
{
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QByteArray data;
|
||||
|
||||
switch (status) {
|
||||
case(200):
|
||||
data = reply->readAll();
|
||||
if(checkXmlData(data)){
|
||||
parseDeviceInformation(data);
|
||||
}
|
||||
break;
|
||||
case(400):
|
||||
qDebug() << "ERROR: 400 Bad request. The event format is not valid or it has an incorrect value.";
|
||||
qDebug() << "--------------------------------------------";
|
||||
return;
|
||||
case(401):
|
||||
qDebug() << "ERROR: 401 Unauthorized. An event is sent when a Host and a Controller are not paired.";
|
||||
qDebug() << "--------------------------------------------";
|
||||
return;
|
||||
case(404):
|
||||
qDebug() << "ERROR: 404 Not Found. The POST path of an event is incorrect.";
|
||||
qDebug() << "--------------------------------------------";
|
||||
return;
|
||||
case(500):
|
||||
qDebug() << "ERROR: 500 Internal Server Error. Event Execution Failure.";
|
||||
qDebug() << "--------------------------------------------";
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TvDiscovery::parseDeviceInformation(QByteArray data)
|
||||
{
|
||||
|
||||
QXmlStreamReader xml(data);
|
||||
|
||||
QString name;
|
||||
QString uuid;
|
||||
QString modelName;
|
||||
QString deviceType;
|
||||
QString manufacturer;
|
||||
int port;
|
||||
|
||||
qDebug() << printXmlData(data);
|
||||
|
||||
while(!xml.atEnd() && !xml.hasError()){
|
||||
xml.readNext();
|
||||
|
||||
if(xml.isStartDocument()){
|
||||
continue;
|
||||
}
|
||||
if(xml.isStartElement()){
|
||||
if(xml.name() == "envelope"){
|
||||
continue;
|
||||
}
|
||||
//check if we have device part of message
|
||||
if(xml.name() == "device"){
|
||||
// seems to be device information
|
||||
while(!xml.atEnd()){
|
||||
if(xml.name() == "deviceType" && xml.isStartElement()){
|
||||
deviceType = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "modelName" && xml.isStartElement()){
|
||||
modelName = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "friendlyName" && xml.isStartElement()){
|
||||
name = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "manufacturer" && xml.isStartElement()){
|
||||
manufacturer = xml.readElementText();
|
||||
}
|
||||
if(xml.name() == "uuid" && xml.isStartElement()){
|
||||
uuid = xml.readElementText();
|
||||
}
|
||||
//check if we have port part of message
|
||||
if(xml.name() == "port"){
|
||||
port = xml.readElementText().toInt();
|
||||
}
|
||||
|
||||
xml.readNext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
foreach (TvDevice *device, m_tvList) {
|
||||
// find our device with this uuid
|
||||
if(device->uuid() == uuid){
|
||||
device->setName(name);
|
||||
device->setModelName(modelName);
|
||||
device->setDeviceType(deviceType);
|
||||
device->setManufacturer(manufacturer);
|
||||
device->setPort(port);
|
||||
|
||||
qDebug() << "--> fetched TV information...";
|
||||
qDebug() << "name: " << device->name();
|
||||
qDebug() << "model name: " << device->modelName();
|
||||
qDebug() << "device type: " << device->deviceType();
|
||||
qDebug() << "manufacturer: " << device->manufacturer();
|
||||
qDebug() << "address: " << device->hostAddress().toString();
|
||||
qDebug() << "port: " << device->port();
|
||||
qDebug() << "location: " << device->location().toString();
|
||||
qDebug() << "uuid: " << device->uuid();
|
||||
qDebug() << "--------------------------------------------";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TvDiscovery::discover(int timeout)
|
||||
{
|
||||
QString searchMessage("M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST:239.255.255.250:1900\r\n"
|
||||
"MAN:\"ssdp:discover\"\r\n"
|
||||
"MX:2\r\n"
|
||||
"ST:udap:rootservice\r\n"
|
||||
"USER-AGENT: UDAP/2.0 \r\n\r\n");
|
||||
|
||||
m_tvList.clear();
|
||||
writeDatagram(searchMessage.toUtf8(),m_host,m_port);
|
||||
m_timeout->start(timeout);
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh 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, version 2 of the License. *
|
||||
* *
|
||||
* Guh 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 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TVDISCOVERY_H
|
||||
#define TVDISCOVERY_H
|
||||
|
||||
#include <QUdpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QTimer>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QXmlStreamAttributes>
|
||||
|
||||
#include "tvdevice.h"
|
||||
|
||||
class TvDiscovery : public QUdpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TvDiscovery(QObject *parent = 0);
|
||||
|
||||
private:
|
||||
QHostAddress m_host;
|
||||
qint16 m_port;
|
||||
|
||||
QTimer *m_timeout;
|
||||
QList<TvDevice*> m_tvList;
|
||||
|
||||
QNetworkAccessManager *m_manager;
|
||||
QNetworkReply *m_deviceInformationReplay;
|
||||
|
||||
QByteArray m_deviceInformationData;
|
||||
bool checkXmlData(QByteArray data);
|
||||
QString printXmlData(QByteArray data);
|
||||
|
||||
signals:
|
||||
void discoveryDone(const QList<TvDevice*> deviceList);
|
||||
|
||||
private slots:
|
||||
void error(QAbstractSocket::SocketError error);
|
||||
void readData();
|
||||
void discoverTimeout();
|
||||
|
||||
void requestDeviceInformation(TvDevice *device);
|
||||
void replyFinished(QNetworkReply *reply);
|
||||
void parseDeviceInformation(QByteArray data);
|
||||
|
||||
public slots:
|
||||
void discover(int timeout);
|
||||
|
||||
};
|
||||
|
||||
#endif // TVDISCOVERY_H
|
||||
@ -51,14 +51,29 @@
|
||||
#include <QStringList>
|
||||
#include <QColor>
|
||||
|
||||
DevicePluginPhilipsHue::DevicePluginPhilipsHue():
|
||||
m_discovery(new Discovery(this))
|
||||
{
|
||||
connect(m_discovery, &Discovery::discoveryDone, this, &DevicePluginPhilipsHue::discoveryDone);
|
||||
VendorId hueVendorId = VendorId("");
|
||||
|
||||
m_bridge = new HueBridgeConnection(this);
|
||||
connect(m_bridge, &HueBridgeConnection::createUserFinished, this, &DevicePluginPhilipsHue::createUserFinished);
|
||||
connect(m_bridge, &HueBridgeConnection::getFinished, this, &DevicePluginPhilipsHue::getFinished);
|
||||
DeviceClassId hueDeviceClassId = DeviceClassId("d8f4c397-e05e-47c1-8917-8e72d4d0d47c");
|
||||
|
||||
StateTypeId hueColorStateTypeId = StateTypeId("d25423e7-b924-4b20-80b6-77eecc65d089");
|
||||
ActionTypeId hueSetColorActionTypeId = ActionTypeId("29cc299a-818b-47b2-817f-c5a6361545e4");
|
||||
|
||||
StateTypeId huePowerStateTypeId = StateTypeId("6ac64eee-f356-4ae4-bc85-8c1244d12b02");
|
||||
ActionTypeId hueSetPowerActionTypeId = ActionTypeId("7782d91e-d73a-4321-8828-da768e2f6827");
|
||||
|
||||
StateTypeId hueBrightnessStateTypeId = StateTypeId("411f489c-4bc9-42f7-b47d-b0581dc0c29e");
|
||||
ActionTypeId hueSetBrightnessActionTypeId = ActionTypeId("3bc95552-cba0-4222-abd5-9b668132e442");
|
||||
|
||||
StateTypeId hueReachableStateTypeId = StateTypeId("15794d26-fde8-4a61-8f83-d7830534975f");
|
||||
|
||||
DevicePluginPhilipsHue::DevicePluginPhilipsHue()
|
||||
//:m_discovery(new Discovery(this))
|
||||
{
|
||||
// connect(m_discovery, &Discovery::discoveryDone, this, &DevicePluginPhilipsHue::discoveryDone);
|
||||
|
||||
// m_bridge = new HueBridgeConnection(this);
|
||||
// connect(m_bridge, &HueBridgeConnection::createUserFinished, this, &DevicePluginPhilipsHue::createUserFinished);
|
||||
// connect(m_bridge, &HueBridgeConnection::getFinished, this, &DevicePluginPhilipsHue::getFinished);
|
||||
}
|
||||
|
||||
DeviceManager::HardwareResources DevicePluginPhilipsHue::requiredHardware() const
|
||||
|
||||
@ -53,9 +53,9 @@
|
||||
|
||||
DevicePluginWemo::DevicePluginWemo()
|
||||
{
|
||||
m_discovery = new WemoDiscovery(this);
|
||||
// m_discovery = new WemoDiscovery(this);
|
||||
|
||||
connect(m_discovery,SIGNAL(discoveryDone(QList<WemoSwitch*>)),this,SLOT(discoveryDone(QList<WemoSwitch*>)));
|
||||
// connect(m_discovery,SIGNAL(discoveryDone(QList<WemoSwitch*>)),this,SLOT(discoveryDone(QList<WemoSwitch*>)));
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginWemo::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||
|
||||
Reference in New Issue
Block a user