├── README.md
├── blink.js
├── light-switch.js
├── multi-light-switch.js
├── package.json
└── server.js
/README.md:
--------------------------------------------------------------------------------
1 | raspberry-pi-home-automation
2 | ============================
3 | A node.js based home automation system based around the Raspberry Pi. For background around this project:
4 |
5 | [](http://www.youtube.com/watch?v=SEAQVXHSwg4)
6 |
7 | Installation
8 | ============
9 | To get started, clone the repository and install the required dependencies.
10 |
11 | git clone https://github.com/anders94/raspberry-pi-home-automation.git
12 | cd raspberry-pi-home-automation
13 | npm install
14 |
15 | Hardware
16 | ========
17 | The Raspberry Pi needs a little bit of circuitry to protect and amplify its GPIO
18 | ports. Here's schematics of the circuits I created for this project.
19 |
20 | Protected Pull-Up Switch
21 | ------------------------
22 | If you want to read from the GPIO pins on the Raspberry Pi, you shouldn't just
23 | switch the pin between 3.3v+ and nothing. Rather, you should either pull it up
24 | to 3.3v+ through a small (1k) resistor or drain it down to ground through a
25 | larger (10k + 1k = 11k) resistance.
26 |
27 |
28 |
29 | Relay Driver
30 | ------------
31 | The GPIO pins on the Raspberry Pi run at 3.3v which isn't really enough to
32 | solidly throw relays. (in my case, I'm using a solid state relay but the
33 | theory is the same) This circuit uses an NPN transistor to amplify the 3.3v
34 | GPIO output to a 5v output which is enough to throw the relay.
35 |
36 |
37 |
38 | Server
39 | ======
40 | The server uses MQTT, a lightweight messaging channel over TCP, and presents a
41 | pub-sub like interface to clients. Clients connect and can publish messages which
42 | get copied to all other connected clients.
43 |
44 | To start the server:
45 |
46 | node server
47 |
48 | It will connect and listen to 0.0.0.0:1883 by default.
49 |
50 | Clients
51 | =======
52 | Clients read from and optionally write to the GPIO pins on the Raspberry Pi. Light
53 | switches are directly attached to 3.3v GPIO pins pushing them either high or low.
54 | Solid state relays to switch 120v AC loads are driven via 3.3v GPIO pins which are
55 | up-converted to 5v with a transistor. (3.3v isn't quite enough to solidly switch the
56 | Sharp S216S02 solid state relays I'm using) You may need to access GPIO pins as root
57 | depending on how you have things set up.
58 |
59 | watch.js
60 | --------
61 | Fires a callback when the GPIO pin state changes. Use this to test GPIO input
62 | functionality.
63 |
64 | blink.js
65 | --------
66 | Blinks GPIO pins on and off for 5 seconds so you can get your SSR setup working.
67 |
68 | light-switch.js
69 | ---------------
70 | Simple on or off lightswitch example, linking input and output. It does exactly
71 | what you think it does.
72 |
73 | multi-light-switch.js
74 | ---------------------
75 | Connects to the server (IP is manually set in the source) via MQTT and
76 | publishes light switch events. It works as a four position lightswitch
77 | for two lights. See the video for a demonstration of this in action.
78 |
79 | TODO
80 | ====
81 |
82 | Publish the SPI code and circuit schematic for the 120vAC current sensing capability.
83 |
--------------------------------------------------------------------------------
/blink.js:
--------------------------------------------------------------------------------
1 | var Gpio = require('onoff').Gpio,
2 | led1 = new Gpio(23, 'out'),
3 | led2 = new Gpio(24, 'out'),
4 | iv,
5 | count = 0,
6 | state = 1;
7 |
8 | iv = setInterval(function() {
9 | led1.writeSync(state);
10 | if (state)
11 | state = 0;
12 | else
13 | state = 1;
14 | led2.writeSync(state);
15 | count = count + 1;
16 | }, 500);
17 |
18 | setTimeout(function() {
19 | clearInterval(iv);
20 | console.log("count " + count);
21 | led1.writeSync(0);
22 | led1.unexport();
23 | led2.writeSync(0);
24 | led2.unexport();
25 | }, 5000);
26 |
--------------------------------------------------------------------------------
/light-switch.js:
--------------------------------------------------------------------------------
1 | var Gpio = require('onoff').Gpio,
2 | button = new Gpio(14, 'in', 'both'),
3 | led = new Gpio(23, 'out'),
4 | state = 0;
5 |
6 | function setlight(value) {
7 | console.log('Button pressed!, its value was ' + value);
8 | led.writeSync(value);
9 | button.watch(function (err, value) {
10 | if (err) throw err;
11 | if (state)
12 | state = 0;
13 | else
14 | state = 1;
15 | setlight(state);
16 | });
17 | }
18 |
19 | setlight(0);
20 |
21 | //setTimeout(function() {
22 | // led.writeSync(0);
23 | // led.unexport();
24 | // button.unexport();
25 | //}, 10000);
26 |
--------------------------------------------------------------------------------
/multi-light-switch.js:
--------------------------------------------------------------------------------
1 | var mqtt = require('mqttjs'),
2 | Gpio = require('onoff').Gpio,
3 | button = new Gpio(14, 'in', 'both'),
4 | led1 = new Gpio(23, 'out'),
5 | led2 = new Gpio(24, 'out'),
6 | state = 1;
7 |
8 | var serverIP = '192.168.1.245';
9 |
10 | mqtt.createClient(2883, serverIP, function(err, client) {
11 | if (err) process.exit(1);
12 |
13 | function setLight() {
14 | console.log('switch ' + state);
15 | led1.writeSync(state % 2 ? 0 : 1);
16 | led2.writeSync(state % 3 ? 0 : 1);
17 | client.publish({topic: 'switch state', payload: JSON.stringify(state)} );
18 | button.watch(function (err, value) {
19 | if (err) throw err;
20 | state++;
21 | if (state > 3)
22 | state = 0;
23 | setLight();
24 | });
25 | }
26 |
27 | client.connect({keepalive: 3000});
28 | console.log('connect');
29 |
30 | client.on('connack', function(packet) {
31 | if (packet.returnCode === 0) {
32 | console.log('connected '+JSON.stringify(packet));
33 | }
34 | else {
35 | console.log('connack error %d', packet.returnCode);
36 | process.exit(-1);
37 | }
38 | });
39 |
40 | client.on('close', function() {
41 | process.exit(0);
42 | });
43 |
44 | client.on('error', function(e) {
45 | console.log('error %s', e);
46 | process.exit(-1);
47 | });
48 |
49 | setLight();
50 | });
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ncs"
3 | , "description": "Node Control Server - MQTT server for collecting info from clients"
4 | , "version": "0.0.1"
5 | , "private": false
6 | , "dependencies": {
7 | "express": ">=3.11.0"
8 | , "jade": ">= 0.0.1"
9 | , "redis": ">= 0.7.1"
10 | , "socket.io": ">= 0.8.7"
11 | , "mqttjs": ">= 0.1.7"
12 | , "onoff": ">= 0.1.0"
13 | , "spi": ">= 0.0.1"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var mqtt = require('mqttjs');
2 | var readline = require('readline');
3 | var port = 1883;
4 |
5 | var rl = readline.createInterface({
6 | input: process.stdin,
7 | output: process.stdout
8 | });
9 |
10 | mqtt.createServer(function(client) {
11 | var self = this;
12 |
13 | process.stdin.resume();
14 | process.stdin.setEncoding('utf8');
15 |
16 | if (!self.clients) self.clients = {};
17 |
18 | client.on('connect', function(packet) {
19 | console.log('connection from '+packet.client);
20 | client.connack({returnCode: 0});
21 | client.id = packet.client;
22 | self.clients[client.id] = client;
23 | });
24 |
25 | client.on('publish', function(packet) {
26 | console.log('got ['+packet.topic+' | '+packet.payload+']');
27 | });
28 |
29 | client.on('subscribe', function(packet) {
30 | console.log('subscribe '+packet.subscriptions);
31 | var granted = [];
32 | for (var i = 0; i < packet.subscriptions.length; i++) {
33 | granted.push(packet.subscriptions[i].qos);
34 | }
35 |
36 | client.suback({granted: granted});
37 | });
38 |
39 | client.on('pingreq', function(packet) {
40 | console.log('pingreq');
41 | client.pingresp();
42 | });
43 |
44 | client.on('disconnect', function(packet) {
45 | console.log('disconnect');
46 | delete self.clients[client.id];
47 | client.stream.end();
48 | });
49 |
50 | client.on('close', function(err) {
51 | console.log('close');
52 | delete self.clients[client.id];
53 | });
54 |
55 | client.on('error', function(err) {
56 | console.log('error');
57 | client.stream.end();
58 | util.log('error!');
59 | });
60 |
61 | rl.on('line', function (cmd) {
62 | console.log('sending ['+cmd+']');
63 | for (var k in self.clients) {
64 | self.clients[k].publish({topic: "msg", payload: cmd});
65 | }
66 | });
67 |
68 | }).listen(port);
69 |
--------------------------------------------------------------------------------