Agentuino - A lightweight SNMP Agent

We have a working library with example uploaded to the project page.

  1. Null (WIP)
  2. Boolean (WIP)
  3. Bits (WIP)
  4. Octet-String
  5. Object-Identifier (WIP)
  6. Integer and Integer32
  7. Counter and Counter64
  8. Gauge
  9. Time-Ticks
  10. IP-Address (WIP)
  11. Opaque (WIP)
  12. Network-Service-Access-Point (NSAP) Address (WIP)

WIP = Work In Progress.

Cheers,

Eric

Library updates:

  1. Null
  2. Boolean
  3. Bits (WIP)
  4. Octet-String
  5. Object-Identifier (WIP)
  6. Integer and Integer32
  7. Counter and Counter64
  8. Gauge
  9. Time-Ticks
  10. IP-Address
  11. Opaque
  12. Network-Service-Access-Point (NSAP) Address

WIP = Work In Progress.

Testers are needed.

Update..

There is a bug with OID decoding/encoding which is being worked on. Any OID value greater than 127 will not be handled properly until the fix is ready.

A Private Enterprise Number (PEN) was issued from iana http://pen.iana.org for the Arduino project.

Text OID...

.iso.org.dod.internet.private.enterprises.arduino

Numeric OID..

.1.3.6.1.4.1.36582

Again once the OID bug is fixed a MIB example will be supplied.

Another Update..
OID issue is fixed and an updated library will be uploaded shortly.

Cheers,

Eric

Hi

Is this library still under development, or is it in a working state as far as the developers are concerned and it'll just remain as is?

Thanks!

Jump in and help.

I don't have the wiznet eth module, so I am stuck until the pic eth enc28j60 library is properly ported....meaning I fix it myself, and thats a whole 'nother project in itself.

If anyone wants to work it, what needs to be done is the arduino ethernet lib needs to have a interface between the wiznet driver and the eth lib on top. As it is now its hardcoded for wiznet5100. Then the pic driver can be added. I need to reread and fully understand the pic eth chip to port the driver.

Frankly I am amazed that the guys got any kind of snmp lib up as soon as they did. I thank them for that.

I have found and fixed a bug in the currently available SNMP library but not sure what to do with the fix. Is anyone actively developing this library?

The issue occurs when an SNMP set is sent with a data length less than 'sizeof' the type being sent.

The iReasoning MIB Browser seems only to send the amount of data that it must send, i.e. for an integer snmpset with a value of 12, it will send 1 byte of data in the packet with the length of data set to 1.

Once the packet has been received, the main code will call a decode function to extract the data. As the code is expecting an integer, the decode(int32_t) function is used. The SNMP library doesn't check the data length and thus expects 4 bytes of data from the snmpset rather than the 1 it actually receives.

As there isn't a decode function for a 1 byte value, this would suggest that the library design is to deal with "short" data lengths using the decode for the expected size (int32_t/uint32_t) rather than expecting the calling code to check the size and to call the 'correct' decode (int8_t/uint8_t, which doesn't exist).

This means that an integer with data size of 1 could be extracted using any decode that takes a large enough integer parameter and the library sizes the data to match the incoming variable size.

As the code stands, decode(uint32_t *value) puts 0x12000000 into value as the low byte is data[0] instead of data[3] where the library expects it.

After the fix...

A packet contains data of 0x12 with a length of 1...

decode(uint32_t *value) puts 0x12 into value
decode(uint16_t *value) puts 0x12 into value
decode(uint8_t *value) puts 0x12 into value (this function variant doesn't actually exist, but could be added)

This present in all SNMP_VALUE decode functions other than char* and bool.

I've been away. It does check the lengths of a data type when parsed.

If anyone would like to contribute please send their e-mail in a private message.

Eric

Please excuse the thread intrerruption and the newbie question: Can i use the SNMP agent code to make the arduino a SNMP host? I want to read some values from a router and output a PWM signal from the arduino based on them.

Hi,
I have recently started a project using the Agentuino library. The project is a weather station with several sensors. The values of the sensors can be requested via SNMP and logged/graphed in Cacti (or similar).

I got this all more or less working but have now run into some issues.

First, Cacti seems to send some default SNMP requests to the agent that are not directly related to the requested value/OID. When the Arduino receives a packet that is not covered in the pduReceived() function, the packet seems to get stuck somewhere. The whole else if construction in the sample sketch (plus my own OIDs added) falls through because no OID matches. Then the pdu is freed. However, the next time I call Agentuino.listen() the same packet seems to be there still. So that creates an endless loop and no further SNMP GET requests will be processed.

So in other words, if I send a GET request that is handled in my sketch, all is fine. But if an unknown packet is being sent to the Arduino, there is an issue.

I've tried to work around it by doing the following:

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 )
{
// handle OID requests as in sample sketch
}
else
{
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = SNMP_ERR_GEN_ERROR;
Agentuino.responsePdu(&pdu);
}

