feat: implement sensor calibration flow
This commit is contained in:
@@ -59,4 +59,36 @@ class PhoenixSensorRepository implements SensorRepository {
|
||||
Stream<Map<String, dynamic>> sensorEvents() => realtime
|
||||
.channelMessages('sensors')
|
||||
.map((m) => {'event': m.event, ...m.payload});
|
||||
|
||||
@override
|
||||
Future<int> beginCalibration(int id) async {
|
||||
final json = await client.beginCalibration(id);
|
||||
return json['samples_needed'] as int;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startStage(int id, double distance) =>
|
||||
client.startStage(id, distance);
|
||||
|
||||
@override
|
||||
Future<({double rssiRef, double pathLossExp})> finishCalibration(
|
||||
int id) async {
|
||||
final json = await client.finishCalibration(id);
|
||||
return (
|
||||
rssiRef: (json['rssi_ref'] as num).toDouble(),
|
||||
pathLossExp: (json['path_loss_exp'] as num).toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> cancelCalibration(int id) => client.cancelCalibration(id);
|
||||
|
||||
@override
|
||||
Stream<({String event, Map<String, dynamic> payload})> calibrationEvents(
|
||||
String sensorDeviceId) =>
|
||||
realtime.channelMessages('calibration:$sensorDeviceId');
|
||||
|
||||
@override
|
||||
void leaveCalibrationChannel(String sensorDeviceId) =>
|
||||
realtime.leaveChannel('calibration:$sensorDeviceId');
|
||||
}
|
||||
|
||||
@@ -16,4 +16,30 @@ abstract class SensorRepository {
|
||||
/// Stream of raw SensorsChannel messages. Each map contains an `event` key
|
||||
/// (`sensor_announced` or `sensor_enrollment_timeout`) plus the payload.
|
||||
Stream<Map<String, dynamic>> sensorEvents();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Calibration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Enters calibration mode on the sensor. Returns the number of samples the
|
||||
/// server will collect per stage.
|
||||
Future<int> beginCalibration(int id);
|
||||
|
||||
/// Starts a collection stage at [distance] metres.
|
||||
Future<void> startStage(int id, double distance);
|
||||
|
||||
/// Runs least-squares regression over all completed stages and persists the
|
||||
/// result. Returns the fitted (rssiRef, pathLossExp) pair.
|
||||
Future<({double rssiRef, double pathLossExp})> finishCalibration(int id);
|
||||
|
||||
/// Aborts calibration and discards all accumulated stage data.
|
||||
Future<void> cancelCalibration(int id);
|
||||
|
||||
/// Real-time events from the server's CalibrationChannel.
|
||||
/// Topic: `calibration:{sensorDeviceId}` (the string BLE device ID).
|
||||
Stream<({String event, Map<String, dynamic> payload})> calibrationEvents(
|
||||
String sensorDeviceId);
|
||||
|
||||
/// Leaves the calibration Phoenix channel for [sensorDeviceId].
|
||||
void leaveCalibrationChannel(String sensorDeviceId);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,12 @@ class RealtimeDataClient {
|
||||
.map((msg) => (event: msg.event.value, payload: msg.payload ?? const {}));
|
||||
}
|
||||
|
||||
/// Leaves [topic] and removes it from the channel cache.
|
||||
void leaveChannel(String topic) {
|
||||
final ch = _channels.remove(topic);
|
||||
ch?.leave();
|
||||
}
|
||||
|
||||
/// Pushes [event] on [topic] and waits for the server reply.
|
||||
/// The channel must have been joined first via [channel].
|
||||
Future<Map<String, dynamic>> push(
|
||||
|
||||
@@ -38,17 +38,22 @@ class SensorClient extends LocaliserdClient {
|
||||
})
|
||||
as Map<String, dynamic>;
|
||||
|
||||
Future<Map<String, dynamic>> startCalibration(
|
||||
int id,
|
||||
double referenceDistance,
|
||||
) async =>
|
||||
await post('/api/sensors/$id/calibration/start', {
|
||||
'reference_distance': referenceDistance,
|
||||
Future<Map<String, dynamic>> beginCalibration(int id) async =>
|
||||
await post('/api/sensors/$id/calibration/begin') as Map<String, dynamic>;
|
||||
|
||||
Future<Map<String, dynamic>> startStage(int id, double distance) async =>
|
||||
await post('/api/sensors/$id/calibration/stage', {
|
||||
'distance': distance,
|
||||
})
|
||||
as Map<String, dynamic>;
|
||||
|
||||
Future<Map<String, dynamic>> stopCalibration(int id) async =>
|
||||
await post('/api/sensors/$id/calibration/stop') as Map<String, dynamic>;
|
||||
Future<Map<String, dynamic>> finishCalibration(int id) async =>
|
||||
await post(
|
||||
'/api/sensors/$id/calibration/finish',
|
||||
) as Map<String, dynamic>;
|
||||
|
||||
Future<void> cancelCalibration(int id) =>
|
||||
delete('/api/sensors/$id/calibration');
|
||||
|
||||
Future<String> getVersion(int id) async {
|
||||
final response =
|
||||
|
||||
Reference in New Issue
Block a user