Monitorando temperatura com Emoncms

Ola ilustríssimos leitores e leitoras. Neste post vamos montar um ambiente de monitoração de temperatura completo e profissional, utilizado Arduino, Raspberry, shield Ethernet e sensores DS18B20. Para isso utilizaremos:

  • 1 Arduino
  • 5 sensores de temperatura DS18B20
  • 1 módulo Ethernet ENC28J60
  • 1 Raspberry PI model 1 B+
  • Plataforma emonCMS

Para quem é recente no blog (bem vindo 🙂 ) e mesmo os que sempre nos acompanham, recomendo que vejam (ou revejam) os seguintes posts:

Bastante posts, mas certamente vão facilitar em muito o entendimento. Ao final, você estará apto a visualizar não só informações sobre temperatura, como de quaisquer outros sensores(luminosidade, corrente, fluxo d´agua, etc), em uma dashboard como a abaixo:

emonCMS Dashboard

Dashboard do emonCMS com medidas obtidas do DS18B20

Obtendo a API key no emonCMS

Considerando que você instalou o emonCMS no Raspberry Pi conforme o post acima, ou mesmo criou uma conta para usar o serviço “na nuvem” (https://emoncms.org/), o primeiro passo para nosso setup é obter a API key(Application Programming Interface KEY). É com esta chave que o Arduino vai poder enviar as informações dos sensores DS18B20 para armazenamento, processamento e visualização no emonCMS. A API key é um código único para cada instalação/conta no emonCMS, e é a responsável pela segurança, ou seja, somente os dados enviados por dispositivos que possuem essa chave são permitidos no emonCMS.

Acesse seu emonCMS, loge-se e logo na página inicial vai encontrar sua API key. Temos dois tipos, a Read e a Write. Como vamos escrever informações no emoCMS, utilizaremos a Write.

API key emonCMS

Encontrando a API key do emonCMS

Como enviar informações para o emonCMS

Legal, agora que obtemos nossa API key, vamos ver como o emonCMS espera receber as informações. Clique em Setup e no menu que aparece clique em Inputs.

emonCMS Inputs

Acessando configuração de Inputs

 

emonCMS sem Inputs

Nenhuma entrada configurada

Veja que não temos nenhuma entrada configurada. Vamos para Input API Helper. Nesta página temos vários exemplos de como enviar informações para o emonCMS. O que nos interessa é a sintaxe para envio a partir de dispositivos externos utilizando a API key. Especificamente procuramos pela linha abaixo:

https://emoncms.org/input/post?json={power:200}&apikey=40f26f5a0c7b22fb4db7e02a70348464

Legal. Já  temos a API key e o formato da URL a “chamar” em nosso sketch. Nós não configuramos nenhuma entrada aqui. Cada Input (informação a ser armazenada, processada e visualizada) é criado dinamicamente conforme formos enviando, por isso a importância da API key para controlar quais dispositivos podem enviar.

Diagrama utilizado.

O diagrama utilizado das conexões entre o Arduino, shield Ethernet e sensores DS18B20 é o abaixo:

Arduino ENC28J60 DS18B20

Arduino com Shield Ethernet ENC28J60 e DS18B20

Maiores detalhes podem ser obtidos no link “Utilizando 5 sensores DS18B20” no início do post. A diferença aqui é que estamos utilizando um shield Ethernet sobre o Arduino e alteramos o pino Sinal no Arduino de 10 para 8, já que o shield Ethernet utiliza o pino 10 para SS(Slave Select). além das conexões acima, temos um cabo de rede conectando o Arduino em nossa rede, e temos ainda um Raspberry Pi também conectado na rede.

Sketch utilizado

O sketch utilizado é uma variante do sketch utilizado no mesmo post indicado acima. As alterações são as necessárias para o funcionamento do ENC28J60 e a transmissão das informações de temperatura dos sensores. Como o sketch ficou “grandinho”, pode baixá-lo diretamente clicando aqui, mas segue o mesmo abaixo:

#include <UIPEthernet.h>
EthernetClient client;
byte server[] = {192, 168, 15, 201};
String apikey = "536f2b76d5f17ecaebd78c47cd398363";
#include <OneWire.h>
OneWire  ds(8);  // on pin 10 (a 4.7K resistor is necessary)

void setup() {
  Serial.begin(9600);
  uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x07};
  if (Ethernet.begin(mac)) {
    Serial.println("SUCESSO");
  }
  delay(1000);
  Serial.print("LocalIP: ");
  Serial.println(Ethernet.localIP());
  Serial.print("SubnetMask: ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("gatewayIP: ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("dnsServerIP");
  Serial.println(Ethernet.dnsServerIP());
}

void loop() {
  le_temperatura();
  delay(5000);
}

void httpRequest(String sensor,float temperatura) {
  if (client.connect(server, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.print("GET /emoncms/input/post.json?node=1&json={");
    client.print(sensor);
    client.print(":");
    client.print(temperatura);
    client.print("}&apikey=");
    client.print(apikey);
    client.println(" HTTP/1.1" );
    client.println("Host: 192.168.15.201");
    client.println("Connection: close");
    client.println();
  } else {
    Serial.println("connection failed");
  }
}

void httpFeedback() {
  while (client.connected()) {
    while (client.available() > 0) {
      char c = client.read();
      Serial.write(c);
    }
  }
  client.stop();
}

void le_temperatura() {
  byte i;
  byte data[12];
  byte addr[8];
  float celsius;
  String sensor = "";
  ds.reset_search();
  while (ds.search(addr)) {
    switch (addr[7]) {
      case 0x2c:
      sensor="amb01";
        Serial.println("  sensor: amb01");
        break;
      case 0x8e:
      sensor="cxA1";
        Serial.println("  sensor: cxA1");
        break;
      case 0xd2:
      sensor="cxA2";
        Serial.println("  sensor: cxA2");
        break;
      case 0x3f:
      sensor="cxB1";
        Serial.println("  sensor: cxB1");
        break;
      case 0xde:
      sensor="cxB2";
        Serial.println("  sensor: cxB2");
        break;
      default:
        Serial.print("ROM =");
        for ( i = 0; i < 8; i++) {
          Serial.write(' ');
          Serial.print(addr[i], HEX);
        }
    }

    ds.reset();
    ds.select(addr);
    float inicio = millis();
    ds.write(0x44);        // start conversion, use ds.write(0x44,1) with parasite power on at the end
    while (ds.read() == 0){
      
    }
    float fim = millis();
    Serial.print("O tempo gasto com a leitura foi de: ");
    Serial.print(fim - inicio);
    Serial.println(" milesegundos");

    delay(1000);     // maybe 750ms is enough, maybe not

    ds.reset();
    ds.select(addr);
    ds.write(0xBE);         // Read Scratchpad

    for ( i = 0; i < 9; i++) {           // we need 9 bytes
      data[i] = ds.read();
    }

    // Convert the data to actual temperature
    // because the result is a 16 bit signed integer, it should
    // be stored to an "int16_t" type, which is always 16 bits
    // even when compiled on a 32 bit processor.
    int16_t raw = (data[1] << 8) | data[0];
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
    celsius = (float)raw / 16.0;

    Serial.print("  Temperature = ");
    Serial.print(celsius);
    Serial.println(" Celsius, ");
    Serial.println("");
    httpRequest(sensor,celsius);
    httpFeedback();
  }
}

Detalhes do sketch

Iniciamos incluindo a biblioteca que utilizaremos para o shield ENC28J60(lembrem-se que há outras), criamos então um objeto client do tipo EthernetClient para cuidar das requisições ao emonCMS, e criamos também o array server[] para armazenar o endereço do emonCMS instalado no Raspberry PI. Ainda criamos uma variável apikey, do tipo String, e nela armazenamos o valor da API key de escrita obtida anteriormente. Encerramos com as declarações necessários para utilizar os sensores DS18B20, com atenção ao pino que utilizaremos como Sinal do protocolo One-Wire.

Em setup() nós inicializamos a console serial e inicializamos o shield Ethernet passando como parâmetro o endereço mac. Após a inicialização nós mostramos na console serial os valores obtidos via DHCP.

No loop() nós chamamos a função le_temperatura(), com um delay de 5 segundos entre cada loop. Até aqui não temos muitas novidades. O código que faz a comunicação ethernet entre o Arduino e o emonCMS esta contido em duas funções: httpRequest(String sensor,float temperatura); e httpFeedback(); Estas funções são chamadas dentro da função le_temperatura();

Arduino – Realizando conexões TCP

A função httpRequest é quem efetivamente realiza a conexão e envia os dados. Ela recebe como parâmetros o sensor que estamos lendo no momento e a temperatura atual. Iniciamos fazendo a conexão TCP entre o módulo ENC28J60 e o emonCMS com client.connect(server,80). Uma vez que a conexão tenha sucesso, chamamos a URL conforme o esperado pelo emonCMS. Vejam no código que chamamos a parte estática(trecho sem os valores), na sequencia enviamos o a dupla sensor:temperatura e por fim finalizamos incluindo a API key na requisição. Ainda enviamos alguns parâmetros do header TCP. Caso a conexão inicial falhe, não executamos nada disso e informamos na console serial a falha na conexão.

A função httpFeedback(); é uma função auxiliar. No nosso caso utilizamos ela para “pausar” o sketch pelo tempo necessário para que a conexão TCP seja corretamente encerrada tanto pelo Arduino quanto pelo emonCMS. Enquanto esperamos o encerramento adequado, imprimimos na console serial o status de retorno(feedback) da requisição que fizemos com httpRequest();

função le_temperatura()

As alterações aqui são mínimas. Na condicional switch, onde antes apenas exibíamos na console serial qual sensor estamos lendo no momento, agora nós gravamos esta informação na variável sensor. Após obtermos a temperatura e transformá-la em celsius, chamamos a função httpRequest, informando ao emonCMS a temperatura do sensor X.

Testando o setup.

Para por em funcionamento é simples. Mas vamos com calma para ver o resultado aparecendo. Considerando que o Raspberry esta operacional e conectado na sua rede, faça as conexões no Arduino mas sem conectá-lo a rede, conecte o mesmo ao seu PC e faça upload do sketch. Veja na console serial se esta tudo OK com as leituras de temperatura. Obviamente que verá algumas informações de erro de conexão, já que ainda não conectamos nosso shield ENC28J60 na rede.

Estando tudo OK na console serial, hora de conectar nosso Arduino na rede. Para isso conecte-se via browser ao emonCMS na seção Inputs, ainda não deverá ter nenhum Input aparecendo na tela. Agora conecte o Arduino finalmente na rede e dê um reset. O reset é necessário pois o sketch consulta o servidor DHCP apenas em setup(). Se ocorreu tudo bem, os Inputs começarão a aparecer na tela do emonCMS, com os nomes de acordo com o configurado no sketch e os valores de acordo com a temperatura atual lida. No emonCMS deverá algo parecido com a tela abaixo:

emonCMS com Inputs DS18B20

emonCMS com Inputs enviados do Arduino e DS18B20

Na tela acima eu adiantei um passo, vejam que em “Process list” temos Log to feed. O motivo é que eu já configurei uma ação a ser realizada sobre os Inputs, e essa ação é logar a informação no mysql instalado no Raspberry. Não se preocupe que já vem instalado e configurado por padrão quando instalamos o emonCMS 😀

O que fazer com as informações enviadas para o emonCMS?

Vou ser específico com o objetivo deste post, porque senão dá um livro…  Vamos armazenar as informações recebidas no banco de dados e criar gráficos para visualizar as informações. Seguindo a imagem acima, cliquem no símbolo de chave (configuração) à direita de cada um dos Inputs, e selecione as opções conforme especificado abaixo:

log to feed emonCMS

emonCMS – Logando informações no mysql

Após este procedimento em todos os Inputs, fique tranquilo que suas informações estão sendo armazenadas na base de dados e poderemos consultá-las historicamente.

Bem, vou encerrando por aqui, sei que esta faltando uma explicação sobre a criação do dashboard, mas calma ai que tem muito assunto para o próximo post. Na verdade estava quase terminado, mas o post estava realmente grande, então achei melhor dividir o post. E, não seria eu se mostrasse o procedimento em um único post… 😀 Além do mais, um pouco de suspense não mata ninguém 🙂

Sério agora, provavelmente amanha mesmo já posto como configurar o dashboard com as entradas que temos até o momento. Um abraço a todos e fiquem a vontade para tirar dúvidas nos comentários.

 

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

dois × cinco =