websocket comms console widget

This commit is contained in:
Mikkeli Matlock
2026-01-26 22:22:33 +09:00
parent d6825eb9d9
commit 7fd92d862b
3 changed files with 122 additions and 7 deletions

View File

@@ -9,6 +9,7 @@ import '../widgets/navigator_widget.dart';
import '../widgets/stat_box.dart'; import '../widgets/stat_box.dart';
import '../widgets/stat_box_main.dart'; import '../widgets/stat_box_main.dart';
import '../widgets/system_bar.dart'; import '../widgets/system_bar.dart';
import '../widgets/debug_console.dart';
// test service for triggers // test service for triggers
import '../services/test_flipflop_service.dart'; import '../services/test_flipflop_service.dart';
@@ -202,11 +203,26 @@ class _DashboardScreenState extends State<DashboardScreen> {
const SizedBox(width: 32), const SizedBox(width: 32),
// Right side: Image display (flex: 1) // Right side: Navigator with debug console overlay
Expanded( Expanded(
flex: 1, flex: 1,
child: Center( child: Stack(
child: NavigatorWidget(key: _navigatorKey), children: [
// Bottom layer: Navigator
Center(
child: NavigatorWidget(key: _navigatorKey),
),
// Top layer: Debug console on lower half only
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
const Spacer(), // Top half - empty
const Expanded(
child: DebugConsole(maxLines: 8),
),
],
),
],
), ),
), ),
], ],

View File

@@ -73,6 +73,11 @@ class WebSocketService {
late StreamController<CommandAck> _ackController; late StreamController<CommandAck> _ackController;
late StreamController<BackendAlert> _alertController; late StreamController<BackendAlert> _alertController;
late StreamController<WsConnectionState> _connectionController; late StreamController<WsConnectionState> _connectionController;
late StreamController<String> _debugController;
// Debug message buffer
static const int _maxDebugMessages = 50;
final List<String> _debugMessages = [];
void _setupStreams() { void _setupStreams() {
_arduinoController = StreamController<ArduinoData>.broadcast(); _arduinoController = StreamController<ArduinoData>.broadcast();
@@ -81,6 +86,16 @@ class WebSocketService {
_ackController = StreamController<CommandAck>.broadcast(); _ackController = StreamController<CommandAck>.broadcast();
_alertController = StreamController<BackendAlert>.broadcast(); _alertController = StreamController<BackendAlert>.broadcast();
_connectionController = StreamController<WsConnectionState>.broadcast(); _connectionController = StreamController<WsConnectionState>.broadcast();
_debugController = StreamController<String>.broadcast();
}
/// Log a debug message (adds to buffer and stream)
void _log(String message) {
_debugMessages.add(message);
if (_debugMessages.length > _maxDebugMessages) {
_debugMessages.removeAt(0);
}
_debugController.add(message);
} }
// --- Public API: Streams --- // --- Public API: Streams ---
@@ -103,6 +118,12 @@ class WebSocketService {
/// Stream of connection state changes /// Stream of connection state changes
Stream<WsConnectionState> get connectionStream => _connectionController.stream; Stream<WsConnectionState> get connectionStream => _connectionController.stream;
/// Stream of debug log messages
Stream<String> get debugStream => _debugController.stream;
/// Current debug message buffer (for initial display)
List<String> get debugMessages => List.unmodifiable(_debugMessages);
// --- Public API: Sync getters (backward compat) --- // --- Public API: Sync getters (backward compat) ---
/// Current connection state /// Current connection state
@@ -135,25 +156,25 @@ class WebSocketService {
}); });
_socket!.onConnect((_) { _socket!.onConnect((_) {
print('[WS] Connected to $_serverUrl'); _log('connected');
_setConnectionState(WsConnectionState.connected); _setConnectionState(WsConnectionState.connected);
_cancelReconnect(); _cancelReconnect();
}); });
_socket!.onDisconnect((_) { _socket!.onDisconnect((_) {
print('[WS] Disconnected'); _log('disconnected');
_setConnectionState(WsConnectionState.disconnected); _setConnectionState(WsConnectionState.disconnected);
_scheduleReconnect(); _scheduleReconnect();
}); });
_socket!.onConnectError((error) { _socket!.onConnectError((error) {
print('[WS] Connection error: $error'); _log('error: $error');
_setConnectionState(WsConnectionState.disconnected); _setConnectionState(WsConnectionState.disconnected);
_scheduleReconnect(); _scheduleReconnect();
}); });
_socket!.onError((error) { _socket!.onError((error) {
print('[WS] Error: $error'); _log('error: $error');
}); });
// --- Telemetry Events --- // --- Telemetry Events ---
@@ -163,6 +184,7 @@ class WebSocketService {
final arduino = ArduinoData.fromJson(data); final arduino = ArduinoData.fromJson(data);
_latestArduino = arduino; _latestArduino = arduino;
_arduinoController.add(arduino); _arduinoController.add(arduino);
_log('ard: ${arduino.rpm ?? "-"}rpm ${arduino.voltage ?? "-"}V g${arduino.gear ?? "-"}');
} }
}); });
@@ -171,6 +193,7 @@ class WebSocketService {
final gps = GpsData.fromJson(data); final gps = GpsData.fromJson(data);
_latestGps = gps; _latestGps = gps;
_gpsController.add(gps); _gpsController.add(gps);
_log('gps: ${gps.speed?.toStringAsFixed(1) ?? "-"}m/s mode${gps.mode ?? "-"}');
} }
}); });
@@ -182,6 +205,7 @@ class WebSocketService {
); );
_latestStatus = status; _latestStatus = status;
_statusController.add(status); _statusController.add(status);
_log('status: gps=${status.gpsConnected} ard=${status.arduinoConnected}');
} }
}); });
@@ -196,6 +220,7 @@ class WebSocketService {
extra: data['extra'], extra: data['extra'],
); );
_ackController.add(ack); _ackController.add(ack);
_log('ack: ${ack.id}=${ack.status}${ack.error != null ? " err:${ack.error}" : ""}');
} }
}); });
@@ -206,6 +231,7 @@ class WebSocketService {
message: data['message'] ?? '', message: data['message'] ?? '',
); );
_alertController.add(alert); _alertController.add(alert);
_log('alert: [${alert.type}] ${alert.message}');
} }
}); });
@@ -283,5 +309,6 @@ class WebSocketService {
_ackController.close(); _ackController.close();
_alertController.close(); _alertController.close();
_connectionController.close(); _connectionController.close();
_debugController.close();
} }
} }

