This commit is contained in:
@@ -42,4 +42,5 @@ CONFIG_BT_ATT_PREPARE_COUNT=5
|
||||
# Enable Lasertag Shared Modules
|
||||
CONFIG_LASERTAG_UTILS=y
|
||||
CONFIG_THREAD_MGMT=y
|
||||
CONFIG_BLE_MGMT=y
|
||||
CONFIG_BLE_MGMT=y
|
||||
CONFIG_GAME_MGMT=y
|
||||
@@ -204,6 +204,7 @@ static ssize_t write_leader_config(struct bt_conn *conn, const struct bt_gatt_at
|
||||
lasertag_set_thread_pan_id(payload->pan_id);
|
||||
lasertag_set_thread_channel(payload->channel);
|
||||
lasertag_set_thread_ext_pan_id(payload->ext_pan_id);
|
||||
LOG_HEXDUMP_INF(payload->network_key, 16, "Setting new Thread network key:");
|
||||
lasertag_set_thread_network_key(payload->network_key);
|
||||
if (payload->network_name[0] != '\0') // Only update if a name is provided
|
||||
{
|
||||
|
||||
@@ -36,6 +36,23 @@ class DeviceProvider extends ChangeNotifier {
|
||||
await provisionDevice(device, configToUse);
|
||||
}
|
||||
|
||||
Future<void> batchProvisionFoundDevices() async {
|
||||
// 1. Scan für 10 Sekunden starten
|
||||
startScan();
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
await FlutterBluePlus.stopScan();
|
||||
|
||||
// 2. Alle gefundenen Peripherals provisionieren
|
||||
for (var device in _discoveredPeripherals) {
|
||||
try {
|
||||
await provisionWithActiveConfig(device, keepName: true);
|
||||
debugPrint("Provisioniert: ${device.name}");
|
||||
} catch (e) {
|
||||
debugPrint("Fehler bei ${device.name}: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startScan() async {
|
||||
_discoveredLeaders.clear();
|
||||
_discoveredPeripherals.clear();
|
||||
|
||||
@@ -218,6 +218,7 @@ class _LeaderConfigScreenState extends State<LeaderConfigScreen> {
|
||||
networkKey: _netKeyCtrl.text.trim(),
|
||||
);
|
||||
|
||||
context.read<DeviceProvider>().setActiveConfig(newConfig);
|
||||
await context.read<DeviceProvider>().provisionDevice(
|
||||
widget.device,
|
||||
newConfig,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// lib/ui/screens/lobby_screen.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lasertag_app/constants.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../models/device_model.dart';
|
||||
import '../../providers/device_provider.dart';
|
||||
import '../widgets/leader_info_dialog.dart';
|
||||
|
||||
class LobbyScreen extends StatelessWidget {
|
||||
@@ -61,20 +64,19 @@ class LobbyScreen extends StatelessWidget {
|
||||
),
|
||||
|
||||
// Keine Divider mehr hier für einen cleanen Übergang
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(),
|
||||
SizedBox(height: 16),
|
||||
Text("Suche Teilnehmer im Thread-Netzwerk..."),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.radar,
|
||||
size: 64,
|
||||
color: colorScheme.outlineVariant,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text("Suche Teilnehmer im Netzwerk..."),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -93,9 +95,19 @@ class LobbyScreen extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
onPressed: () async {
|
||||
final provider = context.read<DeviceProvider>();
|
||||
if (provider.activeConfig != null) {
|
||||
// Leader zurück auf IDLE setzen
|
||||
final idleConfig = provider.activeConfig!.copyWith(
|
||||
systemState: LasertagConfig.sysStateIdle,
|
||||
);
|
||||
await provider.provisionDevice(leaderDevice, idleConfig);
|
||||
}
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Abbrechen"),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../models/device_model.dart';
|
||||
import '../../models/device_config_model.dart';
|
||||
import '../../providers/device_provider.dart';
|
||||
|
||||
class LeaderInfoDialog extends StatelessWidget {
|
||||
@@ -10,40 +9,41 @@ class LeaderInfoDialog extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Wir holen uns die Daten direkt aus dem Cache des Providers
|
||||
final activeConfig = context.read<DeviceProvider>().activeConfig;
|
||||
// watch sorgt dafür, dass der Dialog reagiert, wenn sich der Cache füllt
|
||||
final activeConfig = context.watch<DeviceProvider>().activeConfig;
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text("Leader Konfiguration"),
|
||||
title: const Text("Leader Details"),
|
||||
content: activeConfig == null
|
||||
? const Text("Keine Konfigurationsdaten im Cache gefunden.")
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildInfoRow("Game ID", "0x${activeConfig.gameId.toRadixString(16).toUpperCase()}"),
|
||||
_buildInfoRow("Status", _stateToString(activeConfig.systemState)),
|
||||
const Divider(),
|
||||
const Text("Thread Mesh", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
_buildInfoRow("Netzwerk", activeConfig.networkName),
|
||||
_buildInfoRow("Kanal", activeConfig.channel.toString()),
|
||||
_buildInfoRow("PAN ID", "0x${activeConfig.panId.toRadixString(16).toUpperCase()}"),
|
||||
_buildInfoRow("Ext PAN", activeConfig.extPanId),
|
||||
const Divider(),
|
||||
const Text("Security Key", style: TextStyle(fontSize: 10, color: Colors.grey)),
|
||||
SelectableText(
|
||||
activeConfig.networkKey,
|
||||
style: const TextStyle(fontFamily: 'monospace', fontSize: 10)
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildInfoRow("Game ID", "0x${activeConfig.gameId.toRadixString(16).toUpperCase()}"),
|
||||
_buildInfoRow("Status", _stateToString(activeConfig.systemState)),
|
||||
const Divider(),
|
||||
_buildInfoRow("Netzwerk", activeConfig.networkName),
|
||||
_buildInfoRow("Kanal", activeConfig.channel.toString()),
|
||||
_buildInfoRow("PAN ID", "0x${activeConfig.panId.toRadixString(16).toUpperCase()}"),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Neuer Button für Batch-Provisioning
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: FilledButton.icon(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
context.read<DeviceProvider>().batchProvisionFoundDevices();
|
||||
},
|
||||
icon: const Icon(Icons.bolt),
|
||||
label: const Text("Alle Knoten provisionieren"),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text("Schließen"),
|
||||
),
|
||||
TextButton(onPressed: () => Navigator.pop(context), child: const Text("Schließen")),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user