“IoT feito fácil”: Conectando coisas desde qualquer canto do mundo!

21 21-03:00 dezembro 21-03:00 2017 — 22 Comentários

Nosso objetivo neste tutorial será basicamente coletar informações de uma unidade local, enviando-as à internet. Um usuário em qualquer parte do planeta, olhando estas informações, tomará decisões enviando comandos remotos à atuadores, os quais também estarão nesta unidade local. Qualquer sensor ou atuador poderia ser utilizado.

IoT

Este tutorial foi escrito a partir do que desenvolvi previamente envolvendo o ArduFarmBot e de meu projeto final apresentado para o curso: “Objetos inteligentes conectados”, promovido pelo CodeIOT, um projeto da Samsung em parceria com o Laboratório de Sistemas Integráveis Tecnológico.

A maioria de meu trabalho no campo do IoT utiliza o NodeMCU (ESP826612-E) e mais recentemente, o ESP32. Mas, acredito importante não esquecer de meus primeiros passos, onde começei a aprender IoT, usando-se de um simples Arduino UNO e do velho e bom ESP8266-01.

Decidi então, retornar a essa dupla, agora com um pouquinho mais de experiência e explorar novamente esses ótimos dispositivos, conectando-os à nuvem, usando-se do  ThingSpeak.com como nosso “Web Service”.

Também exploraremos como controlar coisas remotamente desde qualquer lugar no mundo, utilizando-se de um aplicativo Android desenvolvido a partir do MIT AppInventor.

Project Concept

O “Centro do nosso projeto IoT” será o ThingSpeak.com. A unidade local (UNO / ESP-01) será a encarregada de capturar tanto os dados dos sensores quanto o status dos atuadores, enviando-os à Internet, ou seja, “escrevendo” em um canal específico do para o status da unidade local no ThingSpeak.com. A unidade local também receberá dados da internet, “lendo” canais específicos para os atuadores no ThingSpeak.com.

Um aplicativo Android também estará “lendo” esses dados de status guardados no ThingSpeak.com (Status Channel), exibindo-os para o usuário. Da mesma forma, o usuário, com base nesta informação de status, poderá enviar comandos para os atuadores, escrevendo commandos nos canais específicos para os atuadores no ThingSpeak.com (veja o diagrama de blocos acima para entender melhor o fluxo de dados).

O diagrama de blocos mostrado na próxima etapa nos dará uma visão geral do projeto final, onde como exemplo controlaremos a irrigação e o calor de uma plantação.

1: Introdução

Utilizando-se de sensores comuns, nosso projeto irá capturar vários dados, enviando-os para a nuvem, onde todos poderão vê-los através da internet. Para trabalhar esses dados, usaremos o serviço fornecido pela ThingSpeak.com, uma plataforma IoT aberta que nos permitirá coletar, analisar e atuar sobre esses dados.

Os dados a serem coletados pelos sensores serão:

  • Temperatura e umidade relativa do ar
  • Temperatura e umidade do solo
  • Luminosidade

O projeto terá 2 atuadores:

  • Bomba elétrica
  • Lâmpada elétrica

Os status desses atuadores (“ON” ou “OFF”), também deverão ser enviados para a nuvem.

A idéia será capturar esses dados dos sensores, por exemplo, uma plantação e enviá-los para a nuvem. Com base nesses dados, um usuário deverá tomar decisões com base nestes dados:

  • Liguar a bomba de água se a umidade do solo estiver muito baixa
  • Liguar a lâmpada elétrica (“calor”) se a temperatura do solo estiver muito baixa

Para controlar remotamente nossos atuadores, usaremos uma aplicação Android.

2: BoM – Lista de materiais

Os componentes mais importantes listados aqui, possuem um link e um preço indicativo em USD associado a eles. Esses links são apenas para referência.

  1. Arduino UNO (Microcontrolador) – $10.00
  2. ESP8266-01 (Módulo de comunicação) – $3.50
  3. DHT22 (Sensor digital para temperaura e umidade relativa do ar) – $9.00
  4. DS18B20 (Sensor Digital de temperatura para uso com o solo) – $6.00
  5. YL-69 + LM393 (Sensor analógico de umidade de solo) – $2.00
  6. LDR (Sensor analógico de luminosidade) – $0.20
  7. 2 x LEDs (vermelho e verde)
  8. 1 x 2 Channel DC 5V Relay Module with Optocoupler Low Level Trigger – $7.00
  9. 5V DC Pump – $3.00
  10. Lâmpada de 220V
  11. 2 resistores de 330 ohm (para serem utilizados com os LEDs)
  12. 2 resistores de 10K ohm (para serem utilizados com o DHT22 e o LDR)
  13. 1 resistor de 4K7 ohm (para ser utilizado com o DS18B20)
  14. Protoboard
  15. Jumpers
  16. Fonte externa de 5V DC para alimentação dos Relés

3: O Hardware

Montemos o HW do projeto. O ideal é instalar e testar nosso projeto por partes. Como uma sugestão, podemos seguir as etapas:

  1. Instale e teste localmente todos os sensores
  2. Instale e configure o ESP-01 (“BareMinimum”)
  3. Altere a instalação do ESP-01 para sua configuração final e teste-o
  4. Configure o canal de Status no ThingSpeak
  5. Instale o código para conversar com o ThingSpeak em seu Arduino e verifique o status dos Sensores na nuvem
  6. Desenvolva a primeira versão do aplicativo Android para exibir Status e mensagens
  7. Instale os atuadores (LEDs e relés)
  8. Configure os canais dos atuadores no ThingSpeak
  9. Instale e teste o Código Arduino para trabalhar com os atuadores
  10. Desenvolva a versão final da aplicação de Android
  11. Teste todo o projeto

4: Conectando os sensores

Para ler os sensores corretamente, deveremos possuir algumas bibliotecas instaladas no IDE do Arduino. Verifique se você possui todas as bibliotecas instaladas. Sua configuração inicial deve ser:

// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5 // DS18B20 on pin D5 
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
int soilTemp = 0;

//DHT
#include "DHT.h"
#include <stdlib.h>
int pinoDHT = 11;
int tipoDHT =  DHT22;
DHT dht(pinoDHT, tipoDHT); 
int airTemp = 0;
int airHum = 0;

// LDR (Light)
#define ldrPIN 1
int light = 0;

// Soil humidity
#define soilHumPIN 0
int soilHum = 0;

Para o setup() e loop():

void setup()
{
  Serial.begin(9600); 
  DS18B20.begin();
  dht.begin();
}

void loop()
{
  readSensors();
  displaySensors();
  delay (10000);
}

E finalmente, escreveremos duas funções específicas, uma para ler nossos sensores e outra para exibir seus valores no Serial Monitor:

/********* Read Sensors value *************/
void readSensors(void)
{
  airTemp = dht.readTemperature();
  airHum = dht.readHumidity();

  DS18B20.requestTemperatures(); 
  soilTemp = DS18B20.getTempCByIndex(0); // Sensor 0 will capture Soil Temp in Celcius
  
  soilHum = map(analogRead(soilHumPIN), 1023, 0, 0, 100);             
 
  light = map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0  ==> light 100%  

}

/********* Display Sensors value *************/
void displaySensors(void)
{
  Serial.print ("airTemp  (oC): ");
  Serial.println (airTemp);
  Serial.print ("airHum    (%): ");
  Serial.println (airHum);
  Serial.print ("soilTemp (oC): ");
  Serial.println (soilTemp);
  Serial.print ("soilHum   (%): ");
  Serial.println (soilHum);
  Serial.print ("light     (%): ");
  Serial.println (light);
  Serial.println ("");
}

O printScreen do Serial Monitor nos mostra os valores dos sensores:

O código completo poderá ser baixado de meu GITHUB:

Sensors_Test.ino

5: ESP8266-01  – Configuração inicial

O ESP-01 será utilizado como “Serial Bridge”, o que significa que vamos programá-lo usando” AT commands“.

A primeira coisa é ter certeza de que seu ESP-01 está programado com velocidade de comunicação (Baud Rate) correta. No nosso caso: 9.600 bauds. Normalmente, o ESP-01 vem programado da fábrica com 115.200 baud e devemos mudá-lo para 9.600 baud.

Primeiramente, você deverá conectar o ESP-01 como mostrado acima.

Observe que o pino Tx do ESP-01 está conectado ao pino Tx do UNO, o mesmo para os pinos Rx. Isso será alterado mais tarde.

Em seguida, conecte o Arduino ao seu computador, abra o IDE e carregue o exemplo que está em Arquivo> Exemplos> 01.Basics> BareMinimum. Este é um código vazio, utilizado para garantir que não haverá conflito de comunicação entre Arduino e o ESP-01.

Transferiremos este código para o Arduino antes de conectá-lo ao ESP-01,  para garantir que o Arduino não use a comunicação serial (Tx e Rx). Isso é importante para o ESP-01 poder comunicar-se adequadamente.

Abra o monitor serial do IDE e altere a velocidade para 115.200 baud. Comece a enviar um comando “AT” no seu Monitor IDE Serial. O ESP-01 deve retornar “OK”

Em seguida, mudemos sua velocidade. Para isso, você poderá utilizar o comando:

AT + CIOBAUD = 9600

Observe que o ESP-01 poderá eventualmente retornar à programação original de fábrica (não sei se isso é devido à versão FW). Pelo menos no meu caso, tive que usar um comando diferente para mudar o BaudRate definitivamente:

AT+ UART_DEF=<baudrate>,<databits>,<stopbits>,<parity>,<flow control>

Por exemplo, para configurar: 9600 baud / 8 data bits / 1 stop bits,  none parity e flow control:

AT + UART_DEF = 9600,8,1,0,0

Na caixa de seleção na parte inferior do seu Serial Monitor, altere a velocidade para “9600 baud”

Teste a comunicação: na parte superior da janela, digite “AT” e veja se a resposta que chega é “OK”. Agora, você deverá configurar o módulo no Modo Estação para atuar como Cliente de sua rede Wi-Fi. Para isto use o comando:

 AT + CWMODE = 1

Agora, deveremos conectar o módulo a rede Wi-Fi.

Para fazer isso, utilize o comando abaixo, substituindo “network_name” pelo nome da sua rede Wi-Fi e “password” com sua senha. Mantenha as aspas.

AT + CWJAP = "network_name", "password"

Se você ter como resposta o mesmo que abaixo, sua conexão deverá ter sido estabelecida corretamente:

WIFI CONNECTED WIFI GOT IP

Para encontrar o IP, execute o comando:

AT + CIFSR

Tome nota deste IP, voce poderá necessitar do mesmo posteriormente.

6: Testando o ESP-01

Uma vez que temos o ESP-01 configurado, devemos instalá-lo em seu circuito final. Para isso, devemos MUDAR a fiação feita anteriormente e conectar o ESP-01 ao nosso UNO como abaixo:

  • ESP-01 RX (Yellow) ao UNO Pino D7
  • ESP-01 TX (Orange) ao UNO Pino D6
  • ESP-01 Ch-Pd (Brown) ao Vcc (3.3V)
  • ESP-01 Reset (Blue) ao UNO Pino D8
  • ESP-01 Vcc (Red) ao 3.3V
  • ESP-01 GND (Black) ao UNO GND

Note que usaremos a biblioteca do Arduino “Software Serial”, tendo o pino D7 do UNO como Tx, conectado ao pino Rx do ESP-01 e o pino D6 doUNO como Rx, conectado ao pino Tx do ESP-01 .

Faremos um simples teste para verificar se o nosso ESP-01 esta corretamante instalado.

Digite o código abaixo:

#include <SoftwareSerial.h>   
SoftwareSerial esp8266(6,7);  //Rx ==> Pin 6; TX ==> Pin7 

#define speed8266 9600 

void setup() 
{
  esp8266.begin (speed8266); 
  Serial.begin(speed8266);
  Serial.println("ESP8266 Setup test - use AT coomands");
}

void loop() 
{
  while(esp8266.available())
  {
    Serial.write(esp8266.read());
  }
  while(Serial.available())
  {
    esp8266.write(Serial.read());
  }
}

Tente agora alguns comandos AT como estes abaixo:

*    AT     =====> ESP8266 returns OK
*    AT+RST =====> ESP8266 restart and returns OK
*    AT+GMR =====> ESP8266 returns AT Version; SDK version; id; OK
*    AT+CWMODE? => ESP8266 returns mode type
*    AT+CWLAP ===> ESP8266 returs close access points
*    AT+CIFSR ===> ESP8266 returs designided IP

e observe o resultado em seu IDE Serial monitor:

O código acima poderá ser baixado de meu GITHUB:
ESP_AT_Config.ino

Caso voce deseje se conectar a rede WiFi todas as vezes que um reset ocorrer (ou seu arduino seja desligado/ligado) e introduzindo suas credenciais, adicione uma chamada para a função connectWiFi() ao final da função setup():

setup()
{
  ... 
  connectWiFi(); 
}

A função connectWiFi() deverá estar ao final de seu código principal .ino:

/***************************************************
* Connect WiFi
****************************************************/
void connectWiFi(void)
{
  sendData("AT+RST\r\n", 2000, 0); // reset
  sendData("AT+CWJAP=\"YOUR USERNAME\",\"YOUR PASSWORD\"\r\n", 2000, 0); //Connect network
  delay(3000);
  sendData("AT+CWMODE=1\r\n", 1000, 0);
  sendData("AT+CIFSR\r\n", 1000, 0); // Show IP Adress
  Serial.println("8266 Connected");
}

voce deverá entrar com as credencias: “YOUR USERNAME\” and “YOUR PASSWORD\” diretamente na  função, substituindo os strings genéricos.

Observe que a função acima chama outra função sendData(data), a qual também deverá estar localizada em seu código:

/***************************************************
* Send AT commands to module
****************************************************/

String sendData(String command, const int timeout, boolean debug)
{
  String response = "";
  EspSerial.print(command);
  long int time = millis();
  while ( (time + timeout) > millis())
  {
    while (EspSerial.available())
    {
      // The esp has data so display its output to the serial window
      char c = EspSerial.read(); // read the next character.
      response += c;
    }
  }
  if (debug)
  {
    Serial.print(response);
  }
  return response;
}

Em meu GITHub ao final encontrará uma versão completa do projecto (v1.1), a qual contempla a conexão a rede WiFi com credenciais.

7: Conectando sensores e ESP-01 ao UNO

Depois de ter todos os sensores instalados e testados ademais de nosso ESP-01 funcionando corretamente, deixemos tudo junto e preparado para enviar dados para a internet.

8: O ThingSpeak

Uma das partes mais importantes do nosso projeto é o ThingSpeak, uma plataforma IoT aberta que nos permitirá coletar, analisar e atuar em dados capturados. Se você ainda não tem, por favor vá para ThingSpeak sign up e siga os passos para a criação de uma conta. É gratis.

