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("api_math.js"); load("api_file.js"); load("api_neopixel.js"); // Helper C function get_led_gpio_pin() in src/main.c returns built-in LED GPIO let onBoardLed = ffi('int get_led_gpio_pin(void)')(); let button = Cfg.get('pins.button'); let topic = '/devices/' + Cfg.get('device.id') + '/events'; print('LED GPIO:', onBoardLed, 'button GPIO:', button); let getInfo = function() { return JSON.stringify({ total_ram: Sys.total_ram(), free_ram: Sys.free_ram(), uptime: Sys.uptime() }); }; // Blink built-in LED every second /* GPIO.set_mode(onBoardLed, GPIO.MODE_OUTPUT); Timer.set(5000, true, function() { let value = GPIO.toggle(onBoardLed); 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:', ev, evs); }, null); // Initialize LED controller 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 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)'); 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 pin = Cfg.get('led.pin'); let configNumLeds = Cfg.get('led.count'); let colorOrder = NeoPixel.GRB; //let strip = NeoPixel.create(pin, configNumLeds, colorOrder); 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'); let tickDuration = Cfg.get('led.tickDuration'); let brightnessAdjustment = Cfg.get('led.brightness'); let numberOfLeds = configNumLeds, numberOfLedDefs = 0; // from config files, count led definition entries /* Create test pattern */ function showLedTestPattern() { let i; let switchMod; for (i=0; i 5) print("WRONG -- should never reach this in switch statement!"); } //strip.show(); NeoPixel_show(); } function allLedOn() { let i; for (i=0; i configNumLeds) { print('WARNING: LED definition file contains more LEDs (', numberOfLedDefs, ') than configured in system-config (', configNumLeds, ')'); } json = null; // ledDef = null; // NO! Do not do this, as the strings are still referenced! } function loadAnimDefs() { // Load Animation Definitions let json = File.read(animationFile); let animation = []; print('animationFile =', json); if (json === '') { print('ERROR: Animation definition file does not exist!'); } else { animation = JSON.parse(json); } for (i=0; i 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; } 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);