Created
October 2, 2014 14:42
-
-
Save jskrzypek/8538378f4ad28de31a6e to your computer and use it in GitHub Desktop.
Tesselopticon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this is modified from Ben Nadel's Buffer Stream gist at https://gist.github.com/bennadel/b35f3a15cb3b03ddbcf8/ | |
// Required module references. | |
var stream = require( "stream" ); | |
// var chalk = require( "chalk" ); | |
var util = require( "util" ); | |
// var http = require( "http" ); | |
// var fileSystem = require( "fs" ); | |
// ---------------------------------------------------------- // | |
// ---------------------------------------------------------- // | |
// I turn the given source Buffer into a Readable stream. | |
function BufferStream( source ) { | |
if ( ! Buffer.isBuffer( source ) ) { | |
throw( new Error( "Source must be a buffer." ) ); | |
} | |
// Super constructor. | |
stream.Readable.call( this ); | |
this._source = source; | |
// I keep track of which portion of the source buffer is currently being pushed | |
// onto the internal stream buffer during read actions. | |
this._offset = 0; | |
this._length = source.length; | |
// When the stream has ended, try to clean up the memory references. | |
this.on( "end", this._destroy ); | |
} | |
util.inherits( BufferStream, stream.Readable ); | |
// I attempt to clean up variable references once the stream has been ended. | |
// -- | |
// NOTE: I am not sure this is necessary. But, I'm trying to be more cognizant of memory | |
// usage since my Node.js apps will (eventually) never restart. | |
BufferStream.prototype._destroy = function() { | |
this._source = null; | |
this._offset = null; | |
this._length = null; | |
}; | |
// I read chunks from the source buffer into the underlying stream buffer. | |
// -- | |
// NOTE: We can assume the size value will always be available since we are not | |
// altering the readable state options when initializing the Readable stream. | |
BufferStream.prototype._read = function( size ) { | |
// If we haven't reached the end of the source buffer, push the next chunk onto | |
// the internal stream buffer. | |
if ( this._offset < this._length ) { | |
this.push( this._source.slice( this._offset, ( this._offset + size ) ) ); | |
this._offset += size; | |
} | |
// If we've consumed the entire source buffer, close the readable stream. | |
if ( this._offset >= this._length ) { | |
this.push( null ); | |
} | |
}; | |
// ---------------------------------------------------------- // | |
// ---------------------------------------------------------- // | |
// Read the file into memory. We're using the "Sync" version of this to reduce the | |
// complexity of the exploration. | |
// var tankGirlBuffer = fileSystem.readFileSync( "./tank-girl.png" ); | |
// Create a web server that streams the cached file back on every request. | |
// var server = http.createServer( | |
// function handleHttpRequest( request, response ) { | |
// // We're hard-coding this stuff since there's nothing dynamic about the demo. | |
// response.writeHead( | |
// 200, | |
// "OK", | |
// { | |
// "Content-Type": "image/png", | |
// "Content-Disposition": "inline; filename=tank-girl.png", | |
// "Contente-Length": tankGirlBuffer.length | |
// } | |
// ); | |
// // Crate a new instance of the Buffer Stream to wrap the cached buffer. Then, | |
// // pipe that stream into the HTTP response. | |
// // -- | |
// // NOTE: Once the BufferStream "ends", it will automatically end the HTTP | |
// // response stream as well. | |
// new BufferStream( tankGirlBuffer ) | |
// .pipe( response ) | |
// ; | |
// } | |
// ); | |
// server.listen( 8080 ); | |
// console.log( chalk.yellow( "Server running on port 8080." ) ); | |
module.exports = BufferStream; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var express = require('express') | |
, router = express.Router() | |
, fs = require('fs') | |
, http = require('http') | |
, fluent = require('fluent-ffmpeg') | |
, ws = require('nodejs-websocket') | |
// , stream = require('stream') | |
, MjpegServer = require('mjpeg-server'); | |
// , mjpegServer = require('mjpeg-proxy'); | |
// http.createServer(function(req, res) { | |
// mjpegReqHandler = mjpegServer.createReqHandler(req, res); | |
// }).listen(8081); | |
var namestring = '/Users/jskrzypek/Documents/Fullstack/Projects/tessel/tesselopticon/server/resources/'; | |
var mjpegStream; | |
http.createServer(function(req, res){ | |
mjpegStream = mjpegServer.createReqHandler(req, res); | |
}).listen(8001); | |
var ws_port = 8000; | |
var counter = 0; | |
// var mjpegServer = new stream.Readable(); | |
// Create the websocket server, provide connection callback | |
var server = ws.createServer(function (conn) { | |
console.log("New connection"); | |
// If we get text from the client, and echo it | |
conn.on('binary', function (stream) { | |
// print it out | |
console.log("Stream opened") | |
// Send it back (but more excited) | |
// stream.pipe(mjpegStream); | |
// fs.open | |
stream.pipe(fs.createWriteStream(namestring + counter + '.jpg', | |
{ flags: 'r+', | |
encoding: null, | |
mode: 0666 })); | |
// conn.sendText("Receiving stream"); | |
}); | |
conn.on | |
// When the client closes the connection, notify us | |
conn.on("close", function (code, reason) { | |
console.log("Connection closed") | |
}); | |
}).listen(ws_port); | |
console.log('listening on port', ws_port); | |
/* GET home page. */ | |
router.get('/', function(req, res) { | |
res.render('../views/index.html', { title: 'Express' }); | |
}); | |
router.get('/stream.mjpg', function(req, res) { | |
console.log('trying to stream'); | |
res.writeHead(200, { | |
'Content-Type': 'multipart/x-mixed-replace; boundary=myboundary', | |
'Cache-Control': 'no-cache', | |
'Connection': 'close', | |
'Pragma': 'no-cache' | |
}); | |
var i = 0; | |
var stop = false; | |
res.connection.on('close', function() { stop = true; }); | |
var send_next = function() { | |
if (stop) | |
return; | |
i = (i+1) % 150; | |
var filename = i + ".jpg"; | |
fs.readFile(namestring + filename, function (err, content) { | |
res.write("--myboundary\r\n"); | |
res.write("Content-Type: image/jpeg\r\n"); | |
res.write("Content-Length: " + content.length + "\r\n"); | |
res.write("\r\n"); | |
res.write(content, 'binary'); | |
res.write("\r\n"); | |
setTimeout(send_next, 500); | |
}); | |
}; | |
send_next(); | |
}); | |
router.post('/post/:name', function(req, res) { | |
console.log('Receiving post...'); | |
var name = req.params.name; | |
console.log(name); | |
// fs.createWriteStream('/Users/jskrzypek/Desktop/tpics/test-' + name).pipe(req); | |
req.pipe(fs.createWriteStream('/Users/jskrzypek/Desktop/tpics/test_dir/test-' + name)); | |
// req.pipe() | |
// res.send('200'); | |
res.end(); | |
}); | |
module.exports = router; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//################################Setup################################################## | |
var ws = require('nodejs-websocket'); | |
var tessel = require('tessel'); | |
var camera = require('camera-vc0706').use(tessel.port['A']); | |
// var wifi = require('wifi-cc3000'); | |
var servolib = require('servo-pca9685'); | |
var EventEmitter = require('events').EventEmitter, | |
BufferStream = require('./bufStream'); | |
// fs = require('fs'); | |
// Readable = require('stream').Readable; | |
var servo = servolib.use(tessel.port['B']); | |
var servo1 = 1; // We have a servo plugged in at position 1 | |
var snapShotDuration = 2000; | |
// var counter = 0; | |
var timer = new EventEmitter(); | |
// , saver = new EventEmitter(); | |
var nameArray = [] | |
, imageArray = []; | |
var position = 0 | |
, direction = 1 | |
, increment = .05; // Target position of the servo between 0 (min) and 1 (max). | |
// var notificationLED = tessel.led[3]; // Set up an LED to notify when we're taking a picture | |
var ws_port = 8000; | |
// INSERT TESSEL IP ADDRESS HERE. Always prepend with 'ws://' to indicate websocket | |
var ws_connection = ws.connect('ws://192.168.1.82:' + ws_port, function() { | |
// When we connect to the server, send some catchy text | |
console.log('Opened a websocket') | |
ws_connection.sendText('Opened tessel websocket'); | |
}); | |
var counter = 0; | |
ws.setBinaryFragmentation(200); | |
// request = require('request'), | |
// var post_options = { | |
// hostname: '192.168.1.82' | |
// , port: 3000 | |
// , path: '/post/'+name | |
// , method: 'POST' | |
// , 'Content-Type': 'image/jpeg' | |
// // , 'Content-Type': 'multipart/x-mixed-replace;boundary="' + boundary + '"' | |
// }; | |
//###################################EventListeners######################################### | |
// When we get text back | |
ws_connection.on('text', function(text) { | |
// print it out | |
console.log("Echoed back from server:", text); | |
}); | |
// wifi.on('disconnect', function() { console.log("wifi dropped"); }); | |
camera.on('ready', function () { | |
console.log("camera is ready"); | |
// notificationLED.high(); | |
// Take the picture | |
timer.on('tick', | |
function(){ camera.takePicture( | |
function(err, picture) { | |
if (err) { | |
console.log("Camera: ", err); | |
} else { | |
console.log("Camera: Took a picture."); | |
postBuf(picture); | |
// process.sendfile(counter++ + '.jpg', picture); | |
// nameArray.unshift(Date.now() + '.jpg'); | |
// imageArray.unshift(picture); | |
} | |
} | |
); | |
}); | |
}); | |
var postBuf = function (picture) { | |
var picBuf = new BufferStream(picture); | |
console.log('making ws post'); | |
var ws_stream = ws_connection.beginBinary(); | |
picBuf.pipe(ws_stream) | |
.on('finish', function() { | |
ws_stream.end(); | |
console.log('Piping finished'); | |
// timer.emit('ready'); | |
} | |
); | |
// timer.emit('ready'); | |
}; | |
camera.on('error', function (err) { | |
console.log("Camera: got an error"); | |
console.error(err); | |
}); | |
var emitTick = function () { | |
console.log('tick @ ' + Date.now()); | |
timer.emit('tick'); | |
position += increment * direction; | |
if (position > 1 || position < 0) { | |
direction = (direction > 0) ? -1 : 1; // change servo direction | |
position += 2 * increment * direction; | |
} | |
}; | |
timer.on('ready',function(){ | |
if (wifi.isConnected()) { | |
emitTick(); | |
} else { | |
wifi.on('connect', emitTick()); | |
} | |
}) | |
setInterval(function(){emitTick();}, 2000); | |
// The camera emits 'picture' when a picture is taken | |
// camera.on('picture', function(pic) { | |
// // nameArray.pop(), pic = imageArray.pop(); | |
// console.log('Camera: Picture saving as', name, '...'); | |
// // nameArray.push(name); | |
// // imageArray.push(pic); | |
// // console.log("pushed picture ", nameArray.length); | |
// // process.sendfile('lastFrame', new Buffer(name)); | |
// // process.sendfile(name, pic); | |
// // timer.emit('ready'); | |
// postBuf(pic); | |
// }); | |
// var connected = function(){ | |
// camera.on('picture', function(pic) { | |
// var name = Date.now() + '.jpg'; | |
// // nameArray.pop(), pic = imageArray.pop(); | |
// // console.log('Camera: Picture saving as', name, '...'); | |
// // nameArray.push(name); | |
// // imageArray.push(pic); | |
// console.log("pushed picture ", nameArray.length); | |
// // process.sendfile("name, pic"); | |
// postBuf(name, pic); | |
// }); | |
// }; | |
// var disconnected = function(){ | |
// camera.on('picture', function(pic) { | |
// var name = Date.now() + '.jpg'; | |
// // nameArray.pop(), pic = imageArray.pop(); | |
// // console.log('Camera: Picture saving as', name, '...'); | |
// nameArray.push(name); | |
// imageArray.push(pic); | |
// console.log("pushed picture ", nameArray.length); | |
// // process.sendfile("name, pic"); | |
// // postBuf(name, pic); | |
// }); | |
// }; | |
// var wifi_connector = wifi | |
// http.request( | |
// // http request options | |
// // post_options, | |
// { | |
// hostname: '192.168.1.82' | |
// , port: 3000 | |
// , path: '/post/'+name | |
// , method: 'POST' | |
// , 'Content-Type': 'image/jpeg' | |
// // , 'Content-Type': 'multipart/x-mixed-replace;boundary="' + boundary + '"' | |
// }, | |
// function (res) { | |
// // res.setEncoding('utf8'); | |
// res.on('data',function (chunk) { | |
// console.log('body:' + chunk); | |
// }); | |
// } | |
// ) | |
// var picture = fs.readFileSync('/Users/jskrzypek/Desktop/tpics/picture-3ms.jpg'); | |
// saver.on('picture', function(){ | |
// picture.pipe(request.post( | |
// '0.0.0.0:3000/post/picture_savetest.jpg', | |
// function (err, res) { | |
// if (!err && res === '200') { | |
// console.log('done.'); | |
// } else { | |
// console.log('something broke.', err); | |
// } | |
// } | |
// )); | |
// }) | |
// setTimeout(saver.emit('picture'),1000); | |
// var snapShot = function () { | |
// camera.takePicture(function (err, image) { | |
// if (err) { | |
// console.log('error taking image', err); | |
// } else { | |
// //notificationLED.low(); | |
// // Name the image | |
// var name = 'picture-' + counter + 'ms.jpg'; | |
// nameArray.push(name); | |
// // Save the image | |
// console.log('Picture saving as', name, '...'); | |
// // process.sendfile(name, image); | |
// var buf = new Buffer(image.length); | |
// image.copy(buf); | |
// imageArray.push(buf); | |
// // console.log('done.'); | |
// // delete(image); | |
// // // Turn the camera off to end the script | |
// // camera.disable(); | |
// } | |
// }); | |
// }; | |
// servo.on('ready', function () { | |
// // Set the minimum and maximum duty cycle for servo 1. | |
// // If the servo doesn't move to its full extent or stalls out | |
// // and gets hot, try tuning these values (0.05 and 0.12). | |
// // Moving them towards each other = less movement range | |
// // Moving them apart = more range, more likely to stall and burn out | |
// servo.configure(servo1, 0.07, 0.1, function () { | |
// servo.move(servo1, 0); | |
// timer.on('tick',function () { | |
// console.log('Position (in range 0-1):', position, 'at ', Date.now(), 'ms'); | |
// servo.move(servo1, position); | |
// }); | |
// }); | |
// }); | |
// saver.on('save', function(){ | |
// if (nameArray.length > 0 && imageArray.length > 0) {} | |
// var nm = nameArray.shift(), im = imageArray.shift(); | |
// console.log('Picture saving as', nm, '...'); | |
// // cable upload route | |
// process.sendfile(nm, im); | |
// // post route | |
// var reader = new | |
// .request.post( | |
// '0.0.0.0:3000/post/'+nm, | |
// function (err, res) { | |
// if (!error && res === '200') { | |
// console.log('done.'); | |
// } else { | |
// console.log('something broke.', err); | |
// } | |
// } | |
// ); | |
// // saving done, move to next image | |
// saver.emit('save'); | |
// } else { | |
// setTimeout(saver.emit('save'), 1000); | |
// } | |
// }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment