quinta-feira, 4 de maio de 2017

Raspberry Node.js Agente & Gerente SNMP

No post anterior:

 http://rubenshubner.blogspot.com.br/2017/04/agente-snmp-com-raspberry-nodejs-e.html

implementamos um Agente usando o Node.js no Raspberry para armazenar a leitura do A/D MCP3008  de oito canais e armazenar em uma MIB.
Fizemos o teste via o programa Mib Browser e mostrou que funcionou corretamente.
Nesta postagem vamos implementar um gerente SNMP para efetuar a conexão com o Agente da postagem acima e realizar a leitura da MIB.
A tela apresentada pode ser vista abaixo:






















Podemos observar o IP do agente que no nosso caso vai estar rodando no mesmo Raspberry é o mesmo da pagina web.
Os OIDs que serão pesquisados na MIB do Agente e os comandos Pesquisar e Loop.
O botão pesquisar fará uma pesquisa e o botão Loop ficara efetuando a pesquisa a cada segundo.
O hardware é o mesmo da postagem mencionada acima.
No diagrama baixo podemos ver os blocos funcionais deste processo:






























No Raspberry com o SO Raspbian instalamos o aplicativo Node.js onde podemos rodar os scripts para implementar os 03 blocos:

A) Servidor de HTML que fará a transferência dos arquivos HTML, CSS e Javascript para o navegador através do Request e Response do navegador.

B) O Servidor de Socket.io que fará as trocas de mensagens entre o Navegador e o Raspberry.

C) O Gerente SNMP que vai obter as informações do Agente SNMP.



Uma vez que o navegador recebe os scripts HTML, CSS e Javascript é formada a GUI que é a interface gráfica com o usuário e implementa o Socket.io Cliente para troca de mensagens com o servidor sem precisar haver refresh da página.

O funcionamento se dá da seguinte forma:

O Navegador envia a pesquisa para o Raspberry informando quais são os OIDs e IP para pesquisar no Agente através do Socket.io.
No Raspberry o gerente SNMP obtém estes valores da MIB do Agente e envia para o Navegador via Socket.io e são apresentados na interface gráfica GUI.

No Raspberry temos as seguintes pastas:



 A pasta gerente tem os scripts da implementação  que estamos fazendo e a pasta snmpAgent tem os scripts que foi implementado na postagem que detalha sobre o Agent conforme o link acima.

Dentro da pasta gerente podemos observar os conteúdos:




Podemos observar a pasta do navegador onde estão os scripts HTML, CSS e Javascript que rodará no navegador (IE, Chrome, Firefox e etc..).
A pasta node_modules que será instalada usando o comando npm install <nome do arquivo --save.

O arquivo leSnmp.js é o script que rodará no Raspberry e vai gerar os blocos HTML Server, Socket.io Server e o gerente SNMP como mostrado no diagrama acima.

Dentro da pasta do navegador temos os seguintes scripts:



 Index.css e Index.html responsáveis pela GUI.
index.js responsável pela lógica.
O arquivo ws.js é o socket.io client apenas foi renomeado ( não é necessário renomear ), pode ser encontrado na pasta node_modules dentro da pasta socket.io-client.
O jquery é comum a quem programa HTML e pode ser usado o CDN se preferir.

Na pasta node-modules podemos ver os módulos que foram baixados através do npm:






















Exemplo para instalar o express digite depois do prompt:
npm install express --save

E assim para todos os módulos.

Para rodar os processos no Raspberry quando o SO sobe automaticamente precisamos editar a pasta
/etc/rc.local veja abaixo:






















Para isto entramos em um editor de texto por exemplo com o comando:
sudo nano /etc/rc.local e chegamos na tela abaixo:

























Acrescentamos as 04 linhas antes do exit 0
 02 linhas são para dar o start no agente e as outras 02 linhas para dar o start no gerente.

Podemos dar os starts via terminal, mas da forma acima é só ligar e já estará resolvido.

Agora vamos aos Scripts:

Primeiro os que vão na pasta navegador e rodará do lado do cliente:


O index.html


<!DOCTYPE html>
<html>
 <head>
  <title>Page Title</title>

  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
  <meta http-equiv="Pragma" content="no-cache"/>
  <meta http-equiv="Expires" content="0"/>

  <link rel="stylesheet" href="index.css">

  <script type="text/javascript" src= "jquery-1.11.2.js"> </script> 
  <script type="text/javascript" src= "ws.js"></script>
  <script type="text/javascript" src= "index.js"> </script> 
  
