Files
MeshCore/src/helpers/SNMPAgent.cpp
T
agessaman a129420804 fix(network): pre-merge review fixes
- Guard the boot-time link bootstrap to observer ESP32 builds. It ran
  unconditionally in MyMesh::begin(), breaking every non-observer
  repeater/room server build (ESP32 and nRF52).
- Rename NetworkInterface -> NetworkLink (class, accessor, files).
  Arduino-ESP32 3.x ships its own NetworkInterface class and header,
  which broke the ESP32-C6 builds. Drop WiFi.setAutoConnect(), a no-op
  on 2.x and removed in 3.x.
- Refresh stored Wi-Fi credentials every bridge tick so the STA
  reconnect loop picks up `set wifi.ssid` / `set wifi.pwd` without a
  reboot, as the bridge did before the link moved out of it. Skip
  reconnects while the SSID is empty.
- Restore the "WiFi connected: <ip>" / "WiFi disconnected: reason N"
  debug lines the bridge used to print.
- Alert on Ethernet only once it has held a lease this boot or when no
  Wi-Fi is configured; Wi-Fi-only installs of an Ethernet-preferred
  image keep Wi-Fi alerts instead of reporting "Ethernet down".
- Record wifi.setup_complete only for Ethernet LAN onboarding, so
  Wi-Fi builds keep the SSID-based first-boot portal rule.
- Use seq_cst for the route-switch lock/mutation flag handshake.
- Docs: SNMP RSSI sentinel is -127; describe link-return vs medium-switch
  reconnect behavior accurately; note runtime credential pickup.
- Test: unknown keys inside a known /mqtt.json group are ignored, which
  keeps wifi.setup_complete downgrade-safe.
2026-09-19 10:14:16 -07:00

124 lines
4.3 KiB
C++

#ifdef WITH_SNMP
#include "SNMPAgent.h"
#include <esp_heap_caps.h>
#define SNMP_PORT 161
MeshSNMPAgent::MeshSNMPAgent()
: _snmp("public"),
_running(false),
_uptime_secs(0),
_packets_recv(0), _packets_sent(0), _recv_errors(0),
_noise_floor(0), _last_rssi(0), _last_snr(0),
_sent_flood(0), _sent_direct(0), _recv_flood(0), _recv_direct(0),
_total_air_time_secs(0),
_mqtt_connected_slots(0), _mqtt_queue_depth(0), _mqtt_skipped_publishes(0),
_free_heap(0), _max_alloc(0), _internal_free(0), _psram_free(0),
_wifi_rssi(0)
{
_firmware_version[0] = '\0';
_node_name[0] = '\0';
}
void MeshSNMPAgent::begin(const char* community) {
if (_running) return;
_snmp = SNMPAgent(community);
_snmp.setUDP(&_udp);
_snmp.begin();
// System group (.1.x.0)
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".1.1.0", &_uptime_secs);
_snmp.addReadOnlyStaticStringHandler(MESHCORE_OID_BASE ".1.2.0", _firmware_version, sizeof(_firmware_version));
_snmp.addReadOnlyStaticStringHandler(MESHCORE_OID_BASE ".1.3.0", _node_name, sizeof(_node_name));
// Radio group (.2.x.0)
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.1.0", &_packets_recv);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.2.0", &_packets_sent);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.3.0", &_recv_errors);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.4.0", &_noise_floor);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.5.0", &_last_rssi);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.6.0", &_last_snr);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.7.0", &_sent_flood);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.8.0", &_sent_direct);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.9.0", &_recv_flood);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.10.0", &_recv_direct);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".2.11.0", &_total_air_time_secs);
// MQTT group (.3.x.0)
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".3.1.0", &_mqtt_connected_slots);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".3.2.0", &_mqtt_queue_depth);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".3.3.0", &_mqtt_skipped_publishes);
// Memory group (.4.x.0)
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".4.1.0", &_free_heap);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".4.2.0", &_max_alloc);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".4.3.0", &_internal_free);
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".4.4.0", &_psram_free);
// Network group (.5.x.0)
_snmp.addIntegerHandler(MESHCORE_OID_BASE ".5.1.0", &_wifi_rssi);
_snmp.sortHandlers();
_running = true;
}
void MeshSNMPAgent::loop() {
if (!_running) return;
// Update memory and network stats locally (we're on Core 0 with WiFi)
_free_heap = (int)ESP.getFreeHeap();
_max_alloc = (int)ESP.getMaxAllocHeap();
_internal_free = (int)heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
#ifdef BOARD_HAS_PSRAM
_psram_free = (int)heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
#else
_psram_free = 0;
#endif
if (WiFi.isConnected()) {
_wifi_rssi = (int)WiFi.RSSI();
}
_snmp.loop();
}
void MeshSNMPAgent::updateRadioStats(
uint32_t packets_recv, uint32_t packets_sent, uint32_t recv_errors,
int16_t noise_floor, int16_t last_rssi, int16_t last_snr,
uint32_t sent_flood, uint32_t sent_direct,
uint32_t recv_flood, uint32_t recv_direct,
uint32_t total_air_time_secs, uint32_t uptime_secs) {
_packets_recv = (int)packets_recv;
_packets_sent = (int)packets_sent;
_recv_errors = (int)recv_errors;
_noise_floor = (int)noise_floor;
_last_rssi = (int)last_rssi;
_last_snr = (int)last_snr;
_sent_flood = (int)sent_flood;
_sent_direct = (int)sent_direct;
_recv_flood = (int)recv_flood;
_recv_direct = (int)recv_direct;
_total_air_time_secs = (int)total_air_time_secs;
_uptime_secs = (int)uptime_secs;
}
void MeshSNMPAgent::updateMQTTStats(int connected_slots, int queue_depth, int skipped_publishes) {
_mqtt_connected_slots = connected_slots;
_mqtt_queue_depth = queue_depth;
_mqtt_skipped_publishes = skipped_publishes;
}
void MeshSNMPAgent::setNodeName(const char* name) {
strncpy(_node_name, name, sizeof(_node_name) - 1);
_node_name[sizeof(_node_name) - 1] = '\0';
}
void MeshSNMPAgent::setFirmwareVersion(const char* version) {
strncpy(_firmware_version, version, sizeof(_firmware_version) - 1);
_firmware_version[sizeof(_firmware_version) - 1] = '\0';
}
#endif // WITH_SNMP