Skip to content

Instantly share code, notes, and snippets.

@mrpapercut
Last active January 5, 2022 11:47
Show Gist options
  • Save mrpapercut/901f9e7d1525969f339ad65f9e1df187 to your computer and use it in GitHub Desktop.
Save mrpapercut/901f9e7d1525969f339ad65f9e1df187 to your computer and use it in GitHub Desktop.
Philips Hue automatic lighting based on sunrise/sunset
/**
* Automatically turns on lights based on sunrise/sunset
* Usage: use cronjob to trigger every night after midnight
*
* NPM packages required: superagent, node-hue-api
*/
import request from 'superagent';
import HueApi from 'node-hue-api';
const config = {
hue: {
bridge: {
hostname: <bridge IP address>,
id: <bridgeId>
},
user: {
username: <username>,
description: <user description>
},
scenes: {
'Sunrise': <sceneId>,
'Sunset': <sceneId>
}
},
sunsettings: {
latitude: <latitude>,
longitude: <longitude>,
minSunrise: '07:00:00 AM', // Don't turn lights on before this time
minSunset: '06:30:00 PM' // Don't turn lights on before this time
}
}
class SunriseSunset {
constructor() {
this.api = new HueApi(config.hue.bridge.hostname, config.hue.user.username);
this.scenes = config.hue.scenes;
this.fetchSunriseSunset();
}
fetchSunriseSunset() {
const {latitude, longitude} = sunSettings;
request
.get(`https://api.sunrise-sunset.org/json?lat=${latitude}&lng=${longitude}`)
.end((err, {body}) => {
if (err) {
console.error(err);
} else {
// Time options:
// sunrise, sunset
// civil_twilight_begin, civil_twilight_end
// nautical_twilight_begin, nautical_twilight_end
// astronomical_twilight_begin, astronomical_twilight_end
// IMO nautical_twilight works best to start lights
this.setSchedules(body.results.nautical_twilight_begin, body.results.nautical_twilight_end);
}
});
}
// Determine times to use for schedule
setSchedules(sunrise, sunset) {
let {minSunrise, minSunset} = config.sunSettings;
[sunrise, minSunrise, sunset, minSunset] =
[sunrise, minSunrise, sunset, minSunset].map(t => this.formatDate(t));
const [pSunrise, pMinSunrise, pSunset, pMinSunset] =
[sunrise, minSunrise, sunset, minSunset].map(t => Date.parse(this.formatDate(t)));
this.setHueSchedule(pSunrise > pMinSunrise ? sunrise : minSunrise, 'Sunrise');
this.setHueSchedule(pSunset > pMinSunset ? sunset : minSunset, 'Sunset');
}
// Set schedule on Hue device
setHueSchedule(time, name) {
const scheduleEvent = {
name: name,
time: time,
localtime: time,
description: name,
command: {
address: `/api/${hueSettings.user.username}/groups/0/action`,
body: {
scene: this.scenes[name]
},
method: 'PUT'
}
};
this.api.createSchedule(scheduleEvent).catch(e => console.error(e)).done();
}
// Format sunrise-sunset-api-format to node-hue-api-format
// Example input: "6:15:00 PM"
// Example output: "2017-04-01T18:15:00"
formatDate(timestring) {
return timestring.replace(/^([0-9]{1,2}):([0-9]{2}):([0-9]{2})\s(PM|AM)$/, (match, h, m, s, ap) => {
const p = s => ('00' + s).substr(-2);
let [Y, M, d] = ['FullYear', 'Month', 'Date'].map(s => new Date()['get'+s]());
ap === 'PM' ? h = parseInt(h, 10) + 12 : null;
[h, m, s] = [h, m, s].map(p);
return `${Y}-${p(++M)}-${p(d)}T${h}:${m}:${s}`
});
}
}
new SunriseSunset();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment