Added communication between electron main instance and renderer instance (vue app) for showing raw output from python script

Added button on main page to help with user debugging, should be possible to show missing dependencies etc now!
This commit is contained in:
PAJohnson
2020-09-25 17:25:21 -04:00
parent 03214c8dbe
commit 0f14c7a7db
7 changed files with 116 additions and 43 deletions
+5 -5
View File
@@ -76,8 +76,6 @@ def home():
@app.route('/api/odrives', methods=["GET"])
def api_odrives():
print(len(globals()['odrives']))
print("inUse = " + str(globals()['inUse']))
# spinlock
while globals()['inUse']:
time.sleep(0.1)
@@ -189,7 +187,7 @@ def getSampledData(vars):
samples = {}
for path in vars["paths"]:
keys = path.split('.')
samples[path] = getVal(odrives, keys)
samples[path] = getVal(globals()['odrives'], keys)
return samples
@@ -208,8 +206,10 @@ def callFunc(odrives, keyList):
print("fcn call failed")
if __name__ == "__main__":
print("args from python:")
print(sys.argv[1:])
# sleep to allow time for background.js to register event callbacks for stdout,stderr
time.sleep(3)
print("args from python: " + str(sys.argv[1:0]))
#print(sys.argv[1:])
# try to import based on command line arguments or config file
for optPath in sys.argv[1:]:
+37 -13
View File
@@ -5,8 +5,10 @@
<button
class="dash-button"
@click="startsample"
:class="[{active: sampling === true}]"
>start sampling</button>
:class="[{ active: sampling === true }]"
>
start sampling
</button>
<button class="dash-button" @click="stopsample">stop sampling</button>
<button class="dash-button" @click="exportDash">export dash</button>
<button class="dash-button" @click="importDashWrapper">
@@ -15,23 +17,32 @@
type="file"
id="inputDash"
ref="fileInput"
@change="importDashFile($event.target.files);$refs.fileInput.value=null"
@change="
importDashFile($event.target.files);
$refs.fileInput.value = null;
"
value
style="display:none"
style="display: none"
/>
</button>
<button
v-for="dash in dashboards"
:key="dash.id"
:class="['dash-button', { active: currentDash === dash.name}]"
:class="['dash-button', { active: currentDash === dash.name }]"
v-on:click.self="changeDash(dash.name)"
v-on:dblclick="changeDashName(dash.id)"
>
<button
v-if="dash.name !== 'Start' && dash.name !== 'Config' && dash.name !== 'Wizard'"
v-if="
dash.name !== 'Start' &&
dash.name !== 'Config' &&
dash.name !== 'Wizard'
"
class="close-button"
v-on:click="deleteDash(dash.id)"
>X</button>
>
X
</button>
{{ dash.name }}
</button>
<button class="dash-button dash-add" @click="addDash">+</button>
@@ -47,7 +58,12 @@
<!-- FOOTER -->
<div class="footer">
<Axis v-for="axis in axes" :key="axis.name" :axis="axis" :odrives="odrives"></Axis>
<Axis
v-for="axis in axes"
:key="axis.name"
:axis="axis"
:odrives="odrives"
></Axis>
</div>
</div>
</template>
@@ -56,12 +72,11 @@
import Start from "./views/Start.vue";
import Dashboard from "./views/Dashboard.vue";
import Axis from "./components/Axis.vue";
import Wizard from "./views/Wizard.vue"
import Wizard from "./views/Wizard.vue";
import * as socketio from "./comms/socketio";
import { saveAs } from "file-saver";
import { v4 as uuidv4 } from "uuid";
//let propSamplePeriod = 100; //sampling period for properties in ms
import { ipcRenderer } from "electron";
export default {
name: "App",
@@ -119,10 +134,10 @@ export default {
},
currentDash: function () {
return this.$store.state.currentDash;
}
},
},
methods: {
changeDash(dashName){
changeDash(dashName) {
console.log(dashName);
this.$store.commit("setDash", dashName);
},
@@ -229,6 +244,15 @@ export default {
this.$store.dispatch("setServerAddress", "http://127.0.0.1:5000");
// connect to socketio on server for sampled data
this.updateOdrives();
// setup callbacks for ipcRenderer
ipcRenderer.on('server-stdout', (event, arg) => {
//console.log("SERVER STDOUT: " + arg); // prints "pong"
this.$store.commit('logServerMessage', arg);
});
ipcRenderer.on('server-stderr', (event, arg) => {
//console.log("SERVER STDERR: " + arg); // prints "pong"
this.$store.commit('logServerMessage', arg);
});
},
};
</script>
+28 -24
View File
@@ -1,6 +1,6 @@
'use strict'
import { app, protocol, BrowserWindow } from 'electron'
import { app, protocol, BrowserWindow, ipcMain } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
@@ -38,28 +38,7 @@ function getPyCmd() {
}
function createWindow() {
// Spawn the python server
let scriptFilename = path.join(app.getAppPath(), '../server', 'odrive_server.py');
const args = process.argv;
let effectiveCommand = [];
effectiveCommand.push(scriptFilename);
if (app.isPackaged === true) {
for (const arg of args.slice(1)) {
effectiveCommand.push(arg);
}
}
else {
for (const arg of args.slice(2)) {
effectiveCommand.push(arg);
}
}
var python = spawn(getPyCmd(), effectiveCommand);
python.stdout.on('data',function(data) {
console.log(data.toString('utf8'));
});
python.stderr.on('data',function(data) {
console.log(data.toString('utf8'));
});
// Create the browser window.
win = new BrowserWindow({
width: 800,
@@ -67,7 +46,8 @@ function createWindow() {
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
//preload: path.join(__dirname, 'preload.js')
},
icon: path.join(__static, 'icon.png')
})
@@ -124,6 +104,30 @@ app.on('ready', async () => {
}
}
createWindow()
// Spawn the python server
let scriptFilename = path.join(app.getAppPath(), '../server', 'odrive_server.py');
const args = process.argv;
let effectiveCommand = [];
effectiveCommand.push(scriptFilename);
if (app.isPackaged === true) {
for (const arg of args.slice(1)) {
effectiveCommand.push(arg);
}
}
else {
for (const arg of args.slice(2)) {
effectiveCommand.push(arg);
}
}
var python = spawn(getPyCmd(), effectiveCommand);
python.stdout.on('data',function(data) {
console.log(data.toString('utf8'));
win.webContents.send('server-stdout', String(data.toString('utf8')));
});
python.stderr.on('data',function(data) {
console.log(data.toString('utf8'));
win.webContents.send('server-stderr', String(data.toString('utf8')));
});
})
// Exit cleanly on request from parent process in development mode.
-1
View File
@@ -4,7 +4,6 @@ import store from './store'
import Tooltip from 'vue-directive-tooltip';
import 'vue-directive-tooltip/dist/vueDirectiveTooltip.css';
import 'typeface-roboto/index.css';
Vue.config.productionTip = false
Vue.use(Tooltip);
+12
View File
@@ -6,6 +6,9 @@ const axios = require('axios');
import * as socketio from "./comms/socketio";
//import { v4 as uuidv4 } from "uuid";
Vue.use(Vuex);
export default new Vuex.Store({
@@ -16,6 +19,7 @@ export default new Vuex.Store({
axes: Array,
odriveServerAddress: String,
serverConnected: Boolean,
serverOutput: [],
dashboards: [
{
name: "Start",
@@ -147,6 +151,14 @@ export default new Vuex.Store({
}
state.newData = true;
},
logServerMessage(state, payload) {
// payload is string
state.serverOutput.push(payload);
// cut off to 1000 lines
if (state.serverOutput.length > 1000) {
state.serverOutput.splice(0,1);
}
},
setServerStatus(state, val) {
state.serverConnected = val;
},
+32
View File
@@ -9,6 +9,10 @@
<div class="connected-container">
<input type="text" :class="{ notConnected: notConnected, connected: connected}" v-on:change="setUrl" :value="serverAddress">
</div>
<button class="show-msg-button" @click="showServerMessages = !showServerMessages;">Having Trouble? Click here for debug output</button>
<div class="server-msgs" v-if="showServerMessages">
<div class="server-msg" v-for="(msg, index) in serverMessages" :key="msg + index">{{msg}}</div>
</div>
</div>
</template>
@@ -18,6 +22,11 @@ export default {
name: 'Home',
components: {
},
data() {
return {
showServerMessages: false,
}
},
computed: {
connected() {
return this.$store.state.serverConnected == true;
@@ -27,6 +36,15 @@ export default {
},
serverAddress() {
return this.$store.state.odriveServerAddress;
},
serverMessages() {
if (this.$store.state.serverOutput.length >= 10) {
let len = this.$store.state.serverOutput.length;
return this.$store.state.serverOutput.slice(len-10,len);
}
else {
return this.$store.state.serverOutput;
}
}
},
methods: {
@@ -86,4 +104,18 @@ input:focus {
.notConnected {
border-bottom: 1px solid red;
}
.show-msg-button {
border: none;
background-color: var(--bg-color);
margin-top: 0.5rem;
}
.server-msgs {
margin-top: 2rem;
}
.server-msg {
font-family: "Roboto Mono", monospace;
}
</style>
+2
View File
@@ -3,6 +3,8 @@
module.exports = {
pluginOptions: {
electronBuilder: {
//preload: 'src/preload.js',
nodeIntegration: true,
builderOptions: {
"productName": "ODriveGUI",
"asar": false,