Skip to content

Commit

Permalink
Merge pull request #19 from pcnate/fixes
Browse files Browse the repository at this point in the history
Fixes
  • Loading branch information
pcnate authored Dec 2, 2018
2 parents cd7dcfb + 2fb9fd9 commit aa69763
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 45 deletions.
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
# raspberry-pi-camera
nodejs camera application to upload images to server
nodejs raspberry pi camera application to upload images to server. It is designed to be setup once and left alone. Additional configuration will be added to the server side.

Server software https://github.com/pcnate/raspberry-pi-camera-server
> You will need a server to receive the image stream generated by the camera. I recommend [raspberry-pi-camera-server](https://github.com/pcnate/raspberry-pi-camera-server)
# Standalone Install

1) setup a server
2) `npm install -g @pcnate/raspberry-pi-camera`
3) enter url to upload to
4) leave GUID blank
5) leave image path alone, (stores in RAM to save SD card)
1) `npm install -g @pcnate/raspberry-pi-camera`
2) probably need ot exit terminal and reopen/reconnect
3) `raspberry-pi-camera-config`
4) `raspberry-pi-camera`

# Automatic startup with pm2

1) `npm install -g pm2`
2) `pm2 startup`
3) `pm2 install @pcnate/raspberry-pi-camera`
1) `npm install -g pm2 @pcnate/raspberry-pi-camera`
2) probably need to exit terminal and reopen/reconnect
3) `pm2 startup`
4) `raspberry-pi-camera-config`
5) `pm2 start raspberry-pi-camera --name cam`
6) `pm2 save`

# Configuration

1) `raspberry-pi-camera-config`
2) enter url to upload to
3) leave GUID blank
4) leave image path alone, (stores in RAM to save SD card)
22 changes: 10 additions & 12 deletions configure.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
#!/usr/bin/env node

const dotenv = require('dotenv');
const paths = require('./paths');
const fs = require("fs-extra");
const util = require("util");
const ini = require("ini");
const prompt = require("prompt");
const promptGet = util.promisify( prompt.get );
const uuidv5 = require("uuid/v5");
const dotenv = require('dotenv'),
paths = require('./paths'),
fs = require("fs-extra"),
util = require("util"),
ini = require("ini"),
prompt = require("prompt"),
promptGet = util.promisify( prompt.get ),
uuidv5 = require("uuid/v5"),
schema = require('./schema');

dotenv.config({
path: paths.configFilePath
});

// default values
var schema = require('./schema');

( async() => {

for ( const key in schema.properties ) {
Expand All @@ -35,7 +33,7 @@ var schema = require('./schema');
const result = await promptGet( schema );

// generate a new GUID if none is specified
result.deviceID = result.deviceID == schema.GEN_ID ? result.deviceID = uuidv5( result.uploadURL, uuidv5.URL ) : result.deviceID;
result.deviceID = result.deviceID == schema.GEN_ID ? uuidv5( result.uploadURL, uuidv5.URL ) : result.deviceID;

// save the file
await fs.writeFile( paths.configFilePath, ini.stringify( result ) );
Expand Down
9 changes: 7 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{
"name": "@pcnate/raspberry-pi-camera",
"version": "0.0.6",
"version": "0.0.7",
"description": "nodejs camera application to connect to server via socket.io",
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon emulate.js",
"configure": "node configure.js",
"postinstall": "node configure.js"
"configure": "node configure.js"
},
"bin": {
"raspberry-pi-camera": "./server.js",
Expand All @@ -22,6 +21,7 @@
},
"homepage": "https://github.com/pcnate/raspberry-pi-camera#readme",
"dependencies": {
"await-sleep": "0.0.1",
"dotenv": "^6.1.0",
"form-data": "^2.3.2",
"fs-extra": "^7.0.1",
Expand Down
92 changes: 74 additions & 18 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#!/usr/bin/env node

const dotenv = require('dotenv');
const path = require('path');
const paths = require('./paths');
const fs = require("fs-extra");
const fso = require("fs");
const spawn = require("child_process").spawn;
const FormData = require('form-data');
const sleep = require('await-sleep');

dotenv.config({
path: paths.configFilePath
Expand All @@ -18,15 +20,9 @@ if ( typeof process.env.deviceID === 'undefined' ) {
console.log( 'starting camera', process.env.deviceID );
}

// create the file first
fs.exists( process.env.imageFilePath, async ( exists ) => {
if( !exists ) {
console.log( 'image didt exist yet, creating...' );
await fs.writeFile( process.env.imageFilePath, '' );
}
});

var delay = 5;
var pic = null;
var fileWatch = null;
var delay = process.env.cameraDelay || 5;

var dt = new Date();
var secInterval = setInterval( () => {
Expand Down Expand Up @@ -58,7 +54,7 @@ async function startCamera() {
'-a', 4+8,
// '-a', 'test',
];
var pic = spawn('raspistill', args);
pic = spawn('raspistill', args);

pic.stdout.on('data', (data) => {
console.log( 'stdout: ', data );
Expand All @@ -70,19 +66,79 @@ async function startCamera() {
}
}

/**
* asynchronously wait for the file to exist
*
* @param {string} file path to file
*/
async function waitForFile( file ) {
while( true ) {
const exists = await fs.exists( file );
if( exists ) return true;
console.log( 'file does not yet exist, waiting longer' );
await sleep( 333 );
}
}

// watch for changes on the file and upload them to the server
// using native fs for now, switching to something better later
fso.watchFile( process.env.imageFilePath, async() => {
( async() => {

// wait for file to be created
await waitForFile( process.env.imageFilePath );

// watch the file
fileWatch = fso.watch( path.dirname( process.env.imageFilePath ), async( event, changed_fname ) => {

unixTimestamp = Math.round( ( new Date() ).getTime() / 1000 );
if( event !== 'change' ) {
return;
}

var form = new FormData();
form.append( 'filedata', fs.createReadStream( process.env.imageFilePath ) );

const uploadPath = process.env.uploadURL + [ '/upload', process.env.deviceID, unixTimestamp ].join('/');
unixTimestamp = Math.round( ( new Date() ).getTime() / 1000 );

try {
var form = new FormData();
form.append( 'filedata', fs.createReadStream( process.env.imageFilePath ) );

const uploadPath = process.env.uploadURL + [ '/upload', process.env.deviceID, unixTimestamp ].join('/');

await form.submit( uploadPath, err => {
if ( err ) console.error( 'error submitting form', err );
});
} catch( error ) {
console.error( 'error trying to read the image and upload it', error );
}

await form.submit( uploadPath, err => {
if ( err ) console.error( 'error submitting form', err );
});
})();

/**
* gracefully shut the application down
*/
async function shutdown() {
console.info( 'shutting down...' );
// stop raspistill if it running
if( pic !== null ) {
console.info( 'stopping raspistill...' );
pic.kill('SIGINT');
}
if( fileWatch !== null ) {
console.info( 'removing file watch...' );
fileWatch.close();
}
console.info( 'done...' );
process.exit(0);
}

// listen for SIGINT and clean up
process.on('SIGINT', async () => {
console.info( '\r\n\r\n', 'SIGINT signal recieved' );
shutdown();
});

// windows
process.on('message', (msg) => {
if (msg == 'shutdown') {
shutdown();
}
})

0 comments on commit aa69763

Please sign in to comment.