1st version with c implementation of state engine

This commit is contained in:
2017-11-25 23:58:24 +01:00
parent f6a3f4a5f3
commit e2209504da
17 changed files with 1409 additions and 188 deletions

View File

@@ -1,162 +0,0 @@
load('api_rpc.js');
load("api_neopixel.js");
load("api_file.js");
let colors = {
black: {r:0, g:0, b:0},
red: {r:255, g:0, b:0},
green: {r:0, g:255, b:0},
blue: {r:0, g:0, b:255},
yellow: {r:255, g:255, b:0},
orange: {r:255, g:127, b:0},
purple: {r:255, g:0, b:255},
white: {r:255, g:255, b:255},
dimmedWhite: {r:50, g:50, b:50}
};
let LightAnimation = {
numberOfBulbs: 11,
ledPin: 2,
running: false,
mode: "demo",
generalBrightnessDivider: 3,
colorSequence: [
colors.dimmedWhite,
colors.red,
colors.green,
colors.blue,
colors.yellow,
colors.orange,
colors.purple,
colors.red,
colors.red,
colors.green,
colors.green,
colors.white,
colors.white
]
};
// Add RPC handlers
RPC.addHandler('HouseLightning.Start', function(args) {
LightAnimation.running = true;
LightAnimation.mode = "run";
return {result: 'ok'};
}, null);
RPC.addHandler('HouseLightning.Stop', function(args) {
LightAnimation.running = true; // first we want to turn off LEDs, thus needs stop-mode
LightAnimation.mode = "stop";
return {result: 'ok'};
}, null);
RPC.addHandler('HouseLightning.DemoMode', function(args) {
LightAnimation.mode = "demo";
LightAnimation.running = true;
return {result: 'ok'};
}, null);
RPC.addHandler('HouseLightning.CycleMode', function(args) {
LightAnimation.mode = "cycle";
LightAnimation.running = true;
return {result: 'ok'};
}, null);
RPC.addHandler('HouseLightning.GetAnimationConfig', function(args) {
return LightAnimation.animationConfig;
}, null);
RPC.addHandler('HouseLightning.SetAnimationConfig', function(args) {
if (args !== undefined && args.config !== undefined) {
LightAnimation.animationConfig = JSON.parse(args.config);
if (LightAnimation.animationConfig.comment === undefined) {
return {error: 'config is incomplete or invalid / comment not found'};
}
if (LightAnimation.animationConfig.lights === undefined) {
return {error: 'config is incomplete or invalid / lights definition not found'};
}
if (LightAnimation.animationConfig.lights[0] === undefined) {
return {error: 'config is incomplete or invalid / lights not an array?'};
}
let i;
for (i=0; i<LightAnimation.animationConfig.lights.length; ++i) {
if (LightAnimation.animationConfig.lights[i].level === undefined) {
return {error: 'config is incomplete or invalid / level missing in lights definition'};
}
if (LightAnimation.animationConfig.lights[i].room === undefined) {
return {error: 'config is incomplete or invalid / room missing in lights definition'};
}
if (LightAnimation.animationConfig.lights[i].on === undefined) {
return {error: 'config is incomplete or invalid / on missing in lights definition'};
}
if (LightAnimation.animationConfig.lights[i].on[0] === undefined) {
return {error: 'config is incomplete or invalid / on not an array in lights definition?'};
}
if (LightAnimation.animationConfig.lights[i].on.length !== 3) {
return {error: 'config is incomplete or invalid / on must have 3 elements for R/G/B in lights definition?'};
}
if (LightAnimation.animationConfig.lights[i].id === undefined) {
return {error: 'config is incomplete or invalid / id missing in lights definition'};
}
}
return {result: 'ok'};
} else {
return {error: 'parameter config is required'};
}
}, null);
function runNeopixel(strip, shiftBy) {
let i=0, colorIndex=0, color;
for (i=0; i<LightAnimation.numberOfBulbs; ++i) {
colorIndex = shiftBy % LightAnimation.colorSequence.length;
color = LightAnimation.colorSequence[colorIndex];
strip.setPixel(i, color.r/LightAnimation.generalBrightnessDivider, color.g/LightAnimation.generalBrightnessDivider, color.b/LightAnimation.generalBrightnessDivider);
// print("runNeo shift =", shiftBy, ", colorIndex =", colorIndex, ", r =", color.r, ", g =", color.g, ", b =", color.b);
shiftBy++;
}
strip.show();
}
// initialize module
let configString = "";
configString = File.read("lights.cfg");
if (configString === "" || configString === null) configString = "***default***";
// print("configString = ", configString);
LightAnimation.animationConfig = JSON.parse(configString);
// initialize neoPixel
let colorOrder = NeoPixel.GRB;
let strip = NeoPixel.create(LightAnimation.ledPin, LightAnimation.numberOfBulbs, colorOrder);
strip.clear();
strip.show();
// initialize test pattern
let i = 0;
for (i=0; i<LightAnimation.numberOfBulbs; ++i) {
if (i % 2) {
strip.setPixel(i, 80, 20, 20);
} else {
strip.setPixel(i, 20, 80, 20);
}
}
strip.show();
let shiftAnimation = 1;
Timer.set(1990 /* msec */, true /* repeat */, function() {
if (LightAnimation.running) {
if (LightAnimation.mode === "demo") {
runNeopixel(strip, shiftAnimation);
shiftAnimation++;
print("*** demo-mode, next shift=", shiftAnimation);
} else if (LightAnimation.mode === "stop") {
strip.clear();
strip.show();
LightAnimation.running = false;
} else print("*** no-ack, mode =", LightAnimation.mode);
} else print("*** stopped");
}, null);

View File

@@ -1,32 +1,65 @@
load('api_config.js');
load('api_gpio.js');
load('api_mqtt.js');
load('api_net.js');
load('api_sys.js');
load('api_rpc.js');
load('api_timer.js');
load("animateLights.js");
let led = Cfg.get('pins.led');
// Helper C function get_led_gpio_pin() in src/main.c returns built-in LED GPIO
let onBoardLed = ffi('int get_led_gpio_pin()')();
// let onBoardLed = ffi('int get_led_gpio_pin()')();
let button = Cfg.get('pins.button');
let topic = '/devices/' + Cfg.get('device.id') + '/events';
print('LED GPIO:', led, 'button GPIO:', button);
let getInfo = function() {
return JSON.stringify({total_ram: Sys.total_ram(), free_ram: Sys.free_ram()});
return JSON.stringify({
total_ram: Sys.total_ram(),
free_ram: Sys.free_ram()
});
};
// Publish to MQTT topic on a button press. Button is wired to GPIO pin 0
GPIO.set_button_handler(0, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200, function() {
let topic = '/devices/' + Cfg.get('device.id') + '/events';
let message = getInfo();
let ok = MQTT.pub(topic, message, 1);
print('Published:', ok ? 'yes' : 'no', 'topic:', topic, 'message:', message);
}, null);
// Blink built-in LED every second
GPIO.set_mode(onBoardLed, GPIO.MODE_OUTPUT);
// Tick-Tock generation
Timer.set(1000 /* 1 sec */, true /* repeat */, function() {
let value = GPIO.toggle(onBoardLed);
GPIO.set_mode(led, GPIO.MODE_OUTPUT);
Timer.set(5000 /* 1 sec */, true /* repeat */, function() {
let value = GPIO.toggle(led);
print(value ? 'Tick' : 'Tock', 'uptime:', Sys.uptime(), getInfo());
}, null);
// Publish to MQTT topic on a button press. Button is wired to GPIO pin 0
/*
GPIO.set_button_handler(button, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200, function() {
let message = getInfo();
let ok = MQTT.pub(topic, message, 1);
print('Published:', ok, topic, '->', message);
}, null);
*/
// Monitor network connectivity.
Net.setStatusEventHandler(function(ev, arg) {
let evs = '???';
if (ev === Net.STATUS_DISCONNECTED) {
evs = 'DISCONNECTED';
} else if (ev === Net.STATUS_CONNECTING) {
evs = 'CONNECTING';
} else if (ev === Net.STATUS_CONNECTED) {
evs = 'CONNECTED';
} else if (ev === Net.STATUS_GOT_IP) {
evs = 'GOT_IP';
}
print('== Net event:', ev, evs);
}, null);
// Initialize LED controller
let addColor = ffi('void addColor(char *,int,int,int)');
let addLedDefinition = ffi('void addLedDefinition(char *, char *, char *, int, int, int)');
let addAnimationStep = ffi('void addAnimationStep(int, int, int)');
let LEDMode_on=1, LEDMode_off=2, LEDMode_blink=3, LEDMode_tv=4, LEDMode_fire=5;
let LEDStateEngine_start = ffi('void startLEDStateEngine(void)');
let LEDStateEngine_pause = ffi('void pauseLEDStateEngine(void)');

View File

@@ -1,18 +0,0 @@
{
"comment": "lights.cfg / JSON",
"lights": [
{ "level":"EG", "room":"Wohnzimmer", "on":[200,200,200], "id":"EG-WoZi" },
{ "level":"EG", "room":"Bad", "on":[150,150,150], "id":"EG-Bad" },
{ "level":"EG", "room":"Schlafzimmer", "on":[130,130,130], "id":"EG-Schlafen" },
{ "level":"EG", "room":"Buero 0.1", "on":[150,150,130], "id":"EG-Buero-1" },
{ "level":"EG", "room":"Buero 0.2", "on":[150,150,130], "id":"EG-Buero-2" },
{ "level":"OG1", "room":"Buero 1.1", "on":[150,150,130], "id":"OG1-Buero-1" },
{ "level":"OG1", "room":"Buero 1.2", "on":[150,150,130], "id":"OG1-Buero-2" },
{ "level":"OG1", "room":"Buero 1.3", "on":[150,150,130], "id":"OG1-Buero-3" },
{ "level":"OG1", "room":"Buero 1.4", "on":[150,150,130], "id":"OG1-Buero-4" },
{ "level":"OG2", "room":"Buero 2.1", "on":[150,150,130], "id":"OG2-Buero-1" },
{ "level":"OG2", "room":"Buero 2.2", "on":[150,150,130], "id":"OG2-Buero-2" },
{ "level":"OG2", "room":"Buero 2.3", "on":[150,150,130], "id":"OG2-Buero-3" },
{ "level":"OG2", "room":"Buero 2.4", "on":[150,150,130], "id":"OG2-Buero-4" }
]
}