From 4aeebe1b33244de67fd2630918b47264feb5d0c1 Mon Sep 17 00:00:00 2001 From: Dirk Jahnke Date: Sat, 9 Dec 2017 22:10:59 +0100 Subject: [PATCH] Added new mode: Scheduler -- clock based switching of lights --- fs/api_dlite.js | 21 ++++++--- fs/colors.cfg | 6 +++ fs/demoschedule.cfg | 26 +++++++++++ fs/init.js | 94 +++++++++++++++++++++++++++++---------- fs/schedule.cfg | 30 +++++++++++++ mos.yml | 2 + src/LEDState.c | 21 ++------- src/NeoPixel.c | 27 +++++++++--- src/NeoPixel.h | 2 + src/Scheduler.c | 105 ++++++++++++++++++++++++++++++++++++++++++++ src/Scheduler.h | 5 +++ src/main.c | 1 + 12 files changed, 290 insertions(+), 50 deletions(-) create mode 100644 fs/demoschedule.cfg create mode 100644 fs/schedule.cfg create mode 100644 src/Scheduler.c create mode 100644 src/Scheduler.h diff --git a/fs/api_dlite.js b/fs/api_dlite.js index 8efd6e1..fb9145e 100644 --- a/fs/api_dlite.js +++ b/fs/api_dlite.js @@ -1,28 +1,39 @@ let addColor = ffi('void addColor(char *,int,int,int)'); -let LEDDefinition_addByName = ffi('void LEDDefinition_addByName(char *, char *, char *, char *)'); let addAnimationStep = ffi('void addAnimationStep(int, char *, int)'); let LEDMode_on=1, LEDMode_off=2, LEDMode_blink=3, LEDMode_tv=4, LEDMode_fire=5; + let LEDStateEngine_init = ffi('void LEDStateEngine_init(int, int)'); let LEDStateEngine_start = ffi('void startLEDStateEngine(void)'); let LEDStateEngine_pause = ffi('void pauseLEDStateEngine(void)'); +let LEDStateEngine_getMinTickTime = ffi('double LEDStateEngine_getMinTickTime(void)'); +let LEDStateEngine_getMaxTickTime = ffi('double LEDStateEngine_getMaxTickTime(void)'); + let LEDState_getRed = ffi('int LEDState_getLedRed(int)'); let LEDState_getGreen = ffi('int LEDState_getLedGreen(int)'); let LEDState_getBlue = ffi('int LEDState_getLedBlue(int)'); let LEDState_getColorName = ffi('char * LEDState_getLedColorName(int)'); let LEDState_getNextTick = ffi('int LEDState_getNextTick(int)'); let LEDState_getCurrentTick = ffi('int LEDState_getCurrentTick(int)'); + +let LEDDefinition_addByName = ffi('void LEDDefinition_addByName(char *, char *, char *, char *)'); let LEDDefinition_getLevel = ffi('char *LEDDefinition_getLevel(int)'); let LEDDefinition_getRoom = ffi('char *LEDDefinition_getRoom(int)'); let LEDDefinition_getId = ffi('char *LEDDefinition_getId(int)'); let LEDDefinition_getOnColorRed = ffi('int LEDDefinition_getOnColorRed(int)'); let LEDDefinition_getOnColorGreen = ffi('int LEDDefinition_getOnColorGreen(int)'); let LEDDefinition_getOnColorBlue = ffi('int LEDDefinition_getOnColorBlue(int)'); + let getTicks = ffi('int getTicks(void)'); let printColor = ffi('void printColor(char *)'); + let NeoPixel_show = ffi('void NeoPixel_show(void)'); let NeoPixel_clear = ffi('void NeoPixel_clear(void)'); let NeoPixel_set = ffi('void NeoPixel_set(int,int,int,int)'); -let LEDStateEngine_getMinTickTime = ffi('double LEDStateEngine_getMinTickTime(void)'); -let LEDStateEngine_getMaxTickTime = ffi('double LEDStateEngine_getMaxTickTime(void)'); -let LEDStateEngine_getBrightness = ffi('int LEDStateEngine_getBrightness(void)'); -let LEDStateEngine_setBrightness = ffi('void LEDStateEngine_setBrightness(int)'); +let NeoPixel_getBrightness = ffi('int NeoPixel_getBrightness(void)'); +let NeoPixel_setBrightness = ffi('void NeoPixel_setBrightness(int)'); + +let LEDScheduler_init = ffi('void LEDScheduler_init(int, int, int)'); +let LEDScheduler_run = ffi('void LEDScheduler_run(void)'); +let LEDScheduler_pause = ffi('void LEDScheduler_pause(void)'); +let LEDScheduler_addItem = ffi('void LEDScheduler_addItem(int, int, int, char *, char *)'); +let LEDScheduler_setWatch = ffi('void LEDScheduler_setWatch(int, int, int)'); diff --git a/fs/colors.cfg b/fs/colors.cfg index b5e4991..7ade66f 100644 --- a/fs/colors.cfg +++ b/fs/colors.cfg @@ -1,6 +1,12 @@ [ {"name": "off", "red": 0, "green": 0, "blue": 0}, {"name": "candle", "red": 30, "green": 15, "blue": 4}, + {"name": "25w", "red": 35, "green": 15, "blue": 6}, + {"name": "40w", "red": 50, "green": 25, "blue": 10}, + {"name": "60w", "red": 70, "green": 45, "blue": 20}, + {"name": "75w", "red": 80, "green": 70, "blue": 30}, + {"name": "100w", "red": 100, "green": 85, "blue": 50}, + {"name": "neon", "red": 100, "green": 95, "blue": 70}, {"name": "red", "red": 50, "green": 5, "blue": 5}, {"name": "green", "red": 5, "green": 50, "blue": 5}, {"name": "blue", "red": 5, "green": 5, "blue": 80}, diff --git a/fs/demoschedule.cfg b/fs/demoschedule.cfg new file mode 100644 index 0000000..2b4ec74 --- /dev/null +++ b/fs/demoschedule.cfg @@ -0,0 +1,26 @@ +{ + "comment": "7-LED development board", + "lampmapping": [ + "lamp-1", "lamp-2", "lamp-3", "lamp-4", "lamp-5", "lamp-6", "lamp-7" + ], + "mrclock": "N-RE", + "clock_starttime": {"h": 2, "m": 0}, + "clock_speed": 1, + "schedule": [ + {"time": {"h": 2, "m": 30}, "lamp": "lamp-1", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 2, "m": 31}, "lamp": "lamp-2", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 2, "m": 32}, "lamp": "lamp-3", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 2, "m": 45}, "lamp": "lamp-3", "color": "off", "mode": "OnOff"}, + {"time": {"h": 2, "m": 46}, "lamp": "lamp-2", "color": "off", "mode": "OnOff"}, + {"time": {"h": 2, "m": 47}, "lamp": "lamp-1", "color": "off", "mode": "OnOff"}, + {"time": {"h": 4, "m": 2}, "lamp": "lamp-1", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 4}, "lamp": "lamp-2", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 4}, "lamp": "lamp-3", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 18}, "lamp": "lamp-3", "color": "off", "mode": "OnOff"}, + {"time": {"h": 4, "m": 28}, "lamp": "lamp-1", "color": "off", "mode": "OnOff"}, + {"time": {"h": 4, "m": 29}, "lamp": "lamp-4", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 30}, "lamp": "lamp-5", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 31}, "lamp": "lamp-6", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 32}, "lamp": "lamp-7", "color": "60w", "mode": "OnOff"} + ] +} diff --git a/fs/init.js b/fs/init.js index 928f2c3..0991a38 100644 --- a/fs/init.js +++ b/fs/init.js @@ -61,6 +61,8 @@ let configNumLeds = Cfg.get('led.count'); let colorFile = Cfg.get('led.colorFile'); let animationFile = Cfg.get('led.animationFile'); let lampsFile = Cfg.get('led.lampsFile'); +let scheduleFile = Cfg.get('led.scheduleFile'); +let dynamicMode = Cfg.get('led.mode'); let useDefaults = Cfg.get('led.useDefaults'); let tickDuration = Cfg.get('led.tickDuration'); let numberOfLeds = configNumLeds, numberOfLedDefs = 0; // from config files, count led definition entries @@ -155,6 +157,41 @@ function loadAnimDefs() { json = null; } +function loadScheduleDefs() { + // Load Animation Definitions + let json = File.read(scheduleFile); + let scheduleDef = []; + print('scheduleFile =', json); + if (json === '') { + print('ERROR: Schedule definition file does not exist!'); + } else { + scheduleDef = JSON.parse(json); + } + LEDScheduler_init(scheduleDef.schedule.length, numberOfLeds, pin); + LEDScheduler_setWatch(2, 0, 1); // time 02:00, clock speed = 1 real time second per model minute + let ledMapping = scheduleDef.lampmapping; + let mapLed = function (name) { + for (let i=0; i 0 && args.level <= 100) { - LEDStateEngine_setBrightness(args.level); + NeoPixel_setBrightness(args.level); return { result: 'ok' }; } else { return { error: 'Brightness level must be in the range 1..100' }; @@ -226,7 +276,7 @@ RPC.addHandler('led.setBrightness', function(args) { }, "{level: %d}"); print(' led.getBrightness'); RPC.addHandler('led.getBrightness', function(args) { - let brightness = LEDStateEngine_getBrightness(); + let brightness = NeoPixel_getBrightness(); return { result: 'ok', brightness: brightness }; }, null); print(' led.pause'); diff --git a/fs/schedule.cfg b/fs/schedule.cfg new file mode 100644 index 0000000..9a23bf2 --- /dev/null +++ b/fs/schedule.cfg @@ -0,0 +1,30 @@ +{ + "comment": "Company office building with facility manager appartement", + "lampmapping": [ + "eg-1.1", "eg-1.2", "eg-3.1", "eg-4", "eg-5", "eg-8", "eg-7, "eg-6", "eg-3.2", "eg-2.2", "eg-2.1", + "og-1.1", "og-1.2", "og-3.1", "og-4", "og-5", "og-8", "og-7, "og-6", "og-3.2", "og-2.2", "og-2.1", + "dg-1", "dg-2", "dg-3", "dg-4", "dg-5", "dg-6", "dg-7", "dg-8" + ], + "mrclock": "N-RE", + "clock_starttime": {"h": 2, "m": 0}, + "clock_speed": 1, + "schedule": [ + {"time": {"h": 2, "m": 30}, "lamp": "dg-5", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 2, "m": 31}, "lamp": "dg-8", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 2, "m": 32}, "lamp": "dg-7", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 2, "m": 45}, "lamp": "dg-7", "color": "off", "mode": "OnOff"}, + {"time": {"h": 2, "m": 46}, "lamp": "dg-8", "color": "off", "mode": "OnOff"}, + {"time": {"h": 2, "m": 47}, "lamp": "dg-5", "color": "off", "mode": "OnOff"}, + {"time": {"h": 4, "m": 2}, "lamp": "dg-5", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 4}, "lamp": "dg-8", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 4}, "lamp": "dg-7", "color": "25w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 18}, "lamp": "dg-7", "color": "off", "mode": "OnOff"}, + {"time": {"h": 4, "m": 28}, "lamp": "dg-5", "color": "off", "mode": "OnOff"}, + {"time": {"h": 4, "m": 29}, "lamp": "dg-3", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 30}, "lamp": "og-3.2", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 30}, "lamp": "eg-3.2", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 30}, "lamp": "eg-4", "color": "60w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 45}, "lamp": "eg-3.1", "color": "40w", "mode": "OnOff"}, + {"time": {"h": 4, "m": 47}, "lamp": "eg-1.1", "color": "60w", "mode": "OnOff"} + ] +} diff --git a/mos.yml b/mos.yml index f3946bb..4424fc9 100644 --- a/mos.yml +++ b/mos.yml @@ -39,6 +39,8 @@ config_schema: - ["led.colorFile", "s", "colors.cfg", {title: "File name containing color definitions"}] - ["led.lampsFile", "s", "lamps.cfg", {title: "File name containing lamp definitions"}] - ["led.animationFile", "s", "animations.cfg", {title: "File name containing animation definitions"}] + - ["led.mode", "s", "schedule", {title: "Mode = animation (use lampsFile + animationFile) | schedule (use scheduleFile)"}] + - ["led.scheduleFile", "s", "demoschedule.cfg", {title: "File name containing schedule definitions"}] build_vars: MGOS_ENABLE_ONEWIRE: 1 cflags: [] diff --git a/src/LEDState.c b/src/LEDState.c index 19b873b..953fb04 100644 --- a/src/LEDState.c +++ b/src/LEDState.c @@ -9,7 +9,6 @@ static LEDStateEngine theLEDStateEngine; static int ticks = 0; -static int brightness = 50; int getTicks(void) { return ticks; } @@ -27,7 +26,6 @@ void LEDStateEngine_setNumberOfLeds(int numberOfLeds) { void LEDStateEngine_init(int ledPin, int numberOfLeds) { theLEDStateEngine.comment = ""; theLEDStateEngine.pin = ledPin; - brightness = mgos_sys_config_get_led_brightness(); LEDStateEngine_setNumberOfLeds(numberOfLeds); for (int i=0; i 0 && newBrightness <= 100) { - brightness = newBrightness; - } else { - LOG(LL_ERROR, ("invalid brightness value %d", newBrightness)); - } -} - static void updateLedDisplay(LEDState *state) { NeoPixel_set(state->index, - adjustBrightness(state->currentColor.red), - adjustBrightness(state->currentColor.green), - adjustBrightness(state->currentColor.blue)); + state->currentColor.red, + state->currentColor.green, + state->currentColor.blue); } void LEDState_tick(int ledNum) { diff --git a/src/NeoPixel.c b/src/NeoPixel.c index bfe6bed..da36eb5 100644 --- a/src/NeoPixel.c +++ b/src/NeoPixel.c @@ -3,12 +3,28 @@ #include "mgos_bitbang.h" #include "mgos_gpio.h" #include "mgos_system.h" +#include "mgos_sys_config.h" #include "NeoPixel.h" static int NeoPixel_pin = 0; static int NeoPixel_numPixels = 0; static uint8_t *NeoPixel_leds = NULL; // pointer to allocated memory -static enum NeoPixel_ColorOrder NeoPixel_colorOrder = NeoPixel_colorOrder_RGB; +static enum NeoPixel_ColorOrder NeoPixel_colorOrder = NeoPixel_colorOrder_GRB; +static int brightness = 50; + +static uint8_t adjustBrightness(uint8_t value) { + return (value * brightness)/100; +} + +int NeoPixel_getBrightness() { return brightness; } +void NeoPixel_setBrightness(int newBrightness) { + if (newBrightness > 0 && newBrightness <= 100) { + brightness = newBrightness; + } else { + LOG(LL_ERROR, ("invalid brightness value %d", newBrightness)); + } +} + // ## **`NeoPixel_clear()`** // Clear in-memory values of the pixels. @@ -44,7 +60,8 @@ void NeoPixel_create(uint8_t pin, uint8_t numPixels, enum NeoPixel_ColorOrder or mgos_gpio_set_mode(pin, MGOS_GPIO_MODE_OUTPUT); // GPIO.write(pin, 0); // Keep in reset. mgos_gpio_write(pin, false); - LOG(LL_INFO, ("pin=%d, numPixels=%d, colorOrder=%d", pin, numPixels, order)); + brightness = mgos_sys_config_get_led_brightness(); + LOG(LL_INFO, ("pin=%d, numPixels=%d, colorOrder=%d, brightness=%d", pin, numPixels, order, brightness)); NeoPixel_clear(); } @@ -78,9 +95,9 @@ void NeoPixel_set(int pixel, int red, int green, int blue) { } else if (NeoPixel_colorOrder == NeoPixel_colorOrder_BGR) { v0 = blue; v1 = green; v2 = red; } else return; - NeoPixel_leds[3*pixel] = v0; - NeoPixel_leds[3*pixel+1] = v1; - NeoPixel_leds[3*pixel+2] = v2; + NeoPixel_leds[3*pixel] = adjustBrightness(v0); + NeoPixel_leds[3*pixel+1] = adjustBrightness(v1); + NeoPixel_leds[3*pixel+2] = adjustBrightness(v2); } // ## **`NeoPixel_show()`** diff --git a/src/NeoPixel.h b/src/NeoPixel.h index 31e44b6..c22fa76 100644 --- a/src/NeoPixel.h +++ b/src/NeoPixel.h @@ -11,5 +11,7 @@ extern void NeoPixel_release(); extern void NeoPixel_create(uint8_t pin, uint8_t numPixels, enum NeoPixel_ColorOrder order); extern void NeoPixel_set(int pixel, int red, int green, int blue); extern void NeoPixel_show(); +extern int NeoPixel_getBrightness(); +extern void NeoPixel_setBrightness(int newBrightness); #endif diff --git a/src/Scheduler.c b/src/Scheduler.c new file mode 100644 index 0000000..5dbc214 --- /dev/null +++ b/src/Scheduler.c @@ -0,0 +1,105 @@ +#include "Scheduler.h" +#include "LEDDefinition.h" +#include "NeoPixel.h" +#include "mgos_timers.h" + +enum ScheduleItemMode { + ScheduleItemMode_OnOff, + ScheduleItemMode_NeonOn, + ScheduleItemMode_tv_bw, + ScheduleItemMode_tv_color +}; + +static enum ScheduleItemMode modeFromName(char *name) { + if (strcmp(name, "OnOff") == 0) return ScheduleItemMode_OnOff; + if (strcmp(name, "NeonOn") == 0) return ScheduleItemMode_NeonOn; + if (strcmp(name, "TV_BW") == 0) return ScheduleItemMode_tv_bw; + if (strcmp(name, "TV_Color") == 0) return ScheduleItemMode_tv_color; + LOG(LL_ERROR, ("Invalid mode name: %s", name)); + return ScheduleItemMode_OnOff; +} + +typedef struct Schedule_t { + uint8_t h; + uint8_t m; + uint8_t led; + enum ScheduleItemMode mode; + LEDColor *color; +} Schedule; +static Schedule *schedule = NULL; +static int numScheduleItems = 0; +static int loadedScheduleItems = 0; +static int numberOfLeds = 0; +static int currentHour = 0; +static int currentMinute = 0; +static int clockSpeed = 1; // # seconds for every real time minute +static bool clockRunning = false; +static mgos_timer_id clockTimer = 0; + +static void executeScheduleItem(Schedule *s) { + LOG(LL_INFO, ("%d:%d LED #%d / mode=%d / color=%s", s->h, s->m, s->led, s->mode, s->color->name)); + if (s->mode == ScheduleItemMode_OnOff) { + NeoPixel_set(s->led, s->color->red, s->color->green, s->color->blue); + } +} + +static void LEDScheduler_timerTick() { + bool ledsNeedUpdate = false; + + if (clockRunning) { + currentMinute++; + if (currentMinute >= 60) { + currentMinute = 0; + currentHour++; + if (currentHour >= 24) { + currentHour = 0; + } + } + } + for (int i=0; i= numScheduleItems) { + LOG(LL_ERROR, ("Cannot load schedule item as storage is already full, %d:%d LED #%d", h, m, led)); + return; + } + schedule[loadedScheduleItems].h = h; + schedule[loadedScheduleItems].m = m; + schedule[loadedScheduleItems].led = led; + schedule[loadedScheduleItems].mode = modeFromName(mode); + schedule[loadedScheduleItems].color = LEDColor_get(colorName);; + schedule[loadedScheduleItems].h = h; + ++loadedScheduleItems; +} + +void LEDScheduler_run() { clockRunning = true; } +void LEDScheduler_pause() { clockRunning = false; } + +void LEDScheduler_setWatch(int h, int m, int speed) { + currentHour = h; + currentMinute = m; + clockSpeed = speed; + LOG(LL_INFO, ("set time %d:%d and speed to %d real-time seconds for a model minute", h, m, speed)); +} diff --git a/src/Scheduler.h b/src/Scheduler.h new file mode 100644 index 0000000..0393af5 --- /dev/null +++ b/src/Scheduler.h @@ -0,0 +1,5 @@ +extern void LEDScheduler_init(int, int, int); +extern void LEDScheduler_run(); +extern void LEDScheduler_pause(); +extern void LEDScheduler_addItem(int h, int m, int led, char *mode, char *colorName); +extern void LEDScheduler_setWatch(int h, int m, int speed); diff --git a/src/main.c b/src/main.c index 2db8dd1..2222e07 100644 --- a/src/main.c +++ b/src/main.c @@ -52,6 +52,7 @@ static void stateEngineTickTimer() { } } + static void delayed_boot() { LOG(LL_INFO, ("*** Start timer for LED state engine ticks")); mgos_set_timer(mgos_sys_config_get_led_tickDuration(), true, stateEngineTickTimer, NULL);