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.


6 comentários:

  1. Olá, esse código serve no Arduino UNO com o módulo Shield Ethernet W5100? Como posso criar um gráfico para pegar as variações de humidade, tensão, temperatura, etc.... ??

    ResponderExcluir
  2. Esse código foi implementado em um Arduino UNO exatamente com esse shield. O gráfico você cria no Zabbix a partir do momento que o Zabbix consegue coletar os dados do Arduino através de SNMP.

    ResponderExcluir
    Respostas
    1. Quero enviar o valor de uma porta analógica. Ex: o valor de uma tensão, ou de uma temperatura de um sensor LM35, quais as modificações que devo fazer? Vc tem algum exemplo bem simples ai? Qual dessas variáveis é enviada via SNMP?

      Excluir
    2. Olhe esse post no meu blog:

      http://arduinoprojexp.blogspot.com.br/2014/08/snmp-com-arduino-agentuino.html

      Tente primeiro com esse exemplo e procure entender como o código foi construído e leia os comentários nos posts.. às vezes o pessoal já teve a mesma dúvida e já respondi..

      Obrigado,

      Excluir
  3. Sugiro atualizar seu post porque devido a problemas de incompatibilidade com as novas IDE há um pequeno problema quanto a alocação de memória com o PROGMEM.
    Por exemplo: onde vc declarou static char sysDescr[20] PROGMEM = "1.3.6.1.2.1.1.1.0"; // read-only (DisplayString). Deve ficar: static const char sysDescr[20] PROGMEM = "1.3.6.1.2.1.1.1.0"; // read-only (DisplayString).
    Precisam ficar sendo declaradas como constantes.

    ResponderExcluir
  4. Boa noite!!
    Tem alguma mudança que tenha que fazer para esse código funcionar hoje em dia, pois ele só consegue identificar pelos led não manda para o SNMP a retosta se esta on/off.

    ResponderExcluir