├── README.md ├── examples ├── ball.js ├── clear.js ├── conway.js ├── glow.js ├── gradient.js └── scroll.js ├── gradient.jpg ├── iob.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # internet-of-buckets 2 | 3 | > http wrapper for controlling *The Internet of Buckets* art installation 4 | 5 | *The Internet of Buckets* is a 10x5 stack of buckets with RGB LEDs inside. Each 6 | is controlled independently by a microcontroller with its own IP address, which 7 | responds to HTTP requests. This module wraps the process of addressing and 8 | routing to each bucket. 9 | 10 | There are a small variety of demos under `examples/`. 11 | 12 | ## Usage 13 | 14 | Let's draw a gradient: 15 | 16 | ```js 17 | var draw = require('internet-of-buckets') 18 | 19 | for (var i=0; i < 10; i++) { 20 | for (var j=0; j < 5; j++) { 21 | var red = 255 * i / 10 22 | var green = 0 23 | var blue = 255 - 255 * j / 5 24 | draw(i, j, [red, green, blue]) 25 | } 26 | } 27 | ``` 28 | 29 | This will output 30 | 31 | 32 | 33 | ## API 34 | 35 | ```js 36 | var draw = require('internet-of-buckets') 37 | ``` 38 | 39 | ### draw(x, y, rgb, cb=function noop(){}) 40 | 41 | Sets a single bucket at `(x, y)` to the colour `rgb`. 42 | 43 | The top left corner is `(0, 0)`, and the bottom right corner is `(9, 4)`. 44 | 45 | `rgb` is an array of size 3, with values between `0-255`. It represents the red, 46 | green, and blue components respectively. 47 | 48 | If provided, `cb` is a function that will be called once the write is complete. 49 | This can be be useful for e.g. synchronizing several buckets' updates. 50 | 51 | 52 | ## Install 53 | 54 | With [npm](https://npmjs.org/) installed, run 55 | 56 | ``` 57 | $ npm install internet-of-buckets 58 | ``` 59 | 60 | ## License 61 | 62 | ISC 63 | 64 | -------------------------------------------------------------------------------- /examples/ball.js: -------------------------------------------------------------------------------- 1 | var set = require('../iob') 2 | 3 | function makeWorld () { 4 | return new Array(5).fill(0).map(function () { 5 | return new Array(10).fill(0) 6 | }) 7 | } 8 | 9 | var world = makeWorld() 10 | 11 | function applyLight (world, x, y, radius, rgb) { 12 | var next = makeWorld() 13 | for (var i=0; i < 10; i++) { 14 | for (var j=0; j < 5; j++) { 15 | var dx = x - i 16 | var dy = y - j 17 | var dist = Math.sqrt(dx*dx + dy*dy) + 0.001 18 | var power = radius / (dist*dist) 19 | power = Math.max(0, Math.min(1, power)) 20 | // console.log(i, j, power) 21 | next[j][i] = [100 * power, 0, 0] 22 | } 23 | } 24 | return next 25 | } 26 | 27 | function render (world) { 28 | for (var i=0; i < 10; i++) { 29 | for (var j=0; j < 5; j++) { 30 | set(i, j, world[j][i]) 31 | } 32 | } 33 | } 34 | 35 | function renderSync (world, cb) { 36 | var n = 50 37 | for (var i=0; i < 10; i++) { 38 | for (var j=0; j < 5; j++) { 39 | set(i, j, world[j][i], function () { 40 | n-- 41 | if (n <= 0 && cb) return cb() 42 | }) 43 | } 44 | } 45 | } 46 | 47 | var x = 5 48 | var y = 2.5 49 | var ang = Math.random() * 2 * 3.14159 50 | ang = 3.14159 / 4 51 | var xv = Math.cos(ang) * 0.25 52 | var yv = Math.sin(ang) * 0.25 53 | 54 | function step (world) { 55 | x += xv 56 | y += yv 57 | if (x >= 8) xv *= -1 58 | if (x <= 0) xv *= -1 59 | if (y >= 4) yv *= -1 60 | if (y <= 0) yv *= -1 61 | return applyLight(world, x, y, 0.1, [16, 0, 0]) 62 | } 63 | 64 | function frame () { 65 | world = step(world) 66 | renderSync(world, frame) 67 | } 68 | 69 | frame() 70 | 71 | // var world = 72 | -------------------------------------------------------------------------------- /examples/clear.js: -------------------------------------------------------------------------------- 1 | var set = require('../iob') 2 | 3 | for (var i=0; i < 10; i++) { 4 | for (var j=0; j < 5; j++) { 5 | set(i, j, [0, 0, 0]) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/conway.js: -------------------------------------------------------------------------------- 1 | var set = require('../iob') 2 | 3 | 4 | // set(0, 0, [255, 0, 255]) 5 | 6 | function makeWorld () { 7 | return new Array(5).fill(0).map(function () { 8 | return new Array(10).fill(0) 9 | }) 10 | } 11 | 12 | function rand () { 13 | return Math.floor(Math.random() * 255) 14 | } 15 | 16 | var c1 = [rand(), rand(), rand()] 17 | var c2 = [rand(), rand(), rand()] 18 | 19 | 20 | var world = makeWorld() 21 | 22 | for (var i=0; i < 10; i++) { 23 | for (var j=0; j < 5; j++) { 24 | world[j][i] = Math.random() > 0.8 25 | } 26 | } 27 | 28 | function render (world) { 29 | for (var i=0; i < 10; i++) { 30 | for (var j=0; j < 5; j++) { 31 | set(i, j, world[j][i] ? c1 : c2) 32 | } 33 | } 34 | } 35 | 36 | function neighbours (world, x, y) { 37 | var n = 0 38 | for (var i=-1; i <= 1; i++) { 39 | for (var j=-1; j <= 1; j++) { 40 | if (i !== 0 && j !== 0) continue 41 | var xx = x + i 42 | var yy = y + j 43 | xx = Math.abs(xx) % 10 44 | yy = Math.abs(yy) % 5 45 | n += world[yy][xx] ? 1 : 0 46 | } 47 | } 48 | return n 49 | } 50 | 51 | function step (world) { 52 | var next = makeWorld() 53 | for (var i=0; i < 10; i++) { 54 | for (var j=0; j < 5; j++) { 55 | var n = neighbours(world, i, j) 56 | next[j][i] = (n === 2 || n === 3) 57 | } 58 | } 59 | return next 60 | } 61 | 62 | setInterval(function () { 63 | render(world) 64 | world = step(world) 65 | }, 500) 66 | 67 | // var world = 68 | -------------------------------------------------------------------------------- /examples/glow.js: -------------------------------------------------------------------------------- 1 | var set = require('../iob') 2 | 3 | // set(0, 0, [255, 0, 255]) 4 | 5 | function makeWorld () { 6 | return new Array(5).fill(0).map(function () { 7 | return new Array(10).fill(0) 8 | }) 9 | } 10 | 11 | function rand () { 12 | return Math.floor(Math.random() * 255) 13 | } 14 | 15 | var c1 = [rand(), rand(), rand()] 16 | var c2 = [rand(), rand(), rand()] 17 | 18 | var world = makeWorld() 19 | 20 | function applyLight (world, x, y, radius, rgb) { 21 | var next = makeWorld() 22 | for (var i=0; i < 10; i++) { 23 | for (var j=0; j < 5; j++) { 24 | var dx = x - i 25 | var dy = y - j 26 | var dist = Math.sqrt(dx*dx + dy*dy) + 0.001 27 | var power = radius / (dist*dist) 28 | power = Math.max(0, Math.min(1, power)) 29 | // console.log(i, j, power) 30 | next[j][i] = [100 * power, 0, 0] 31 | } 32 | } 33 | return next 34 | } 35 | 36 | function render (world) { 37 | for (var i=0; i < 10; i++) { 38 | for (var j=0; j < 5; j++) { 39 | set(i, j, world[j][i]) 40 | } 41 | } 42 | } 43 | 44 | function renderSync (world, cb) { 45 | var n = 50 46 | for (var i=0; i < 10; i++) { 47 | for (var j=0; j < 5; j++) { 48 | set(i, j, world[j][i], function () { 49 | n-- 50 | if (n <= 0 && cb) return cb() 51 | }) 52 | } 53 | } 54 | } 55 | 56 | function step (world) { 57 | var t = new Date().getTime() 58 | var x = 5 + Math.sin(t/1000) * 2 59 | var y = 2 + Math.cos(t/285) * 1.5 60 | x = 5 61 | y = 2 62 | var r = 1 + Math.sin(t/500) 63 | return applyLight(world, x, y, r, [255, 0, 0]) 64 | } 65 | 66 | function frame () { 67 | world = step(world) 68 | renderSync(world, frame) 69 | } 70 | 71 | frame() 72 | 73 | // var world = 74 | -------------------------------------------------------------------------------- /examples/gradient.js: -------------------------------------------------------------------------------- 1 | var set = require('../iob') 2 | 3 | for (var i=0; i < 10; i++) { 4 | for (var j=0; j < 5; j++) { 5 | set(i, j, [255 * (i/50),0,255 * (j/25)]) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/scroll.js: -------------------------------------------------------------------------------- 1 | var set = require('../iob') 2 | 3 | function makeWorld (old) { 4 | var w = new Array(5).fill(0).map(function () { 5 | return new Array(10).fill([0, 0, 0]) 6 | }) 7 | for (var i=0; i < 10; i++) { 8 | for (var j=0; j < 5; j++) { 9 | w[j][i] = old ? old[j][i] : [0, 0, 0] 10 | } 11 | } 12 | return w 13 | } 14 | 15 | 16 | var world = makeWorld() 17 | 18 | var letters = { 19 | ' ': [ 20 | 0, 0, 0, 21 | 0, 0, 0, 22 | 0, 0, 0, 23 | 0, 0, 0, 24 | 0, 0, 0 25 | ], 26 | 'A': [ 27 | 1, 1, 1, 28 | 1, 0, 1, 29 | 1, 1, 1, 30 | 1, 0, 1, 31 | 1, 0, 1 32 | ], 33 | 'I': [ 34 | 1, 1, 1, 35 | 0, 1, 0, 36 | 0, 1, 0, 37 | 0, 1, 0, 38 | 1, 1, 1 39 | ], 40 | 'B': [ 41 | 1, 1, 0, 42 | 1, 0, 1, 43 | 1, 1, 1, 44 | 1, 0, 1, 45 | 1, 1, 0 46 | ], 47 | 'C': [ 48 | 1, 1, 1, 49 | 1, 0, 0, 50 | 1, 0, 0, 51 | 1, 0, 0, 52 | 1, 1, 1 53 | ], 54 | 'K': [ 55 | 1, 0, 1, 56 | 1, 1, 0, 57 | 1, 0, 0, 58 | 1, 1, 0, 59 | 1, 0, 1 60 | ], 61 | 'T': [ 62 | 1, 1, 1, 63 | 0, 1, 0, 64 | 0, 1, 0, 65 | 0, 1, 0, 66 | 0, 1, 0 67 | ], 68 | 'H': [ 69 | 1, 0, 1, 70 | 1, 0, 1, 71 | 1, 1, 1, 72 | 1, 0, 1, 73 | 1, 0, 1 74 | ], 75 | 'E': [ 76 | 1, 1, 1, 77 | 1, 0, 0, 78 | 1, 1, 0, 79 | 1, 0, 0, 80 | 1, 1, 1 81 | ], 82 | 'P': [ 83 | 1, 1, 1, 84 | 1, 0, 1, 85 | 1, 1, 0, 86 | 1, 0, 0, 87 | 1, 0, 0 88 | ], 89 | 'L': [ 90 | 1, 0, 0, 91 | 1, 0, 0, 92 | 1, 0, 0, 93 | 1, 0, 0, 94 | 1, 1, 1 95 | ], 96 | 'N': [ 97 | 1, 0, 1, 98 | 1, 1, 1, 99 | 1, 1, 1, 100 | 1, 0, 1, 101 | 1, 0, 1 102 | ], 103 | 'N': [ 104 | 1, 0, 1, 105 | 1, 1, 1, 106 | 1, 1, 1, 107 | 1, 0, 1, 108 | 1, 0, 1 109 | ], 110 | } 111 | 112 | function letter (world, letter, x, rgb) { 113 | var next = makeWorld(world) 114 | var data = letters[letter] 115 | for (var i=x; i < x+3; i++) { 116 | for (var j=0; j < 5; j++) { 117 | var xx = (i-x) % 10 118 | var col = data[xx + j*3] 119 | next[j][i] = col ? rgb : [0, 0, 0] 120 | // console.log(i, j, col, next[j][i]) 121 | } 122 | } 123 | return next 124 | } 125 | 126 | function render (world) { 127 | for (var i=0; i < 10; i++) { 128 | for (var j=0; j < 5; j++) { 129 | set(i, j, world[j][i]) 130 | } 131 | } 132 | } 133 | 134 | function renderSync (world, cb) { 135 | var n = 50 136 | for (var i=0; i < 10; i++) { 137 | for (var j=0; j < 5; j++) { 138 | set(i, j, world[j][i], function () { 139 | n-- 140 | if (n <= 0 && cb) return cb() 141 | }) 142 | } 143 | } 144 | } 145 | 146 | function string (world, txt, offset, rgb) { 147 | return txt.split('').reduce(function (w, l) { 148 | var res = letter(w, l, offset, rgb) 149 | offset += 4 150 | return res 151 | }, world) 152 | } 153 | 154 | var x = 8 155 | function step (world) { 156 | x -= 0.5 157 | var offset = Math.floor(x) 158 | var intensity = ((Math.sin(new Date().getTime() / 500) + 1) / 2) * 8 + 32 159 | return string(makeWorld(), 'HACK THE PLANET', offset, [intensity, 0, 0]) 160 | // world = letter(world, 'H', x, [8, 0, 0]) 161 | // world = letter(world, 'I', x+4, [8, 0, 0]) 162 | return world 163 | } 164 | 165 | function frame () { 166 | world = makeWorld() 167 | world = step(world) 168 | renderSync(world, frame) 169 | } 170 | 171 | frame() 172 | 173 | // var world = 174 | -------------------------------------------------------------------------------- /gradient.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackergrrl/internet-of-buckets/da68fee06bb15e996275a15849b235f65b73c432/gradient.jpg -------------------------------------------------------------------------------- /iob.js: -------------------------------------------------------------------------------- 1 | var request = require('request') 2 | 3 | function address (x, y) { 4 | var idx = 201 + (y * 10) + x 5 | return 'http://192.168.16.' + idx 6 | } 7 | 8 | function color (rgb) { 9 | return '?r='+rgb[0]+'&g='+rgb[1]+'&b='+rgb[2] 10 | } 11 | 12 | function set (x, y, rgb, cb) { 13 | request(address(x, y) + color(rgb), function () { if (cb) cb() }) 14 | } 15 | 16 | module.exports = set 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "internet-of-buckets", 3 | "version": "1.0.2", 4 | "description": "http wrapper for controlling /The Internet of Buckets/ art installation", 5 | "main": "iob.js", 6 | "directories": { 7 | "example": "examples" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [ 13 | "internet", 14 | "of", 15 | "buckets", 16 | "iob" 17 | ], 18 | "author": "Stephen Whitmore ", 19 | "license": "ISC", 20 | "dependencies": { 21 | "request": "^2.74.0" 22 | } 23 | } 24 | --------------------------------------------------------------------------------