Olá pessoal,
Hoje vamos abordar o Agentuino - projeto que implementa um agente SNMP no Arduino permitindo que dados do dispositivo - informações sobre pinos de entrada e saída, sensores, etc - sejam disponibilizados através do protocolo SNMP e com isso agentes de monitoramento SNMP "conversam" através do protocolo SNMP para coletar esses dados. Isso permite que os dados sejam monitorados periodicamente através da rede e permitem o registro de dados e a exibição de forma gráfica desses dados coletados.
Dentro do projeto de acionamento automático de ar condicionado com infravermelho apontamos que seria necessário ter registros periódicos da temperatura e se tivéssemos que utilizar os e-mails ou SMS para fazer esses registros estes somente seriam ativados no acionamento por temperatura alta e não em períodos pré-determinados e assim não teríamos um monitoramento completo. Utilizando SNMP a coleta de dados é periódica e disponibilizada para leitura para os agentes de monitoramento SNMP e muitos destes agentes (por exemplo o Zabbix, Nagios, etc) permitem a composição de gráficos e também a emissão de alertas de acordo com condições específicas dos dados coletados. No caso do projeto isto seria o ideal: a temperatura seria coletada em intervalos periódicos, seria registrada e poderíamos montar um gráfico de monitoramento e acompanhar. Além disso seria possível programar alertas no agente de monitoramento para o caso em que a temperatura chegasse a um limite pré-programado e seria possível emitir alertas de e-mail e SMS. Era tudo que precisávamos! No Arduino não precisaríamos usar o código de envio de e-mail e como veremos mais tarde descobri que não precisaríamos usar o shield GSM também!
Para utilizar SNMP no Arduino você deve estar com um shield de rede ativa e funcionando e baixar a biblioteca agentuino. Fiquem atentos para as bibliotecas que o agentuino requer e baixe-as.
A biblioteca agentuino está disponível em:
https://code.google.com/p/agentuino/source/checkout
Utilize um cliente svn por linha de comando e baixe a versão do agentuino mais nova. Depois de instalado o cliente basta dar o comando:
svn checkout http://agentuino.googlecode.com/svn/trunk/ agentuino-read-only
A biblioteca será baixada na pasta agentuino-read-only na pasta de onde você rodou o comando.
Vamos ao código de exemplo do agentuino (vem na biblioteca):
/**
* Agentuino SNMP Agent Library Prototyping...
*
* Copyright 2010 Eric C. Gionet <lavco_eg@hotmail.com>
*
*/
#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
//
static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
static byte ip[] = { 192, 168, 2, 64 };
static byte gateway[] = { 192, 168, 2, 1 };
static byte subnet[] = { 255, 255, 255, 0 };
//
// tkmib - linux mib browser
//
// RFC1213-MIB OIDs
// .iso (.1)
// .iso.org (.1.3)
// .iso.org.dod (.1.3.6)
// .iso.org.dod.internet (.1.3.6.1)
// .iso.org.dod.internet.mgmt (.1.3.6.1.2)
// .iso.org.dod.internet.mgmt.mib-2 (.1.3.6.1.2.1)
// .iso.org.dod.internet.mgmt.mib-2.system (.1.3.6.1.2.1.1)
// .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)
//
// Arduino defined OIDs
// .iso.org.dod.internet.private (.1.3.6.1.4)
// .iso.org.dod.internet.private.enterprises (.1.3.6.1.4.1)
// .iso.org.dod.internet.private.enterprises.arduino (.1.3.6.1.4.1.36582)
//
//
// RFC1213 local values
static char locDescr[] = "Agentuino, a light-weight SNMP Agent."; // read-only (static)
static char locObjectID[] = "1.3.6.1.3.2009.0"; // read-only (static)
static uint32_t locUpTime = 0; // read-only (static)
static char locContact[20] = "Eric Gionet"; // 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] = "Nova Scotia, CA"; // should be stored/read from EEPROM - read/write (not done for simplicity)
static int32_t locServices = 7; // read-only (static)
uint32_t prevMillis = millis();
char oid[SNMP_MAX_OID_LEN];
SNMP_API_STAT_CODES api_status;
SNMP_ERR_CODES status;
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
} else if ( strcmp_P(oid, sysUpTime ) == 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_TIME_TICKS, locUpTime);
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
}
//
#ifdef DEBUG
Serial << F("sysUpTime...") << locUpTime << F(" ") << pdu.VALUE.size << endl;
#endif
} else if ( strcmp_P(oid, sysName ) == 0 ) {
// handle sysName (set/get) requests
if ( pdu.type == SNMP_PDU_SET ) {
// response packet from set-request - object is read/write
status = pdu.VALUE.decode(locName, strlen(locName));
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
} else {
// response packet from get-request - locName
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locName);
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
}
//
#ifdef DEBUG
Serial << F("sysName...") << locName << F(" ") << pdu.VALUE.size << endl;
#endif
} else if ( strcmp_P(oid, sysContact ) == 0 ) {
// handle sysContact (set/get) requests
if ( pdu.type == SNMP_PDU_SET ) {
// response packet from set-request - object is read/write
status = pdu.VALUE.decode(locContact, strlen(locContact));
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
} else {
// response packet from get-request - locContact
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locContact);
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
}
//
#ifdef DEBUG
Serial << F("sysContact...") << locContact << F(" ") << pdu.VALUE.size << endl;
#endif
} else if ( strcmp_P(oid, sysLocation ) == 0 ) {
// handle sysLocation (set/get) requests
if ( pdu.type == SNMP_PDU_SET ) {
// response packet from set-request - object is read/write
status = pdu.VALUE.decode(locLocation, strlen(locLocation));
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
} else {
// response packet from get-request - locLocation
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locLocation);
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
}
//
#ifdef DEBUG
Serial << F("sysLocation...") << locLocation << F(" ") << pdu.VALUE.size << endl;
#endif
} else if ( strcmp_P(oid, sysServices) == 0 ) {
// handle sysServices (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 - locServices
status = pdu.VALUE.encode(SNMP_SYNTAX_INT, locServices);
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
}
//
#ifdef DEBUG
Serial << F("locServices...") << locServices << F(" ") << pdu.VALUE.size << endl;
#endif
} else {
// oid does not exist
//
// response packet - object not found
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = SNMP_ERR_NO_SUCH_NAME;
}
//
Agentuino.responsePdu(&pdu);
}
//
Agentuino.freePdu(&pdu);
//
//Serial << "UDP Packet Received End.." << " RAM:" << freeMemory() << endl;
}
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
//
api_status = Agentuino.begin();
//
if ( api_status == SNMP_API_STAT_SUCCESS ) {
//
Agentuino.onPduReceive(pduReceived);
//
delay(10);
//
Serial << F("SNMP Agent Initalized...") << endl;
//
return;
}
//
delay(10);
//
Serial << F("SNMP Agent Initalization Problem...") << status << endl;
}
void loop()
{
// listen/handle for 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;
}
}
Lembrem-se: testar se a conectividade de rede está ok com ping.
Para testar o agentuino:
1) Baixar o snmpget ou o snmpwalk. No caso eu baixei o snmpget.
2) Testar com o comando snmpget:
snmpget -v 1 -r 1 -c public 192.168.2.64 sysName.0
ou
snmpget -v 1 -r 1 -c public 192.168.2.64 1.3.6.1.2.1.1.5.0
Onde:
-v 1: versão do SNMP (1)
-r 1: número de tentativas (1 tentativa)
-c public: nome da community (public)
192.168.2.64: ip do arduino que está rodando o agentuino
1.3.6.1.2.1.1.5.0 ou sysName.0: OID que se quer consultar.
O comando deverá retornar: Agentuino.
Bom é isso aí pessoal! Qualquer dúvida entrem em contato!
Até mais!