fixed volume action
parent
855c6cb3d1
commit
dbaecd9c1b
|
|
@ -0,0 +1,8 @@
|
|||
# Bose Soundtouch
|
||||
|
||||
This plug-in controls Bose speakers throught the local API.
|
||||
|
||||
## Device Setup
|
||||
|
||||
To connect the speaker to the WiFi the Bose App is required. This plug-in
|
||||
supports device discovery.
|
||||
|
|
@ -1,24 +1,30 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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
|
||||
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||
* 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 "devicepluginbose.h"
|
||||
#include "devices/device.h"
|
||||
|
|
@ -52,7 +58,6 @@ void DevicePluginBose::setupDevice(DeviceSetupInfo *info)
|
|||
QString ipAddress = info->device()->paramValue(soundtouchDeviceIpParamTypeId).toString();
|
||||
SoundTouch *soundTouch = new SoundTouch(hardwareManager()->networkManager(), ipAddress, this);
|
||||
connect(soundTouch, &SoundTouch::connectionChanged, this, &DevicePluginBose::onConnectionChanged);
|
||||
|
||||
connect(soundTouch, &SoundTouch::infoReceived, this, &DevicePluginBose::onInfoObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::nowPlayingReceived, this, &DevicePluginBose::onNowPlayingObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::volumeReceived, this, &DevicePluginBose::onVolumeObjectReceived);
|
||||
|
|
@ -60,15 +65,7 @@ void DevicePluginBose::setupDevice(DeviceSetupInfo *info)
|
|||
connect(soundTouch, &SoundTouch::bassReceived, this, &DevicePluginBose::onBassObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::bassCapabilitiesReceived, this, &DevicePluginBose::onBassCapabilitiesObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::zoneReceived, this, &DevicePluginBose::onZoneObjectReceived);
|
||||
|
||||
soundTouch->getInfo();
|
||||
soundTouch->getNowPlaying();
|
||||
soundTouch->getVolume();
|
||||
soundTouch->getSources();
|
||||
soundTouch->getBass();
|
||||
soundTouch->getBassCapabilities();
|
||||
soundTouch->getZone();
|
||||
|
||||
connect(soundTouch, &SoundTouch::requestExecuted, this, &DevicePluginBose::onRequestExecuted);
|
||||
m_soundTouch.insert(info->device(), soundTouch);
|
||||
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
|
|
@ -79,7 +76,16 @@ void DevicePluginBose::setupDevice(DeviceSetupInfo *info)
|
|||
|
||||
void DevicePluginBose::postSetupDevice(Device *device)
|
||||
{
|
||||
Q_UNUSED(device)
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||
soundTouch->getInfo();
|
||||
soundTouch->getNowPlaying();
|
||||
soundTouch->getVolume();
|
||||
soundTouch->getSources();
|
||||
soundTouch->getBass();
|
||||
soundTouch->getBassCapabilities();
|
||||
soundTouch->getZone();
|
||||
}
|
||||
|
||||
if (!m_pluginTimer) {
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
|
||||
|
|
@ -137,82 +143,83 @@ void DevicePluginBose::executeAction(DeviceActionInfo *info)
|
|||
|
||||
if (action.actionTypeId() == soundtouchPowerActionTypeId) {
|
||||
//bool power = action.param(soundtouchPowerActionPowerParamTypeId).value().toBool();
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_POWER); //only toggling possible
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchMuteActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_MUTE);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchPlayActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchPauseActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PAUSE);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchStopActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchSkipNextActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_NEXT_TRACK);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchSkipBackActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PREV_TRACK);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_POWER); //only toggling possible
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
if (action.actionTypeId() == soundtouchShuffleActionTypeId) {
|
||||
} else if (action.actionTypeId() == soundtouchMuteActionTypeId) {
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_MUTE); //only toggling possible
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchPlayActionTypeId) {
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchPauseActionTypeId) {
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_PAUSE);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchStopActionTypeId) {
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchSkipNextActionTypeId) {
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_NEXT_TRACK);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchSkipBackActionTypeId) {
|
||||
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_PREV_TRACK);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchShuffleActionTypeId) {
|
||||
|
||||
QUuid requestId;
|
||||
bool shuffle = action.param(soundtouchShuffleActionShuffleParamTypeId).value().toBool();
|
||||
if (shuffle) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_ON);
|
||||
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_ON);
|
||||
} else {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_OFF);
|
||||
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_OFF);
|
||||
}
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
if (action.actionTypeId() == soundtouchRepeatActionTypeId) {
|
||||
} else if (action.actionTypeId() == soundtouchRepeatActionTypeId) {
|
||||
|
||||
QUuid requestId;
|
||||
QString repeat = action.param(soundtouchRepeatActionRepeatParamTypeId).value().toString();
|
||||
if (repeat == "None") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_OFF);
|
||||
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_OFF);
|
||||
} else if (repeat == "One") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ONE);
|
||||
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ONE);
|
||||
} else if (repeat == "All") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ALL);
|
||||
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ALL);
|
||||
}
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchVolumeActionTypeId) {
|
||||
|
||||
if (action.actionTypeId() == soundtouchVolumeActionTypeId) {
|
||||
int volume = action.param(soundtouchVolumeActionVolumeParamTypeId).value().toInt();
|
||||
soundTouch->setVolume(volume);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
QUuid requestId = soundTouch->setVolume(volume);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else if (action.actionTypeId() == soundtouchBassActionTypeId) {
|
||||
|
||||
if (action.actionTypeId() == soundtouchBassActionTypeId) {
|
||||
int bass = action.param(soundtouchBassActionBassParamTypeId).value().toInt();
|
||||
soundTouch->setBass(bass);
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
return;
|
||||
}
|
||||
QUuid requestId = soundTouch->setBass(bass);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
if (action.actionTypeId() == soundtouchPlaybackStatusActionTypeId) {
|
||||
} else if (action.actionTypeId() == soundtouchPlaybackStatusActionTypeId) {
|
||||
|
||||
QUuid requestId;
|
||||
QString status = action.param(soundtouchPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
|
||||
if (status == "Playing") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||
|
|
@ -221,14 +228,48 @@ void DevicePluginBose::executeAction(DeviceActionInfo *info)
|
|||
} else if (status == "Stopped") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||
}
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
m_pendingActions.insert(requestId, info);
|
||||
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||
|
||||
} else {
|
||||
info->finish(Device::DeviceErrorActionTypeNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
info->finish(Device::DeviceErrorActionTypeNotFound);
|
||||
return;
|
||||
} else {
|
||||
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::browseDevice(BrowseResult *result)
|
||||
{
|
||||
Device *device = result->device();
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||
QUuid requestId = soundTouch->getSources();
|
||||
m_asyncBrowseResults.insert(requestId, result);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::browserItem(BrowserItemResult *result)
|
||||
{
|
||||
Device *device = result->device();
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
//SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||
//QUuid requestId = soundTouch->getSources();
|
||||
//m_asyncBrowseResults.insert(requestId, result);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::executeBrowserItem(BrowserActionInfo *info)
|
||||
{
|
||||
Device *device = info->device();
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||
ContentItemObject contentItem;
|
||||
QUuid requestId = soundTouch->setSource(contentItem);
|
||||
m_asyncExecuteBroweItems.insert(requestId, info);
|
||||
connect(info, &BrowserActionInfo::aborted, this, [this, requestId]{m_asyncExecuteBroweItems.remove(requestId);});
|
||||
}
|
||||
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onPluginTimer()
|
||||
|
|
@ -256,15 +297,36 @@ void DevicePluginBose::onDeviceNameChanged()
|
|||
soundtouch->setName(device->name());
|
||||
}
|
||||
|
||||
void DevicePluginBose::onInfoObjectReceived(InfoObject infoObject)
|
||||
void DevicePluginBose::onRequestExecuted(QUuid requestId, bool success)
|
||||
{
|
||||
if (m_pendingActions.contains(requestId)) {
|
||||
DeviceActionInfo *info = m_pendingActions.value(requestId);
|
||||
if (success) {
|
||||
info->finish(Device::DeviceErrorNoError);
|
||||
} else {
|
||||
info->finish(Device::DeviceErrorHardwareFailure);
|
||||
}
|
||||
} else if (m_asyncBrowseResults.contains(requestId)) {
|
||||
if (!success) {
|
||||
BrowseResult *result = m_asyncBrowseResults.take(requestId);
|
||||
result->finish(Device::DeviceErrorHardwareFailure);
|
||||
}
|
||||
} else {
|
||||
//This request was not an action or browse request
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::onInfoObjectReceived(QUuid requestId, InfoObject infoObject)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
device->setName(infoObject.name);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onNowPlayingObjectReceived(NowPlayingObject nowPlaying)
|
||||
void DevicePluginBose::onNowPlayingObjectReceived(QUuid requestId, NowPlayingObject nowPlaying)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
|
||||
|
|
@ -302,43 +364,56 @@ void DevicePluginBose::onNowPlayingObjectReceived(NowPlayingObject nowPlaying)
|
|||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::onVolumeObjectReceived(VolumeObject volume)
|
||||
void DevicePluginBose::onVolumeObjectReceived(QUuid requestId, VolumeObject volume)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
device->setStateValue(soundtouchVolumeStateTypeId, volume.actualVolume);
|
||||
device->setStateValue(soundtouchMuteStateTypeId, volume.muteEnabled);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onSourcesObjectReceived(SourcesObject sources)
|
||||
void DevicePluginBose::onSourcesObjectReceived(QUuid requestId, SourcesObject sources)
|
||||
{
|
||||
foreach (SourceItemObject sourceItem, sources.sourceItems) {
|
||||
qDebug(dcBose()) << "Source:" << sources.deviceId << sourceItem.source << sourceItem.displayName;
|
||||
if (m_asyncBrowseResults.contains(requestId)) {
|
||||
BrowseResult *result = m_asyncBrowseResults.value(requestId);
|
||||
foreach (SourceItemObject sourceItem, sources.sourceItems) {
|
||||
qDebug(dcBose()) << "Source:" << sources.deviceId << sourceItem.source << sourceItem.displayName;
|
||||
BrowserItem item("sources"+sourceItem.source, sourceItem.displayName, false, true);
|
||||
result->addItem(item);
|
||||
}
|
||||
result->finish(Device::DeviceErrorNoError);
|
||||
} else {
|
||||
qCWarning(dcBose()) << "Received sources without an associated BrowseResult";
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::onBassObjectReceived(BassObject bass)
|
||||
void DevicePluginBose::onBassObjectReceived(QUuid requestId, BassObject bass)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
device->setStateValue(soundtouchBassStateTypeId, bass.actualBass);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onBassCapabilitiesObjectReceived(BassCapabilitiesObject bassCapabilities)
|
||||
void DevicePluginBose::onBassCapabilitiesObjectReceived(QUuid requestId, BassCapabilitiesObject bassCapabilities)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
qDebug(dcBose()) << "Bass capabilities (max, min, default):" << bassCapabilities.bassMax << bassCapabilities.bassMin << bassCapabilities.bassDefault;
|
||||
}
|
||||
|
||||
void DevicePluginBose::onGroupObjectReceived(GroupObject group)
|
||||
void DevicePluginBose::onGroupObjectReceived(QUuid requestId, GroupObject group)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
qDebug(dcBose()) << "Group" << group.name << group.status;
|
||||
foreach (RolesObject role, group.roles) {
|
||||
qDebug(dcBose()) << "-> member:" << role.groupRole.deviceID;
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::onZoneObjectReceived(ZoneObject zone)
|
||||
void DevicePluginBose::onZoneObjectReceived(QUuid requestId, ZoneObject zone)
|
||||
{
|
||||
Q_UNUSED(requestId);
|
||||
qDebug(dcBose()) << "Zone master" << zone.deviceID;
|
||||
foreach (MemberObject member, zone.members) {
|
||||
qDebug(dcBose()) << "-> member:" << member.deviceID;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,30 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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
|
||||
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||
* 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 DEVICEPLUGINBOSE_H
|
||||
#define DEVICEPLUGINBOSE_H
|
||||
|
|
@ -30,6 +36,7 @@
|
|||
|
||||
#include <QHash>
|
||||
#include <QDebug>
|
||||
#include <QUuid>
|
||||
|
||||
class DevicePluginBose : public DevicePlugin
|
||||
{
|
||||
|
|
@ -48,25 +55,32 @@ public:
|
|||
void deviceRemoved(Device *device) override;
|
||||
void executeAction(DeviceActionInfo *info) override;
|
||||
|
||||
void browseDevice(BrowseResult *result) override;
|
||||
void browserItem(BrowserItemResult *result) override;
|
||||
void executeBrowserItem(BrowserActionInfo *info) override;
|
||||
|
||||
private:
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
|
||||
QHash<Device *, SoundTouch *> m_soundTouch;
|
||||
QHash<int, ActionId> m_pendingActions;
|
||||
QHash<QUuid, DeviceActionInfo *> m_pendingActions;
|
||||
QHash<QUuid, BrowseResult *> m_asyncBrowseResults;
|
||||
QHash<QUuid, BrowserActionInfo *> m_asyncExecuteBroweItems;
|
||||
|
||||
private slots:
|
||||
void onPluginTimer();
|
||||
void onConnectionChanged(bool connected);
|
||||
void onDeviceNameChanged();
|
||||
void onRequestExecuted(QUuid requestId, bool success);
|
||||
|
||||
void onInfoObjectReceived(InfoObject infoObject);
|
||||
void onNowPlayingObjectReceived(NowPlayingObject nowPlaying);
|
||||
void onVolumeObjectReceived(VolumeObject volume);
|
||||
void onSourcesObjectReceived(SourcesObject sources);
|
||||
void onBassObjectReceived(BassObject bass);
|
||||
void onBassCapabilitiesObjectReceived(BassCapabilitiesObject bassCapabilities);
|
||||
void onGroupObjectReceived(GroupObject group);
|
||||
void onZoneObjectReceived(ZoneObject zone);
|
||||
void onInfoObjectReceived(QUuid requestId, InfoObject infoObject);
|
||||
void onNowPlayingObjectReceived(QUuid requestId, NowPlayingObject nowPlaying);
|
||||
void onVolumeObjectReceived(QUuid requestId, VolumeObject volume);
|
||||
void onSourcesObjectReceived(QUuid requestId, SourcesObject sources);
|
||||
void onBassObjectReceived(QUuid requestId, BassObject bass);
|
||||
void onBassCapabilitiesObjectReceived(QUuid requestId, BassCapabilitiesObject bassCapabilities);
|
||||
void onGroupObjectReceived(QUuid requestId, GroupObject group);
|
||||
void onZoneObjectReceived(QUuid requestId, ZoneObject zone);
|
||||
};
|
||||
|
||||
#endif // DEVICEPLUGINBOSE_H
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
"displayName": "SoundTouch",
|
||||
"interfaces": ["extendedvolumecontroller", "mediametadataprovider", "shufflerepeat", "connectable"],
|
||||
"createMethods": ["discovery"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "1a897065-57c6-49b3-bac9-1e5db27859e5",
|
||||
|
|
|
|||
|
|
@ -1,24 +1,30 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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
|
||||
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||
* 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 "soundtouch.h"
|
||||
#include "hardwaremanager.h"
|
||||
|
|
@ -30,113 +36,133 @@ SoundTouch::SoundTouch(NetworkAccessManager *networkAccessManager, QString ipAdd
|
|||
m_networkAccessManager(networkAccessManager),
|
||||
m_ipAddress(ipAddress)
|
||||
{
|
||||
m_websocket = new QWebSocket();
|
||||
connect(m_websocket, &QWebSocket::connected, this, &SoundTouch::onWebsocketConnected);
|
||||
connect(m_websocket, &QWebSocket::disconnected, this, &SoundTouch::onWebsocketDisconnected);
|
||||
connect(m_websocket, &QWebSocket::textMessageReceived, this, &SoundTouch::onWebsocketMessageReceived);
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("ws");
|
||||
url.setPort(8080);
|
||||
qDebug(dcBose) << "Connecting websocket to" << url;
|
||||
//THIS CODE IS LEFT INTENTIONALLY
|
||||
//m_websocket = new QWebSocket();
|
||||
//connect(m_websocket, &QWebSocket::connected, this, &SoundTouch::onWebsocketConnected);
|
||||
//connect(m_websocket, &QWebSocket::disconnected, this, &SoundTouch::onWebsocketDisconnected);
|
||||
//connect(m_websocket, &QWebSocket::textMessageReceived, this, &SoundTouch::onWebsocketMessageReceived);
|
||||
//QUrl url;
|
||||
//url.setHost(m_ipAddress);
|
||||
//url.setScheme("ws");
|
||||
//url.setPort(8080);
|
||||
//qDebug(dcBose) << "Connecting websocket to" << url;
|
||||
//TODO missing websocket subprotocol "gabbo"
|
||||
//Seems QWebsockets doesn't support subprotocols
|
||||
m_websocket->open(url);
|
||||
//QWebsockets doesn't support subprotocols
|
||||
//m_websocket->open(url);
|
||||
}
|
||||
|
||||
void SoundTouch::getInfo()
|
||||
QUuid SoundTouch::getInfo()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/info");
|
||||
requestId = sendGetRequest("/info");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/info"))
|
||||
m_getRequestQueue.append("/info");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getVolume()
|
||||
QUuid SoundTouch::getVolume()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/volume");
|
||||
requestId = sendGetRequest("/volume");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/volume"))
|
||||
m_getRequestQueue.append("/volume");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getNowPlaying()
|
||||
QUuid SoundTouch::getNowPlaying()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/now_playing");
|
||||
requestId = sendGetRequest("/now_playing");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/now_playing"))
|
||||
m_getRequestQueue.append("/now_playing");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getBass()
|
||||
QUuid SoundTouch::getBass()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/bass");
|
||||
requestId = sendGetRequest("/bass");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/bass"))
|
||||
m_getRequestQueue.append("/bass");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getGroup()
|
||||
QUuid SoundTouch::getGroup()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/getGroup");
|
||||
requestId = sendGetRequest("/getGroup");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/getGroup"))
|
||||
m_getRequestQueue.append("/getGroup");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getSources()
|
||||
QUuid SoundTouch::getSources()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/sources");
|
||||
requestId = sendGetRequest("/sources");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/sources"))
|
||||
m_getRequestQueue.append("/sources");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getZone()
|
||||
QUuid SoundTouch::getZone()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/getZone");
|
||||
requestId = sendGetRequest("/getZone");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/getZone"))
|
||||
m_getRequestQueue.append("/getZone");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::getPresets()
|
||||
QUuid SoundTouch::getPresets()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/presets");
|
||||
requestId = sendGetRequest("/presets");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/presets"))
|
||||
m_getRequestQueue.append("/presets");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
|
||||
void SoundTouch::getBassCapabilities()
|
||||
QUuid SoundTouch::getBassCapabilities()
|
||||
{
|
||||
QUuid requestId;
|
||||
if (!m_getRepliesPending) {
|
||||
sendGetRequest("/bassCapabilities");
|
||||
requestId = sendGetRequest("/bassCapabilities");
|
||||
} else {
|
||||
if (!m_getRequestQueue.contains("/bassCapabilities"))
|
||||
m_getRequestQueue.append("/bassCapabilities");
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setKey(KEY_VALUE keyValue)
|
||||
QUuid SoundTouch::setKey(KEY_VALUE keyValue)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -199,13 +225,24 @@ void SoundTouch::setKey(KEY_VALUE keyValue)
|
|||
break;
|
||||
default:
|
||||
qWarning(dcBose) << "key not yet implemented";
|
||||
return;
|
||||
return "0";
|
||||
}
|
||||
xml.writeEndElement(); //key
|
||||
xml.writeEndDocument();
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
//qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
|
||||
if (keyValue == KEY_VALUE_POWER) {
|
||||
QUrl url;
|
||||
|
|
@ -223,12 +260,14 @@ void SoundTouch::setKey(KEY_VALUE keyValue)
|
|||
xml.writeEndElement(); //key
|
||||
xml.writeEndDocument();
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [reply] {reply->deleteLater();});
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setVolume(int volume)
|
||||
QUuid SoundTouch::setVolume(int volume)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -240,11 +279,24 @@ void SoundTouch::setVolume(int volume)
|
|||
content.append("</volume>");
|
||||
//qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setSource(ContentItemObject contentItem)
|
||||
QUuid SoundTouch::setSource(ContentItemObject contentItem)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -261,11 +313,24 @@ void SoundTouch::setSource(ContentItemObject contentItem)
|
|||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setZone(ZoneObject zone)
|
||||
QUuid SoundTouch::setZone(ZoneObject zone)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -284,11 +349,24 @@ void SoundTouch::setZone(ZoneObject zone)
|
|||
xml.writeEndDocument();
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::addZoneSlave(ZoneObject zone)
|
||||
QUuid SoundTouch::addZoneSlave(ZoneObject zone)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -307,11 +385,25 @@ void SoundTouch::addZoneSlave(ZoneObject zone)
|
|||
xml.writeEndDocument();
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::removeZoneSlave(ZoneObject zone)
|
||||
QUuid SoundTouch::removeZoneSlave(ZoneObject zone)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -330,11 +422,24 @@ void SoundTouch::removeZoneSlave(ZoneObject zone)
|
|||
xml.writeEndDocument();
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setBass(int volume)
|
||||
QUuid SoundTouch::setBass(int volume)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -346,11 +451,24 @@ void SoundTouch::setBass(int volume)
|
|||
content.append("</bass>");
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setName(QString name)
|
||||
QUuid SoundTouch::setName(QString name)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -362,11 +480,24 @@ void SoundTouch::setName(QString name)
|
|||
content.append("</name>");
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO parse error
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::setSpeaker(PlayInfoObject playInfo)
|
||||
QUuid SoundTouch::setSpeaker(PlayInfoObject playInfo)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
|
|
@ -386,7 +517,10 @@ void SoundTouch::setSpeaker(PlayInfoObject playInfo)
|
|||
xml.writeEndDocument();
|
||||
qDebug(dcBose) << "Sending request" << url << content;
|
||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::onWebsocketConnected()
|
||||
|
|
@ -408,28 +542,96 @@ void SoundTouch::onWebsocketDisconnected()
|
|||
});
|
||||
}
|
||||
|
||||
void SoundTouch::onRestRequestFinished() {
|
||||
void SoundTouch::onRestRequestError(QNetworkReply::NetworkError error)
|
||||
{
|
||||
Q_UNUSED(error)
|
||||
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
qWarning(dcBose) << "Rest Error" << reply->errorString();
|
||||
}
|
||||
|
||||
if (m_getRequestQueue.isEmpty()) {
|
||||
m_getRepliesPending = false;
|
||||
} else {
|
||||
sendGetRequest(m_getRequestQueue.takeFirst());
|
||||
void SoundTouch::onWebsocketMessageReceived(QString message)
|
||||
{
|
||||
qDebug(dcBose) << "Websocket message received:" << message;
|
||||
}
|
||||
|
||||
QUuid SoundTouch::sendGetRequest(QString path)
|
||||
{
|
||||
QUuid requestId = QUuid::createUuid();
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
url.setPort(m_port);
|
||||
url.setPath(path);
|
||||
//qDebug(dcBose) << "Sending request" << url;
|
||||
QNetworkRequest request = QNetworkRequest(url);
|
||||
|
||||
QNetworkReply *reply = m_networkAccessManager->get(request);
|
||||
m_getRepliesPending = true;
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
reply->deleteLater();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (m_getRequestQueue.isEmpty()) {
|
||||
m_getRepliesPending = false;
|
||||
} else {
|
||||
sendGetRequest(m_getRequestQueue.takeFirst());
|
||||
}
|
||||
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
emit requestExecuted(requestId, true);
|
||||
QByteArray data = reply->readAll();
|
||||
parseData(requestId, data);
|
||||
});
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRestRequestError(QNetworkReply::NetworkError)));
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void SoundTouch::emitRequestStatus(QUuid requestId, const QByteArray &data)
|
||||
{
|
||||
QXmlStreamReader xml;
|
||||
xml.addData(data);
|
||||
|
||||
if (xml.readNextStartElement()) {
|
||||
if (xml.name() == "status") {
|
||||
//QString status = xml.readElementText();
|
||||
emit requestExecuted(requestId, true);
|
||||
} else if (xml.name() == "errors") {
|
||||
emit requestExecuted(requestId, false);
|
||||
QString deviceId;
|
||||
if(xml.attributes().hasAttribute("deviceID")) {
|
||||
deviceId = xml.attributes().value("deviceID").toString();
|
||||
}
|
||||
while(xml.readNextStartElement()){
|
||||
if(xml.name() == "error"){
|
||||
ErrorObject error;
|
||||
error.deviceId = deviceId;
|
||||
error.error = xml.readElementText();
|
||||
if(xml.attributes().hasAttribute("value")) {
|
||||
error.value = xml.attributes().value("value").toInt();
|
||||
}
|
||||
if(xml.attributes().hasAttribute("name")) {
|
||||
error.name = xml.attributes().value("name").toString();
|
||||
}
|
||||
if(xml.attributes().hasAttribute("severity")) {
|
||||
error.severity = xml.attributes().value("severity").toString();
|
||||
}
|
||||
emit errorReceived(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check HTTP status code
|
||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
//qDebug(dcBose) << data;
|
||||
|
||||
void SoundTouch::parseData(QUuid requestId, const QByteArray &data)
|
||||
{
|
||||
QXmlStreamReader xml;
|
||||
xml.addData(data);
|
||||
|
||||
|
|
@ -482,7 +684,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit infoReceived(info);
|
||||
emit infoReceived(requestId, info);
|
||||
} else if (xml.name() == "nowPlaying") {
|
||||
NowPlayingObject nowPlaying;
|
||||
if(xml.attributes().hasAttribute("deviceID")) {
|
||||
|
|
@ -585,7 +787,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
}
|
||||
}
|
||||
|
||||
emit nowPlayingReceived(nowPlaying);
|
||||
emit nowPlayingReceived(requestId, nowPlaying);
|
||||
} else if (xml.name() == "volume") {
|
||||
VolumeObject volumeObject;
|
||||
if(xml.attributes().hasAttribute("deviceID")) {
|
||||
|
|
@ -606,7 +808,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit volumeReceived(volumeObject);
|
||||
emit volumeReceived(requestId, volumeObject);
|
||||
} else if (xml.name() == "sources") {
|
||||
SourcesObject sourcesObject;
|
||||
if(xml.attributes().hasAttribute("deviceID")) {
|
||||
|
|
@ -643,7 +845,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit sourcesReceived(sourcesObject);
|
||||
emit sourcesReceived(requestId, sourcesObject);
|
||||
} else if (xml.name() == "bass") {
|
||||
BassObject bassObject;
|
||||
if(xml.attributes().hasAttribute("deviceID")) {
|
||||
|
|
@ -661,7 +863,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit bassReceived(bassObject);
|
||||
emit bassReceived(requestId, bassObject);
|
||||
} else if (xml.name() == "bassCapabilities") {
|
||||
BassCapabilitiesObject bassCapabilities;
|
||||
|
||||
|
|
@ -686,7 +888,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit bassCapabilitiesReceived(bassCapabilities);
|
||||
emit bassCapabilitiesReceived(requestId, bassCapabilities);
|
||||
} else if (xml.name() == "presets") {
|
||||
PresetObject preset;
|
||||
if(xml.attributes().hasAttribute("id")) {
|
||||
|
|
@ -713,7 +915,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit presetsReceived(preset);
|
||||
emit presetsReceived(requestId, preset);
|
||||
|
||||
} else if (xml.name() == "group") {
|
||||
GroupObject group;
|
||||
|
|
@ -735,7 +937,7 @@ void SoundTouch::onRestRequestFinished() {
|
|||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
emit groupReceived(group);
|
||||
emit groupReceived(requestId, group);
|
||||
} else if (xml.name() == "zone") {
|
||||
ZoneObject zone;
|
||||
if(xml.attributes().hasAttribute("master")) {
|
||||
|
|
@ -753,43 +955,10 @@ void SoundTouch::onRestRequestFinished() {
|
|||
}
|
||||
zone.members.append(member);
|
||||
}
|
||||
emit zoneReceived(zone);
|
||||
emit zoneReceived(requestId, zone);
|
||||
}
|
||||
else {
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundTouch::onRestRequestError(QNetworkReply::NetworkError error)
|
||||
{
|
||||
Q_UNUSED(error)
|
||||
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
qWarning(dcBose) << "Rest Error" << reply->errorString();
|
||||
}
|
||||
|
||||
|
||||
void SoundTouch::onWebsocketMessageReceived(QString message)
|
||||
{
|
||||
qDebug(dcBose) << "Websocket message received:" << message;
|
||||
|
||||
}
|
||||
|
||||
void SoundTouch::sendGetRequest(QString path)
|
||||
{
|
||||
QUrl url;
|
||||
url.setHost(m_ipAddress);
|
||||
url.setScheme("http");
|
||||
url.setPort(m_port);
|
||||
url.setPath(path);
|
||||
//qDebug(dcBose) << "Sending request" << url;
|
||||
QNetworkRequest request = QNetworkRequest(url);
|
||||
|
||||
QNetworkReply *reply = m_networkAccessManager->get(request);
|
||||
m_getRepliesPending = true;
|
||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRestRequestError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,30 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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
|
||||
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||
* 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 SOUNDTOUCH_H
|
||||
#define SOUNDTOUCH_H
|
||||
|
|
@ -26,6 +32,7 @@
|
|||
#include <QObject>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QtWebSockets/QtWebSockets>
|
||||
#include <QUuid>
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
#include "soundtouchtypes.h"
|
||||
|
|
@ -40,37 +47,32 @@ class SoundTouch : public QObject
|
|||
public:
|
||||
explicit SoundTouch(NetworkAccessManager *networkAccessManager, QString ipAddress, QObject *parent = nullptr);
|
||||
|
||||
void getInfo(); //Get basic information about a product.
|
||||
void getVolume(); //Get the current volume and mute status of a product.
|
||||
void getNowPlaying(); //Get information about what's playing on a product.
|
||||
void getBass(); //Get the bass level of a product, if supported.
|
||||
void getGroup(); //Get the current left/right stereo pair configuration of a product.
|
||||
void getSources(); //Get available sources for a product.
|
||||
void getZone(); //Get the current multiroom zone state of a product.
|
||||
void getPresets(); //Get information related to the user's SoundTouch presets.
|
||||
void getBassCapabilities(); //Get whether a product supports reducing bass.
|
||||
|
||||
void setKey(KEY_VALUE keyValue); //Start and control playback on a product.
|
||||
void setVolume(int volume); //Set the volume of a product.
|
||||
void setSource(ContentItemObject contentItem); //Select a product's source.
|
||||
void setZone(ZoneObject zone); //Create a zone of synced products.
|
||||
void addZoneSlave(ZoneObject zone); //Add one or more slave product(s) to a multiroom zone.
|
||||
void removeZoneSlave(ZoneObject zone); //Remove one or more slave product(s) from a multiroom zone.
|
||||
void setBass(int volume); //Set the bass level of a product, if supported.*/
|
||||
void setName(QString name); //Set the products user-facing name.
|
||||
void setSpeaker(PlayInfoObject playInfo); //initiate playback of a specified network-accessible audio file on a Bose SoundTouch product.
|
||||
QUuid getInfo(); //Get basic information about a product.
|
||||
QUuid getVolume(); //Get the current volume and mute status of a product.
|
||||
QUuid getNowPlaying(); //Get information about what's playing on a product.
|
||||
QUuid getBass(); //Get the bass level of a product, if supported.
|
||||
QUuid getGroup(); //Get the current left/right stereo pair configuration of a product.
|
||||
QUuid getZone(); //Get the current multiroom zone state of a product.
|
||||
QUuid getBassCapabilities(); //Get whether a product supports reducing bass.
|
||||
QUuid getSources(); //Get available sources for a product.
|
||||
QUuid getPresets(); //Get information related to the user's SoundTouch presets.
|
||||
|
||||
//ACTIONS
|
||||
QUuid setKey(KEY_VALUE keyValue); //Start and control playback on a product.
|
||||
QUuid setVolume(int volume); //Set the volume of a product.
|
||||
QUuid setSource(ContentItemObject contentItem); //Select a product's source.
|
||||
QUuid setZone(ZoneObject zone); //Create a zone of synced products.
|
||||
QUuid addZoneSlave(ZoneObject zone); //Add one or more slave product(s) to a multiroom zone.
|
||||
QUuid removeZoneSlave(ZoneObject zone); //Remove one or more slave product(s) from a multiroom zone.
|
||||
QUuid setBass(int volume); //Set the bass level of a product, if supported.*/
|
||||
QUuid setName(QString name); //Set the products user-facing name.
|
||||
QUuid setSpeaker(PlayInfoObject playInfo); //initiate playback of a specified network-accessible audio file on a Bose SoundTouch product.
|
||||
|
||||
private:
|
||||
enum RequestType {
|
||||
Get,
|
||||
Post
|
||||
};
|
||||
|
||||
void sendGetRequest(QString path);
|
||||
//get calls are getting queued to don't overstrain the device
|
||||
//post calls must get sent immediately
|
||||
//if an get call of the same URL is already in the queu the new one will be ignored
|
||||
QUuid sendGetRequest(QString path);
|
||||
//Get calls are getting queued to don't overstrain the device
|
||||
//Post calls must be sent immediately
|
||||
//If an get call of the same URL is already in the queu the new one will be ignored
|
||||
QList<QString> m_getRequestQueue;
|
||||
bool m_getRepliesPending = false;
|
||||
|
||||
|
|
@ -78,26 +80,29 @@ private:
|
|||
QString m_ipAddress;
|
||||
int m_port = 8090;
|
||||
QWebSocket *m_websocket = nullptr;
|
||||
void emitRequestStatus(QUuid requestId, const QByteArray &data); //returns the status, -1 in case of error
|
||||
void parseData(QUuid requestId, const QByteArray &data);
|
||||
|
||||
signals:
|
||||
void connectionChanged(bool connected);
|
||||
|
||||
void infoReceived(InfoObject info);
|
||||
void nowPlayingReceived(NowPlayingObject nowPlaying);
|
||||
void volumeReceived(VolumeObject volume);
|
||||
void sourcesReceived(SourcesObject sources);
|
||||
void zoneReceived(ZoneObject);
|
||||
void bassCapabilitiesReceived(BassCapabilitiesObject bassCapabilities);
|
||||
void bassReceived(BassObject bass);
|
||||
void presetsReceived(PresetObject presets);
|
||||
void groupReceived(GroupObject group);
|
||||
void infoReceived(QUuid requestId, InfoObject info);
|
||||
void nowPlayingReceived(QUuid requestId, NowPlayingObject nowPlaying);
|
||||
void volumeReceived(QUuid requestId, VolumeObject volume);
|
||||
void sourcesReceived(QUuid requestId, SourcesObject sources);
|
||||
void zoneReceived(QUuid requestId, ZoneObject);
|
||||
void bassCapabilitiesReceived(QUuid requestId, BassCapabilitiesObject bassCapabilities);
|
||||
void bassReceived(QUuid requestId, BassObject bass);
|
||||
void presetsReceived(QUuid requestId, PresetObject presets);
|
||||
void groupReceived(QUuid requestId, GroupObject group);
|
||||
|
||||
void requestExecuted(QUuid requestId, bool success);
|
||||
void errorReceived(ErrorObject error);
|
||||
|
||||
private slots:
|
||||
void onWebsocketConnected();
|
||||
void onWebsocketDisconnected();
|
||||
void onWebsocketMessageReceived(QString message);
|
||||
void onRestRequestFinished();
|
||||
void onRestRequestError(QNetworkReply::NetworkError error);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,30 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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
|
||||
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||
* 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 SOUNDTOUCHTYPES_H
|
||||
#define SOUNDTOUCHTYPES_H
|
||||
|
|
@ -246,5 +252,14 @@ struct PlayInfoObject {
|
|||
QString message; //Element. This indicates further details about the notification. This text will appear on the device display (when available) and the SoundTouch application screen. If a message string is not provided, the field with be blank.
|
||||
int volume; //Element. This indicates the desired volume level while playing the notification. The value represents a percentage (0 to 100) of the full audible range of the speaker device. A value less than 10 or greater than 70 will result in an error and not play the notification. Upon completion of the notification, the speaker volume will return to its original value. If not present, the notification will play at the existing volume level.
|
||||
};
|
||||
|
||||
struct ErrorObject{
|
||||
QString deviceId;
|
||||
int value;
|
||||
QString name;
|
||||
QString severity;
|
||||
QString error;
|
||||
};
|
||||
|
||||
#endif // SOUNDTOUCHTYPES_H
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue