moved authentication into sonos class

master
nymea 2019-09-06 00:26:10 +02:00 committed by Michael Zanetti
parent 5ba83790c8
commit cd17134c19
9 changed files with 243 additions and 454 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "sonos/sonos/noson"]
path = sonos/sonos/noson
url = https://github.com/janbar/noson.git

View File

@ -32,7 +32,6 @@
DevicePluginSonos::DevicePluginSonos()
{
}
@ -83,20 +82,22 @@ Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
});
}
if(!m_tokenRefreshTimer) {
m_tokenRefreshTimer = new QTimer(this);
m_tokenRefreshTimer->setSingleShot(false);
connect(m_tokenRefreshTimer, &QTimer::timeout, this, &DevicePluginSonos::onRefreshTimeout);
}
if (device->deviceClassId() == sonosConnectionDeviceClassId) {
qCDebug(dcSonos()) << "Sonos OAuth setup complete";
Sonos *sonos;
if (m_setupSonosConnections.keys().contains(device->id())) {
//Fresh device setup, has already a fresh access token
sonos = m_setupSonosConnections.take(device->id());
} else {
//device loaded from the device database, needs a new access token;
pluginStorage()->beginGroup(device->id().toString());
QByteArray refreshToken = pluginStorage()->value("refresh_token").toByteArray();
pluginStorage()->endGroup();
pluginStorage()->beginGroup(device->id().toString());
QByteArray accessToken = pluginStorage()->value("access_token").toByteArray();
pluginStorage()->endGroup();
sonos = new Sonos(hardwareManager()->networkManager(), "b15cbf8c-a39c-47aa-bd93-635a96e9696c", "c086ba71-e562-430b-a52f-867c6482fd11", "", this);
sonos->getAccessTokenFromRefreshToken(refreshToken);
}
Sonos *sonos = new Sonos(hardwareManager()->networkManager(), accessToken, this);
connect(sonos, &Sonos::connectionChanged, this, &DevicePluginSonos::onConnectionChanged);
connect(sonos, &Sonos::householdIdsReceived, this, &DevicePluginSonos::onHouseholdIdsReceived);
connect(sonos, &Sonos::groupsReceived, this, &DevicePluginSonos::onGroupsReceived);
@ -115,22 +116,13 @@ Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
DevicePairingInfo DevicePluginSonos::pairDevice(DevicePairingInfo &devicePairingInfo)
{
if (devicePairingInfo.deviceClassId() == sonosConnectionDeviceClassId) {
QString clientId = "b15cbf8c-a39c-47aa-bd93-635a96e9696c";
QString clientSecret = "c086ba71-e562-430b-a52f-867c6482fd11";
QUrl url("https://api.sonos.com/login/v3/oauth");
QUrlQuery queryParams;
queryParams.addQueryItem("client_id", clientId);
queryParams.addQueryItem("redirect_uri", "https://127.0.0.1:8888");
queryParams.addQueryItem("response_type", "code");
queryParams.addQueryItem("scope", "playback-control-all");
queryParams.addQueryItem("state", QUuid::createUuid().toString());
url.setQuery(queryParams);
Sonos *sonos = new Sonos(hardwareManager()->networkManager(), "b15cbf8c-a39c-47aa-bd93-635a96e9696c", "c086ba71-e562-430b-a52f-867c6482fd11", "", this);
QUrl url = sonos->getLoginUrl(QUrl("https://127.0.0.1:8000"));
qCDebug(dcSonos()) << "Sonos url:" << url;
devicePairingInfo.setOAuthUrl(url);
devicePairingInfo.setStatus(Device::DeviceErrorNoError);
m_setupSonosConnections.insert(devicePairingInfo.deviceId(), sonos);
return devicePairingInfo;
}
@ -148,61 +140,39 @@ DevicePairingInfo DevicePluginSonos::confirmPairing(DevicePairingInfo &devicePai
qCDebug(dcSonos()) << "Secret is" << secret;
QUrl url(secret);
QUrlQuery query(url);
qCDebug(dcSonos()) << "Acess code is:" << query.queryItemValue("code");
QByteArray accessCode = query.queryItemValue("code").toLocal8Bit();
qCDebug(dcSonos()) << "Acess code is:" << accessCode;
QString accessCode = query.queryItemValue("code");
Sonos *sonos = m_setupSonosConnections.value(devicePairingInfo.deviceId());
// Obtaining access token
url = QUrl("https://api.sonos.com/login/v3/oauth/access");
query.clear();
query.addQueryItem("grant_type", "authorization_code");
query.addQueryItem("code", accessCode);
query.addQueryItem("redirect_uri", "https%3A%2F%2F127.0.0.1%3A8888");
url.setQuery(query);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded;charset=utf-8");
QByteArray clientId = "b15cbf8c-a39c-47aa-bd93-635a96e9696c";
QByteArray clientSecret = "c086ba71-e562-430b-a52f-867c6482fd11";
QByteArray auth = QByteArray(clientId + ':' + clientSecret).toBase64(QByteArray::Base64Encoding | QByteArray::KeepTrailingEquals);
request.setRawHeader("Authorization", QString("Basic %1").arg(QString(auth)).toUtf8());
QNetworkReply *reply = hardwareManager()->networkManager()->post(request, QByteArray());
connect(reply, &QNetworkReply::finished, this, [this, reply, devicePairingInfo](){
reply->deleteLater();
if (!sonos) {
m_setupSonosConnections.remove(devicePairingInfo.deviceId());
sonos->deleteLater();
devicePairingInfo.setStatus(Device::DeviceErrorHardwareFailure);
return devicePairingInfo;
}
sonos->getAccessTokenFromAuthorizationCode(accessCode);
connect(sonos, &Sonos::authenticationStatusChanged, this, [devicePairingInfo, this](bool authenticated){
Sonos *sonos = static_cast<Sonos *>(sender());
DevicePairingInfo info(devicePairingInfo);
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
qCDebug(dcSonos()) << "Sonos accessToken reply:" << this << reply->error() << reply->errorString() << jsonDoc.toJson();
if(!jsonDoc.toVariant().toMap().contains("access_token") || !jsonDoc.toVariant().toMap().contains("refresh_token") ) {
if(!authenticated) {
m_setupSonosConnections.remove(info.deviceId());
sonos->deleteLater();
info.setStatus(Device::DeviceErrorSetupFailed);
emit pairingFinished(info);
return;
}
qCDebug(dcSonos()) << "Access token:" << jsonDoc.toVariant().toMap().value("access_token").toString();
QByteArray accessToken = jsonDoc.toVariant().toMap().value("access_token").toByteArray();
qCDebug(dcSonos()) << "Refresh token:" << jsonDoc.toVariant().toMap().value("refresh_token").toString();
QByteArray refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toByteArray();
QByteArray accessToken = sonos->accessToken();
QByteArray refreshToken = sonos->refreshToken();
pluginStorage()->beginGroup(info.deviceId().toString());
pluginStorage()->setValue("access_token", accessToken);
pluginStorage()->setValue("refresh_token", refreshToken);
pluginStorage()->endGroup();
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
//m_tokenRefreshTimer->start((expireTime - 20) * 1000);
//TODO
}
info.setStatus(Device::DeviceErrorNoError);
emit pairingFinished(info);
});
devicePairingInfo.setStatus(Device::DeviceErrorAsync);
return devicePairingInfo;
}
@ -348,39 +318,18 @@ void DevicePluginSonos::onConnectionChanged(bool connected)
}
}
void DevicePluginSonos::onRefreshTimeout()
void DevicePluginSonos::onAuthenticationStatusChanged(bool authenticated)
{
qCDebug(dcSonos) << "Refresh authentication token";
QUrlQuery query;
query.addQueryItem("grant_type", "refresh_token");
query.addQueryItem("refresh_token", m_sonosConnectionRefreshToken);
QUrl url("https://api.sonos.com/login/v3/oauth");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
QNetworkReply *reply = hardwareManager()->networkManager()->post(request, QByteArray());
connect(reply, &QNetworkReply::finished, this, [this, reply](){
reply->deleteLater();
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
qCDebug(dcSonos()) << "Sonos accessToken reply:" << this << reply->error() << reply->errorString() << jsonDoc.toJson();
if(!jsonDoc.toVariant().toMap().contains("access_token")) {
return;
}
qCDebug(dcSonos()) << "Access token:" << jsonDoc.toVariant().toMap().value("access_token").toString();
m_sonosConnectionAccessToken = jsonDoc.toVariant().toMap().value("access_token").toByteArray();
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
if (!m_tokenRefreshTimer) {
qWarning(dcSonos()) << "Token refresh timer not initialized";
return;
}
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
}
});
Sonos *sonosConnection = static_cast<Sonos *>(sender());
Device *device = m_sonosConnections.key(sonosConnection);
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);
}
}
void DevicePluginSonos::onHouseholdIdsReceived(QList<QString> householdIds)
@ -419,8 +368,9 @@ void DevicePluginSonos::onPlaylistSummaryReceived(const QString &householdId, So
}
}
void DevicePluginSonos::onGroupsReceived(QList<Sonos::GroupObject> groupObjects)
void DevicePluginSonos::onGroupsReceived(const QString &householdId, QList<Sonos::GroupObject> groupObjects)
{
Q_UNUSED(householdId);
Sonos *sonos = static_cast<Sonos *>(sender());
Device *parentDevice = m_sonosConnections.key(sonos);
if (!parentDevice)

View File

@ -29,8 +29,6 @@
#include <QHash>
#include <QDebug>
#include <QTimer>
class DevicePluginSonos : public DevicePlugin
{
@ -54,8 +52,8 @@ public:
private:
PluginTimer *m_pluginTimer5sec = nullptr;
PluginTimer *m_pluginTimer60sec = nullptr;
QTimer *m_tokenRefreshTimer = nullptr;
QHash<DeviceId, Sonos *> m_setupSonosConnections;
QHash<Device *, Sonos *> m_sonosConnections;
QList<QByteArray> m_householdIds;
@ -63,16 +61,17 @@ private:
QByteArray m_sonosConnectionRefreshToken;
QHash<QUuid, ActionId> m_pendingActions;
private slots:
void onConnectionChanged(bool connected);
void onRefreshTimeout();
void onAuthenticationStatusChanged(bool authenticated);
void onHouseholdIdsReceived(QList<QString> householdIds);
void onFavouritesReceived(const QString &householdId, QList<Sonos::FavouriteObject> favourites);
void onPlaylistsReceived(const QString &householdId, QList<Sonos::PlaylistObject> playlists);
void onPlaylistSummaryReceived(const QString &householdId, Sonos::PlaylistSummaryObject playlistSummary);
void onGroupsReceived(QList<Sonos::GroupObject> groupIds);
void onGroupsReceived(const QString &householdId, QList<Sonos::GroupObject> groupIds);
void onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack);
void onMetadataStatusReceived(const QString &groupId, Sonos::MetadataStatus metaDataStatus);
void onVolumeReceived(const QString &groupId, Sonos::VolumeObject groupVolume);

View File

@ -26,6 +26,14 @@
"displayNameEvent": "connected changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "48b5c1bf-7df0-45d0-9ba3-290fc3acddc3",
"name": "loggedIn",
"displayName": "Logged in",
"displayNameEvent": "Logged in changed",
"defaultValue": false,
"type": "bool"
}
]
},

View File

@ -1,221 +0,0 @@
#include "oauth.h"
#include "extern-plugininfo.h"
#include <QNetworkRequest>
#include <QJsonDocument>
#include <QUuid>
OAuth::OAuth(QString clientId, QObject *parent) :
QObject(parent),
m_clientId(clientId),
m_authenticated(false)
{
m_networkManager = new QNetworkAccessManager(this);
connect(m_networkManager, &QNetworkAccessManager::finished, this, &OAuth::replyFinished);
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
connect(m_timer, &QTimer::timeout, this, &OAuth::refreshTimeout);
}
QUrl OAuth::url() const
{
return m_url;
}
void OAuth::setUrl(const QUrl &url)
{
m_url = url;
}
QUrlQuery OAuth::query() const
{
return m_query;
}
void OAuth::setQuery(const QUrlQuery &query)
{
m_query = query;
}
QString OAuth::clientId() const
{
return m_clientId;
}
void OAuth::setClientId(const QString &clientId)
{
m_clientId = clientId;
}
QString OAuth::scope() const
{
return m_scope;
}
void OAuth::setScope(const QString &scope)
{
m_scope = scope;
}
QString OAuth::authorizationCode() const
{
return m_token;
}
QString OAuth::bearerToken() const
{
return m_token;
}
bool OAuth::authenticated() const
{
return m_authenticated;
}
void OAuth::startAuthentication()
{
qCDebug(dcSonos) << "Start authentication";
QUrlQuery query;
query.addQueryItem("client_id", m_clientId);
query.addQueryItem("redirect_uri", m_redirectUri);
query.addQueryItem("response_type", "code");
query.addQueryItem("scope", m_scope);
m_state = QUuid().toByteArray();
query.addQueryItem("state", m_state);
setQuery(query);
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
m_tokenRequests.append(m_networkManager->post(request, m_query.toString().toUtf8()));
}
void OAuth::setAuthenticated(const bool &authenticated)
{
if (authenticated) {
qCDebug(dcSonos()) << "Authenticated successfully";
} else {
m_timer->stop();
qCWarning(dcSonos) << "Authentication failed";
}
m_authenticated = authenticated;
emit authenticationChanged();
}
void OAuth::setToken(const QString &token)
{
m_token = token;
emit tokenChanged();
}
void OAuth::replyFinished(QNetworkReply *reply)
{
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
reply->deleteLater();
// token request
if (m_tokenRequests.contains(reply)) {
QByteArray data = reply->readAll();
m_tokenRequests.removeAll(reply);
// check HTTP status code
if (status != 200) {
qCWarning(dcSonos) << "Request token reply HTTP error:" << status << reply->errorString();
qCWarning(dcSonos) << data;
setAuthenticated(false);
return;
}
// check JSON
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcSonos) << "Request token reply JSON error:" << error.errorString();
setAuthenticated(false);
return;
}
if (!jsonDoc.toVariant().toMap().contains("code")) {
qCWarning(dcSonos) << "Could not get code" << jsonDoc.toJson();
setAuthenticated(false);
return;
}
if (!jsonDoc.toVariant().toMap().contains("state")) {
qCWarning(dcSonos) << "Could not get state" << jsonDoc.toJson();
return;
}
if (jsonDoc.toVariant().toMap().value("state").toString() != m_state) {
qCWarning(dcSonos) << "State doesn't match. Expected:" << m_state << "Received:" << jsonDoc.toVariant().toMap().value("state").toString();
}
setToken(jsonDoc.toVariant().toMap().value("code").toString());
setAuthenticated(true);
if (jsonDoc.toVariant().toMap().contains("expires_in") && jsonDoc.toVariant().toMap().contains("refresh_token")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toString();
qCDebug(dcSonos) << "Token will be refreshed in" << expireTime << "[s]";
m_timer->start((expireTime - 20) * 1000);
}
} else if (m_refreshTokenRequests.contains(reply)) {
QByteArray data = reply->readAll();
m_refreshTokenRequests.removeAll(reply);
// check HTTP status code
if (status != 200) {
qCWarning(dcSonos) << "Refresh token reply HTTP error:" << status << reply->errorString();
qCWarning(dcSonos) << data;
setAuthenticated(false);
return;
}
// check JSON
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcSonos) << "Refresh token reply JSON error:" << error.errorString();
setAuthenticated(false);
return;
}
if (!jsonDoc.toVariant().toMap().contains("access_token")) {
qCWarning(dcSonos) << "Could not get access token after refresh" << jsonDoc.toJson();
setAuthenticated(false);
return;
}
setToken(jsonDoc.toVariant().toMap().value("access_token").toString());
qCDebug(dcSonos) << "Token refreshed successfully";
if (jsonDoc.toVariant().toMap().contains("expires_in") && jsonDoc.toVariant().toMap().contains("refresh_token")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toString();
qCDebug(dcSonos) << "Token will be refreshed in" << expireTime << "[s]";
m_timer->start((expireTime - 20) * 1000);
}
if (!authenticated())
setAuthenticated(true);
}
}
void OAuth::refreshTimeout()
{
qCDebug(dcSonos) << "Refresh authentication token for";
QUrlQuery query;
query.addQueryItem("grant_type", "refresh_token");
query.addQueryItem("refresh_token", m_refreshToken);
query.addQueryItem("client_id", m_clientId);
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
m_refreshTokenRequests.append(m_networkManager->post(request, query.toString().toUtf8()));
}

