aboutsummaryrefslogtreecommitdiff
path: root/hsm-web/Client
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2026-01-03 16:05:41 +0000
committerPaul Oliver <contact@pauloliver.dev>2026-01-03 19:53:59 +0000
commite2d8f74823c7139ce1ccd0831876e361fcd6c419 (patch)
treef52c49dce7a064d60882a89a895fbbbaecd9a3b2 /hsm-web/Client
parent81c97deaf7bd984a704db28f0cd676530a7b443e (diff)
Adds motor control to frontendgstreamer_webrtc
Diffstat (limited to 'hsm-web/Client')
-rw-r--r--hsm-web/Client/src/App.vue5
-rw-r--r--hsm-web/Client/src/MotorCtl.vue98
2 files changed, 83 insertions, 20 deletions
diff --git a/hsm-web/Client/src/App.vue b/hsm-web/Client/src/App.vue
index a4c8338..4645034 100644
--- a/hsm-web/Client/src/App.vue
+++ b/hsm-web/Client/src/App.vue
@@ -54,7 +54,10 @@ button {
padding: 0;
}
button:active {
- background-color: #0a414b;
+ opacity: 0.5;
+}
+button:disabled {
+ opacity: 0.5;
}
input {
background-color: transparent;
diff --git a/hsm-web/Client/src/MotorCtl.vue b/hsm-web/Client/src/MotorCtl.vue
index b1c53b2..d7d026e 100644
--- a/hsm-web/Client/src/MotorCtl.vue
+++ b/hsm-web/Client/src/MotorCtl.vue
@@ -4,27 +4,37 @@
<tbody>
<tr>
<td>
- <button :id='ccw' class='bmot'>{{ dirIcons.ccw }}</button>
+ <button :class='bdirClass("ccw")' @click='nextDir = "ccw"' :disabled='armed'>
+ {{ dirIcons.ccw }}
+ </button>
</td>
<td>
<table id='tmot'>
<tbody>
<tr v-for='ds in [["nw", "n", "ne"], ["w", "", "e"], ["sw", "s", "se"]]' :key='ds.id'>
<td v-for='d in ds' :key='d.id'>
- <button v-if='d' :id='d' class='bmot'>{{ dirIcons[d] }}</button>
+ <button v-if='d' :class='bdirClass(d)' @click='nextDir = d' :disabled='armed'>
+ {{ dirIcons[d] }}
+ </button>
</td>
</tr>
</tbody>
</table>
</td>
<td>
- <button :id='cw' class='bmot'>{{ dirIcons.cw }}</button>
+ <button :class='bdirClass("cw")' @click='nextDir = "cw"' :disabled='armed'>
+ {{ dirIcons.cw }}
+ </button>
</td>
<td>
<table id='tspeed'>
<tbody>
- <tr v-for='s in ["Top", "Fast", "Slow", "Slow2", "Slow4"]' :key='s.id'>
- <td><button id='s{{ s.toLowerCase() }}'>{{ s }}</button></td>
+ <tr v-for='s in ["top", "fast", "slow", "slow2", "slow4"]' :key='s.id'>
+ <td>
+ <button :class='bspeedClass(s)' @click='nextSpeed = s' :disabled='armed'>
+ {{ s }}
+ </button>
+ </td>
</tr>
</tbody>
</table>
@@ -32,8 +42,12 @@
<td>
<table id='ttime'>
<tbody>
- <tr v-for='t in ["4s", "2s", "1s", "hs", "qs"]' :key='t.id'>
- <td><button id='t{{ t }}'>{{ t }}</button></td>
+ <tr v-for='t in ["4s", "2s", "1s", "0.5s", "0.25s"]' :key='t.id'>
+ <td>
+ <button :class='btimeClass(t)' @click='nextTime = t' :disabled='armed'>
+ {{ t }}
+ </button>
+ </td>
</tr>
</tbody>
</table>
@@ -41,28 +55,27 @@
</tr>
</tbody>
</table>
- <table id='thist'>
+ <table id='tcmd'>
<tbody>
<tr>
- <td><input id='ihist' placeholder='command' disabled /></td>
- <td v-for='h in ["hup", "hdown"]' :key='h.id'>
- <button id='{{ h }}'>{{ h }}</button>
- </td>
+ <td><input id='ihist' :value='renderCommand()' disabled /></td>
</tr>
</tbody>
</table>
<table id='tarm'>
<tbody>
<tr>
- <td v-for='a in ["arm", "dispatch"]' :key='a.id'>
- <button id='{{ a }}'>{{ a }}</button>
- </td>
+ <td><button id='arm' @click='armed = !armed' :disabled='running'>{{ armed ? 'disarm' : 'arm' }}</button></td>
+ <td><button id='dispatch' @click='dispatch()' :disabled='!armed || running'>dispatch</button></td>
</tr>
</tbody>
</table>
</template>
<script>
+import axios from 'axios'
+import config from './config'
+
export default {
data() {
return {
@@ -77,12 +90,42 @@ export default {
nw: '↖',
ccw: '↺',
cw: '↻'
- }
+ },
+ nextDir: 'n',
+ nextSpeed: 'slow',
+ nextTime: '1s',
+ armed: false,
+ running: false
}
},
- mounted() {
- },
methods: {
+ bdirClass(d) {
+ return 'bmot' + (d == this.nextDir ? ' bhigh' : '')
+ },
+ bspeedClass(d) {
+ return d == this.nextSpeed ? 'bhigh' : ''
+ },
+ btimeClass(t) {
+ return t == this.nextTime ? 'bhigh' : ''
+ },
+ renderCommand() {
+ const cmd = ['ccw', 'cw'].includes(this.nextDir) ? 'Tilt' : 'Move'
+ const dir = this.nextDir.toUpperCase()
+ const speed = this.nextSpeed.charAt(0).toUpperCase() + this.nextSpeed.slice(1)
+ const time = this.nextTime.slice(0, -1)
+
+ return `${cmd} ${dir} ${speed} ${time}`
+ },
+ async dispatch() {
+ this.running = true
+
+ const res = await axios.get(config.api + '/command?cmd=' + this.renderCommand())
+
+ if (res.status == 200) {
+ this.armed = false
+ this.running = false
+ }
+ }
}
}
</script>
@@ -92,11 +135,28 @@ export default {
height: 33%;
width: 33%;
}
-#tmain td, #thist td {
+#tmain td, #tcmd td {
background-color: #2aa198;
}
.bmot {
font-size: 16px;
font-weight: bold;
}
+.bhigh {
+ background-color: #b58900;
+ color: #073642;
+}
+#tarm td:nth-child(1) {
+ width: 30%;
+}
+#arm {
+ background-color: #dc322f;
+}
+#dispatch {
+ background-color: #859900;
+}
+#arm, #dispatch {
+ color: #073642;
+ font-weight: bold;
+}
</style>