Kodi: Automatically redetect Kodi when its IP address changes
parent
be230d9a3b
commit
8a074e3c37
|
|
@ -1,26 +1,21 @@
|
|||
# Kodi
|
||||
|
||||
This plugin allows you to controll the media center [Kodi](http://kodi.tv/). If you want to discover
|
||||
and control Kodi with nymea, you need to activate the remote access and the UPnP service.
|
||||
This plugin allows to integrate nymea with the [Kodi media center](http://kodi.tv/). The minimum requred version of
|
||||
Kodi is 13 (Gotham).
|
||||
|
||||
## Activate Zeroconf
|
||||
## Setup
|
||||
|
||||
In order to discover Kodi in the network, you need to activate the zeroconf serive in the Kodi settings:
|
||||
Is is required to enable the following settings in Kodi:
|
||||
|
||||
### Settings
|
||||
Navigate to Settings -> Services -> Control and activate "Alow Remote control via HTTP".
|
||||
|
||||

|
||||
If nymea and Kodi are installed on the same system, activate "Allow remote control from applications on this system" or if
|
||||
kodi is installed on a different system in the same network, activate "Allow remote control from applications on other systems".
|
||||
|
||||
### Settings - Services
|
||||
In addition, it is recommended to activate "Announce services to other systems" to allow nymea discovery the kodi setup automatically.
|
||||
|
||||

|
||||
Once those settings are activated, the kodi system can be added to nymea.
|
||||
|
||||
Activate zeroconf.
|
||||
|
||||
## Activate "Remote Control"
|
||||
In order to control Kodi over the network with nymea, you need to activate the remote control permissions:
|
||||
|
||||
### Settings - Services - Remote Control
|
||||
Activate all options.
|
||||
|
||||

|
||||
Note: If ZeroConf cannot be used, the device can be added manually and at least the IP, Port and HTTP Port parameters must be given.
|
||||
It is recommended to configure the Kodi system to a static IP if the manual setup with IP is used. When using discovery, nymea
|
||||
will re-detect kodi when its IP address changes.
|
||||
|
|
|
|||
|
|
@ -52,10 +52,15 @@ DevicePluginKodi::DevicePluginKodi()
|
|||
DevicePluginKodi::~DevicePluginKodi()
|
||||
{
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
||||
delete m_serviceBrowser;
|
||||
delete m_httpServiceBrowser;
|
||||
}
|
||||
|
||||
void DevicePluginKodi::init()
|
||||
{
|
||||
m_serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_xbmc-jsonrpc._tcp");
|
||||
m_httpServiceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_http._tcp");
|
||||
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginKodi::onPluginTimer);
|
||||
}
|
||||
|
|
@ -64,9 +69,62 @@ void DevicePluginKodi::setupDevice(DeviceSetupInfo *info)
|
|||
{
|
||||
Device *device = info->device();
|
||||
qCDebug(dcKodi) << "Setup Kodi device" << device->paramValue(kodiDeviceIpParamTypeId).toString();
|
||||
|
||||
QUuid kodiUuid = device->paramValue(kodiDeviceUuidParamTypeId).toUuid();
|
||||
|
||||
// The IP string is optional, we'll try to discover it in any case via zeroconf, however, if it's
|
||||
// set in the params, we'll always fall back to that in case we can't find it on zeroconf.
|
||||
|
||||
// The recommended way is to not store an IP in the settings as with DHCP lease times (or IPv6 privacy
|
||||
// extension address randomization) an IP might expire eventually and it'll stop working.
|
||||
|
||||
// So actually the params should *only* store the UUID, but we'll support manually entering IP, port and http port
|
||||
// for setups that can't use ZeroConf for whatever reason.
|
||||
|
||||
QString ipString = device->paramValue(kodiDeviceIpParamTypeId).toString();
|
||||
int port = device->paramValue(kodiDevicePortParamTypeId).toInt();
|
||||
int httpPort = device->paramValue(kodiDeviceHttpPortParamTypeId).toInt();
|
||||
|
||||
if (!kodiUuid.isNull()) {
|
||||
foreach (const ZeroConfServiceEntry &entry, m_serviceBrowser->serviceEntries()) {
|
||||
QString uuid;
|
||||
foreach (const QString &txt, entry.txt()) {
|
||||
if (txt.startsWith("uuid")) {
|
||||
uuid = txt.split("=").last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (QUuid(uuid) == kodiUuid) {
|
||||
ipString = entry.hostAddress().toString();
|
||||
port = entry.port();
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, m_httpServiceBrowser->serviceEntries()) {
|
||||
QString uuid;
|
||||
foreach (const QString &txt, avahiEntry.txt()) {
|
||||
if (txt.startsWith("uuid")) {
|
||||
uuid = txt.split("=").last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (QUuid(uuid) == kodiUuid) {
|
||||
httpPort = avahiEntry.port();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ipString.isEmpty()) {
|
||||
// Ok, we could not find an ip on zeroconf... Let's try again in a second while setupInfo hasn't timed out.
|
||||
qCDebug(dcKodi()) << "Device not found via ZeroConf... Waiting for a second for it to appear...";
|
||||
QTimer::singleShot(1000, info, [this, info](){
|
||||
setupDevice(info);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Kodi *kodi= new Kodi(QHostAddress(ipString), port, httpPort, this);
|
||||
|
||||
connect(kodi, &Kodi::connectionStatusChanged, this, &DevicePluginKodi::onConnectionChanged);
|
||||
|
|
@ -147,18 +205,11 @@ void DevicePluginKodi::deviceRemoved(Device *device)
|
|||
|
||||
void DevicePluginKodi::discoverDevices(DeviceDiscoveryInfo *info)
|
||||
{
|
||||
|
||||
ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_xbmc-jsonrpc._tcp");
|
||||
connect(info, &QObject::destroyed, serviceBrowser, &QObject::deleteLater);
|
||||
|
||||
ZeroConfServiceBrowser *httpServiceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_http._tcp");
|
||||
connect(info, &QObject::destroyed, httpServiceBrowser, &QObject::deleteLater);
|
||||
|
||||
QTimer::singleShot(5000, info, [this, info, serviceBrowser, httpServiceBrowser](){
|
||||
QTimer::singleShot(5000, info, [this, info](){
|
||||
|
||||
QHash<QString, DeviceDescriptor> descriptors;
|
||||
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, serviceBrowser->serviceEntries()) {
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, m_serviceBrowser->serviceEntries()) {
|
||||
|
||||
QString uuid;
|
||||
foreach (const QString &txt, avahiEntry.txt()) {
|
||||
|
|
@ -176,9 +227,9 @@ void DevicePluginKodi::discoverDevices(DeviceDiscoveryInfo *info)
|
|||
qCDebug(dcKodi) << "Zeroconf entry:" << avahiEntry;
|
||||
DeviceDescriptor descriptor(kodiDeviceClassId, avahiEntry.name(), avahiEntry.hostName() + " (" + avahiEntry.hostAddress().toString() + ")");
|
||||
ParamList params;
|
||||
params << Param(kodiDeviceIpParamTypeId, avahiEntry.hostAddress().toString());
|
||||
params << Param(kodiDevicePortParamTypeId, avahiEntry.port());
|
||||
params << Param(kodiDeviceUuidParamTypeId, uuid);
|
||||
// params << Param(kodiDeviceIpParamTypeId, avahiEntry.hostAddress().toString());
|
||||
params << Param(kodiDevicePortParamTypeId, avahiEntry.port());
|
||||
descriptor.setParams(params);
|
||||
|
||||
Devices existing = myDevices().filterByParam(kodiDeviceUuidParamTypeId, uuid);
|
||||
|
|
@ -189,8 +240,8 @@ void DevicePluginKodi::discoverDevices(DeviceDiscoveryInfo *info)
|
|||
descriptors.insert(uuid, descriptor);
|
||||
}
|
||||
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, httpServiceBrowser->serviceEntries()) {
|
||||
// qCDebug(dcKodi) << "Zeroconf http entry:" << avahiEntry;
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, m_httpServiceBrowser->serviceEntries()) {
|
||||
qCDebug(dcKodi) << "Zeroconf http entry:" << avahiEntry;
|
||||
QString uuid;
|
||||
foreach (const QString &txt, avahiEntry.txt()) {
|
||||
if (txt.startsWith("uuid")) {
|
||||
|
|
@ -209,7 +260,6 @@ void DevicePluginKodi::discoverDevices(DeviceDiscoveryInfo *info)
|
|||
descriptors[uuid] = descriptor;
|
||||
}
|
||||
|
||||
|
||||
foreach (const DeviceDescriptor &d, descriptors.values()) {
|
||||
qCDebug(dcKodi()) << "Returning descritpor:" << d.params();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include <QDebug>
|
||||
#include <QTcpSocket>
|
||||
|
||||
class ZeroConfServiceBrowser;
|
||||
|
||||
class DevicePluginKodi : public DevicePlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -56,6 +58,8 @@ private:
|
|||
PluginTimer *m_pluginTimer;
|
||||
QHash<Kodi*, Device*> m_kodis;
|
||||
QHash<Kodi*, DeviceSetupInfo*> m_asyncSetups;
|
||||
ZeroConfServiceBrowser *m_serviceBrowser = nullptr;
|
||||
ZeroConfServiceBrowser *m_httpServiceBrowser = nullptr;
|
||||
|
||||
QHash<int, DeviceActionInfo*> m_pendingActions;
|
||||
QHash<int, BrowserActionInfo*> m_pendingBrowserActions;
|
||||
|
|
|
|||
Loading…
Reference in New Issue