added bluos files

master
bernhard.trinnes 2020-03-13 12:54:42 +01:00
parent 49907ecb89
commit 6a199f5ae8
8 changed files with 450 additions and 0 deletions

0
bluos/README.md Normal file
View File

0
bluos/bluos.cpp Normal file
View File

0
bluos/bluos.h Normal file
View File

13
bluos/bluos.pro Normal file
View File

@ -0,0 +1,13 @@
include(../plugins.pri)
QT += network
TARGET = $$qtLibraryTarget(nymea_integrationpluginbluos)
SOURCES += \
integrationpluginbluos.cpp \
bluos.cpp \
HEADERS += \
integrationpluginbluos.h \
bluos.h \

View File

@ -0,0 +1,172 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "integrationpluginbluos.h"
#include "plugininfo.h"
#include "integrations/thing.h"
#include "network/networkaccessmanager.h"
#include "platform/platformzeroconfcontroller.h"
#include "network/zeroconf/zeroconfservicebrowser.h"
#include <QDebug>
#include <QStringList>
#include <QJsonDocument>
#include <QTimer>
IntegrationPluginBluOS::IntegrationPluginBluOS()
{
}
IntegrationPluginBluOS::~IntegrationPluginBluOS()
{
}
void IntegrationPluginBluOS::init()
{
}
void IntegrationPluginBluOS::discoverThings(ThingDiscoveryInfo *info)
{
if (info->thingClassId() == bluosThingClassId) {
/*
* The HEOS products can be discovered using the UPnP SSDP protocol. Through discovery,
* the IP address of the HEOS products can be retrieved. Once the IP address is retrieved,
* a telnet connection to port 1255 can be opened to access the HEOS CLI and control the HEOS system.
* The HEOS product IP address can also be set statically and manually programmed into the control system.
* Search target name (ST) in M-SEARCH discovery request is 'urn:schemas-denon-com:thing:ACT-Denon:1'.
*/
UpnpDiscoveryReply *reply = hardwareManager()->upnpDiscovery()->discoverDevices();
connect(reply, &UpnpDiscoveryReply::finished, info, [this, reply, info](){
reply->deleteLater();
if (reply->error() != UpnpDiscoveryReply::UpnpDiscoveryReplyErrorNoError) {
qCWarning(dcDenon()) << "Upnp discovery error" << reply->error();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("UPnP discovery failed."));
return;
}
foreach (const UpnpDeviceDescriptor &upnpDevice, reply->deviceDescriptors()) {
qCDebug(dcDenon) << "UPnP thing found:" << upnpDevice.modelDescription() << upnpDevice.friendlyName() << upnpDevice.hostAddress().toString() << upnpDevice.modelName() << upnpDevice.manufacturer() << upnpDevice.serialNumber();
if (upnpDevice.modelName().contains("HEOS")) {
QString serialNumber = upnpDevice.serialNumber();
if (serialNumber != "0000001") {
// child devices have serial number 0000001
qCDebug(dcDenon) << "UPnP thing found:" << upnpDevice.modelDescription() << upnpDevice.friendlyName() << upnpDevice.hostAddress().toString() << upnpDevice.modelName() << upnpDevice.manufacturer() << upnpDevice.serialNumber();
ThingDescriptor descriptor(heosThingClassId, upnpDevice.modelName(), serialNumber);
ParamList params;
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(heosThingSerialNumberParamTypeId).toString().contains(serialNumber, Qt::CaseSensitivity::CaseInsensitive)) {
descriptor.setThingId(existingThing->id());
break;
}
}
params.append(Param(heosThingModelNameParamTypeId, upnpDevice.modelName()));
params.append(Param(heosThingIpParamTypeId, upnpDevice.hostAddress().toString()));
params.append(Param(heosThingSerialNumberParamTypeId, serialNumber));
descriptor.setParams(params);
info->addThingDescriptor(descriptor);
}
}
}
info->finish(Thing::ThingErrorNoError);
});
return;
}
info->finish(Thing::ThingErrorThingClassNotFound);
}
void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
if (thing->thingClassId() == AVRX1000ThingClassId) {
qCDebug(dcDenon) << "Setup Denon device" << thing->paramValue(AVRX1000ThingIpParamTypeId).toString();
QHostAddress address(thing->paramValue(AVRX1000ThingIpParamTypeId).toString());
if (address.isNull()) {
qCWarning(dcDenon) << "Could not parse ip address" << thing->paramValue(AVRX1000ThingIpParamTypeId).toString();
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The given IP address is not valid."));
return;
}
AvrConnection *denonConnection = new AvrConnection(address, 23, this);
connect(denonConnection, &AvrConnection::connectionStatusChanged, this, &IntegrationPluginDenon::onAvrConnectionChanged);
connect(denonConnection, &AvrConnection::socketErrorOccured, this, &IntegrationPluginDenon::onAvrSocketError);
connect(denonConnection, &AvrConnection::channelChanged, this, &IntegrationPluginDenon::onAvrChannelChanged);
connect(denonConnection, &AvrConnection::powerChanged, this, &IntegrationPluginDenon::onAvrPowerChanged);
connect(denonConnection, &AvrConnection::volumeChanged, this, &IntegrationPluginDenon::onAvrVolumeChanged);
connect(denonConnection, &AvrConnection::surroundModeChanged, this, &IntegrationPluginDenon::onAvrSurroundModeChanged);
connect(denonConnection, &AvrConnection::muteChanged, this, &IntegrationPluginDenon::onAvrMuteChanged);
m_avrConnections.insert(thing, denonConnection);
m_asyncAvrSetups.insert(denonConnection, info);
// In case the setup is cancelled before we finish it...
connect(info, &QObject::destroyed, this, [this, info, denonConnection]() { m_asyncAvrSetups.remove(denonConnection); });
denonConnection->connectDevice();
return;
}
if (thing->thingClassId() == heosThingClassId) {
qCDebug(dcDenon) << "Setup Denon device" << thing->paramValue(heosThingIpParamTypeId).toString();
QHostAddress address(thing->paramValue(heosThingIpParamTypeId).toString());
Heos *heos = new Heos(address, this);
connect(heos, &Heos::connectionStatusChanged, this, &IntegrationPluginDenon::onHeosConnectionChanged);
connect(heos, &Heos::playerDiscovered, this, &IntegrationPluginDenon::onHeosPlayerDiscovered);
connect(heos, &Heos::playStateReceived, this, &IntegrationPluginDenon::onHeosPlayStateReceived);
connect(heos, &Heos::repeatModeReceived, this, &IntegrationPluginDenon::onHeosRepeatModeReceived);
connect(heos, &Heos::shuffleModeReceived, this, &IntegrationPluginDenon::onHeosShuffleModeReceived);
connect(heos, &Heos::muteStatusReceived, this, &IntegrationPluginDenon::onHeosMuteStatusReceived);
connect(heos, &Heos::volumeStatusReceived, this, &IntegrationPluginDenon::onHeosVolumeStatusReceived);
connect(heos, &Heos::nowPlayingMediaStatusReceived, this, &IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived);
m_heos.insert(thing, heos);
m_asyncHeosSetups.insert(heos, info);
// In case the setup is cancelled before we finish it...
connect(info, &QObject::destroyed, this, [this, info, heos]() { m_asyncHeosSetups.remove(heos); });
heos->connectHeos();
return;
}
if (thing->thingClassId() == heosPlayerThingClassId) {
info->finish(Thing::ThingErrorNoError);
return;
}
info->finish(Thing::ThingErrorThingClassNotFound);
}

