From 61661aed50faef2f3c39ea865d2f87616a91da0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 31 May 2023 13:18:09 +0200 Subject: [PATCH 1/6] Broadcast neighbor info also update trunk --- .trunk/trunk.yaml | 4 +- src/mesh/NodeDB.cpp | 4 + src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 14 +- .../generated/meshtastic/module_config.pb.c | 3 + .../generated/meshtastic/module_config.pb.h | 30 ++- src/modules/Modules.cpp | 2 + src/modules/NeighborInfoModule.cpp | 249 ++++++++++++++++++ src/modules/NeighborInfoModule.h | 72 +++++ src/mqtt/MQTT.cpp | 18 ++ 10 files changed, 390 insertions(+), 8 deletions(-) create mode 100644 src/modules/NeighborInfoModule.cpp create mode 100644 src/modules/NeighborInfoModule.h diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index cdf662e1f..8ab9166fb 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.9.1 + version: 1.10.0 plugins: sources: - id: trunk @@ -10,7 +10,7 @@ lint: enabled: - taplo@0.7.0 - ruff@0.0.265 - - yamllint@1.31.0 + - yamllint@1.32.0 - isort@5.12.0 - markdownlint@0.34.0 - oxipng@8.0.0 diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b1dd3d06d..62b7a650e 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -14,6 +14,7 @@ #include "error.h" #include "main.h" #include "mesh-pb-constants.h" +#include "modules/NeighborInfoModule.h" #include #include #include @@ -128,6 +129,8 @@ bool NodeDB::factoryReset() installDefaultChannels(); // third, write everything to disk saveToDisk(); + // write NeighbourInfo + neighborInfoModule->saveProtoForModule(); #ifdef ARCH_ESP32 // This will erase what's in NVS including ssl keys, persistant variables and ble pairing nvs_flash_erase(); @@ -259,6 +262,7 @@ void NodeDB::resetNodes() devicestate.node_db_count = 0; memset(devicestate.node_db, 0, sizeof(devicestate.node_db)); saveDeviceStateToDisk(); + neighborInfoModule->resetNeighbors(); } void NodeDB::installDefaultDeviceState() diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index ffce0cdd4..1def963ae 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -227,7 +227,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; #define meshtastic_ChannelFile_size 638 #define meshtastic_DeviceState_size 22736 #define meshtastic_NodeRemoteHardwarePin_size 29 -#define meshtastic_OEMStore_size 3142 +#define meshtastic_OEMStore_size 3152 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index fd1c8a5c1..d70acc7fc 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -72,6 +72,9 @@ typedef struct _meshtastic_LocalModuleConfig { /* The part of the config that is specific to the Remote Hardware module */ bool has_remote_hardware; meshtastic_ModuleConfig_RemoteHardwareConfig remote_hardware; + /* The part of the config that is specific to the Neighbor Info module */ + bool has_neighbor_info; + meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info; } meshtastic_LocalModuleConfig; @@ -81,9 +84,9 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0} -#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default} +#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default} #define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0} -#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero} +#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_LocalConfig_device_tag 1 @@ -104,6 +107,7 @@ extern "C" { #define meshtastic_LocalModuleConfig_version_tag 8 #define meshtastic_LocalModuleConfig_audio_tag 9 #define meshtastic_LocalModuleConfig_remote_hardware_tag 10 +#define meshtastic_LocalModuleConfig_neighbor_info_tag 11 /* Struct field encoding specification for nanopb */ #define meshtastic_LocalConfig_FIELDLIST(X, a) \ @@ -135,7 +139,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, telemetry, 6) \ X(a, STATIC, OPTIONAL, MESSAGE, canned_message, 7) \ X(a, STATIC, SINGULAR, UINT32, version, 8) \ X(a, STATIC, OPTIONAL, MESSAGE, audio, 9) \ -X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) +X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \ +X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) #define meshtastic_LocalModuleConfig_CALLBACK NULL #define meshtastic_LocalModuleConfig_DEFAULT NULL #define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig @@ -147,6 +152,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) #define meshtastic_LocalModuleConfig_canned_message_MSGTYPE meshtastic_ModuleConfig_CannedMessageConfig #define meshtastic_LocalModuleConfig_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig #define meshtastic_LocalModuleConfig_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig +#define meshtastic_LocalModuleConfig_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig extern const pb_msgdesc_t meshtastic_LocalConfig_msg; extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; @@ -157,7 +163,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_LocalConfig_size 461 -#define meshtastic_LocalModuleConfig_size 535 +#define meshtastic_LocalModuleConfig_size 545 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.c b/src/mesh/generated/meshtastic/module_config.pb.c index 123a4fedf..9352feb17 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.c +++ b/src/mesh/generated/meshtastic/module_config.pb.c @@ -15,6 +15,9 @@ PB_BIND(meshtastic_ModuleConfig_MQTTConfig, meshtastic_ModuleConfig_MQTTConfig, PB_BIND(meshtastic_ModuleConfig_RemoteHardwareConfig, meshtastic_ModuleConfig_RemoteHardwareConfig, AUTO) +PB_BIND(meshtastic_ModuleConfig_NeighborInfoConfig, meshtastic_ModuleConfig_NeighborInfoConfig, AUTO) + + PB_BIND(meshtastic_ModuleConfig_AudioConfig, meshtastic_ModuleConfig_AudioConfig, AUTO) diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 53a55073f..6273a89ae 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -114,6 +114,15 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig { char root[16]; } meshtastic_ModuleConfig_MQTTConfig; +/* NeighborInfoModule Config */ +typedef struct _meshtastic_ModuleConfig_NeighborInfoConfig { + /* Whether the Module is enabled */ + bool enabled; + /* Interval in seconds of how often we should try to send our + Neighbor Info to the mesh */ + uint32_t update_interval; +} meshtastic_ModuleConfig_NeighborInfoConfig; + /* Audio Config for codec2 voice */ typedef struct _meshtastic_ModuleConfig_AudioConfig { /* Whether Audio is enabled */ @@ -313,6 +322,8 @@ typedef struct _meshtastic_ModuleConfig { meshtastic_ModuleConfig_AudioConfig audio; /* TODO: REPLACE */ meshtastic_ModuleConfig_RemoteHardwareConfig remote_hardware; + /* TODO: REPLACE */ + meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info; } payload_variant; } meshtastic_ModuleConfig; @@ -345,6 +356,7 @@ extern "C" { + #define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud #define meshtastic_ModuleConfig_SerialConfig_baud_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Baud @@ -365,6 +377,7 @@ extern "C" { #define meshtastic_ModuleConfig_init_default {0, {meshtastic_ModuleConfig_MQTTConfig_init_default}} #define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, ""} #define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}} +#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0} #define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -376,6 +389,7 @@ extern "C" { #define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}} #define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, ""} #define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}} +#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0} #define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -394,6 +408,8 @@ extern "C" { #define meshtastic_ModuleConfig_MQTTConfig_json_enabled_tag 6 #define meshtastic_ModuleConfig_MQTTConfig_tls_enabled_tag 7 #define meshtastic_ModuleConfig_MQTTConfig_root_tag 8 +#define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1 +#define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2 #define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1 #define meshtastic_ModuleConfig_AudioConfig_ptt_pin_tag 2 #define meshtastic_ModuleConfig_AudioConfig_bitrate_tag 3 @@ -464,6 +480,7 @@ extern "C" { #define meshtastic_ModuleConfig_canned_message_tag 7 #define meshtastic_ModuleConfig_audio_tag 8 #define meshtastic_ModuleConfig_remote_hardware_tag 9 +#define meshtastic_ModuleConfig_neighbor_info_tag 10 /* Struct field encoding specification for nanopb */ #define meshtastic_ModuleConfig_FIELDLIST(X, a) \ @@ -475,7 +492,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,range_test,payload_variant.r X(a, STATIC, ONEOF, MESSAGE, (payload_variant,telemetry,payload_variant.telemetry), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_variant.canned_message), 7) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) #define meshtastic_ModuleConfig_CALLBACK NULL #define meshtastic_ModuleConfig_DEFAULT NULL #define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig @@ -487,6 +505,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_vari #define meshtastic_ModuleConfig_payload_variant_canned_message_MSGTYPE meshtastic_ModuleConfig_CannedMessageConfig #define meshtastic_ModuleConfig_payload_variant_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig #define meshtastic_ModuleConfig_payload_variant_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig +#define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig #define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ @@ -508,6 +527,12 @@ X(a, STATIC, REPEATED, MESSAGE, available_pins, 3) #define meshtastic_ModuleConfig_RemoteHardwareConfig_DEFAULT NULL #define meshtastic_ModuleConfig_RemoteHardwareConfig_available_pins_MSGTYPE meshtastic_RemoteHardwarePin +#define meshtastic_ModuleConfig_NeighborInfoConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ +X(a, STATIC, SINGULAR, UINT32, update_interval, 2) +#define meshtastic_ModuleConfig_NeighborInfoConfig_CALLBACK NULL +#define meshtastic_ModuleConfig_NeighborInfoConfig_DEFAULT NULL + #define meshtastic_ModuleConfig_AudioConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \ X(a, STATIC, SINGULAR, UINT32, ptt_pin, 2) \ @@ -601,6 +626,7 @@ X(a, STATIC, SINGULAR, UENUM, type, 3) extern const pb_msgdesc_t meshtastic_ModuleConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_MQTTConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_RemoteHardwareConfig_msg; +extern const pb_msgdesc_t meshtastic_ModuleConfig_NeighborInfoConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_AudioConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_SerialConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_ExternalNotificationConfig_msg; @@ -614,6 +640,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_fields &meshtastic_ModuleConfig_msg #define meshtastic_ModuleConfig_MQTTConfig_fields &meshtastic_ModuleConfig_MQTTConfig_msg #define meshtastic_ModuleConfig_RemoteHardwareConfig_fields &meshtastic_ModuleConfig_RemoteHardwareConfig_msg +#define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg #define meshtastic_ModuleConfig_AudioConfig_fields &meshtastic_ModuleConfig_AudioConfig_msg #define meshtastic_ModuleConfig_SerialConfig_fields &meshtastic_ModuleConfig_SerialConfig_msg #define meshtastic_ModuleConfig_ExternalNotificationConfig_fields &meshtastic_ModuleConfig_ExternalNotificationConfig_msg @@ -628,6 +655,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_CannedMessageConfig_size 49 #define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40 #define meshtastic_ModuleConfig_MQTTConfig_size 220 +#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8 #define meshtastic_ModuleConfig_RangeTestConfig_size 10 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index df29698a2..710c9bfb7 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -5,6 +5,7 @@ #include "input/cardKbI2cImpl.h" #include "modules/AdminModule.h" #include "modules/CannedMessageModule.h" +#include "modules/NeighborInfoModule.h" #include "modules/NodeInfoModule.h" #include "modules/PositionModule.h" #include "modules/RemoteHardwareModule.h" @@ -89,6 +90,7 @@ void setupModules() } else { adminModule = new AdminModule(); traceRouteModule = new TraceRouteModule(); + neighborInfoModule = new NeighborInfoModule(); } // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp new file mode 100644 index 000000000..9e6df3d34 --- /dev/null +++ b/src/modules/NeighborInfoModule.cpp @@ -0,0 +1,249 @@ +#include "NeighborInfoModule.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" + +#define MAX_NEIGHBOR_AGE 10 * 60 * 1000 // 10 minutes +#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options +NeighborInfoModule *neighborInfoModule; + +static const char *neighborInfoConfigFile = "/prefs/neighbors.proto"; + +/* +Prints a single neighbor info packet and associated neighbors +Uses LOG_DEBUG, which equates to Console.log +NOTE: For debugging only +*/ +void NeighborInfoModule::printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np) +{ + LOG_DEBUG("%s NEIGHBORINFO PACKET from Node %d to Node %d (last sent by %d)\n", header, np->node_id, nodeDB.getNodeNum(), + np->last_sent_by_id); + LOG_DEBUG("----------------\n"); + LOG_DEBUG("Packet contains %d neighbors\n", np->neighbors_count); + for (int i = 0; i < np->neighbors_count; i++) { + LOG_DEBUG("Neighbor %d: node_id=%d, snr=%d\n", i, np->neighbors[i].node_id, np->neighbors[i].snr); + } + LOG_DEBUG("----------------\n"); +} +/* +Prints the nodeDB nodes so we can see whose nodeInfo we have +NOTE: for debugging only +*/ +void NeighborInfoModule::printNodeDBNodes(const char *header) +{ + int num_nodes = nodeDB.getNumNodes(); + LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum()); + LOG_DEBUG("----------------\n"); + LOG_DEBUG("DB contains %d nodes\n", num_nodes); + for (int i = 0; i < num_nodes; i++) { + meshtastic_NodeInfo *dbEntry = nodeDB.getNodeByIndex(i); + LOG_DEBUG(" Node %d: node_id=%d, snr=%d\n", i, dbEntry->num, dbEntry->snr); + } + LOG_DEBUG("----------------\n"); +} + +/* +Prints the nodeDB neighbors +NOTE: for debugging only +*/ +void NeighborInfoModule::printNodeDBNeighbors(const char *header) +{ + int num_neighbors = getNumNeighbors(); + LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum()); + LOG_DEBUG("----------------\n"); + LOG_DEBUG("DB contains %d neighbors\n", num_neighbors); + for (int i = 0; i < num_neighbors; i++) { + meshtastic_Neighbor *dbEntry = getNeighborByIndex(i); + LOG_DEBUG(" Node %d: node_id=%d, snr=%d\n", i, dbEntry->node_id, dbEntry->snr); + } + LOG_DEBUG("----------------\n"); +} + +/* +Prints the nodeDB with selectors for the neighbors we've chosen to send (inefficiently) +Uses LOG_DEBUG, which equates to Console.log +NOTE: For debugging only +*/ +void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np) +{ + int num_neighbors = getNumNeighbors(); + LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum()); + LOG_DEBUG("----------------\n"); + LOG_DEBUG("Selected %d neighbors of %d DB neighbors\n", np->neighbors_count, num_neighbors); + for (int i = 0; i < num_neighbors; i++) { + meshtastic_Neighbor *dbEntry = getNeighborByIndex(i); + bool chosen = false; + for (int j = 0; j < np->neighbors_count; j++) { + if (np->neighbors[j].node_id == dbEntry->node_id) { + chosen = true; + } + } + if (!chosen) { + LOG_DEBUG(" Node %d: neighbor=%d, snr=%d\n", i, dbEntry->node_id, dbEntry->snr); + } else { + LOG_DEBUG("---> Node %d: neighbor=%d, snr=%d\n", i, dbEntry->node_id, dbEntry->snr); + } + } + LOG_DEBUG("----------------\n"); +} + +/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */ +NeighborInfoModule::NeighborInfoModule() + : neighbors(neighborState.neighbors), numNeighbors(&neighborState.neighbors_count), + ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg), concurrency::OSThread( + "NeighborInfoModule") +{ + ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP; + + if (moduleConfig.neighbor_info.enabled) { + this->loadProtoForModule(); + setIntervalFromNow(35 * 1000); + } else { + LOG_DEBUG("NeighborInfoModule is disabled\n"); + disable(); + } +} + +/* +Allocate a zeroed neighbor info packet +*/ +meshtastic_NeighborInfo *NeighborInfoModule::allocateNeighborInfoPacket() +{ + meshtastic_NeighborInfo *neighborInfo = (meshtastic_NeighborInfo *)malloc(sizeof(meshtastic_NeighborInfo)); + memset(neighborInfo, 0, sizeof(meshtastic_NeighborInfo)); + return neighborInfo; +} + +/* +Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time +Assumes that the neighborInfo packet has been allocated +@returns the number of entries collected +*/ +uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo) +{ + int num_neighbors = getNumNeighbors(); + int current_time = getTime(); + int my_node_id = nodeDB.getNodeNum(); + neighborInfo->node_id = my_node_id; + neighborInfo->last_sent_by_id = my_node_id; + + for (int i = 0; i < num_neighbors; i++) { + meshtastic_Neighbor *dbEntry = getNeighborByIndex(i); + if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) { + neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id; + neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr; + neighborInfo->neighbors_count++; + } + } + printNodeDBNodes("DBSTATE"); + printNodeDBNeighbors("NEIGHBORS"); + printNodeDBSelection("COLLECTED", neighborInfo); + return neighborInfo->neighbors_count; +} + +/* Send neighbor info to the mesh */ +void NeighborInfoModule::sendNeighborInfo(NodeNum dest, bool wantReplies) +{ + meshtastic_NeighborInfo *neighborInfo = allocateNeighborInfoPacket(); + collectNeighborInfo(neighborInfo); + meshtastic_MeshPacket *p = allocDataProtobuf(*neighborInfo); + // send regardless of whether or not we have neighbors in our DB, + // because we want to get neighbors for the next cycle + p->to = dest; + p->decoded.want_response = wantReplies; + printNeighborInfo("SENDING", neighborInfo); + service.sendToMesh(p, RX_SRC_LOCAL, true); +} + +/* +Encompasses the full construction and sending packet to mesh +Will be used for broadcast. +*/ +int32_t NeighborInfoModule::runOnce() +{ + bool requestReplies = false; + sendNeighborInfo(NODENUM_BROADCAST, requestReplies); + return getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs); +} + +/* +Collect a recieved neighbor info packet from another node +Pass it to an upper client; do not persist this data on the mesh +*/ +bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np) +{ + printNeighborInfo("RECIEVED", np); + updateNeighbors(mp, np); + np->last_sent_by_id = nodeDB.getNodeNum(); + // Allow others to handle this packet + return false; +} + +void NeighborInfoModule::resetNeighbors() +{ + neighborState.neighbors_count = 0; + memset(neighborState.neighbors, 0, sizeof(neighborState.neighbors)); + saveProtoForModule(); +} + +void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np) +{ + // The last sent ID will be 0 if the packet is from the phone, which we don't count as + // an edge. So we assume that if it's zero, then this packet is from our node. + if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) { + getOrCreateNeighbor(np->last_sent_by_id, mp.rx_snr); + } +} + +meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum n, int snr) +{ + // our node and the phone are the same node (not neighbors) + if (n == 0) { + n = nodeDB.getNodeNum(); + } + // look for one in the existing list + for (int i = 0; i < (*numNeighbors); i++) { + meshtastic_Neighbor *nbr = &neighbors[i]; + if (nbr->node_id == n) { + // if found, update it + nbr->snr = snr; + return nbr; + } + } + // otherwise, allocate one and assign data to it + // TODO: max memory for the database should take neighbors into account, but currently doesn't + if (*numNeighbors < MAX_NUM_NODES) { + (*numNeighbors)++; + } + meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)]; + new_nbr->node_id = n; + new_nbr->snr = snr; + return new_nbr; +} + +void NeighborInfoModule::loadProtoForModule() +{ + if (!nodeDB.loadProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, sizeof(meshtastic_NeighborInfo), + &meshtastic_NeighborInfo_msg, &neighborState)) { + neighborState = meshtastic_NeighborInfo_init_zero; + } +} + +/** + * @brief Save the module config to file. + * + * @return true On success. + * @return false On error. + */ +bool NeighborInfoModule::saveProtoForModule() +{ + bool okay = true; + +#ifdef FS + FS.mkdir("/prefs"); +#endif + + okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState); + + return okay; +} diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h new file mode 100644 index 000000000..a6f61b025 --- /dev/null +++ b/src/modules/NeighborInfoModule.h @@ -0,0 +1,72 @@ +#pragma once +#include "ProtobufModule.h" + +/* + * Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh + */ +class NeighborInfoModule : public ProtobufModule, private concurrency::OSThread +{ + meshtastic_Neighbor *neighbors; + pb_size_t *numNeighbors; + + public: + /* + * Expose the constructor + */ + NeighborInfoModule(); + + /* Reset neighbor info after clearing nodeDB*/ + void resetNeighbors(); + + bool saveProtoForModule(); + + protected: + // Note: this holds our local info. + meshtastic_NeighborInfo neighborState; + + /* + * Called to handle a particular incoming message + * @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override; + + /* + * Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time + * @return the number of entries collected + */ + uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo); + + /* Allocate a new NeighborInfo packet */ + meshtastic_NeighborInfo *allocateNeighborInfoPacket(); + + /// Find a neighbor in our DB, create an empty neighbor if missing + meshtastic_Neighbor *getOrCreateNeighbor(NodeNum n, int snr); + + /* + * Send info on our node's neighbors into the mesh + */ + void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + size_t getNumNeighbors() { return *numNeighbors; } + + meshtastic_Neighbor *getNeighborByIndex(size_t x) + { + assert(x < *numNeighbors); + return &neighbors[x]; + } + + /* update neighbors with subpacket sniffed from network */ + void updateNeighbors(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np); + + void loadProtoForModule(); + + /* Does our periodic broadcast */ + int32_t runOnce() override; + + /* These are for debugging only */ + void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np); + void printNodeDBNodes(const char *header); + void printNodeDBNeighbors(const char *header); + void printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np); +}; +extern NeighborInfoModule *neighborInfoModule; \ No newline at end of file diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 532a2d125..5e6b4ac1d 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -544,6 +544,24 @@ std::string MQTT::downstreamPacketToJson(meshtastic_MeshPacket *mp) }; break; } + case meshtastic_PortNum_NEIGHBORINFO_APP: { + msgType = "neighborinfo"; + meshtastic_NeighborInfo scratch; + meshtastic_NeighborInfo *decoded = NULL; + if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, + &scratch)) { + decoded = &scratch; + msgPayload["node_id"] = new JSONValue((int)decoded->node_id); + msgPayload["neighbors_count"] = new JSONValue((int)decoded->neighbors_count); + msgPayload["neighbors"] = new JSONValue(decoded->neighbors); + } else { + LOG_ERROR("Error decoding protobuf for neighborinfo message!\n"); + } + }; + break; + } // add more packet types here if needed default: break; From d70bd232607971b9980073363df5204bc350ab4b Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 6 Jun 2023 21:06:19 +0200 Subject: [PATCH 2/6] Use float print specifier for SNR --- src/modules/NeighborInfoModule.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 9e6df3d34..d4b53fabc 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -37,7 +37,7 @@ void NeighborInfoModule::printNodeDBNodes(const char *header) LOG_DEBUG("DB contains %d nodes\n", num_nodes); for (int i = 0; i < num_nodes; i++) { meshtastic_NodeInfo *dbEntry = nodeDB.getNodeByIndex(i); - LOG_DEBUG(" Node %d: node_id=%d, snr=%d\n", i, dbEntry->num, dbEntry->snr); + LOG_DEBUG(" Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->num, dbEntry->snr); } LOG_DEBUG("----------------\n"); } @@ -54,7 +54,7 @@ void NeighborInfoModule::printNodeDBNeighbors(const char *header) LOG_DEBUG("DB contains %d neighbors\n", num_neighbors); for (int i = 0; i < num_neighbors; i++) { meshtastic_Neighbor *dbEntry = getNeighborByIndex(i); - LOG_DEBUG(" Node %d: node_id=%d, snr=%d\n", i, dbEntry->node_id, dbEntry->snr); + LOG_DEBUG(" Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr); } LOG_DEBUG("----------------\n"); } @@ -79,9 +79,9 @@ void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtast } } if (!chosen) { - LOG_DEBUG(" Node %d: neighbor=%d, snr=%d\n", i, dbEntry->node_id, dbEntry->snr); + LOG_DEBUG(" Node %d: neighbor=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr); } else { - LOG_DEBUG("---> Node %d: neighbor=%d, snr=%d\n", i, dbEntry->node_id, dbEntry->snr); + LOG_DEBUG("---> Node %d: neighbor=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr); } } LOG_DEBUG("----------------\n"); @@ -246,4 +246,4 @@ bool NeighborInfoModule::saveProtoForModule() okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState); return okay; -} +} \ No newline at end of file From cdf44ce7fa7c54c7a86abc919a5aafc7fe44c5f2 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 6 Jun 2023 21:07:12 +0200 Subject: [PATCH 3/6] Move module init out of repeater clause --- src/modules/Modules.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 192b98e65..41a9143ab 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -47,6 +47,7 @@ void setupModules() waypointModule = new WaypointModule(); textMessageModule = new TextMessageModule(); traceRouteModule = new TraceRouteModule(); + neighborInfoModule = new NeighborInfoModule(); // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // to a global variable. @@ -89,9 +90,8 @@ void setupModules() } else { adminModule = new AdminModule(); traceRouteModule = new TraceRouteModule(); - neighborInfoModule = new NeighborInfoModule(); } // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks routingModule = new RoutingModule(); -} +} \ No newline at end of file From 66c71250b85407e53148a3b0f1601fe163fd9d6f Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Thu, 8 Jun 2023 20:02:36 +0200 Subject: [PATCH 4/6] Update last_sent_by_id in FloodingRouter --- src/mesh/FloodingRouter.cpp | 11 +++++++---- src/mesh/FloodingRouter.h | 3 ++- src/modules/NeighborInfoModule.cpp | 20 +++++++++++++++++++- src/modules/NeighborInfoModule.h | 6 ++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 171199277..f412c0e1c 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -44,10 +44,13 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas tosend->hop_limit--; // bump down the hop count - // If it is a traceRoute request, update the route that it went via me - if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule && - traceRouteModule->wantPacket(p)) { - traceRouteModule->updateRoute(tosend); + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + // If it is a traceRoute request, update the route that it went via me + if (traceRouteModule && traceRouteModule->wantPacket(p)) + traceRouteModule->updateRoute(tosend); + // If it is a neighborInfo packet, update last_sent_by_id + if (neighborInfoModule && neighborInfoModule->wantPacket(p)) + neighborInfoModule->updateLastSentById(tosend); } LOG_INFO("Rebroadcasting received floodmsg to neighbors\n"); diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 73dbd1f3f..bf3e34c24 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -2,6 +2,7 @@ #include "PacketHistory.h" #include "Router.h" +#include "modules/NeighborInfoModule.h" #include "modules/TraceRouteModule.h" /** @@ -57,4 +58,4 @@ class FloodingRouter : public Router, protected PacketHistory * Look for broadcasts we need to rebroadcast */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; -}; +}; \ No newline at end of file diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index d4b53fabc..be1d70fd8 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -174,11 +174,29 @@ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, { printNeighborInfo("RECIEVED", np); updateNeighbors(mp, np); - np->last_sent_by_id = nodeDB.getNodeNum(); // Allow others to handle this packet return false; } +/* +Copy the content of a current NeighborInfo packet into a new one and update the last_sent_by_id to our NodeNum +*/ +void NeighborInfoModule::updateLastSentById(meshtastic_MeshPacket *p) +{ + auto &incoming = p->decoded; + meshtastic_NeighborInfo scratch; + meshtastic_NeighborInfo *updated = NULL; + memset(&scratch, 0, sizeof(scratch)); + pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, &meshtastic_NeighborInfo_msg, &scratch); + updated = &scratch; + + updated->last_sent_by_id = nodeDB.getNodeNum(); + + // Set updated last_sent_by_id to the payload of the to be flooded packet + p->decoded.payload.size = + pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_NeighborInfo_msg, updated); +} + void NeighborInfoModule::resetNeighbors() { neighborState.neighbors_count = 0; diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index a6f61b025..923ac1f7e 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -20,6 +20,9 @@ class NeighborInfoModule : public ProtobufModule, priva bool saveProtoForModule(); + // Let FloodingRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet + friend class FloodingRouter; + protected: // Note: this holds our local info. meshtastic_NeighborInfo neighborState; @@ -58,6 +61,9 @@ class NeighborInfoModule : public ProtobufModule, priva /* update neighbors with subpacket sniffed from network */ void updateNeighbors(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np); + /* update a NeighborInfo packet with our NodeNum as last_sent_by_id */ + void updateLastSentById(meshtastic_MeshPacket *p); + void loadProtoForModule(); /* Does our periodic broadcast */ From 6bdf67c9be90386967e424994bebf6aea2585bcd Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 25 Jun 2023 15:41:06 +0200 Subject: [PATCH 5/6] Conversion to NodeInfoLite --- src/modules/NeighborInfoModule.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index be1d70fd8..a485fe5f8 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -31,12 +31,12 @@ NOTE: for debugging only */ void NeighborInfoModule::printNodeDBNodes(const char *header) { - int num_nodes = nodeDB.getNumNodes(); + int num_nodes = nodeDB.getNumMeshNodes(); LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum()); LOG_DEBUG("----------------\n"); LOG_DEBUG("DB contains %d nodes\n", num_nodes); for (int i = 0; i < num_nodes; i++) { - meshtastic_NodeInfo *dbEntry = nodeDB.getNodeByIndex(i); + meshtastic_NodeInfoLite *dbEntry = nodeDB.getMeshNodeByIndex(i); LOG_DEBUG(" Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->num, dbEntry->snr); } LOG_DEBUG("----------------\n"); @@ -122,7 +122,6 @@ Assumes that the neighborInfo packet has been allocated uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo) { int num_neighbors = getNumNeighbors(); - int current_time = getTime(); int my_node_id = nodeDB.getNodeNum(); neighborInfo->node_id = my_node_id; neighborInfo->last_sent_by_id = my_node_id; From e60a5f1cf2033f33ffe94c1e12bcfa94af43340e Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 25 Jun 2023 15:41:19 +0200 Subject: [PATCH 6/6] Setter for NeighborInfo --- src/modules/AdminModule.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index ae254e7f7..de7870340 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -370,6 +370,11 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c) moduleConfig.has_remote_hardware = true; moduleConfig.remote_hardware = c.payload_variant.remote_hardware; break; + case meshtastic_ModuleConfig_neighbor_info_tag: + LOG_INFO("Setting module config: Neighbor Info\n"); + moduleConfig.has_neighbor_info = true; + moduleConfig.neighbor_info = c.payload_variant.neighbor_info; + break; } saveChanges(SEGMENT_MODULECONFIG); @@ -665,4 +670,4 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP { // restrict to the admin channel for rx boundChannel = Channels::adminChannel; -} +} \ No newline at end of file