feat(mqtt): add neighbors JSON payload builder (host-tested)
Add buildNeighborsMessage to the pure MQTTPayloadBuilder core and a thin delegating wrapper + NeighborsMessageEntry alias on MQTTMessageBuilder, so the neighbors topic is built by the same firmware-facing API as status/ packet/raw while the layout logic stays exercisable by native tests. The document is bounded to the publish buffer: entries arrive ordered most- to least-useful and the tail is dropped once the next entry would overflow, so a fixed PSRAM buffer can never be handed truncated JSON. Uses ArduinoJson v7 idioms (.to<JsonObject>()/.add<JsonObject>()) to stay warning-clean under -Werror, unlike the deprecated createNested* forms. Adds three test_mqtt_payload_builder cases: self+entry round-trip, empty table / null scopes, and bounded-growth tail-drop under a tight buffer.
This commit is contained in:
1 parent
8d7a47abf7
commit
e36aee04d4
5 files changed
+182
No files matched your search
@@ -102,6 +102,22 @@ int MQTTMessageBuilder::buildRawMessage(
|
||||
origin, origin_id, timestamp, raw, buffer, buffer_size);
|
||||
}
|
||||
|
||||
int MQTTMessageBuilder::buildNeighborsMessage(
|
||||
JsonDocument& doc,
|
||||
const char* origin,
|
||||
const char* origin_id,
|
||||
const char* timestamp,
|
||||
const char* self_scopes,
|
||||
const NeighborsMessageEntry* neighbors,
|
||||
int neighbor_count,
|
||||
char* buffer,
|
||||
size_t buffer_size
|
||||
) {
|
||||
return MQTTPayloadBuilder::buildNeighborsMessage(
|
||||
doc, origin, origin_id, timestamp, self_scopes, neighbors, neighbor_count,
|
||||
buffer, buffer_size);
|
||||
}
|
||||
|
||||
int MQTTMessageBuilder::buildPacketJSON(
|
||||
JsonDocument& doc,
|
||||
mesh::Packet* packet,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "MeshCore.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include "MQTTPayloadBuilder.h"
|
||||
#include <Mesh.h>
|
||||
#include <Timezone.h>
|
||||
|
||||
@@ -153,6 +154,22 @@ public:
|
||||
size_t buffer_size
|
||||
);
|
||||
|
||||
// Neighbors table entry + JSON builder. The layout logic lives in the pure,
|
||||
// host-tested MQTTPayloadBuilder; this is the firmware-facing alias/delegate,
|
||||
// matching the status/packet/raw builders.
|
||||
using NeighborsMessageEntry = MQTTPayloadBuilder::NeighborsMessageEntry;
|
||||
static int buildNeighborsMessage(
|
||||
JsonDocument& doc,
|
||||
const char* origin,
|
||||
const char* origin_id,
|
||||
const char* timestamp,
|
||||
const char* self_scopes,
|
||||
const NeighborsMessageEntry* neighbors,
|
||||
int neighbor_count,
|
||||
char* buffer,
|
||||
size_t buffer_size
|
||||
);
|
||||
|
||||
/**
|
||||
* Convert packet to JSON message
|
||||
*
|
||||
|
||||
@@ -184,3 +184,48 @@ int MQTTPayloadBuilder::buildRawMessage(
|
||||
|
||||
return serializeComplete(root, buffer, buffer_size);
|
||||
}
|
||||
|
||||
int MQTTPayloadBuilder::buildNeighborsMessage(
|
||||
JsonDocument& doc,
|
||||
const char* origin,
|
||||
const char* origin_id,
|
||||
const char* timestamp,
|
||||
const char* self_scopes,
|
||||
const NeighborsMessageEntry* neighbors,
|
||||
int neighbor_count,
|
||||
char* buffer,
|
||||
size_t buffer_size
|
||||
) {
|
||||
if (!buffer || buffer_size == 0) return 0;
|
||||
|
||||
doc.clear();
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
root["timestamp"] = timestamp;
|
||||
root["origin"] = origin;
|
||||
root["origin_id"] = origin_id;
|
||||
|
||||
JsonObject self = root["self"].to<JsonObject>();
|
||||
self["scopes"] = self_scopes ? self_scopes : "";
|
||||
|
||||
JsonArray arr = root["neighbors"].to<JsonArray>();
|
||||
if (measureJson(root) >= buffer_size) return 0;
|
||||
|
||||
for (int i = 0; i < neighbor_count; i++) {
|
||||
JsonObject nb = arr.add<JsonObject>();
|
||||
nb["pubkey"] = neighbors[i].pubkey_hex;
|
||||
nb["snr"] = neighbors[i].snr;
|
||||
nb["heard_secs_ago"] = neighbors[i].heard_secs_ago;
|
||||
nb["scopes"] = neighbors[i].scopes ? neighbors[i].scopes : "";
|
||||
nb["status"] = neighbors[i].status;
|
||||
|
||||
// Entries arrive ordered most- to least-useful. Stop as soon as the next
|
||||
// one would fill the fixed publish buffer, dropping the remaining tail so
|
||||
// document growth stays bounded.
|
||||
if (measureJson(root) >= buffer_size) {
|
||||
arr.remove(arr.size() - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return serializeComplete(root, buffer, buffer_size);
|
||||
}
|
||||
@@ -68,5 +68,28 @@ public:
|
||||
char* buffer,
|
||||
size_t buffer_size
|
||||
);
|
||||
|
||||
struct NeighborsMessageEntry {
|
||||
const char* pubkey_hex;
|
||||
float snr;
|
||||
uint32_t heard_secs_ago;
|
||||
const char* scopes;
|
||||
const char* status;
|
||||
};
|
||||
|
||||
// Build neighbors-table JSON for the meshcore/{iata}/{device}/neighbors topic.
|
||||
// Callers order entries most- to least-useful; document growth is bounded to
|
||||
// buffer_size and the remaining tail is dropped once the next entry won't fit.
|
||||
static int buildNeighborsMessage(
|
||||
JsonDocument& doc,
|
||||
const char* origin,
|
||||
const char* origin_id,
|
||||
const char* timestamp,
|
||||
const char* self_scopes,
|
||||
const NeighborsMessageEntry* neighbors,
|
||||
int neighbor_count,
|
||||
char* buffer,
|
||||
size_t buffer_size
|
||||
);
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user