That has stopped the endless loop but now the Arduino resets shortly after receiving an unknown packet.

The other issue is that Cacti seems to think that my room is 80 million degrees hot. :o
When I use Presser SNMP Tester to send test GET requests, I get a normal temperature reading of, say, 24 degrees. In Cacti it is being graphed as 80 million. There seems to be a data format issue that I haven't figured out yet.

This is what I do if I get a GET request for the Object Temperature:

// response packet from get-request - v_ObjTemp
status = pdu.VALUE.encode(SNMP_SYNTAX_INT32, v_ObjTemp);
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;

I see in SNMP Tester and in Wireshark that the response has a value of 24 (for example) and is 4 bytes long.

I'll work on these 2 today and report back but I think I might need a little help with this. So if anyone has any ideas, they would be more than welcome.

I just thought of something. Does the Agentuino lib check if a received packet is indeed an SNMP packet and only then pass it to the sketch? Or would it be possible that any other UDP packet could be reported in pduReceived() ? Would I need to handle that in the sketch?

OK, I think I figured both out.

The Agentuino lib does NOT like receiving another GET request before it has responded to the previous one. The workaround was to increase the time-out value to 1500ms in Cacti. This causes Cacti to wait 1.5 sec for a response (instead of the default 500ms) before re-transmitting the request. Since the Arduino does reply within 1.5 sec, Cacti does not need to re-transmit the request. With my current code the Arduino takes just under 1 sec to reply.

It would be nice if the lib could handle this a bit better. But I guess with 2kB of RAM, you can't buffer more than one packet?

The problem with the values being in the millions was solved by specifying "GAUGE" as the data type in Cacti. Before I used ABSOLUTE, which seems to interpret the data differently.
So that was not an issue with the Agentuino lib.

yesyes:

You mentioned that you are using SNMP to read data from your arduino weather station. Are the sensors read using non-blocking calls? Simple test is to place a timer variable at the beginning of your loop and see how long it take to cycle without making an SNMP call. This may explain why there is latency between SNMP requests.

I am using a Sensirion SHT?? (Temp/RH) and Intersema BP sensor both over serial or bit bang (together and plan on adding a second BP sensor)) and I don't have a latency problem. Keep mind that both libraries I have written for these sensors have non-blocking capabilities.

And yes the library does detect non-snmp packets, although there is always room to improve on the implemented method.

arduku:

