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.
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.
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.
- Arduino UNO (Microcontrolador) – $10.00
- ESP8266-01 (Módulo de comunicação) – $3.50
- DHT22 (Sensor digital para temperaura e umidade relativa do ar) – $9.00
- DS18B20 (Sensor Digital de temperatura para uso com o solo) – $6.00
- YL-69 + LM393 (Sensor analógico de umidade de solo) – $2.00
- LDR (Sensor analógico de luminosidade) – $0.20
- 2 x LEDs (vermelho e verde)
- 1 x 2 Channel DC 5V Relay Module with Optocoupler Low Level Trigger – $7.00
- 5V DC Pump – $3.00
- Lâmpada de 220V
- 2 resistores de 330 ohm (para serem utilizados com os LEDs)
- 2 resistores de 10K ohm (para serem utilizados com o DHT22 e o LDR)
- 1 resistor de 4K7 ohm (para ser utilizado com o DS18B20)
- Protoboard
- Jumpers
- 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:
- Instale e teste localmente todos os sensores
- Instale e configure o ESP-01 (“BareMinimum”)
- Altere a instalação do ESP-01 para sua configuração final e teste-o
- Configure o canal de Status no ThingSpeak
- Instale o código para conversar com o ThingSpeak em seu Arduino e verifique o status dos Sensores na nuvem
- Desenvolva a primeira versão do aplicativo Android para exibir Status e mensagens
- Instale os atuadores (LEDs e relés)
- Configure os canais dos atuadores no ThingSpeak
- Instale e teste o Código Arduino para trabalhar com os atuadores
- Desenvolva a versão final da aplicação de Android
- 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:
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”
- 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).
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:
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:
- Channel ID 375598 ==> LED Vermelho – Bomba (Pump)
- Field1 = 0 ==> Pump OFF
- Field1 = 1 ==> Pump ON
- 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:
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
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:
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:
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
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.
CurtirCurtir
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?
CurtirCurtir
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.
CurtirCurtir
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?
CurtirCurtir
Boa noite Marcelo,
É possível mandar escrever no canal do thingspeak através do App Inventor?
CurtirCurtir
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
CurtirCurtir
Oí Gabriel. Boa noite. Não entendi sua pergunta. Os dados enviados ao TS serão ligas. Se são binários, serão apresentados como binários (0 ou 1). Se são inteiros aparecerão 125, 2529, etc. Se enviar float, aparecerão 12.5 etc…..
CurtirCurtir
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.
CurtirCurtir
Tenho varios. Quase todos os projetos conectam dados do ESP com a nuvem (em geral Thingspeak). Tenho também alguns que leem o Thingspeak e se conectam com o App-Inventor.
CurtirCurtido por 1 pessoa
Da uma olhada nos projetos. Comece com os que têm o ESP-8266 ou o 32.
CurtirCurtir
Marcelo, boa tarde. Ja fez o mesmo so que usando a Amazon IOT?
CurtirCurtir
Oí Gabriel. Nao conheço.
CurtirCurtir
o melhor
CurtirCurtir
Obrigado! 😉
CurtirCurtir
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
CurtirCurtir
Melhor artigo sobre o tema! parabens.
CurtirCurtir
Muito obrigado! 😉
CurtirCurtir
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.
CurtirCurtir
anda luar biasa, proyek dan pembelajaran yang menakjubkan bagi saya
CurtirCurtir
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?
CurtirCurtir
Grande Marcelo, excelente publicação..👏🏻👏🏻👏🏻 Forte abraço amigo
CurtirCurtido por 1 pessoa
Valeu! Muito obrigado! 😉
CurtirCurtir