diff --git a/README.md b/README.md index 1a8ce45..35ff356 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ then retry the command. Runtimes are created in the `dist` directory under the `electron-node-red` project. +The `merger.js` utility can be pointed at an existing Node-RED projects directory and it will try to copy over and package up the relevant files into this project ready to install and build - so the simple flow would be + +``` +./merger.js {path to my Node-RED project directory} && yarn && yarn start +``` + ### Building for other platforms Generally you can just add the required parameter to the command diff --git a/example/electronflow.json b/example/electronflow.json new file mode 100644 index 0000000..d8fbe3c --- /dev/null +++ b/example/electronflow.json @@ -0,0 +1 @@ +[{"id":"41f61d2.fbe09e4","type":"tab","label":"Flow 1"},{"id":"52a903f3.ad56fc","type":"ui_tab","z":"41f61d2.fbe09e4","name":"Home","icon":"dashboard"},{"id":"30e652f.d9de3ae","type":"ui_group","z":"41f61d2.fbe09e4","name":"Panel 2","tab":"52a903f3.ad56fc","order":5,"disp":true,"width":"6"},{"id":"a8ecb9.c60f4348","type":"ui_group","z":"41f61d2.fbe09e4","name":"Introduction","tab":"52a903f3.ad56fc","order":1,"disp":false,"width":"4","collapse":false},{"id":"bbdf3e02.e8fee","type":"ui_group","z":"41f61d2.fbe09e4","name":"Panel 1","tab":"52a903f3.ad56fc","order":2,"disp":true,"width":"6"},{"id":"d9ba26fa.6d2b18","type":"ui_base","theme":{"name":"theme-light","lightTheme":{"default":"#0094CE","baseColor":"#8e0d17","baseFont":"Gill Sans,Geneva,sans-serif","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#097479","baseFont":"Helvetica Neue","edited":false},"customTheme":{"name":"Untitled Theme 1","default":"#4B7930","baseColor":"#4B7930","baseFont":"Helvetica Neue"},"themeState":{"base-color":{"default":"#0094CE","value":"#d80005","edited":true},"page-titlebar-backgroundColor":{"value":"#8e0d17","edited":false},"page-backgroundColor":{"value":"#fafafa","edited":false},"page-sidebar-backgroundColor":{"value":"#000000","edited":false},"group-textColor":{"value":"#d41322","edited":false},"group-borderColor":{"value":"#ffffff","edited":false},"group-backgroundColor":{"value":"#ffffff","edited":false},"widget-textColor":{"value":"#111111","edited":false},"widget-backgroundColor":{"value":"#8e0d17","edited":false},"widget-borderColor":{"value":"#ffffff","edited":false},"base-font":{"value":"Gill Sans,Geneva,sans-serif"}}},"site":{"name":"Node-RED Dashboard","hideToolbar":"false","allowSwipe":"false","dateFormat":"DD/MM/YYYY","sizes":{"sx":48,"sy":48,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"87356b62.92e3d8","type":"ui_group","z":"","name":"Text to Speech","tab":"52a903f3.ad56fc","order":3,"disp":true,"width":"6"},{"id":"c75ad4f0.0cede8","type":"ui_group","z":"","name":"Map","tab":"52a903f3.ad56fc","order":4,"disp":true,"width":"6"},{"id":"189cf871.681118","type":"ui_template","z":"41f61d2.fbe09e4","group":"a8ecb9.c60f4348","name":"Welcome","order":1,"width":"4","height":"9","format":"

Welcome to the Node-RED Dashboard

\n

On the right you will see a graph and a gauge logging data from the sliders underneath.

\n

There is also an example of embedding a small map.

