mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-18 09:29:03 +08:00
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:
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
module.exports = {
|
||||
pluginOptions: {
|
||||
electronBuilder: {
|
||||
//preload: 'src/preload.js',
|
||||
nodeIntegration: true,
|
||||
builderOptions: {
|
||||
"productName": "ODriveGUI",
|
||||
"asar": false,
|
||||
|
||||
Reference in New Issue
Block a user