mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
Fix telemetry merge bug
This commit is contained in:
@@ -878,7 +878,16 @@ class ContactsProvider with ChangeNotifier {
|
||||
' ⚠️ Retaining last valid GPS. Incoming telemetry GPS is invalid/missing: $incomingGps',
|
||||
);
|
||||
}
|
||||
telemetry = mergedTelemetry;
|
||||
telemetry = ContactTelemetry(
|
||||
gpsLocation: telemetry.gpsLocation,
|
||||
batteryPercentage: mergedTelemetry.batteryPercentage,
|
||||
batteryMilliVolts: mergedTelemetry.batteryMilliVolts,
|
||||
temperature: mergedTelemetry.temperature,
|
||||
timestamp: mergedTelemetry.timestamp,
|
||||
humidity: mergedTelemetry.humidity,
|
||||
pressure: mergedTelemetry.pressure,
|
||||
extraSensorData: telemetry.extraSensorData,
|
||||
);
|
||||
}
|
||||
|
||||
// Update contact with new telemetry AND last seen time
|
||||
@@ -993,10 +1002,10 @@ class ContactsProvider with ChangeNotifier {
|
||||
// last known reading for any field that is omitted in the incoming update.
|
||||
final incomingGps = _getValidGpsOrNull(incomingTelemetry.gpsLocation);
|
||||
final previousGps = _getValidGpsOrNull(existingTelemetry?.gpsLocation);
|
||||
final mergedExtraSensorData = <String, dynamic>{
|
||||
...?existingTelemetry?.extraSensorData,
|
||||
...?incomingTelemetry.extraSensorData,
|
||||
};
|
||||
final mergedExtraSensorData = _mergeExtraSensorData(
|
||||
existingTelemetry?.extraSensorData,
|
||||
incomingTelemetry.extraSensorData,
|
||||
);
|
||||
|
||||
return ContactTelemetry(
|
||||
gpsLocation: incomingGps ?? previousGps,
|
||||
@@ -1017,6 +1026,49 @@ class ContactsProvider with ChangeNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _mergeExtraSensorData(
|
||||
Map<String, dynamic>? existingExtraSensorData,
|
||||
Map<String, dynamic>? incomingExtraSensorData,
|
||||
) {
|
||||
final merged = <String, dynamic>{...?existingExtraSensorData};
|
||||
if (incomingExtraSensorData == null || incomingExtraSensorData.isEmpty) {
|
||||
return merged;
|
||||
}
|
||||
|
||||
final incomingMetricFamilies = incomingExtraSensorData.keys
|
||||
.map(_telemetryMetricFamilyForKey)
|
||||
.whereType<String>()
|
||||
.toSet();
|
||||
if (incomingMetricFamilies.isNotEmpty) {
|
||||
merged.removeWhere((key, _) {
|
||||
final family = _telemetryMetricFamilyForKey(key);
|
||||
return family != null && incomingMetricFamilies.contains(family);
|
||||
});
|
||||
}
|
||||
|
||||
merged.addAll(incomingExtraSensorData);
|
||||
return merged;
|
||||
}
|
||||
|
||||
String? _telemetryMetricFamilyForKey(String key) {
|
||||
const sourcePrefix = '__source_channel:';
|
||||
if (key.startsWith(sourcePrefix)) {
|
||||
return key.substring(sourcePrefix.length);
|
||||
}
|
||||
|
||||
final separatorIndex = key.lastIndexOf('_');
|
||||
if (separatorIndex <= 0 || separatorIndex == key.length - 1) {
|
||||
return key;
|
||||
}
|
||||
|
||||
final suffix = key.substring(separatorIndex + 1);
|
||||
if (int.tryParse(suffix) == null) {
|
||||
return key;
|
||||
}
|
||||
|
||||
return key.substring(0, separatorIndex);
|
||||
}
|
||||
|
||||
int _coordinateToAdvertMicrodegrees(double coordinate) {
|
||||
return (coordinate * 1e6).round();
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ void main() {
|
||||
expect(updated.telemetry!.extraSensorData, containsPair('co2', 415.0));
|
||||
});
|
||||
|
||||
test('retains prior telemetry fields across sparse telemetry updates', () {
|
||||
test('retains scalar telemetry but wipes stale extra sensor fields on refresh', () {
|
||||
final fullTelemetry = ContactTelemetry(
|
||||
gpsLocation: const LatLng(46.0569, 14.5058),
|
||||
batteryPercentage: 54.0,
|
||||
@@ -366,7 +366,55 @@ void main() {
|
||||
expect(updated.telemetry!.temperature, equals(19.5));
|
||||
expect(updated.telemetry!.humidity, equals(58.0));
|
||||
expect(updated.telemetry!.pressure, equals(1011.2));
|
||||
expect(updated.telemetry!.extraSensorData, containsPair('pm25', 8.0));
|
||||
expect(updated.telemetry!.extraSensorData, isNull);
|
||||
});
|
||||
|
||||
test('replaces old source-channel mappings when a metric moves channels', () {
|
||||
final initialTelemetry = ContactTelemetry(
|
||||
gpsLocation: null,
|
||||
batteryPercentage: null,
|
||||
batteryMilliVolts: null,
|
||||
temperature: 21.5,
|
||||
timestamp: DateTime.now().subtract(const Duration(minutes: 2)),
|
||||
humidity: null,
|
||||
pressure: null,
|
||||
extraSensorData: const {
|
||||
'__source_channel:temperature': 2,
|
||||
'temperature_2': 21.5,
|
||||
'humidity_4': 66.0,
|
||||
},
|
||||
);
|
||||
|
||||
provider.addOrUpdateContact(
|
||||
createContact(
|
||||
key: publicKey,
|
||||
type: ContactType.chat,
|
||||
).copyWith(telemetry: initialTelemetry),
|
||||
);
|
||||
|
||||
final movedChannelTelemetry = CayenneLppParser.createTemperatureData(
|
||||
23.5,
|
||||
channel: 3,
|
||||
);
|
||||
|
||||
provider.updateTelemetry(publicKey.sublist(0, 6), movedChannelTelemetry);
|
||||
|
||||
final updated = provider.findContactByKey(publicKey)!;
|
||||
expect(updated.telemetry, isNotNull);
|
||||
expect(updated.telemetry!.temperature, closeTo(23.5, 0.1));
|
||||
expect(
|
||||
updated.telemetry!.extraSensorData,
|
||||
containsPair('__source_channel:temperature', 3),
|
||||
);
|
||||
expect(
|
||||
updated.telemetry!.extraSensorData,
|
||||
containsPair('temperature_3', closeTo(23.5, 0.1)),
|
||||
);
|
||||
expect(
|
||||
updated.telemetry!.extraSensorData,
|
||||
isNot(contains('temperature_2')),
|
||||
);
|
||||
expect(updated.telemetry!.extraSensorData, isNot(contains('humidity_4')));
|
||||
});
|
||||
|
||||
test('builds message snapshot from latest valid telemetry', () {
|
||||
|
||||
Reference in New Issue
Block a user