terça-feira, 25 de novembro de 2014

Agentuino + Zabbix - Parte 1 - implementação do Agentuino no projeto de monitoramento de temperatura

Olá pessoal,



Depois de um bom tempo sem postar no blog vamos continuar de onde paramos...

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 -1 -1 -public <endereço IP do Arduino> temp
    ou
snmpget -1 -1 -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!



terça-feira, 19 de agosto de 2014

SNMP com Arduino - Agentuino




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!

sábado, 16 de agosto de 2014

Complexidade dos projetos e adequação

Olá pessoal,

Hoje não vamos abordar um shield ou um componente mas vamos falar de assunto importante para os desenvolvedores da plataforma Arduino: a complexidade dos projetos e sua adequação.
Nestes posts até agora percebemos que à medida que vamos adicionando funcionalidades ao projeto a sua complexidade aumenta e é importante elencarmos os fatores que devemos estar atentos para que o projeto continue funcionando e haja a devida adequação de software (código) ao hardware e vice-versa.
Dentro da minha experiência na plataforma devemos estar atentos aos seguintes fatores:

1) Aumento do tamanho dos sketches

    A medida que o projeto aumenta no uso de shields, componentes e bibliotecas é necessário cada vez mais espaço para armanezar os sketches. Os sketches são armazenados na Flash Memory. Fiz uma relação abaixo das versões do Arduino que utilizei nos meus testes e projetos:

Arduino UNO:

.


MicrocontroladorATmega328
Tensão de operação5V
Tensão de entrada(recomendado)7-12V
Tensão de entrada (limites)6-20V
Pinos de I/O Digitais14 (dos quais 6 fornecem saída PWM)
Pinos de entrada analógicos6
Corrente DC por pino de I/O 40 mA
Corrente DC Pino 3.3V50 mA
Memória Flash 32 KB (ATmega328) dos quais 0.5 KB são usados pelo bootloader
SRAM2 KB (ATmega328)
EEPROM1 KB (ATmega328)
Velocidade do Clock16 MHz

Arduino Duemilanove:



MicrocontroladorATmega168 ou ATmega328
Tensão de operação5V
Tensão de entrada(recomendado)
7-12V
Tensão de entrada (limites)6-20V
Pinos de I/O Digitais14 (dos quais 6 fornecem saída PWM)
Pinos de entrada analógicos6
Corrente DC por pino I/O 40 mA
Corrente DC pino 3.3V50 mA
Memória Flash16 KB (ATmega168) ou 32 KB (ATmega328) dos quais 2 KB são usados pelo bootloader
SRAM1 KB (ATmega168) ou 2 KB (ATmega328)
EEPROM512 bytes (ATmega168) ou 1 KB (ATmega328)
Velocidade do Clock16 MHz

Arduino Leonardo:


MicrocontroladorATmega32u4
Tensão de operação5V
Tensão de entrada(recomendado)
7-12V
Tensão de entrada (limites)6-20V
Pinos de I/O digitais20
Canais PWM7
Canais de entrada analógicos12
Corrente DC por pino I/O40 mA
Corrente DC pino 3.3V50 mA
Memória Flash32 KB (ATmega32u4) dos quais 4 KB são usados pelo bootloader
SRAM2.5 KB (ATmega32u4)
EEPROM1 KB (ATmega32u4)
Velocidade do Clock 16 MHz

Arduino Mega:


MicrocontroladorATmega2560
Tensão de operação5V
Tensão de entrada(recomendado)
7-12V
Tensão de entrada (limites)6-20V
Pinos de I/O Digitais54 (dos quais 15 fornecem saída PWM)
Pinos de entrada analógicos16
Corrente DC por pino I/O 40 mA
Corrente DC pino 3.3V50 mA
Memória Flash256 KB dos quais 8 KB são usados pelo bootloader
SRAM8 KB
EEPROM4 KB
Velocidade do Clock16 MHz
É importante adequar os sketches para utilizar menos código quando você tem um Arduino com menor espaço de armazenamento. Siga algumas dessas dicas:
a) Verifique se há alguma biblioteca desnecessária ao projeto e se for comente-a.
b) Faça debug com a Serial somente nos trechos de código que é realmente necessário checar. Debug na serial consome espaço de código.
c) Se não há mais o que otimizar no código considere a possibilidade de adquirir um outro Arduino com mais espaço para os sketches (Arduino Mega por exemplo).

2) Aumento do uso de variáveis de memória

    O uso de variáveis de memória e estruturas consomem SRAM e dependendo do Arduino podem fazer com que haja reinicializações por conta de falta de memória SRAM . Tive uma experiência em projeto em que o Arduino simplesmente reinicializava se fosse utilizando uma variável float! Siga algumas dicas para usar menos memória:
a) Defina o tamanho das arrays char no tamanho exato.
b) Evitar usar variáveis float quando os valores a serem armazenados possam ser armazenados em variáveis int.
c) Se não há mais o que otimizar no uso de variáveis considere a possibilidade de adquirir um outro Arduino com mais SRAM (Arduino Mega por exemplo). Você pode adquirir também o Arduino Leonardo porém ele tem menos Flash Memory.


3) Aumento do uso de componentes e sensores

    Se o projeto demanda por mais pinos considere utilizar um Arduino com maior quantidade de pinos de entrada/saída. Deve-se ficar atento em relação à alimentação do Arduino quando utilizar muitos componentes nas portas digitais. Relata-se bastante problemas com relês que de alguma forma fazem o Arduino reiniciar.


4) Uso de várias bibliotecas e shields.

    O uso de várias bibliotecas podem aumentar o código além de aumentar a probabilidade de conflito de componentes ou shields por utilizarem os mesmos pinos. Os shields geralmente são empilháveis porém podem trazer algumas dificuldades para conexão.
Dica: ao trabalhar com display LCD prefira os que são I2C pois eles necessitam somente de dois pinos analógicos.

5) Módulos que necessitam de mais corrente.

   Shields GSM e servos podem necessitar de mais corrente que o fornecido pelo Arduino e necessitam de alimentação externa e podem influenciar no funcionamento destes. Fiquem atentos nestes detalhes!

Espero que essas dicas sejam bastante úteis! Se você tem experiências desse tipo relate-nos.

Até a próxima!!