Agentuino - A lightweight SNMP Agent

I really appreciate your help Chris :slight_smile:

latest update..Y axis limits are realistic now! (0 to 100)

I think the problem is shown on the first screenshot. You only have GPRINT items in your graph template. These are text prints. You need to add an AREA item (filled graph). See the 2nd and 3rd (from bottom) of my screenshots...

Sweet!!!! thnk u :slight_smile: (dnt know how I missed that)
Have good day!!

Cheers

I take it that means it's working? :wink: Or have you not tried yet?

Update.. There is grab in data cause I disconnected the sensor.
I was looking at your watchdog circuit very useful.. :)I am facing the same prob..SNMP gets stuck with unknow packet. That's my next step...

oh yes itz working ..Yaaayeee and big HI5 to u :slight_smile:

Great. It's working .. :wink:

I just realised that we were discussing this in the Agentuino thread. I hope LAVco doesn't mind... :wink:

Yahh oppss!! but I am sure people will find it useful at some stage.

Hi everyone, I'm an SNMP newbie.
However, I've added basic trap support.
If you're interested, I've attached the patches to this post.
Here is how you'd use it:
Sending the trap:

void send()
{
    SNMP_PDU pdu;
    char agent[] = {192, 168, 0, 177};
    const uint8_t manager[] = {192, 168, 0, 3};
    pdu.OID.size = 2;
    pdu.OID.data[0] = 7;
    pdu.OID.data[1] = 7;
    pdu.address = agent;
    pdu.trap_type = SNMP_TRAP_ENTERPRISE_SPECIFIC;
    pdu.specific_trap = 1;
    pdu.time_ticks = 0;
    /* the size of the data you will add at the end of the packet */
    pdu.trap_data_size = 10;
    /* the function that adds this data */
    pdu.trap_data_adder = add_trap_data;
    Agentuino.sendTrap(&pdu, manager);
}

The trap_data_adder function:

void add_trap_data(byte* p)
{
    byte i;
    SNMP_OID var_name;
    var_name.data[0] = 42;
    var_name.data[1] = 2;
    var_name.data[2] = 3;
    var_name.data[3] = 4;
    var_name.size = 4;
    *(p++) = SNMP_SYNTAX_OID;
    *(p++) = var_name.size;
    for(i = 0; i < var_name.size; i++) *(p++) = var_name.data[i];
    *(p++) = SNMP_SYNTAX_INT;
    *(p++) = 2;
    *(p++) = 0x42;
    *(p++) = 0;
}

Agentuino.h.diff (710 Bytes)

Agentuino.cpp.diff (4.14 KB)

Hello,

I'm new with SNMP but for a project i need it :slight_smile:

Can anyone help me to get a value from a agent and display it in my serial monitor ?

example
"I need the up time from a NAS server, so i can display it into a LCD on my Arduino".

Thank you

yazgoo:
Hi everyone, I'm an SNMP newbie.
However, I've added basic trap support.
If you're interested, I've attached the patches to this post.

Has anyone been able to successfully merge these changes into the library? 8/12 of the hunks failed when i tried to apply the files as a patch and I can't figure out where the failed pieces are supposed to go.

Hi, this is my first Arduino project after testing some example sketches and making an LCD display menu. I would like to read a few predefined MIB’s from a modem with SNMP get-commands. First I want to display a MIB in my serial monitor and finally I’d like to display them on my LCD. The modem I am using for this test is configured for use with SNMP V2c. The modem is not in a “live” environment. When I use a MIB browser I can see one of predefined MIB’s at this location: 1.3.6.1.2.1.10.127.1.1.1.1.6.3. The MIB contains a value around -490.

When I check my serial monitor using the code below the only thing I see is “SNMP Agent Initalized…” Can someone tell me how I can display a MIB there?

I used the sketch from the “Agentuino SNMP Astronomy Weather Station” and I adapted it for my own needs. I compared it with the Agentuino example sketch and the only difference I see was an “F” every time this function is used: Serial << F("SNMP Agent Initalized...") << endl;
Can someone tell what the “F” is needed for?

/*
* Adaptation of
* Agentuino SNMP Astronomy Weather Station
* http://openhardware.gridshield.net/home/arduino-snmp-temperature-sensor
* example from "yesyesserver.co.uk/temp/wheater_station"
*/

#include <Streaming.h>         // Include the Streaming library
#include <Ethernet.h>          // Include the Ethernet library
#include <SPI.h>
#include <MemoryFree.h>
#include <Agentuino.h>
#include <Flash.h>

#define DEBUG 

// SNMP stuff
byte count=0; // count number of processed SNMP requests 

// parameters for the Ethernet library
static byte mac[] = { 0x90, 0xA3, 0xDA, 0x0E, 0xAD, 0x3f };
static byte ip[] = { 192, 168, 1, 200 };
static byte gateway[] = { 192, 168, 1, 1 };
static byte subnet[] = { 255, 255, 255, 0 };

// must-have RFC1213-MIB OIDs (taken from agentuino sample sketch)
// .iso.org.dod.internet.mgmt.mib-2.system.sysDescr (.1.3.6.1.2.1.1.1)
static char sysDescr[] PROGMEM      = "1.3.6.1.2.1.1.1.0";  // read-only  (DisplayString)
// .iso.org.dod.internet.mgmt.mib-2.system.sysObjectID (.1.3.6.1.2.1.1.2)
static char sysObjectID[] PROGMEM   = "1.3.6.1.2.1.1.2.0";  // read-only  (ObjectIdentifier)
// .iso.org.dod.internet.mgmt.mib-2.system.sysUpTime (.1.3.6.1.2.1.1.3)
static char sysUpTime[] PROGMEM     = "1.3.6.1.2.1.1.3.0";  // read-only  (TimeTicks)
// .iso.org.dod.internet.mgmt.mib-2.system.sysContact (.1.3.6.1.2.1.1.4)
static char sysContact[] PROGMEM    = "1.3.6.1.2.1.1.4.0";  // read-write (DisplayString)
// .iso.org.dod.internet.mgmt.mib-2.system.sysName (.1.3.6.1.2.1.1.5)
static char sysName[] PROGMEM       = "1.3.6.1.2.1.1.5.0";  // read-write (DisplayString)
// .iso.org.dod.internet.mgmt.mib-2.system.sysLocation (.1.3.6.1.2.1.1.6)
static char sysLocation[] PROGMEM   = "1.3.6.1.2.1.1.6.0";  // read-write (DisplayString)
// .iso.org.dod.internet.mgmt.mib-2.system.sysServices (.1.3.6.1.2.1.1.7)
static char sysServices[] PROGMEM   = "1.3.6.1.2.1.1.7.0";  // read-only  (Integer)

// custom OIDs -> Aan te passen
static char MyMib[] PROGMEM   = "1.3.6.1.2.1.10.127.1.1.1.1.6.3";     // The MIB I want to read

// RFC1213 local values (taken from agentuino sample sketch) -> Aan te passen
static char locDescr[]              = "Arduino based SNMP Astronomy Weather Station";  // read-only (static)
static char locObjectID[]           = "1.3.6.1.2.1.10.127.1";                       // read-only (static)
static uint32_t locUpTime           = 0;                                        // read-only (static)
static char locContact[20]          = "yesyes";                            // should be stored/read from EEPROM - read/write (not done for simplicity)
static char locName[20]             = "Agentuino";                              // should be stored/read from EEPROM - read/write (not done for simplicity)
static char locLocation[20]         = "Maidenhead, UK";                        // should be stored/read from EEPROM - read/write (not done for simplicity)
static int32_t locServices          = 7;                                        // read-only (static)

uint32_t prevMillis = millis(); // used for system uptime calculation
char oid[SNMP_MAX_OID_LEN];     // will hold the OID of an SNMP request
SNMP_API_STAT_CODES api_status; // agentuino SNMP status
SNMP_ERR_CODES status;

// SNMP callback function, taken from agentuino sample sketch and extended to include my custom OIDs
void pduReceived()  // is being called when an SNMP packet has been received
{
  SNMP_PDU pdu;
  //
  #ifdef DEBUG	
   Serial << "UDP Packet Received Start.." << " RAM:" << freeMemory() << endl;
  #endif		
  //
  api_status = Agentuino.requestPdu(&pdu);
  
  // check if valid packet
  if ( (pdu.type == SNMP_PDU_GET || pdu.type == SNMP_PDU_GET_NEXT || pdu.type == SNMP_PDU_SET) 
        && pdu.error == SNMP_ERR_NO_ERROR && api_status == SNMP_API_STAT_SUCCESS ) 
    {
    //
    pdu.OID.toString(oid);
    //
    Serial << "OID: " << oid << endl;
    //
    
    if ( strcmp_P(oid, sysDescr ) == 0 ) 
    	{
      	// handle sysDescr (set/get) requests
      	if ( pdu.type == SNMP_PDU_SET ) 
      	{
       	 // response packet from set-request - object is read-only
        	pdu.type = SNMP_PDU_RESPONSE;
        	pdu.error = SNMP_ERR_READ_ONLY;
      	} 
      	else 
      	{
        	// response packet from get-request - locDescr
        	status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locDescr);
        	pdu.type = SNMP_PDU_RESPONSE;
        	pdu.error = status;
      	}
      	//
      	#ifdef DEBUG
       	Serial << "sysDescr..." << locDescr << " " << pdu.VALUE.size << endl;
      	#endif
    	}
    
    else if ( strcmp_P(oid, sysObjectID ) == 0 ) 
    	{
      	// handle sysName (set/get) requests
      	if ( pdu.type == SNMP_PDU_SET ) 
     	 {
        	// response packet from set-request - object is read-only
        	pdu.type = SNMP_PDU_RESPONSE;
        	pdu.error = SNMP_ERR_READ_ONLY;
      	} 
      	else 
      	{
        	// response packet from get-request - locUpTime
        	status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locObjectID);
        	pdu.type = SNMP_PDU_RESPONSE;
        	pdu.error = status;
      	}
      	//
      	#ifdef DEBUG
       	Serial << "ObjectID" << locObjectID << " " << pdu.VALUE.size << endl;
      	#endif
    	}    

//…    had to shorten the code for I can post only 9500 characters in the Arduino forum. Check out the full code at the web page shown at the beginning of this example.
        
// add more custom OID blocks here


    
    else 
    {
      // oid does not exist
      //
      // response packet - object not found
      pdu.type = SNMP_PDU_RESPONSE;
      pdu.error = SNMP_ERR_NO_SUCH_NAME;
      Serial << "Unknown OID" << endl;
    }
    
    //
    Serial << "Sending response..." << endl;
    
    Agentuino.responsePdu(&pdu);
    count++;
  }
  
  else 
  // packet not valid, send GENERAL_ERROR response. Required, otherwise the invalid packet 
  // will get stuck in the buffer and processed over and over again
  
  {
    Serial << "Unknown Packet!!" << endl;
    Serial << "PDU Type: " << pdu.type << " PDU Error: " << pdu.error << " API status: "<< api_status << endl; 
    pdu.type = SNMP_PDU_RESPONSE;
    pdu.error = SNMP_ERR_GEN_ERROR;
    Agentuino.responsePdu(&pdu);
    Serial << "Sent 'GENERAL_ERROR' response" << endl;
  }

  //
  Serial << "freeing PDU.." << " RAM:" << freeMemory() << endl;
  Agentuino.freePdu(&pdu);
  //
  Serial << "UDP Packet Received End.." << " RAM:" << freeMemory() << endl;
}

void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  
  // start Agentuino SNMP library
  api_status = Agentuino.begin();
  if ( api_status == SNMP_API_STAT_SUCCESS ) 
  	{
    	Agentuino.onPduReceive(pduReceived); // register callback function that is being called when an SNMP packet has been received
    	delay(10);
    	Serial << "SNMP Agent Initalized..." << endl;
  	}
  else
  	{
    	delay(10);
    	Serial << "SNMP Agent Initalization Problem..." << status << endl;
  	}
}

void loop()
{
  Serial.print(MyMib);  
  
  // listen for / handle incoming SNMP requests
  Agentuino.listen();

  // sysUpTime - The time (in hundredths of a second) since
  // the network management portion of the system was last
  // re-initialized.
  if ( millis() - prevMillis > 1000 ) {
    // increment previous milliseconds
    prevMillis += 1000;
    //
    // increment up-time counter
    locUpTime += 100;
  }
}

Wouter202:
Hi, this is my first Arduino project after testing some example sketches and making an LCD display menu. I would like to read a few predefined MIB’s from a modem with SNMP get-commands. First I want to display a MIB in my serial monitor and finally I’d like to display them on my LCD. The modem I am using for this test is configured for use with SNMP V2c. The modem is not in a “live” environment. When I use a MIB browser I can see one of predefined MIB’s at this location: 1.3.6.1.2.1.10.127.1.1.1.1.6.3. The MIB contains a value around -490.

When I check my serial monitor using the code below the only thing I see is “SNMP Agent Initalized…” Can someone tell me how I can display a MIB there?

I used the sketch from the “Agentuino SNMP Astronomy Weather Station” and I adapted it for my own needs. I compared it with the Agentuino example sketch and the only difference I see was an “F” every time this function is used: Serial << F("SNMP Agent Initalized...") << endl;
Can someone tell what the “F” is needed for?

I believe the F function is part of the Flash library. "SNMP Agent Initialized..." is probably stored in EEPROM to save on memory. The F function pulls it out of EEPROM so that it can be sent to the Serial port.

