Compare commits

...

9 Commits

1 changed files with 91 additions and 17 deletions

View File

@ -1,10 +1,20 @@
const Gpio = require("pigpio").Gpio; const Gpio = require("pigpio").Gpio;
const schedule = require("./schedule.json"); const schedule = require("./schedule.json");
const HZ = 40000; 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}); let ledRed = new Gpio(12, {mode: Gpio.OUTPUT});
ledRed.hardwarePwmWrite(HZ, 0);
let ledGreen = new Gpio(13, {mode: Gpio.OUTPUT}); 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) => { let timings = schedule.times.reduce((result, time) => {
result.push({start: time.time, color: time.color}); result.push({start: time.time, color: time.color});
return result; return result;
@ -13,41 +23,90 @@ let timings = schedule.times.reduce((result, time) => {
return timing; return timing;
}); });
//We need to split the last scheduled interval at midnight
//(and fill it in for the start of the day)
splitAtMidnight(timings); splitAtMidnight(timings);
//Initialize State
let 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 renderInterval = setInterval(render, 50);
let debugInterval = DEBUG && setInterval(logLEDStatus, 2000);
//********
function updateState() { napButton.on("alert", startNap);
let time = getTime(); DEBUG && process.on('SIGUSR2', () => {
let timing = timings.find(x => x.start <= time && x.end > time); console.debug("Simulating button press!");
if(timing.color !== state.color) { startNap();
state = { });
color: timing.color
}; 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() { function render() {
switch(state.color) { switch(state.color) {
case "red": case "red":
if(ledGreen.digitalRead()) { if(ledGreen.digitalRead()) {
DEBUG && console.log("Turning off Green LED.");
return ledGreen.digitalWrite(0); return ledGreen.digitalWrite(0);
} }
DEBUG && !ledRed.getPwmDutyCycle() && console.log("Turning on Red LED");
return ledRed.hardwarePwmWrite(HZ, getBrightness(Date.now())); return ledRed.hardwarePwmWrite(HZ, getBrightness(Date.now()));
break; break;
case "green": case "green":
if(ledRed.digitalRead()) { if(ledRed.getPwmDutyCycle()) {
return ledRed.digitalWrite(0); 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); return ledGreen.digitalWrite(1);
} }
//Commenting out. Probably don't need breathing on green leds //Commenting out. Probably don't need breathing on green leds
@ -56,10 +115,20 @@ function render() {
} }
} }
function getBrightness(x) { function logLEDStatus() {
return Math.floor(breathingCurve(x, 8000, 250000, 700000)); 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) { function breathingCurve(x, interval = 3000, min, max) {
let t = x * Math.PI/(interval/2); let t = x * Math.PI/(interval/2);
let y = Math.sin(t + Math.sin(t) * 0.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; 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) { function splitAtMidnight(arr) {
let last = arr[arr.length -1]; let last = arr[arr.length -1];
arr.unshift({ ...last, start: 0}); arr.unshift({ ...last, start: 0});
arr[arr.length - 1].end = 2400; 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() { function getTime() {
let date = new Date(Date.now()); let date = new Date(Date.now());
return (date.getHours() * 100) + date.getMinutes() + 1 return (date.getHours() * 100) + date.getMinutes() + 1