|
| 1 | +var gpio = require("gpio"); |
| 2 | +gpio.logging = true; |
| 3 | + |
| 4 | + |
| 5 | +// The gpio ids we're using. Note that these aren't the pin numbers, but |
| 6 | +// the IDs exposed by the Pi. Search for Pi GPIO pinout for details. |
| 7 | +var ledGPIOID = 4; //actually pin 7, 4 down on left header |
| 8 | +var buttonGPIOID = 17; |
| 9 | +var relayGPIOID = 18; |
| 10 | + |
| 11 | +// Handles for our connected gpio devices |
| 12 | +var ledDevice; |
| 13 | +var buttonDevice; |
| 14 | +var relayDevice; |
| 15 | + |
| 16 | +// A collection of all connected sockets. |
| 17 | +// Maps socketid => { socket: sockethandle, id: socketid } |
| 18 | +var connections = {}; |
| 19 | + |
| 20 | +exports.settings={}; |
| 21 | +//These are dynamically updated by the runtime |
| 22 | +//settings.appname - the app id (folder) where your app is installed |
| 23 | +//settings.viewpath - prefix to where your view html files are located |
| 24 | +//settings.staticurl - base url path to static assets /static/apps/appname |
| 25 | +//settings.appurl - base url path to this app /app/appname |
| 26 | +//settings.device_name - name given to this coder by the user, Ie."Billy's Coder" |
| 27 | +//settings.coder_owner - name of the user, Ie. "Suzie Q." |
| 28 | +//settings.coder_color - hex css color given to this coder. |
| 29 | + |
| 30 | +// Incoming get routes that our app knows how to respond to |
| 31 | +exports.get_routes = [ |
| 32 | + { path:'/', handler:'index_handler' }, // Render out main html page |
| 33 | +]; |
| 34 | + |
| 35 | +// Incoming post routes that our app knows how to respond to |
| 36 | +// (None in this example) |
| 37 | +exports.post_routes = [ |
| 38 | +]; |
| 39 | + |
| 40 | +// Incoming socket events that this module will expose. |
| 41 | +exports.socketio_routes = [ |
| 42 | + { key:'connect', handler:'on_socket_connect' }, // sent by client once socket is loaded |
| 43 | + { key:'setled', handler:'on_socket_setled' }, // sent by client to turn on/off the led |
| 44 | + { key:'setrelay', handler:'on_socket_setrelay' }, // sent by client to turn on/off the relay |
| 45 | +]; |
| 46 | + |
| 47 | + |
| 48 | + |
| 49 | +// |
| 50 | +// Handles sending the HTML page to the browser |
| 51 | +// |
| 52 | +exports.index_handler = function( req, res ) { |
| 53 | + // Set up some template variables that are substituted in our HTML. |
| 54 | + // Look in the HTML head tag to see where these are inserted. |
| 55 | + var tmplvars = {}; |
| 56 | + tmplvars['static_url'] = exports.settings.staticurl; |
| 57 | + tmplvars['app_name'] = exports.settings.appname; |
| 58 | + tmplvars['app_url'] = exports.settings.appurl; |
| 59 | + tmplvars['device_name'] = exports.settings.device_name; |
| 60 | + |
| 61 | + // Send the HTML document to the web browser. |
| 62 | + res.render( exports.settings.viewpath + '/index', tmplvars ); |
| 63 | +}; |
| 64 | + |
| 65 | + |
| 66 | +// |
| 67 | +// Respond to the "connect" message sent by a new socket client. |
| 68 | +// |
| 69 | +// We do two things here: |
| 70 | +// 1. save the socket object into the "connections" variable so we can talk to it later. |
| 71 | +// 2. initialize the GPIO pins if this is the first time a socket has connected. |
| 72 | +// |
| 73 | +exports.on_socket_connect = function( socket, data ) { |
| 74 | + console.log( 'socket connect from ID: ' + socket.socketID ); |
| 75 | + console.log( data ); |
| 76 | + |
| 77 | + // Enable the GPIO pins if this is the first connection |
| 78 | + if ( Object.keys( connections ).length <= 0 ) { |
| 79 | + enableGPIO(); |
| 80 | + } |
| 81 | + |
| 82 | + // Store information about this socket so we can communicate with |
| 83 | + // all connected sockets in the future. |
| 84 | + connections[socket.socketID] = { |
| 85 | + socket: socket, |
| 86 | + id: socket.socketID |
| 87 | + }; |
| 88 | + |
| 89 | + // Watch for this socket to disconnect so that we can remove it from |
| 90 | + // our collection of connected sockets. |
| 91 | + socket.on('disconnect', function() { |
| 92 | + console.log( 'socket disconnect from ID: ' + socket.socketID ); |
| 93 | + delete connections[socket.socketID]; |
| 94 | + |
| 95 | + //Free up the GPIO when the last socket disconnects |
| 96 | + if ( Object.keys( connections ).length <= 0 ) { |
| 97 | + disableGPIO(); |
| 98 | + connected = false; |
| 99 | + } |
| 100 | + }); |
| 101 | + |
| 102 | +}; |
| 103 | + |
| 104 | +// |
| 105 | +// Respond to a "setled" message from a socket connection to update the LED value |
| 106 | +// |
| 107 | +exports.on_socket_setled = function( socket, data ) { |
| 108 | + if ( data.value !== "undefined" ) { |
| 109 | + setLED( data.value ); |
| 110 | + } |
| 111 | +}; |
| 112 | + |
| 113 | +// |
| 114 | +// Respond to a "setrelay" message from a socket connection to update the relay value |
| 115 | +// |
| 116 | +exports.on_socket_setrelay = function( socket, data ) { |
| 117 | + if ( data.value !== "undefined" ) { |
| 118 | + setRelay( data.value ); |
| 119 | + } |
| 120 | +}; |
| 121 | + |
| 122 | +// |
| 123 | +// This is called once from our first socket connection. |
| 124 | +// - set up the LED GPIO as an output |
| 125 | +// - set up the Button GPIO as an input and tie it to send a "change" message |
| 126 | +// |
| 127 | +var enableGPIO = function() { |
| 128 | + |
| 129 | + // Set up the LED output GPIO |
| 130 | + console.log("Setting up LED as an output on GPIO " + ledGPIOID ); |
| 131 | + ledDevice = gpio.export( ledGPIOID, { |
| 132 | + ready: function() { |
| 133 | + // This works around a bug in gpio, where sometimes this device |
| 134 | + // doesn't become immediately available. |
| 135 | + setTimeout( function() { |
| 136 | + ledDevice.setDirection("out"); |
| 137 | + }, 100); //wait 100 ms before setting direction |
| 138 | + } |
| 139 | + }); |
| 140 | + |
| 141 | + console.log("Setting up Relay as an output on GPIO " + relayGPIOID ); |
| 142 | + relayDevice = gpio.export( relayGPIOID, { |
| 143 | + direction: "out", |
| 144 | + ready: function() { |
| 145 | + // This works around a bug in gpio, where sometimes this device |
| 146 | + // doesn't become immediately available. |
| 147 | + setTimeout( function() { |
| 148 | + relayDevice.setDirection("out"); |
| 149 | + }, 400); //wait 100 ms before setting direction |
| 150 | + } |
| 151 | + }); |
| 152 | + |
| 153 | + // Set up the button input GPIO |
| 154 | + console.log("Setting up Button as an input on GPIO" + buttonGPIOID); |
| 155 | + buttonDevice = gpio.export( buttonGPIOID, { |
| 156 | + direction: "in", |
| 157 | + ready: function() { |
| 158 | + |
| 159 | + // Set up buttonDevice to call the buttonChange |
| 160 | + // function (below) whenever its value changes. |
| 161 | + buttonDevice.on("change", buttonChange); |
| 162 | + } |
| 163 | + }); |
| 164 | + |
| 165 | +}; |
| 166 | + |
| 167 | +// |
| 168 | +// This is called when the last socket disconnects. |
| 169 | +// It releases our GPIO pins so they can be used by another program. |
| 170 | +// |
| 171 | +var disableGPIO = function() { |
| 172 | + console.log("Disabling GPIO" + ledGPIOID ); |
| 173 | + ledDevice.removeAllListeners(); |
| 174 | + ledDevice.reset(); |
| 175 | + ledDevice.unexport(); |
| 176 | + |
| 177 | + console.log("Disabling GPIO" + relayGPIOID ); |
| 178 | + relayDevice.removeAllListeners(); |
| 179 | + relayDevice.reset(); |
| 180 | + relayDevice.unexport(); |
| 181 | + |
| 182 | + console.log("Disabling GPIO" + buttonGPIOID ); |
| 183 | + buttonDevice.removeAllListeners(); |
| 184 | + buttonDevice.reset(); |
| 185 | + buttonDevice.unexport(); |
| 186 | +}; |
| 187 | + |
| 188 | +// |
| 189 | +// This is triggered by the GPIO "change" event on buttonDevice. This was |
| 190 | +// set up inside emabledGPIO(). |
| 191 | +// |
| 192 | +// The change event sends this function a value, either 0 (off) or 1 (on). |
| 193 | +// |
| 194 | +var buttonChange = function( val ) { |
| 195 | + // Recall that this code is running on the device. We need to send a |
| 196 | + // socket message with the button data to our javascript in the |
| 197 | + // web browser. In fact, we need to send this data to every connected |
| 198 | + // socket, since there may be more than one browser window looking at |
| 199 | + // this page. |
| 200 | + |
| 201 | + console.log( "buttonChange event with value: " + val ); |
| 202 | + |
| 203 | + // Iterate through all of our socket connections |
| 204 | + for ( var socketid in connections ) { |
| 205 | + // Get the socket object for this socket |
| 206 | + var socket = connections[socketid].socket; |
| 207 | + |
| 208 | + // The "appdata" event will be received by the Coder.socketConnection |
| 209 | + // object in the front end code and sent to the appropriate listener |
| 210 | + // that we've defined. |
| 211 | + // The "buttonupdate" key refers to a listener we set up on the front |
| 212 | + // end with the code: |
| 213 | + // Coder.socketConnection.addListener( "buttonupdate", function... ) |
| 214 | + socket.emit( "appdata", { |
| 215 | + key: "buttonupdate", |
| 216 | + data: val |
| 217 | + }); |
| 218 | + } |
| 219 | +}; |
| 220 | + |
| 221 | +// |
| 222 | +// Set the value on the LED GPIO device, either 0 (off) or 1 (on). |
| 223 | +// |
| 224 | +var setLED = function( val ) { |
| 225 | + val = parseInt( val ); |
| 226 | + if ( val != 0 ) { |
| 227 | + val = 1; |
| 228 | + } |
| 229 | + ledDevice.set( val ); |
| 230 | +}; |
| 231 | + |
| 232 | +var setRelay = function( val ) { |
| 233 | + val = parseInt( val ); |
| 234 | + if ( val != 0 ) { |
| 235 | + val = 1; |
| 236 | + } |
| 237 | + relayDevice.set( val ); |
| 238 | +}; |
| 239 | + |
| 240 | +// |
| 241 | +// Called by Coder whenever this module is reloaded. This usually happens when |
| 242 | +// you save your code in the editor. This is a good place to destroy any intervals |
| 243 | +// or clean up any long running code or handles. |
| 244 | +// |
| 245 | +exports.on_destroy = function() { |
| 246 | +}; |
| 247 | + |
| 248 | + |
| 249 | + |
0 commit comments