MIB: File that contains a list of OIDs and their definitions, kind of a dictionary.
OID: Object Identifier, think of it as an encoded variable name.
Agent: An SNMP device that responds to GET and SET commands and can also send out traps/notifications.
Manager: An SNMP device or application that sends out GET and SET commands and listens for traps/notifications.
Versions: There are three common SNMP versions used today. 1, 2c, and 3.

The Agentuino library allows your Arduino to act as an SNMP v1 Agent. It sounds like you are wanting to use your Arduino as a v2c Manager, is that correct?

Hi there Rex, thank you for your reply. So maybe I should be placing the "F" in front every time Serial is called. Because in the SNMP Astronomy Weather Station example that wasn't the case?

Do you think it would be possible to use the Arduino as a v2c SNMP Manager with the Agentuino code? I think the GET-command is about the same in V1 as in V2. But maybe the code would need some adaptation then?

Wouter202:
Hi there Rex, thank you for your reply. So maybe I should be placing the "F" in front every time Serial is called. Because in the SNMP Astronomy Weather Station example that wasn't the case?

Do you think it would be possible to use the Arduino as a v2c SNMP Manager with the Agentuino code? I think the GET-command is about the same in V1 as in V2. But maybe the code would need some adaptation then?

You can either include the Flash library or alter all of the serial calls, up to you. All it is doing is writing to the serial port.

It would be possible to adapt the Agentuino library but you're going to have to get very familiar with the SNMP packet structure. I spent about 3 weeks learning about SNMP, bought an SNMP software suite, and made heavy modifications to the Agentuino library to bring it up to v2c specs (and make it a little easier to use with traps).

I haven't had a need to make it a manager but thinking off the top of my head (I don't have the Agentuino library open right now) it would go something like this:
Take the method that is used to send the get/set responses and use that as a template for sending a GET or SET PDU.
The PDU parsing method should work for parsing the response PDUs that will come back since they follow the same structure.
Find all of the references to the PDU version attribute, I believe it was hardcoded for v1, a value of 0. v2c has a value of 1.
v2c traps may work as well since, unlike v1 traps, they follow the standard PDU structure.

Find all of the references to the PDU version attribute, I believe it was hardcoded for v1, a value of 0. v2c has a value of 1.

Okay, I’ve been diving into the .cpp and .h file of the Agentuino library. This is the only place where a saw a version mentioned (cpp file):

//
	// extract version
	pdu->version = 0;
	for ( i = 0; i < verLen; i++ ) {
		pdu->version = (pdu->version << 8) | _packet[5 + i];

So I should change "pdu->version = 0;" into “=1”?

Take the method that is used to send the get/set responses and use that as a template for sending a GET or SET PDU.

Do you mean I should use this (below) as a template? Or do I need to go looking in the .h or .cpp file?

void pduReceived()
{
  SNMP_PDU pdu;
  //
  #ifdef DEBUG
    Serial << F("UDP Packet Received Start..") << F(" RAM:") << freeMemory() << endl;
  #endif
  //
  api_status = Agentuino.requestPdu(&pdu);
  //
  if ( pdu.type == SNMP_PDU_GET || pdu.type == SNMP_PDU_GET_NEXT || pdu.type == SNMP_PDU_SET
    && pdu.error == SNMP_ERR_NO_ERROR && api_status == SNMP_API_STAT_SUCCESS ) {
    //
    pdu.OID.toString(oid);
    //
    //Serial << "OID: " << oid << endl;
    //
    if ( strcmp_P(oid, sysDescr ) == 0 ) {
      // handle sysDescr (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) {
        // response packet from set-request - object is read-only
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = SNMP_ERR_READ_ONLY;
      } else {
        // response packet from get-request - locDescr
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locDescr);
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
      //
      #ifdef DEBUG
        Serial << F("sysDescr...") << locDescr << F(" ") << pdu.VALUE.size << endl;
      #endif

v2c traps may work as well since, unlike v1 traps, they follow the standard PDU structure.

I don’t think I will need traps to get the info out of my mib?

Thank you for looking into this with me. And thank you for sharing your knowledge, this is all pretty new for me. I would really like to get this working.

I realize this is an old thread. Does anyone have the library with the changes above for the send trap example to work? I need to send basic V1 SNMP traps. Receive and walk is working aok but I just cant find a way to send the traps.

regards
Craig.

:slight_smile: :slight_smile:
Dear try to upload the changes to send traps but do not quite understand the diff file, could someone post the files and the cpp .h with somenew to start working from there.
stay tuned to your comments.
:slight_smile: :slight_smile:

Does anyone knows if it is possible to receive SNMP Traps in Arduino (with Ethernet Shield)??

Thanks!