added oauth
parent
d4c0bd41c8
commit
85060d152c
|
|
@ -41,85 +41,44 @@ DevicePluginSonos::~DevicePluginSonos()
|
|||
|
||||
Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
|
||||
{
|
||||
if (!sonos) {
|
||||
if (!m_pluginTimer) {
|
||||
|
||||
}
|
||||
if (device->deviceClassId() == sonosConnectionDeviceClassId) {
|
||||
|
||||
Sonos *sonos = new Sonos("0a8f6d44-d9d1-4474-bcfa-cfb41f8b66e8", this);
|
||||
pluginStorage()->beginGroup(device->id().toString());
|
||||
QString username = pluginStorage()->value("username").toString();
|
||||
QString password = pluginStorage()->value("password").toString();
|
||||
pluginStorage()->endGroup();
|
||||
|
||||
sonos->authenticate(username, password);
|
||||
|
||||
m_sonosConnections.insert(device->id(), sonos);
|
||||
connect(sonos, &Sonos::authenticationFinished, this, [this, sonos](bool success){
|
||||
if (success) {
|
||||
} else {
|
||||
qCWarning(dcSonos()) << "Cannot authenticate to Sonos api";
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (device->deviceClassId() == sonosDeviceClassId) {
|
||||
if (!m_sonosSystem->Discover()) {
|
||||
return Device::DeviceSetupStatusFailure;
|
||||
}
|
||||
QString zoneName = device->paramValue(sonosDeviceZoneNameParamTypeId).toString();
|
||||
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
||||
|
||||
SONOS::ZoneList zones = m_sonosSystem->GetZoneList();
|
||||
|
||||
for(SONOS::ZoneList::const_iterator iz = zones.begin(); iz != zones.end(); ++iz) {
|
||||
|
||||
if (iz->second->GetZoneName().c_str() == zoneName) {
|
||||
if (!m_sonosSystem->ConnectZone(iz->second, nullptr, nullptr)) {
|
||||
qCDebug(dcSonos()) << "Failed connecting to zone" << zoneName;
|
||||
return Device::DeviceSetupStatusFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
device->setStateValue(sonosConnectedStateTypeId, true);
|
||||
//set parent ID
|
||||
}
|
||||
return Device::DeviceSetupStatusSuccess;
|
||||
}
|
||||
|
||||
void DevicePluginSonos::postSetupDevice(Device *device)
|
||||
{
|
||||
if (device->deviceClassId() == sonosDeviceClassId) {
|
||||
SONOS::ZonePtr pl = m_sonosSystem->GetConnectedZone();
|
||||
uint8_t volume;
|
||||
uint8_t mute;
|
||||
for (SONOS::Zone::iterator ip = pl->begin(); ip != pl->end(); ++ip) {
|
||||
if (!m_sonosSystem->GetPlayer()->GetVolume((*ip)->GetUUID(), &volume)) {
|
||||
qWarning(dcSonos()) << "Could not get volume for" << (*ip)->GetHost().c_str();
|
||||
} else {
|
||||
device->setStateValue(sonosVolumeStateTypeId, volume);
|
||||
}
|
||||
if (device->deviceClassId() == sonosConnectionDeviceClassId) {
|
||||
|
||||
if (!m_sonosSystem->GetPlayer()->GetMute((*ip)->GetUUID(), &mute)) {
|
||||
qWarning(dcSonos()) << "Could not get mute state for" << (*ip)->GetHost().c_str();
|
||||
} else {
|
||||
device->setStateValue(sonosMuteStateTypeId, mute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(m_sonosSystem->GetPlayer()->TransportPropertyEmpty());
|
||||
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
||||
|
||||
SONOS::AVTProperty properties = m_sonosSystem->GetPlayer()->GetTransportProperty();
|
||||
|
||||
qDebug(dcSonos()) << "Transport Status" << properties.TransportStatus.c_str();
|
||||
qDebug(dcSonos()) << "Transport State" << properties.TransportState.c_str();
|
||||
if (QString(properties.TransportState.c_str()) == "PLAYING") {
|
||||
device->setStateValue(sonosPlaybackStatusStateTypeId, "Playing");
|
||||
} else if (QString(properties.TransportState.c_str()) == "PAUSED") {
|
||||
device->setStateValue(sonosPlaybackStatusStateTypeId, "Paused");
|
||||
} else if (QString(properties.TransportState.c_str()) == "STOPPED") {
|
||||
device->setStateValue(sonosPlaybackStatusStateTypeId, "Stopped");
|
||||
}
|
||||
|
||||
qDebug(dcSonos()) << "AVTransport URI" << properties.AVTransportURI.c_str();
|
||||
qDebug(dcSonos()) << "AVTransportTitle" << properties.AVTransportURIMetaData->GetValue("dc:title").c_str();
|
||||
qDebug(dcSonos()) << "Current Track" << properties.CurrentTrack;
|
||||
qDebug(dcSonos()) << "Current Track Duration" << properties.CurrentTrackDuration.c_str();
|
||||
qDebug(dcSonos()) << "Current Track URI" << properties.CurrentTrackURI.c_str();
|
||||
//device->setStateValue(sonosArtworkStateTypeId, properties.CurrentTrackURI.c_str());
|
||||
qDebug(dcSonos()) << "Current Track Title" << properties.CurrentTrackMetaData->GetValue("dc:title").c_str();
|
||||
device->setStateValue(sonosTitleStateTypeId, properties.CurrentTrackMetaData->GetValue("dc:title").c_str());
|
||||
qDebug(dcSonos()) << "Current Track Album" << properties.CurrentTrackMetaData->GetValue("upnp:album").c_str();
|
||||
qDebug(dcSonos()) << "Current Track Artist" << properties.CurrentTrackMetaData->GetValue("dc:creator").c_str();
|
||||
device->setStateValue(sonosArtistStateTypeId, properties.CurrentTrackMetaData->GetValue("dc:creator").c_str());
|
||||
qDebug(dcSonos()) << "Current Crossfade Mode" << properties.CurrentCrossfadeMode.c_str();
|
||||
qDebug(dcSonos()) << "Current Play Mode" << properties.CurrentPlayMode.c_str();
|
||||
qDebug(dcSonos()) << "Current TransportActions" << properties.CurrentTransportActions.c_str();
|
||||
qDebug(dcSonos()) << "Number Of Tracks" << properties.NumberOfTracks;
|
||||
qDebug(dcSonos()) << "Alarm Running" << properties.r_AlarmRunning.c_str();
|
||||
qDebug(dcSonos()) << "Alarm ID Running" << properties.r_AlarmIDRunning.c_str();
|
||||
qDebug(dcSonos()) << "Alarm Logged Start Time" << properties.r_AlarmLoggedStartTime.c_str();
|
||||
qDebug(dcSonos()) << "AlarmState" << properties.r_AlarmState.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,100 +86,59 @@ void DevicePluginSonos::deviceRemoved(Device *device)
|
|||
{
|
||||
qCDebug(dcSonos) << "Delete " << device->name();
|
||||
if (myDevices().empty()) {
|
||||
delete m_sonosSystem;
|
||||
}
|
||||
}
|
||||
|
||||
Device::DeviceError DevicePluginSonos::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||
{
|
||||
Q_UNUSED(params)
|
||||
Q_UNUSED(deviceClassId)
|
||||
|
||||
|
||||
if (!m_sonosSystem->Discover()) {
|
||||
return Device::DeviceErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
QList<DeviceDescriptor> descriptors;
|
||||
SONOS::ZoneList zones = m_sonosSystem->GetZoneList();
|
||||
|
||||
for (SONOS::ZoneList::const_iterator it = zones.begin(); it != zones.end(); ++it) {
|
||||
qDebug(dcSonos()) << "Found zone" << it->second->GetZoneName().c_str();
|
||||
DeviceDescriptor descriptor(sonosDeviceClassId, it->second->GetZoneName().c_str());
|
||||
ParamList params;
|
||||
params << Param(sonosDeviceZoneNameParamTypeId, it->second->GetZoneName().c_str());
|
||||
descriptor.setParams(params);
|
||||
descriptors << descriptor;
|
||||
}
|
||||
emit devicesDiscovered(sonosDeviceClassId, descriptors);
|
||||
return Device::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Action &action)
|
||||
{
|
||||
Q_UNUSED(action)
|
||||
if (device->deviceClassId() == sonosDeviceClassId) {
|
||||
if (device->deviceClassId() == sonosGroupDeviceClassId) {
|
||||
Sonos *sonos = m_sonosConnections.value(device->parentId());
|
||||
int groupId = device->paramValue(sonosGroupDe)
|
||||
if (!sonos)
|
||||
return Device::DeviceErrorInvalidParameter;
|
||||
|
||||
if (action.actionTypeId() == sonosPlayActionTypeId) {
|
||||
if (!m_sonosSystem->GetPlayer()->Play()) {
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
return Device::DeviceErrorNoError;
|
||||
if (action.actionTypeId() == sonosGroupPlayActionTypeId) {
|
||||
sonos->play();
|
||||
return Device::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == sonosShuffleActionTypeId) {
|
||||
SONOS::PlayMode_t mode = SONOS::PlayMode_t::PlayMode_NORMAL;;
|
||||
if (action.param(sonosShuffleActionShuffleParamTypeId).value().toBool()) {
|
||||
mode = SONOS::PlayMode_t::PlayMode_NORMAL;
|
||||
}
|
||||
if (!m_sonosSystem->GetPlayer()->SetPlayMode(mode)) {
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
return Device::DeviceErrorNoError;
|
||||
if (action.actionTypeId() == sonosGroupShuffleActionTypeId) {
|
||||
|
||||
return Device::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == sonosRepeatActionTypeId) {
|
||||
SONOS::PlayMode_t mode;
|
||||
if (action.param(sonosRepeatActionRepeatParamTypeId).value().toString() == "None") {
|
||||
mode = SONOS::PlayMode_t::PlayMode_NORMAL;
|
||||
} else if (action.param(sonosShuffleActionShuffleParamTypeId).value().toString() == "One") {
|
||||
mode = SONOS::PlayMode_t::PlayMode_REPEAT_ONE;
|
||||
} else if (action.param(sonosShuffleActionShuffleParamTypeId).value().toString() == "All") {
|
||||
mode = SONOS::PlayMode_t::PlayMode_REPEAT_ALL;
|
||||
if (action.actionTypeId() == sonosGroupRepeatActionTypeId) {
|
||||
|
||||
if (action.param(sonosGroupRepeatActionRepeatParamTypeId).value().toString() == "None") {
|
||||
|
||||
} else if (action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toString() == "One") {
|
||||
|
||||
} else if (action.param(sonosGroupShuffleActionShuffleParamTypeId).value().toString() == "All") {
|
||||
|
||||
} else {
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
if (!m_sonosSystem->GetPlayer()->SetPlayMode(mode)) {
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
return Device::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == sonosGroupPauseActionTypeId) {
|
||||
sonos->pause();
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == sonosPauseActionTypeId) {
|
||||
if (!m_sonosSystem->GetPlayer()->Pause()) {
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
if (action.actionTypeId() == sonosGroupStopActionTypeId) {
|
||||
sonos->stop();
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == sonosStopActionTypeId) {
|
||||
if (!m_sonosSystem->GetPlayer()->Stop()) {
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == sonosGroupMuteActionTypeId) {
|
||||
bool mute = action.param(sonosGroupMuteActionMuteParamTypeId).value().toBool();
|
||||
|
||||
if (action.actionTypeId() == sonosMuteActionTypeId) {
|
||||
bool mute = action.param(sonosMuteActionMuteParamTypeId).value().toBool();
|
||||
|
||||
SONOS::ZonePtr pl = m_sonosSystem->GetConnectedZone();
|
||||
for (SONOS::Zone::iterator ip = pl->begin(); ip != pl->end(); ++ip) {
|
||||
if (!m_sonosSystem->GetPlayer()->SetMute((*ip)->GetUUID(), mute)) {
|
||||
qWarning(dcSonos()) << "Could not set mute state for" << (*ip)->GetHost().c_str();
|
||||
return Device::DeviceErrorHardwareFailure;
|
||||
}
|
||||
}
|
||||
sonos->setGroupMute()
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ public:
|
|||
Device::DeviceError executeAction(Device *device, const Action &action) override;
|
||||
|
||||
private:
|
||||
Sonos *sonos = nullptr;
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
QHash<DeviceId, Sonos *> m_sonosConnections;
|
||||
|
||||
|
||||
private slots:
|
||||
void onPluginTimer();
|
||||
|
|
|
|||
|
|
@ -11,12 +11,19 @@
|
|||
"deviceClasses": [
|
||||
{
|
||||
"id": "22df416d-7732-44f1-b6b9-e41296211178",
|
||||
"name": "sonosGroup",
|
||||
"displayName": "Sonos group",
|
||||
"interfaces": ["gateway", "connectable"],
|
||||
"createMethods": ["discovery"],
|
||||
"paramTypes": [
|
||||
"name": "sonosConnection",
|
||||
"displayName": "Sonos connection",
|
||||
"interfaces": ["gateway"],
|
||||
"createMethods": ["user"],
|
||||
"setupMethod": "userandpassword",
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "5aa4360c-61de-47d0-a72e-a19d57712e1c",
|
||||
"name": "connected",
|
||||
"displayName": "connected",
|
||||
"displayNameEvent": "connected changed",
|
||||
"defaultValue": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -29,8 +36,8 @@
|
|||
"paramTypes": [
|
||||
{
|
||||
"id": "defc44cd-2ffb-4af1-b348-d6a3474c7515",
|
||||
"name": "zoneName",
|
||||
"displayName": "Zone name",
|
||||
"name": "groupId",
|
||||
"displayName": "Group id",
|
||||
"type" : "QString"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,221 @@
|
|||
#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()));
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#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
|
||||
|
|
@ -22,26 +22,33 @@
|
|||
|
||||
#include "sonos.h"
|
||||
#include "extern-plugininfo.h"
|
||||
#include "network/networkaccessmanager.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
||||
Sonos::Sonos(QObject *parent)
|
||||
Sonos::Sonos(QByteArray apiKey, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_apiKey(apiKey)
|
||||
{
|
||||
}
|
||||
|
||||
void Sonos::authenticate(const QString &username, const QString &password)
|
||||
{
|
||||
//get oauth autherisation
|
||||
Q_UNUSED(username)
|
||||
Q_UNUSED(password)
|
||||
|
||||
//get accesst token
|
||||
m_OAuth = new OAuth(m_apiKey, this);
|
||||
m_OAuth->setUrl(QUrl(m_baseAuthorizationUrl));
|
||||
m_OAuth->setScope("playback-control-all");
|
||||
m_OAuth->startAuthentication();
|
||||
}
|
||||
|
||||
void Sonos::getHouseholds()
|
||||
{
|
||||
QNetworkRequest request;
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", "Bearer" + m_bearerToken);
|
||||
request.setUrl(m_baseControlUrl + "/households");
|
||||
request.setRawHeader("Authorization", "Bearer" + m_OAuth->bearerToken());
|
||||
request.setUrl(QUrl(m_baseControlUrl + "/households"));
|
||||
QNetworkReply *reply = QNetworkAccessManager.get(request);
|
||||
connect(reply, &QNetworkReply::finished, this [this] {
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
|
@ -61,12 +68,3 @@ void Sonos::getHouseholds()
|
|||
});
|
||||
}
|
||||
|
||||
void Sonos::getPlayerVolume(int playerId)
|
||||
{
|
||||
QNetworkRequest request;
|
||||
|
||||
QJsonObject object;
|
||||
object.
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "devices/device.h"
|
||||
#include "oauth.h"
|
||||
|
||||
class Sonos : public QObject
|
||||
{
|
||||
|
|
@ -135,8 +136,7 @@ public:
|
|||
{
|
||||
QString name;
|
||||
ArtistObject artist;
|
||||
QString
|
||||
|
||||
//TODO
|
||||
};
|
||||
|
||||
struct ContainerObject
|
||||
|
|
@ -150,6 +150,8 @@ public:
|
|||
};
|
||||
|
||||
explicit Sonos(QByteArray apiKey, QObject *parent = nullptr);
|
||||
|
||||
void setApiKey(QByteArray apiKey);
|
||||
void authenticate(const QString &username, const QString &password);
|
||||
|
||||
void getHouseholds();
|
||||
|
|
@ -201,14 +203,17 @@ public:
|
|||
void setPlayerSettings();
|
||||
|
||||
private:
|
||||
QUrl m_baseAuthorizationUrl = "api.sonos.com/login/v3/oauth";
|
||||
QUrl m_baseControlUrl = "api.ws.sonos.com/control/api/v1";
|
||||
QByteArray m_baseAuthorizationUrl = "api.sonos.com/login/v3/oauth";
|
||||
QByteArray m_baseControlUrl = "api.ws.sonos.com/control/api/v1";
|
||||
QByteArray m_apiKey;
|
||||
|
||||
OAuth *m_OAuth = nullptr;
|
||||
|
||||
private slots:
|
||||
|
||||
|
||||
signals:
|
||||
void authenticationSuccessfull();
|
||||
void authenticationFinished();
|
||||
void authenticationFailed(const QString &reason);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ TARGET = $$qtLibraryTarget(nymea_devicepluginsonos)
|
|||
SOURCES += \
|
||||
devicepluginsonos.cpp \
|
||||
sonos.cpp \
|
||||
oauth.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginsonos.h \
|
||||
sonos.h \
|
||||
oauth.h
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue