segunda-feira, 14 de setembro de 2015

Monitoramento de tensão - SNMP + Zabbix

Olá pessoal!

Depois de um bom tempo sem postagens o blog volta com novidades! Dando continuidade ao projeto de monitoramento de tensão hoje veremos como implementar SNMP com Agentuino neste projeto e monitorá-lo através do Zabbix da mesma forma como fizemos com o circuito de monitoramento de temperatura.
O que precisaremos para implementar SNMP? Antes de mais nada precisamos acrescentar um Shield Ethernet W5100 ao nosso projeto, configurar a rede e conectá-lo. Uma vez acrescentado o Shield Ethernet W5100, vamos ao código:

A única coisa que mudou em relação ao SNMP Agentuino do projeto de monitoramento de temperatura foi a variável tensao que será disponibilizada via SNMP para a leitura pelo agente SNMP Zabbix.


#include <Wire.h> 
#include <SPI.h>
#include <Ethernet.h>
#include <Agentuino.h> 

static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D }; 

EthernetClient client;

static const 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 const 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 const 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 const 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 const 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 const 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 const 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 const char valA0[] PROGMEM   = "1.3.6.1.4.1.36582.3.1.0";  // read-only  (Integer)

static const 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 const char valD0[] PROGMEM   = "1.3.6.1.4.1.36582.3.7.0";  // read-only  (Integer)

static const char valD1[] PROGMEM   = "1.3.6.1.4.1.36582.3.8.0";  // read-only  (Integer)
*/
static const char tensao[24] PROGMEM = "1.3.6.1.4.1.36582.3.5.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;
boolean loctensao = 0; 
boolean statustensao = 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;


byte LEDNORMAL = 3; //pino do Led verde (ENERGIA NORMAL)
byte LEDFALTA = 4; //pino do Led vermelho (FALTA DE ENERGIA)

volatile unsigned long contador; //variável controlada através da interrupção na porta 2 

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, tensao) == 0 ) {
      status = pdu.VALUE.encode(SNMP_SYNTAX_INT, loctensao);
    
    } else {
      status = SNMP_ERR_NO_SUCH_NAME;
    }
    pdu.type = SNMP_PDU_RESPONSE;
    pdu.error = status;
    Agentuino.responsePdu(&pdu);
  }
  Agentuino.freePdu(&pdu);
  
}

void setup() {
     Ethernet.begin(mac);
     pinMode(LEDNORMAL, OUTPUT);
     digitalWrite (LEDNORMAL, LOW);
     pinMode(LEDFALTA, OUTPUT);
     digitalWrite(LEDFALTA, LOW);

     pinMode(2,INPUT); //porta 2 que detecta se está em estado alto ou baixo
     digitalWrite(2,LOW);  
     contador = 0;
     attachInterrupt(0, detect, RISING); //a interrupção 0 utiliza a porta 2 para atender a interrupção e caso haja a interrupção chama a função detect na subida do estado (LOW para HIGH)

    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() {
  unsigned long contador_loop = contador; 
  unsigned long tempo = millis()+100; 
  while (tempo > millis()); 
  if (contador > contador_loop) //se chamar a interrupção detect contador ficará maior que contador_loop
  {
     digitalWrite(LEDNORMAL, HIGH); //se tiver tensão no circuito acende Led Verde
     digitalWrite(LEDFALTA, LOW); //se tiver tensão no circuito apaga Led vermelho
     statustensao = 1;
  }
  else
  {
     contador = 0;
     digitalWrite(LEDFALTA, HIGH); //se não tiver tensão no circuito acende Led vermelho
     digitalWrite(LEDNORMAL, LOW); //se não tiver tensão no circuito apaga Led verde   }
     statustensao = 0;
  }
  Agentuino.listen();
  loctensao = statustensao;  
}

void detect() {
   contador++; 
}

Com isso basta configurar o Zabbix para ler via SNMP a variável tensao e acionar uma trigger se o valor for igual a zero (falta tensão).

Configuramos um gráfico para visualizar:




Pessoal, por enquanto é só. Quaisquer dúvidas estamos aqui. No próximo post iniciaremos um novo projeto.