</head>
<body>

<div id="divComando">
    <span style="color:blue" id="spIpAgent"> IP Agent </span>
    <input type="text" id="txtIpAgent" value= "192.168.0.30"> <br>


    <table id= "tableTitulo" border="1" >
         <tr>
             <td style="width:70%;" > OID </td>
             <td style="width:30%;" > Valor </td>
                   
        </tr>           
    </table>


    <table id= "tableResultado" border="1" >
         <tr>
             <td style="width:70%;"  >  <input   type="text" class="text1"  id="txtOid1" value="1.1.1.1.1.1.1.1.1.0" />  </td>
             <td style="width:30%;"  >  <input   type="text" class="text1"  id="txtValor1" /> </td>
                   
        </tr> 
        <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid2" value="1.1.1.1.1.1.1.1.2.0"/>  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor2" /> </td>
                   
        </tr> 
       
       <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid3" value="1.1.1.1.1.1.1.1.3.0" />  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor3" /> </td>
                   
        </tr> 
        <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid4" value="1.1.1.1.1.1.1.1.4.0"/>  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor4" /> </td>
                   
        </tr> 
        <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid5" value="1.1.1.1.1.1.1.1.5.0"/>  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor5" /> </td>
                   
        </tr> 
        <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid6" value="1.1.1.1.1.1.1.1.6.0" />  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor6" /> </td>
                   
        </tr> 
        <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid7" value="1.1.1.1.1.1.1.1.7.0"/>  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor7" /> </td>
                   
        </tr> 
       
         <tr>
             <td style="width:70%;" >  <input   type="text"  class="text1" id="txtOid8" value="1.1.1.1.1.1.1.1.8.0"/>  </td>
             <td style="width:30%;" >  <input   type="text"  class="text1" id="txtValor8" /> </td>
                   
        </tr> 


    </table>


<button type="button" id="btPesquisar">Pesquisar</button>
<button type="button" id="btLoop">Loop</button>
  
  
</div>

</body>
</html>



 index.css

O script html é bastante simples e será formatado pelo index.css como segue:

#divComando

  
    background:#ccccdd;
    color: #000000;
    position:absolute;
    float: left;
    float: top;
    left:1px;
    top:10px;
    width:1000px;
    height:600px;
    border: 2px solid;
    border-radius: 0px;    
}

#divComando #spIpAgent
{
    width: 100px; 
    position:absolute;
    float: left;
    float: top;
    left:1px;
    top:5px;
    font-size: 15px;
    font-family: Arial Black;
    font-style: oblique;
    text-align: center; 
}
#divComando #txtIpAgent
{
    width: 20%; 
    position:absolute;
    float: left;
    float: top;
    left:100px;
    top:5px;
    font-size: 15px;
    font-family: Arial Black;
    font-style: oblique;
    text-align: center; 
}
#divComando #tableTitulo
{
    color: #0000aa;
    position:absolute;
    float: left;
    float: top; 
    left:5%;
    top:50px;
    font-size: 15px;
    font-family: Arial Black;
    font-style: oblique;
    text-align: center;
    width: 90%;
    border: 2px solid black;
}
#divComando #tableResultado
{
    color: #0000aa;
    position:absolute;
    float: left;
    float: top; 
    left:5%;
    top:100px;
    font-size: 15px;
    font-family: Arial Black;
    font-style: oblique;
    text-align: center;
    width: 90%;
    border: 2px solid black;
}

#divComando .text1
{
font-size: 15px;
    font-family: Arial Black;
    font-style: oblique;
    text-align: center; 
    width: 90%;



#divComando #btPesquisar
 {

    position:absolute;
    float: left;
    float: top;
  margin-left: 400px;
    margin-top: 400px;

    background-color: #FFFFFF; 
    border: none; 
    color: black;
    padding: 16px 32px; /* tamanho do button */
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
     
   
}

#divComando #btPesquisar:hover 
{
    background-color: #4CAF50;
    color: white;
}

#divComando #btLoop
 {
    position:absolute;
    float: left;
    float: top;
    margin-left: 550px;
    margin-top: 400px;

    background-color: #FFFFFF; 
    border: none; 
    color: black;
    padding: 16px 32px; /* tamanho do button */
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
     
   
}
#divComando #btLoop:hover 
{
    background-color: #4CAF50;
    color: white;

}



 index.js


O index.js é o responsável pela lógica e a implementação do socket.io client, foi usado o jquery para tratar eventos de botão como visto abaixo:


var oid1=oid2=oid3=oid4=oid5=oid6=oid7=oid8="0";
var socket, io;
var ipAgent="0.0.0.0";
var msgFromserver = "";
var valores=[];

var ip = location.host;//Ip do Servidor HTML Conectado
var endereco="";
var loop;



$(document).ready(function () {

 ip = location.host;//Ip do Servidor HTML Conectado

    $('#btPesquisar').css('color','green');
    $('#btLoop').css('color','red');
    
 $("#txtIpAgent").val(ip);



    $('#btPesquisar').click(function () {

     $('#btLoop').css('color','red');
     $('#btPesquisar').css('color','green');
     clearInterval(loop);//Stop o setInterval
     conectar();
     pesquisar();

    }); //Fim do botao pesquisar



    $('#btLoop').click(function () {

    $('#btLoop').css('color','green');
    $('#btPesquisar').css('color','red');
    conectar();
    pesquisaLoop();
   

    }); //Fim do botao Loop


});

//============Funcao para conectar o Socket.io==============================

function conectar()
{

   endereco= "http://" + ip + ":3000";//Servidor socket.io no mesmo IP do servidor HTML

   socket = io.connect(endereco);


}



//==Funcao para conectar o Servidor Node.js para receber/Enviar WS==============
function pesquisar()
{


var oids="";


ipAgent=$("#txtIpAgent").val().trim();

oid1= $("#txtOid1").val().trim();
oid2= $("#txtOid2").val().trim();
oid3= $("#txtOid3").val().trim();
oid4= $("#txtOid4").val().trim();
oid5= $("#txtOid5").val().trim();
oid6= $("#txtOid6").val().trim();
oid7= $("#txtOid7").val().trim();
oid8= $("#txtOid8").val().trim();

  oids= ipAgent + "/"+ oid1 + "/" + oid2 + "/" + oid3 + "/" + oid4 + "/" + oid5 + "/" + oid6 + "/" + oid7 + "/" + oid8 +  "/";

  socket.emit('toServer', oids );//Envia para o servidor socket.io


  socket.on('toClient', function (msg) {//Evento que recebe do server mensagem do socket.io

  valores=msg.split("/");

  $("#txtValor1").val(valores[0]);
  $("#txtValor2").val(valores[1]);
  $("#txtValor3").val(valores[2]);
  $("#txtValor4").val(valores[3]);
  $("#txtValor5").val(valores[4]);
  $("#txtValor6").val(valores[5]);
  $("#txtValor7").val(valores[6]);
  $("#txtValor8").val(valores[7]);

  }); //Fim do evento que recebe do server mensagem do socket.io

}

//==================Funcao para pesquisar em loop================

function pesquisaLoop()
{


  loop=setInterval(function(){ pesquisar(); }, 1000);


}

Podemos observar que:

 socket.emit('toServer', oids ); envia o IP e as OIDS para o raspberry fazer a pesquisa no Agente.
no Raspberry tem um tratamento conforme o trecho abaixo:

 socket.on('toServer', function (data) {//Recebe mensagem de algum Cliente Conectado

    pesqOids=data.split("/");

   

    ipAgent=pesqOids[0];
    oids[0]=pesqOids[1];
    oids[1]=pesqOids[2];
    oids[2]=pesqOids[3];
    oids[3]=pesqOids[4];
    oids[4]=pesqOids[5];
    oids[5]=pesqOids[6];
    oids[6]=pesqOids[7];
    oids[7]=pesqOids[8];

    console.log("IP-->"    + ipAgent);
    console.log("OID 1-->" + oids[0]); 
    console.log("OID 2-->" + oids[1]); 
    console.log("OID 3-->" + oids[2]); 
    console.log("OID 4-->" + oids[3]); 
    console.log("OID 5-->" + oids[4]); 
    console.log("OID 6-->" + oids[5]); 
    console.log("OID 7-->" + oids[6]); 
    console.log("OID 8-->" + oids[7]); 

    leOids();
    
   }); 

Este trecho no Raspberry recebe através da chave toServer e separa a mensagem pelo delimitador "/".


Ainda no index.js temos o trecho que recebe os valores das leituras do agente através do trecho abaixo:

socket.on('toClient', function (msg) {//Evento que recebe do server mensagem do socket.io

  valores=msg.split("/");

  $("#txtValor1").val(valores[0]);
  $("#txtValor2").val(valores[1]);
  $("#txtValor3").val(valores[2]);
  $("#txtValor4").val(valores[3]);
  $("#txtValor5").val(valores[4]);
  $("#txtValor6").val(valores[5]);
  $("#txtValor7").val(valores[6]);
  $("#txtValor8").val(valores[7]);


  }); //Fim do evento que recebe do server mensagem do socket.io


No index.js este trecho aguarda o evento com a chave "toCliente" que vem com os valores do Raspberry.


leSnmp.js


Agora vamos ao código do leSnmp.js que roda no Raspberry:

var  static = require( 'node-static' );
var  http = require( 'http' );
var  snmp = require ("net-snmp");
var app = require('express')()
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);





//==========================variaveis globais============================
var port=80;
var pesqOids = [];
var oids=[8];
var valores=[];
var ipAgent="0.0.0.0";
var msgToClient=" ";
var soquete;




//===Servidor HTML arquivos da pasta navegador sao enviados ao cliente=========

var file = new static.Server( './navegador', {
    cache: 3600,
    gzip: true
} );

http.createServer( function ( request, response ) {
    request.addListener( 'end', function () {
        file.serve( request, response );
    } ).resume();
} ).listen( port );


//===============Servidor socket.io===================

server.listen(3000, function(){
   console.log("Socket.io Escutando a porta 3000... \n");
 });


    io.sockets.on('connection', function (socket) {

    soquete=socket;//soquete variavel global socket variavel local

    socket.on('toServer', function (data) {//Recebe mensagem de algum Cliente Conectado

    pesqOids=data.split("/");

   

    ipAgent=pesqOids[0];
    oids[0]=pesqOids[1];
    oids[1]=pesqOids[2];
    oids[2]=pesqOids[3];
    oids[3]=pesqOids[4];
    oids[4]=pesqOids[5];
    oids[5]=pesqOids[6];
    oids[6]=pesqOids[7];
    oids[7]=pesqOids[8];

    console.log("IP-->"    + ipAgent);
    console.log("OID 1-->" + oids[0]); 
    console.log("OID 2-->" + oids[1]); 
    console.log("OID 3-->" + oids[2]); 
    console.log("OID 4-->" + oids[3]); 
    console.log("OID 5-->" + oids[4]); 
    console.log("OID 6-->" + oids[5]); 
    console.log("OID 7-->" + oids[6]); 
    console.log("OID 8-->" + oids[7]); 

    leOids();
    
   }); 
   
});

//=========================Conecta com o Agent==================

function leOids()
{

 msgToClient="";

 session = snmp.createSession (ipAgent, "public");

 session.get (oids, function (error, varbinds)
 {
    if (error) 
    {
        console.error (error);
    } 
    else
    {
        for (var i = 0; i < varbinds.length; i++)
        {
            if (snmp.isVarbindError (varbinds[i]))
            {
                console.error (snmp.varbindError (varbinds[i]));

            }
               
            else
            {
                //console.log (varbinds[i].oid + " = " + varbinds[i].value);
                //msgOid[i]=varbinds[i].oid.toString();
                //valores[i]=varbinds[i].value.toString();
                //console.log(msgOid[i] + "-->" + msgValue[i] ); 
                //soquete.emit('toClient', msgOid[i] + "-->" + msgValue[i]);//Envia ao cliente

                valores[i] = varbinds[i].value.toString();

                msgToClient= msgToClient + valores[i] + "/";

                console.log(valores[i] );

            }                
        }

        console.log(msgToClient);
        soquete.emit('toClient', msgToClient );//Envia para o cliente socket.io                   
    }
});


}

Temos as seguintes partes:
a) Os requeres que usam os módulos instalados pelo npm
b) As variáveis globais.
c) O trecho  responsável pela conexão HTTP e transfere o HTML, CSS e Javascript para o navegador.
d) O Servidor de socket.io que envia e recebe mensagens do navegador
e) O gerente que obtém as informações do Agente.

Os trechos em azul são os códigos inteiros e os trechos em vermelho são partes que foram usados para comentários.

Com isto implementamos no Raspberry algumas coisas que podem ser feitas com o Node.js

Até a próxima.....










Nenhum comentário:

Postar um comentário