Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
John Shaver | 8d10e604f0 | |
John Shaver | e88568b3c7 | |
John Shaver | 29701fd944 | |
John Shaver | 4c11d57a6c | |
John Shaver | 13f16e0b18 | |
John Shaver | ed29517098 | |
John Shaver | ffd9778e32 | |
John Shaver | da848f6800 | |
John Shaver | 9e35f65520 |
108
runSchedule.js
108
runSchedule.js
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue