Vamos à implementação do Agentuino no projeto de monitoramento de temperatura. A idéia básica é fazer com que o Arduino colete a temperatura e disponibilize esta informação via SNMP. O código adaptado ficou assim:
#include<dht11.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <IRremote.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Agentuino.h>
byte termometro[8] =//icone para termometro
{
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
byte higrometro[8] = //icone para umidade
{
B00100,
B00100,
B01010,
B01010,
B10001,
B10001,
B10001,
B01110,
};
//codigo rawcode capturado do ar condiconado via IRRecvDump
unsigned int powerOn[92] = {8950,4300,650,500,700,450,650,1600,650,500,600,1650,700,450,650,500,650,500,650,450,600,1700,600,550,550,550,600,1700,600,500,600,550,600,550,600,550,600,500,700,450,600,550,600,550,600,500,600,550,600,550,600,550,550,550,600,550,600,550,600,550,550,550,600,550,600,550,600,500,600,550,650,500,600,550,600,500,600,550,600,550,600,550,550,1700,600,550,600,550,550,1700,700};
// this must be unique
static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// change network settings to yours
EthernetClient client;
// 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[20] 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[20] 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[20] 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[20] 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[20] 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[20] 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[20] 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)
// .iso.org.dod.internet.private.enterprises.arduino.value.valA0-A5 (.1.3.6.1.4.1.36582.3.1-6)
/*
static char valA0[] PROGMEM = "1.3.6.1.4.1.36582.3.1.0"; // read-only (Integer)
static char valA1[] PROGMEM = "1.3.6.1.4.1.36582.3.2.0"; // read-only (Integer)
// .iso.org.dod.internet.private.enterprises.arduino.value.valD0-D13 (.1.3.6.1.4.1.36582.3.7-20)
static char valD0[] PROGMEM = "1.3.6.1.4.1.36582.3.7.0"; // read-only (Integer)
static char valD1[] PROGMEM = "1.3.6.1.4.1.36582.3.8.0"; // read-only (Integer)
*/
static char temp[24] PROGMEM = "1.3.6.1.4.1.36582.3.1.0"; // read-only (Integer)
static char locDescr[20] = "Agentuino";
static char locObjectID[20] = "1.3.6.1.4.1.36582";
static uint32_t locUpTime = 0;
static char locContact[20] = "Eric Gionet";
static char locName[20] = "Agentuino";
static char locLocation[20] = "Nova Scotia, CA";
static int32_t locServices = 7;
static int loctemp = 0;
//uint32_t prevMillis = millis();
uint32_t dispMillis = 0;
char oid[SNMP_MAX_OID_LEN];
SNMP_API_STAT_CODES api_status;
SNMP_ERR_CODES status;
boolean disparou;
boolean disptempo;
// Objeto irsend para emissor infrared
IRsend irsend;
// Objeto rtc (relogio de tempo real)
//RTC_DS1307 rtc;
int sinVal = 0;
int toneVal = 0;
#define lcdAddr 0x20
// Objeto LCD com 2 linhas e 16 caracteres por linha
LiquidCrystal_I2C lcd(lcdAddr, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE);
//objeto sensor para DHT11 (sensor de temperatura)
dht11 sensor;
void pduReceived()
{
SNMP_PDU pdu;
Serial.println("UDP Packet Received...");
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.print("OID = ");
Serial.println(oid);
if ( pdu.type == SNMP_PDU_SET ) {
status = SNMP_ERR_READ_ONLY;
} else if ( strcmp_P(oid, sysDescr ) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locDescr);
} else if ( strcmp_P(oid, sysUpTime ) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_TIME_TICKS, locUpTime);
} else if ( strcmp_P(oid, sysName ) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locName);
} else if ( strcmp_P(oid, sysContact ) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locContact);
} else if ( strcmp_P(oid, sysLocation ) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locLocation);
} else if ( strcmp_P(oid, sysServices) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_INT, locServices);
} else if ( strcmp_P(oid, sysObjectID) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locObjectID);
} else if ( strcmp_P(oid, temp) == 0 ) {
status = pdu.VALUE.encode(SNMP_SYNTAX_INT, loctemp);
} else {
status = SNMP_ERR_NO_SUCH_NAME;
}
pdu.type = SNMP_PDU_RESPONSE;
pdu.error = status;
Agentuino.responsePdu(&pdu);
}
Agentuino.freePdu(&pdu);
}
void adicionazero(int numar) { //this adds a 0 before single digit numbers
if (numar >= 0 && numar < 10) {
lcd.write('0');
}
lcd.print(numar);
}
void lcdnormal(int temp, int umi) {
// DateTime now = rtc.now(); // carrega a data e hora do RTC
lcd.clear(); //limpa o display do LCD.
lcd.home();
lcd.createChar(1,termometro);
lcd.createChar(2,higrometro);
lcd.setCursor(1,0);
lcd.write(1);
lcd.setCursor(3,0);
//lcd.print("Temp: "); //imprime a string no display do LCD.
lcd.print(temp); // imprime a temperatura no LCD
lcd.write((char)223); //Simbolo de graus celsius
lcd.print("C");
lcd.setCursor(10,0);
lcd.write(2);
lcd.setCursor(12,0);
lcd.print(umi); // imprime a umidade no LCD
lcd.print("%");
lcd.setCursor(1, 1);
}
void lcdalto(int temp) {
lcd.clear(); //limpa o display do LCD.
lcd.home();
lcd.createChar(1,termometro);
lcd.setCursor(1,0);
lcd.write(1);
lcd.setCursor(3,0);
//lcd.print("Temp: "); //imprime a string no display do LCD.
lcd.print(temp); // imprime a temperatura no LCD
lcd.write((char)223); //Simbolo de graus celsius
lcd.print("C");
lcd.setCursor(0,1); //posiciona o cursor na coluna 0 linha 1 do LCD.
lcd.print("TEMP. ALTA!"); //Imprime a string no display do LCD.
}
void setup() {
Serial.begin(9600); // Inicia conexao serial para monitoramento
Ethernet.begin(mac);
// Serial.println("Ethernet iniciado");
#ifdef AVR
Wire.begin();
#else
Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
lcd.begin(16,2); // inicializa o lcd
lcd.setBacklight(1);
//Serial.println("LCD iniciado");
pinMode(8,OUTPUT); //pino 8 para saida do alto falante
disparou = false;
disptempo = true;
api_status = Agentuino.begin();
if ( api_status == SNMP_API_STAT_SUCCESS ) {
Agentuino.onPduReceive(pduReceived);
delay(10);
Serial.println("SNMP Agent Initiated...");
return;
} else
{
delay(10);
Serial.print("SNMP Agent failed!");
}
}
void loop() {
int chk = sensor.read(7); //le a temperatura
// Serial.println("Lendo Sensor: ");
/*
//Verifica o status do DHT11
switch(chk) {
case DHTLIB_OK:
Serial.println("OK");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.println("Erro no checksum");
break;
case DHTLIB_ERROR_TIMEOUT:
Serial.println("Tempo esgotado");
break;
default:
Serial.println("Erro desconhecido");
}
*/
// Carrega os valores de temperatura e umidade do sensor nas variaveis correspondentes
int t = sensor.temperature;
int u = sensor.humidity;
// Monitora a umidade e temperatura para a conexao serial
/*
Serial.print("Umidade (%): ");
Serial.println(u);
Serial.print("Temperatura (graus Celsius): ");
Serial.println(t);
*/
if (t > 26) { //se temperatura for maior que 26 graus
// Aciona o ar condicionado novamente
//irsend.sendRaw(powerOn,92,38);
if (!disparou) {
// Serial.print("Dispara primeira");
irsend.sendRaw(powerOn,92,38);
dispMillis = millis();
disptempo = false;
//Serial.print("Disparou pela primeira vez");
}
//Aguarda 5 minutos para enviar novamente o codigo IR caso a temperatura nao baixe
if ((millis() - dispMillis > 300000) && (!disptempo)){
irsend.sendRaw(powerOn,92,38);
// Serial.print("Disparou por tempo");
disptempo = true;
}
// Exibe o valor da temperatura lida pelo sensor
lcdalto(t);
//Envia sinal sonoro para o pino 8 - alto falante
for (int x=0; x<180; x++) {
// converte graus para radianos e depois obtem o valor do seno
//Serial.print("Toca o som");
sinVal = (sin(x*(3.1416/180)));
toneVal = 2000+(int(sinVal*1000));
tone(8, toneVal);
delay(2);
}
disparou = true;
delay(2000);
}
else
{
// Temperatura normal
lcdnormal(t,u);
delay(2000);
noTone(8);
disparou = false;
}
Agentuino.listen();
loctemp = t;
}
Cabe aqui algumas considerações sobre a implementação:
1) Complexidade do código e uso de memória SRAM: como vocês podem ver no código que utilizamos muitas variáveis e simplesmente não rodou no Arduino Duemilanove!!! TIve que enxugar ao máximo o código e mesmo assim o Arduino reiniciava. Comprei um Arduino Leonardo com mais SRAM (porém com menos espaço na Flash) e aí rodou bem. Tenho a impressão que o Arduino Leonardo é mais rápido que os outros Arduinos.
2) Uso da serial: se vocês observarem no código eu comentei bastantes linhas de debug de código pela Serial. Isso ajuda a conservar memória porém não permite você analisar mais a fundo se o código está rodando corretamente.
3) Eliminação do uso do shield GSM e do código de envio de e-mail.
Para testarmos se o Agentuino está rodando perfeitamente basta fazer um teste com um cliente snmp via linha de comando:
snmpget -v 1 -r 1 -c public <endereço IP do Arduino> temp
ou
snmpget -v 1 -r 1 -c public <endereço IP do Arduino> 1.3.6.1.4.1.36582.3.1.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.4.1.36582.3.1.0 ou temp: OID que armazena a temperatura
O comando deverá retornar a temperatura coletada no momento.
No próximo post veremos como implementar o Zabbix para coletarmos e visualizarmos a temperatura através de SNMP.
Dúvidas entrem em contato,
Até a próxima!