View File

@@ -0,0 +1,72 @@
import 'dart:async';
import 'package:flutter/material.dart';
import '../services/websocket_service.dart';
import '../theme/app_theme.dart';
/// Self-contained debug console that displays WebSocket log messages.
/// Subscribes to WebSocketService.debugStream internally.
class DebugConsole extends StatefulWidget {
/// Maximum lines to display
final int maxLines;
const DebugConsole({
super.key,
this.maxLines = 8,
});
@override
State<DebugConsole> createState() => _DebugConsoleState();
}
class _DebugConsoleState extends State<DebugConsole> {
final List<String> _messages = [];
StreamSubscription<String>? _debugSub;
@override
void initState() {
super.initState();
// Initialize with existing buffer
_messages.addAll(WebSocketService.instance.debugMessages);
_trimMessages();
// Subscribe to new messages
_debugSub = WebSocketService.instance.debugStream.listen((msg) {
setState(() {
_messages.add(msg);
_trimMessages();
});
});
}
void _trimMessages() {
while (_messages.length > widget.maxLines) {
_messages.removeAt(0);
}
}
@override
void dispose() {
_debugSub?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = AppTheme.of(context);
return Container(
padding: const EdgeInsets.all(4),
child: Text(
_messages.isEmpty ? '(no messages)' : _messages.join('\n'),
style: TextStyle(
fontFamily: 'monospace',
fontSize: 34,
color: theme.foreground,
height: 1.2,
),
),
);
}
}