fix: Deduplicate telemetry from 0x8B + 0x8C double delivery

When firmware sends telemetry via both pushTelemetryResponse (0x8B)
and pushBinaryResponse (0x8C), the same LPP data was parsed and
applied twice, causing duplicate sensor entries.

Added hash-based dedup: same payload for same contact within 2s is
skipped. Also added minimum length check for binary responses.
This commit is contained in:
Janez T
2026-03-18 14:24:38 +01:00
parent 29b75a3155
commit 67d8e1c906
2 changed files with 26 additions and 4 deletions

View File

@@ -1338,11 +1338,14 @@ class AppProvider with ChangeNotifier {
return;
}
debugPrint(
'📊 [AppProvider] Binary response (0x8C) received - updating contact telemetry',
'📊 [AppProvider] Binary response (0x8C tag=$tag) received',
);
// Binary response tag 0 = telemetry data (Cayenne LPP format)
// Other tags may be used for different data types in the future
contactsProvider.updateTelemetry(publicKeyPrefix, responseData);
// Binary responses carry Cayenne LPP telemetry data.
// The data starts with a channel byte — valid LPP always has at least
// 3 bytes (channel + type + value). Skip clearly non-telemetry payloads.
if (responseData.length >= 3) {
contactsProvider.updateTelemetry(publicKeyPrefix, responseData);
}
};
// When raw binary data is received (PUSH_CODE_RAW_DATA 0x84)

View File

@@ -926,6 +926,10 @@ class ContactsProvider with ChangeNotifier {
}
/// Update contact telemetry
// Dedup: track last telemetry data hash per contact to avoid processing
// the same payload twice (0x8B + 0x8C can both fire for the same data).
final Map<String, (int, DateTime)> _lastTelemetryHash = {};
void updateTelemetry(Uint8List publicKeyPrefix, Uint8List lppData) {
debugPrint('📊 [ContactsProvider] updateTelemetry() called');
debugPrint(
@@ -933,6 +937,21 @@ class ContactsProvider with ChangeNotifier {
);
debugPrint(' LPP data size: ${lppData.length} bytes');
// Deduplicate: same data for same contact within 2 seconds = skip
final prefixHex = publicKeyPrefix
.map((b) => b.toRadixString(16).padLeft(2, '0'))
.join();
final dataHash = lppData.fold<int>(0, (h, b) => h * 31 + b);
final now = DateTime.now();
final last = _lastTelemetryHash[prefixHex];
if (last != null &&
last.$1 == dataHash &&
now.difference(last.$2).inSeconds < 2) {
debugPrint(' ⏭️ Duplicate telemetry payload, skipping');
return;
}
_lastTelemetryHash[prefixHex] = (dataHash, now);
// Find contact by public key prefix
final contact = _findContactByPrefix(publicKeyPrefix);
if (contact == null) {