","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":100,"y":60,"wires":[[]]},{"id":"9f19ee5c.beaef","type":"ui_chart","z":"41f61d2.fbe09e4","name":"","group":"bbdf3e02.e8fee","order":1,"width":"0","height":"0","label":"","chartType":"line","xformat":"HH:mm:ss","interpolate":"basis","nodata":"No Data","dot":false,"ymin":"0","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":"","colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":2,"x":270,"y":200,"wires":[[],[]]},{"id":"799d9318.fd385c","type":"ui_gauge","z":"41f61d2.fbe09e4","name":"","group":"30e652f.d9de3ae","order":2,"width":"","height":"","gtype":"gage","title":"Title","label":"gauge","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"x":270,"y":140,"wires":[]},{"id":"6f18b200.666a4","type":"ui_button","z":"41f61d2.fbe09e4","name":"","group":"87356b62.92e3d8","order":2,"width":0,"height":0,"label":"press to talk","color":"","bgcolor":"","icon":"fa-volume-up","payload":"Hello to Jason Isaacs","payloadType":"str","topic":"","x":110,"y":320,"wires":[["f897d7c2.467a58"]]},{"id":"f897d7c2.467a58","type":"ui_audio","z":"41f61d2.fbe09e4","name":"","group":"30e652f.d9de3ae","voice":"0","x":300,"y":320,"wires":[]},{"id":"da0f7e67.0d38a","type":"ui_slider","z":"41f61d2.fbe09e4","name":"","label":"slider","group":"30e652f.d9de3ae","order":4,"width":0,"height":0,"passthru":true,"topic":"","min":0,"max":"100","step":1,"x":90,"y":140,"wires":[["799d9318.fd385c","219da65f.e0b0da"]]},{"id":"eabf2bd7.f4e0c8","type":"ui_slider","z":"41f61d2.fbe09e4","name":"","label":"slider","group":"bbdf3e02.e8fee","order":4,"width":0,"height":0,"passthru":true,"topic":"","min":0,"max":"100","step":1,"x":130,"y":200,"wires":[["9f19ee5c.beaef","ccee40e3.c1618"]]},{"id":"45508d88.744a54","type":"function","z":"41f61d2.fbe09e4","name":"","func":"// create random position\nvar lat = 51 + Math.random() * 0.2;\nvar lon = -1.45 + Math.random() * 0.2;\nmsg.payload={lat:lat, lon:lon, name:\"Jason\", icon:\"male\", url:\"IBM link\"};\nreturn msg;","outputs":1,"noerr":0,"x":290,"y":400,"wires":[["f76b15b1.dd27a8"]]},{"id":"6ca8cfc2.e0bce","type":"ui_button","z":"41f61d2.fbe09e4","name":"","group":"c75ad4f0.0cede8","order":1,"width":0,"height":0,"passthru":false,"label":"Where's Jason ?","color":"","bgcolor":"#910000","icon":"fa-male","payload":"","payloadType":"str","topic":"","x":110,"y":400,"wires":[["45508d88.744a54"]]},{"id":"219da65f.e0b0da","type":"debug","z":"41f61d2.fbe09e4","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","x":300,"y":100,"wires":[]},{"id":"ccee40e3.c1618","type":"debug","z":"41f61d2.fbe09e4","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","targetType":"msg","x":300,"y":260,"wires":[]},{"id":"1c597308.3cfc0d","type":"worldmap in","z":"41f61d2.fbe09e4","name":"worldmap in","path":"","events":"","x":110,"y":480,"wires":[["7d6cb82c.3f3ea8"]]},{"id":"7d6cb82c.3f3ea8","type":"debug","z":"41f61d2.fbe09e4","name":"","active":true,"tosidebar":false,"console":true,"tostatus":false,"complete":"payload","x":350,"y":480,"wires":[]},{"id":"762cecef.af00d4","type":"inject","z":"41f61d2.fbe09e4","name":"","topic":"","payload":"26","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":"2","x":90,"y":260,"wires":[["eabf2bd7.f4e0c8"]]},{"id":"f76b15b1.dd27a8","type":"ui_worldmap","z":"41f61d2.fbe09e4","group":"c75ad4f0.0cede8","order":1,"width":"6","height":"7","name":"","lat":"51.17","lon":"-1.4","zoom":"","layer":"","cluster":"","maxage":"","usermenu":"hide","layers":"hide","panit":"false","panlock":"false","zoomlock":"false","hiderightclick":"true","coords":"none","showgrid":"false","path":"/worldmap","x":440,"y":400,"wires":[]}] \ No newline at end of file diff --git a/example/electronflow_cred.json b/example/electronflow_cred.json new file mode 100644 index 0000000..4d5996a --- /dev/null +++ b/example/electronflow_cred.json @@ -0,0 +1 @@ +{"$":"8dbcfcd6d9f25932aa00994065774d5ctxk="} \ No newline at end of file diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..462e5c4 --- /dev/null +++ b/example/package.json @@ -0,0 +1,17 @@ +{ + "name": "electron_node_red", + "description": "Electron Node-RED application starter kit for development", + "version": "1.0.2", + "dependencies": { + "node-red-contrib-play-audio": "*", + "node-red-contrib-web-worldmap": "*", + "node-red-dashboard": "*", + "node-red-node-base64": "*", + "node-red-node-geofence": "*", + "node-red-node-random": "*", + "node-red-node-smooth": "*" + }, + "scripts": { + "start": "node node_modules/node-red/red.js -u . electronflow.json" + } +} diff --git a/main.js b/main.js index b4e73a3..7365816 100755 --- a/main.js +++ b/main.js @@ -50,7 +50,7 @@ red_app.use("/",express.static("web")); // Create a server var server = http.createServer(red_app); -// Setup user directory and flowfile +// Setup user directory and flowfile (if editable) var userdir = __dirname; if (editable) { // if running as raw electron use the current directory (mainly for dev) diff --git a/merger.js b/merger.js new file mode 100755 index 0000000..f7b881a --- /dev/null +++ b/merger.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require('path'); +const pkg = require("./package-template.json"); + +let arg = "./example"; +let flowfile = null; +let dn = arg; +let app; +if (process.argv.length === 3 ) { + arg = process.argv[2]; + + let dn = path.dirname(arg); + if (path.extname(arg) === ".json") { + if (path.basename(arg, '.json') !== "package") { + flowfile = path.basename(arg); + app = require(path.join(dn, "package.json")); + } + else { + app = require(arg); + } + } + else { + app = require(path.join(arg, "package.json")); + dn = arg; + } +} +else { + app = require(arg+"/package.json"); +} + +const merge = { + ...app.dependencies, + ...pkg.dependencies +}; + +pkg.dependencies = merge; +// Try to get flow file name +if (app.hasOwnProperty("node-red") && app["node-red"].hasOwnProperty("settings") && app["node-red"].settings.hasOwnProperty("flowFile") ) { + pkg.NRelectron.flowFile = app["node-red"].settings.flowFile; +} +else if (app.hasOwnProperty("scripts") && app.scripts.hasOwnProperty("start")) { + pkg.NRelectron.flowFile = app.scripts.start.split(' ').pop(); +} +else { + pkg.NRelectron.flowFile = flowfile || "flow.json"; +} + +if (merge.hasOwnProperty("node-red-dashboard")) { + pkg.NRelectron.start = "dashboard"; +} +pkg.name = app.name; +pkg.version = app.version; +pkg.description = app.description; +// console.log(pkg); + +fs.copyFile(path.join(arg, pkg.NRelectron.flowFile), path.join("./", pkg.NRelectron.flowFile), (err) => { + if (err) { console.log("Failed to copy flows file - "+path.join(arg, pkg.NRelectron.flowFile)); } + else { console.log('Copied flows file - '+pkg.NRelectron.flowFile); } +}); +const creds = path.basename(pkg.NRelectron.flowFile,".json")+"_cred.json"; +fs.copyFile(path.join(arg, creds), path.join("./", creds), (err) => { + if (err) { console.log("Failed to copy creds file - "+path.join(arg, creds)); } + else { console.log('Copied creds file - '+creds); } +}); + +fs.writeFile("./package.json", JSON.stringify(pkg, null, 4), 'utf8', function (err) { + if (err) { console.log("Failed to re-write package.json file."); } + else { + console.log("Merged package.json."); + } +}); diff --git a/package-template.json b/package-template.json new file mode 100644 index 0000000..cd7746e --- /dev/null +++ b/package-template.json @@ -0,0 +1,84 @@ +{ + "name": "electron_node_red", + "version": "1.0.2", + "description": "Electron Node-RED application starter kit for development", + "main": "main.js", + "scripts": { + "pack": "electron-builder --dir", + "dist": "electron-builder", + "release": "electron-builder build -p always", + "postinstall": "electron-builder install-app-deps", + "start": "electron main.js", + "test": "echo \" Warning: no test specified \"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dceejay/electron-node-red.git" + }, + "dependencies": { + "electron-is-dev": "*", + "express": "^4.17.1", + "node-red": "1.0.2" + }, + "keywords": [ + "electron", + "quick start", + "node-red" + ], + "author": { + "name": "Dave Conway-Jones", + "email": "dceejay@gmail.com" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/dceejay/electron-node-red/issues" + }, + "homepage": "https://github.com/dceejay/electron-node-red#readme", + "devDependencies": { + "electron": "^7.1.1", + "electron-builder": "^22.1.0" + }, + "NRelectron": { + "productName": "Node-RED Electron", + "editable": true, + "allowLoadSave": false, + "showMap": false, + "kioskMode": false, + "flowFile": "electronflow.json", + "start": "editor" + }, + "build": { + "appId": "com.electron.node-red", + "productName": "Node-RED Electron", + "copyright": "Copyright © 2019 D.Conway-Jones", + "mac": { + "category": "public.app-category.developer-tools", + "target": "dmg" + }, + "linux": { + "target": [ + "rpm", + "apk", + { + "target": "deb", + "arch": [ + "x64", + "armv7l" + ] + } + ], + "synopsis": "Node-RED Low Code development", + "category": "Development" + }, + "win": { + "target": [ + { + "target": "msi", + "arch": [ + "x64" + ] + } + ] + } + } +} diff --git a/package.json b/package.json index 7a0b5d5..82f8f38 100644 --- a/package.json +++ b/package.json @@ -16,16 +16,16 @@ "url": "git+https://github.com/dceejay/electron-node-red.git" }, "dependencies": { - "electron-is-dev": "*", - "express": "^4.17.1", - "node-red": "1.0.2", "node-red-contrib-play-audio": "*", "node-red-contrib-web-worldmap": "*", "node-red-dashboard": "*", "node-red-node-base64": "*", "node-red-node-geofence": "*", "node-red-node-random": "*", - "node-red-node-smooth": "*" + "node-red-node-smooth": "*", + "electron-is-dev": "*", + "express": "^4.17.1", + "node-red": "1.0.2" }, "keywords": [ "electron", @@ -50,7 +50,7 @@ "editable": true, "allowLoadSave": false, "showMap": false, - "kioskMode": false, + "kioskMode": false, "flowFile": "electronflow.json", "start": "dashboard" }, @@ -88,4 +88,4 @@ ] } } -} +} \ No newline at end of file