Em seguida, crie um novo Canal onde coletaremos o status de nossos 2 atuadores, os dados provenientes dos 5 sensores e um campo sobressalente para uso futuro (ou debug):

  • Field 1: Actuator 1
  • Field 2: Actuator 2
  • Field 3: Air Temperature in oC
  • Filed 4: Air Relative Humidity in %
  • Field 5: Soil Temperature in oC
  • Field 6: Soil Humidity in %
  • Field 7: Luminosity in %
  • Field 8: Spare

O campo 8 será deixado como sobressalente para ser usado para expansão futura ou para fins de depuração. Por exemplo, vou usá-lo como um “contador” para cada erro de comunicação que ocorre durante o handshake entre o Arduino / ESP-01 com o ThingSpeak.com.

Depois de criar o seu canal (neste caso será o nosso “Canal de Status”), será importante tomar nota de seu ID e de suas chaves, conforme mostrado abaixo:

9: Enviando dados para a nuvem

Neste ponto, já temos nosso Cloud Service disponível e nossos sensores capturando dados localmente. Vamos tomar esses valores e enviá-los para o ThingSpeak.com.

Deveremos ESCREVER no canal do ThingSpeak e para isso, precisaremos enviar uma string do tipo “GET”. Faremos isto em 3 partes:

Enviaremos um “start cmd”, que apontará para a URL do ThingSpeak.com:

AT+CIPSTART="TCP","184.106.153.149",80

Seguido do comprimento em bytes “length” do comando a ser enviado:

AT+CIPSEND=116

E finalmente o “GET string”, o qual escreverá os dados nos campos correspondentes do canal:

GET /update?api_key=YOUR_WRITE_KEY_HERE&field1=pump&fieldlamp=0&field3=airTemp&field4=airHum&field5=soilTemp&field6=soilHum&field7=light&field8=spare

Observe que não devemos escrever no canal do ThingSpeak em intervalos inferiores a 16 segundos.

O código abaixo fará o trabalho para nós e o PrintScreen acima mostra o resultado final que aparece no IDE Serial Monitor:

// Thingspeak  
String statusChWriteKey = "YOUR WRITE KEY";  // Status Channel id: 385184

#include <SoftwareSerial.h>
SoftwareSerial EspSerial(6, 7); // Rx,  Tx
#define HARDWARE_RESET 8

// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5 // DS18B20 on pin D5 
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
int soilTemp = 0;

//DHT
#include "DHT.h"
#include <stdlib.h>
int pinoDHT = 11;
int tipoDHT =  DHT22;
DHT dht(pinoDHT, tipoDHT); 
int airTemp = 0;
int airHum = 0;

// LDR (Light)
#define ldrPIN 1
int light = 0;

// Soil humidity
#define soilHumPIN 0
int soilHum = 0;

// Variables to be used with timers
long writeTimingSeconds = 17; // ==> Define Sample time in seconds to send data
long startWriteTiming = 0;
long elapsedWriteTime = 0;

// Variables to be used with Actuators
boolean pump = 0; 
boolean lamp = 0; 

int spare = 0;
boolean error;

void setup()
{
  Serial.begin(9600);
  
  pinMode(HARDWARE_RESET,OUTPUT);
  
  digitalWrite(HARDWARE_RESET, HIGH);
  
  DS18B20.begin();
  dht.begin();

  EspSerial.begin(9600); // Comunicacao com Modulo WiFi
  EspHardwareReset(); //Reset do Modulo WiFi
  startWriteTiming = millis(); // starting the "program clock"
}

void loop()
{
  start: //label 
  error=0;
  
  elapsedWriteTime = millis()-startWriteTiming; 
  
  if (elapsedWriteTime > (writeTimingSeconds*1000)) 
  {
    readSensors();
    writeThingSpeak();
    startWriteTiming = millis();   
  }
  
  if (error==1) //Resend if transmission is not completed 
  {       
    Serial.println(" <<<< ERROR >>>>");
    delay (2000);  
    goto start; //go to label "start"
  }
}

/********* Read Sensors value *************/
void readSensors(void)
{
  airTemp = dht.readTemperature();
  airHum = dht.readHumidity();

  DS18B20.requestTemperatures(); 
  soilTemp = DS18B20.getTempCByIndex(0); // Sensor 0 will capture Soil Temp in Celcius
             
  light = map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0  ==> light 100%  
  soilHum = map(analogRead(soilHumPIN), 1023, 0, 0, 100); 

}

/********* Conexao com TCP com Thingspeak *******/
void writeThingSpeak(void)
{

  startThingSpeakCmd();

  // preparacao da string GET
  String getStr = "GET /update?api_key=";
  getStr += statusChWriteKey;
  getStr +="&field1=";
  getStr += String(pump);
  getStr +="&field2=";
  getStr += String(lamp);
  getStr +="&field3=";
  getStr += String(airTemp);
  getStr +="&field4=";
  getStr += String(airHum);
  getStr +="&field5=";
  getStr += String(soilTemp);
  getStr +="&field6=";
  getStr += String(soilHum);
  getStr +="&field7=";
  getStr += String(light);
  getStr +="&field8=";
  getStr += String(spare);
  getStr += "\r\n\r\n";

  sendThingSpeakGetCmd(getStr); 
}

