2017-07-13 04:18:04 +00:00
|
|
|
load('api_config.js');
|
|
|
|
load('api_gpio.js');
|
|
|
|
load('api_mqtt.js');
|
2017-11-25 22:58:24 +00:00
|
|
|
load('api_net.js');
|
2017-07-13 04:18:04 +00:00
|
|
|
load('api_sys.js');
|
2017-07-13 09:31:50 +00:00
|
|
|
load('api_rpc.js');
|
2017-07-13 04:18:04 +00:00
|
|
|
load('api_timer.js');
|
2017-11-27 05:47:27 +00:00
|
|
|
load("api_math.js");
|
2017-12-02 07:03:56 +00:00
|
|
|
load("api_file.js");
|
2017-11-27 05:47:27 +00:00
|
|
|
load("api_neopixel.js");
|
2017-11-25 22:58:24 +00:00
|
|
|
|
2017-07-13 04:18:04 +00:00
|
|
|
|
|
|
|
// Helper C function get_led_gpio_pin() in src/main.c returns built-in LED GPIO
|
2017-11-27 05:47:27 +00:00
|
|
|
let onBoardLed = ffi('int get_led_gpio_pin(void)')();
|
2017-11-25 22:58:24 +00:00
|
|
|
let button = Cfg.get('pins.button');
|
|
|
|
let topic = '/devices/' + Cfg.get('device.id') + '/events';
|
|
|
|
|
2017-11-27 05:47:27 +00:00
|
|
|
print('LED GPIO:', onBoardLed, 'button GPIO:', button);
|
2017-07-13 04:18:04 +00:00
|
|
|
|
|
|
|
let getInfo = function() {
|
2017-11-25 22:58:24 +00:00
|
|
|
return JSON.stringify({
|
|
|
|
total_ram: Sys.total_ram(),
|
2017-12-03 08:22:54 +00:00
|
|
|
free_ram: Sys.free_ram(),
|
|
|
|
uptime: Sys.uptime()
|
2017-11-25 22:58:24 +00:00
|
|
|
});
|
2017-07-13 04:18:04 +00:00
|
|
|
};
|
|
|
|
|
2017-11-25 22:58:24 +00:00
|
|
|
// Blink built-in LED every second
|
2017-11-27 05:47:27 +00:00
|
|
|
/*
|
|
|
|
GPIO.set_mode(onBoardLed, GPIO.MODE_OUTPUT);
|
|
|
|
Timer.set(5000, true, function() {
|
|
|
|
let value = GPIO.toggle(onBoardLed);
|
2017-11-25 22:58:24 +00:00
|
|
|
print(value ? 'Tick' : 'Tock', 'uptime:', Sys.uptime(), getInfo());
|
|
|
|
}, null);
|
2017-11-27 05:47:27 +00:00
|
|
|
*/
|
2017-11-25 22:58:24 +00:00
|
|
|
|
2017-07-13 04:18:04 +00:00
|
|
|
// Publish to MQTT topic on a button press. Button is wired to GPIO pin 0
|
2017-11-25 22:58:24 +00:00
|
|
|
/*
|
|
|
|
GPIO.set_button_handler(button, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200, function() {
|
2017-07-13 04:18:04 +00:00
|
|
|
let message = getInfo();
|
|
|
|
let ok = MQTT.pub(topic, message, 1);
|
2017-11-25 22:58:24 +00:00
|
|
|
print('Published:', ok, topic, '->', message);
|
2017-07-13 04:18:04 +00:00
|
|
|
}, null);
|
2017-11-25 22:58:24 +00:00
|
|
|
*/
|
2017-07-13 04:18:04 +00:00
|
|
|
|
2017-11-25 22:58:24 +00:00
|
|
|
// 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';
|
|
|
|
}
|
2017-12-03 08:22:54 +00:00
|
|
|
print('==> NET:', ev, evs);
|
2017-11-25 22:58:24 +00:00
|
|
|
}, null);
|
|
|
|
|
|
|
|
// Initialize LED controller
|
|
|
|
let addColor = ffi('void addColor(char *,int,int,int)');
|
2017-12-07 09:33:14 +00:00
|
|
|
let LEDDefinition_addByName = ffi('void LEDDefinition_addByName(char *, char *, char *, char *)');
|
2017-12-02 07:03:56 +00:00
|
|
|
let addAnimationStep = ffi('void addAnimationStep(int, char *, int)');
|
2017-11-25 22:58:24 +00:00
|
|
|
let LEDMode_on=1, LEDMode_off=2, LEDMode_blink=3, LEDMode_tv=4, LEDMode_fire=5;
|
2017-12-07 09:33:14 +00:00
|
|
|
let LEDStateEngine_init = ffi('void LEDStateEngine_init(int, int)');
|
2017-11-25 22:58:24 +00:00
|
|
|
let LEDStateEngine_start = ffi('void startLEDStateEngine(void)');
|
|
|
|
let LEDStateEngine_pause = ffi('void pauseLEDStateEngine(void)');
|
2017-11-27 05:47:27 +00:00
|
|
|
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_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)');
|
2017-12-02 07:03:56 +00:00
|
|
|
let printColor = ffi('void printColor(char *)');
|
2017-12-07 09:33:14 +00:00
|
|
|
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)');
|
2017-11-27 05:47:27 +00:00
|
|
|
|
2017-12-02 07:03:56 +00:00
|
|
|
let pin = Cfg.get('led.pin');
|
2017-12-07 09:33:14 +00:00
|
|
|
let configNumLeds = Cfg.get('led.count');
|
2017-12-02 07:03:56 +00:00
|
|
|
let colorOrder = NeoPixel.GRB;
|
2017-12-07 09:33:14 +00:00
|
|
|
//let strip = NeoPixel.create(pin, configNumLeds, colorOrder);
|
2017-12-02 07:03:56 +00:00
|
|
|
let colorFile = Cfg.get('led.colorFile');
|
|
|
|
let animationFile = Cfg.get('led.animationFile');
|
|
|
|
let lampsFile = Cfg.get('led.lampsFile');
|
|
|
|
let useDefaults = Cfg.get('led.useDefaults');
|
|
|
|
let updateCycle = Cfg.get('led.updateCycle');
|
2017-12-03 08:22:54 +00:00
|
|
|
let tickDuration = Cfg.get('led.tickDuration');
|
2017-12-02 07:03:56 +00:00
|
|
|
let brightnessAdjustment = Cfg.get('led.brightness');
|
2017-12-07 09:33:14 +00:00
|
|
|
let numberOfLeds = configNumLeds, numberOfLedDefs = 0; // from config files, count led definition entries
|
2017-11-27 05:47:27 +00:00
|
|
|
|
|
|
|
/* Create test pattern */
|
2017-12-07 09:33:14 +00:00
|
|
|
function showLedTestPattern() {
|
2017-11-27 05:47:27 +00:00
|
|
|
let i;
|
|
|
|
let switchMod;
|
2017-12-07 09:33:14 +00:00
|
|
|
for (i=0; i<configNumLeds; ++i) {
|
2017-11-27 05:47:27 +00:00
|
|
|
switchMod = i - 6 * Math.floor(i/6);
|
2017-12-07 09:33:14 +00:00
|
|
|
/*if (switchMod === 0) strip.setPixel(i, 10, 10, 10);
|
2017-12-03 08:22:54 +00:00
|
|
|
if (switchMod === 1) strip.setPixel(i, 10, 10, 10);
|
|
|
|
if (switchMod === 2) strip.setPixel(i, 10, 100, 0);
|
|
|
|
if (switchMod === 3) strip.setPixel(i, 0, 10, 0);
|
|
|
|
if (switchMod === 4) strip.setPixel(i, 0, 10, 10);
|
2017-12-07 09:33:14 +00:00
|
|
|
if (switchMod === 5) strip.setPixel(i, 0, 0, 10);*/
|
|
|
|
if (switchMod === 0) NeoPixel_set(i, 10, 10, 10);
|
|
|
|
if (switchMod === 1) NeoPixel_set(i, 10, 10, 10);
|
|
|
|
if (switchMod === 2) NeoPixel_set(i, 10, 100, 0);
|
|
|
|
if (switchMod === 3) NeoPixel_set(i, 0, 10, 0);
|
|
|
|
if (switchMod === 4) NeoPixel_set(i, 0, 10, 10);
|
|
|
|
if (switchMod === 5) NeoPixel_set(i, 0, 0, 10);
|
2017-11-27 05:47:27 +00:00
|
|
|
if (switchMod < 0 || switchMod > 5) print("WRONG -- should never reach this in switch statement!");
|
|
|
|
}
|
2017-12-07 09:33:14 +00:00
|
|
|
//strip.show();
|
|
|
|
NeoPixel_show();
|
2017-11-27 05:47:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function allLedOn() {
|
|
|
|
let i;
|
2017-12-07 09:33:14 +00:00
|
|
|
for (i=0; i<configNumLeds; ++i) {
|
|
|
|
//strip.setPixel(i, 10, 10, 10);
|
|
|
|
NeoPixel_set(i, 10, 10, 10);
|
2017-11-27 05:47:27 +00:00
|
|
|
}
|
2017-12-07 09:33:14 +00:00
|
|
|
//strip.show();
|
|
|
|
NeoPixel_show();
|
2017-11-27 05:47:27 +00:00
|
|
|
}
|
2017-07-13 04:18:04 +00:00
|
|
|
|
2017-11-27 05:47:27 +00:00
|
|
|
function allLedOff() {
|
2017-12-07 09:33:14 +00:00
|
|
|
//strip.clear();
|
|
|
|
NeoPixel_clear();
|
|
|
|
//strip.show();
|
|
|
|
NeoPixel_show();
|
2017-11-27 05:47:27 +00:00
|
|
|
}
|
2017-07-13 04:18:04 +00:00
|
|
|
|
2017-12-02 07:03:56 +00:00
|
|
|
function adjustBrightness(value) {
|
|
|
|
return Math.floor(value * brightnessAdjustment/100);
|
|
|
|
}
|
2017-11-27 05:47:27 +00:00
|
|
|
|
2017-12-07 09:33:14 +00:00
|
|
|
function loadColorDefs() {
|
2017-12-02 07:03:56 +00:00
|
|
|
// Load Color definitions
|
|
|
|
let json = File.read(colorFile);
|
|
|
|
let colors = [];
|
|
|
|
|
|
|
|
print('colorJson =', json);
|
|
|
|
if (json === '') {
|
|
|
|
print('ERROR: Color definition file does not exist!');
|
|
|
|
} else {
|
|
|
|
colors = JSON.parse(json);
|
|
|
|
}
|
|
|
|
for (i=0; i<colors.length; ++i) {
|
|
|
|
print('- addColor', colors[i].name, colors[i].red, colors[i].green, colors[i].blue);
|
|
|
|
addColor(colors[i].name, colors[i].red, colors[i].green, colors[i].blue);
|
|
|
|
}
|
|
|
|
json = null;
|
|
|
|
// colors = null; // NO! Do not do this, as the strings are still referenced!
|
2017-12-07 09:33:14 +00:00
|
|
|
}
|
2017-12-02 07:03:56 +00:00
|
|
|
|
2017-12-07 09:33:14 +00:00
|
|
|
function loadLedDefs() {
|
2017-12-02 07:03:56 +00:00
|
|
|
// Load LED Definitions
|
|
|
|
let json = File.read(lampsFile);
|
|
|
|
let ledDef = [];
|
2017-12-03 08:22:54 +00:00
|
|
|
print('lampsFile =', json);
|
2017-12-02 07:03:56 +00:00
|
|
|
if (json === '') {
|
|
|
|
print('ERROR: LED definition file does not exist!');
|
|
|
|
} else {
|
|
|
|
ledDef = JSON.parse(json);
|
|
|
|
}
|
2017-12-07 09:33:14 +00:00
|
|
|
numberOfLedDefs = 0;
|
2017-12-02 07:03:56 +00:00
|
|
|
for (i=0; i<ledDef.length; ++i) {
|
2017-12-07 09:33:14 +00:00
|
|
|
++numberOfLedDefs;
|
2017-12-02 07:03:56 +00:00
|
|
|
print('- addLedDefinition', ledDef[i].level, ledDef[i].room, ledDef[i].id, ledDef[i].onColor);
|
2017-12-07 09:33:14 +00:00
|
|
|
LEDDefinition_addByName(ledDef[i].level, ledDef[i].room, ledDef[i].id, ledDef[i].onColor);
|
2017-12-02 07:03:56 +00:00
|
|
|
// printColor(ledDef[i].onColor);
|
|
|
|
}
|
2017-12-07 09:33:14 +00:00
|
|
|
if (numberOfLedDefs > configNumLeds) {
|
|
|
|
print('WARNING: LED definition file contains more LEDs (', numberOfLedDefs, ') than configured in system-config (', configNumLeds, ')');
|
|
|
|
}
|
2017-12-02 07:03:56 +00:00
|
|
|
json = null;
|
|
|
|
// ledDef = null; // NO! Do not do this, as the strings are still referenced!
|
2017-12-07 09:33:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function loadAnimDefs() {
|
2017-12-02 07:03:56 +00:00
|
|
|
// Load Animation Definitions
|
|
|
|
let json = File.read(animationFile);
|
|
|
|
let animation = [];
|
2017-12-03 08:22:54 +00:00
|
|
|
print('animationFile =', json);
|
2017-12-02 07:03:56 +00:00
|
|
|
if (json === '') {
|
|
|
|
print('ERROR: Animation definition file does not exist!');
|
|
|
|
} else {
|
|
|
|
animation = JSON.parse(json);
|
|
|
|
}
|
|
|
|
for (i=0; i<animation.length; ++i) {
|
|
|
|
print('- addAnimationStep', animation[i].led, animation[i].mode, animation[i].ticks);
|
|
|
|
addAnimationStep(animation[i].led, animation[i].mode, animation[i].ticks);
|
|
|
|
}
|
|
|
|
json = null;
|
2017-11-27 05:47:27 +00:00
|
|
|
}
|
2017-12-02 07:03:56 +00:00
|
|
|
|
2017-12-07 09:33:14 +00:00
|
|
|
function initialize() {
|
|
|
|
// initialize LEDs
|
|
|
|
// ===============
|
|
|
|
print('***** Start initialization', getInfo());
|
|
|
|
let i;
|
|
|
|
|
|
|
|
if (useDefaults) {
|
|
|
|
print('Using default color definition');
|
|
|
|
numberOfLeds = configNumLeds;
|
|
|
|
startLEDStateEngine();
|
|
|
|
} else {
|
|
|
|
loadColorDefs();
|
|
|
|
loadLedDefs();
|
|
|
|
loadAnimDefs();
|
|
|
|
|
|
|
|
// Initialize LED State Engine
|
|
|
|
LEDStateEngine_init(pin, numberOfLeds);
|
|
|
|
}
|
2017-12-02 07:03:56 +00:00
|
|
|
allLedOff();
|
2017-12-07 09:33:14 +00:00
|
|
|
print('***** End of initialization', getInfo());
|
|
|
|
print('_______________________________________________________');
|
|
|
|
print('LedPin:', pin);
|
|
|
|
print('NumLEDs:', numberOfLeds);
|
|
|
|
print('Ticks:', getTicks());
|
|
|
|
print('Tick duration:', tickDuration, 'ms');
|
|
|
|
print('LED Update Cycle:', updateCycle, 'ms');
|
|
|
|
print('Brightness:', brightnessAdjustment, '%');
|
|
|
|
print('LED', 'Color', 'R', 'G', 'B', 'Tick', 'Level', 'Room', 'Id');
|
|
|
|
print('---', '-----', '---', '---', '-----', '---', '-----', '----', '--');
|
|
|
|
for (i=0; i<numberOfLeds; ++i) {
|
|
|
|
// print(i, LEDState_getRed(i), LEDState_getGreen(i), LEDState_getBlue(i), LEDState_getCurrentTick(i), LEDDefinition_getLevel(i), LEDDefinition_getRoom(i), LEDDefinition_getId(i))
|
|
|
|
print(i, LEDState_getColorName(i), adjustBrightness(LEDDefinition_getOnColorRed(i)), adjustBrightness(LEDDefinition_getOnColorGreen(i)), adjustBrightness(LEDDefinition_getOnColorBlue(i), LEDState_getCurrentTick(i), LEDDefinition_getLevel(i), LEDDefinition_getRoom(i), LEDDefinition_getId(i)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer.set(3000, false, function() {
|
|
|
|
initialize();
|
|
|
|
allLedOn();
|
|
|
|
print('***** Starting timer to delay test pattern generation');
|
|
|
|
/*print('***** Wait 1 second for other tasks to startup', getInfo());
|
2017-12-03 08:22:54 +00:00
|
|
|
Timer.set(1000, false, function() {
|
2017-12-07 09:33:14 +00:00
|
|
|
Timer.set(1000, false, function() {*/
|
|
|
|
allLedOff();
|
|
|
|
print('***** LED test pattern', getInfo());
|
|
|
|
showLedTestPattern();
|
|
|
|
print('***** Start LED state engine and LED-update timer', getInfo());
|
|
|
|
LEDStateEngine_start();
|
|
|
|
/*
|
|
|
|
Timer.set(updateCycle, true, function () {
|
|
|
|
let i;
|
|
|
|
for (i=0; i<numberOfLeds; ++i) {
|
|
|
|
strip.setPixel(i, adjustBrightness(LEDState_getRed(i)), adjustBrightness(LEDState_getGreen(i)), adjustBrightness(LEDState_getBlue(i)));
|
|
|
|
}
|
|
|
|
strip.show();
|
|
|
|
}, null);*/
|
|
|
|
/*}, null);
|
|
|
|
}, null);*/
|
2017-11-27 05:47:27 +00:00
|
|
|
}, null);
|
2017-12-03 08:22:54 +00:00
|
|
|
print('***** End of init.js, sub tasks still running', getInfo());
|
2017-11-27 05:47:27 +00:00
|
|
|
|
2017-12-02 07:03:56 +00:00
|
|
|
|
2017-12-03 08:22:54 +00:00
|
|
|
/* ------ RPC Handlers ------- */
|
2017-12-03 06:42:38 +00:00
|
|
|
|
|
|
|
RPC.addHandler('led.setBrightness', function(args) {
|
|
|
|
// print(args);
|
|
|
|
if (args !== undefined && args.level !== undefined) {
|
|
|
|
if (args.level > 0 && args.level <= 100) {
|
|
|
|
brightnessAdjustment = args.level;
|
|
|
|
return { result: 'ok' };
|
|
|
|
} else {
|
|
|
|
return { error: 'Brightness level must be in the range 1..100' };
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return { error: 'level is required having a value in the range 1..100' };
|
|
|
|
}
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
|
|
|
|
RPC.addHandler('led.pause', function(args) {
|
|
|
|
LEDStateEngine_pause();
|
|
|
|
return { result: 'ok' };
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
RPC.addHandler('led.run', function(args) {
|
|
|
|
LEDStateEngine_start();
|
|
|
|
return { result: 'ok' };
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
RPC.addHandler('led.getColors', function(args) {
|
|
|
|
let colors = JSON.parse(File.read(colorFile));
|
|
|
|
return { result: 'ok', colors: colors };
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
RPC.addHandler('led.getLamps', function(args) {
|
|
|
|
let lamps = JSON.parse(File.read(lampsFile));
|
|
|
|
return { result: 'ok', lamps: lamps };
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
RPC.addHandler('led.getAnimations', function(args) {
|
|
|
|
let anims = JSON.parse(File.read(animationFile));
|
|
|
|
return { result: 'ok', animations: anims };
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
function saveFile(filename, content) {
|
|
|
|
let backupFilename = 'bak-' + filename;
|
|
|
|
File.remove(backupFilename);
|
|
|
|
File.rename(filename, backupFilename);
|
|
|
|
File.write(JSON.stringify(content), filename);
|
|
|
|
let backupFilename = null;
|
|
|
|
}
|
2017-12-03 08:22:54 +00:00
|
|
|
|
|
|
|
function recoverFile(filename) {
|
|
|
|
let newerFilename = 'new-' + filename;
|
|
|
|
let backupFilename = 'bak-' + filename;
|
|
|
|
let bakFileContent = File.read(backupFilename);
|
|
|
|
if (bakFileContent === '') {
|
|
|
|
Log.error('recoverFile(' + filename + '): Backup file ' + backupFilename + ' does not exist or is empty');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
File.remove(newerFilename);
|
|
|
|
File.rename(filename, newerFilename);
|
|
|
|
File.rename(backupFilename, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
RPC.addHandler('led.putColors', function(args) {
|
|
|
|
if (args !== undefined && args.colors !== undefined) {
|
|
|
|
saveFile(colorFile, args.colors);
|
|
|
|
return { result: 'ok' };
|
|
|
|
} else {
|
|
|
|
return { error: 'colors: {name, red, green, blue} is required' };
|
|
|
|
}
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
RPC.addHandler('led.putLamps', function(args) {
|
|
|
|
if (args !== undefined && args.lamps !== undefined) {
|
|
|
|
saveFile(lampsFile, args.lamps);
|
|
|
|
return { result: 'ok' };
|
|
|
|
} else {
|
|
|
|
return { error: 'lamps: {level, room, id, onColor} is required' };
|
|
|
|
}
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
RPC.addHandler('led.putAnimations', function(args) {
|
|
|
|
if (args !== undefined && args.animations !== undefined) {
|
|
|
|
saveFile(animationFile, args.animations);
|
|
|
|
return { result: 'ok' };
|
|
|
|
} else {
|
|
|
|
return { error: 'animations: {led, mode, ticks} is required' };
|
|
|
|
}
|
|
|
|
}, null);
|