Myself and John D. have been busy (work pays and this doesn't he he) since we started the project and orbitalair is hardware stricken till he can get a new ethernet sheild or port an ethernet lib. Although it seems that the wiznet and other chipsets have become the arduino standard. Anyway hopefully Santa comes through for orbitalair and drops off a new ethernet shield :slight_smile:

I do intend on spending more time on this project in the new year as it ties into another project I am working on.

As per the project's web site (Google Code Archive - Long-term storage for Google Code Project Hosting.); this is an Alpha library and were looking for others to contribute.

Alcor wrote;
Please excuse the thread intrerruption and the newbie question: Can i use the SNMP agent code to make the arduino a SNMP host? I want to read some values from a router and output a PWM signal from the arduino based on them.

Yes, you could use code from agentuino to talk to a host. Instead of listening, your requesting and waiting for a response. In theory the PDU can be used interchangeably.

If you decide to cut code and get it working please share your findings with us.

Regards,

Eric

LAVco, I use blocking calls when reading the sensors. But I don't read them when an SNMP request comes in. I read the Melexis temperature sensor continuously once per loop(). I've added a SHT15 last night and that is being read at least 10 seconds after the previous read (to stop it from getting warm and mess up my readings). The values are stored in global variables. When the SNMP request comes in, it just replies with the value from the variable.

I have put everything back outside now collecting data. So I can't change code right now (I wish there was a way to update the sketch via the Eth shield instead of USB). Will try it as soon as I bring it in for "maintenance" again or as soon as my 2nd Arduino arrives (which ever is sooner).

I'm really glad you made this library. I'd like to contribute but I'm not a good programmer. I do know some C / C++ and have written small MFC apps on Windows. So the Arduino API feels a bit familiar. But I'm not sure what I could contribute. Maybe some testing?

I still think there is some sort of issue in agentuino when a non-SNMP packet is received. When I call Agentuino.listen() and there was a packet received, I HAVE to send a response packet back, otherwise it will end up in an endless loop trying to process the previous packet.

Another question:

Can you think of any way of supporting a float data type in agentuino? I'd like to send my temperature data with one or 2 decimal places. Currently you only seem to have some integers and strings.

yesyes wrote;
Can you think of any way of supporting a float data type in agentuino? I'd like to send my temperature data with one or 2 decimal places. Currently you only seem to have some integers and strings.

SNMP doesn't support floating points. Strings are possible as per included example e.g. sysName and sysDescr but read the limitations section on our main project page.

Now back to floating point values, as the saying goes, there is more than one way to skin a cat! Use multipliers and divisors.

Know what your measuring; based on the sensor and parameter being measured there is always a max/min range and resolution that it can measure. So let's use Temperature and RH as an example. Say the sensor measures temperature from 70 deg C to -40 deg C and RH from 0 to 100 %.

INT is 65535 (unsigned 16bit int) but it can handle signed values as well -32000 to 32000 (approximation but a 16bit float)

Temperature:
70.00 (upper range) = 7000 (x100)
-40.00 (lower range) = 4000 (x100)

To normalize this further for other types of sensors (some can measure down to -50 deg C etc.) we could simply use 10,000 (max upper range) and -10,000 (min lower range) having an error value of 10,001. So if the system detects an out of bound measurement (out of range of the sensor's parameter being measured) you can flag it as an error. So if you receive an SNMP value of 2345, simply divide by 100 to get 23.45 deg C.

RH (floating point with RH is rarely used due to the type of measurement - it's relative :slight_smile: )
0 (lower range) = 0
100 (upper range) = 100

RH is always 0 to 100 (%) and again you could use 101 to reflect an error.

Resolution; if the sensor's parameter's resolution is only 0.1, your not adding accuracy by offering a resolution of 0.01.

The error codes aren't required and are used as basic QA/QC (meteorological QA/QC is a whole other subject).

On the string side, are you sure you need strings e.g. you can use enumerators in SNMP which consume an INT value versus a string (in the MCU wold that's needless memory consumption). For example, Precipitation Situation; 1-Light Rain, 2-Moderate Rain, 3-Heavy Rain.

I read the Melexis temperature sensor continuously once per loop

You don't need to sample that frequently for meteorological related applications. As per WMO/NWS standards it is recommended to sample air temperature at either 3 or 5 second intervals and is averaged over 1-minute. Soil temperature is sampled every minute due to the slow rate of change.

Hope this shed's some light on measurements using SNMP. The above examples are methodologies used in existing meteorological standards that I have been involved with.

Regards,

Eric

Thanks for that. I did think of that way of doing it. But (at least for now) for me the only purpose of using SNMP is to graph (and store) the data with Cacti. And that doesn't seem to have an option to divide received data by 10 or 100. At least none that I could find. I'll have a poke around. Maybe a Cacti script could help.

I only mentioned the strings because you already support them. I won't use them other than for the standard system name and so on. They are hard to graph .. :stuck_out_tongue:

In the end this weather station will go in my observatory (a roll-off roof shed with a telescope inside), record weather data and warn me when there's cloud and rain. And eventually close the roof when it starts raining. But that's not even built yet... :wink:

yesyes
I took a quick look at Cacti (seems like a pretty cool tool) and it's based on the RRDTool. The RRDTool round-robin database does support divisors.

If you haven't done so yet, I would subscribe to their forum and ask.

Sounds like a pretty neat project your undertaking. Good luck.

Also, I am waiting for TangoAlpha to upload his updates so I can add some updates that I've done as well.

Regards,

Eric

Correction; RRDTool graphing portion supports divisors.

Hi, just wanted to report back with success... :wink:
I have asked on the Cacti forum after failing to find anything in the Cacti documentation. Got an answer from a developer that pointed me in the right direction. While you can't modify data before being written to the database, you can apply math to the data before being graphed. So I now send (float_value * 100) converted to an int32 from the Arduino and when generating a graph it automatically divides everything by 100 again. Nice.

Thanks to you, LAVco, for pointing me in the right direction....

Hi All,

An updated library was uploaded to Google Code http://code.google.com/p/agentuino/.

  • decode functions were corrected (byte array, uint, int, etc)
  • all malloc calls were removed

We would like to thank TangoAlpha for detecting and correcting decoding bugs.

More to come and keep us posted should you find a bug.

Regards,

Eric

Thanks for the new version. Any chance of more details on the fixed bugs? Is there a changelog? :wink:
There was an issue when a new SNMP request comes in before the current one had been fully processed and replied to. Has this been fixed by any chance? :slight_smile: