added kodi connection and jsonhandler
This commit is contained in:
parent
ceaad7c7fd
commit
1f35f78238
2
debian/guh-plugins.install
vendored
2
debian/guh-plugins.install
vendored
@ -17,3 +17,5 @@ usr/lib/guh/plugins/libguh_devicepluginunitec.so
|
|||||||
usr/lib/guh/plugins/libguh_devicepluginleynew.so
|
usr/lib/guh/plugins/libguh_devicepluginleynew.so
|
||||||
usr/lib/guh/plugins/libguh_deviceplugintune.so
|
usr/lib/guh/plugins/libguh_deviceplugintune.so
|
||||||
usr/lib/guh/plugins/libguh_devicepluginudpcommander.so
|
usr/lib/guh/plugins/libguh_devicepluginudpcommander.so
|
||||||
|
usr/lib/guh/plugins/libguh_devicepluginkodi.so
|
||||||
|
|
||||||
|
|||||||
@ -48,3 +48,4 @@ Q_LOGGING_CATEGORY(dcUdpCommander, "UdpCommander")
|
|||||||
Q_LOGGING_CATEGORY(dcWakeOnLan, "WakeOnLan")
|
Q_LOGGING_CATEGORY(dcWakeOnLan, "WakeOnLan")
|
||||||
Q_LOGGING_CATEGORY(dcWemo, "Wemo")
|
Q_LOGGING_CATEGORY(dcWemo, "Wemo")
|
||||||
Q_LOGGING_CATEGORY(dcWifiDetector, "WifiDetector")
|
Q_LOGGING_CATEGORY(dcWifiDetector, "WifiDetector")
|
||||||
|
Q_LOGGING_CATEGORY(dcKodi, "Kodi")
|
||||||
|
|||||||
@ -53,6 +53,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcUdpCommander)
|
|||||||
Q_DECLARE_LOGGING_CATEGORY(dcWakeOnLan)
|
Q_DECLARE_LOGGING_CATEGORY(dcWakeOnLan)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcWemo)
|
Q_DECLARE_LOGGING_CATEGORY(dcWemo)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcWifiDetector)
|
Q_DECLARE_LOGGING_CATEGORY(dcWifiDetector)
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcKodi)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,8 @@
|
|||||||
\ingroup plugins
|
\ingroup plugins
|
||||||
\ingroup network
|
\ingroup network
|
||||||
|
|
||||||
|
TODO: description
|
||||||
|
|
||||||
|
|
||||||
\chapter Plugin properties
|
\chapter Plugin properties
|
||||||
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
||||||
@ -45,6 +47,7 @@
|
|||||||
#include "devicepluginkodi.h"
|
#include "devicepluginkodi.h"
|
||||||
#include "plugin/device.h"
|
#include "plugin/device.h"
|
||||||
#include "plugininfo.h"
|
#include "plugininfo.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
DevicePluginKodi::DevicePluginKodi()
|
DevicePluginKodi::DevicePluginKodi()
|
||||||
{
|
{
|
||||||
@ -53,52 +56,85 @@ DevicePluginKodi::DevicePluginKodi()
|
|||||||
|
|
||||||
DeviceManager::HardwareResources DevicePluginKodi::requiredHardware() const
|
DeviceManager::HardwareResources DevicePluginKodi::requiredHardware() const
|
||||||
{
|
{
|
||||||
return DeviceManager::HardwareResourceNone;
|
return DeviceManager::HardwareResourceTimer | DeviceManager::HardwareResourceUpnpDisovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceManager::DeviceSetupStatus DevicePluginKodi::setupDevice(Device *device)
|
DeviceManager::DeviceSetupStatus DevicePluginKodi::setupDevice(Device *device)
|
||||||
{
|
{
|
||||||
Q_UNUSED(device)
|
KodiConnection *kodiConnection = new KodiConnection(QHostAddress(device->paramValue("ip").toString()), 9090, this);
|
||||||
|
|
||||||
|
connect(kodiConnection, &KodiConnection::connectionStateChanged, this, &DevicePluginKodi::onConnectionChanged);
|
||||||
|
|
||||||
|
kodiConnection->connectToKodi();
|
||||||
|
|
||||||
|
m_kodiConnections.insert(kodiConnection, device);
|
||||||
return DeviceManager::DeviceSetupStatusSuccess;
|
return DeviceManager::DeviceSetupStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::deviceRemoved(Device *device)
|
void DevicePluginKodi::deviceRemoved(Device *device)
|
||||||
{
|
{
|
||||||
Q_UNUSED(device)
|
KodiConnection *kodiConnection = m_kodiConnections.key(device);
|
||||||
|
m_kodiConnections.remove(kodiConnection);
|
||||||
|
qCDebug(dcKodi) << "delete Kodi" << device->paramValue("name");
|
||||||
|
kodiConnection->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceManager::DeviceSetupStatus DevicePluginKodi::confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
|
||||||
{
|
|
||||||
Q_UNUSED(pairingTransactionId)
|
|
||||||
Q_UNUSED(deviceClassId)
|
|
||||||
Q_UNUSED(params)
|
|
||||||
|
|
||||||
return DeviceManager::DeviceSetupStatusSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceManager::DeviceError DevicePluginKodi::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
DeviceManager::DeviceError DevicePluginKodi::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||||
{
|
{
|
||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
Q_UNUSED(deviceClassId)
|
Q_UNUSED(deviceClassId)
|
||||||
|
qCDebug(dcKodi) << "start Kodi UPnP search";
|
||||||
upnpDiscover();
|
upnpDiscover();
|
||||||
|
return DeviceManager::DeviceErrorAsync;
|
||||||
return DeviceManager::DeviceErrorNoError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList)
|
void DevicePluginKodi::upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList)
|
||||||
{
|
{
|
||||||
Q_UNUSED(upnpDeviceDescriptorList)
|
QList<DeviceDescriptor> deviceDescriptors;
|
||||||
|
foreach (const UpnpDeviceDescriptor &upnpDescriptor, upnpDeviceDescriptorList) {
|
||||||
|
if (upnpDescriptor.modelName().contains("Kodi")) {
|
||||||
|
qCDebug(dcKodi) << upnpDescriptor;
|
||||||
|
DeviceDescriptor deviceDescriptor(kodiDeviceClassId, "Kodi - Media Center", upnpDescriptor.hostAddress().toString());
|
||||||
|
ParamList params;
|
||||||
|
params.append(Param("name", upnpDescriptor.friendlyName()));
|
||||||
|
params.append(Param("ip", upnpDescriptor.hostAddress().toString()));
|
||||||
|
params.append(Param("port", 9090));
|
||||||
|
deviceDescriptor.setParams(params);
|
||||||
|
deviceDescriptors.append(deviceDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit devicesDiscovered(kodiDeviceClassId, deviceDescriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::networkManagerReplyReady(QNetworkReply *reply)
|
DeviceManager::DeviceError DevicePluginKodi::executeAction(Device *device, const Action &action)
|
||||||
{
|
{
|
||||||
Q_UNUSED(reply)
|
if (device->deviceClassId() == kodiDeviceClassId) {
|
||||||
|
if (action.actionTypeId() == sendNotificationActionTypeId) {
|
||||||
|
|
||||||
|
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == volumeActionTypeId) {
|
||||||
|
|
||||||
|
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
}
|
||||||
|
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||||
|
}
|
||||||
|
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginKodi::guhTimer()
|
void DevicePluginKodi::onConnectionChanged(const bool &connected)
|
||||||
{
|
{
|
||||||
|
KodiConnection *kodiConnection = static_cast<KodiConnection *>(sender());
|
||||||
|
Device *device = m_kodiConnections.value(kodiConnection);
|
||||||
|
|
||||||
|
device->setStateValue(connectedStateTypeId, connected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DevicePluginKodi::dataReceived(const QByteArray &data)
|
||||||
|
{
|
||||||
|
KodiConnection *kodiConnection = static_cast<KodiConnection *>(sender());
|
||||||
|
emit dataReady(kodiConnection, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,9 +22,11 @@
|
|||||||
#define DEVICEPLUGINKODI_H
|
#define DEVICEPLUGINKODI_H
|
||||||
|
|
||||||
#include "plugin/deviceplugin.h"
|
#include "plugin/deviceplugin.h"
|
||||||
|
#include "kodiconnection.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
|
||||||
class DevicePluginKodi : public DevicePlugin
|
class DevicePluginKodi : public DevicePlugin
|
||||||
{
|
{
|
||||||
@ -39,16 +41,20 @@ public:
|
|||||||
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||||
void deviceRemoved(Device *device) override;
|
void deviceRemoved(Device *device) override;
|
||||||
|
|
||||||
DeviceManager::DeviceSetupStatus confirmPairing(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
|
||||||
|
|
||||||
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
||||||
void upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList) override;
|
void upnpDiscoveryFinished(const QList<UpnpDeviceDescriptor> &upnpDeviceDescriptorList) override;
|
||||||
void networkManagerReplyReady(QNetworkReply *reply) override;
|
|
||||||
void guhTimer() override;
|
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QHash<KodiConnection *, Device *> m_kodiConnections;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void dataReady(KodiConnection *kodiConnection, const QByteArray &data);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void onConnectionChanged(const bool &connected);
|
||||||
|
void dataReceived(const QByteArray &data);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,60 @@
|
|||||||
"deviceClasses": [
|
"deviceClasses": [
|
||||||
{
|
{
|
||||||
"deviceClassId": "d09953e3-c5bd-415b-973b-0d0bf2be3f69",
|
"deviceClassId": "d09953e3-c5bd-415b-973b-0d0bf2be3f69",
|
||||||
|
"idName": "kodi",
|
||||||
"name": "Kodi",
|
"name": "Kodi",
|
||||||
"createMethods": ["discovery"],
|
"createMethods": ["user", "discovery"],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "TextLine"
|
"inputType": "TextLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ip",
|
||||||
|
"type" : "QString",
|
||||||
|
"inputType": "IPv4Address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "port",
|
||||||
|
"type" : "int"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "09dfbd40-c97c-4a20-9ecd-f80e389a4864",
|
||||||
|
"idName": "connected",
|
||||||
|
"name": "connected",
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bc98cdb0-4d0e-48ca-afc7-922e49bb7813",
|
||||||
|
"idName": "mute",
|
||||||
|
"name": "mute",
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9dfe5d78-4c3f-497c-bab1-bb9fdf7e93a9",
|
||||||
|
"idName": "volume",
|
||||||
|
"name": "volume",
|
||||||
|
"unit": "Percentage",
|
||||||
|
"type": "int",
|
||||||
|
"writable": true,
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actionTypes": [
|
||||||
|
{
|
||||||
|
"id": "dc0aa3b5-4eae-4e58-a4ac-d4c124da53f1",
|
||||||
|
"idName": "sendNotification",
|
||||||
|
"name": "send notification",
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"name": "message",
|
||||||
|
"type": "QString"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
6
plugins/deviceplugins/kodi/jsonhandler.cpp
Normal file
6
plugins/deviceplugins/kodi/jsonhandler.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "jsonhandler.h"
|
||||||
|
|
||||||
|
JsonHandler::JsonHandler(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
18
plugins/deviceplugins/kodi/jsonhandler.h
Normal file
18
plugins/deviceplugins/kodi/jsonhandler.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef JSONHANDLER_H
|
||||||
|
#define JSONHANDLER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class JsonHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit JsonHandler(QObject *parent = 0);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JSONHANDLER_H
|
||||||
@ -3,8 +3,12 @@ include(../../plugins.pri)
|
|||||||
TARGET = $$qtLibraryTarget(guh_devicepluginkodi)
|
TARGET = $$qtLibraryTarget(guh_devicepluginkodi)
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
devicepluginkodi.cpp
|
devicepluginkodi.cpp \
|
||||||
|
kodiconnection.cpp \
|
||||||
|
jsonhandler.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
devicepluginkodi.h
|
devicepluginkodi.h \
|
||||||
|
kodiconnection.h \
|
||||||
|
jsonhandler.h
|
||||||
|
|
||||||
|
|||||||
85
plugins/deviceplugins/kodi/kodiconnection.cpp
Normal file
85
plugins/deviceplugins/kodi/kodiconnection.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "kodiconnection.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
|
KodiConnection::KodiConnection(const QHostAddress &hostAddress, const int &port, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_hostAddress(hostAddress),
|
||||||
|
m_port(port)
|
||||||
|
{
|
||||||
|
m_socket = new QTcpSocket(this);
|
||||||
|
|
||||||
|
connect(m_socket, &QTcpSocket::connected, this, &KodiConnection::onConnected);
|
||||||
|
connect(m_socket, &QTcpSocket::disconnected, this, &KodiConnection::onDisconnected);
|
||||||
|
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
|
||||||
|
connect(m_socket, &QTcpSocket::readyRead, this, &KodiConnection::readData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::connectToKodi()
|
||||||
|
{
|
||||||
|
m_socket->connectToHost(m_hostAddress, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::disconnectFromKodi()
|
||||||
|
{
|
||||||
|
m_socket->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHostAddress KodiConnection::hostAddress() const
|
||||||
|
{
|
||||||
|
return m_hostAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
int KodiConnection::port() const
|
||||||
|
{
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::onConnected()
|
||||||
|
{
|
||||||
|
qCDebug(dcKodi) << "connected successfully to" << hostAddress().toString() << port();
|
||||||
|
emit connectionStateChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::onDisconnected()
|
||||||
|
{
|
||||||
|
qCDebug(dcKodi) << "disconnected from" << hostAddress().toString() << port();
|
||||||
|
emit connectionStateChanged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::onError(QAbstractSocket::SocketError socketError)
|
||||||
|
{
|
||||||
|
qCWarning(dcKodi) << "socket error:" << socketError << m_socket->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::readData()
|
||||||
|
{
|
||||||
|
QByteArray data = m_socket->readAll();
|
||||||
|
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
|
||||||
|
if(error.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(dcKodi) << "failed to parse JSON data:" << data << ":" << error.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qCDebug(dcKodi) << "data received:" << jsonDoc.toJson();
|
||||||
|
|
||||||
|
unsigned short m_IconSize;
|
||||||
|
emit dataReady(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KodiConnection::sendData(const QString &method, const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
QVariantMap package;
|
||||||
|
package.insert("id", m_id);
|
||||||
|
package.insert("method", method);
|
||||||
|
package.insert("params", params);
|
||||||
|
package.insert("jsonrpc", "2.0");
|
||||||
|
m_id++;
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromVariant(package);
|
||||||
|
qCDebug(dcKodi) << "sending data" << jsonDoc.toJson();
|
||||||
|
|
||||||
|
m_socket->write(jsonDoc.toJson());
|
||||||
|
}
|
||||||
|
|
||||||
45
plugins/deviceplugins/kodi/kodiconnection.h
Normal file
45
plugins/deviceplugins/kodi/kodiconnection.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef KODICONNECTION_H
|
||||||
|
#define KODICONNECTION_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
class KodiConnection : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit KodiConnection(const QHostAddress &hostAddress, const int &port = 9090, QObject *parent = 0);
|
||||||
|
|
||||||
|
void connectToKodi();
|
||||||
|
void disconnectFromKodi();
|
||||||
|
|
||||||
|
QHostAddress hostAddress() const;
|
||||||
|
int port() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHostAddress m_hostAddress;
|
||||||
|
int m_port;
|
||||||
|
int m_id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QTcpSocket *m_socket;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onConnected();
|
||||||
|
void onDisconnected();
|
||||||
|
void onError(QAbstractSocket::SocketError socketError);
|
||||||
|
void readData();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void connectionStateChanged(const bool &connected);
|
||||||
|
void dataReady(const QByteArray &data);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void sendData(const QString &method, const QVariantMap ¶ms = QVariantMap());
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KODICONNECTION_H
|
||||||
@ -81,6 +81,7 @@ int main(int argc, char *argv[])
|
|||||||
s_loggingFilters.insert("WakeOnLan", false);
|
s_loggingFilters.insert("WakeOnLan", false);
|
||||||
s_loggingFilters.insert("Wemo", false);
|
s_loggingFilters.insert("Wemo", false);
|
||||||
s_loggingFilters.insert("WifiDetector", false);
|
s_loggingFilters.insert("WifiDetector", false);
|
||||||
|
s_loggingFilters.insert("Kodi", true);
|
||||||
|
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
|
|||||||
Reference in New Issue
Block a user