Telemetry Monitor
A Flutter application for visualizing real-time telemetry streams over WebSocket. Targets: Linux desktop, Android, and Web browsers (Flutter 3.41+).
What it does
Connects to a WebSocket server, decodes Protocol Buffer packets carrying up to
16 channels of double data plus 8 status integers and a pause flag, and renders
them as rolling time-series charts at 60 Hz. Also receives log packets with
severity, error number, timestamp, and description.
Key features:
- 4–16 simultaneous charts in a configurable grid.
- 1 kHz packet rate with batched per-frame rendering.
- Min/max decimation for smooth display at any zoom level.
- Hatched regions for missing-data gaps; thin markers for sub-pixel gaps.
- Scrollback through the configured packet buffer (default 10 minutes).
- Shared X-zoom across charts; per-chart Y-zoom.
- Two-tab UI: dashboard with errors-only mini log, plus a full filterable log.
- CSV export for both packet data and log entries.
- Pause from UI button or from a proto field.
- 8 named status indicators with 4-state color coding (gray / red / yellow / green).
Quick start
Prerequisites
- Flutter 3.41 or later.
- Protocol Buffers compiler (
protoc) version 3.x. - The Dart
protoc_pluginpackage (installed automatically viapubspec.yaml).
Generating Protobuf bindings
The messages.proto file lives in proto/. After cloning, run:
mkdir -p lib/proto
protoc --dart_out=lib/proto/ -Iproto/ proto/messages.proto
This produces lib/proto/messages.pb.dart and friends. The generated files are
gitignored; regenerate after any schema change.
Running
flutter pub get
flutter run -d linux # Linux desktop
flutter run -d <device-id> # Android
flutter run -d chrome # Web (CanvasKit recommended)
For Web, prefer the CanvasKit renderer for chart performance:
flutter run -d chrome --web-renderer canvaskit
First-run configuration
The app starts with a default WebSocket URL of ws://localhost:9000. Open
Settings to change it. Open Layout to assign channels to grid cells and
name them.
Architecture overview
See ARCHITECTURE.md for the full design. Brief summary:
- Transport owns the WebSocket and reconnection.
- Decoder turns raw frames into
Envelopemessages (isolate on native, inline on Web). - Session owns ring buffers for packets and logs, the view-state machine, and the per-frame Ticker that drives all rendering.
- Layout owns the grid configuration, channel assignments, channel names,
and status indicator names. Persisted via
shared_preferences. - Export writes CSV files (path_provider on native, Blob download on Web).
- UI is a
CustomPainter-based chart grid plus the toolbar, status bar, tabs, and dialogs.
Key invariants
These are the design rules that keep the app correct. Don't violate them
without re-reading ARCHITECTURE.md.
-
Single source of truth. Sample data lives only in the packet ring buffer. Log entries live only in the log ring buffer. Status snapshots are derived from the packet buffer each frame, not latched.
-
Producer/consumer decoupling. WebSocket packets write into ring buffers eagerly. Charts repaint only on the per-frame Ticker. The two are decoupled by design — never call repaint from a packet handler.
-
Disabled channels still record. Toggling a channel "off" hides it on the dashboard but does not stop recording or change the CSV output.
-
Buffer is authoritative for export. CSV always reads from the buffer, never from cached UI snapshots.
-
Window state is shared, Y state is per-chart. All charts share one X-axis window (zoom + pan + anchor). Each chart owns its own Y-mode and Y-range.
Project layout
lib/
main.dart # Entry point
app.dart # MaterialApp, top-level wiring
proto/ # Generated from messages.proto
config/ # AppConfig, Settings (persisted)
transport/ # WebSocket abstraction
decoder/ # Protobuf decoding
session/ # Ring buffers, view state, controller
layout/ # Grid + chart config
export/ # CSV exporter
ui/ # Widgets, dialogs, painters
proto/
messages.proto # Protocol Buffer schema
Build targets
| Target | Notes |
|---|---|
| Linux | Primary development target. Full feature set. |
| Android | Same code as Linux. Uses IOWebSocketChannel. |
| Web | Decoder runs inline (no isolates). CanvasKit recommended. CSV export uses Blob downloads. |
License
(Add as appropriate.)