Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 208 additions & 131 deletions README.md

Large diffs are not rendered by default.

42 changes: 29 additions & 13 deletions examples/ESP32_SNMP/ESP32_SNMP.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@
#endif

/* -------------------------------------------------------------------------- *
* COMPILE-TIME TUNING (optional, BEFORE #include <SNMP_Agent.h>)
* MEMORY MODEL (SNMP_Agent v3.2.0+ — nothing to configure for this sketch)
*
* All SNMP size constants in src/include/defs.h are wrapped with
* `#ifndef ... #endif` so a sketch-side #define placed here wins over the
* library defaults. Good targets for ESP-01 1 MB / 80 KB RAM sensors:
* The library derives its ASN pool size at compile time from the number of
* handlers you register (SNMP_MAX_CALLBACKS_PER_AGENT) plus the worst-case
* transient demand of the configured caps, and locks the arena in as one
* contiguous block in the SNMPAgent constructor — before setup() and WiFi —
* so packet handling performs zero per-packet heap traffic.
*
* #define SNMP_MAX_COMPLEX_CHILDREN 8
* #define SNMP_MAX_VARBINDS 4
* #define SNMP_MAX_CALLBACKS_PER_AGENT 16
* #define SNMP_MAX_TRAPS_INFLIGHT 4
* #define SNMP_POOL_ASN_OBJECTS 32
* #define SNMP_POOL_VARBIND_OBJECTS 12
*
* Saves ~25 KB BSS (ASNPool halves: (64 - 32) * 768 B = 24,576 B) and a
* few KB more from smaller fixed callback/varbind arrays.
* !! SIZE OVERRIDES AND THE ONE-DEFINITION RULE !!
* Never #define size knobs (SNMP_MAX_CALLBACKS_PER_AGENT, SNMP_POOL_*,
* OCTET_TYPE_MAX_LENGTH, ...) inside a sketch file: they change CLASS
* LAYOUT, so a sketch-only #define makes the sketch and the compiled
* library disagree about object sizes -> undefined behaviour (on ESP8266:
* instant reboot loops). Set them as GLOBAL build flags so every
* translation unit agrees:
* arduino-cli: --build-flags "-DSNMP_MAX_CALLBACKS_PER_AGENT=64"
* platformio : build_flags = -DSNMP_MAX_CALLBACKS_PER_AGENT=64
* -------------------------------------------------------------------------- */

#include <WiFiUdp.h>
Expand Down Expand Up @@ -49,13 +51,22 @@ TimestampCallback* timestampCallbackOID;

char staticString[] = "This value will never change";

/* Versioned sysDescr served on .1.3.6.1.2.1.1.1.0 — the handler keeps the pointer,
so this must be a static buffer, not a local. Lets `snmpget` confirm the exact
library build running on the chip during hardware testing. */
static char sysDescrBuf[64];

// Setup an SNMPTrap for later use
SNMPTrap* settableNumberTrap = new SNMPTrap("public", SNMP_VERSION_2C);
char _changingStringBuf[25];
char* changingString = _changingStringBuf;

void setup(){
Serial.begin(115200);

// Hardware-test banner: confirm the flashed library version in the serial monitor
Serial.printf("SNMP_Agent v%s\n", snmp.getVersion());

WiFi.begin(ssid, password);
// WiFi.begin(ssid);
Serial.println("");
Expand All @@ -81,6 +92,11 @@ void setup(){
stuff[2] = 24;
stuff[3] = 67;

// RFC1213 sysDescr: serves the library version, queryable from the SNMP terminal:
// snmpget -v 2c -c public <IP> .1.3.6.1.2.1.1.1.0
snprintf(sysDescrBuf, sizeof(sysDescrBuf), "ESP32_SNMP demo (SNMP_Agent v%s)", snmp.getVersion());
snmp.addReadOnlyStaticStringHandler(".1.3.6.1.2.1.1.1.0", sysDescrBuf);

// add 'callback' for an OID - pointer to an integer
changingNumberOID = snmp.addIntegerHandler(".1.3.6.1.4.1.5.0", &changingNumber);

Expand Down
87 changes: 45 additions & 42 deletions examples/SNMP_Sensor/SNMP_Sensor.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,33 @@
#endif

/* -------------------------------------------------------------------------- *
* COMPILE-TIME TUNING (optional, BEFORE #include <SNMP_Agent.h>)
* MEMORY MODEL (SNMP_Agent v3.2.0+ — nothing to configure for this sketch)
*
* SNMP v3.1.3+ auto-tunes itself for ESP8266: on ESP8266 the library
* activates a "_SNMP_ESP8266_TINY" profile that shrinks all static pool
* sizes so that WiFi + LittleFS + ArduinoJson + SNMP fit into 80 KB DRAM
* with headroom (~ -28 KB BSS vs the generic defaults). This sketch
* registers 34 OID callbacks, well within the ESP8266 profile budget of
* 24 callbacks + 24 ASN pool slots + 8 VarBind slots.
*
* All SNMP size constants live in src/include/defs.h and are wrapped with
* `#ifndef ... #endif`. To OVERRIDE library or auto-tune values from
* your sketch, put a #define HERE (before SNMP_Agent.h). Examples:
*
* // Reclaim capacity on bigger ESP8266 modules or ESP32 sketches:
* #define SNMP_MAX_CALLBACKS_PER_AGENT 64
* #define SNMP_POOL_ASN_OBJECTS 32
* #define SNMP_MAX_VARBINDS 16
* #define SNMP_MAX_COMPLEX_CHILDREN 16
*
* // Opt OUT of ESP8266 auto-tune entirely (use generic defaults):
* #define SNMP_SKIP_ESP8266_AUTOTUNE 1
*
* // Drop max OctetString/Opaque payload size further for tiny sensors:
* #define OCTET_TYPE_MAX_LENGTH 128
*
* Snapshot of the on-by-default ESP8266 auto-tune profile applied by
* SNMP_Agent v3.1.3+ (NOT a sketch-side define, just shown for reference):
* MAX_SNMP_PACKET_LENGTH 1024
* OCTET_TYPE_MAX_LENGTH 256
* SNMP_MAX_OID_STR_LEN 192
* SNMP_MAX_COMPLEX_CHILDREN 8
* The library auto-tunes itself for ESP8266 ("_SNMP_ESP8266_TINY" profile)
* and DERIVES its ASN pool size at compile time from the number of handlers
* you register (SNMP_MAX_CALLBACKS_PER_AGENT) plus the worst-case transient
* demand of the configured caps. The arena is locked in as one contiguous
* block in the SNMPAgent constructor — before setup() and WiFi — so packet
* handling performs zero per-packet heap traffic and cannot fragment the
* heap. On ESP8266 the derived TINY defaults for this sketch's profile are:
* SNMP_MAX_VARBINDS 6
* SNMP_MAX_CALLBACKS_PER_AGENT 24
* SNMP_MAX_TRAPS_INFLIGHT 4
* SNMP_MAX_CALLBACKS_PER_TRAP 8
* SNMP_POOL_ASN_OBJECTS 24
* SNMP_POOL_VARBIND_OBJECTS 8
* SNMP_POOL_SLOT_SIZE 640
* SNMP_POOL_ASN_OBJECTS (derived) 84 x 288 B, locked at boot
*
* !! SIZE OVERRIDES AND THE ONE-DEFINITION RULE !!
* Never #define size knobs (SNMP_MAX_CALLBACKS_PER_AGENT, SNMP_POOL_*,
* OCTET_TYPE_MAX_LENGTH, ...) inside a sketch file: they change CLASS
* LAYOUT, so a sketch-only #define makes the sketch and the compiled
* library disagree about object sizes -> undefined behaviour (on ESP8266:
* instant reboot loops). Set them as GLOBAL build flags so every
* translation unit agrees:
* arduino-cli: --build-flags "-DSNMP_MAX_CALLBACKS_PER_AGENT=64"
* platformio : build_flags = -DSNMP_MAX_CALLBACKS_PER_AGENT=64
*
* Handler budget: the ESP8266 TINY profile caps registrations at 24.
* This sketch registers 33 OIDs across three MIB groups, so the 18-OID
* ENTITY-MIB physical row is compiled in only on non-TINY targets (the
* RFC1213 system group and the ENTITY-SENSOR-MIB values remain on all).
* -------------------------------------------------------------------------- */

#include <WiFiUdp.h>
Expand Down Expand Up @@ -85,7 +74,10 @@ const char* oidSysName = ".1.3.6.1.2.1.1.5.0"; // OctetString SysName
const char* oidSysLocation = ".1.3.6.1.2.1.1.6.0"; // OctetString SysLocation
const char* oidSysServices = ".1.3.6.1.2.1.1.7.0"; // Integer sysServices

char sysDescr[] = "SNMP Agent";
/* Versioned sysDescr served on .1.3.6.1.2.1.1.1.0 — filled in setup() with the
running library version so `snmpget` confirms the exact build during hardware
testing. 64 B leaves room for the version string; handler keeps the pointer. */
static char sysDescr[64] = "SNMP Agent";
char sysObjectID[] = "";
uint32_t sysUptime = 0;
char sysContactValue[255];
Expand Down Expand Up @@ -131,7 +123,7 @@ char entPhysicalFirmwareRev_1[] = "";
char entPhysicalSoftwareRev_1[] = "";
char entPhysicalSerialNum_1[] = "";
char entPhysicalMfgName_1[] = "";
char entPhysicalModelName_11[] = "";
char entPhysicalModelName_1[] = "";
char entPhysicalAlias_1[] = "";
char entPhysicalAssetID_1[] = "";
int entPhysicalIsFRU_1 = 0;
Expand Down Expand Up @@ -194,6 +186,10 @@ void printFile(const char* filename);
void setup()
{
Serial.begin(115200);

// Hardware-test banner: confirm the flashed library version in the serial monitor
Serial.printf("SNMP_Agent v%s\n", snmp.getVersion());

if (!FS_BEGIN())
{
Serial.println("LittleFS Mount Failed");
Expand All @@ -217,9 +213,16 @@ void setup()
snmp.setUDP(&udp);
snmp.begin();

addRFC1213MIBHandler(); // RFC1213-MIB (System)
addENTITYMIBHandler(); // ENTITY-MIB
addENTITYSENSORMIBHandler(); // ENTITY-SENSOR-MIB
// Fill sysDescr (.1.3.6.1.2.1.1.1.0) with the version string, queryable from the
// SNMP terminal: snmpget -v 2c -c public <IP> .1.3.6.1.2.1.1.1.0
snprintf(sysDescr, sizeof(sysDescr), "SNMP_Sensor demo (SNMP_Agent v%s)", snmp.getVersion());

addRFC1213MIBHandler(); // RFC1213-MIB (System) — 7 OIDs
#ifndef _SNMP_ESP8266_TINY
addENTITYMIBHandler(); // ENTITY-MIB — 18 OIDs; needs the 64-handler
// default profile (ESP8266 TINY caps at 24)
#endif
addENTITYSENSORMIBHandler(); // ENTITY-SENSOR-MIB — 8 OIDs

// Read previously stored values, if any.
if (loadSNMPValues())
Expand All @@ -228,7 +231,7 @@ void setup()
printFile(savedValuesFile);
}

// Ensure to sortHandlers after adding/removing and OID callbacks - this makes snmpwalk work
// Ensure to sortHandlers after adding/removing OID callbacks - this makes snmpwalk work
snmp.sortHandlers();
}

Expand Down Expand Up @@ -397,7 +400,7 @@ void addENTITYMIBHandler()
snmp.addReadOnlyStaticStringHandler(oidentPhysicalSoftwareRev_1, entPhysicalSoftwareRev_1);
snmp.addReadOnlyStaticStringHandler(oidentPhysicalSerialNum_1, entPhysicalSerialNum_1);
snmp.addReadOnlyStaticStringHandler(oidentPhysicalMfgName_1, entPhysicalMfgName_1);
snmp.addReadOnlyStaticStringHandler(oidentPhysicalModelName_1, entPhysicalModelName_11);
snmp.addReadOnlyStaticStringHandler(oidentPhysicalModelName_1, entPhysicalModelName_1);
snmp.addReadOnlyStaticStringHandler(oidentPhysicalAlias_1, entPhysicalAlias_1);
snmp.addReadOnlyStaticStringHandler(oidentPhysicalAssetID_1, entPhysicalAssetID_1);
snmp.addIntegerHandler(oidentPhysicalIsFRU_1, &entPhysicalIsFRU_1);
Expand Down
74 changes: 48 additions & 26 deletions extras/demos/arduino_cli_esp32/arduino_cli_esp32.ino
Original file line number Diff line number Diff line change
@@ -1,30 +1,47 @@
/*
* SNMP_Agent minimal demo — ESP32 (esp32:esp32:esp32)
* SNMP_Agent minimal demo — ESP32
* Target: arduino-cli compile --fqbn esp32:esp32:esp32
* Purpose: DoD H — confirm Arduino-CLI ESP32 build is zero-error,
* zero-warning against the current SNMP_Agent HEAD checkout.
*
* Wiring: Serial 115200 baud (native USB on ESP32 DevKitC).
* Purpose: Zero-config starting point: fill in WiFi credentials, flash,
* and poll the OIDs below with net-snmp from any machine.
*
* Before run:
* 1. Fill in WIFI_SSID / WIFI_PASSWORD below.
* 2. Install esp32:esp32 core via Arduino CLI board manager.
* 3. Symlink / copy this repo into your <sketchbook>/libraries/SNMP_Agent
* (Arduino-CLI scans for libraries here at compile time).
* e.g. ln -s <repo> ~/Arduino/libraries/SNMP_Agent
* 2. Install the esp32 core via the Arduino CLI board manager.
* 3. Install this library into <sketchbook>/libraries/SNMP_Agent
* (Arduino-CLI scans for libraries there at compile time).
*
* Test from another machine once the IP prints to serial:
* snmpget -v 2c -c public <ip> .1.3.6.1.4.1.5.0
* snmpset -v 2c -c private <ip> .1.3.6.1.4.1.5.0 i 99
* snmpbulkwalk -v 2c -c public <ip> .1.3.6.1.4.1.5
*/

#include <WiFi.h>
#include <WiFiUdp.h>
#include <SNMP_Agent.h>

#define WIFI_SSID "your-ssid-here"
#define WIFI_PASSWORD "your-pass-here"

static SNMPAgent agent;
/* NOTE (v3.2.0+): never #define library size knobs (SNMP_MAX_CALLBACKS_PER_AGENT,
* SNMP_POOL_*, OCTET_TYPE_MAX_LENGTH, ...) inside a sketch file. They change
* CLASS LAYOUT, so a sketch-only #define makes the sketch and the compiled
* library disagree about object sizes -> undefined behaviour. Set them as
* GLOBAL build flags, e.g.
* arduino-cli ... --build-flags "-DSNMP_MAX_CALLBACKS_PER_AGENT=16"
* This demo needs no overrides: the library auto-sizes its pools from the
* number of handlers you register, locks the arena in at boot, and serves
* requests with zero per-packet heap traffic. */

// The UDP socket the agent listens on. The agent calls udp.begin(161) itself
// inside begin() — you only need to hand it over with setUDP().
static WiFiUDP udp;

static SNMPAgent agent = SNMPAgent("public", "private");

static int myInteger = 42;
static char sensorName[] = "ESP32-Sensor";
static uint32_t counter32 = 0;
static int myInteger = 42; // SETtable via snmpset
static char sensorName[] = "ESP32-Sensor";
static uint32_t counter32 = 0;

static uint32_t getUptimeSeconds(void) { return (uint32_t)(millis() / 1000U); }

Expand All @@ -33,7 +50,7 @@ void setup()
Serial.begin(115200);
delay(500);
Serial.println();
Serial.println("SNMP_Agent v3.x minimal demo (ESP32)");
Serial.printf("SNMP_Agent v%s minimal demo (ESP32)\n", agent.getVersion());

WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Expand All @@ -42,29 +59,34 @@ void setup()
Serial.print('.');
}
Serial.println();
Serial.print("IP: "); Serial.println(WiFi.localIP());
Serial.print(F("IP: ")); Serial.println(WiFi.localIP());

agent.begin(); // Default community: "public", OID prefix: ".1.3.6.1.2.1.1"
// REQUIRED wiring: UDP socket first, then bind + start listening.
agent.setUDP(&udp);
agent.begin();

/* Three representative handlers to stress-test different ValueCallback
* code paths (integer / static string / dynamic-timestamp). */
agent.addIntegerHandler(".8.0", &myInteger, true);
agent.addReadOnlyStaticStringHandler(".5.0", sensorName);
agent.addDynamicReadOnlyTimestampHandler(".3.0", getUptimeSeconds);
// Three representative handlers (integer / static string / dynamic timestamp).
agent.addIntegerHandler(".1.3.6.1.4.1.5.0", &myInteger, true);
agent.addReadOnlyStaticStringHandler(".1.3.6.1.4.1.5.1", sensorName);
agent.addDynamicReadOnlyTimestampHandler(".1.3.6.1.4.1.5.2", getUptimeSeconds);
agent.addCounter32Handler(".1.3.6.1.4.1.5.3", &counter32);

agent.addCounter32Handler(".6.1.2.1.0", &counter32);
// Keep walk order correct after registering handlers.
agent.sortHandlers();

Serial.println("SNMP agent started. try: snmpget -v 2c -c public <ip> .1.3.6.1.2.1.1.8.0");
Serial.println(F("SNMP agent started. try:"));
Serial.println(F(" snmpget -v 2c -c public <ip> .1.3.6.1.4.1.5.0"));
Serial.println(F(" snmpset -v 2c -c private <ip> .1.3.6.1.4.1.5.0 i 99"));
Serial.println(F(" snmpbulkwalk -v 2c -c public <ip> .1.3.6.1.4.1.5"));
}

void loop()
{
agent.loop();
agent.loop(); // must be called as often as possible

static unsigned long lastTick = 0;
if (millis() - lastTick > 1000UL) {
lastTick = millis();
counter32++; /* Exercise the counter32 handler on each tick so
subsequent SNMP walks see changing data. */
counter32++; // demo counter: +1 per second
}
}
Loading
Loading