From 23ff818577281dcdb3fc718c1d70cf79c0cc12f1 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 9 Oct 2019 14:52:58 +0200 Subject: [PATCH] Update to latest api changes --- sonos/devicepluginsonos.cpp | 169 ++++++++++++++++++----------------- sonos/devicepluginsonos.h | 10 +-- sonos/devicepluginsonos.json | 5 +- sonos/sonos.cpp | 114 +++++++++++++---------- 4 files changed, 164 insertions(+), 134 deletions(-) diff --git a/sonos/devicepluginsonos.cpp b/sonos/devicepluginsonos.cpp index 80bfce5d..2fa4eb90 100644 --- a/sonos/devicepluginsonos.cpp +++ b/sonos/devicepluginsonos.cpp @@ -44,8 +44,10 @@ DevicePluginSonos::~DevicePluginSonos() } -Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device) +void DevicePluginSonos::setupDevice(DeviceSetupInfo *info) { + Device *device = info->device(); + if (!m_pluginTimer5sec) { m_pluginTimer5sec = hardwareManager()->pluginTimerManager()->registerTimer(5); connect(m_pluginTimer5sec, &PluginTimer::timeout, this, [this]() { @@ -98,8 +100,17 @@ Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device) connect(sonos, &Sonos::volumeReceived, this, &DevicePluginSonos::onVolumeReceived); connect(sonos, &Sonos::actionExecuted, this, &DevicePluginSonos::onActionExecuted); connect(sonos, &Sonos::authenticationStatusChanged, this, &DevicePluginSonos::onAuthenticationStatusChanged); + + connect(sonos, &Sonos::authenticationStatusChanged, info, [info](bool authenticated){ + if (authenticated) { + info->finish(Device::DeviceErrorNoError); + } else { + info->finish(Device::DeviceErrorAuthenticationFailure); + } + }); + m_sonosConnections.insert(device, sonos); - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } else { //device loaded from the device database, needs a new access token; pluginStorage()->beginGroup(device->id().toString()); @@ -117,39 +128,39 @@ Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device) connect(sonos, &Sonos::authenticationStatusChanged, this, &DevicePluginSonos::onAuthenticationStatusChanged); sonos->getAccessTokenFromRefreshToken(refreshToken); m_sonosConnections.insert(device, sonos); - return Device::DeviceSetupStatusAsync; + return info->finish(Device::DeviceErrorNoError); } } if (device->deviceClassId() == sonosGroupDeviceClassId) { - return Device::DeviceSetupStatusSuccess; + return info->finish(Device::DeviceErrorNoError); } - return Device::DeviceSetupStatusFailure; + + qCWarning(dcSonos()) << "Unhandled device class id in setupDevice" << device->deviceClassId(); } -DevicePairingInfo DevicePluginSonos::pairDevice(DevicePairingInfo &devicePairingInfo) +void DevicePluginSonos::startPairing(DevicePairingInfo *info) { - if (devicePairingInfo.deviceClassId() == sonosConnectionDeviceClassId) { + if (info->deviceClassId() == sonosConnectionDeviceClassId) { Sonos *sonos = new Sonos(hardwareManager()->networkManager(), "0a8f6d44-d9d1-4474-bcfa-cfb41f8b66e8", "3095ce48-0c5d-47ce-a1f4-6005c7b8fdb5", this); QUrl url = sonos->getLoginUrl(QUrl("https://127.0.0.1:8888")); qCDebug(dcSonos()) << "Sonos url:" << url; - devicePairingInfo.setOAuthUrl(url); - devicePairingInfo.setStatus(Device::DeviceErrorNoError); - m_setupSonosConnections.insert(devicePairingInfo.deviceId(), sonos); - return devicePairingInfo; + info->setOAuthUrl(url); + info->finish(Device::DeviceErrorNoError); + m_setupSonosConnections.insert(info->deviceId(), sonos); + return; } qCWarning(dcSonos()) << "Unhandled pairing metod!"; - devicePairingInfo.setStatus(Device::DeviceErrorCreationMethodNotSupported); - return devicePairingInfo; + info->finish(Device::DeviceErrorCreationMethodNotSupported); } -DevicePairingInfo DevicePluginSonos::confirmPairing(DevicePairingInfo &devicePairingInfo, const QString &username, const QString &secret) +void DevicePluginSonos::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) { - Q_UNUSED(username); + Q_UNUSED(username) - if (devicePairingInfo.deviceClassId() == sonosConnectionDeviceClassId) { + if (info->deviceClassId() == sonosConnectionDeviceClassId) { qCDebug(dcSonos()) << "Redirect url is" << secret; QUrl url(secret); QUrlQuery query(url); @@ -157,44 +168,39 @@ DevicePairingInfo DevicePluginSonos::confirmPairing(DevicePairingInfo &devicePai QByteArray state = query.queryItemValue("state").toLocal8Bit(); //TODO evaluate state if it equals the given state - Sonos *sonos = m_setupSonosConnections.value(devicePairingInfo.deviceId()); + Sonos *sonos = m_setupSonosConnections.value(info->deviceId()); if (!sonos) { - qWarning(dcSonos()) << "No sonos connection found for device:" << devicePairingInfo.deviceName(); - m_setupSonosConnections.remove(devicePairingInfo.deviceId()); + qWarning(dcSonos()) << "No sonos connection found for device:" << info->deviceName(); + m_setupSonosConnections.remove(info->deviceId()); sonos->deleteLater(); - devicePairingInfo.setStatus(Device::DeviceErrorHardwareFailure); - return devicePairingInfo; + info->finish(Device::DeviceErrorHardwareFailure); + return; } sonos->getAccessTokenFromAuthorizationCode(authorizationCode); - connect(sonos, &Sonos::authenticationStatusChanged, this, [devicePairingInfo, this](bool authenticated){ + connect(sonos, &Sonos::authenticationStatusChanged, info, [this, info](bool authenticated){ Sonos *sonos = static_cast(sender()); - DevicePairingInfo info(devicePairingInfo); if(!authenticated) { - qWarning(dcSonos()) << "Authentication process failed" << devicePairingInfo.deviceName(); - m_setupSonosConnections.remove(info.deviceId()); + qWarning(dcSonos()) << "Authentication process failed" << info->deviceName(); + m_setupSonosConnections.remove(info->deviceId()); sonos->deleteLater(); - info.setStatus(Device::DeviceErrorSetupFailed); - emit pairingFinished(info); + info->finish(Device::DeviceErrorSetupFailed, QT_TR_NOOP("Authentication failed. Please try again.")); return; } QByteArray accessToken = sonos->accessToken(); QByteArray refreshToken = sonos->refreshToken(); qCDebug(dcSonos()) << "Token:" << accessToken << refreshToken; - pluginStorage()->beginGroup(info.deviceId().toString()); + pluginStorage()->beginGroup(info->deviceId().toString()); pluginStorage()->setValue("refresh_token", refreshToken); pluginStorage()->endGroup(); - info.setStatus(Device::DeviceErrorNoError); - emit pairingFinished(info); + info->finish(Device::DeviceErrorNoError); }); - devicePairingInfo.setStatus(Device::DeviceErrorAsync); - return devicePairingInfo; + return; } qCWarning(dcSonos()) << "Invalid deviceclassId -> no pairing possible with this device"; - devicePairingInfo.setStatus(Device::DeviceErrorHardwareFailure); - return devicePairingInfo; + info->finish(Device::DeviceErrorDeviceClassNotFound); } void DevicePluginSonos::postSetupDevice(Device *device) @@ -239,88 +245,91 @@ void DevicePluginSonos::deviceRemoved(Device *device) } -Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Action &action) +void DevicePluginSonos::executeAction(DeviceActionInfo *info) { + Device *device = info->device(); + Action action = info->action(); + if (device->deviceClassId() == sonosGroupDeviceClassId) { Sonos *sonos = m_sonosConnections.value(myDevices().findById(device->parentId())); QString groupId = device->paramValue(sonosGroupDeviceGroupIdParamTypeId).toString(); if (!sonos) { qWarning(dcSonos()) << "Action cannot be executed: Sonos connection not available"; - return Device::DeviceErrorInvalidParameter; + return info->finish(Device::DeviceErrorHardwareNotAvailable, QT_TR_NOOP("Sonos device is not available.")); } if (action.actionTypeId() == sonosGroupPlayActionTypeId) { - m_pendingActions.insert(sonos->groupPlay(groupId), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->groupPlay(groupId), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupShuffleActionTypeId) { bool shuffle = action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toBool(); - m_pendingActions.insert(sonos->groupSetShuffle(groupId, shuffle), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->groupSetShuffle(groupId, shuffle), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupRepeatActionTypeId) { if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "None") { - m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeNone), action.id()); + m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeNone), QPointer(info)); } else if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "One") { - m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeOne), action.id()); + m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeOne), QPointer(info)); } else if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "All") { - m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeAll), action.id()); + m_pendingActions.insert(sonos->groupSetRepeat(groupId, Sonos::RepeatModeAll), QPointer(info)); } else { - return Device::DeviceErrorHardwareFailure; + return info->finish(Device::DeviceErrorHardwareFailure); } - return Device::DeviceErrorAsync; + return; } if (action.actionTypeId() == sonosGroupPauseActionTypeId) { - m_pendingActions.insert(sonos->groupPause(groupId), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->groupPause(groupId), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupStopActionTypeId) { - m_pendingActions.insert(sonos->groupPause(groupId), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->groupPause(groupId), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupMuteActionTypeId) { bool mute = action.param(sonosGroupMuteActionMuteParamTypeId).value().toBool(); - m_pendingActions.insert(sonos->setGroupMute(groupId, mute), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->setGroupMute(groupId, mute), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupVolumeActionTypeId) { int volume = action.param(sonosGroupVolumeActionVolumeParamTypeId).value().toInt(); - m_pendingActions.insert(sonos->setGroupVolume(groupId, volume), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->setGroupVolume(groupId, volume), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupSkipNextActionTypeId) { - m_pendingActions.insert(sonos->groupSkipToNextTrack(groupId), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->groupSkipToNextTrack(groupId), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupSkipBackActionTypeId) { - m_pendingActions.insert(sonos->groupSkipToPreviousTrack(groupId), action.id()); - return Device::DeviceErrorAsync; + m_pendingActions.insert(sonos->groupSkipToPreviousTrack(groupId), QPointer(info)); + return; } if (action.actionTypeId() == sonosGroupPlaybackStatusActionTypeId) { QString playbackStatus = action.param(sonosGroupPlaybackStatusActionPlaybackStatusParamTypeId).value().toString(); if (playbackStatus == "Playing") { - m_pendingActions.insert(sonos->groupPlay(groupId), action.id()); + m_pendingActions.insert(sonos->groupPlay(groupId), QPointer(info)); } else if(playbackStatus == "Stopped") { - m_pendingActions.insert(sonos->groupPause(groupId), action.id()); + m_pendingActions.insert(sonos->groupPause(groupId), QPointer(info)); } else if(playbackStatus == "Paused") { - m_pendingActions.insert(sonos->groupPause(groupId), action.id()); + m_pendingActions.insert(sonos->groupPause(groupId), QPointer(info)); } - return Device::DeviceErrorAsync; + return; } - return Device::DeviceErrorActionTypeNotFound; + return info->finish(Device::DeviceErrorActionTypeNotFound); } - return Device::DeviceErrorDeviceClassNotFound; + info->finish(Device::DeviceErrorDeviceClassNotFound); } void DevicePluginSonos::onConnectionChanged(bool connected) @@ -343,21 +352,13 @@ void DevicePluginSonos::onAuthenticationStatusChanged(bool authenticated) if (!device) return; - if (!device->setupComplete()) { - if (authenticated) { - emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess); - } else { - emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure); - } - } else { - device->setStateValue(sonosConnectionLoggedInStateTypeId, authenticated); - if (!authenticated) { - //refresh access token needs to be refreshed - pluginStorage()->beginGroup(device->id().toString()); - QByteArray refreshToken = pluginStorage()->value("refresh_token").toByteArray(); - pluginStorage()->endGroup(); - sonosConnection->getAccessTokenFromRefreshToken(refreshToken); - } + device->setStateValue(sonosConnectionLoggedInStateTypeId, authenticated); + if (!authenticated) { + //refresh access token needs to be refreshed + pluginStorage()->beginGroup(device->id().toString()); + QByteArray refreshToken = pluginStorage()->value("refresh_token").toByteArray(); + pluginStorage()->endGroup(); + sonosConnection->getAccessTokenFromRefreshToken(refreshToken); } } @@ -421,7 +422,7 @@ void DevicePluginSonos::onGroupsReceived(const QString &householdId, QListid())) { @@ -495,11 +496,15 @@ void DevicePluginSonos::onVolumeReceived(const QString &groupId, Sonos::VolumeOb void DevicePluginSonos::onActionExecuted(QUuid sonosActionId, bool success) { if (m_pendingActions.contains(sonosActionId)) { - ActionId nymeaActionId = m_pendingActions.value(sonosActionId); + QPointer info = m_pendingActions.value(sonosActionId); + if (info.isNull()) { + qCWarning(dcSonos()) << "DeviceActionInfo has disappeared. Did it time out?"; + return; + } if (success) { - emit actionExecutionFinished(nymeaActionId, Device::DeviceErrorNoError); + info->finish(Device::DeviceErrorNoError); } else { - emit actionExecutionFinished(nymeaActionId, Device::DeviceErrorHardwareFailure); + info->finish(Device::DeviceErrorHardwareFailure); } } } diff --git a/sonos/devicepluginsonos.h b/sonos/devicepluginsonos.h index fcf2eb38..f72d4796 100644 --- a/sonos/devicepluginsonos.h +++ b/sonos/devicepluginsonos.h @@ -40,14 +40,14 @@ public: explicit DevicePluginSonos(); ~DevicePluginSonos() override; - Device::DeviceSetupStatus setupDevice(Device *device) override; - DevicePairingInfo pairDevice(DevicePairingInfo &devicePairingInfo) override; - DevicePairingInfo confirmPairing(DevicePairingInfo &devicePairingInfo, const QString &username, const QString &secret) override; + void setupDevice(DeviceSetupInfo *info) override; + void startPairing(DevicePairingInfo *info) override; + void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override; void postSetupDevice(Device *device) override; void startMonitoringAutoDevices() override; void deviceRemoved(Device *device) override; - Device::DeviceError executeAction(Device *device, const Action &action) override; + void executeAction(DeviceActionInfo *info) override; private: PluginTimer *m_pluginTimer5sec = nullptr; @@ -60,7 +60,7 @@ private: QByteArray m_sonosConnectionAccessToken; QByteArray m_sonosConnectionRefreshToken; - QHash m_pendingActions; + QHash > m_pendingActions; private slots: void onConnectionChanged(bool connected); diff --git a/sonos/devicepluginsonos.json b/sonos/devicepluginsonos.json index aa46d38b..97b23875 100644 --- a/sonos/devicepluginsonos.json +++ b/sonos/devicepluginsonos.json @@ -13,7 +13,7 @@ "id": "22df416d-7732-44f1-b6b9-e41296211178", "name": "sonosConnection", "displayName": "Sonos connection", - "interfaces": ["gateway"], + "interfaces": ["account", "gateway"], "createMethods": ["user"], "setupMethod": "oauth", "paramTypes": [ @@ -40,7 +40,8 @@ "name": "userDisplayName", "displayName": "User name", "displayNameEvent": "User name changed", - "type": "QString" + "type": "QString", + "defaultValue": "" } ] }, diff --git a/sonos/sonos.cpp b/sonos/sonos.cpp index 1f58218e..356a0f80 100644 --- a/sonos/sonos.cpp +++ b/sonos/sonos.cpp @@ -102,15 +102,15 @@ void Sonos::getHouseholds() emit connectionChanged(true); emit authenticationStatusChanged(true); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) { + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { qDebug(dcSonos()) << "Household ID: Recieved invalide JSON object"; return; } QList households; - QJsonArray jsonArray = data["households"].toArray(); - foreach (const QJsonValue & value, jsonArray) { - QJsonObject obj = value.toObject(); + foreach (const QVariant &variant, data.toVariant().toMap().value("households").toList()) { + QVariantMap obj = variant.toMap(); qDebug(dcSonos()) << "Household ID received:" << obj["id"].toString(); households.append(obj["id"].toString()); } @@ -182,18 +182,21 @@ void Sonos::getFavorites(const QString &householdId) emit connectionChanged(true); emit authenticationStatusChanged(true); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcSonos()) << "Invalid json received from server"; + return; + } + + if (!data.toVariant().toMap().contains("items")) return; - if (!data["items"].isArray()) - return; - - QJsonArray array = data["items"].toArray(); + QVariantList array = data.toVariant().toMap().value("items").toList(); QList favourites ; - foreach (const QJsonValue & value, array) { - QJsonObject itemObject = value.toObject(); + foreach (const QVariant &variant, array) { + QVariantMap itemObject = variant.toMap(); qDebug(dcSonos()) << "Item ID received:" << itemObject["id"].toString(); FavouriteObject favourite; favourite.id = itemObject["id"].toString(); @@ -233,17 +236,18 @@ void Sonos::getGroups(const QString &householdId) emit authenticationStatusChanged(true); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) return; - if (!data["groups"].isArray()) + if (!data.toVariant().toMap().contains("groups")) return; - QJsonArray array = data["groups"].toArray(); + QVariantList array = data.toVariant().toMap().value("groups").toList(); QList groupObjects; - foreach (const QJsonValue & value, array) { - QJsonObject obj = value.toObject(); + foreach (const QVariant &value, array) { + QVariantMap obj = value.toMap(); qDebug(dcSonos()) << "Group ID received:" << obj["id"].toString(); GroupObject group; group.groupId = obj["id"].toString(); @@ -281,15 +285,19 @@ void Sonos::getGroupVolume(const QString &groupId) emit authenticationStatusChanged(true); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcSonos()) << "JSON Parse error" << error.errorString(); return; + } VolumeObject volume; - volume.volume = data["volume"].toInt(); - volume.muted = data["muted"].toBool(); - volume.fixed = data["fixed"].toBool(); + QVariantMap variant = data.toVariant().toMap(); + volume.volume = variant["volume"].toInt(); + volume.muted = variant["muted"].toBool(); + volume.fixed = variant["fixed"].toBool(); emit volumeReceived(groupId, volume); }); @@ -1100,14 +1108,18 @@ void Sonos::getPlayerVolume(const QByteArray &playerId) emit authenticationStatusChanged(true); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcSonos()) << "Json parse error" << error.errorString(); return; + } VolumeObject volume; - volume.volume = data["volume"].toInt(); - volume.muted = data["muted"].toBool(); - volume.fixed = data["fixed"].toBool(); + QVariantMap variant = data.toVariant().toMap(); + volume.volume = variant["volume"].toInt(); + volume.muted = variant["muted"].toBool(); + volume.fixed = variant["fixed"].toBool(); emit playerVolumeReceived(playerId, volume); }); } @@ -1261,17 +1273,22 @@ void Sonos::getPlaylist(const QString &householdId, const QString &playlistId) emit authenticationStatusChanged(true); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcSonos()) << "Json parse error" << error.errorString(); return; + } - if (!data["tracks"].isArray()) + QVariantMap variant = data.toVariant().toMap(); + + if (!variant.contains("tracks")) return; PlaylistSummaryObject playlist; - QJsonArray array = data["tracks"].toArray(); - foreach (const QJsonValue & value, array) { - QJsonObject itemObject = value.toObject(); + QVariantList array = variant["tracks"].toList(); + foreach (const QVariant &value, array) { + QVariantMap itemObject = value.toMap(); qDebug(dcSonos()) << "Item ID received:" << itemObject["id"].toString(); PlaylistTrackObject track; track.name = itemObject["name"].toString(); @@ -1310,17 +1327,20 @@ void Sonos::getPlaylists(const QString &householdId) emit authenticationStatusChanged(true); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (!data.isObject()) { + qCWarning(dcSonos()) << "Json parse error:" << error.errorString(); + return; + } + + if (!data.toVariant().toMap().contains("playlists")) return; - if (!data["items"].isArray()) - return; - - QJsonArray array = data["playlists"].toArray(); + QVariantList array = data.toVariant().toMap().value("playlists").toList(); QList playlists; - foreach (const QJsonValue & value, array) { - QJsonObject itemObject = value.toObject(); + foreach (const QVariant &value, array) { + QVariantMap itemObject = value.toMap(); qDebug(dcSonos()) << "Item ID received:" << itemObject["id"].toString(); PlaylistObject playlist; playlist.id = itemObject["id"].toString(); @@ -1396,10 +1416,14 @@ void Sonos::getPlayerSettings(const QString &playerId) emit connectionChanged(true); emit authenticationStatusChanged(true); - QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); - if (!data.isObject()) + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcSonos()) << "Json parse error" << error.errorString(); return; + } + QVariantMap data = jsonDoc.toVariant().toMap(); PlayerSettingsObject playerSettings; playerSettings.monoMode = data["monoMode"].toBool(); playerSettings.volumeMode = data["volumeMode"].toString();