/********* Reset ESP *************/
void EspHardwareReset(void)
{
  Serial.println("Reseting......."); 
  digitalWrite(HARDWARE_RESET, LOW); 
  delay(500);
  digitalWrite(HARDWARE_RESET, HIGH);
  delay(8000);//Tempo necessário para começar a ler 
  Serial.println("RESET"); 
}

/********* Start communication with ThingSpeak*************/
void startThingSpeakCmd(void)
{
  EspSerial.flush();//limpa o buffer antes de começar a gravar
  
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += "184.106.153.149"; // Endereco IP de api.thingspeak.com
  cmd += "\",80";
  EspSerial.println(cmd);
  Serial.print("enviado ==> Start cmd: ");
  Serial.println(cmd);

  if(EspSerial.find("Error"))
  {
    Serial.println("AT+CIPSTART error");
    return;
  }
}

/********* send a GET cmd to ThingSpeak *************/
String sendThingSpeakGetCmd(String getStr)
{
  String cmd = "AT+CIPSEND=";
  cmd += String(getStr.length());
  EspSerial.println(cmd);
  Serial.print("enviado ==> lenght cmd: ");
  Serial.println(cmd);

  if(EspSerial.find((char *)">"))
  {
    EspSerial.print(getStr);
    Serial.print("enviado ==> getStr: ");
    Serial.println(getStr);
    delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando

    String messageBody = "";
    while (EspSerial.available()) 
    {
      String line = EspSerial.readStringUntil('\n');
      if (line.length() == 1) 
      { //actual content starts after empty line (that has length 1)
        messageBody = EspSerial.readStringUntil('\n');
      }
    }
    Serial.print("MessageBody received: ");
    Serial.println(messageBody);
    return messageBody;
  }
  else
  {
    EspSerial.println("AT+CIPCLOSE");     // alert user
    Serial.println("ESP8266 CIPSEND ERROR: RESENDING"); //Resend...
    spare = spare + 1;
    error=1;
    return "error";
  } 
}

O código acima poderá ser baixado de meu GITHUB: SendingStatusTS_EXT.ino

10: O App Android (1a. parte) – Monitorando o status

Vamos criar nossa primeira parte da aplicação de Android.

Primeiro, criaremos a interface do usuário. Abaixo vemos os principais elementos visíveis e não visíveis:

Em seguida, programemos os blocos:

  • As variáveis ​​de status devem ser declaradas como globais (#1).
  • A cada 2 segundos, definido pelo Clock1 (#2), chamaremos um procedimento chamado: “readArduino”.
    • O retorno de tal procedimento será o valor para cada uma das variáveis ​​Status que devem ser exibidas na tela.
    • Note que “converteremos” os valores “0” e “1” do status dos atuadores para “OFF” e “ON” para uma melhor compreensão.
    • Esses valores (“Status”) serão exibidos no correspondente “rótulos”

AppDev_2

  • O procedimento “readArduino”, na verdade, lerá o Status Channel no ThingSpeak. Então, devemos definir o URL a ser enviado para o Thingspeak.
  • Para isso, 3 variáveis ​​globais devem ser declaradas e juntas para criar o URL a ser enviado ao TS (#3) . Um GET deve ser enviado para o componente Web chamado “ArduFarmBotStatusCh”
  • O texto obtido pela função anterior, chegará no formato JSon (#4). Este texto deverá então ser processado (cada campo lido e armazenado na variável global correspondente).

AppDev_3

Em seguida, lidaremos com as mensagens de alarme:

  • O procedimento “Alarm” (#5), analisará o status dos dois sensores relativos ao solo. Se a temperatura for muito baixa (no caso 10oC), uma mensagem deverá ser exibida. O mesmo para a umidade, se for inferior a 60%.
  • Observe que definimos outro temporizador (Clock2), programado para ser disparado cada 1 segundo. Isto é apenas para “alternar” a cor do texto da mensagem (do branco ao vermelho). Isso fará com que a mensagem “pisque”.

A foto abaixo mostra o App funcionando:

O codigo no formato .aia poderá ser baixado desde meu  GITHUB:

ArduFarmBot_Status_App_EXT.aia

11: Instalando os atuadores (LEDs e Relés)

Vamos completar o nosso HW.

Para isso, devemos instalar os Atuadores. Como você se lembra, receberemos comandos remotamente para ligar e desligar uma bomba e uma lâmpada. A saída do Arduino ativará um Relé (e um LED) para obter essas ações.

Utilizaremos um módulo de relé que tenha acionamento por “nível baixo” (ou seja “0”) e isolamento óptico. Além disso, forneceremos os 5V de alimentação para este relé através de uma fonte separada do Arduino e portanto não precisaremos fornecer a corrente necessária para atuação do relé em seu pino de entrada. O módulo do relé fará isso para nós.

A figura acima mostra como os atuadores devem estar conectados. Observe que o pino GND do relé NÃO ESTÁ CONECTADO ao GND do Arduino. Isso ajudará a que o UNO não receba ruídos quando o relé funcionar.

Por simplicidade, omiti do diagrama os sensores. Mas você poderá adicionar os circuitos dos atuadores ao seu projeto sem remover o dos sensores,  os quais você já instalou e testou.

12: Configurando os canais de atuadores no ThingSpeak

Da mesma forma que fizemos para o Status, criaremos agora 2 novos canais, um para cada atuador.

De cada canal, tome nota  de seu ID e chaves de leitura e escrita.

Escreveremos apenas no Campo 1 de cada um desses canais. Em meu caso, por exemplo:

  1. Channel ID 375598 ==> LED Vermelho – Bomba (Pump)
    • Field1 = 0 ==> Pump OFF
    • Field1 = 1 ==> Pump ON
  2. Channel ID 375599 ==> LED verde – Lâmpada (Lamp)
    • Field1 = 0 ==> Lamp OFF
    • Field1 = 1 ==> Lamp ON

13: Introduzindo os atuadores no código do Arduino

Quando enviamos dados para a Web, o que fizemos foi ESCREVER em um canal ThingSpeak (canal de Status ). O Arduino/ESP-01 deve “transmitir” (upload) estes dados. Agora, devemos LER de um canal ThingSpeak (Canal Atuador). O Arduino deverá “receber” (download) estes dados.

LEREMOS de um canal ThingSpeak e para isso, precisaremos enviar uma “string do tipo GET”. Faremos isto em 3 partes:

Enviaremos um “start cmd”, que apontará para a URL do ThingSpeak.com:

AT+CIPSTART="TCP","184.106.153.149",80

Seguido do comprimento em bytes “length” do comando a ser enviado:

AT+CIPSEND=36

E finalmente o “GET string”, o qual lerá o último valor armazenado no campo 1 correspondente a cada canal do atuador:

GET /channels/375598/fields/1/last

Nós estaremos lendo dos canais do ThingSpeak em intervalos de 10 segundos

Depois de enviar o comando GET acima, o qual estará solicitando o “ÚLTIMO VALOR ARMAZENADO NO CAMPO 1”, receberemos uma resposta do ThingSpeak que deve ser “1” ou “0” em uma posição específica da resposta. Se algo diferente disso chegar, devemos ignorá-lo.

A principal diferença entre esta parte do código e a anterior (para enviar os dados de status) é a função:

readThingSpeak(String channelID)

O código abaixo fará o trabalho para nós e o PrintScreen acima mostra o resultado final que aparece no IDE Serial Monitor:

// Thingspeak  
String canalID1 = "999999"; //Actuator1
String canalID2 = "999999"; //Actuator2

#include <SoftwareSerial.h>
SoftwareSerial EspSerial(6, 7); // Rx,  Tx
#define HARDWARE_RESET 8

// Variables to be used with timers
long readTimingSeconds = 10; // ==> Define Sample time in seconds to receive data
long startReadTiming = 0;
long elapsedReadTime = 0;

//Relays
#define ACTUATOR1 10 // RED LED   ==> Pump
#define ACTUATOR2 12 // GREEN LED ==> Lamp
boolean pump = 0; 
boolean lamp = 0; 

int spare = 0;
boolean error;

void setup()
{
  Serial.begin(9600);
  
  pinMode(ACTUATOR1,OUTPUT);
  pinMode(ACTUATOR2,OUTPUT);
  pinMode(HARDWARE_RESET,OUTPUT);

  digitalWrite(ACTUATOR1, HIGH); //o módulo relé é ativo em LOW
  digitalWrite(ACTUATOR2, HIGH); //o módulo relé é ativo em LOW
  digitalWrite(HARDWARE_RESET, HIGH);

  EspSerial.begin(9600); // Comunicacao com Modulo WiFi
  EspHardwareReset(); //Reset do Modulo WiFi
  startReadTiming = millis(); // starting the "program clock"
}

void loop()
{
  start: //label 
  error=0;
  
  elapsedReadTime = millis()-startReadTiming; 

  if (elapsedReadTime > (readTimingSeconds*1000)) 
  {
    int command = readThingSpeak(canalID1); 
    if (command != 9) pump = command; 
    delay (5000);
    command = readThingSpeak(canalID2); 
    if (command != 9) lamp = command; 
    takeActions();
    startReadTiming = millis();   
  }
  
  if (error==1) //Resend if transmission is not completed 
  {       
    Serial.println(" <<<< ERROR >>>>");
    delay (2000);  
    goto start; //go to label "start"
  }
}

/********* Take actions based on ThingSpeak Commands *************/
void takeActions(void)
{
  Serial.print("Pump: ");
  Serial.println(pump);
  Serial.print("Lamp: ");
  Serial.println(lamp);
  if (pump == 1) digitalWrite(ACTUATOR1, LOW);
  else digitalWrite(ACTUATOR1, HIGH);
  if (lamp == 1) digitalWrite(ACTUATOR2, LOW);
  else digitalWrite(ACTUATOR2, HIGH);
}

/********* Read Actuators command from ThingSpeak *************/
int readThingSpeak(String channelID)
{
  startThingSpeakCmd();
  int command;
  // preparacao da string GET
  String getStr = "GET /channels/";
  getStr += channelID;
  getStr +="/fields/1/last";
  getStr += "\r\n";

  String messageDown = sendThingSpeakGetCmd(getStr);
  if (messageDown[5] == 49)
  {
    command = messageDown[7]-48; 
    Serial.print("Command received: ");
    Serial.println(command);
  }
  else command = 9;
  return command;
}

/********* Reset ESP *************/
void EspHardwareReset(void)
{
  Serial.println("Reseting......."); 
  digitalWrite(HARDWARE_RESET, LOW); 
  delay(500);
  digitalWrite(HARDWARE_RESET, HIGH);
  delay(8000);//Tempo necessário para começar a ler 
  Serial.println("RESET"); 
}

/********* Start communication with ThingSpeak*************/
void startThingSpeakCmd(void)
{
  EspSerial.flush();//limpa o buffer antes de começar a gravar
  
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += "184.106.153.149"; // Endereco IP de api.thingspeak.com
  cmd += "\",80";
  EspSerial.println(cmd);
  Serial.print("enviado ==> Start cmd: ");
  Serial.println(cmd);

  if(EspSerial.find("Error"))
  {
    Serial.println("AT+CIPSTART error");
    return;
  }
}

/********* send a GET cmd to ThingSpeak *************/
String sendThingSpeakGetCmd(String getStr)
{
  String cmd = "AT+CIPSEND=";
  cmd += String(getStr.length());
  EspSerial.println(cmd);
  Serial.print("enviado ==> lenght cmd: ");
  Serial.println(cmd);

  if(EspSerial.find((char *)">"))
  {
    EspSerial.print(getStr);
    Serial.print("enviado ==> getStr: ");
    Serial.println(getStr);
    delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando

    String messageBody = "";
    while (EspSerial.available()) 
    {
      String line = EspSerial.readStringUntil('\n');
      if (line.length() == 1) 
      { //actual content starts after empty line (that has length 1)
        messageBody = EspSerial.readStringUntil('\n');
      }
    }
    Serial.print("MessageBody received: ");
    Serial.println(messageBody);
    return messageBody;
  }
  else
  {
    EspSerial.println("AT+CIPCLOSE");     // alert user
    Serial.println("ESP8266 CIPSEND ERROR: RESENDING"); //Resend...
    spare = spare + 1;
    error=1;
    return "error";
  } 
}

O código completo apara a leitura dos comandos poderá ser baixado de meu GITHUB:

ReadingCommandTS_EXT.ino

14: Enviando comandos aos atuadores

Neste ponto, temos os canais atuadores configurados no ThingSpeak e alterando o valor do Campo 1 em cada canal, deveremos ver os atuadores mudarem de acordo.

Em nosso projeto final, faremos essa tarefa utilizando-se do aplicativo Android, mas para efeito de testes, poderemos fazer isso utilizando-se de um navegador.

Os comandos são:

Turn ON Pump (RED LED):

https://api.thingspeak.com/update?api_key=ACT1_WRITE_KEY&field1=1

Turn OFF Pump (RED LED):

https://api.thingspeak.com/update?api_key=ACT1_WRITE_KEY&field1=0

Turn ON Lamp (GREEN LED):

https://api.thingspeak.com/update?api_key=ACT2_WRITE_KEY&field1=1

Turn OFF Lamp (GREEN LED):

https://api.thingspeak.com/update?api_key=ACT2_WRITE_KEY&field1=0

N parte superior da figura acima, você poderá observar o envio do comando para ligar a bomba em um navegador e na parte inferior da figura, como este comando aparecerá no IDE Serial Monitor. Obviamente, o LED Vermelho e o relé também serão ativados.

15: Completando o App Android

Completemos agora a APP. Anteriormente, desenvolvemos uma aplicação simples que obtém o status do ThingSpeak, LENDO o  “Status Channel”. Agora, deveremos ESCREVER nos canais do Atuador para que esses comandos possam ser lidos pelo Arduino e atuem em Bomba e Lâmpada de acordo.

Para que um usuário passe os comandos para o aplicativo, usaremos “botões”. Um par de botões (ON e OFF) para cada um dos atuadores.Quando um botão é pressionado, a cor do texto deverá mudar.

  • If ON ==> Azul
  • if OFF ==> Vermelho

Acima, você pode ver o conjunto de blocos para cada um dos pares de botões.

O App final pode ser visto abaixo:

AppFinal

Teste o aplicativo, enviando comandos para ligar e desligar os atuadores. Verifique no monitor serial de seu IDE, as mensagens trocadas entre ESP-01 e ThingSpeak (deverão ser semelhantes as que vimos anteriormente).

O codigo completo para o APP poderá ser baixado de meu GITHUB:

ArduFarmBot_V1_EXT.aia

16: Juntando tudo!


Perfeito! Neste ponto, você tem uma aplicação completa para ser utilizada em seu dispositivo Android, um HW completo, mas você ainda não possui um código que continuamente leia e escreva no ThingSpeak. Vamos combinar tudo o que desenvolvemos anteriormente.

No código final, você encontrará porções adicionais para verificar, por exemplo, se o ESP-01 não está congelando. Nós faremos isso, enviando um comando AT antes de que o ESP-01 execute uma função de ler ou escrever no ThinSpeak. Como vimos no início deste tutorial, o envio de um simples comando: “AT” ao ESP-01 deve receber como resposta um “OK”. Se isso não acontecer, procederemos com uma reinicialização de HW, comandada pelo SW, como fazemos durante a fase de setup().

O código final completo poderá ser baixado de meu GITHUB:
ArduFarmBot_Light_EXT.ino

Uma versão adicional (v1.1) foi adicionada a meu depositário, a qual inclui conexão rede WiFi local usando credenciais: versão 1.1

17: Conclusão

Há muito a ser explorado na arena IoT com estes fantásticos dispositivos, o Arduino Uno e o ESP8266-01 juntamente com o ThingSpeak e o MIT App Inventor. Voltaremos com novos tutoriais! Continue seguindo os tutoriais do MJRoBot!

Como sempre, espero que este projeto possa ajudar os outros a encontrar seu caminho no excitante mundo da eletrônica, da robótica e do IoT!

Visite meu GitHub para arquivos atualizados: ArduFarmBot_Light

Saludos desde el sur del mundo! 😉

Até meu próximo post!

Abração

Marcelo

22 Respostas para “IoT feito fácil”: Conectando coisas desde qualquer canto do mundo!

  1. 

    Olá Marcelo Rovai; excelente tutorial, muito detalhado e didático, porém me veio uma dúvida. Porque o senhor usou dois canais diferentes para os relés? Não poderia usar um canal só para os atuadores, já que temos 8 fields em cada canal?

    Encontrei seu blog por acaso e estou amando seus projetos.

    Curtir

  2. 

    Ola Marcos Rovai, Preciso adicionar um ESP01 ao meu projeto que já utiliza um RX, TX para gravar dados no cartão. Como adiciono outro RX, TX para o ESP, isso é possivel?

    Curtir

  3. 

    Olá Marcelo, Parabéns pelo excelente tutorial. Percebi que existe uma certa complexidade para fazer isso funcionar e mostrar os dados através de um canal e app. Minha dúvida é: da para fazer este projeto sem usar “5V DC Pump “? E como você fez os testes, colocou 5V DC Pump dentro de reservatório com água e inseriu o sensor de umidade no solo? Obrigado pela atenção.

    Curtir

  4. 
    Gustavo Motta Cardoso Silva 24 24-03:00 julho 24-03:00 2020 às 10:40

    Opa, parece que seu link do AppInventor está quebrado
    https://github.com/Mjrovai/ArduFarmBot_Light/blob/master/ArduFarmBot_Light/App%20Development/App%20Dev%20Part%201%20Sensors/ArduFarmBot_Status_App_EXT.aia
    Quando exportei para o appinventor deu erro, “could not upload”, tentei de tudo mas parece que há algo de errado
    Poderia me ajudar?

    Curtir

  5. 

    Boa noite Marcelo,

    É possível mandar escrever no canal do thingspeak através do App Inventor?

    Curtir

  6. 

    Marcelo, boa tarde. Como faço para ler uma informação do Thingspeak que seja maior que 0 ou 1? Por exemplo o número 2130

    Curtir

  7. 

    Olá Marcelo. Preciso enviar informações do monitor serial, que obtive da ide do arduino através da nodemcu esp32 – 8266, para uma nuvem e após para o app inventor.
    Tens algum tutorial que mostre isso? Ou como eu poderia faze-lo.

    Curtir

  8. 

    Marcelo, boa tarde. Ja fez o mesmo so que usando a Amazon IOT?

    Curtir

  9. 

    Olá Marcelo parabéns pelo texto!

    Será que você consegue me ajudar com o envio de dados de um SIM808 (dados GPS) para o https://api.cloudmqtt.com ?

    Estou tentando usar o comando CIPSEND mas não estou tendo resultado. Não sei como enviar as informações de autenticação (user and password) e a mensagem (payload). Pelo que vi no seu post você usa um único CIPSEND para enviar os dados … mas parece que não tem autenticação.

    Obrigado!

    Luciano

    Curtir

  10. 

    Melhor artigo sobre o tema! parabens.

    Curtir

  11. 

    Hola Rovai,
    Estoy haciendo un proyecto con App, y me estoy basando en la aplicacion que has hecho. Quiero controlar un motor con un rele, he cogido la parte que has hecho de control, pero cuando pulso el boton para accionar o parar el motor no me funciona, en Thingspeak si que me sale el cambio de 0 o 1 cuando pulso los botones, pero en arduino no me hace caso.
    Te agradeceria que me ayudarad en esta parte.
    Un saludo.

    Curtir

  12. 

    anda luar biasa, proyek dan pembelajaran yang menakjubkan bagi saya

    Curtir

  13. 

    Bom dia, Marcelo!
    Teus tutoriais tem me ajudado bastante e acredito que a outras pessoas também, Parabéns!
    Mas me diga, é possível integrar o Blynk a este projeto ao invés do aplicativo feito no App invertor?

    Curtir

  14. 

    Grande Marcelo, excelente publicação..👏🏻👏🏻👏🏻 Forte abraço amigo

    Curtido por 1 pessoa

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s