Browse Source

Initial checkin.

master
flabbergast 9 years ago
commit
bc7a1a8315
  1. 4
      .gitignore
  2. 29
      README.md
  3. 45
      app.js
  4. 8
      llap.sublime-project
  5. 105
      modules/serial_node.js
  6. 41
      modules/socket_server.js
  7. 24
      package.json
  8. 39
      public/css/style.styl
  9. 12
      public/js/index.js
  10. 19
      public/js/socket_client.js
  11. 9
      public/vendor/bootstrap.min.css
  12. 4
      public/vendor/jquery-1.9.0.min.js
  13. 27
      views/index.jade
  14. 17
      views/layout.jade

4
.gitignore

@ -0,0 +1,4 @@
.DS_Store
node_modules
*.sublime-workspace
public/css/style.css

29
README.md

@ -0,0 +1,29 @@
##[Node-LEDS](http://www.quietless.com/kitchen/controlling-24-leds-with-node-js-and-a-raspberry-pi/)
This was a quick project to see how difficult it would be to control an Arduino microcontroller over a local network with a Raspberry PI.
To build the project you'll need to setup Node.js. [ideally on a PI if you want to build the project to spec.](http://www.quietless.com/kitchen/how-to-setup-node-js-on-a-raspberry-pi/)
Materials used in this project:
* [Raspberry PI Model B](http://www.raspberrypi.org/)
* [Arduino Leonardo](https://www.sparkfun.com/products/11286)
* [2x 400 tie pt Breadboards](https://www.sparkfun.com/products/9567)
* [1x Full Length Breadboard](https://www.sparkfun.com/products/112)
* [4x74HC595 Shift Registers](https://www.sparkfun.com/products/733)
* [7-Segment Display - 4-Digit](https://www.sparkfun.com/products/9481)
* [24 Leds](http://www.amazon.com/microtivity-IL188-Assorted-Resistors-Colors/dp/B0060FGA8A)
* [Bunch of Jumper Wires](http://www.amazon.com/Breadboard-jumper-wire-75pcs-pack/dp/B0040DEI9M)
Installation:
1. [Follow the schematic to wire everything up](http://quietless.com/docs/node-leds/node-leds.pdf)
2. Flash the sketch at /arduino/node-led/node-led.ino onto your Arduino
3. Connect the Arduino to your PI
4. Fire up the Node server by running the app via > node app
5. Point a web browser at the IP address of the PI e.g. 192.168.2.1:8080
Any questions, comments, suggestions open an issue or [post a comment on my blog.](http://www.quietless.com/kitchen/controlling-24-leds-with-node-js-and-a-raspberry-pi/)
![Node-LEDS-schematic](http://quietless.com/docs/node-leds/node-leds.png "Node-LEDS-schematic")

45
app.js

@ -0,0 +1,45 @@
/**
* Node-Serial
* Author: flabbergast
* based on node-leds by Stephen Braitsch (https://github.com/braitsch/node-leds)
*/
var express = require('express')
, http = require('http')
, port = require('./modules/serial_node')
, socket = require('./modules/socket_server');
var app = express();
app.configure(function(){
app.set('port', 8080);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.locals.pretty = true;
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'super-duper-secret-secret' }));
app.use(express.methodOverride());
app.use(require("stylus").middleware({
compress: true,
src: __dirname + "/public"
}));
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
/* ROUTES */
app.get('/', function(req, res){
res.render('index');
});
/* start the node server & initialize socket-io */
var server = http.createServer(app).listen(app.get('port'), function(){
socket.init(require('socket.io').listen(server));
console.log("Express server listening at", server.address());
});

8
llap.sublime-project

@ -0,0 +1,8 @@
{
"folders":
[
{
"path": "/Users/js/Documents/Programming/Node/llap"
}
]
}

105
modules/serial_node.js

@ -0,0 +1,105 @@
/*
Public API
*/
exports.writeNumber = function(n)
{
// parse number into multiplier and remainder //
var m = Math.floor(n/255);
var r = n%255;
var data = [1, m, r];
console.log('sending over serial ::', data);
sendDataOverSerial(new Buffer(data));
}
exports.getPath = function()
{
if(serport) {
return serport.path;
} else {
return "not connected";
}
}
/*
Private Methods
*/
var serport;
var socket = require('./socket_server');
var serialport = require('serialport');
var exec = require('child_process').exec;
/*
Attempt to connect to a serial port
*/
var detectSerialOnOSX = function()
{
var port;
console.log('* attempting to detect a serial port on mac osx *');
exec('ls /dev/tty.*', function(error, stdout, stderr){
if (stdout){
var ports = stdout.split('\n');
for (var i = ports.length - 1; i >= 0; i--){
if (ports[i].search('usbmodem') != -1 || ports[i].search('usbserial') != -1) port = ports[i];
}
}
if (port){
attemptConnection(port);
} else{
detectSerialOnRaspberryPI();
}
});
}
var detectSerialOnRaspberryPI = function()
{
var port;
console.log('* attempting to connect to a serial port on raspberry pi *');
serialport.list(function (e, ports) {
ports.forEach(function(obj) {
if (obj.hasOwnProperty('pnpId')){
// FTDI captures the duemilanove //
// Arduino captures the leonardo //
if (obj.pnpId.search('FTDI') != -1 || obj.pnpId.search('Arduino') != -1) {
port = obj.comName;
}
}
});
if (port){
attemptConnection(port);
} else{
console.log('* failed to find a serial port : please check your connections *');
}
});
}
var attemptConnection = function(port)
{
console.log('* attempting to connect to serial at :', port, ' *');
serport = new serialport.SerialPort(port, { baudrate: 9600, parser: serialport.parsers.readline("\n") });
serport.on("open", function () {
console.log('* connection to a serial port successful ! *');
serport.on('data', function(data){
// send incoming data from serport out to the socket server //
socket.onDataOverSerial(data);
});
});
}
var sendDataOverSerial = function(buffer)
{
// calling write if an serport is not connected will crash the server! //
if (serport){
serport.write(buffer, function(e, results) {
if (e) {
console.log('error :: ' + e);
} else{
// console.log('message successfully sent');
}
});
}
}
detectSerialOnOSX();

41
modules/socket_server.js

@ -0,0 +1,41 @@
var sockets;
var serport = require('./serial_node');
var activeUser;
/*
TODO - need to store the current animation & autoMode setting on the server
*/
exports.init = function(io){
sockets = io.sockets;
io.set('log level', 1);
sockets.on('connection', function (socket) {
// only allow the most recent connected user to interact with serial //
activeUser = socket;
// tell client they have successfully connected to the server and wait for their response //
socket.emit('connected-to-server', {
// transmit current status
});
// listen for the client to tell us who they are //
socket.on('connected-client-response', function(data){
socket.user = data;
onUserConnected(socket);
});
// transmit info about the server on request
socket.on('request-server-info', function (data) {
socket.emit('server-info-response', { serialPort: serport.getPath() });
});
});
};
exports.onDataOverSerial = function(data){
console.log('onDataOverSerial', data);
// process data received
};
var onUserConnected = function(socket)
{
serport.writeNumber(socket.user.id);
// here comes socket.on('something-happens', ...)
}

24
package.json

@ -0,0 +1,24 @@
{
"name": "node-led",
"version": "0.0.1",
"author": {
"name": "Stephen Braitsch",
"email": "stephen@fuseproject.com"
},
"repository": {
"type": "git",
"url": "git@github.com:fuseproject/node-led.git"
},
"private": true,
"dependencies": {
"express": "3.1.0",
"jade": "0.28.1",
"stylus": "0.32.0",
"socket.io": "0.9.12",
"serialport": "https://github.com/voodootikigod/node-serialport/tarball/master"
},
"engines": {
"node": "0.8.18",
"npm": "1.2.2"
}
}

39
public/css/style.styl

@ -0,0 +1,39 @@
raiseText()
color grey
text-shadow: -1px 1px 0 white
-moz-text-shadow: -1px 1px 0 white
-webkit-text-shadow: -1px 1px 0 white
html, body
margin 0
padding 0
body
height 100%
background-color #EEE
.navbar-inner
padding 0
.navbar-inner .brand
width 100%
margin 0
text-align center
.navbar .brand
padding 10px 0 10px 0
#wrapper
padding 15px 50px 0 50px
margin auto
footer
text-align center
padding 30px 0
margin-top 70px
border-top 1px solid #e5e5e5
background-color #f5f5f5
.footer p
margin-bottom 0
color #777

12
public/js/index.js

@ -0,0 +1,12 @@
$(document).ready(function(){
$('#wrapper #serialtalk #serialtalk-btn').click(function(e){
// handle the button press
/* useful fns: $(e.target).attr('id') .addClass('btn-warning')
if (socket && socket_connected){
socket.emit('animation-selected', { id:n });
}
*/
});
});

19
public/js/socket_client.js

@ -0,0 +1,19 @@
var socket = io.connect('/');
var socket_connected = false;
var autoMode;
socket.on('connected-to-server', function (data) {
// update the view based with the current server settings //
// generate a random id for this newly connected user //
var id = Math.floor(Math.random()*9999);
$('#user-id').html('Connected : <span style="color:blue">'+id+'</span>');
socket_connected = true;
socket.emit('connected-client-response', { id:id });
socket.emit('request-server-info', {});
});
socket.on('server-info-response', function (data) {
$('footer #serial-port-elt').html('<span>'+data.serialPort+'</span>');
});

9
public/vendor/bootstrap.min.css

File diff suppressed because one or more lines are too long

4
public/vendor/jquery-1.9.0.min.js

File diff suppressed because one or more lines are too long

27
views/index.jade

@ -0,0 +1,27 @@
extends layout
block content
.navbar
.navbar-inner
#user-id.brand
#wrapper
#serialtalk(style="text-align: center;")
//form.form-inline
.input-append
input#serialtalk-text.span2(type="text", placeholder="LLAP message")
button#serialtalk-btn.btn Send
p Last response:&nbsp;
span#serialtalk-resp nothing yet
block footer
p <strong>Server info:</strong>&nbsp;
| #{process.title}:[#{process.version}]
| serial-port:[
span#serial-port-elt
|]
block scripts
script(src='/js/index.js')
script(src="/socket.io/socket.io.js")
script(src='/js/socket_client.js')

17
views/layout.jade

@ -0,0 +1,17 @@
!!! 5
html
head
title Node LED
link(rel='stylesheet', href='/vendor/bootstrap.min.css')
link(rel='stylesheet', href='/css/style.css')
meta(http-equiv="cache-control", content="no-cache")
meta(name="apple-touch-fullscreen", content="yes")
meta(name="apple-mobile-web-app-capable", content="yes")
meta(name="apple-mobile-web-app-status-bar-style", content="black")
meta(name="viewport", content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0")
body
block content
footer.footer
block footer
script(src='/vendor/jquery-1.9.0.min.js')
block scripts
Loading…
Cancel
Save