Compare commits

..

9 Commits

2 changed files with 92 additions and 18 deletions

View File

@ -1,3 +1,3 @@
This is a little project I started to help my 2 year old son know when it is time to wake up and when it is time to keep sleeping. Living 47deg north of the equator means the sun is an unreliable indicator for him depending on the time of year.
This is a little I started to help my 2 year old son know when it is time to wake up and when it is time to keep sleeping. Living 47deg north of the equator means the sun is an unreliable indicator for him depending on the time of year.
The red leds will pulse calmly during the night and the green leds will switch on when it's time to wake up in the morning!

View File

@ -1,10 +1,20 @@
const Gpio = require("pigpio").Gpio;
const schedule = require("./schedule.json");
const HZ = 40000;
const NAP_DURATION = 100 * 60 * 1000;
const DEBUG = !!process.env["DEBUG"];
//Let's setup our connections to our physical hardware devices.
let ledRed = new Gpio(12, {mode: Gpio.OUTPUT});
ledRed.hardwarePwmWrite(HZ, 0);
let ledGreen = new Gpio(13, {mode: Gpio.OUTPUT});
let napButton = new Gpio(6, {mode: Gpio.INPUT, pullUpDown: Gpio.PUD_UP, alert: true });
napButton.glitchFilter(10000);
//Make an easily searchable array so we can find what color it should
//be using at any given time.
let timings = schedule.times.reduce((result, time) => {
result.push({start: time.time, color: time.color});
return result;
@ -13,41 +23,90 @@ let timings = schedule.times.reduce((result, time) => {
return timing;
});
//We need to split the last scheduled interval at midnight
//(and fill it in for the start of the day)
splitAtMidnight(timings);
//Initialize State
let state = {
color: "red"
color: "red",
napTime: false,
}
updateState();
//Make sure the color is set correctly in state for the current time before we start.
//It will automatically update every seconds, but it might be wrong for a second.
updateColorState();
let updateStateInterval = setInterval(updateState, 1000);
//Set intervals to update LED lights.
//********
let updateColorStateInterval = setInterval(updateColorState, 1000);
let renderInterval = setInterval(render, 50);
let debugInterval = DEBUG && setInterval(logLEDStatus, 2000);
//********
function updateState() {
let time = getTime();
let timing = timings.find(x => x.start <= time && x.end > time);
if(timing.color !== state.color) {
state = {
color: timing.color
};
napButton.on("alert", startNap);
DEBUG && process.on('SIGUSR2', () => {
console.debug("Simulating button press!");
startNap();
});
function startNap(level, tick) {
console.log("Button alert recieved. Starting nap time!");
state = { ...state,
napTime: true,
napEnd: Date.now() + NAP_DURATION
}
}
function updateColorState() {
let newColor = state.color;
switch(state.napTime) {
case true:
console.log("Nap time until :", state.napEnd);
if(Date.now() < state.napEnd) {
newColor = "red";
break;
} else {
state = { ...state,
napTime: false,
napEnd: 0,
};
}
case false:
console.log("NO NAP!");
let time = getTime();
let timing = timings.find(x => x.start <= time && x.end > time);
newColor = timing.color
}
if(newColor !== state.color) {
console.log("setting color state to", newColor);
state = { ...state,
color: newColor,
};
}
}
function render() {
switch(state.color) {
case "red":
if(ledGreen.digitalRead()) {
if(ledGreen.digitalRead()) {
DEBUG && console.log("Turning off Green LED.");
return ledGreen.digitalWrite(0);
}
}
DEBUG && !ledRed.getPwmDutyCycle() && console.log("Turning on Red LED");
return ledRed.hardwarePwmWrite(HZ, getBrightness(Date.now()));
break;
case "green":
if(ledRed.digitalRead()) {
return ledRed.digitalWrite(0);
if(ledRed.getPwmDutyCycle()) {
DEBUG && console.log("Turning off Red LED.");
return ledRed.hardwarePwmWrite(HZ, 0);
}
if(!ledGreen.digitalRead()) {
if(!ledGreen.digitalRead()) {
DEBUG && console.log("Turning on Green LED.");
return ledGreen.digitalWrite(1);
}
//Commenting out. Probably don't need breathing on green leds
@ -56,10 +115,20 @@ function render() {
}
}
function getBrightness(x) {
return Math.floor(breathingCurve(x, 8000, 250000, 700000));
function logLEDStatus() {
console.log({
red: ledRed.getPwmDutyCycle(),
green: ledGreen.digitalRead(),
});
}
//get brightness for time value for LED pulse breathing
function getBrightness(time) {
//These values should be configurable, maybe?
return Math.floor(breathingCurve(time, 6500, 200000, 800000));
}
//algorithm for pulse breathing LEDs
function breathingCurve(x, interval = 3000, min, max) {
let t = x * Math.PI/(interval/2);
let y = Math.sin(t + Math.sin(t) * 0.2);
@ -68,12 +137,17 @@ function breathingCurve(x, interval = 3000, min, max) {
return y * (max - min) + min;
}
//split the last time interval at midnight and add the remaining to the
//beginning of the the array.
function splitAtMidnight(arr) {
let last = arr[arr.length -1];
arr.unshift({ ...last, start: 0});
arr[arr.length - 1].end = 2400;
}
//get current time in military style time. This format is used for ease of
//human input in conviguration file. I should have converted to Date when read
//from configuration.. oh well, I'll fix that later.
function getTime() {
let date = new Date(Date.now());
return (date.getHours() * 100) + date.getMinutes() + 1