terça-feira, 25 de novembro de 2014

Agentuino + Zabbix - parte 2 - implementação do Zabbix

Olá pessoal,

No último post vimos o uso do Agentuino que implementa uma biblioteca para tornar o Arduino um agente SNMP e como ele disponibiliza informações coletadas pelo Arduino através de SNMP, fazendo que agentes de monitoramento SNMP (Zabbix, Nagios, etc) possam ser utilizados para verificar estas informações e disponibilizá-los para visualização e monitoramento. No caso do nosso projeto de monitoramento de temperatura vamos usar o Zabbix para visualizar e monitorar a temperatura.
Hoje veremos como utilizar o Zabbix para monitoramento SNMP:

Zabbix:

Deve-se instalar um Zabbix em uma máquina física ou através de máquina virtual. Lembrando que o Zabbix é open-source e é praticamente uma distro Linux especializada em monitoramento. A instalação é bem simples.

Download:

http://www.zabbix.com/download.php

Uma vez instalado o Zabbix devemos acessá-lo para configurar o monitoramento do Arduino:


Entre com o usuário Admin e senha configurada para o acesso admin. Uma vez logado vá em Configurações, Templates e clique no botão Criar Template:



    Dê um nome para o template. No caso eu coloquei como SNMP Arduino. Clique em Salvar.


Em Configurações, Templates, selecione SNMP Arduino:



Clique em Itens:


Clique em Criar Item:
 

Preencha os campos:
 
- Nome: Nome do Item. Neste caso coloquei como Temperatura
- Tipo: Agente SNMPv1 (o Agentuino está implementado em SNMP v1).
- Chave: temp (é o campo disponibilizado pelo SNMP que contém a temperatura coletada).
- SNMP OID: é a OID que está armazenando a temperatura.
- Comunidade SNMP: public

Os demais campos pode deixar como estão. Dê um Salvar.


Agora vamos criar um gráfico para visualizarmos a temperatura. Clique em Gráficos:


Clique em Criar Gráfico:


Dê um nome para o Gráfico e clique em Adicionar (como mostra a figura):


Escolha o item Temperatura que foi criado anteriormente:


Clique em Salvar:


Clique na aba Visualizar:


Vamos criar o host agora. Vá em Configuração, Hosts e clique em Criar host:


Preencha os campos:

- Nome do host
- Nome de exibição
- Interfaces SNMP: coloque o endereço IP do Arduino.

Clique em Salvar.



Selecione a aba Templates e clique em Adicionar:


Selecione o template SNMP Arduino:


Clique em Salvar:


Clique em Macros  e preencha os campos:

- Macro: {$SNMP_COMMUNITY}
- Valor: public

Clique em Salvar


Observe que o host Arduino Sensor no ícone de Disponibilidade SNMP está em verde.


Vamos agora criar uma Tela de visualização. Vá em Configuração, Telas e clique em Criar tela:


Escolha um Nome para a tela e especifique o número de linhas e colunas. No caso é 1 x 1 pois é somente o gráfico que iremos exibir na tela.


Clique em Alterar:


Escolha como Recurso o Gráfico simples e clique no botão Selecionar do campo Parâmetro:


Nas caixas escolha o Grupo onde o host Arduino Sensor está e selecione o Host Arduino Sensor.
Selecione o item Temperatura:


Deixe os campos no padrão e clique em Salvar:


Para visualizar a tela vá em Monitoramento, Telas e escolha a tela que você criou (Arduino Temperatura):


Com isso configuramos o Zabbix para mostrar a temperatura de forma gráfica. No próximo post vamos configurar Triggers (gatilhos) para avisar via e-mail ou SMS se a temperatura está acima do esperado.

Até a próxima!

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!