aboutsummaryrefslogtreecommitdiff
path: root/hsm-web/Client/src
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2026-01-03 00:26:51 +0000
committerPaul Oliver <contact@pauloliver.dev>2026-01-03 03:42:43 +0000
commit864a1d2a22580a33b5e928734fd256c2133fb672 (patch)
treef164047133c293ae768112a6aad7eaab5df53401 /hsm-web/Client/src
parentf7f11acafe0a404fa218c13832e32fce574ae0f6 (diff)
Adds camera streaming to frontend
Diffstat (limited to 'hsm-web/Client/src')
-rw-r--r--hsm-web/Client/src/App.vue5
-rw-r--r--hsm-web/Client/src/CameraStream.vue103
-rw-r--r--hsm-web/Client/src/INA226.vue31
-rw-r--r--hsm-web/Client/src/config.js2
4 files changed, 124 insertions, 17 deletions
diff --git a/hsm-web/Client/src/App.vue b/hsm-web/Client/src/App.vue
index 84fefcf..af4ca3e 100644
--- a/hsm-web/Client/src/App.vue
+++ b/hsm-web/Client/src/App.vue
@@ -1,14 +1,17 @@
<template>
<h1>HsMouse</h1>
<INA226 />
+ <CameraStream />
</template>
<script>
import INA226 from './INA226.vue'
+import CameraStream from './CameraStream.vue'
export default {
components: {
- INA226
+ INA226,
+ CameraStream
}
}
</script>
diff --git a/hsm-web/Client/src/CameraStream.vue b/hsm-web/Client/src/CameraStream.vue
new file mode 100644
index 0000000..1defed2
--- /dev/null
+++ b/hsm-web/Client/src/CameraStream.vue
@@ -0,0 +1,103 @@
+<template>
+ <h2>Camera Stream</h2>
+ <button @click='toggleStream()' :disabled='disabled'>{{ command }}</button>
+ <video ref='player' muted></video>
+</template>
+
+<script>
+import axios from 'axios'
+import config from './config'
+import GstWebRTCAPI from '@tomoxv/gstwebrtc-api/src/gstwebrtc-api.js'
+import { useTemplateRef } from 'vue'
+
+export default {
+ data() {
+ return {
+ api: null,
+ listener: null,
+ player: null,
+ session: null,
+
+ command: 'Loading',
+ disabled: true,
+ streaming: false
+ }
+ },
+ mounted() {
+ this.player = useTemplateRef('player')
+ this.monitor()
+ this.bindStream()
+ },
+ methods: {
+ // Continuously checks if WebRTC stream is running on server
+ async monitor() {
+ const res = await axios.get(config.api + '/isStreaming')
+
+ switch (res.status) {
+ case 200:
+ this.command = res.data ? 'Stop' : 'Play'
+ this.disabled = false
+ this.streaming = res.data
+ break
+ default:
+ this.command = 'Error'
+ this.disabled = true
+ this.streaming = false
+ }
+
+ setTimeout(this.monitor, 1000)
+ },
+
+ // Toggles WebRTC stream
+ async toggleStream() {
+ const ep = this.streaming ? '/stopStream' : '/startStream'
+ const res = await axios.get(config.api + ep)
+
+ if (res.status != 200) {
+ console.error(res)
+ }
+ },
+
+ // Binds WebRTC stream to video element
+ bindStream() {
+ this.api = new GstWebRTCAPI({
+ meta: { name: 'WebClient-' + Date.now() },
+ signalingServerUrl: 'ws://' + window.location.hostname + ':8443'
+ })
+
+ this.listener = {
+ producerAdded: (producer) => {
+ console.log("Producer added", producer)
+
+ this.session = this.api.createConsumerSession(producer.id)
+ this.session.addEventListener('streamsChanged', () => {
+ if (this.session.streams.length > 0) {
+ this.player.srcObject = this.session.streams[0]
+ this.player.play()
+ }
+ })
+
+ this.session.connect()
+ },
+
+ producerRemoved: (producer) => {
+ console.log("Producer removed", producer)
+
+ this.player.pause()
+ this.player.srcObject = null
+ this.session = null
+ }
+ }
+
+ this.api.registerProducersListener(this.listener)
+ }
+ }
+}
+</script>
+
+<style>
+video {
+ height: 360px;
+ width: 480px;
+}
+</style>
diff --git a/hsm-web/Client/src/INA226.vue b/hsm-web/Client/src/INA226.vue
index bf0141f..a827b0b 100644
--- a/hsm-web/Client/src/INA226.vue
+++ b/hsm-web/Client/src/INA226.vue
@@ -1,41 +1,42 @@
<template>
- <h3>Battery Status</h3>
+ <h2>Battery Status</h2>
<table>
<tbody>
<tr>
- <td>{{ ina226Reading.voltage.toFixed(2) }}V</td>
- <td>{{ ina226Reading.current.toFixed(2) }}A</td>
- <td>{{ ina226Reading.power.toFixed(2) }}W</td>
+ <td>{{ fmt(reading.voltage, 'V') }}</td>
+ <td>{{ fmt(reading.current, 'A') }}</td>
+ <td>{{ fmt(reading.power, 'W') }}</td>
</tr>
</tbody>
</table>
</template>
<script>
-import axios from 'axios'
+import axios from 'axios'
import config from './config'
export default {
data() {
return {
- ina226Reading: {
+ reading: {
voltage: 0,
current: 0,
- power: 0
+ power: 0
}
}
},
mounted() {
- this.getINA226Reading()
+ this.getReading()
},
methods: {
- getINA226Reading() {
- axios
- .get(`${config.api}/ina226`)
- .then(res => {
- this.ina226Reading = res.data
- setTimeout(this.getINA226Reading, 1000)
- })
+ async getReading() {
+ const res = await axios.get(config.api + '/ina226')
+ this.reading = res.data
+
+ setTimeout(this.getReading, 1000)
+ },
+ fmt(val, sfx) {
+ return val.toFixed(2) + sfx
}
}
}
diff --git a/hsm-web/Client/src/config.js b/hsm-web/Client/src/config.js
index b8e9a98..b2217b7 100644
--- a/hsm-web/Client/src/config.js
+++ b/hsm-web/Client/src/config.js
@@ -1,3 +1,3 @@
module.exports = {
- api: 'http://192.168.8.170:3000'
+ api: `http://${window.location.hostname}:3000`
}