fix(mqtt): omit SNR/RSSI instead of publishing placeholder values

The reconstruction-less fallback path in buildPacketJSON (queued packet
with no captured raw frame that cannot be re-serialized) published
fabricated SNR 12.5 / RSSI -65 that consumers could not distinguish
from real radio readings. It now passes NAN / MQTT_RSSI_UNKNOWN, and
buildPacketMessage omits the SNR/RSSI keys entirely when no measurement
exists, mirroring the existing score omission.

Ports the fix from ACETyr's PR #13 (0a037040) on mqtt-bridge-implementation.

Co-Authored-By: ACETyr <35745290+ACETyr@users.noreply.github.com>
This commit is contained in:
agessamanandACETyr committed 2026-09-26 10:46:11 -07:00
1 parent 16fe47cd0e
commit f9df11f33e
4 files changed
+93 -6

No files matched your search

@@ -36,6 +36,16 @@ static int buildRepresentativePacket(JsonDocument& scratch, const char* directio
path_hash_size, 64, buffer, buffer_size);
}
static int buildPacketWithMetrics(JsonDocument& scratch, const char* direction,
float snr, int rssi, float score,
char* buffer, size_t buffer_size) {
return MQTTPayloadBuilder::buildPacketMessage(
scratch, "DEN Repeater", "0123456789ABCDEF", kTimestamp, direction,
"12:34:56", "18/07/2026", 42, 4, "D", 20, "A0B1C2D3",
snr, rssi, score, "89ABCDEF01234567", nullptr, 0, 0, 64,
buffer, buffer_size);
}
TEST(MQTTPayloadBuilder, MinimalStatusHasExactRequiredContract) {
JsonDocument scratch;
char buffer[768];
@@ -169,6 +179,72 @@ TEST(MQTTPayloadBuilder, RxPacketOmitsUnknownNanScore) {
EXPECT_FALSE(parsed["score"].is<JsonVariant>());
}
TEST(MQTTPayloadBuilder, RxPacketOmitsUnknownSnrAndRssi) {
JsonDocument scratch;
char buffer[2048];
int len = buildPacketWithMetrics(
scratch, "rx", NAN, MQTT_RSSI_UNKNOWN, NAN, buffer, sizeof(buffer));
ASSERT_GT(len, 0);
JsonDocument parsed;
ASSERT_FALSE(deserializeJson(parsed, buffer));
EXPECT_FALSE(parsed["SNR"].is<JsonVariant>());
EXPECT_FALSE(parsed["RSSI"].is<JsonVariant>());
EXPECT_FALSE(parsed["score"].is<JsonVariant>());
}
TEST(MQTTPayloadBuilder, RxPacketFormatsRealSnrAndRssi) {
JsonDocument scratch;
char buffer[2048];
int len = buildPacketWithMetrics(
scratch, "rx", 7.25f, -93, NAN, buffer, sizeof(buffer));
ASSERT_GT(len, 0);
JsonDocument parsed;
ASSERT_FALSE(deserializeJson(parsed, buffer));
EXPECT_STREQ("7.2", parsed["SNR"].as<const char*>());
EXPECT_STREQ("-93", parsed["RSSI"].as<const char*>());
EXPECT_FALSE(parsed["score"].is<JsonVariant>());
}
TEST(MQTTPayloadBuilder, RxPacketOmitsOnlyUnknownMetric) {
// SNR unknown, RSSI real: only the SNR key is omitted.
JsonDocument scratch;
char buffer[2048];
int len = buildPacketWithMetrics(
scratch, "rx", NAN, -93, NAN, buffer, sizeof(buffer));
ASSERT_GT(len, 0);
JsonDocument parsed;
ASSERT_FALSE(deserializeJson(parsed, buffer));
EXPECT_FALSE(parsed["SNR"].is<JsonVariant>());
EXPECT_STREQ("-93", parsed["RSSI"].as<const char*>());
// RSSI unknown, SNR real: only the RSSI key is omitted.
len = buildPacketWithMetrics(
scratch, "rx", 7.25f, MQTT_RSSI_UNKNOWN, NAN, buffer, sizeof(buffer));
ASSERT_GT(len, 0);
parsed.clear();
ASSERT_FALSE(deserializeJson(parsed, buffer));
EXPECT_STREQ("7.2", parsed["SNR"].as<const char*>());
EXPECT_FALSE(parsed["RSSI"].is<JsonVariant>());
}
TEST(MQTTPayloadBuilder, TxPacketOmitsSnrRssiAndScoreWithRealValues) {
JsonDocument scratch;
char buffer[2048];
int len = buildPacketWithMetrics(
scratch, "tx", 7.25f, -93, 0.5f, buffer, sizeof(buffer));
ASSERT_GT(len, 0);
JsonDocument parsed;
ASSERT_FALSE(deserializeJson(parsed, buffer));
EXPECT_FALSE(parsed["SNR"].is<JsonVariant>());
EXPECT_FALSE(parsed["RSSI"].is<JsonVariant>());
EXPECT_FALSE(parsed["score"].is<JsonVariant>());
}
TEST(MQTTPayloadBuilder, RawMessageHasExactContractAndEscapesData) {
char buffer[512];
JsonDocument doc;