const utils = require('..');
const ifttt = require('../ifttt');
const v3 = require('node-hue-api').v3;
const time = require('../time');
// Values for the ClientId, ClientSecret and AppId from the Hue Remote Application you create in your developer account.
const remoteBootstrap = v3.api.createRemote(
process.env.HUE_CLIENT_ID,
process.env.HUE_CLIENT_SECRET
);
let hue_api;
let update_access_token_timeout;
function authenticate() {
return utils.query("SELECT access_token, refresh_token, username FROM hue_auth").then(function(rows) {
if (rows.length) {
const auth = rows[0];
if (auth.access_token && auth.refresh_token && auth.username) {
remoteBootstrap.connectWithTokens(
auth.access_token,
auth.refresh_token,
auth.username
).catch(function(error) {
console.warn("Failed to get a remote connection using existing tokens");
console.error(error);
}).then(function(api) {
hue_api = api;
console.log("Philips Hue authentication successful");
}).finally(schedule_refresh_tokens);
}
} else {
console.log("Cannot authenticate Philips Hue, obtain tokens using init_hue_auth.js");
}
});
}
function schedule_refresh_tokens() {
return utils.query("SELECT access_token_expires, refresh_token_expires FROM hue_auth").then(function(rows) {
const expirations = rows[0];
let now = Date.now();
let time_until_access_token_expires = Math.max(expirations.access_token_expires - now, 0);
let time_until_refresh_token_expires = Math.max(expirations.refresh_token_expires - now, 0);
console.log("Days until access token expires:", time_until_access_token_expires / time.one_day);
console.log("Days until refresh token expires:", time_until_refresh_token_expires / time.one_day);
return [time_until_access_token_expires, time_until_refresh_token_expires];
}).then(function([time_until_access_token_expires, time_until_refresh_token_expires]) {
// Conditional on hue_api being truthy because that means even if we
// do not have expiration data, the tokens still worked. We should
// immediately refresh so that we can get new expiration data. In
// general, the expirations data should not be empty. Still testing.
if (time_until_refresh_token_expires > 0 || hue_api) {
clearTimeout(update_access_token_timeout);
update_access_token_timeout = setTimeout(function() {
console.log("Time to refresh Philips Hue tokens", time.toString());
refresh_tokens().then(function() {
console.log("Philips Hue tokens updated on", time.toString());
}).catch(function(error) {
console.error("Failed refresh tokens using existing tokens");
console.error(error);
});
}, time_until_access_token_expires);
console.log("Token refresh scheduled");
} else {
console.error("Philips Hue API tokens expired!");
ifttt({
type: "notification",
data: "Philips Hue API tokens expired!"
});
}
});
}
function refresh_tokens() {
return hue_api.remote.refreshTokens().then(function(tokens) {
console.log(tokens);
console.log(tokens.accessToken);
console.log(tokens.accessTokenExpiresAt);
return store_auth({
access_token: tokens.accessToken,
access_token_expires: tokens.accessTokenExpiresAt,
refresh_token: tokens.refreshToken,
refresh_token_expires: tokens.refreshTokenExpiresAt
});
}).then(authenticate);
}
function store_auth(data) {
console.log(`The new Access Token is valid until: ${time.toString(time.now(data.access_token_expires))}`);
console.log(`The new Refresh Token is valid until: ${time.toString(time.now(data.refresh_token_expires))}`);
return utils.query("UPDATE hue_auth SET ?", data);
}
module.exports = {
authenticate: authenticate,
store_auth: store_auth,
schedule_refresh_tokens: schedule_refresh_tokens,
get_api: function() {
return hue_api;
}
};