I'm working on an ESP8266/ESP32 project using the Arduino_SNMP_Manager
library to retrieve SNMP data from a network device. My code works as expected, but I encounter a problem when I try to set the UDP object for the SNMP manager. Specifically, when I uncomment the line snmpRequest.setUDP(&udp);
in my code, the ESP8266/ESP32 reboots continuously.
Here’s the relevant portion of my code:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include "TouchScreen.h"
#include <Arduino_SNMP_Manager.h>
#include <WiFi.h>
#include <WiFiUdp.h>
// Include WiFi library for network communication
// NTP server and time zone
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 7; // Adjust for your time zone (e.g., -18000 for EST)
const int daylightOffset_sec = 3600;
int pollInterval = 10000;
IPAddress router(192, 168, 88, 1);
const char *community = "public";
const int snmpVersion = 1; // IP address of your MikroTik device
WiFiUDP udp; // UDP object used to send and receive packets
SNMPManager snmp = SNMPManager(community); // Starts an SNMPManager to listen to replies to get-requests
SNMPGet snmpRequest = SNMPGet(community, snmpVersion);
// Variables
uint32_t ifSpeedResponse = 0;
uint32_t downloadEtherr1 = 0;
int servicesResponse = 0;
char sysName[50];
char *sysNameResponse = sysName;
long long unsigned int hcCounter = 0;
uint32_t uptime = 0;
uint32_t lastUptime = 0;
unsigned long pollStart = 0;
unsigned long intervalBetweenPolls = 0;
float bandwidthInUtilPct = 0;
uint32_t lastInOctets = 0;
// SNMP OIDs for Ether1 traffic (replace with actual OIDs for your setup)
const char *oidIfSpeedGauge1 = ".1.3.6.1.2.1.2.2.1.5.1"; // Gauge Regular ethernet interface ifSpeed.4
const char *uploadether1 = ".1.3.6.1.2.1.2.2.1.10.1";
const char *downloadether1 = ".1.3.6.1.2.1.2.2.1.6.1";
const char *oidIfSpeedGauge2 = ".1.3.6.1.2.1.2.2.1.5.2";
const char *downloadether2 = ".1.3.6.1.2.1.2.2.1.6.2"; // Gauge Regular ethernet interface ifSpeed.4
const char *uploadether2 = ".1.3.6.1.2.1.2.2.1.10.2"; // Counter32 ifInOctets.4
const char *oidServiceCountInt = ".1.3.6.1.2.1.1.7.0"; // Integer sysServices
const char *oidSysName = ".1.3.6.1.2.1.1.5.0"; // OctetString SysName
const char *oid64Counter = ".1.3.6.1.2.1.31.1.1.1.6.4"; // Counter64 64-bit ifInOctets.4
const char *oidUptime = ".1.3.6.1.2.1.1.3.0";
// long ether1upload = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.10.1"); // Replace with the correct OID for Ether1
// long ether1Download = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.6.1");
ValueCallback *callbackIfSpeed;
ValueCallback *callbackInOctets;
ValueCallback *downloadEther1;
ValueCallback *callbackServices;
ValueCallback *callbackSysName;
ValueCallback *callback64Counter;
ValueCallback *callbackUptime;
// long ether2upload = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.10.2"); // Replace with the correct OID for Ether1
// long ether2Download = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.6.2");
const char* ssid = "BALINET";
const char* password = "";
#define YP 4 // must be an analog pin, use "An" notation!
#define XM 15 // must be an analog pin, use "An" notation!
#define YM 14 // can be a digital pin
#define XP 27 // can be a digital pin
#define MINPRESSURE 100
#define MAXPRESSURE 1000
#define TS_MINX 136
#define TS_MINY 85
#define TS_MAXX 905
#define TS_MAXY 905
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320
// Touchscreen coordinates: (x, y) and pressure (z)
uint16_t x, y, z;
#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char * buf) {
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
}
bool getTouch(uint16_t * x, uint16_t * y) {
TSPoint p = ts.getPoint();
pinMode(YP, OUTPUT);
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH);
digitalWrite(XM, HIGH);
bool pressed = (p.z > 10 && p.z < 1000);
if (pressed) {
*x = map(p.x, TS_MINX, TS_MAXX, 0, 320);
*y = map(p.y, TS_MINY, TS_MAXY, 0, 240);
}
return pressed;
}
// Get the Touchscreen data
void touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {
// Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)
uint16_t x, y;
bool touched = getTouch(&x, &y);
if (touched) {
data->point.x = x;
data->point.y = y;
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
// static lv_obj_t * time_label;
// // Function to update the time label
// static void update_time(lv_timer_t * timer) {
// time_t now;
// struct tm timeinfo;
// char time_str[16];
// time(&now); // Get the current time
// localtime_r(&now, &timeinfo); // Convert to local time
// // Format the time as HH:MM:SS
// strftime(time_str, sizeof(time_str), "%H:%M:%S", &timeinfo);
// // Set the time label text
// lv_label_set_text(time_label, time_str);
// }
static lv_obj_t * slider_label;
// Callback that prints the current slider value on the TFT display and Serial Monitor for debugging purposes
static void slider_event_callback(lv_event_t * e) {
lv_obj_t * slider = (lv_obj_t*) lv_event_get_target(e);
char buf[8];
lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));
lv_label_set_text(slider_label, buf);
lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
LV_LOG_USER("Slider changed to %d%%", (int)lv_slider_get_value(slider));
}
void doSNMPCalculations()
{
if (uptime == lastUptime) {
Serial.println("Data not updated between polls");
Serial.println(uptime);
Serial.println(lastUptime);
return;
} else if (uptime < lastUptime) {
Serial.println("Uptime < lastUptime. Device restarted?");
} else {
if (downloadEtherr1 > 0 && lastInOctets > 0) {
uint32_t octetsDiff;
if (downloadEtherr1 > lastInOctets) {
octetsDiff = downloadEtherr1 - lastInOctets;
} else {
// Handle counter wrap-around
octetsDiff = (4294967295 - lastInOctets) + downloadEtherr1;
}
// Convert octets (bytes) to bits
uint64_t bits = (uint64_t)octetsDiff * 8;
// Calculate time difference in seconds
uint32_t timeDiff = (uptime - lastUptime) / 100; // uptime is in hundredths of seconds
if (timeDiff > 0) {
float mbps = (float)bits / (timeDiff * 1000000.0);
Serial.printf("Bandwidth in Mbps: %.2f\n", mbps);
} else {
Serial.println("Time difference is too small or zero.");
}
}
}
// Update last samples
lastUptime = uptime;
lastInOctets = downloadEtherr1;
}
void lv_create_main_gui(void) {
// Create a text label aligned center on top ("Hello, world!")
/*Create a Tab view object*/
lv_obj_t * tabview;
tabview = lv_tabview_create(lv_screen_active());
lv_tabview_set_tab_bar_position(tabview, LV_DIR_LEFT);
lv_tabview_set_tab_bar_size(tabview, 50);
lv_obj_set_style_bg_color(tabview, lv_palette_lighten(LV_PALETTE_RED, 2), 0);
lv_obj_t * tab_buttons = lv_tabview_get_tab_bar(tabview);
lv_obj_set_style_bg_color(tab_buttons, lv_palette_darken(LV_PALETTE_GREY, 3), 0);
lv_obj_set_style_text_color(tab_buttons, lv_palette_lighten(LV_PALETTE_GREY, 5), 0);
lv_obj_set_style_border_side(tab_buttons, LV_BORDER_SIDE_RIGHT, LV_PART_ITEMS | LV_STATE_CHECKED);
/*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
lv_obj_t * tab1 = lv_tabview_add_tab(tabview, LV_SYMBOL_OK);
lv_obj_t * tab2 = lv_tabview_add_tab(tabview, LV_SYMBOL_HOME);
lv_obj_t * tab3 = lv_tabview_add_tab(tabview, LV_SYMBOL_WIFI);
lv_obj_t * tab4 = lv_tabview_add_tab(tabview, LV_SYMBOL_SETTINGS);
lv_obj_t * tab5 = lv_tabview_add_tab(tabview, LV_SYMBOL_CHARGE);
lv_obj_set_style_bg_color(tab2, lv_palette_lighten(LV_PALETTE_AMBER, 3), 0);
lv_obj_set_style_bg_opa(tab2, LV_OPA_COVER, 0);
/*Add content to the tabs*/
lv_obj_t * label = lv_label_create(tab1);
lv_label_set_text(label, "MIKROTIK");
/*Create a chart*/
lv_obj_t * chart1;
chart1 = lv_chart_create(tab1);
lv_obj_set_size(chart1, 200, 100);
lv_obj_align(chart1, LV_ALIGN_TOP_MID, 10, 30);
lv_chart_set_type(chart1, LV_CHART_TYPE_LINE); /*Show lines and points too*/
/*Add two data series*/
lv_chart_series_t * ser1 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t * ser2 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_SECONDARY_Y);
int32_t * ser2_y_points = lv_chart_get_y_array(chart1, ser2);
uint32_t i;
for(i = 0; i < 10; i++) {
/*Set the next points on 'ser1'*/
lv_chart_set_next_value(chart1, ser1, lv_rand(10, 50));
/*Directly set points on 'ser2'*/
ser2_y_points[i] = lv_rand(50, 90);
}
lv_chart_refresh(chart1); /*Required after direct set*/
// Add "Download:" and "Upload:" labels below each chart
lv_obj_t * download_label1 = lv_label_create(tab1);
lv_label_set_text(download_label1, "Download:");
lv_obj_align_to(download_label1, chart1, LV_ALIGN_BOTTOM_LEFT, 10, 30);
lv_obj_t * upload_label1 = lv_label_create(tab1);
lv_label_set_text(upload_label1, "Upload:");
lv_obj_align_to(upload_label1, download_label1, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
// Create the second chart
lv_obj_t * chart2;
chart2 = lv_chart_create(tab1);
lv_obj_set_size(chart2, 200, 100);
lv_obj_align_to(chart2, chart1, LV_ALIGN_OUT_BOTTOM_MID, 0, 30);
lv_chart_set_type(chart2, LV_CHART_TYPE_LINE); // Show lines and points too
// Add two data series for upload and download speeds
lv_chart_series_t * upload_ser = lv_chart_add_series(chart2, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t * download_ser = lv_chart_add_series(chart2, lv_palette_main(LV_PALETTE_ORANGE), LV_CHART_AXIS_PRIMARY_Y);
for (uint32_t i = 0; i < 10; i++) {
lv_chart_set_next_value(chart2, upload_ser, lv_rand(10, 100)); // Example upload values
lv_chart_set_next_value(chart2, download_ser, lv_rand(10, 100)); // Example download values
}
lv_chart_refresh(chart2); // Required after direct set
lv_obj_t * download_label2 = lv_label_create(tab1);
lv_label_set_text(download_label2, "Download:");
lv_obj_align_to(download_label2, chart2, LV_ALIGN_BOTTOM_LEFT, 10, 30);
lv_obj_t * upload_label2 = lv_label_create(tab1);
lv_label_set_text(upload_label2, "Upload:");
lv_obj_align_to(upload_label2, download_label2, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
/*Create an Arc*/
lv_obj_t * arc = lv_arc_create(tab1);
lv_obj_set_size(arc, 70, 70);
lv_arc_set_rotation(arc, 135);
lv_arc_set_bg_angles(arc, 0, 270);
lv_arc_set_value(arc, 10);
lv_obj_align(arc,LV_ALIGN_TOP_LEFT,10,30);
/*Manually update the label for the first time*/
lv_obj_send_event(arc, LV_EVENT_VALUE_CHANGED, NULL);
// Add CPU and Uptime labels in the top-right corner
lv_obj_t * cpu_label = lv_label_create(tab1);
lv_label_set_text(cpu_label, "CPU");
lv_obj_align_to(cpu_label, arc, LV_ALIGN_OUT_BOTTOM_MID, 0, -50);
lv_obj_t * cpu_label2 = lv_label_create(tab1);
lv_label_set_text(cpu_label2, "%");
lv_obj_align_to(cpu_label2, cpu_label, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
/*Create an Arc*/
lv_obj_t * arc2 = lv_arc_create(tab1);
lv_obj_set_size(arc2, 70, 70);
lv_arc_set_rotation(arc2, 135);
lv_arc_set_bg_angles(arc2, 0, 270);
lv_arc_set_value(arc2, 10);
lv_obj_align_to(arc2, arc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 30);
/*Manually update the label for the first time*/
lv_obj_send_event(arc2, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_t * uptime_label = lv_label_create(tab1);
lv_label_set_text(uptime_label, "Uptime: ");
lv_obj_align(uptime_label, LV_ALIGN_TOP_RIGHT, 0, 0);
// Create the time label and position it below the uptime label
lv_obj_t * labeltime = lv_label_create(tab1);
lv_label_set_text(labeltime, "TIME : ");
lv_obj_align(labeltime,LV_ALIGN_TOP_MID, 0,0);
// time_label = lv_label_create(tab1);
// lv_label_set_text(time_label, "00:00:00");
// lv_obj_align_to(time_label, labeltime, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
// TAB 2
label = lv_label_create(tab2);
lv_label_set_text(label, LV_SYMBOL_OK);
// TAB 3
label = lv_label_create(tab3);
lv_label_set_text(label, LV_SYMBOL_WIFI);
// TAB 4
label = lv_label_create(tab4);
lv_label_set_text(label, LV_SYMBOL_SETTINGS);
// TAB 5
label = lv_label_create(tab5);
lv_label_set_text(label, LV_SYMBOL_SETTINGS);
lv_obj_remove_flag(lv_tabview_get_content(tabview), LV_OBJ_FLAG_SCROLLABLE);
}
// callbackServices = snmp.addIntegerHandler(router, oidServiceCountInt, &servicesResponse);
void printUptime(uint32_t uptime) {
// Konversi uptime dari centi-seconds (hundredths of a second) ke detik
uint32_t seconds = uptime / 100;
uint32_t days = seconds / 86400; // 86400 detik dalam satu hari
seconds %= 86400;
uint32_t hours = seconds / 3600; // 3600 detik dalam satu jam
seconds %= 3600;
uint32_t minutes = seconds / 60; // 60 detik dalam satu menit
seconds %= 60;
Serial.printf("Uptime: %u days, %u hours, %u minutes, %u seconds\n", days, hours, minutes, seconds);
}
void setup() {
String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Initialize NTP
// configTime(25200, 0, "0.id.pool.ntp.org");
// Start LVGL
lv_init();
// Register print function for debugging
lv_log_register_print_cb(log_print);
// start snmp
snmp.setUDP(&udp); // give snmp a pointer to the UDP object
snmp.begin();
// Get callbacks from creating a handler for each of the OID
callbackIfSpeed = snmp.addGaugeHandler(router, oidIfSpeedGauge1, &ifSpeedResponse);
downloadEther1= snmp.addCounter32Handler(router, downloadether1, &downloadEtherr1);
// callbackServices = snmp.addIntegerHandler(router, oidServiceCountInt, &servicesResponse);
callbackSysName = snmp.addStringHandler(router, oidSysName, &sysNameResponse);
// callback64Counter = snmp.addCounter64Handler(router, oid64Counter, &hcCounter);
callbackUptime = snmp.addTimestampHandler(router, oidUptime, &uptime);
// Create a display object
lv_display_t * disp;
// Initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
// Initialize an LVGL input device object (Touchscreen)
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
// Set the callback function to read Touchscreen input
lv_indev_set_read_cb(indev, touchscreen_read);
// Initialize NTP
// Existing LVGL setup code...
lv_create_main_gui();
// Add the timer to update the time label every second
// lv_timer_create(update_time, 1000, NULL);
}
void loop() {
snmp.loop();
intervalBetweenPolls = millis() - pollStart;
if (intervalBetweenPolls >= pollInterval)
{ getSNMP();
doSNMPCalculations();
}
lv_task_handler(); // let the GUI do its work
lv_tick_inc(5); // tell LVGL how much time has passed
delay(5); // let this time pass
}
void getSNMP()
{
// Build a SNMP get-request add each OID to the request
snmpRequest.addOIDPointer(callbackIfSpeed);
snmpRequest.addOIDPointer(callbackInOctets);
snmpRequest.addOIDPointer(callbackServices);
snmpRequest.addOIDPointer(callbackSysName);
snmpRequest.addOIDPointer(callback64Counter);
snmpRequest.addOIDPointer(callbackUptime);
snmpRequest.setIP(WiFi.localIP());
snmpRequest.setPort(161); // Default is UDP port 161 for SNMP. But can be overriden if necessary.
snmpRequest.setUDP(&udp);
snmpRequest.setRequestID(rand() % 5555);
snmpRequest.sendTo(router);
snmpRequest.clearOIDList();
}
I've ensured that the UDP object is correctly initialized, and the rest of my code works without any issues when I comment out the setUDP()
line. However, setting the UDP object seems to cause a continuous reboot loop.
- Device: ESP32
- Library: Arduino_SNMP_Manager, LVGL
- Symptoms: Continuous reboot when setting the UDP object for SNMP
Has anyone else experienced this issue? What could be causing the reboots, and how can I resolve it?
Any insights or suggestions would be greatly appreciated!