feat: grab sensor firmware version for detail sheet

This commit is contained in:
2026-05-20 19:43:15 +02:00
parent e0a3d5e481
commit acbba735a0
6 changed files with 49 additions and 12 deletions
@@ -52,6 +52,9 @@ class PhoenixSensorRepository implements SensorRepository {
Future<Sensor> unplaceSensor(int id) async => Future<Sensor> unplaceSensor(int id) async =>
Sensor.fromJson(await client.unplaceSensor(id)); Sensor.fromJson(await client.unplaceSensor(id));
@override
Future<String?> getVersion(int id) => client.getVersion(id);
@override @override
Stream<Map<String, dynamic>> sensorEvents() => realtime Stream<Map<String, dynamic>> sensorEvents() => realtime
.channelMessages('sensors') .channelMessages('sensors')
@@ -11,6 +11,8 @@ abstract class SensorRepository {
{required int roomId, required double x, required double y}); {required int roomId, required double x, required double y});
Future<Sensor> unplaceSensor(int id); Future<Sensor> unplaceSensor(int id);
Future<String?> getVersion(int id);
/// Stream of raw SensorsChannel messages. Each map contains an `event` key /// Stream of raw SensorsChannel messages. Each map contains an `event` key
/// (`sensor_announced` or `sensor_enrollment_timeout`) plus the payload. /// (`sensor_announced` or `sensor_enrollment_timeout`) plus the payload.
Stream<Map<String, dynamic>> sensorEvents(); Stream<Map<String, dynamic>> sensorEvents();
+25 -9
View File
@@ -13,30 +13,46 @@ class SensorClient extends LocaliserdClient {
await get('/api/sensors/$id') as Map<String, dynamic>; await get('/api/sensors/$id') as Map<String, dynamic>;
Future<Map<String, dynamic>> updateSensor( Future<Map<String, dynamic>> updateSensor(
int id, Map<String, dynamic> params) async => int id,
await put('/api/sensors/$id', params) as Map<String, dynamic>; Map<String, dynamic> params,
) async => await put('/api/sensors/$id', params) as Map<String, dynamic>;
Future<void> deleteSensor(int id) => delete('/api/sensors/$id'); Future<void> deleteSensor(int id) => delete('/api/sensors/$id');
Future<Map<String, dynamic>> placeSensor( Future<Map<String, dynamic>> placeSensor(
int id, Map<String, dynamic> params) async => int id,
Map<String, dynamic> params,
) async =>
await put('/api/sensors/$id/place', params) as Map<String, dynamic>; await put('/api/sensors/$id/place', params) as Map<String, dynamic>;
Future<Map<String, dynamic>> unplaceSensor(int id) async => Future<Map<String, dynamic>> unplaceSensor(int id) async =>
await deleteBody('/api/sensors/$id/place') as Map<String, dynamic>; await deleteBody('/api/sensors/$id/place') as Map<String, dynamic>;
Future<Map<String, dynamic>> createSensor(String sensorId, Future<Map<String, dynamic>> createSensor(
{String? name}) async => String sensorId, {
String? name,
}) async =>
await post('/api/sensors', { await post('/api/sensors', {
'sensor_id': sensorId, 'sensor_id': sensorId,
if (name != null) 'name': name, if (name != null) 'name': name,
}) as Map<String, dynamic>; })
as Map<String, dynamic>;
Future<Map<String, dynamic>> startCalibration( Future<Map<String, dynamic>> startCalibration(
int id, double referenceDistance) async => int id,
await post('/api/sensors/$id/calibration/start', double referenceDistance,
{'reference_distance': referenceDistance}) as Map<String, dynamic>; ) async =>
await post('/api/sensors/$id/calibration/start', {
'reference_distance': referenceDistance,
})
as Map<String, dynamic>;
Future<Map<String, dynamic>> stopCalibration(int id) async => Future<Map<String, dynamic>> stopCalibration(int id) async =>
await post('/api/sensors/$id/calibration/stop') as Map<String, dynamic>; await post('/api/sensors/$id/calibration/stop') as Map<String, dynamic>;
Future<String> getVersion(int id) async {
final response =
(await get('/api/sensors/$id/version') as Map<String, dynamic>);
return response['version']!;
}
} }
+5 -1
View File
@@ -7,6 +7,7 @@ class Sensor {
this.roomId, this.roomId,
this.x, this.x,
this.y, this.y,
this.version,
}); });
final int id; final int id;
@@ -16,6 +17,7 @@ class Sensor {
final int? roomId; final int? roomId;
final double? x; // room relative final double? x; // room relative
final double? y; // room relative final double? y; // room relative
final String? version;
bool get isPlaced => roomId != null && x != null && y != null; bool get isPlaced => roomId != null && x != null && y != null;
String get displayName => name ?? sensorId; String get displayName => name ?? sensorId;
@@ -28,6 +30,7 @@ class Sensor {
roomId: json['room_id'] as int?, roomId: json['room_id'] as int?,
x: (json['x'] as num?)?.toDouble(), x: (json['x'] as num?)?.toDouble(),
y: (json['y'] as num?)?.toDouble(), y: (json['y'] as num?)?.toDouble(),
version: json['version'] as String?,
); );
Sensor copyWith({ Sensor copyWith({
@@ -35,7 +38,7 @@ class Sensor {
int? roomId, int? roomId,
double? x, double? x,
double? y, double? y,
double? rssiRef, String? version,
}) => }) =>
Sensor( Sensor(
id: id, id: id,
@@ -45,5 +48,6 @@ class Sensor {
roomId: roomId ?? this.roomId, roomId: roomId ?? this.roomId,
x: x ?? this.x, x: x ?? this.x,
y: y ?? this.y, y: y ?? this.y,
version: version ?? this.version,
); );
} }
@@ -89,6 +89,7 @@ class _SensorDetailSheetState extends ConsumerState<SensorDetailSheet> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sensorAsync = ref.watch(sensorProvider(widget.sensorId)); final sensorAsync = ref.watch(sensorProvider(widget.sensorId));
final roomsAsync = ref.watch(roomsProvider); final roomsAsync = ref.watch(roomsProvider);
final versionAsync = ref.watch(sensorVersionProvider(widget.sensorId));
return sensorAsync.when( return sensorAsync.when(
loading: () => const SizedBox( loading: () => const SizedBox(
@@ -110,9 +111,12 @@ class _SensorDetailSheetState extends ConsumerState<SensorDetailSheet> {
?.name, ?.name,
); );
final version = versionAsync.whenOrNull(data: (v) => v);
return _SheetBody( return _SheetBody(
sensor: sensor, sensor: sensor,
roomName: roomName, roomName: roomName,
version: version,
editing: _editing, editing: _editing,
nameCtrl: _nameCtrl, nameCtrl: _nameCtrl,
onEditToggle: () => setState(() { onEditToggle: () => setState(() {
@@ -132,6 +136,7 @@ class _SheetBody extends StatelessWidget {
const _SheetBody({ const _SheetBody({
required this.sensor, required this.sensor,
required this.roomName, required this.roomName,
required this.version,
required this.editing, required this.editing,
required this.nameCtrl, required this.nameCtrl,
required this.onEditToggle, required this.onEditToggle,
@@ -142,6 +147,7 @@ class _SheetBody extends StatelessWidget {
final Sensor sensor; final Sensor sensor;
final String? roomName; final String? roomName;
final String? version;
final bool editing; final bool editing;
final TextEditingController nameCtrl; final TextEditingController nameCtrl;
final VoidCallback onEditToggle; final VoidCallback onEditToggle;
@@ -210,6 +216,7 @@ class _SheetBody extends StatelessWidget {
? '(${sensor.x!.toStringAsFixed(2)}, ${sensor.y!.toStringAsFixed(2)})' ? '(${sensor.x!.toStringAsFixed(2)}, ${sensor.y!.toStringAsFixed(2)})'
: 'Not placed', : 'Not placed',
), ),
_InfoRow(label: 'Firmware', value: version ?? ''),
const SizedBox(height: 24), const SizedBox(height: 24),
FilledButton.icon( FilledButton.icon(
icon: Icon(Icons.my_location), icon: Icon(Icons.my_location),
+5
View File
@@ -145,6 +145,11 @@ final sensorProvider =
return ref.watch(sensorRepositoryProvider).getSensor(id); return ref.watch(sensorRepositoryProvider).getSensor(id);
}); });
final sensorVersionProvider =
FutureProvider.autoDispose.family<String?, int>((ref, id) {
return ref.watch(sensorRepositoryProvider).getVersion(id);
});
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Tag data // Tag data
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------