Skip to content

Instantly share code, notes, and snippets.

@jskrzypek
Created October 2, 2014 14:42
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jskrzypek/8538378f4ad28de31a6e to your computer and use it in GitHub Desktop.
Tesselopticon
// 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;
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;
//################################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