298 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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_file.js');
 | |
| load('api_dlite.js');
 | |
| 
 | |
| // Helper C function get_led_gpio_pin() in src/main.c returns built-in LED GPIO
 | |
| 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);
 | |
| 
 | |
| let pin = Cfg.get('led.pin');
 | |
| 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 useDefaults = Cfg.get('led.useDefaults');
 | |
| 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<configNumLeds; ++i) {
 | |
|     switchMod = i - 6 * Math.floor(i/6);
 | |
|     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);
 | |
|     if (switchMod < 0 || switchMod > 5) print("WRONG -- should never reach this in switch statement!");
 | |
|   }
 | |
|   NeoPixel_show();
 | |
| }
 | |
| 
 | |
| function allLedOn() {
 | |
|   let i;
 | |
|   for (i=0; i<configNumLeds; ++i) {
 | |
|     NeoPixel_set(i, 10, 10, 10);
 | |
|   }
 | |
|   NeoPixel_show();
 | |
| }
 | |
| 
 | |
| function allLedOff() {
 | |
|   NeoPixel_clear();
 | |
|   NeoPixel_show();
 | |
| }
 | |
| 
 | |
| function adjustBrightness(value) {
 | |
|   return Math.floor(value * brightnessAdjustment/100);
 | |
| }
 | |
| 
 | |
| function loadColorDefs() {
 | |
|   // 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!
 | |
| }
 | |
| 
 | |
| function loadLedDefs() {
 | |
|   // Load LED Definitions
 | |
|   let json = File.read(lampsFile);
 | |
|   let ledDef = [];
 | |
|   print('lampsFile =', json);
 | |
|   if (json === '') {
 | |
|     print('ERROR: LED definition file does not exist!');
 | |
|   } else {
 | |
|     ledDef = JSON.parse(json);
 | |
|   }
 | |
|   numberOfLedDefs = 0;
 | |
|   for (i=0; i<ledDef.length; ++i) {
 | |
|     ++numberOfLedDefs;
 | |
|     print('- addLedDefinition', ledDef[i].level, ledDef[i].room, ledDef[i].id, ledDef[i].onColor);
 | |
|     LEDDefinition_addByName(ledDef[i].level, ledDef[i].room, ledDef[i].id, ledDef[i].onColor);
 | |
|     // printColor(ledDef[i].onColor);
 | |
|   }
 | |
|   if (numberOfLedDefs > 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<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;
 | |
| }
 | |
| 
 | |
| function initialize() {
 | |
|   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);
 | |
|   }
 | |
|   allLedOff();
 | |
|   print('***** End of initialization', getInfo());
 | |
|   print('_______________________________________________________');
 | |
|   print('LedPin:', pin);
 | |
|   print('NumLEDs:', numberOfLeds);
 | |
|   print('Ticks:', getTicks());
 | |
|   print('Tick duration:', tickDuration, '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(1500, false, function() {
 | |
|   initialize();
 | |
|   allLedOn();
 | |
|   print('***** Starting timer to delay test pattern generation');
 | |
|   allLedOff();
 | |
|   print('***** LED test pattern', getInfo());
 | |
|   showLedTestPattern();
 | |
|   print('***** Start LED state engine and LED-update timer', getInfo());
 | |
|   LEDStateEngine_start();
 | |
|   Timer.set(10000, true, function() {
 | |
|     print("Timer: minTickTime =", LEDStateEngine_getMinTickTime(), ", maxTickTime =", LEDStateEngine_getMaxTickTime());
 | |
|   }, null);
 | |
| }, null);
 | |
| 
 | |
| /* ------ RPC Handlers ------- */
 | |
| print('**** Adding RPC handlers');
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 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);
 | |
| 
 | |
| print('***** End of init.js, sub tasks still running', getInfo());
 |