Add interface preview and fix WebView bridge exposure

This commit is contained in:
2026-08-25 22:24:03 +02:00
parent e845ae7eb6
commit b48f9846d5
4 changed files with 16 additions and 12 deletions
+2
View File
@@ -4,6 +4,8 @@ A deliberately small, low-bandwidth MAVLink controller for bench-testing an
ArduSub vehicle over a USB serial connection. It sends no parameter-list ArduSub vehicle over a USB serial connection. It sends no parameter-list
request and no telemetry-stream request. request and no telemetry-stream request.
![SUB Control interface](docs/sub-control-interface.png)
The desktop window uses a local HTML/CSS/JavaScript interface rendered by the The desktop window uses a local HTML/CSS/JavaScript interface rendered by the
Windows WebView. Python remains the only launcher and owns the MAVLink worker, Windows WebView. Python remains the only launcher and owns the MAVLink worker,
arming, logging, output limiting, and parameter writes. It does not run a web arming, logging, output limiting, and parameter writes. It does not run a web
Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

+1 -1
View File
@@ -62,7 +62,7 @@
<header class="topbar"> <header class="topbar">
<div><div class="eyebrow">PILOT CONSOLE</div><h1>Drive</h1></div> <div><div class="eyebrow">PILOT CONSOLE</div><h1>Drive</h1></div>
<div class="connection"> <div class="connection">
<select id="port" aria-label="Serial port"><option value="">No COM ports</option></select> <select id="port" aria-label="Serial port"><option value="">Select COM port…</option></select>
<button id="refresh" class="icon-button" title="Refresh ports">↻</button> <button id="refresh" class="icon-button" title="Refresh ports">↻</button>
<button class="icon-button" data-open="link-modal" title="Link settings">•••</button> <button class="icon-button" data-open="link-modal" title="Link settings">•••</button>
<button id="connect" class="button connect-button">Connect</button> <button id="connect" class="button connect-button">Connect</button>
+13 -11
View File
@@ -35,7 +35,9 @@ class ControlApi:
self.motor_directions: dict[int, int] = {} self.motor_directions: dict[int, int] = {}
self.battery_path = Path(__file__).resolve().parent / "battery_settings.json" self.battery_path = Path(__file__).resolve().parent / "battery_settings.json"
self.model_path = Path(__file__).resolve().parent / "model_settings.json" self.model_path = Path(__file__).resolve().parent / "model_settings.json"
self.window = None # Leading underscore keeps the native WebView object out of js_api
# serialization. Only the small public methods below are exposed.
self._window = None
self.maximized = False self.maximized = False
self.battery_config = { self.battery_config = {
"cells": 4, "capacity_mah": 5500, "c_rating": 35, "cells": 4, "capacity_mah": 5500, "c_rating": 35,
@@ -58,29 +60,29 @@ class ControlApi:
return [p.device for p in list_ports.comports()] return [p.device for p in list_ports.comports()]
def minimize_window(self): def minimize_window(self):
if self.window: if self._window:
self.window.minimize() self._window.minimize()
return True return True
def toggle_maximize_window(self): def toggle_maximize_window(self):
if not self.window: if not self._window:
return False return False
if self.maximized: if self.maximized:
self.window.restore() self._window.restore()
else: else:
self.window.maximize() self._window.maximize()
self.maximized = not self.maximized self.maximized = not self.maximized
return self.maximized return self.maximized
def close_window(self): def close_window(self):
if self.window: if self._window:
self.window.destroy() self._window.destroy()
return True return True
def choose_model(self): def choose_model(self):
if not self.window: if not self._window:
raise RuntimeError("Window is not ready") raise RuntimeError("Window is not ready")
selected = self.window.create_file_dialog( selected = self._window.create_file_dialog(
webview.OPEN_DIALOG, webview.OPEN_DIALOG,
allow_multiple=False, allow_multiple=False,
file_types=("STL mesh (*.stl)", "STEP model (*.step;*.stp)"), file_types=("STL mesh (*.stl)", "STEP model (*.step;*.stp)"),
@@ -285,7 +287,7 @@ def main():
background_color="#111719", frameless=True, easy_drag=False, background_color="#111719", frameless=True, easy_drag=False,
shadow=True, shadow=True,
) )
api.window = window api._window = window
window.events.maximized += lambda: setattr(api, "maximized", True) window.events.maximized += lambda: setattr(api, "maximized", True)
window.events.restored += lambda: setattr(api, "maximized", False) window.events.restored += lambda: setattr(api, "maximized", False)
try: try: