diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..3ad5780 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +coverage/* +firmware/src/libs/firmata/* diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..9c1d445 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,58 @@ +{ + "env": { + "node": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 2019, + "sourceType": "module" + }, + "rules": { + "eqeqeq": 0, + "no-var": 2, + "prefer-const": 2, + "no-shadow": 2, + "no-shadow-restricted-names": 2, + "no-use-before-define": 2, + "comma-dangle": [2, "never"], + "no-cond-assign": [2, "always"], + "no-constant-condition": 1, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-ex-assign": 2, + "no-extra-boolean-cast": 1, + "no-extra-semi": 2, + "no-func-assign": 2, + "no-irregular-whitespace": 2, + "default-case": 2, + "guard-for-in": 2, + "no-floating-decimal": 2, + "no-self-compare": 2, + "no-sequences": 2, + "no-throw-literal": 2, + "radix": 2, + "quotes": [2, "single", "avoid-escape"], + "indent": [2, 2, { "SwitchCase": 1 }], + "brace-style": [2, "1tbs", { "allowSingleLine": true }], + "comma-style": [2, "last"], + "no-multiple-empty-lines": 2, + "no-nested-ternary": 2, + "one-var": [2, "never"], + "padded-blocks": [2, "never"], + "keyword-spacing": 2, + "no-console": 0, + "space-before-blocks": 2, + "space-before-function-paren": [2, "never"], + "spaced-comment": 2, + "valid-jsdoc": [2, { "requireReturn": false }], + "no-unreachable": 2, + "no-unexpected-multiline": 2, + "no-else-return": 2, + "constructor-super": 2, + "no-this-before-super": 2, + "object-shorthand": [2, "always"], + "no-loop-func": 0, + "no-param-reassign": 0, + "no-empty": 0 + } +} diff --git a/Makefile b/Makefile index 7e903c3..9b91826 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ install: clean npm install lint: - @echo "Not implemented" + npm run lint test: npm run test diff --git a/examples/channel_fade.js b/examples/channel_fade.js index 71f0460..c468789 100644 --- a/examples/channel_fade.js +++ b/examples/channel_fade.js @@ -4,86 +4,85 @@ // This example shows how to use node-pixel using Johnny Five as the // hook for the board. -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; -var fps = 40; // how many frames per second do you want to try? +const fps = 40; // how many frames per second do you want to try? -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + strip = new pixel.Strip({ + board: this, + controller: 'FIRMATA', + strips: [ {pin: 6, length: 8}, {pin: 8, length: 8}], + gamma: 2.8 + }); - strip = new pixel.Strip({ - board: this, - controller: "FIRMATA", - strips: [ {pin: 6, length: 8}, {pin: 8, length: 8},], - gamma: 2.8, - }); + strip.on('ready', function() { + console.log("Strip ready, let's go"); - strip.on("ready", function() { + strip.color('#000000'); + strip.show(); + const colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta']; + let current_color = 0; + let fade_level = 0; + let fade_up = true; + const fader = setInterval(function() { + if (fade_up) { + // fading upwards, if we hit the top then turn around + // and go back down again. + if (++fade_level > 255) { + fade_up = false; + } + } else { + if (--fade_level < 0) { + fade_up = true; + fade_level = 0; + if (++current_color >= colors.length) current_color = 0; + } + } - console.log("Strip ready, let's go"); + let hc = ''; + switch (colors[current_color]) { + case 'red': + hc = `rgb(${fade_level}, 0, 0)`; + break; + case 'green': + hc = `rgb(0, ${fade_level}, 0)`; + break; + case 'blue': + hc = `rgb(0, 0, ${fade_level})`; + break; + case 'white': + hc = `rgb(${fade_level}, ${fade_level}, ${fade_level})`; + break; + case 'yellow': + hc = `rgb(${fade_level}, ${fade_level}, 0)`; + break; + case 'magenta': + hc = `rgb(${fade_level}, 0, ${fade_level})`; + break; + case 'cyan': + hc = `rgb(0, ${fade_level}, ${fade_level})`; + break; + default: + break; + } - strip.color('#000000'); - strip.show(); - let colors = ["red", "green", "blue", "yellow", "cyan", "magenta"]; - let current_color = 0; - let fade_level = 0; - let fade_up = true; - var fader = setInterval(function() { - - if (fade_up) { - // fading upwards, if we hit the top then turn around - // and go back down again. - if (++fade_level > 255) { - fade_up = false; - } - } else { - if (--fade_level < 0) { - fade_up = true; - fade_level = 0; - if (++current_color >= colors.length) current_color = 0; - } - } - - let hc = ""; - switch (colors[current_color]) { - case "red": - hc = `rgb(${fade_level}, 0, 0)`; - break; - case "green": - hc = `rgb(0, ${fade_level}, 0)`; - break; - case "blue": - hc = `rgb(0, 0, ${fade_level})`; - break; - case "white": - hc = `rgb(${fade_level}, ${fade_level}, ${fade_level})`; - break; - case "yellow": - hc = `rgb(${fade_level}, ${fade_level}, 0)`; - break; - case "magenta": - hc = `rgb(${fade_level}, 0, ${fade_level})`; - break; - case "cyan": - hc = `rgb(0, ${fade_level}, ${fade_level})`; - break; - } - - // need to do this by pixel - for (let i = 0; i < strip.length; i++) { - strip.pixel(i).color(hc); - } - //strip.color(hc); - strip.show(); - }, 1000/fps); - }); + // need to do this by pixel + for (let i = 0; i < strip.length; i++) { + strip.pixel(i).color(hc); + } + // strip.color(hc); + strip.show(); + }, 1000/fps); + }); }); diff --git a/examples/firmata.js b/examples/firmata.js index c59c7dc..9f1918e 100644 --- a/examples/firmata.js +++ b/examples/firmata.js @@ -1,43 +1,41 @@ // This example shows how to use node-pixel using firmata as the // hook for the board. -var firmata = require("firmata"); -var pixel = require("../lib/pixel.js"); +const firmata = require('firmata'); +const pixel = require('../lib/pixel.js'); -var opts = {}; +const opts = {}; if (process.argv[2] == undefined) { - console.log("Please supply a device port to connect to"); - process.exit(); + console.log('Please supply a device port to connect to'); + process.exit(); } opts.port = process.argv[2]; -var strip = null; +let strip = null; -var board = new firmata.Board(opts.port, function() { +const board = new firmata.Board(opts.port, function() { + console.log('Firmata ready, lets add light'); - console.log("Firmata ready, lets add light"); + strip = new pixel.Strip({ + data: 6, + length: 4, + firmata: board + }); - strip = new pixel.Strip({ - data: 6, - length: 4, - firmata: board, - }); + let pos = 0; + const colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white']; + let current_color = 0; - var pos = 0; - var colors = ["red", "green", "blue", "yellow", "cyan", "magenta", "white"]; - var current_color = 0; + const blinker = setInterval(function() { + strip.color('#000'); // blanks it out - var blinker = setInterval(function() { + if (++pos >= strip.length) { + pos = 0; + if (++current_color>= colors.length) current_color = 0; + } + strip.pixel(pos).color(colors[current_color]); - strip.color("#000"); // blanks it out - - if (++pos >= strip.length) { - pos = 0; - if (++current_color>= colors.length) current_color = 0; - } - strip.pixel(pos).color(colors[current_color]); - - strip.show(); - }, 1000/2); + strip.show(); + }, 1000/2); }); diff --git a/examples/johnnyfive-i2c.js b/examples/johnnyfive-i2c.js index f2806be..e723682 100644 --- a/examples/johnnyfive-i2c.js +++ b/examples/johnnyfive-i2c.js @@ -1,47 +1,44 @@ // This example shows how to use node-pixel using Johnny Five as the // hook for the board. -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); - -var opts = {}; -opts.port = process.argv[2] || ""; - -var board = new five.Board(opts); -var strip = null; - -var fps = 1; // how many frames per second do you want to try? - -board.on("ready", function() { - - console.log("Board ready, lets add light"); - - strip = new pixel.Strip({ - color_order: pixel.COLOR_ORDER.GRB, - board: this, - controller: "I2CBACKPACK", - strips: [8], - }); - - strip.on("ready", function() { - - console.log("Strip ready, let's go"); - - var colors = ["red", "green", "blue", "yellow", "cyan", "magenta", "white"]; - var current_colors = [0,1,2,3,4]; - var current_pos = [0,1,2,3,4]; - var blinker = setInterval(function() { - - strip.color("#000"); // blanks it out - - for (var i=0; i< current_pos.length; i++) { - if (++current_pos[i] >= strip.length) { - current_pos[i] = 0; - if (++current_colors[i] >= colors.length) current_colors[i] = 0; - } - strip.pixel(current_pos[i]).color(colors[current_colors[i]]); - } - - strip.show(); - }, 1000/fps); - }); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); + +const opts = {}; +opts.port = process.argv[2] || ''; + +const board = new five.Board(opts); +let strip = null; + +const fps = 1; // how many frames per second do you want to try? + +board.on('ready', function() { + console.log('Board ready, lets add light'); + + strip = new pixel.Strip({ + color_order: pixel.COLOR_ORDER.GRB, + board: this, + controller: 'I2CBACKPACK', + strips: [8] + }); + + strip.on('ready', function() { + console.log("Strip ready, let's go"); + + const colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white']; + const current_colors = [0,1,2,3,4]; + const current_pos = [0,1,2,3,4]; + const blinker = setInterval(function() { + strip.color('#000'); // blanks it out + + for (let i=0; i< current_pos.length; i++) { + if (++current_pos[i] >= strip.length) { + current_pos[i] = 0; + if (++current_colors[i] >= colors.length) current_colors[i] = 0; + } + strip.pixel(current_pos[i]).color(colors[current_colors[i]]); + } + + strip.show(); + }, 1000/fps); + }); }); diff --git a/examples/johnnyfive.js b/examples/johnnyfive.js index 8a88fc8..1e61c74 100644 --- a/examples/johnnyfive.js +++ b/examples/johnnyfive.js @@ -1,45 +1,42 @@ // This example shows how to use node-pixel using Johnny Five as the // hook for the board. -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; -var fps = 10; // how many frames per second do you want to try? +const fps = 10; // how many frames per second do you want to try? -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + strip = new pixel.Strip({ + data: 6, + length: 8, + color_order: pixel.COLOR_ORDER.GRB, + board: this, + controller: 'FIRMATA' + }); - strip = new pixel.Strip({ - data: 6, - length: 8, - color_order: pixel.COLOR_ORDER.GRB, - board: this, - controller: "FIRMATA", - }); - - strip.on("ready", function() { - - console.log("Strip ready, let's go"); + strip.on('ready', function() { + console.log("Strip ready, let's go"); - var colors = ["red", "green", "blue", "yellow", "cyan", "magenta", "white"]; - //var current_colors = [0,1,2,3,4]; - var current_pos = [0,1,2,3,4]; + const colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white']; + // var current_colors = [0,1,2,3,4]; + const current_pos = [0,1,2,3,4]; - current_pos.forEach((pos) => { - strip.pixel(pos).color(colors[pos]); - }); - - var blinker = setInterval(function() { + current_pos.forEach((pos) => { + strip.pixel(pos).color(colors[pos]); + }); - strip.shift(1, pixel.FORWARD, true); + const blinker = setInterval(function() { + strip.shift(1, pixel.FORWARD, true); - strip.show(); - }, 1000/fps); - }); + strip.show(); + }, 1000/fps); + }); }); diff --git a/examples/mega-multipin.js b/examples/mega-multipin.js index 686f4f2..d6ba2c1 100644 --- a/examples/mega-multipin.js +++ b/examples/mega-multipin.js @@ -1,73 +1,71 @@ // This example shows how to use node-pixel // to control multiple strips on the same board -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; -var fps = 10; // how many frames per second do you want to try? +const fps = 10; // how many frames per second do you want to try? -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + strip = new pixel.Strip({ + board: this, + controller: 'FIRMATA', + strips: [ + {pin: 2, length: 8}, {pin: 3, length: 8}, + {pin: 4, length: 8}, {pin: 5, length: 8}, + {pin: 6, length: 8}, {pin: 7, length: 8}, + {pin: 8, length: 8}, {pin: 9, length: 8} + ] + }); - strip = new pixel.Strip({ - board: this, - controller: "FIRMATA", - strips: [ - {pin: 2, length: 8}, {pin: 3, length: 8}, - {pin: 4, length: 8}, {pin: 5, length: 8}, - {pin: 6, length: 8}, {pin: 7, length: 8}, - {pin: 8, length: 8}, {pin: 9, length: 8}, - ] - }); + strip.on('ready', function() { + console.log('Strip ready'); - strip.on("ready", function() { + const strips = 8; + const lengths = 8; - console.log("Strip ready"); + const current_pos = new Array(); + for (let i=0; i< strips; i++) { + current_pos.push(new Array()); + } - var strips = 8; - var lengths = 8; - - var current_pos = new Array(); - for (var i=0; i< strips; i++) { - current_pos.push(new Array()); + // periodically drop a new item onto one of the strips randomly. + const dripper = setInterval(function() { + const s = Math.round(Math.random()*strips); + try { + current_pos[s].push(0); + } catch (e) { + if (e instanceof TypeError) { + // this usually happens if we're splicing and writing at the + // same time. + return; } - - // periodically drop a new item onto one of the strips randomly. - var dripper = setInterval(function() { - var s = Math.round(Math.random()*strips); - try { - current_pos[s].push(0); - } catch (e) { - if (e instanceof TypeError) { - // this usually happens if we're splicing and writing at the - // same time. - return; - } - } - }, 75); + } + }, 75); - var iterator = setInterval(function() { - strip.color("#000"); // blanks it out + const iterator = setInterval(function() { + strip.color('#000'); // blanks it out - for (var i=0; i< current_pos.length; i++) { - for (var j=0; j< current_pos[i].length; j++) { - if (current_pos[i][j] >= 8) { - current_pos[i].splice(j, 1);// remove the item - } else { - strip.pixel(i * lengths + current_pos[i][j]).color("#440"); - current_pos[i][j]++; - } - } - } - strip.show(); - }, 1000/fps); - }); + for (let i=0; i< current_pos.length; i++) { + for (let j=0; j< current_pos[i].length; j++) { + if (current_pos[i][j] >= 8) { + current_pos[i].splice(j, 1);// remove the item + } else { + strip.pixel(i * lengths + current_pos[i][j]).color('#440'); + current_pos[i][j]++; + } + } + } + strip.show(); + }, 1000/fps); + }); }); diff --git a/examples/multipin-i2c.js b/examples/multipin-i2c.js index a3ab71f..ac46c33 100644 --- a/examples/multipin-i2c.js +++ b/examples/multipin-i2c.js @@ -1,47 +1,45 @@ // This example shows how to use node-pixel // to control multiple strips on the same board -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; -var fps = 30; // how many frames per second do you want to try? +const fps = 30; // how many frames per second do you want to try? -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + strip = new pixel.Strip({ + board: this, + controller: 'I2CBACKPACK', + color_order: pixel.COLOR_ORDER.GRB, + strips: [ 8, 8 ] + }); - strip = new pixel.Strip({ - board: this, - controller: "I2CBACKPACK", - color_order: pixel.COLOR_ORDER.GRB, - strips: [ 8, 8 ] - }); - - strip.on("ready", function() { - - console.log("Strip ready"); - - var colors = ["red", "green", "blue"]; - var current_pos = [0,1,2]; - strip.color("#000"); // blanks it out - current_pos.forEach((pos) => { - strip.pixel(pos).color(colors[pos]); - }); - strip.show(); - var blinker = setInterval(function() { - strip.shift(1, pixel.FORWARD, true); - strip.show(); - }, 1000/fps); - }); + strip.on('ready', function() { + console.log('Strip ready'); - strip.on("error", function(err) { - console.log(err); - process.exit(); + const colors = ['red', 'green', 'blue']; + const current_pos = [0,1,2]; + strip.color('#000'); // blanks it out + current_pos.forEach((pos) => { + strip.pixel(pos).color(colors[pos]); }); + strip.show(); + const blinker = setInterval(function() { + strip.shift(1, pixel.FORWARD, true); + strip.show(); + }, 1000/fps); + }); + + strip.on('error', function(err) { + console.log(err); + process.exit(); + }); }); diff --git a/examples/multipin.js b/examples/multipin.js index 31e594e..53ff577 100644 --- a/examples/multipin.js +++ b/examples/multipin.js @@ -1,51 +1,48 @@ // This example shows how to use node-pixel // to control multiple strips on the same board -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); - -var opts = {}; -opts.port = process.argv[2] || ""; - -var board = new five.Board(opts); -var strip = null; - -var fps = 30; // how many frames per second do you want to try? - -board.on("ready", function() { - - console.log("Board ready, lets add light"); - - strip = new pixel.Strip({ - board: this, - controller: "FIRMATA", - strips: [ {pin: 6, length: 8}, {pin: 7, length: 8},] - }); - - strip.on("ready", function() { - - console.log("Strip ready"); - - var colors = ["red", "green", "blue"]; - var current_colors = [0,1,2]; - var pixel_list = [0,1,2]; - var blinker = setInterval(function() { - - strip.color("#000"); // blanks it out - for (var i=0; i< pixel_list.length; i++) { - if (++pixel_list[i] >= strip.length) { - pixel_list[i] = 0; - if (++current_colors[i] >= colors.length) current_colors[i] = 0; - } - strip.pixel(pixel_list[i]).color(colors[current_colors[i]]); - } - - strip.show(); - }, 1000/fps); - }); - - strip.on("error", function(err) { - console.log(err); - process.exit(); - }); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); + +const opts = {}; +opts.port = process.argv[2] || ''; + +const board = new five.Board(opts); +let strip = null; + +const fps = 30; // how many frames per second do you want to try? + +board.on('ready', function() { + console.log('Board ready, lets add light'); + + strip = new pixel.Strip({ + board: this, + controller: 'FIRMATA', + strips: [ {pin: 6, length: 8}, {pin: 7, length: 8}] + }); + + strip.on('ready', function() { + console.log('Strip ready'); + + const colors = ['red', 'green', 'blue']; + const current_colors = [0,1,2]; + const pixel_list = [0,1,2]; + const blinker = setInterval(function() { + strip.color('#000'); // blanks it out + for (let i=0; i< pixel_list.length; i++) { + if (++pixel_list[i] >= strip.length) { + pixel_list[i] = 0; + if (++current_colors[i] >= colors.length) current_colors[i] = 0; + } + strip.pixel(pixel_list[i]).color(colors[current_colors[i]]); + } + + strip.show(); + }, 1000/fps); + }); + + strip.on('error', function(err) { + console.log(err); + process.exit(); + }); }); diff --git a/examples/panel.js b/examples/panel.js index 8bb60c4..3842247 100644 --- a/examples/panel.js +++ b/examples/panel.js @@ -2,39 +2,36 @@ // This example shows how to use node-pixel using Johnny Five as the // hook for the board. -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); - -var opts = {}; -opts.port = process.argv[2] || ""; - -var board = new five.Board(opts); -var strip = null; - -var fps = 1; // how many frames per second do you want to try? - -board.on("ready", function() { - - console.log("Board ready, lets add light"); - - strip = new pixel.Strip({ - board: this, - controller: "FIRMATA", - data: 6, - length: 64, - }); - - strip.on("ready", function() { - - console.log("Strip ready, let's go"); - - var colors = ["red", "green", "blue", "yellow", "cyan", "magenta", "white"]; - var current_colors = 0; - var blinker = setInterval(function() { - - if (++current_colors >= colors.length) current_colors = 0; - strip.color(colors[current_colors]); // blanks it out - strip.show(); - }, 1000/fps); - }); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); + +const opts = {}; +opts.port = process.argv[2] || ''; + +const board = new five.Board(opts); +let strip = null; + +const fps = 1; // how many frames per second do you want to try? + +board.on('ready', function() { + console.log('Board ready, lets add light'); + + strip = new pixel.Strip({ + board: this, + controller: 'FIRMATA', + data: 6, + length: 64 + }); + + strip.on('ready', function() { + console.log("Strip ready, let's go"); + + const colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white']; + let current_colors = 0; + const blinker = setInterval(function() { + if (++current_colors >= colors.length) current_colors = 0; + strip.color(colors[current_colors]); // blanks it out + strip.show(); + }, 1000/fps); + }); }); diff --git a/examples/rainbow-dynamic-multipin.js b/examples/rainbow-dynamic-multipin.js index 66e5199..0381e50 100644 --- a/examples/rainbow-dynamic-multipin.js +++ b/examples/rainbow-dynamic-multipin.js @@ -4,77 +4,75 @@ * * adapted from the examples by @pierceray */ -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; /** * how many frames per second do you want to try? */ -var fps = 30; +const fps = 30; -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + // Input a value 0 to 255 to get a color value. + // The colors are a transition r - g - b - back to r. + function colorWheel( WheelPos ) { + let r; let g; let b; + WheelPos = 255 - WheelPos; - // setup the node-pixel strip. - strip = new pixel.Strip({ - board: this, - controller: "FIRMATA", - strips: [ {pin: 6, length: 8}, {pin: 7, length: 8}], - }); - - strip.on("ready", function() { - console.log("Strip ready, let's go"); - dynamicRainbow(fps); - }); + if ( WheelPos < 85 ) { + r = 255 - WheelPos * 3; + g = 0; + b = WheelPos * 3; + } else if (WheelPos < 170) { + WheelPos -= 85; + r = 0; + g = WheelPos * 3; + b = 255 - WheelPos * 3; + } else { + WheelPos -= 170; + r = WheelPos * 3; + g = 255 - WheelPos * 3; + b = 0; + } + // returns a string with the rgb value to be used as the parameter + return 'rgb(' + r +',' + g + ',' + b + ')'; + } - function dynamicRainbow( delay ){ - console.log( 'dynamicRainbow' ); + function dynamicRainbow( delay ) { + console.log( 'dynamicRainbow' ); - var showColor; - var cwi = 0; // colour wheel index (current position on colour wheel) - var foo = setInterval(function(){ - if (++cwi > 255) { - cwi = 0; - } + let showColor; + let cwi = 0; // colour wheel index (current position on colour wheel) + const foo = setInterval(function() { + if (++cwi > 255) { + cwi = 0; + } - for(var i = 0; i < strip.length; i++) { - showColor = colorWheel( ( cwi+i ) & 255 ); - strip.pixel( i ).color( showColor ); - } - strip.show(); - }, 1000/delay); - } + for (let i = 0; i < strip.length; i++) { + showColor = colorWheel( ( cwi+i ) & 255 ); + strip.pixel( i ).color( showColor ); + } + strip.show(); + }, 1000/delay); + } - // Input a value 0 to 255 to get a color value. - // The colors are a transition r - g - b - back to r. - function colorWheel( WheelPos ){ - var r,g,b; - WheelPos = 255 - WheelPos; - - if ( WheelPos < 85 ) { - r = 255 - WheelPos * 3; - g = 0; - b = WheelPos * 3; - } else if (WheelPos < 170) { - WheelPos -= 85; - r = 0; - g = WheelPos * 3; - b = 255 - WheelPos * 3; - } else { - WheelPos -= 170; - r = WheelPos * 3; - g = 255 - WheelPos * 3; - b = 0; - } - // returns a string with the rgb value to be used as the parameter - return "rgb(" + r +"," + g + "," + b + ")"; - } + // setup the node-pixel strip. + strip = new pixel.Strip({ + board: this, + controller: 'FIRMATA', + strips: [ {pin: 6, length: 8}, {pin: 7, length: 8}] + }); + strip.on('ready', function() { + console.log("Strip ready, let's go"); + dynamicRainbow(fps); + }); }); diff --git a/examples/rainbow-dynamic.js b/examples/rainbow-dynamic.js index 2c3b899..3692376 100644 --- a/examples/rainbow-dynamic.js +++ b/examples/rainbow-dynamic.js @@ -5,78 +5,76 @@ * * created by @pierceray in June 2015 */ -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; /** * how many frames per second do you want to try? */ -var fps = 20; +const fps = 20; -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + // Input a value 0 to 255 to get a color value. + // The colors are a transition r - g - b - back to r. + function colorWheel( WheelPos ) { + let r; let g; let b; + WheelPos = 255 - WheelPos; - // setup the node-pixel strip. - strip = new pixel.Strip({ - data: 6, - length: 17, // number of pixels in the strip. - board: this, - controller: "FIRMATA" - }); - - strip.on("ready", function() { - console.log("Strip ready, let's go"); - dynamicRainbow(fps); - }); + if ( WheelPos < 85 ) { + r = 255 - WheelPos * 3; + g = 0; + b = WheelPos * 3; + } else if (WheelPos < 170) { + WheelPos -= 85; + r = 0; + g = WheelPos * 3; + b = 255 - WheelPos * 3; + } else { + WheelPos -= 170; + r = WheelPos * 3; + g = 255 - WheelPos * 3; + b = 0; + } + // returns a string with the rgb value to be used as the parameter + return 'rgb(' + r +',' + g + ',' + b + ')'; + } - function dynamicRainbow( delay ){ - console.log( 'dynamicRainbow' ); + function dynamicRainbow( delay ) { + console.log( 'dynamicRainbow' ); - var showColor; - var cwi = 0; // colour wheel index (current position on colour wheel) - var foo = setInterval(function(){ - if (++cwi > 255) { - cwi = 0; - } + let showColor; + let cwi = 0; // colour wheel index (current position on colour wheel) + const foo = setInterval(function() { + if (++cwi > 255) { + cwi = 0; + } - for(var i = 0; i < strip.length; i++) { - showColor = colorWheel( ( cwi+i ) & 255 ); - strip.pixel( i ).color( showColor ); - } - strip.show(); - }, 1000/delay); - } + for (let i = 0; i < strip.length; i++) { + showColor = colorWheel( ( cwi+i ) & 255 ); + strip.pixel( i ).color( showColor ); + } + strip.show(); + }, 1000/delay); + } - // Input a value 0 to 255 to get a color value. - // The colors are a transition r - g - b - back to r. - function colorWheel( WheelPos ){ - var r,g,b; - WheelPos = 255 - WheelPos; - - if ( WheelPos < 85 ) { - r = 255 - WheelPos * 3; - g = 0; - b = WheelPos * 3; - } else if (WheelPos < 170) { - WheelPos -= 85; - r = 0; - g = WheelPos * 3; - b = 255 - WheelPos * 3; - } else { - WheelPos -= 170; - r = WheelPos * 3; - g = 255 - WheelPos * 3; - b = 0; - } - // returns a string with the rgb value to be used as the parameter - return "rgb(" + r +"," + g + "," + b + ")"; - } + // setup the node-pixel strip. + strip = new pixel.Strip({ + data: 6, + length: 17, // number of pixels in the strip. + board: this, + controller: 'FIRMATA' + }); + strip.on('ready', function() { + console.log("Strip ready, let's go"); + dynamicRainbow(fps); + }); }); diff --git a/examples/rainbow-static.js b/examples/rainbow-static.js index ef795ea..b9e36fc 100644 --- a/examples/rainbow-static.js +++ b/examples/rainbow-static.js @@ -4,67 +4,65 @@ * * created by @pierceray in June 2015 */ -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var opts = {}; -opts.port = process.argv[2] || ""; +const opts = {}; +opts.port = process.argv[2] || ''; -var board = new five.Board(opts); -var strip = null; +const board = new five.Board(opts); +let strip = null; -board.on("ready", function() { +board.on('ready', function() { + console.log('Board ready, lets add light'); - console.log("Board ready, lets add light"); + // Input a value 0 to 255 to get a color value. + // The colours are a transition r - g - b - back to r. + function colorWheel( WheelPos ) { + let r; let g; let b; + WheelPos = 255 - WheelPos; - // setup the node-pixel strip. - strip = new pixel.Strip({ - data: 6, - length: 16, // number of pixels in the strip. - board: this, - controller: "FIRMATA" - }); - - strip.on("ready", function() { - console.log("Strip ready, let's go"); - - staticRainbow(); - }); + if ( WheelPos < 85 ) { + r = 255 - WheelPos * 3; + g = 0; + b = WheelPos * 3; + } else if (WheelPos < 170) { + WheelPos -= 85; + r = 0; + g = WheelPos * 3; + b = 255 - WheelPos * 3; + } else { + WheelPos -= 170; + r = WheelPos * 3; + g = 255 - WheelPos * 3; + b = 0; + } + // returns a string with the rgb value to be used as the parameter + return 'rgb(' + r +',' + g + ',' + b + ')'; + } - function staticRainbow(){ - console.log('staticRainbow'); + function staticRainbow() { + console.log('staticRainbow'); - var showColor; - for(var i = 0; i < strip.length; i++) { - showColor = colorWheel( ( (i+10)*256 / strip.length ) & 255 ); - strip.pixel(i).color( showColor); - } - strip.show(); + let showColor; + for (let i = 0; i < strip.length; i++) { + showColor = colorWheel( ( (i+10)*256 / strip.length ) & 255 ); + strip.pixel(i).color( showColor); } + strip.show(); + } - // Input a value 0 to 255 to get a color value. - // The colours are a transition r - g - b - back to r. - function colorWheel( WheelPos ){ - var r,g,b; - WheelPos = 255 - WheelPos; + // setup the node-pixel strip. + strip = new pixel.Strip({ + data: 6, + length: 16, // number of pixels in the strip. + board: this, + controller: 'FIRMATA' + }); - if ( WheelPos < 85 ) { - r = 255 - WheelPos * 3; - g = 0; - b = WheelPos * 3; - } else if (WheelPos < 170) { - WheelPos -= 85; - r = 0; - g = WheelPos * 3; - b = 255 - WheelPos * 3; - } else { - WheelPos -= 170; - r = WheelPos * 3; - g = 255 - WheelPos * 3; - b = 0; - } - // returns a string with the rgb value to be used as the parameter - return "rgb(" + r +"," + g + "," + b + ")"; - } + strip.on('ready', function() { + console.log("Strip ready, let's go"); + staticRainbow(); + }); }); diff --git a/examples/repl.js b/examples/repl.js index db39a2f..857b29e 100644 --- a/examples/repl.js +++ b/examples/repl.js @@ -1,37 +1,35 @@ // This example shows how to use node-pixel using Johnny Five as the // hook for the board. -const five = require("johnny-five"); -const pixel = require("../lib/pixel.js"); - -var opts = {}; -opts.port = process.argv[2] || ""; - -var board = new five.Board(opts); -var strip = null; - -board.on("ready", function() { - - console.log("Board ready, lets add light"); - - strip = new pixel.Strip({ - data: 6, - length: 8, - color_order: pixel.COLOR_ORDER.GRB, - board: this, - controller: "FIRMATA", - //strips: [8], - }); - - strip.on("ready", function() { - - console.log("Strip ready, let's go"); - console.log("You can now interact with the strip using the repl using the `strip` object"); - - strip.color("#000"); - strip.pixel(1).color("red"); - strip.show(); - board.repl.inject({ - strip: this, - }); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); + +const opts = {}; +opts.port = process.argv[2] || ''; + +const board = new five.Board(opts); +let strip = null; + +board.on('ready', function() { + console.log('Board ready, lets add light'); + + strip = new pixel.Strip({ + data: 6, + length: 8, + color_order: pixel.COLOR_ORDER.GRB, + board: this, + controller: 'FIRMATA' + // strips: [8], + }); + + strip.on('ready', function() { + console.log("Strip ready, let's go"); + console.log('You can now interact with the strip using the repl using the `strip` object'); + + strip.color('#000'); + strip.pixel(1).color('red'); + strip.show(); + board.repl.inject({ + strip: this }); + }); }); diff --git a/examples/shift.js b/examples/shift.js index 8a025c0..699633a 100644 --- a/examples/shift.js +++ b/examples/shift.js @@ -1,44 +1,41 @@ // This example shows how to use node-pixel using Johnny Five as the // hook for the board. -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); - -var opts = {}; -opts.port = process.argv[2] || ""; - -var board = new five.Board(opts); -var strip = null; - -var fps = 20; // how many frames per second do you want to try? - -board.on("ready", function() { - - console.log("Board ready, lets add light"); - - strip = new pixel.Strip({ - data: 7, - length: 64, - color_order: pixel.COLOR_ORDER.GRB, - board: this, - controller: "FIRMATA", - }); - - strip.on("ready", function() { - - console.log("Strip ready, let's go"); - - strip.color("#000"); - strip.pixel(0).color("#300"); - strip.pixel(1).color("#300"); - strip.pixel(2).color("#300"); - strip.pixel(5).color("#003"); - strip.pixel(6).color("#003"); - strip.show(); - var blinker = setInterval(function() { - - strip.shift(1, pixel.BACKWARD, true); - - strip.show(); - }, 1000/fps); - }); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); + +const opts = {}; +opts.port = process.argv[2] || ''; + +const board = new five.Board(opts); +let strip = null; + +const fps = 20; // how many frames per second do you want to try? + +board.on('ready', function() { + console.log('Board ready, lets add light'); + + strip = new pixel.Strip({ + data: 7, + length: 64, + color_order: pixel.COLOR_ORDER.GRB, + board: this, + controller: 'FIRMATA' + }); + + strip.on('ready', function() { + console.log("Strip ready, let's go"); + + strip.color('#000'); + strip.pixel(0).color('#300'); + strip.pixel(1).color('#300'); + strip.pixel(2).color('#300'); + strip.pixel(5).color('#003'); + strip.pixel(6).color('#003'); + strip.show(); + const blinker = setInterval(function() { + strip.shift(1, pixel.BACKWARD, true); + + strip.show(); + }, 1000/fps); + }); }); diff --git a/firmware/boards.js b/firmware/boards.js index 6f65e0f..8b30897 100644 --- a/firmware/boards.js +++ b/firmware/boards.js @@ -4,27 +4,27 @@ // flashed. module.exports = { - "uno" :{ - package: "arduino:avr:uno", - }, - "nano": { - cpu: "atmega328", - package: "arduino:avr:nano:cpu=atmega328", - }, - "pro-mini": { - cpu: "16MHzatmega328", - package: "arduino:avr:pro:cpu=16MHzatmega328", - }, - "mega": { - package: "arduino:avr:mega:cpu=atmega2560", - }, - "diecimila": { - package: "arduino:avr:diecimila:cpu=atmega328", - }, - "leonardo": { - package: "arduino:avr:leonardo", - }, - "micro": { - package: "arduino:avr:micro", - }, + 'uno' :{ + package: 'arduino:avr:uno' + }, + 'nano': { + cpu: 'atmega328', + package: 'arduino:avr:nano:cpu=atmega328' + }, + 'pro-mini': { + cpu: '16MHzatmega328', + package: 'arduino:avr:pro:cpu=16MHzatmega328' + }, + 'mega': { + package: 'arduino:avr:mega:cpu=atmega2560' + }, + 'diecimila': { + package: 'arduino:avr:diecimila:cpu=atmega328' + }, + 'leonardo': { + package: 'arduino:avr:leonardo' + }, + 'micro': { + package: 'arduino:avr:micro' + } }; diff --git a/lib/pixel.js b/lib/pixel.js index d7e909f..d9f18db 100644 --- a/lib/pixel.js +++ b/lib/pixel.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // Defines a set of WS2812 LED Pixels for use @@ -10,41 +10,41 @@ // Pixel grid should be able to: // - Set pixels in a range from X->Y a colour -var ColorString = require("color-string"); // used for color parsing -var events = require("events"); -var util = require("util"); +const ColorString = require('color-string'); // used for color parsing +const events = require('events'); +const util = require('util'); // create a helper to output an int so messages can be shorter -ColorString.colorValue = function colorValue (colors, g_table) { - // colors are assumed to be an array of [r, g, b] bytes - // colorValue returns a packed value able to be pushed to firmata rather than - // text values. - // if gtable is passed then it should use the supplied gamma - // correction table to correct the received value. - - // before sending, account for gamma correction. - colors[0] = g_table[colors[0]]; - colors[1] = g_table[colors[1]]; - colors[2] = g_table[colors[2]]; - - return ((colors[0] << 16) + (colors[1] << 8) + (colors[2])); +ColorString.colorValue = function colorValue(colors, g_table) { + // colors are assumed to be an array of [r, g, b] bytes + // colorValue returns a packed value able to be pushed to firmata rather than + // text values. + // if gtable is passed then it should use the supplied gamma + // correction table to correct the received value. + + // before sending, account for gamma correction. + colors[0] = g_table[colors[0]]; + colors[1] = g_table[colors[1]]; + colors[2] = g_table[colors[2]]; + + return ((colors[0] << 16) + (colors[1] << 8) + (colors[2])); } // CONSTANTS -const START_SYSEX = 0xF0, -STRING_DATA = 0x71, -END_SYSEX = 0xF7, -FIRMATA_7BIT_MASK = 0x7F, -PIXEL_SHIFT_WRAP = 0x40, -PIXEL_COMMAND = 0x51, -PIXEL_OFF = 0x00, -PIXEL_CONFIG = 0x01, -PIXEL_SHOW = 0x02, -PIXEL_SET_PIXEL = 0x03, -PIXEL_SET_STRIP = 0x04, -PIXEL_SHIFT = 0x05, -SHIFT_FORWARD = 0x20, -SHIFT_BACKWARD = 0x00; +const START_SYSEX = 0xF0; +const STRING_DATA = 0x71; +const END_SYSEX = 0xF7; +const FIRMATA_7BIT_MASK = 0x7F; +const PIXEL_SHIFT_WRAP = 0x40; +const PIXEL_COMMAND = 0x51; +const PIXEL_OFF = 0x00; +const PIXEL_CONFIG = 0x01; +const PIXEL_SHOW = 0x02; +const PIXEL_SET_PIXEL = 0x03; +const PIXEL_SET_STRIP = 0x04; +const PIXEL_SHIFT = 0x05; +const SHIFT_FORWARD = 0x20; +const SHIFT_BACKWARD = 0x00; const MAX_STRIPS = 8; @@ -54,732 +54,724 @@ const I2C_DEFAULT = 0x42; const GAMMA_DEFAULT = 1.0; // set to 1.0 in 0.9, 2.8 in 0.10 -var Controllers = { - FIRMATA: { - initialize: { - value: function(opts) { - - var MAX_PIXELS = 216; // based on # bytes available in firmata - var strip_length = opts.length || 6; // just an arbitrary val - var data_pin = opts.data || PIN_DEFAULT; - var color_order = opts.color_order || COLOR_ORDER.GRB; // default GRB - var strip_definition = opts.strips || new Array(); - var skip_firmware_check = !!opts.skip_firmware_check; - // do firmata / IO checks - var firmata = opts.firmata || undefined; - if (firmata == undefined) { - try { - firmata = opts.board.io; - } catch (e) { - if (e instanceof TypeError) { - // there's no board - firmata = undefined; - } - } - } - // check if we're *still* undefined - if (firmata == undefined) { - let err = new Error("A firmata or board object is required"); - err.name = "NoFirmataError"; - throw err; - } - - if (firmata.firmware.name !== 'node_pixel_firmata.ino' && !skip_firmware_check) { - let err = new Error("Please upload NodePixel Firmata to the board"); - err.name = "IncorrectFirmataVersionError"; - throw err; - } - - // figure out where we are writing to - var port = firmata.transport || firmata.sp || firmata; - - if (port.write === undefined) { - let err = new Error("Node Pixel FIRMATA controller requires IO that can write out"); - err.name = "NoWritablePortError"; - throw err; - } - - var gamma = opts.gamma || GAMMA_DEFAULT; // Changing to 2.8 in v0.10 - - // set up the gamma table - var gtable = create_gamma_table(256, gamma, this.dep_warning.gamma); - - - - // work out the map of strips and pixels. - if (typeof(strip_definition[0]) == "undefined") { - // there is nothing specified so it's probably a single strip - // using the length and pin shorthand - strip_definition.push( { - pin: data_pin, - color_order: color_order, - length: strip_length, - }); - } - - // put in check if it's gone over value - if (strip_definition.length > MAX_STRIPS) { - var err = new RangeError("Maximum number of strips " + MAX_STRIPS + " exceeded"); - this.emit("error", err); - } - - var total_length = 0; - strip_definition.forEach(function(data) { - total_length += data.length; - }); - - // put in check if there are too many pixels. - if (total_length > MAX_PIXELS) { - var err = new RangeError("Maximum number of pixels " + MAX_PIXELS + " exceeded"); - this.emit("error", err); - } - - var pixels = []; - - for (var i=0; i< total_length; i++) { - pixels.push(new Pixel({ - addr: i, - firmata: firmata, - port: port, - controller: "FIRMATA", - strip: this, - }) ); - } - - strips.set(this, { - pixels: pixels, - data: data_pin, - firmata: firmata, - port: port, - gtable: gtable, - gamma: gamma, - }); - - // now send the config message with length and data point. - var data = []; - - data[0] = START_SYSEX; - data[1] = PIXEL_COMMAND; - data[2] = PIXEL_CONFIG; - strip_definition.forEach(function(strip) { - data.push( (strip.color_order << 5) | strip.pin); - data.push( strip.length & FIRMATA_7BIT_MASK); - data.push( (strip.length >> 7) & FIRMATA_7BIT_MASK); - }); - data.push(END_SYSEX); - - port.write(new Buffer(data), function(error, res) { - var err = null; - if (error) { - err = error; - this.emit("error", err); - } - // there is a weird bug in OSX which sometimes causes - // a segfault if you try to write to fast. As such - // just delay the ready event by 1msec because even this - // is faster than hooman will perceive as a delay - setTimeout(() => { - this.emit("ready", err); - }, 1); - - }.bind(this) ); - }, - }, - show: { - value: function() { - - // call the frame on the strip. - var strip = strips.get(this); - - var data = []; - data[0] = START_SYSEX; - data[1] = PIXEL_COMMAND; - data[2] = PIXEL_SHOW; - data[3] = END_SYSEX; - - // now just write that to the port and it should show the frame. - strip.port.write(new Buffer(data)); - }, - }, - strip_color: { - value: function(color) { - // colour work is already done this just sets it the appropriate - // way. - var strip = strips.get(this); - var data = []; - - data[0] = START_SYSEX; - data[1] = PIXEL_COMMAND; - data[2] = PIXEL_SET_STRIP; - data[3] = color & FIRMATA_7BIT_MASK; - data[4] = (color >> 7) & FIRMATA_7BIT_MASK; - data[5] = (color >> 14) & FIRMATA_7BIT_MASK; - data[6] = (color >> 21) & FIRMATA_7BIT_MASK; - data[7] = END_SYSEX; - - strip.port.write(new Buffer(data)); - }, - }, - _shift: { - value: function(amt, direction, wrap) { - // shifts the strip in the appropriate direction. - // - let wrap_val = wrap ? PIXEL_SHIFT_WRAP : 0; - let strip = strips.get(this); - let data = []; - data[0] = START_SYSEX; - data[1] = PIXEL_COMMAND; - data[2] = PIXEL_SHIFT; - data[3] = (amt | direction | wrap_val) & FIRMATA_7BIT_MASK; - data[4] = END_SYSEX; - - strip.port.write(new Buffer(data)); - }, - }, +// helper function for building gamma values +function create_gamma_table(steps, gamma, warning) { + // used to build a gamma table for a particular value + + if (! warning && gamma == GAMMA_DEFAULT && ! global.IS_TEST_MODE) { + console.info('INFO: Default gamma behaviour is changing'); + console.info('0.9 - gamma=1.0 - consistent with pre-gamma values'); + console.info('0.10 - gamma=2.8 - default fix for WS2812 LEDs'); + warning = true; + } + + const g_table = new Array(steps); + for (let i = 0; i < steps; i++) { + g_table[i] = Math.floor(Math.pow((i / 255.0), gamma) * 255 + 0.5); + } + + return g_table; +} + +const COLOR_ORDER = { + GRB: 0x00, + RGB: 0x01, + BRG: 0x02 +}; + +const pixels = new WeakMap(); + +const Pixel_Controllers = { + FIRMATA: { + initialize: { + value(opts) { + // initialises the base object + + const pixel = { + address: opts.addr, + id: opts.addr, + color: { + r: 0, g: 0, b: 0, hexcode: '#000000', color: 'black', rgb: [0,0,0] + }, + firmata: opts.firmata, + port: opts.port, + parent: opts.strip + }; + + return pixel; + } }, - I2CBACKPACK: { - initialize: { - value: function(opts) { - - var MAX_PIXELS = 500; // based on # bytes available in firmata - var strip_length = opts.length || 6; // just an arbitrary val - var strip_definition = opts.strips || new Array(); - var color_order = opts.color_order || COLOR_ORDER.GRB; // default GRB - var gamma = opts.gamma || GAMMA_DEFAULT; // Changing to 2.8 in v0.10 - - // set up the gamma table - var gtable = create_gamma_table(256, gamma, this.dep_warning.gamma); - - var io = opts.firmata || opts.board.io; - - if (!opts.address) { - opts.address = I2C_DEFAULT; - } - - if (io == undefined) { - let err = new Error("An IO object is required to I2C controller"); - err.name = "NoIOError"; - throw err; - } - - // work out the map of strips and pixels. - if (typeof(strip_definition[0]) == "undefined") { - // there is nothing specified so it's probably a single strip - // using the length and colour type. - strip_definition.push( { - color_order: color_order, - length: strip_length, - }); - } else if (parseInt(strip_definition[0]) != NaN) { - // we have the array of pin lengths but do we have the colour - - for (var i = 0; i< strip_definition.length; i++) { - var len = strip_definition[i]; - strip_definition[i] = { - color_order: color_order, - length: len, - }; - } - } - - // put in check if it's gone over. - if (strip_definition.length > MAX_STRIPS) { - var err = new RangeError("Maximum number of strips " + MAX_STRIPS + " exceeded"); - this.emit("error", err); - } - - var total_length = 0; - strip_definition.forEach(function(data) { - total_length += data.length; - }); - - // put in check if there are too many pixels. - if (total_length > MAX_PIXELS) { - var err = new RangeError("Maximum number of pixels " + MAX_PIXELS + " exceeded"); - this.emit("error", err); - } - - var pixels = []; - - for (var i=0; i < total_length; i++) { - pixels.push(new Pixel({ - addr: i, - io: io, - controller: "I2CBACKPACK", - i2c_address: opts.address, - strip: this, - }) ); - } - - strips.set(this, { - pixels: pixels, - io: io, - i2c_address: opts.address, - gtable: gtable, - gamma: gamma, - }); - - // now send the config message with length and data point. - var data = []; - - data.push(PIXEL_CONFIG); - strip_definition.forEach(function(strip) { - data.push( (strip.color_order << 5) | strip.pin); - data.push( strip.length & FIRMATA_7BIT_MASK); - data.push( (strip.length >> 7) & FIRMATA_7BIT_MASK); - }); - // send the I2C config message. - io.i2cConfig(opts); - process.nextTick(function() { - try { - io.i2cWrite(opts.address, data); - } catch (e) { - if (e instanceof Error && e.name == "EIO") { - this.emit("np_i2c_write_error", data); - } - } - process.nextTick(function() { - this.emit("ready", null) - }.bind(this) ); - }.bind(this) ); - }, - }, - show: { - value: function() { - var strip = strips.get(this); - try { - strip.io.i2cWrite(strip.i2c_address, [PIXEL_SHOW]); - } catch (e) { - if (e instanceof Error && e.name == "EIO") { - this.emit("np_i2c_write_error", "PIXEL_SHOW"); - } - } - }, - }, - strip_color: { - value: function(color) { - var strip = strips.get(this); - var data = []; - - data[0] = PIXEL_SET_STRIP; - - data[1] = color & FIRMATA_7BIT_MASK; - data[2] = (color >> 7) & FIRMATA_7BIT_MASK; - data[3] = (color >> 14) & FIRMATA_7BIT_MASK; - data[4] = (color >> 21) & FIRMATA_7BIT_MASK; - try { - strip.io.i2cWrite(strip.i2c_address, data); - } catch (e) { - if (e instanceof Error && e.name == "EIO") { - this.emit("np_i2c_write_error", data); - } - } - }, - }, - _shift: { - value: function(amt, direction, wrap) { - // shifts the strip in the appropriate direction. - // - let wrap_val = wrap ? PIXEL_SHIFT_WRAP : 0; - let strip = strips.get(this); - let data = []; - data[0] = PIXEL_SHIFT; - data[1] = (amt | direction | wrap_val) & FIRMATA_7BIT_MASK; - try { - strip.io.i2cWrite(strip.i2c_address, data); - } catch (e) { - if (e instanceof Error && e.name == "EIO") { - this.emit("np_i2c_write_error", data); - } - } - }, - }, + pixel_color: { + value(color) { + // sets the actual pixel colour + const pixel = pixels.get(this); + + const data = []; + + data.push(START_SYSEX); + data.push(PIXEL_COMMAND); + data.push(PIXEL_SET_PIXEL); + data.push(pixel.address & FIRMATA_7BIT_MASK); + data.push((pixel.address >> 7) & FIRMATA_7BIT_MASK); + data.push(color & FIRMATA_7BIT_MASK); + data.push((color >> 7) & FIRMATA_7BIT_MASK); + data.push((color >> 14) & FIRMATA_7BIT_MASK); + data.push((color >> 21) & FIRMATA_7BIT_MASK); + data.push(END_SYSEX); + + pixel.port.write(new Buffer(data)); + } + } + }, + I2CBACKPACK: { + initialize: { + value(opts) { + // initialises the base object + + const pixel = { + address: opts.addr, + id: opts.addr, + color: { + r: 0, g: 0, b: 0, hexcode: '#000000', color: 'black', rgb: [0,0,0] + }, + io: opts.io, + i2c_address: opts.i2c_address, + parent: opts.strip + }; + + return pixel; + } }, + pixel_color: { + value(color) { + // sets the actual pixel colour + const pixel = pixels.get(this); + + const data = []; + + data.push(PIXEL_SET_PIXEL); + data.push(pixel.address & FIRMATA_7BIT_MASK); + data.push((pixel.address >> 7) & FIRMATA_7BIT_MASK); + data.push(color & FIRMATA_7BIT_MASK); + data.push((color >> 7) & FIRMATA_7BIT_MASK); + data.push((color >> 14) & FIRMATA_7BIT_MASK); + data.push((color >> 21) & FIRMATA_7BIT_MASK); + + pixel.io.i2cWrite(pixel.i2c_address, data); + } + } + } }; -// helper function for building gamma values -function create_gamma_table(steps, gamma, warning) { - // used to build a gamma table for a particular value - if (! warning && gamma == GAMMA_DEFAULT && ! global.IS_TEST_MODE) { - console.info("INFO: Default gamma behaviour is changing"); - console.info("0.9 - gamma=1.0 - consistent with pre-gamma values"); - console.info("0.10 - gamma=2.8 - default fix for WS2812 LEDs"); - warning = true; - } +function Pixel(opts) { + if (!(this instanceof Pixel)) { + return new Pixel(opts); + } - var g_table = new Array(steps); - for (let i = 0; i < steps; i++) { - g_table[i] = Math.floor(Math.pow((i / 255.0), gamma) * 255 + 0.5); + // we can assume this is set because the controller is set by the strip. + const controller = Pixel_Controllers[opts.controller]; + + Object.defineProperties(this, controller); + + // we use this to be able to update the address of the + // pixel in the array if we do shift operations. + Object.defineProperty(this, 'address', { + get() { + const pixel = pixels.get(this); + return pixel.address; + }, + set(newAddress) { + const pixel = pixels.get(this); + pixel.address = newAddress; } + }); - return g_table; + pixels.set(this, this.initialize(opts)); } -var strips = new WeakMap(); - -function Strip(opts) { +Pixel.prototype.off = Pixel.prototype.clear = function() { + // sets the pixel value to [0, 0, 0]. Equivalent to calling + // `strip.off()` but for an individual pixel. + this.color([0, 0, 0]); +} - // opts contains an object with. - // data: data pin for the pixel strip // DEPRECATED will be phased out. - // length: length of the pixel strip. // DEPRECATED, will be phased out. - // board: johnny five board object. - // controller: controller type to use - // firmata: actual firmata object if using firmata - // stripShape: an array that contains lengths or optionally data pins and - // lengths for each of them. - // eg: [ [6, 30], [12, 20], [7, 10] ] which would be 3 strips attached - // to pins 6, 12 and 7 and make a strip 60 pixels long. - // Otherwise [ 30, 20, 10 ] which would be 3 strips on PORTD 0-2 but - // still a strip 60 pixels long - // gamma: A user specified value for gamma correction for the strip. - // default is 1.0 but will be changed to 2.8 over versions - - if (!(this instanceof Strip)) { - return new Strip(opts); +Pixel.prototype.colour = Pixel.prototype.color = function(color, opts) { + // use a particular form to set the color either + // color = hex value or named colors or array of colors + // opts can contain _sendmsg_ as bool. If set to false message won't be + // sent to firmata - useful for strip level updates to keep message choke down + + const pixel = pixels.get(this); + + const options = opts || {}; + let sendmsg = true; + if (options.sendmsg != undefined) { sendmsg = options.sendmsg; } + + let pixelcolor = null; + + if (color) { + // get the color based on a string + if (typeof(color) === 'object') { + // we have an RGB array value + pixelcolor = { + model: 'rgb', + value: color + }; + } else { + pixelcolor = ColorString.get(color); + } + } else { + return pixel.color; + } + + if (pixelcolor != null) { + // fill out the values for the pixel and then send the message to update + // it on the strip + + pixel.color.r = pixelcolor.value[0]; + pixel.color.g = pixelcolor.value[1]; + pixel.color.b = pixelcolor.value[2]; + pixel.color.hexcode = ColorString.to.hex(pixelcolor.value); + pixel.color.color = ColorString.to.keyword(pixelcolor.value); + if (pixelcolor.value.length == 4) { + pixelcolor.value.pop(); } + pixel.color.rgb = pixelcolor.value; - var controller; - if (typeof opts.controller === "string") { - controller = Controllers[opts.controller]; - } else { - controller = opts.controller || Controllers["FIRMATA"]; + // console.log(pixel.parent.gtable); + color = ColorString.colorValue(pixelcolor.value, pixel.parent.gtable); + if (sendmsg) { + // TODO probably should be pulling the color off the obj rather than + // sending it to this function.... + this.pixel_color(color); } + } else { + console.log("Color supplied couldn't be parsed: " + color); + } +}; - this.dep_warning = { - stripLength: false, - gammaValue: (! typeof opts.gamma === 'undefined'), - }; +const strips = new WeakMap(); + +const Controllers = { + FIRMATA: { + initialize: { + value(opts) { + const MAX_PIXELS = 216; // based on # bytes available in firmata + const strip_length = opts.length || 6; // just an arbitrary val + const data_pin = opts.data || PIN_DEFAULT; + const color_order = opts.color_order || COLOR_ORDER.GRB; // default GRB + const strip_definition = opts.strips || new Array(); + const skip_firmware_check = !!opts.skip_firmware_check; + // do firmata / IO checks + let firmata = opts.firmata || undefined; + if (firmata == undefined) { + try { + firmata = opts.board.io; + } catch (e) { + if (e instanceof TypeError) { + // there's no board + firmata = undefined; + } + } + } + // check if we're *still* undefined + if (firmata == undefined) { + const err = new Error('A firmata or board object is required'); + err.name = 'NoFirmataError'; + throw err; + } - Object.defineProperties(this, controller); + if (firmata.firmware.name !== 'node_pixel_firmata.ino' && !skip_firmware_check) { + const err = new Error('Please upload NodePixel Firmata to the board'); + err.name = 'IncorrectFirmataVersionError'; + throw err; + } - Object.defineProperty(this, 'length', { - get: function() { - let strip = strips.get(this); - return strip.pixels.length; - }, - }); + // figure out where we are writing to + const port = firmata.transport || firmata.sp || firmata; - Object.defineProperty(this, 'gamma', { - get: function() { - let strip = strips.get(this); - return strip.gamma; - }, - }); + if (port.write === undefined) { + const err = new Error('Node Pixel FIRMATA controller requires IO that can write out'); + err.name = 'NoWritablePortError'; + throw err; + } - Object.defineProperty(this, 'gtable', { - get: function() { - let strip = strips.get(this); - return strip.gtable; - }, - }); + const gamma = opts.gamma || GAMMA_DEFAULT; // Changing to 2.8 in v0.10 - if (typeof this.initialize === "function") { - this.initialize(opts); - } -} + // set up the gamma table + const gtable = create_gamma_table(256, gamma, this.dep_warning.gamma); -util.inherits(Strip, events.EventEmitter); -Strip.prototype.pixel = function(addr) { - var strip = strips.get(this); + // work out the map of strips and pixels. + if (typeof(strip_definition[0]) == 'undefined') { + // there is nothing specified so it's probably a single strip + // using the length and pin shorthand + strip_definition.push( { + pin: data_pin, + color_order, + length: strip_length + }); + } - return strip.pixels[addr]; -}; + // put in check if it's gone over value + if (strip_definition.length > MAX_STRIPS) { + const err = new RangeError('Maximum number of strips ' + MAX_STRIPS + ' exceeded'); + this.emit('error', err); + } -Strip.prototype.colour = Strip.prototype.color = function(color, opts) { - // sets the color of the entire strip - // use a particular form to set the color either - // color = hex value or named colors - // or set color null and set opt which is an object as {rgb: [rx, gx, bx]} - // values where x is an 8-bit value (0-255); - var strip = strips.get(this); - - var stripcolor = null; - - if (color) { - // use text to determine the color - if(typeof(color) === "object") { - // we have an RGB array value - stripcolor = color; - } else { - try { - stripcolor = ColorString.get(color).value; - } catch (e) { - if (e instanceof TypeError && ColorString.get(color) === null ) { - stripcolor = null; - } - } + let total_length = 0; + strip_definition.forEach(function(data) { + total_length += data.length; + }); + + // put in check if there are too many pixels. + if (total_length > MAX_PIXELS) { + const err = new RangeError('Maximum number of pixels ' + MAX_PIXELS + ' exceeded'); + this.emit('error', err); } - } - if (stripcolor != null) { - // fill out the values for the pixels and then update the strip + const pixel_list = []; - for (var i = 0; i < strip.pixels.length; i++) { - strip.pixels[i].color(color, {sendmsg: false}); + for (let i=0; i< total_length; i++) { + pixel_list.push(new Pixel({ + addr: i, + firmata, + port, + controller: 'FIRMATA', + strip: this + }) ); } - // set the whole strip color to the appropriate int value - this.strip_color(ColorString.colorValue(stripcolor, strip.gtable)); + strips.set(this, { + pixels: pixel_list, + data: data_pin, + firmata, + port, + gtable, + gamma + }); - } else { - console.log("Supplied colour couldn't be parsed: " + color); + // now send the config message with length and data point. + const data = []; + + data[0] = START_SYSEX; + data[1] = PIXEL_COMMAND; + data[2] = PIXEL_CONFIG; + strip_definition.forEach(function(strip) { + data.push( (strip.color_order << 5) | strip.pin); + data.push( strip.length & FIRMATA_7BIT_MASK); + data.push( (strip.length >> 7) & FIRMATA_7BIT_MASK); + }); + data.push(END_SYSEX); + + port.write(new Buffer(data), function(error, res) { + let err = null; + if (error) { + err = error; + this.emit('error', err); + } + // there is a weird bug in OSX which sometimes causes + // a segfault if you try to write to fast. As such + // just delay the ready event by 1msec because even this + // is faster than hooman will perceive as a delay + setTimeout(() => { + this.emit('ready', err); + }, 1); + }.bind(this) ); + } + }, + show: { + value() { + // call the frame on the strip. + const strip = strips.get(this); + + const data = []; + data[0] = START_SYSEX; + data[1] = PIXEL_COMMAND; + data[2] = PIXEL_SHOW; + data[3] = END_SYSEX; + + // now just write that to the port and it should show the frame. + strip.port.write(new Buffer(data)); + } + }, + strip_color: { + value(color) { + // colour work is already done this just sets it the appropriate + // way. + const strip = strips.get(this); + const data = []; + + data[0] = START_SYSEX; + data[1] = PIXEL_COMMAND; + data[2] = PIXEL_SET_STRIP; + data[3] = color & FIRMATA_7BIT_MASK; + data[4] = (color >> 7) & FIRMATA_7BIT_MASK; + data[5] = (color >> 14) & FIRMATA_7BIT_MASK; + data[6] = (color >> 21) & FIRMATA_7BIT_MASK; + data[7] = END_SYSEX; + + strip.port.write(new Buffer(data)); + } + }, + _shift: { + value(amt, direction, wrap) { + // shifts the strip in the appropriate direction. + // + const wrap_val = wrap ? PIXEL_SHIFT_WRAP : 0; + const strip = strips.get(this); + const data = []; + data[0] = START_SYSEX; + data[1] = PIXEL_COMMAND; + data[2] = PIXEL_SHIFT; + data[3] = (amt | direction | wrap_val) & FIRMATA_7BIT_MASK; + data[4] = END_SYSEX; + + strip.port.write(new Buffer(data)); + } } -} + }, + I2CBACKPACK: { + initialize: { + value(opts) { + const MAX_PIXELS = 500; // based on # bytes available in firmata + const strip_length = opts.length || 6; // just an arbitrary val + const strip_definition = opts.strips || new Array(); + const color_order = opts.color_order || COLOR_ORDER.GRB; // default GRB + const gamma = opts.gamma || GAMMA_DEFAULT; // Changing to 2.8 in v0.10 + + // set up the gamma table + const gtable = create_gamma_table(256, gamma, this.dep_warning.gamma); + + const io = opts.firmata || opts.board.io; + + if (!opts.address) { + opts.address = I2C_DEFAULT; + } -Strip.prototype.off = Strip.prototype.clear = function() { - // sets the strip to 'black', effectively setting it to 'off' - this.color([0, 0, 0]); - this.show(); -}; + if (io == undefined) { + const err = new Error('An IO object is required to I2C controller'); + err.name = 'NoIOError'; + throw err; + } -Strip.prototype.shift = function(amt, direction, wrap) { - // public version of the shift function independent of the controller. - // this looks after the actual internal shifting of the pixels within the - // js side and then calls the controller to mirror the same function. + // work out the map of strips and pixels. + if (typeof(strip_definition[0]) == 'undefined') { + // there is nothing specified so it's probably a single strip + // using the length and colour type. + strip_definition.push( { + color_order, + length: strip_length + }); + } else if (parseInt(strip_definition[0], 10) != NaN) { + // we have the array of pin lengths but do we have the colour + + for (let i = 0; i< strip_definition.length; i++) { + const len = strip_definition[i]; + strip_definition[i] = { + color_order, + length: len + }; + } + } - if (amt > 0) { + // put in check if it's gone over. + if (strip_definition.length > MAX_STRIPS) { + const err = new RangeError('Maximum number of strips ' + MAX_STRIPS + ' exceeded'); + this.emit('error', err); + } - let strip = strips.get(this); + let total_length = 0; + strip_definition.forEach(function(data) { + total_length += data.length; + }); - // take a copy of the pixels at the end that is being towards - let start_element = 0; - if (direction == SHIFT_FORWARD) { - start_element = this.length - amt; + // put in check if there are too many pixels. + if (total_length > MAX_PIXELS) { + const err = new RangeError('Maximum number of pixels ' + MAX_PIXELS + ' exceeded'); + this.emit('error', err); } - let tmp_pixels = strip.pixels.splice(start_element, amt); - while (tmp_pixels.length > 0) { - let px = tmp_pixels.pop(); - - // set the pixel off if not wrapping. - if (! wrap) { - px.color("#000"); - } + const pixel_list = []; - if (direction == SHIFT_FORWARD) { - strip.pixels.unshift(px); - } else { - strip.pixels.push(px); - } + for (let i=0; i < total_length; i++) { + pixel_list.push(new Pixel({ + addr: i, + io, + controller: 'I2CBACKPACK', + i2c_address: opts.address, + strip: this + }) ); } - // renumber the items so the addresses are correct for display - strip.pixels.forEach((px, index) => { - px.address = index; + strips.set(this, { + pixels: pixel_list, + io, + i2c_address: opts.address, + gtable, + gamma }); - // now get the firmware to update appropriately as well. - this._shift(amt, direction, wrap); + // now send the config message with length and data point. + const data = []; + + data.push(PIXEL_CONFIG); + strip_definition.forEach(function(strip) { + data.push( (strip.color_order << 5) | strip.pin); + data.push( strip.length & FIRMATA_7BIT_MASK); + data.push( (strip.length >> 7) & FIRMATA_7BIT_MASK); + }); + // send the I2C config message. + io.i2cConfig(opts); + process.nextTick(function() { + try { + io.i2cWrite(opts.address, data); + } catch (e) { + if (e instanceof Error && e.name == 'EIO') { + this.emit('np_i2c_write_error', data); + } + } + process.nextTick(function() { + this.emit('ready', null) + }.bind(this) ); + }.bind(this) ); + } + }, + show: { + value() { + const strip = strips.get(this); + try { + strip.io.i2cWrite(strip.i2c_address, [PIXEL_SHOW]); + } catch (e) { + if (e instanceof Error && e.name == 'EIO') { + this.emit('np_i2c_write_error', 'PIXEL_SHOW'); + } + } + } + }, + strip_color: { + value(color) { + const strip = strips.get(this); + const data = []; + + data[0] = PIXEL_SET_STRIP; + + data[1] = color & FIRMATA_7BIT_MASK; + data[2] = (color >> 7) & FIRMATA_7BIT_MASK; + data[3] = (color >> 14) & FIRMATA_7BIT_MASK; + data[4] = (color >> 21) & FIRMATA_7BIT_MASK; + try { + strip.io.i2cWrite(strip.i2c_address, data); + } catch (e) { + if (e instanceof Error && e.name == 'EIO') { + this.emit('np_i2c_write_error', data); + } + } + } + }, + _shift: { + value(amt, direction, wrap) { + // shifts the strip in the appropriate direction. + // + const wrap_val = wrap ? PIXEL_SHIFT_WRAP : 0; + const strip = strips.get(this); + const data = []; + data[0] = PIXEL_SHIFT; + data[1] = (amt | direction | wrap_val) & FIRMATA_7BIT_MASK; + try { + strip.io.i2cWrite(strip.i2c_address, data); + } catch (e) { + if (e instanceof Error && e.name == 'EIO') { + this.emit('np_i2c_write_error', data); + } + } + } } + } }; -Strip.prototype.stripLength = function() { - // gets the number of pixels in the strip - let strip = strips.get(this); +function Strip(opts) { + // opts contains an object with. + // data: data pin for the pixel strip // DEPRECATED will be phased out. + // length: length of the pixel strip. // DEPRECATED, will be phased out. + // board: johnny five board object. + // controller: controller type to use + // firmata: actual firmata object if using firmata + // stripShape: an array that contains lengths or optionally data pins and + // lengths for each of them. + // eg: [ [6, 30], [12, 20], [7, 10] ] which would be 3 strips attached + // to pins 6, 12 and 7 and make a strip 60 pixels long. + // Otherwise [ 30, 20, 10 ] which would be 3 strips on PORTD 0-2 but + // still a strip 60 pixels long + // gamma: A user specified value for gamma correction for the strip. + // default is 1.0 but will be changed to 2.8 over versions + + if (!(this instanceof Strip)) { + return new Strip(opts); + } + + let controller; + + if (typeof opts.controller === 'string') { + controller = Controllers[opts.controller]; + } else { + controller = opts.controller || Controllers['FIRMATA']; + } + + this.dep_warning = { + stripLength: false, + gammaValue: (! typeof opts.gamma === 'undefined') + }; + + Object.defineProperties(this, controller); + + Object.defineProperty(this, 'length', { + get() { + const strip = strips.get(this); + return strip.pixels.length; + } + }); - if (! this.dep_warning.stripLength) { - console.info("ERROR: strip.stripLength() is deprecated in favour of strip.length"); - console.info("0.8 - notice"); - console.info("0.9 - error"); - console.info("0.10 - removal"); - this.dep_warning.stripLength = true; + Object.defineProperty(this, 'gamma', { + get() { + const strip = strips.get(this); + return strip.gamma; } + }); - throw new Error({ - name: "NotImplemented", - message: "stripLength is no longer supported, use strip.length", - toString: function() { return "NotImplemented: stripLength is no longer supported" }, - }); -}; + Object.defineProperty(this, 'gtable', { + get() { + const strip = strips.get(this); + return strip.gtable; + } + }); -var pixels = new WeakMap(); + if (typeof this.initialize === 'function') { + this.initialize(opts); + } +} -// controllers for the pixel side as well. -var Pixel_Controllers = { - FIRMATA: { - initialize: { - value: function(opts) { - // initialises the base object - - var pixel = { - address: opts.addr, - id: opts.addr, - color: { - r: 0, g: 0, b: 0, hexcode: "#000000", color: "black", rgb: [0,0,0], - }, - firmata: opts.firmata, - port: opts.port, - parent: opts.strip, - }; - - return pixel; - }, - }, - pixel_color: { - value: function(color) { - // sets the actual pixel colour - var pixel = pixels.get(this); - - var data = []; - - data.push(START_SYSEX); - data.push(PIXEL_COMMAND); - data.push(PIXEL_SET_PIXEL); - data.push(pixel.address & FIRMATA_7BIT_MASK); - data.push((pixel.address >> 7) & FIRMATA_7BIT_MASK); - data.push(color & FIRMATA_7BIT_MASK); - data.push((color >> 7) & FIRMATA_7BIT_MASK); - data.push((color >> 14) & FIRMATA_7BIT_MASK); - data.push((color >> 21) & FIRMATA_7BIT_MASK); - data.push(END_SYSEX); - - pixel.port.write(new Buffer(data)); - }, - }, - }, - I2CBACKPACK: { - initialize: { - value: function(opts) { - // initialises the base object - - var pixel = { - address: opts.addr, - id: opts.addr, - color: { - r: 0, g: 0, b: 0, hexcode: "#000000", color: "black", rgb: [0,0,0], - }, - io: opts.io, - i2c_address: opts.i2c_address, - parent: opts.strip - }; - - return pixel; - }, - }, - pixel_color: { - value: function(color) { - // sets the actual pixel colour - var pixel = pixels.get(this); - - var data = []; - - data.push(PIXEL_SET_PIXEL); - data.push(pixel.address & FIRMATA_7BIT_MASK); - data.push((pixel.address >> 7) & FIRMATA_7BIT_MASK); - data.push(color & FIRMATA_7BIT_MASK); - data.push((color >> 7) & FIRMATA_7BIT_MASK); - data.push((color >> 14) & FIRMATA_7BIT_MASK); - data.push((color >> 21) & FIRMATA_7BIT_MASK); - - pixel.io.i2cWrite(pixel.i2c_address, data); - }, - }, - }, -}; +util.inherits(Strip, events.EventEmitter); +Strip.prototype.pixel = function(addr) { + const strip = strips.get(this); -function Pixel(opts) { + return strip.pixels[addr]; +}; - if (!(this instanceof Pixel)) { - return new Pixel(opts); +Strip.prototype.colour = Strip.prototype.color = function(color, opts) { + // sets the color of the entire strip + // use a particular form to set the color either + // color = hex value or named colors + // or set color null and set opt which is an object as {rgb: [rx, gx, bx]} + // values where x is an 8-bit value (0-255); + const strip = strips.get(this); + + let stripcolor = null; + + if (color) { + // use text to determine the color + if (typeof(color) === 'object') { + // we have an RGB array value + stripcolor = color; + } else { + try { + stripcolor = ColorString.get(color).value; + } catch (e) { + if (e instanceof TypeError && ColorString.get(color) === null ) { + stripcolor = null; + } + } } + } - // we can assume this is set because the controller is set by the strip. - var controller = Pixel_Controllers[opts.controller]; - - Object.defineProperties(this, controller); - - // we use this to be able to update the address of the - // pixel in the array if we do shift operations. - Object.defineProperty(this, 'address', { - get: function() { - let pixel = pixels.get(this); - return pixel.address; - }, - set: function(newAddress) { - let pixel = pixels.get(this); - pixel.address = newAddress; - }, - }); + if (stripcolor != null) { + // fill out the values for the pixels and then update the strip - pixels.set(this, this.initialize(opts)); -} + for (let i = 0; i < strip.pixels.length; i++) { + strip.pixels[i].color(color, {sendmsg: false}); + } -Pixel.prototype.off = Pixel.prototype.clear = function () { - // sets the pixel value to [0, 0, 0]. Equivalent to calling - // `strip.off()` but for an individual pixel. - this.color([0, 0, 0]); + // set the whole strip color to the appropriate int value + this.strip_color(ColorString.colorValue(stripcolor, strip.gtable)); + } else { + console.log("Supplied colour couldn't be parsed: " + color); + } } -Pixel.prototype.colour = Pixel.prototype.color = function(color, opts) { - // use a particular form to set the color either - // color = hex value or named colors or array of colors - // opts can contain _sendmsg_ as bool. If set to false message won't be - // sent to firmata - useful for strip level updates to keep message choke down - - var pixel = pixels.get(this); - - var options = opts || {}; - var sendmsg = true; - if (options.sendmsg != undefined) { sendmsg = options.sendmsg; } - - var pixelcolor = null; - - if (color) { - // get the color based on a string - if(typeof(color) === "object") { - // we have an RGB array value - pixelcolor = { - model: 'rgb', - value: color - }; - } else { - pixelcolor = ColorString.get(color); - } - } else { - return pixel.color; +Strip.prototype.off = Strip.prototype.clear = function() { + // sets the strip to 'black', effectively setting it to 'off' + this.color([0, 0, 0]); + this.show(); +}; + +Strip.prototype.shift = function(amt, direction, wrap) { + // public version of the shift function independent of the controller. + // this looks after the actual internal shifting of the pixels within the + // js side and then calls the controller to mirror the same function. + + if (amt > 0) { + const strip = strips.get(this); + + // take a copy of the pixels at the end that is being towards + let start_element = 0; + if (direction == SHIFT_FORWARD) { + start_element = this.length - amt; } + const tmp_pixels = strip.pixels.splice(start_element, amt); - if (pixelcolor != null) { - // fill out the values for the pixel and then send the message to update - // it on the strip - - pixel.color.r = pixelcolor.value[0]; - pixel.color.g = pixelcolor.value[1]; - pixel.color.b = pixelcolor.value[2]; - pixel.color.hexcode = ColorString.to.hex(pixelcolor.value); - pixel.color.color = ColorString.to.keyword(pixelcolor.value); - if (pixelcolor.value.length == 4) { - pixelcolor.value.pop(); - } - pixel.color.rgb = pixelcolor.value; + while (tmp_pixels.length > 0) { + const px = tmp_pixels.pop(); + // set the pixel off if not wrapping. + if (! wrap) { + px.color('#000'); + } - //console.log(pixel.parent.gtable); - color = ColorString.colorValue(pixelcolor.value, pixel.parent.gtable); - if (sendmsg) { - // TODO probably should be pulling the color off the obj rather than - // sending it to this function.... - this.pixel_color(color); - } - } else { - console.log("Color supplied couldn't be parsed: " + color); + if (direction == SHIFT_FORWARD) { + strip.pixels.unshift(px); + } else { + strip.pixels.push(px); + } } + + // renumber the items so the addresses are correct for display + strip.pixels.forEach((px, index) => { + px.address = index; + }); + + // now get the firmware to update appropriately as well. + this._shift(amt, direction, wrap); + } }; -var COLOR_ORDER = { - GRB: 0x00, - RGB: 0x01, - BRG: 0x02, +Strip.prototype.stripLength = function() { + // gets the number of pixels in the strip + + const strip = strips.get(this); + + if (! this.dep_warning.stripLength) { + console.info('ERROR: strip.stripLength() is deprecated in favour of strip.length'); + console.info('0.8 - notice'); + console.info('0.9 - error'); + console.info('0.10 - removal'); + this.dep_warning.stripLength = true; + } + + throw new Error({ + name: 'NotImplemented', + message: 'stripLength is no longer supported, use strip.length', + toString() { return 'NotImplemented: stripLength is no longer supported' } + }); }; +// controllers for the pixel side as well. module.exports = { - Strip: Strip, - COLOR_ORDER: COLOR_ORDER, - FORWARD: SHIFT_FORWARD, - BACKWARD: SHIFT_BACKWARD, + Strip, + COLOR_ORDER, + FORWARD: SHIFT_FORWARD, + BACKWARD: SHIFT_BACKWARD }; diff --git a/package-lock.json b/package-lock.json index 783852a..a70a6bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -123,6 +123,47 @@ "to-fast-properties": "^2.0.0" } }, + "@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, "@serialport/binding-abstract": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-8.0.6.tgz", @@ -293,6 +334,18 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, "add-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", @@ -318,6 +371,12 @@ "dev": true, "optional": true }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -431,6 +490,12 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -580,6 +645,12 @@ "write-file-atomic": "^2.4.2" } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -1253,6 +1324,15 @@ "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -1310,6 +1390,15 @@ "once": "^1.4.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1360,18 +1449,287 @@ } } }, + "eslint": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.10.0.tgz", + "integrity": "sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, "esm": { "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "dev": true }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", @@ -1436,6 +1794,15 @@ "escape-string-regexp": "^1.0.5" } }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -1481,6 +1848,48 @@ "dev": true, "optional": true }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", @@ -1542,6 +1951,12 @@ "integrity": "sha512-Iw4MzMfS3udk/rqxTiDDCllhGwlOrsr50zViTOO/W6lS/9y6B1J0BD2VZzrnWUYBJsl3aeqjgR5v7bWWhZSYbA==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -1994,6 +2409,15 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2101,6 +2525,22 @@ "dev": true, "optional": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2146,6 +2586,12 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-finite": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", @@ -2162,6 +2608,15 @@ "number-is-nan": "^1.0.0" } }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -2414,6 +2869,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -2873,6 +3334,12 @@ "dev": true, "optional": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -3129,6 +3596,15 @@ "release-zalgo": "^1.0.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-github-repo-url": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", @@ -3157,6 +3633,12 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", @@ -3269,6 +3751,12 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3392,6 +3880,12 @@ "strip-indent": "^3.0.0" } }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -3530,6 +4024,21 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "shelljs": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", @@ -3628,6 +4137,25 @@ } } }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", @@ -4037,6 +4565,52 @@ "has-flag": "^1.0.0" } }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "tap": { "version": "12.7.0", "resolved": "https://registry.npmjs.org/tap/-/tap-12.7.0.tgz", @@ -4246,6 +4820,12 @@ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -4423,6 +5003,12 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -4539,6 +5125,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/package.json b/package.json index b5cec5b..c6369e8 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "test": "IS_TEST_MODE=true ./node_modules/.bin/nodeunit test/*", "test-cover": "IS_TEST_MODE=true istanbul cover ./node_modules/.bin/nodeunit test/*", "coveralls": "cat ./coverage/lcov.info | coveralls", - "release": "standard-version" + "release": "standard-version", + "lint": "./node_modules/.bin/eslint ." }, "repository": { "type": "git", @@ -46,13 +47,14 @@ "johnny-five": "^2.0.0" }, "devDependencies": { - "standard-version": "^9.0.0", "board-io": "^3.0.4", "coveralls": "^3.1.0", + "eslint": "^7.10.0", "istanbul": "^0.4.5", "johnny-five": "^2.0.0", "mock-firmata": "0.2.0", "nodeunit": "^0.11.3", - "sinon": "^9.1.0" + "sinon": "^9.1.0", + "standard-version": "^9.0.0" } } diff --git a/test/core.js b/test/core.js index 9f94015..e55fd79 100644 --- a/test/core.js +++ b/test/core.js @@ -1,362 +1,360 @@ global.IS_TEST_MODE = true; -var mocks = require("mock-firmata"); -var MockFirmata = mocks.Firmata; -var MockSerialPort = mocks.SerialPort; +const mocks = require('mock-firmata'); +const MockFirmata = mocks.Firmata; +const MockSerialPort = mocks.SerialPort; -var sinon = require("sinon"); +const sinon = require('sinon'); -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var Board = five.Board; +const Board = five.Board; function newBoard() { - var sp = new MockSerialPort("/dev/test"); - var io = new MockFirmata(sp); - io["firmware"] = { name: "node_pixel_firmata.ino", }; + const sp = new MockSerialPort('/dev/test'); + const io = new MockFirmata(sp); + io['firmware'] = { name: 'node_pixel_firmata.ino' }; - io.emit("connect"); - io.emit("ready"); + io.emit('connect'); + io.emit('ready'); - var board = new Board({ - io: io, - debug: false, - repl: false, - }); + const board = new Board({ + io, + debug: false, + repl: false + }); - return board; + return board; } function restore(target) { - for (var prop in target) { - - if (Array.isArray(target[prop])) { - continue; - } + for (const prop in target) { + if (Array.isArray(target[prop])) { + continue; + } - if (target[prop] != null && typeof target[prop].restore === "function") { - target[prop].restore(); - } + if (target[prop] != null && typeof target[prop].restore === 'function') { + target[prop].restore(); + } - if (typeof target[prop] === "object") { - restore(target[prop]); - } + if (typeof target[prop] === 'object') { + restore(target[prop]); } + } } -exports["Test Mode configured"] = { - setUp: function(done) { - done(); - }, - - tearDown: function(done) { - done(); - }, - - testMode: function(test) { - // tests that the env variable is set properly - test.expect(1); - test.equal(process.env.IS_TEST_MODE, 'true', "Test mode should be configured"); - test.done(); - }, +exports['Test Mode configured'] = { + setUp(done) { + done(); + }, + + tearDown(done) { + done(); + }, + + testMode(test) { + // tests that the env variable is set properly + test.expect(1); + test.equal(process.env.IS_TEST_MODE, 'true', 'Test mode should be configured'); + test.done(); + } }; -exports["Strip"] = { - // used for the main strip tests. - setUp: function(done) { - this.board = newBoard(); - this.strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - controller: "FIRMATA", - }); - done(); - }, +exports['Strip'] = { + // used for the main strip tests. + setUp(done) { + this.board = newBoard(); + this.strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board, + controller: 'FIRMATA' + }); + done(); + }, + + tearDown(done) { + Board.purge(); + restore(this); + done(); + }, + + length(test) { + // tests length of the strip properly. + test.expect(3); + + const strip = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [{pin: 2, length: 100}] + }); + test.equal(strip.length, 100, 'Single strip length should be equal to provided length'); - tearDown: function(done) { - Board.purge(); - restore(this); - done(); - }, + const strip2 = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [{pin: 2, length: 50}, {pin: 3, length: 50}] + }); + test.equal(strip2.length, 100, 'Multiple strips length should be equal to sum of lengths'); - length: function(test) { - // tests length of the strip properly. - test.expect(3); - - var strip = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [{pin: 2, length: 100}] - }); - test.equal(strip.length, 100, "Single strip length should be equal to provided length"); - - var strip2 = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [{pin: 2, length: 50}, {pin: 3, length: 50}] - }); - test.equal(strip2.length, 100, "Multiple strips length should be equal to sum of lengths"); - - var strip3 = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - pin: 3, - length: 150, - }); - - test.throws(() => { - strip3.stripLength() - }, - /NotImplemented/, - "Deprecated stripLength() should throw NotImplemented error"); - - test.done(); - }, + const strip3 = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + pin: 3, + length: 150 + }); - colour: function(test) { - // tests if the colour sequences are working okay - test.expect(4); - - var colourcheck = { - r: 255, g: 255, b: 255, - hexcode: "#FFFFFF", - color: "white", - rgb: [255, 255, 255], - }; - - this.strip.color("#FFFFFF"); - test.deepEqual(this.strip.pixel(0).color(), colourcheck, - "If colour is set with full hex colour, colour object should be updated"); - - colourcheck = { - r: 0, g: 255, b: 0, - hexcode: "#00FF00", - color: "lime", - rgb: [0, 255, 0], - }; - - this.strip.color([0, 255, 0]); - test.deepEqual(this.strip.pixel(3).color(), colourcheck, - "If setting colour by RGB array, the colour object should be updated"); - - test.doesNotThrow( - () => { - this.strip.colour("QWERTYUIOP"); - }, - undefined, - "An invalid color should be ignored not throw an error" - ); - - test.doesNotThrow( - () => { - this.strip.color(); - }, - undefined, - "When no colour is provided it should be ignored and not throw an error" - ); - - test.done(); + test.throws(() => { + strip3.stripLength() }, + /NotImplemented/, + 'Deprecated stripLength() should throw NotImplemented error'); + + test.done(); + }, + + colour(test) { + // tests if the colour sequences are working okay + test.expect(4); + + let colourcheck = { + r: 255, g: 255, b: 255, + hexcode: '#FFFFFF', + color: 'white', + rgb: [255, 255, 255] + }; + + this.strip.color('#FFFFFF'); + test.deepEqual(this.strip.pixel(0).color(), colourcheck, + 'If colour is set with full hex colour, colour object should be updated'); + + colourcheck = { + r: 0, g: 255, b: 0, + hexcode: '#00FF00', + color: 'lime', + rgb: [0, 255, 0] + }; + + this.strip.color([0, 255, 0]); + test.deepEqual(this.strip.pixel(3).color(), colourcheck, + 'If setting colour by RGB array, the colour object should be updated'); + + test.doesNotThrow( + () => { + this.strip.colour('QWERTYUIOP'); + }, + undefined, + 'An invalid color should be ignored not throw an error' + ); + + test.doesNotThrow( + () => { + this.strip.color(); + }, + undefined, + 'When no colour is provided it should be ignored and not throw an error' + ); + + test.done(); + }, + + off(test) { + // tests if setting strip off results in black pixel colour + test.expect(1); + + this.strip.color('#FF0000'); + + const colourcheck = { + r: 0, g: 0, b: 0, + hexcode: '#000000', + color: 'black', + rgb: [0, 0, 0] + }; + + this.strip.off(); + test.deepEqual(this.strip.pixel(0).color(), colourcheck, + 'If setting a colour then turning the strip off, the colour should revert to off state.'); + test.done(); + }, + + gamma(test) { + // tests if setting the gamma works as expected + test.expect(4); + + // test gamma being set + const strip = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [{pin: 2, length: 1}], + gamma: 2.3 + }); + test.equal(strip.gamma, 2.3, + 'If setting gamma in constructor, the gamma value should be retained'); - off: function(test) { - // tests if setting strip off results in black pixel colour - test.expect(1); - - this.strip.color("#FF0000"); + test.equal(strip.gtable.length, 256, + 'If setting gamma in constructor, the Gamma Table should be built'); - var colourcheck = { - r: 0, g: 0, b: 0, - hexcode: "#000000", - color: "black", - rgb: [0, 0, 0], - }; + test.equal(strip.gtable[18], 1, + 'If setting gamma, the gamma table values should be built correctly'); - this.strip.off(); - test.deepEqual(this.strip.pixel(0).color(), colourcheck, - "If setting a colour then turning the strip off, the colour should revert to off state."); - test.done(); - }, + // now check that a non gamma returns the right values + const strip2 = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [{pin: 2, length: 1}] + }); - gamma: function(test) { - // tests if setting the gamma works as expected - test.expect(4); - - // test gamma being set - var strip = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [{pin: 2, length: 1}], - gamma: 2.3 - }); - test.equal(strip.gamma, 2.3, - "If setting gamma in constructor, the gamma value should be retained"); - - test.equal(strip.gtable.length, 256, - "If setting gamma in constructor, the Gamma Table should be built"); - - test.equal(strip.gtable[18], 1, - "If setting gamma, the gamma table values should be built correctly"); - - // now check that a non gamma returns the right values - var strip2 = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [{pin: 2, length: 1}], - }); - - test.equal(strip2.gtable[18], 18, - "If gamma is not set, the gamma values should be built using default"); - - test.done(); - }, + test.equal(strip2.gtable[18], 18, + 'If gamma is not set, the gamma values should be built using default'); - shift: function(test) { - // tests that wrapping behaviour is consistent + test.done(); + }, - test.expect(12); + shift(test) { + // tests that wrapping behaviour is consistent - var strip = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [{ pin: 2, length: 8}], - }); + test.expect(12); - // set up a pixel on either end of the strip - // in preparation for movement. - strip.pixel(1).color("red"); - strip.pixel(6).color("blue"); + const strip = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [{ pin: 2, length: 8}] + }); - // call a shift but it shouldn't do anything - strip.shift(0, pixel.FORWARD, false); - test.equal(strip.pixel(1).color().color, "red", - "If pixels are advanced by 0 elements, pixel 1 should stay the same"); + // set up a pixel on either end of the strip + // in preparation for movement. + strip.pixel(1).color('red'); + strip.pixel(6).color('blue'); - // advance the pixels one step along the strip. - strip.shift(1, pixel.FORWARD, false); + // call a shift but it shouldn't do anything + strip.shift(0, pixel.FORWARD, false); + test.equal(strip.pixel(1).color().color, 'red', + 'If pixels are advanced by 0 elements, pixel 1 should stay the same'); - test.equal(strip.pixel(7).color().color, "blue", - "If pixels are advanced one position, pixel 6 value should be on pixel 7"); + // advance the pixels one step along the strip. + strip.shift(1, pixel.FORWARD, false); - test.equal(strip.pixel(7).address, 7, - "After pixels are shifted, pixel address should be updated again"); + test.equal(strip.pixel(7).color().color, 'blue', + 'If pixels are advanced one position, pixel 6 value should be on pixel 7'); - test.equal(strip.pixel(6).color().color, "black", - "If pixels are advanced one position, pixel 5 value should overwrite pixel 6"); + test.equal(strip.pixel(7).address, 7, + 'After pixels are shifted, pixel address should be updated again'); - test.equal(strip.pixel(0).color().color, "black", - "If pixels advance with no wrapping, pixel 0 value should be off"); + test.equal(strip.pixel(6).color().color, 'black', + 'If pixels are advanced one position, pixel 5 value should overwrite pixel 6'); - strip.shift(1, pixel.BACKWARD, false); + test.equal(strip.pixel(0).color().color, 'black', + 'If pixels advance with no wrapping, pixel 0 value should be off'); - test.equal(strip.pixel(6).color().color, "blue", - "If pixels are reversed one position, pixel 7 value should be on pixel 6"); + strip.shift(1, pixel.BACKWARD, false); - test.equal(strip.pixel(5).color().color, "black", - "If pixels are reversed one position, pixel 6 value should overwrite pixel 5"); + test.equal(strip.pixel(6).color().color, 'blue', + 'If pixels are reversed one position, pixel 7 value should be on pixel 6'); - test.equal(strip.pixel(7).color().color, "black", - "If pixels reverse with no wrapping, pixel 7 value should be off"); + test.equal(strip.pixel(5).color().color, 'black', + 'If pixels are reversed one position, pixel 6 value should overwrite pixel 5'); - // now we are back to starting spot let's do a multistep advancement - // with a wrap around. + test.equal(strip.pixel(7).color().color, 'black', + 'If pixels reverse with no wrapping, pixel 7 value should be off'); - strip.shift(2, pixel.FORWARD, true); + // now we are back to starting spot let's do a multistep advancement + // with a wrap around. - test.equal(strip.pixel(3).color().color, "red", - "If pixels are advanced 2 positions & wrapped, pixel 1 value should be on pixel 3"); + strip.shift(2, pixel.FORWARD, true); - test.equal(strip.pixel(0).color().color, "blue", - "If pixels are advanced 2 positions & wrapped, pixel 6 value should be on pixel 0"); + test.equal(strip.pixel(3).color().color, 'red', + 'If pixels are advanced 2 positions & wrapped, pixel 1 value should be on pixel 3'); - // now let's test a jump over the length of the strip. - strip.shift(9, pixel.BACKWARD, true); + test.equal(strip.pixel(0).color().color, 'blue', + 'If pixels are advanced 2 positions & wrapped, pixel 6 value should be on pixel 0'); - test.equal(strip.pixel(7).color().color, "blue", - "If pixels are reversed more than strip length (9), pixel 0 should be on pixel 7"); + // now let's test a jump over the length of the strip. + strip.shift(9, pixel.BACKWARD, true); - // make sure there's nothing dangling behind. - test.equal(strip.pixel(6).color().color, "black", - "If pixels are shifted and wrapped, original pixel should have moved"); + test.equal(strip.pixel(7).color().color, 'blue', + 'If pixels are reversed more than strip length (9), pixel 0 should be on pixel 7'); - test.done(); + // make sure there's nothing dangling behind. + test.equal(strip.pixel(6).color().color, 'black', + 'If pixels are shifted and wrapped, original pixel should have moved'); - }, + test.done(); + } }; -exports["Pixel"] = { - setUp: function(done) { - this.board = newBoard(); - - this.strip = new pixel.Strip({ - data: 6, - length: 4, - board: this.board, - controller: "FIRMATA", - }); - - done(); - }, +exports['Pixel'] = { + setUp(done) { + this.board = newBoard(); - tearDown: function(done) { - Board.purge(); - restore(this); - done(); - }, - - colour: function(test) { - // tests if the colour sequences are working okay - test.expect(3); - - var colourcheck = { - r: 255, g: 255, b: 255, - hexcode: "#FFFFFF", - color: "white", - rgb: [255, 255, 255], - }; - - this.strip.pixel(0).color("#FFFFFF"); - test.deepEqual(this.strip.pixel(0).color(), colourcheck, - "If pixel colour is set, the pixel colour object should be updated"); - - colourcheck = { - r: 0, g: 255, b: 0, - hexcode: "#00FF00", - color: "lime", - rgb: [0, 255, 0], - }; - - this.strip.pixel(3).color([0, 255, 0]); - test.deepEqual(this.strip.pixel(3).color(), colourcheck, - "If setting the pixel colour using RGB array, the pixel colour object should be updated"); - - test.doesNotThrow( - () => { - this.strip.pixel(1).colour("QWERTYUIOP"); - }, - undefined, - "An invalid color should be ignored not throw an error" - ); - - test.done(); - }, - - off: function(test) { - // tests if setting strip off results in black pixel colour - test.expect(1); - - this.strip.color("#FF0000"); - - var colourcheck = { - r: 0, g: 0, b: 0, - hexcode: "#000000", - color: "black", - rgb: [0, 0, 0], - }; + this.strip = new pixel.Strip({ + data: 6, + length: 4, + board: this.board, + controller: 'FIRMATA' + }); - this.strip.pixel(1).off(); - test.deepEqual(this.strip.pixel(1).color(), colourcheck, - "If setting a colour then turning a pixel off, the colour should revert to off state."); - test.done(); - }, + done(); + }, + + tearDown(done) { + Board.purge(); + restore(this); + done(); + }, + + colour(test) { + // tests if the colour sequences are working okay + test.expect(3); + + let colourcheck = { + r: 255, g: 255, b: 255, + hexcode: '#FFFFFF', + color: 'white', + rgb: [255, 255, 255] + }; + + this.strip.pixel(0).color('#FFFFFF'); + test.deepEqual(this.strip.pixel(0).color(), colourcheck, + 'If pixel colour is set, the pixel colour object should be updated'); + + colourcheck = { + r: 0, g: 255, b: 0, + hexcode: '#00FF00', + color: 'lime', + rgb: [0, 255, 0] + }; + + this.strip.pixel(3).color([0, 255, 0]); + test.deepEqual(this.strip.pixel(3).color(), colourcheck, + 'If setting the pixel colour using RGB array, the pixel colour object should be updated'); + + test.doesNotThrow( + () => { + this.strip.pixel(1).colour('QWERTYUIOP'); + }, + undefined, + 'An invalid color should be ignored not throw an error' + ); + + test.done(); + }, + + off(test) { + // tests if setting strip off results in black pixel colour + test.expect(1); + + this.strip.color('#FF0000'); + + const colourcheck = { + r: 0, g: 0, b: 0, + hexcode: '#000000', + color: 'black', + rgb: [0, 0, 0] + }; + + this.strip.pixel(1).off(); + test.deepEqual(this.strip.pixel(1).color(), colourcheck, + 'If setting a colour then turning a pixel off, the colour should revert to off state.'); + test.done(); + } }; diff --git a/test/firmata.js b/test/firmata.js index 3acd309..8bb6af3 100644 --- a/test/firmata.js +++ b/test/firmata.js @@ -1,331 +1,317 @@ global.IS_TEST_MODE = true; -var mocks = require("mock-firmata"); -var MockFirmata = mocks.Firmata; -var MockSerialPort = mocks.SerialPort; +const mocks = require('mock-firmata'); +const MockFirmata = mocks.Firmata; +const MockSerialPort = mocks.SerialPort; -var sinon = require("sinon"); +const sinon = require('sinon'); -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var Board = five.Board; +const Board = five.Board; function newBoard() { - var sp = new MockSerialPort("/dev/test"); - var io = new MockFirmata(sp); - io["firmware"] = { name: "node_pixel_firmata.ino", }; + const sp = new MockSerialPort('/dev/test'); + const io = new MockFirmata(sp); + io['firmware'] = { name: 'node_pixel_firmata.ino' }; - io.emit("connect"); - io.emit("ready"); + io.emit('connect'); + io.emit('ready'); - var board = new Board({ - io: io, - debug: false, - repl: false, - }); + const board = new Board({ + io, + debug: false, + repl: false + }); - return board; + return board; } function restore(target) { - for (var prop in target) { - - if (Array.isArray(target[prop])) { - continue; - } + for (const prop in target) { + if (Array.isArray(target[prop])) { + continue; + } - if (target[prop] != null && typeof target[prop].restore === "function") { - target[prop].restore(); - } + if (target[prop] != null && typeof target[prop].restore === 'function') { + target[prop].restore(); + } - if (typeof target[prop] === "object") { - restore(target[prop]); - } + if (typeof target[prop] === 'object') { + restore(target[prop]); } + } } -exports["Firmata - Initialisation"] = { - - setUp: function(done){ - - this.board = newBoard(); - done(); - }, - - tearDown: function(done) { - Board.purge(); - restore(this); - done(); - }, - - firmataInitialisation: function(test) { - - test.expect(4); - let mock_firmata = { - firmware: { - name: "node_pixel_firmata.ino", - }, - }; - - test.doesNotThrow( - () => { - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - }); - }, - "If no controller is provided strip should default to firmata without error" - ); - - // check error states. - test.throws( - () => { - var strip = new pixel.Strip({ - data: 6, - length: 8, - controller: "FIRMATA", - }); - }, - function(err) { - if (err) { - if (err.name == "NoFirmataError") { - return true; - } else { - return false; - } - } else { - return false; - } - }, - "If board is not present an error should be thrown" - ); - - test.throws( - () => { - // build with an empty firmata to test non-writable port. - // - - var strip = new pixel.Strip({ - data: 6, - length: 8, - firmata: mock_firmata, - controller: "FIRMATA", - }); - - }, - function(err) { - if (err) { - if (err.name == "NoWritablePortError") { - return true; - } else { - return false; - } - } else { - return false; - } - }, - "If there is no writable port, controller should throw an error" - ); - - test.throws( - () => { - // build with an empty firmata to test bad naming. - mock_firmata.firmware.name = "StandardFirmata.ino"; - - var strip = new pixel.Strip({ - data: 6, - length: 8, - firmata: mock_firmata, - controller: "FIRMATA", - }); - - }, - function(err) { - if (err) { - if (err.name == "IncorrectFirmataVersionError") { - return true; - } else { - return false; - } - } else { - return false; - } - }, - "If firmware name is incorrect, controller should throw an error" - ); - - test.done(); - }, +exports['Firmata - Initialisation'] = { + + setUp(done) { + this.board = newBoard(); + done(); + }, + + tearDown(done) { + Board.purge(); + restore(this); + done(); + }, + + firmataInitialisation(test) { + test.expect(4); + const mock_firmata = { + firmware: { + name: 'node_pixel_firmata.ino' + } + }; + + test.doesNotThrow( + () => { + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board + }); + }, + 'If no controller is provided strip should default to firmata without error' + ); + + // check error states. + test.throws( + () => { + const strip = new pixel.Strip({ + data: 6, + length: 8, + controller: 'FIRMATA' + }); + }, + function(err) { + if (err) { + if (err.name == 'NoFirmataError') { + return true; + } + return false; + } + return false; + }, + 'If board is not present an error should be thrown' + ); + + test.throws( + () => { + // build with an empty firmata to test non-writable port. + // + + const strip = new pixel.Strip({ + data: 6, + length: 8, + firmata: mock_firmata, + controller: 'FIRMATA' + }); + }, + function(err) { + if (err) { + if (err.name == 'NoWritablePortError') { + return true; + } + return false; + } + return false; + }, + 'If there is no writable port, controller should throw an error' + ); + + test.throws( + () => { + // build with an empty firmata to test bad naming. + mock_firmata.firmware.name = 'StandardFirmata.ino'; + + const strip = new pixel.Strip({ + data: 6, + length: 8, + firmata: mock_firmata, + controller: 'FIRMATA' + }); + }, + function(err) { + if (err) { + if (err.name == 'IncorrectFirmataVersionError') { + return true; + } + return false; + } + return false; + }, + 'If firmware name is incorrect, controller should throw an error' + ); + + test.done(); + } }; -exports["Strip - Firmata"] = { - setUp: function(done){ +exports['Strip - Firmata'] = { + setUp(done) { + this.write = sinon.stub(MockSerialPort.prototype, 'write').callsFake( function(buffer, callback) { + if (typeof callback === 'function') { + process.nextTick(callback); + } else { + return; + } + }); - this.write = sinon.stub(MockSerialPort.prototype, "write").callsFake( function(buffer, callback) { - if (typeof callback === "function") { - process.nextTick(callback); - } else { - return; - } - }); + this.board = newBoard(); + done(); + }, + + tearDown(done) { + Board.purge(); + restore(this); + done(); + }, + + stripReady(test) { + // tests if the strip emits the ready event properly. + test.expect(2); + + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board, + controller: 'FIRMATA' + }); - this.board = newBoard(); - done(); - }, - - tearDown: function(done) { - Board.purge(); - restore(this); - done(); - }, - - stripReady: function(test) { - // tests if the strip emits the ready event properly. - test.expect(2); - - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - controller: "FIRMATA", - }); + test.equal(this.write.callCount, 1, + 'During initialisation serial write should occur only once'); - test.equal(this.write.callCount, 1, - "During initialisation serial write should occur only once"); + strip.on('ready', function() { + test.ok(true, 'If initialisation is complete a ready event should be emitted'); + test.done(); + }); + }, - strip.on("ready", function() { - test.ok(true, "If initialisation is complete a ready event should be emitted"); - test.done(); - }); - }, - - maxNumberOfStrips: function(test) { - test.expect(1); - - test.throws( - () => { - var strip = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [8, 8, 8, 8, 8, 8, 8, 8, 8] - }); - }, - function (err) { - if (err instanceof RangeError) { - return true; - } - }, - "Excessive number of strips should throw a RangeError" - ); - - test.done(); - }, - - maxNumberOfPixels: function(test) { - test.expect(2); - - test.throws( - () => { - var strip1 = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [ {pin: 6, length: 300}, ] - }); - }, - function (err) { - if (err instanceof RangeError) { - return true; - } - }, - "Excess pixels in a single strip should throw a RangeError" - ); - - test.throws( - () => { - var strip2 = new pixel.Strip({ - board: this.board, - controller: "FIRMATA", - strips: [ {pin: 2, length: 64}, - {pin: 2, length: 64}, - {pin: 2, length: 64}, - {pin: 2, length: 64}, - {pin: 2, length: 64}, - ], // more than 256 - }); - }, - function (err) { - if (err instanceof RangeError) { - return true; - } - }, - "Excess pixels in multiple strips should throw a RangeError" - ); - test.done(); - - }, - - show: function(test) { - // tests if the strip calls the show out to I2C properly. - // - test.expect(2); + maxNumberOfStrips(test) { + test.expect(1); - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - controller: "FIRMATA", + test.throws( + () => { + const strip = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [8, 8, 8, 8, 8, 8, 8, 8, 8] + }); + }, + function(err) { + if (err instanceof RangeError) { + return true; + } + }, + 'Excessive number of strips should throw a RangeError' + ); + + test.done(); + }, + + maxNumberOfPixels(test) { + test.expect(2); + + test.throws( + () => { + const strip1 = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [ {pin: 6, length: 300} ] + }); + }, + function(err) { + if (err instanceof RangeError) { + return true; + } + }, + 'Excess pixels in a single strip should throw a RangeError' + ); + + test.throws( + () => { + const strip2 = new pixel.Strip({ + board: this.board, + controller: 'FIRMATA', + strips: [ {pin: 2, length: 64}, + {pin: 2, length: 64}, + {pin: 2, length: 64}, + {pin: 2, length: 64}, + {pin: 2, length: 64} + ] // more than 256 }); + }, + function(err) { + if (err instanceof RangeError) { + return true; + } + }, + 'Excess pixels in multiple strips should throw a RangeError' + ); + test.done(); + }, + + show(test) { + // tests if the strip calls the show out to I2C properly. + // + test.expect(2); + + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board, + controller: 'FIRMATA' + }); - strip.on("ready", function() { - test.equal(this.write.callCount, 1, - "Firmata should call serial write only once during setup"); - strip.show(); - test.equal(this.write.callCount, 2, - "Show should call serial write once after setup is complete."); - test.done(); - }.bind(this)); - } + strip.on('ready', function() { + test.equal(this.write.callCount, 1, + 'Firmata should call serial write only once during setup'); + strip.show(); + test.equal(this.write.callCount, 2, + 'Show should call serial write once after setup is complete.'); + test.done(); + }.bind(this)); + } }; -exports["Pixel - Firmata"] = { - setUp: function(done){ - - this.write = sinon.stub(MockSerialPort.prototype, "write").callsFake(function(buffer, callback) { - if (typeof callback === "function") { - process.nextTick(callback); - } else { - return; - } - }); +exports['Pixel - Firmata'] = { + setUp(done) { + this.write = sinon.stub(MockSerialPort.prototype, 'write').callsFake(function(buffer, callback) { + if (typeof callback === 'function') { + process.nextTick(callback); + } else { + return; + } + }); - this.board = newBoard(); + this.board = newBoard(); - this.strip = new pixel.Strip({ - data: 6, - length: 4, - board: this.board, - controller: "FIRMATA", - }); + this.strip = new pixel.Strip({ + data: 6, + length: 4, + board: this.board, + controller: 'FIRMATA' + }); - done(); - }, - - tearDown: function(done) { - Board.purge(); - restore(this); - done(); - }, - - writing: function(test) { - // tests to see whether the write to the pixel is going out properly - test.expect(1); - this.strip.pixel(0).color("#FFF"); - test.equal(this.write.callCount, 2, - "Setting the pixel value should make a single serial call"); - test.done() - }, + done(); + }, + + tearDown(done) { + Board.purge(); + restore(this); + done(); + }, + + writing(test) { + // tests to see whether the write to the pixel is going out properly + test.expect(1); + this.strip.pixel(0).color('#FFF'); + test.equal(this.write.callCount, 2, + 'Setting the pixel value should make a single serial call'); + test.done() + } }; diff --git a/test/i2cbackpack.js b/test/i2cbackpack.js index 2d7ab50..8ce135f 100644 --- a/test/i2cbackpack.js +++ b/test/i2cbackpack.js @@ -1,268 +1,258 @@ global.IS_TEST_MODE = true; -var mocks = require("mock-firmata"); -var MockFirmata = mocks.Firmata; -var MockSerialPort = mocks.SerialPort; +const mocks = require('mock-firmata'); +const MockFirmata = mocks.Firmata; +const MockSerialPort = mocks.SerialPort; -var sinon = require("sinon"); +const sinon = require('sinon'); -var five = require("johnny-five"); -var pixel = require("../lib/pixel.js"); +const five = require('johnny-five'); +const pixel = require('../lib/pixel.js'); -var Board = five.Board; +const Board = five.Board; function newBoard() { - var sp = new MockSerialPort("/dev/test"); - var io = new MockFirmata(sp); + const sp = new MockSerialPort('/dev/test'); + const io = new MockFirmata(sp); - io.emit("connect"); - io.emit("ready"); + io.emit('connect'); + io.emit('ready'); - var board = new Board({ - io: io, - debug: false, - repl: false, - }); + const board = new Board({ + io, + debug: false, + repl: false + }); - return board; + return board; } function restore(target) { - for (var prop in target) { - - if (Array.isArray(target[prop])) { - continue; - } + for (const prop in target) { + if (Array.isArray(target[prop])) { + continue; + } - if (target[prop] != null && typeof target[prop].restore === "function") { - target[prop].restore(); - } + if (target[prop] != null && typeof target[prop].restore === 'function') { + target[prop].restore(); + } - if (typeof target[prop] === "object") { - restore(target[prop]); - } + if (typeof target[prop] === 'object') { + restore(target[prop]); } + } } -exports["Strip - I2C"] = { - setUp: function(done){ +exports['Strip - I2C'] = { + setUp(done) { + this.board = newBoard(); + this.clock = sinon.useFakeTimers(); + this.i2cConfig = sinon.spy(MockFirmata.prototype, 'i2cConfig'); + this.i2cWrite = sinon.stub(MockFirmata.prototype, 'i2cWrite').callsFake(function(i2caddr, data) { + return; + }); - this.board = newBoard(); - this.clock = sinon.useFakeTimers(); - this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig"); - this.i2cWrite = sinon.stub(MockFirmata.prototype, "i2cWrite").callsFake(function(i2caddr, data) { - return; - }); + done(); + }, - done(); - }, - - tearDown: function(done) { - this.i2cConfig.restore(); - this.i2cWrite.restore(); - this.clock.restore(); - done(); - }, - - i2cControllerConfig: function(test) { - // ensures that the configuration of the controller works correctly - - test.expect(1); - - test.throws( - () => { - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: {}, - controller: "I2CBACKPACK", - }); - }, - function(err) { - if (err) { - if (err.name == "NoIOError") { - return true; - } else { - return false; - } - } else { - return false; - } - }, - "If IO is not present an error should be thrown" - ); - - test.done(); - - }, - - stripReady: function(test) { - // tests if the strip emits the ready event properly. - - test.expect(3); - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - controller: "I2CBACKPACK", - }); + tearDown(done) { + this.i2cConfig.restore(); + this.i2cWrite.restore(); + this.clock.restore(); + done(); + }, - // emit the ready event ahead of time. - - test.equal(this.i2cConfig.callCount, 1, - "I2C Config should be called only once during config."); - - strip.on("ready", function() { - test.equal(this.i2cWrite.callCount, 1, - "I2C Write should be called once as part of config"); - test.ok(true, - "If configuration is complete a ready even should be emitted"); - test.done(); - }.bind(this)); - }, - - maxNumberOfStrips: function(test) { - test.expect(1); - - test.throws( - () => { - var strip = new pixel.Strip({ - board: this.board, - controller: "I2CBACKPACK", - strips: [8, 8, 8, 8, 8, 8, 8, 8, 8] - }); - }, - function (err) { - if (err instanceof RangeError) { - return true; - } - }, - "Excessive number of strips should throw a RangeError" - ); - - test.done(); - }, - - maxNumberOfPixels: function(test) { - test.expect(2); - - test.throws( - () => { - var strip1 = new pixel.Strip({ - board: this.board, - controller: "I2CBACKPACK", - strips: [ 600 ] - }); - }, - function (err) { - if (err instanceof RangeError) { - return true; - } - }, - "Excess pixels in a single strip should throw a RangeError" - ); - - test.throws( - () => { - var strip2 = new pixel.Strip({ - board: this.board, - controller: "I2CBACKPACK", - strips: [ 100, 100, 100, 100, 100, 100, 100, ] - }); - }, - function (err) { - if (err instanceof RangeError) { - return true; - } - }, - "Excess pixels in multiple strips should throw a RangeError" - ); - test.done(); - - }, - show: function(test) { - // tests if the strip calls the show out to I2C properly. - // - test.expect(1); - - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - controller: "I2CBACKPACK", - }); + i2cControllerConfig(test) { + // ensures that the configuration of the controller works correctly + + test.expect(1); - strip.on("ready", function() { - strip.show(); - // first call count will be for the setup call - test.equal(this.i2cWrite.callCount, 2, - "i2cWrite should be called only once during show"); - test.done(); - }.bind(this)); - - }, - - color: function(test) { - // aims for coverage tests to ensure that colours are set properly. - // - test.expect(2); - - var strip = new pixel.Strip({ - data: 6, - length: 8, - board: this.board, - controller: "I2CBACKPACK", + test.throws( + () => { + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: {}, + controller: 'I2CBACKPACK' }); + }, + function(err) { + if (err) { + if (err.name == 'NoIOError') { + return true; + } + return false; + } + return false; + }, + 'If IO is not present an error should be thrown' + ); + + test.done(); + }, + + stripReady(test) { + // tests if the strip emits the ready event properly. + + test.expect(3); + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board, + controller: 'I2CBACKPACK' + }); - strip.on("ready", function() { + // emit the ready event ahead of time. + + test.equal(this.i2cConfig.callCount, 1, + 'I2C Config should be called only once during config.'); + + strip.on('ready', function() { + test.equal(this.i2cWrite.callCount, 1, + 'I2C Write should be called once as part of config'); + test.ok(true, + 'If configuration is complete a ready even should be emitted'); + test.done(); + }.bind(this)); + }, + + maxNumberOfStrips(test) { + test.expect(1); + + test.throws( + () => { + const strip = new pixel.Strip({ + board: this.board, + controller: 'I2CBACKPACK', + strips: [8, 8, 8, 8, 8, 8, 8, 8, 8] + }); + }, + function(err) { + if (err instanceof RangeError) { + return true; + } + }, + 'Excessive number of strips should throw a RangeError' + ); + + test.done(); + }, + + maxNumberOfPixels(test) { + test.expect(2); + + test.throws( + () => { + const strip1 = new pixel.Strip({ + board: this.board, + controller: 'I2CBACKPACK', + strips: [ 600 ] + }); + }, + function(err) { + if (err instanceof RangeError) { + return true; + } + }, + 'Excess pixels in a single strip should throw a RangeError' + ); + + test.throws( + () => { + const strip2 = new pixel.Strip({ + board: this.board, + controller: 'I2CBACKPACK', + strips: [ 100, 100, 100, 100, 100, 100, 100 ] + }); + }, + function(err) { + if (err instanceof RangeError) { + return true; + } + }, + 'Excess pixels in multiple strips should throw a RangeError' + ); + test.done(); + }, + show(test) { + // tests if the strip calls the show out to I2C properly. + // + test.expect(1); + + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board, + controller: 'I2CBACKPACK' + }); - strip.color("red"); - // first call count will be for the setup call - test.equal(this.i2cWrite.callCount, 2, - "i2cWrite should be called only once during colour setting"); + strip.on('ready', function() { + strip.show(); + // first call count will be for the setup call + test.equal(this.i2cWrite.callCount, 2, + 'i2cWrite should be called only once during show'); + test.done(); + }.bind(this)); + }, + + color(test) { + // aims for coverage tests to ensure that colours are set properly. + // + test.expect(2); + + const strip = new pixel.Strip({ + data: 6, + length: 8, + board: this.board, + controller: 'I2CBACKPACK' + }); - strip.shift(1, pixel.FORWARDS, true); - test.equal(this.i2cWrite.callCount, 3, - "i2cWrite should be called only once during shift call"); + strip.on('ready', function() { + strip.color('red'); + // first call count will be for the setup call + test.equal(this.i2cWrite.callCount, 2, + 'i2cWrite should be called only once during colour setting'); - test.done(); - }.bind(this)); + strip.shift(1, pixel.FORWARDS, true); + test.equal(this.i2cWrite.callCount, 3, + 'i2cWrite should be called only once during shift call'); - }, + test.done(); + }.bind(this)); + } }; -exports["Pixel - I2C"] = { - setUp: function(done){ - - this.board = newBoard(); - this.clock = sinon.useFakeTimers(); - this.i2cConfig = sinon.spy(MockFirmata.prototype, "i2cConfig"); - this.i2cWrite = sinon.stub(MockFirmata.prototype, "i2cWrite").callsFake(function(i2caddr, data) { - return; - }); +exports['Pixel - I2C'] = { + setUp(done) { + this.board = newBoard(); + this.clock = sinon.useFakeTimers(); + this.i2cConfig = sinon.spy(MockFirmata.prototype, 'i2cConfig'); + this.i2cWrite = sinon.stub(MockFirmata.prototype, 'i2cWrite').callsFake(function(i2caddr, data) { + return; + }); - this.strip = new pixel.Strip({ - data: 6, - length: 4, - board: this.board, - controller: "I2CBACKPACK", - }); + this.strip = new pixel.Strip({ + data: 6, + length: 4, + board: this.board, + controller: 'I2CBACKPACK' + }); - done(); - }, - - tearDown: function(done) { - this.i2cConfig.restore(); - this.i2cWrite.restore(); - this.clock.restore(); - done(); - }, - - writing: function(test) { - // tests to see whether the write to the pixel is going out properly - test.expect(1); - this.strip.pixel(0).color("#FFF"); - test.equal(this.i2cWrite.callCount, 1, - "i2cWrite should only call once to write a pixel value"); - test.done() - }, + done(); + }, + + tearDown(done) { + this.i2cConfig.restore(); + this.i2cWrite.restore(); + this.clock.restore(); + done(); + }, + + writing(test) { + // tests to see whether the write to the pixel is going out properly + test.expect(1); + this.strip.pixel(0).color('#FFF'); + test.equal(this.i2cWrite.callCount, 1, + 'i2cWrite should only call once to write a pixel value'); + test.done() + } }