View File

@ -0,0 +1,69 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INTEGRATIONPLUGINBLUOS_H
#define INTEGRATIONPLUGINBLUOS_H
#include "integrations/integrationplugin.h"
#include <QUdpSocket>
#include <QNetworkAccessManager>
class PluginTimer;
class IntegrationPluginBluOS: public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginbluos.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginBluOS();
~IntegrationPluginBluOS();
void init() override;
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
private slots:
void refreshStates();
private:
private:
PluginTimer *m_pollTimer = nullptr;
};
#endif // INTEGRATIONPLUGINBLUOS_H

View File

@ -0,0 +1,195 @@
{
"displayName": "BluOS",
"name": "bluos",
"id": "",
"vendors": [
{
"id": "cf0a9644-2c13-4daf-85c1-ad88d6745b42",
"displayName": "Denon",
"name": "denon",
"thingClasses": [
{
"id": "fce5247f-4c6d-408f-ac62-e5973dc6adfa",
"name": "heosPlayer",
"displayName": "Heos player",
"createMethods": ["auto"],
"interfaces": ["mediaplayer", "mediacontroller", "extendedvolumecontroller", "mediametadataprovider", "shufflerepeat", "connectable"],
"paramTypes":[
{
"id": "89629008-6ad8-4e92-863d-b86e0e012d0b",
"name": "playerId",
"displayName": "Player ID",
"type" : "int"
},
{
"id": "e760f92b-8fca-4f20-aead-a52045505b81",
"name": "model",
"displayName": "Model",
"type" : "QString"
},
{
"id": "aa1158f7-b451-456a-840f-4f0c63b2b7f0",
"name": "version",
"displayName": "Version",
"type" : "QString"
},
{
"id": "866e8d6a-953f-4bdc-8d85-8d92e51e8592",
"name": "serialNumber",
"displayName": "Serial number",
"type" : "QString"
}
],
"stateTypes": [
{
"id": "9a4e527e-057c-4b19-8a02-605cc8349f5e",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "fcc89c7c-b793-4b6f-a3dc-0e0e3a86748f",
"name": "mute",
"displayName": "Mute",
"displayNameEvent": "Mute changed",
"displayNameAction": "Set mute",
"type": "bool",
"defaultValue": false,
"cached": false,
"writable": true
},
{
"id": "6d4886a1-fa5d-4889-96c5-7a1c206f59be",
"name": "volume",
"displayName": "Volume",
"displayNameEvent": "Volume changed",
"displayNameAction": "Set volume",
"type": "int",
"defaultValue": 50,
"minValue": 0,
"maxValue": 100,
"writable": true
},
{
"id": "6db3b484-4cd4-477b-b822-275865d308db",
"name": "playbackStatus",
"displayName": "Playback status",
"displayNameEvent": "Playback status changed",
"displayNameAction": "Set playback status",
"type": "QString",
"defaultValue": "Stopped",
"possibleValues": ["Playing", "Paused", "Stopped"],
"cached": false,
"writable": true
},
{
"id": "4b581237-acf5-4d8f-9e83-9b24e9ac900a",
"name": "shuffle",
"displayName": "Shuffle",
"displayNameEvent": "Shuffle changed",
"displayNameAction": "Set shuffle",
"type": "bool",
"defaultValue": false,
"cached": false,
"writable": true
},
{
"id": "4e60cd17-5845-4351-aa2c-2504610e1532",
"name": "repeat",
"displayName": "Repeat mode",
"displayNameEvent": "Repeat mode changed",
"displayNameAction": "Set repeat mode",
"type": "QString",
"defaultValue": "None",
"possibleValues": ["None", "One", "All"],
"cached": false,
"writable": true
},
{
"id": "eee22722-3ee5-48f7-8af8-275dc04b21eb",
"name": "source",
"displayName": "Source",
"displayNameEvent": "Source changed",
"type": "QString",
"defaultValue": ""
},
{
"id": "0a9183a4-b633-4773-ba7a-f4266895157e",
"name": "artist",
"displayName": "Artist",
"displayNameEvent": "Artist changed",
"type": "QString",
"defaultValue": ""
},
{
"id": "9cd60864-f141-4e03-a85b-357690cad1b8",
"name": "collection",
"displayName": "Album",
"displayNameEvent": "Album changed",
"type": "QString",
"defaultValue": ""
},
{
"id": "bbeecf30-6feb-48d5-ade3-57b2a4eea05f",
"name": "title",
"displayName": "Title",
"displayNameEvent": "Title changed",
"type": "QString",
"defaultValue": ""
},
{
"id": "a7f0ba95-383a-4efd-adc5-a36e50a04018",
"name": "artwork",
"displayName": "Artwork",
"displayNameEvent": "Artwork changed",
"type": "QString",
"defaultValue": ""
},
{
"id": "c59835ac-ee6e-4e6c-aa20-aeb3501937c5",
"name": "playerType",
"displayName": "Player type",
"displayNameEvent": "Player type changed",
"possibleValues": [
"audio",
"video"
],
"type": "QString",
"defaultValue": "audio"
}
],
"actionTypes": [
{
"id": "a718f7e9-0b54-4403-b661-49f7b0d13085",
"name": "skipBack",
"displayName": "Akip back"
},
{
"id": "c4b29c09-e3b3-4843-b6d9-e032f3fc1d78",
"name": "stop",
"displayName": "Stop"
},
{
"id": "c64964e4-cea0-468a-a9bf-8f69657b74e9",
"name": "play",
"displayName": "Play"
},
{
"id": "21c1cbe6-278f-4688-a65f-6620be1ee5ea",
"name": "pause",
"displayName": "Pause"
},
{
"id": "57697e9c-ce5e-4b8f-b42e-16662829ceb2",
"name": "skipNext",
"displayName": "Skip next"
}
]
}
]
}
]
}

1
debian/nymea-plugin-bluos.install.in vendored Normal file
View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginbluos.so