@katesthings/smartsonos
Version:
Utility functions to control Sonos speakers
133 lines (132 loc) • 6.94 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const SmartState = require('@katesthings/smartstate');
const axios = require("axios");
function getSonosData(key) {
return __awaiter(this, void 0, void 0, function* () {
return yield SmartState.getHomeMode('niwot', 'sonos-' + key);
});
}
;
function putSonosData(key, value) {
return __awaiter(this, void 0, void 0, function* () {
yield SmartState.putHomeMode('niwot', 'sonos-' + key, value);
});
}
;
function refreshToken() {
return __awaiter(this, void 0, void 0, function* () {
let accessToken;
try {
const refreshToken = yield getSonosData('refresh-token');
console.log('refreshToken - retrieved refresh token: ', refreshToken);
const urlToken = 'https://api.sonos.com/login/v3/oauth/access';
const params = new URLSearchParams();
params.append('grant_type', 'refresh_token');
params.append('refresh_token', refreshToken);
console.log('refreshToken - initialized parameters: ', params);
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
'Authorization': 'Basic ZDMxM2EyYTAtOTYwZS00ODFmLTlmYzctM2MwMmU0MzY2OTU1OjNhY2ZkZmQ5LTI3YzQtNGE3NC05NzhkLWUyN2ZlZmE0NWJkMg=='
}
};
console.log('refreshToken - refreshing access token');
axios.post(urlToken, params, config).then((result) => {
console.log('refreshToken - Success! Data: ', result.data);
const token_data = result.data;
accessToken = token_data.access_token;
putSonosData('token-time', new Date());
putSonosData('access-token', token_data.access_token);
putSonosData('refresh-token', token_data.refresh_token);
putSonosData('expires-in', token_data.expires_in.toString());
}).catch((err) => { console.log('refreshToken - error refreshing token: ', err); });
}
catch (err) {
console.log('refreshToken - error getting refresh token from DynamoDB: ', err);
}
return accessToken;
});
}
;
function getAccessToken() {
return __awaiter(this, void 0, void 0, function* () {
let accessToken;
try {
console.log('getAccessToken - getting Sonos data from DyanmoDB');
accessToken = yield getSonosData('access-token');
const tokenTime = new Date(yield getSonosData('token-time'));
const expiresIn = yield getSonosData('expires-in');
const currentTime = new Date();
const elapsedTime = (currentTime.getTime() - tokenTime.getTime()) / 1000;
console.log('getAccessToken - token-time: ', tokenTime, ', expires-in: ', expiresIn, ', time gap: ', elapsedTime);
if (elapsedTime > expiresIn) {
console.log('getAccessToken - token expired, need to refresh: ', elapsedTime);
accessToken = yield refreshToken();
}
}
catch (err) {
console.log('getAccessToken - error getting refresh token from DynamoDB: ', err);
}
return accessToken;
});
}
;
function controlSpeakers(context, speakers, command) {
return __awaiter(this, void 0, void 0, function* () {
try {
const access_token = yield getAccessToken();
const sonosControl = axios.create({
baseURL: 'https://api.ws.sonos.com/control/api/v1',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + access_token
}
});
console.log('controlSpeakers - getting households');
sonosControl.get('households').then((result) => {
const householdId = result.data.households[0].id;
console.log('controlSpeakers - household ID: ', householdId);
sonosControl.get('households/' + householdId + '/groups').then((result) => {
const sonosPlayers = result.data.players;
const sonosGroups = result.data.groups;
const speakerDevices = context.config[speakers];
for (const speaker of speakerDevices) {
const speakerId = speaker.deviceConfig.deviceId;
context.api.devices.get(speakerId).then((speakerInfo) => {
const speakerName = speakerInfo.name;
console.log('controlSpeakers - find speaker: ', speakerName, ', speakerId: ', speakerId);
const player = sonosPlayers.find(speaker => speaker.name === speakerName);
console.log('controlSpeakers - player found: ', player, ', id: ', player.id);
for (const group of sonosGroups) {
const groupPlayers = group.playerIds;
if (groupPlayers.indexOf(player.id) > -1) {
const urlControl = '/groups/' + group.id + '/playback/' + command;
console.log('controlSpeakers - command: ', command, ', urlControl: ', urlControl);
sonosControl.post(urlControl).then((result) => {
console.log('controlSpeakers - Success! Data: ', result.data);
;
}).catch((err) => { console.log('controlSpeakers - error controlling speaker: ', err, ', command: ', command); });
}
}
});
}
}).catch((err) => { console.log('controlSpeakers - error getting groups/speakers: ', err); });
}).catch((err) => { console.log('controlSpeakers - error getting household(s): ', err); });
}
catch (err) {
console.log('controlSpeakers - error controlling Sonos: ', err);
}
});
}
;
module.exports.controlSpeakers = controlSpeakers;