diff --git a/app/lib/arduino/package.json b/app/lib/arduino/package.json new file mode 100644 index 0000000..43708c1 --- /dev/null +++ b/app/lib/arduino/package.json @@ -0,0 +1,11 @@ +{ + "name": "arduino", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/display/index.js b/app/lib/display/index.js new file mode 100644 index 0000000..8fbe126 --- /dev/null +++ b/app/lib/display/index.js @@ -0,0 +1,127 @@ +'use strict'; + +const path = require('path'); +const { BrowserWindow } = require('electron'); + +const exec = require('exec'); +const spawn = require('spawn'); +const delay = require('delay'); + +let wv; +let cp; +let system = {}; +let digitalWindow; + +let TMPDIR; + +class WebView { + constructor() { + + } + async open () { + digitalWindow = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + allowRunningInsecureContent: false, + 'unsafe-eval' : false + }, + width: 800, + height: 600, + minWidth : 800, + minHeight : 600//, + //icon: path.join(__dirname, '../../assets/icons/icon.png') + }); + digitalWindow.loadURL('file://' + __dirname + '../../../display.html'); + if (process.argv.indexOf('-d') !== -1 || process.argv.indexOf('--dev') !== -1) { + digitalWindow.webContents.openDevTools(); + } + digitalWindow.on('closed', () => { + digitalWindow = null + }); + } + async fullScreen () { + return digitalWindow.setFullScreen(true); + } + async setImage (src) { + return digitalWindow.webContents.send('display', { src }); + } + async setMeter () { + return digitalWindow.webContents.send('display', { meter : true }); + } + async setGrid () { + return digitalWindow.webContents.send('display', { grid : true }); + } + async close () { + if (digitalWindow) { + digitalWindow.close(); + } + return true + } + async move () { + + } +} + +function padded_frame (i) { + let len = (i + '').length; + let str = i + ''; + for (let x = 0; x < 5 - len; x++) { + str = '0' + str; + } + return str; +} + +async function display_eog (src) { + //timeout 3 eog --fullscreen ${src} + cp = spawn('eog', ['--fullscreen', src]); +} + + +async function display_wv (src) { + await wv.open(); + await wv.fullScreen(); + await delay(200); + await wv.setImage(src); +} + +async function end () { + if (system.platform !== 'nix') { + await wv.close(); + } else { + cp.kill() + } +} + +async function start (frame) { + let padded = padded_frame(frame); + let ext = 'tif'; + let tmppath; + + if (system.platform !== 'nix') { + ext = 'png'; + } + + tmppath = path.join(TMPDIR, `export-${padded}.${ext}`); + + if (system.platform !== 'nix') { + display_wv(tmppath); + } else { + display_eog(tmppath); + } +} + +module.exports = function (sys) { + system = sys; + TMPDIR = path.join(system.tmp, 'intval_go_node'); + + if (system.platform !== 'nix') { + wv = new WebView(); + } else { + //child process + } + + return { + start, + end + } +} \ No newline at end of file diff --git a/app/lib/display/package.json b/app/lib/display/package.json new file mode 100644 index 0000000..62e044a --- /dev/null +++ b/app/lib/display/package.json @@ -0,0 +1,11 @@ +{ + "name": "display", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/ffmpeg/index.js b/app/lib/ffmpeg/index.js new file mode 100644 index 0000000..33a5b49 --- /dev/null +++ b/app/lib/ffmpeg/index.js @@ -0,0 +1,158 @@ +'use strict'; + +const uuid = require('uuid').v4; +const path = require('path'); +const fs = require('fs-extra'); + +const exec = require('exec'); +//const spawn = require('spawn'); +const exit = require('exit'); + +let system = {}; +let TMPDIR; + +function padded_frame (i) { + let len = (i + '').length; + let str = i + ''; + for (let x = 0; x < 5 - len; x++) { + str = '0' + str; + } + return str; +} + +async function frame (video, frame, obj) { + let padded = padded_frame(frame); + let ext = 'tif'; + let tmpoutput; + let cmd; + let output; + + if (system.platform !== 'nix') { + ext = 'png'; + } + + tmpoutput = path.join(TMPDIR, `export-${padded}.${ext}`) + + cmd = `ffmpeg -i "${video}" -vf select='gte(n\\,${frame})' -vframes 1 -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"` + + //ffmpeg -i "${video}" -ss 00:00:07.000 -vframes 1 "export-${time}.jpg" + //ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "export-%05d.tiff" + //-vf "select=gte(n\,${frame})" -compression_algo raw -pix_fmt rgb24 "export-${padded}.png" + + try { + output = await exec(cmd); + console.log(cmd); + } catch (err) { + console.error(err); + } + + if (output) console.log(`"${output}"`); + +} + +async function frames (video, obj) { + let tmppath = TMPDIR; + let ext = 'tif'; + let tmpoutput; + + if (system.platform !== 'nix') { + ext = 'png'; + } + + tmpoutput = path.join(tmppath, `export-%05d.${ext}`); + try { + await fs.mkdir(tmppath) + } catch (Err) { + console.error(err); + } + + //ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}" +} + +async function clear (frame) { + let padded = padded_frame(frame); + let ext = 'tif'; + let tmppath; + let tmpoutput; + let cmd; + let exists; + + if (system.platform !== 'nix') { + ext = 'png'; + } + + tmppath = path.join(TMPDIR, `export-${padded}.${ext}`); + + try { + exists = await fs.exists(tmppath); + } catch (err) { + console.error(err); + } + + if (!exists) return false; + + try { + await fs.unlink(tmppath); + console.log(`Cleared frame ${tmppath}`); + } catch (err) { + console.error(err); + } + + return true; +} + +async function clearAll () { + let tmppath = TMPDIR; + let files; + try { + files = await fs.readdir(tmppath); + } catch (err) { + console.error(err); + } + if (files) { + files.forEach(async (file, index) => { + try { + await fs.unlink(path.join(tmppath, file)); + } catch (err) { + console.error(err); + } + }); + } +} + +async function checkDir () { + let exists; + try { + exists = await fs.exists(TMPDIR); + } catch (err) { + console.error('Error checking for tmp dir', err); + } + + if (!exists) { + try { + await fs.mkdir(TMPDIR); + console.log(`Created tmpdir ${TMPDIR}`); + } catch (err) { + console.error('Error creating tmp dir', err); + } + } + try { + await clearAll(); + } catch (err) { + console.error(err); + } +} + +module.exports = (sys) => { + system = sys; + TMPDIR = path.join(system.tmp, 'intval_go_node'); + + checkDir(); + + return { + frames, + frame, + clear, + clearAll + } +} \ No newline at end of file diff --git a/app/lib/ffmpeg/package.json b/app/lib/ffmpeg/package.json new file mode 100644 index 0000000..b78c1be --- /dev/null +++ b/app/lib/ffmpeg/package.json @@ -0,0 +1,11 @@ +{ + "name": "ffmpeg", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/ffprobe/index.js b/app/lib/ffprobe/index.js new file mode 100644 index 0000000..cea2514 --- /dev/null +++ b/app/lib/ffprobe/index.js @@ -0,0 +1,91 @@ +'use strict'; + +const fs = require('fs-extra'); + +const exec = require('exec'); +//const spawn = require('spawn'); +const exit = require('exit'); + +let system = {}; + +async function info (video) { + let cmd = `ffprobe -v quiet -print_format json -show_format -show_streams "${video}"` + let exists; + let raw; + let json; + let vid; + + try { + exists = await fs.exists(video); + } catch (err) { + return exit(err, 5); + } + if (!exists) { + return exit(`File ${video} does not exist`, 6); + } + try { + raw = await exec(cmd); + } catch (err) { + return exit(err, 7); + } + try { + json = JSON.parse(raw); + } catch (err) { + return raw; + } + + if (json && json.streams) { + vid = json.streams.find(stream => { + if (stream.width && stream.height) return stream; + }); + } + + if (vid) { + json.width = vid.width; + json.height = vid.height; + } + + return json; +} + +async function frames (video) { + let cmd = `ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 "${video}"`; + let exists; + let raw; + let frames; + + try { + exists = await fs.exists(video); + } catch (err) { + return exit(err, 5); + } + if (!exists) { + return exit(`File ${video} does not exist`, 6); + } + + try { + raw = await exec(cmd); + } catch (err) { + console.error(err); + } + + try { + frames = parseInt(raw) + } catch (err) { + return raw; + } + + return frames; +} + +function map (obj) { + console.dir(obj); +} + +module.exports = (sys) => { + system = sys; + return { + info, + frames + } +} diff --git a/app/lib/ffprobe/package.json b/app/lib/ffprobe/package.json new file mode 100644 index 0000000..586ea4e --- /dev/null +++ b/app/lib/ffprobe/package.json @@ -0,0 +1,11 @@ +{ + "name": "ffprobe", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/intval/package.json b/app/lib/intval/package.json new file mode 100644 index 0000000..d888b72 --- /dev/null +++ b/app/lib/intval/package.json @@ -0,0 +1,11 @@ +{ + "name": "intval", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/server/package.json b/app/lib/server/package.json new file mode 100644 index 0000000..c7747d9 --- /dev/null +++ b/app/lib/server/package.json @@ -0,0 +1,11 @@ +{ + "name": "server", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/settings/package.json b/app/lib/settings/package.json new file mode 100644 index 0000000..87cc2fb --- /dev/null +++ b/app/lib/settings/package.json @@ -0,0 +1,11 @@ +{ + "name": "settings", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/spawn/index.js b/app/lib/spawn/index.js new file mode 100644 index 0000000..627ed38 --- /dev/null +++ b/app/lib/spawn/index.js @@ -0,0 +1,18 @@ +'use strict'; + +const spawnRaw = require('child_process').spawn; + +function spawn (cmd, args) { + const sp = spawnRaw(cmd, args); + let output = ''; + sp.stderr.on('data', (data) => { + output += data; + //console.log(`${data}`); + }); + sp.on('close', (code) => { + console.log(output); + }); + return sp; +} + +module.exports = spawn; \ No newline at end of file diff --git a/app/lib/spawn/package.json b/app/lib/spawn/package.json new file mode 100644 index 0000000..7fbd317 --- /dev/null +++ b/app/lib/spawn/package.json @@ -0,0 +1,11 @@ +{ + "name": "spawn", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/app/lib/system/index.js b/app/lib/system/index.js new file mode 100644 index 0000000..20596df --- /dev/null +++ b/app/lib/system/index.js @@ -0,0 +1,67 @@ +'use strict'; + +const os = require('os'); +const electron = require('electron'); + +const exec = require('exec'); +//const spawn = require('spawn'); +const exit = require('exit'); + +async function dependencies (platform) { + let obj = {}; + + try { + await exec('ffmpeg -h'); + obj.ffmpeg = 'ffmpeg'; + } catch (err) { + return exit('ffmpeg is not installed', 3); + } + //if linux + if (platform === 'nix') { + try { + await exec('eog -h'); + obj.eog = 'eog'; + } catch (err) { + return exit('eog is not installed', 4); + } + } + + return obj; +} + +async function system () { + const obj = {}; + let displays = electron.screen.getAllDisplays(); + let platform; + + try { + obj.tmp = os.tmpdir(); + } catch (err) { + obj.tmp = '/tmp' + } + + platform = os.type(); + + if (platform === 'Darwin') { + obj.platform = 'osx'; + } else if (platform === 'Windows_NT') { + obj.platform = 'win'; + } else { + obj.platform = 'nix'; + } + + obj.displays = displays.map(obj => { + return { + width : obj.workArea.width, + height : obj.workArea.height, + x : obj.bounds.x, + y : obj.bounds.y + } + }); + + obj.deps = await dependencies(obj.platform); + + return obj; +} + +module.exports = system; \ No newline at end of file diff --git a/app/lib/system/package.json b/app/lib/system/package.json new file mode 100644 index 0000000..148877b --- /dev/null +++ b/app/lib/system/package.json @@ -0,0 +1,11 @@ +{ + "name": "system", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/ino/components/mcopy_camera_relay/mcopy_camera_relay.ino b/ino/components/mcopy_camera_relay/mcopy_camera_relay.ino new file mode 100644 index 0000000..e7e9629 --- /dev/null +++ b/ino/components/mcopy_camera_relay/mcopy_camera_relay.ino @@ -0,0 +1,105 @@ +boolean debug_state = false; + +/* ------------------------------------------------ + * pins + * ------------------------------------------------*/ +//Arduino Uno + relay module + +const int PIN_INDICATOR = 13; +const int PIN_CAMERA = 9; + +volatile boolean running = false; + +unsigned long timer = 0; +unsigned long frame_start = 0; +unsigned long delay_start = 0; + +volatile long seq_delay = 42; + +const char cmd_camera = 'c'; + +const char cmd_debug = 'd'; +const char cmd_connect = 'i'; +volatile char cmd_char = 'z'; +const char cmd_mcopy_identifier = 'm'; +const char cmd_cam_identifier = 'k'; + +const int serialDelay = 5; + +void setup() { + Serial.begin(57600); + Serial.flush(); + Serial.setTimeout(serialDelay); + + Pins_init(); +} + +void loop() { + if (Serial.available()) { + /* read the most recent byte */ + cmd_char = (char)Serial.read(); + } + if (cmd_char != 'z') { + cmd(cmd_char); + cmd_char = 'z'; + } + timer = millis(); +} + +void cmd (char val) { + if (val == cmd_debug) { + debug(); + } else if (val == cmd_connect) { + connect(); + } else if (val == cmd_mcopy_identifier) { + identify(); + } else if (val == cmd_camera) { + Frame(); + } +} + +void debug () { + debug_state = true; + Serial.println(cmd_debug); + log("debugging enabled"); +} + +void connect () { + Serial.println(cmd_connect); + log("connect()"); +} + +void identify () { + Serial.println(cmd_cam_identifier); + log("identify()"); +} + +void Pins_init () { + pinMode(PIN_CAMERA, OUTPUT); + pinMode(PIN_INDICATOR, OUTPUT); + + digitalWrite(PIN_CAMERA, LOW); + digitalWrite(PIN_INDICATOR, LOW); +} + +void Frame () { + frame_start = millis(); + running = true; + + digitalWrite(PIN_CAMERA, HIGH); + digitalWrite(PIN_INDICATOR, HIGH); + delay(200); + digitalWrite(PIN_CAMERA, LOW); + digitalWrite(PIN_INDICATOR, LOW); + delay(600); + running = false; + + Serial.println(cmd_camera); + log("Frame completed"); +} + +void log (String msg) { + if (debug_state) { + Serial.println(msg); + } +}