View File

@ -1,71 +0,0 @@
#ifndef OAUTH_H
#define OAUTH_H
#include <QObject>
#include <QString>
#include <QTimer>
#include <QUrl>
#include <QUrlQuery>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class OAuth : public QObject
{
Q_OBJECT
public:
explicit OAuth(QString clientId, QObject *parent = nullptr);
QUrl url() const;
void setUrl(const QUrl &url);
QUrlQuery query() const;
void setQuery(const QUrlQuery &query);
QString clientId() const;
void setClientId(const QString &clientId);
QString scope() const;
void setScope(const QString &scope);
QByteArray authorizationCode() const;
QByteArray bearerToken() const;
bool authenticated() const;
void startAuthentication();
private:
QNetworkAccessManager *m_networkManager;
QTimer *m_timer;
QList<QNetworkReply *> m_tokenRequests;
QList<QNetworkReply *> m_refreshTokenRequests;
QUrl m_url;
QUrlQuery m_query;
QString m_clientId;
QString m_scope;
QString m_state;
QString m_redirectUri;
QString m_responseType;
QString m_token;
QString m_refreshToken;
bool m_authenticated;
void setAuthenticated(const bool &authenticated);
void setToken(const QString &token);
private slots:
void replyFinished(QNetworkReply *reply);
void refreshTimeout();
signals:
void authenticationChanged();
void tokenChanged();
};
#endif // OAUTH_H

View File

@ -26,17 +26,46 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QUrlQuery>
Sonos::Sonos(NetworkAccessManager *networkmanager, const QByteArray &accessToken, QObject *parent) :
Sonos::Sonos(NetworkAccessManager *networkmanager, const QByteArray &clientKey, const QByteArray &clientSecret, const QByteArray &refreshToken, QObject *parent) :
QObject(parent),
m_accessToken(accessToken),
m_clientKey(clientKey),
m_clientSecret(clientSecret),
m_refreshToken(refreshToken),
m_networkManager(networkmanager)
{
if(!m_tokenRefreshTimer) {
m_tokenRefreshTimer = new QTimer(this);
m_tokenRefreshTimer->setSingleShot(true);
connect(m_tokenRefreshTimer, &QTimer::timeout, this, &Sonos::onRefreshTimeout);
}
}
void Sonos::setAccessToken(const QByteArray &accessToken)
QUrl Sonos::getLoginUrl(const QUrl &redirectUrl)
{
m_accessToken = accessToken;
QString clientId = "b15cbf8c-a39c-47aa-bd93-635a96e9696c";
QUrl url("https://api.sonos.com/login/v3/oauth");
QUrlQuery queryParams;
queryParams.addQueryItem("client_id", clientId);
queryParams.addQueryItem("redirect_uri", redirectUrl.toString());
queryParams.addQueryItem("response_type", "code");
queryParams.addQueryItem("scope", "playback-control-all");
queryParams.addQueryItem("state", QUuid::createUuid().toString());
url.setQuery(queryParams);
return url;
}
QByteArray Sonos::accessToken()
{
return m_accessToken;
}
QByteArray Sonos::refreshToken()
{
return m_refreshToken;
}
void Sonos::getHouseholds()
@ -44,7 +73,7 @@ void Sonos::getHouseholds()
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/households"));
QNetworkReply *reply = m_networkManager->get(request);
qDebug(dcSonos()) << "Sending request" << request.url() << request.rawHeaderList() << request.rawHeader("Authorization");
@ -53,6 +82,12 @@ void Sonos::getHouseholds()
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
connectionChanged(true);
if (status == 401) {
//Authentication required
getAccessTokenFromRefreshToken(m_refreshToken);
return;
}
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
@ -82,7 +117,7 @@ QUuid Sonos::loadFavorite(const QString &groupId, const QString &favouriteId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/favourites"));
QUuid actionId = QUuid::createUuid();
@ -90,7 +125,7 @@ QUuid Sonos::loadFavorite(const QString &groupId, const QString &favouriteId)
object.insert("favoriteId", QJsonValue::fromVariant(favouriteId));
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
QNetworkReply *reply = m_networkManager->post(request, doc.toJson(QJsonDocument::Compact));
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@ -101,8 +136,6 @@ QUuid Sonos::loadFavorite(const QString &groupId, const QString &favouriteId)
emit actionExecuted(actionId, false);
return;
}
//TODO parse response
emit actionExecuted(actionId, true);
});
return actionId;
@ -113,7 +146,7 @@ void Sonos::getFavorites(const QString &householdId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/favorites"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, householdId, this] {
@ -126,7 +159,6 @@ void Sonos::getFavorites(const QString &householdId)
return;
}
//qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
if (!data.isObject())
return;
@ -156,10 +188,10 @@ void Sonos::getGroups(const QString &householdId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/groups"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, this] {
connect(reply, &QNetworkReply::finished, this, [reply, householdId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@ -187,7 +219,7 @@ void Sonos::getGroups(const QString &householdId)
group.displayName = obj["name"].toString();
groupObjects.append(group);
}
emit groupsReceived(groupObjects);
emit groupsReceived(householdId, groupObjects);
});
}
@ -196,7 +228,7 @@ void Sonos::getGroupVolume(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, groupId, this] {
@ -229,7 +261,7 @@ QUuid Sonos::setGroupVolume(const QString &groupId, int volume)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume"));
QUuid actionId = QUuid::createUuid();
@ -260,7 +292,7 @@ QUuid Sonos::setGroupMute(const QString &groupId, bool mute)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume/mute"));
QUuid actionId = QUuid::createUuid();
@ -292,7 +324,7 @@ QUuid Sonos::setGroupRelativeVolume(const QString &groupId, int volumeDelta)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume/relative"));
QUuid actionId = QUuid::createUuid();
@ -324,7 +356,7 @@ void Sonos::getGroupPlaybackStatus(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, this, groupId] {
@ -378,7 +410,7 @@ QUuid Sonos::groupLoadLineIn(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/lineIn"));
QUuid actionId = QUuid::createUuid();
@ -404,7 +436,7 @@ QUuid Sonos::groupPlay(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/play"));
QUuid actionId = QUuid::createUuid();
@ -432,7 +464,7 @@ QUuid Sonos::groupPause(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/pause"));
QUuid actionId = QUuid::createUuid();
@ -461,7 +493,7 @@ QUuid Sonos::groupSeek(const QString &groupId, int possitionMillis)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/seek"));
QUuid actionId = QUuid::createUuid();
@ -490,7 +522,7 @@ QUuid Sonos::groupSeekRelative(const QString &groupId, int deltaMillis)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/seekRelative"));
QUuid actionId = QUuid::createUuid();
@ -519,7 +551,7 @@ QUuid Sonos::groupSetPlayModes(const QString &groupId, PlayMode playMode)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
@ -554,7 +586,7 @@ QUuid Sonos::groupSetShuffle(const QString &groupId, bool shuffle)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
@ -586,7 +618,7 @@ QUuid Sonos::groupSetRepeat(const QString &groupId, RepeatMode repeatMode)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
@ -630,7 +662,7 @@ QUuid Sonos::groupSetCrossfade(const QString &groupId, bool crossfade)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
@ -662,7 +694,7 @@ QUuid Sonos::groupSkipToNextTrack(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/skipToNextTrack"));
QUuid actionId = QUuid::createUuid();
@ -688,7 +720,7 @@ QUuid Sonos::groupSkipToPreviousTrack(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/skipToPreviousTrack"));
QUuid actionId = QUuid::createUuid();
@ -714,7 +746,7 @@ QUuid Sonos::groupTogglePlayPause(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/togglePlayPause"));
QUuid actionId = QUuid::createUuid();
@ -740,7 +772,7 @@ void Sonos::getGroupMetadataStatus(const QString &groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playbackMetadata"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, groupId, this] {
@ -871,7 +903,7 @@ void Sonos::getPlayerVolume(const QByteArray &playerId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, playerId, this] {
@ -902,7 +934,7 @@ QUuid Sonos::setPlayerVolume(const QByteArray &playerId, int volume)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume"));
QUuid actionId = QUuid::createUuid();
@ -934,7 +966,7 @@ QUuid Sonos::setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume/relative"));
QUuid actionId = QUuid::createUuid();
@ -964,7 +996,7 @@ QUuid Sonos::setPlayerMute(const QByteArray &playerId, bool mute)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/playerVolume"));
QUuid actionId = QUuid::createUuid();
@ -994,7 +1026,7 @@ void Sonos::getPlaylist(const QString &householdId, const QString &playlistId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/playlists/getPlaylist"));
@ -1041,7 +1073,7 @@ void Sonos::getPlaylists(const QString &householdId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/households/" + householdId + "/playlists"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, householdId, this] {
@ -1083,7 +1115,7 @@ QUuid Sonos::loadPlaylist(const QString &groupId, const QString &playlistId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playlists"));
QUuid actionId = QUuid::createUuid();
@ -1112,7 +1144,7 @@ void Sonos::getPlayerSettings(const QString &playerId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/settings/player"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, playerId, this] {
@ -1142,7 +1174,7 @@ QUuid Sonos::setPlayerSettings(const QString &playerId, PlayerSettingsObject set
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setRawHeader("X-Sonos-Api-Key", m_clientKey);
request.setUrl(QUrl(m_baseControlUrl + "/players/" + playerId + "/settings/player"));
QUuid actionId = QUuid::createUuid();
@ -1169,3 +1201,91 @@ QUuid Sonos::setPlayerSettings(const QString &playerId, PlayerSettingsObject set
});
return actionId;
}
void Sonos::onRefreshTimeout()
{
qCDebug(dcSonos) << "Refresh authentication token";
getAccessTokenFromRefreshToken(m_refreshToken);
}
void Sonos::getAccessTokenFromRefreshToken(const QByteArray &refreshToken)
{
QUrlQuery query;
query.addQueryItem("grant_type", "refresh_token");
query.addQueryItem("refresh_token", refreshToken);
QUrl url("https://api.sonos.com/login/v3/oauth");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
QNetworkReply *reply = m_networkManager->post(request, QByteArray());
connect(reply, &QNetworkReply::finished, this, [this, reply](){
reply->deleteLater();
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
qCDebug(dcSonos()) << "Sonos accessToken reply:" << this << reply->error() << reply->errorString() << jsonDoc.toJson();
if(!jsonDoc.toVariant().toMap().contains("access_token")) {
emit authenticationStatusChanged(false);
return;
}
qCDebug(dcSonos()) << "Access token:" << jsonDoc.toVariant().toMap().value("access_token").toString();
m_accessToken = jsonDoc.toVariant().toMap().value("access_token").toByteArray();
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
if (!m_tokenRefreshTimer) {
qWarning(dcSonos()) << "Token refresh timer not initialized";
return;
}
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
}
emit authenticationStatusChanged(true);;
});
}
void Sonos::getAccessTokenFromAuthorizationCode(const QByteArray &authorizationCode)
{
// Obtaining access token
QUrl url = QUrl(m_baseAuthorizationUrl);
QUrlQuery query;
query.clear();
query.addQueryItem("grant_type", "authorization_code");
query.addQueryItem("code", authorizationCode);
query.addQueryItem("redirect_uri", "https%3A%2F%2F127.0.0.1%3A8888");
url.setQuery(query);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded;charset=utf-8");
QByteArray auth = QByteArray(m_clientKey + ':' + m_clientSecret).toBase64(QByteArray::Base64Encoding | QByteArray::KeepTrailingEquals);
request.setRawHeader("Authorization", QString("Basic %1").arg(QString(auth)).toUtf8());
QNetworkReply *reply = m_networkManager->post(request, QByteArray());
connect(reply, &QNetworkReply::finished, this, [this, reply](){
reply->deleteLater();
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
qCDebug(dcSonos()) << "Sonos accessToken reply:" << this << reply->error() << reply->errorString() << jsonDoc.toJson();
if(!jsonDoc.toVariant().toMap().contains("access_token") || !jsonDoc.toVariant().toMap().contains("refresh_token") ) {
emit authenticationStatusChanged(false);;
return;
}
qCDebug(dcSonos()) << "Access token:" << jsonDoc.toVariant().toMap().value("access_token").toString();
m_accessToken = jsonDoc.toVariant().toMap().value("access_token").toByteArray();
qCDebug(dcSonos()) << "Refresh token:" << jsonDoc.toVariant().toMap().value("refresh_token").toString();
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toByteArray();
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
if (!m_tokenRefreshTimer) {
qWarning(dcSonos()) << "Token refresh timer not initialized";
return;
}
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
}
emit authenticationStatusChanged(true);;
});
}

View File

@ -24,6 +24,7 @@
#define SONOS_H
#include <QObject>
#include <QTimer>
#include "network/networkaccessmanager.h"
#include "devices/device.h"
@ -150,14 +151,14 @@ public:
};
struct PlayBackObject {
QString itemId;
bool isDucking;
PlayBackState playbackState;
PlayMode playMode;
uint positionMillis;
QString previousItemId;
uint previousPositionMillis;
QString queueVersion;
QString itemId;
bool isDucking;
PlayBackState playbackState;
PlayMode playMode;
uint positionMillis;
QString previousItemId;
uint previousPositionMillis;
QString queueVersion;
};
/*
@ -206,9 +207,13 @@ public:
QList<PlaylistTrackObject> tracks;
};
explicit Sonos(NetworkAccessManager *networkManager, const QByteArray &accessToken, QObject *parent = nullptr);
explicit Sonos(NetworkAccessManager *networkManager, const QByteArray &clientId, const QByteArray &clientSecret, const QByteArray &refreshToken = "", QObject *parent = nullptr);
void setAccessToken(const QByteArray &accessToken);
QUrl getLoginUrl(const QUrl &redirectUrl);
QByteArray accessToken();
QByteArray refreshToken();
void getAccessTokenFromRefreshToken(const QByteArray &refreshToken);
void getAccessTokenFromAuthorizationCode(const QByteArray &authorizationCode);
void getHouseholds();
void getFavorites(const QString &householdId);
@ -259,21 +264,27 @@ public:
QUuid setPlayerSettings(const QString &playerId, PlayerSettingsObject settings);
private:
QByteArray m_baseAuthorizationUrl = "https://api.sonos.com/login/v3/oauth";
QByteArray m_baseAuthorizationUrl = "https://api.sonos.com/login/v3/oauth/access";
QByteArray m_baseControlUrl = "https://api.ws.sonos.com/control/api/v1";
QByteArray m_apiKey = "b15cbf8c-a39c-47aa-bd93-635a96e9696c";
QByteArray m_clientKey;
QByteArray m_clientSecret;
QByteArray m_accessToken;
QByteArray m_refreshToken;
NetworkAccessManager *m_networkManager = nullptr;
QTimer *m_tokenRefreshTimer = nullptr;
private slots:
void onRefreshTimeout();
signals:
void connectionChanged(bool connected);
void authenticationStatusChanged(bool authenticated);
void householdIdsReceived(QList<QString> householdIds);
void favouritesReceived(const QString &householdId, QList<FavouriteObject> favourites);
void playlistsReceived(const QString &householdId, QList<PlaylistObject> playlists);
void groupsReceived(QList<GroupObject> groups);
void groupsReceived(const QString &householdId, QList<GroupObject> groups);
void playlistSummaryReceived(const QString &householdId, PlaylistSummaryObject playlistSummary);
void playBackStatusReceived(const QString &groupId, PlayBackObject playBack);
@ -283,7 +294,5 @@ signals:
void playerVolumeReceived(const QString &playerId, VolumeObject playerVolume);
void playerSettingsRecieved(const QString &playerId, PlayerSettingsObject playerSettings);
void actionExecuted(QUuid actionId,bool success);
};
#endif // SONOS_H

View File

@ -11,5 +11,3 @@ SOURCES += \
HEADERS += \
devicepluginsonos.h \
sonos.h \