Os dados provenientes das portas analógicas A0, A1, A2 e A3 do Arduino (ATMega328P) serão enviados via serial para o ESP8266, que através do protocolo MQTT, os publicará no serviço IOT da Adafruit.
1) Criar conta no serviço IOT
Para poder publicar os dados na nuvem, será necessário criar uma conta e configurar conforme detalhado abaixo:1.1) crie uma conta no site iot.adafruit.com
1.2) crie 4 feeds com os seguintes nomes: A0, A1, A2 e A3
1.3) crie um dashboard chamado "mbz"
1.4) no dashboard mbz, crie 4 blocks do tipo gauge, com os seguintes titles: A0, A1, A2 e A3
1.5) configure os valores mínimos do gauge para 0 e o máximo para 255
1.6) instale na IDE do Arduino a biblioteca Adafruit MQTT Library
2) Limpar programa no ATMega328P
Para evitar erros de upload de programa para o ESP8266, é aconselhável limpar o programa no ATMega328P.2.1) Mude os jumpers perto do conector FDTI para a posição "atmega":
2.2) Selecione no menu "Ferramentas" a placa "Arduino/Genuino Uno":
2.3) Crie um "programa em branco", selecionando "Novo" no menu "Arquivo", compile e faça o upload para o ATMega328P:
3) Carregar o programa no ESP8266
O programa mbz_mqtt_esp8266.ino recebe os dados do Arduino e faz a publicação.3.1) Conecte uma fonte de alimentação externa
3.2) Selecione no menu "Ferramentas" a placa "Generic ESP8266 Module":
3.3) Mude os jumpers perto do conector FDTI para a posição "esp". Mude os jumpers perto do ESP8266 conforme a imagem abaixo:
3.4) Pressione o botão "ESP_reset"
3.5) Compile e faça o upload do programa abaixo para o ESP8266:
Programa mbz_mqtt_esp8266.ino
/******************************************************************* MBZ MQTT example (ESP8266) ----------------------------- Este programa recebe os dados das portas analógicas do ATMEGA328P e os envia para o serviço de IOT da Adafruit via protocolo MQTT ********************************************************************/ #include <ESP8266WiFi.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #define SSID "WIFI_SSID" // id do roteador WIFI #define PWD "WIFI_PASSWORD" // senha do roteador WIFI #define SERVER "io.adafruit.com" // servidor MQTT #define PORT 1883 // porta do servidor #define USR "AIO_USER" // usuário do IO Adafruit #define KEY "AIO_KEY" // chave de acesso do IO Adafruit WiFiClient client; Adafruit_MQTT_Client mqtt(&client, SERVER, PORT, USR, KEY); Adafruit_MQTT_Publish PIN_A0 = Adafruit_MQTT_Publish(&mqtt, USR "/feeds/A0"); Adafruit_MQTT_Publish PIN_A1 = Adafruit_MQTT_Publish(&mqtt, USR "/feeds/A1"); Adafruit_MQTT_Publish PIN_A2 = Adafruit_MQTT_Publish(&mqtt, USR "/feeds/A2"); Adafruit_MQTT_Publish PIN_A3 = Adafruit_MQTT_Publish(&mqtt, USR "/feeds/A3"); void setup() { Serial.begin(19200); // Conecta no WIFI Serial.println(); Serial.print("Conectando no WIFI: "); Serial.println(SSID); WiFi.begin(SSID, PWD); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi conectado"); Serial.print("IP: "); Serial.println(WiFi.localIP()); Serial.println(); } // variaveis dos sensores int val_A0 = 0; int val_A1 = 0; int val_A2 = 0; int val_A3 = 0; void loop() { // verifica se recebeu dados pela serial if (getSerialData()) { if (mqtt.connect() == 0) { // envia dados para o servidor MQTT PIN_A0.publish(val_A0); PIN_A1.publish(val_A1); PIN_A2.publish(val_A2); PIN_A3.publish(val_A3); } } delay(100); } bool getSerialData() { String serialData; bool ret = false; if (Serial.available()) { // lê porta serial serialData = Serial.readString(); // retorna 'ok' para sinalizar que recebeu os dados Serial.print("ok"); } if (!serialData.equals("")) { val_A0 = getValue(serialData, "A0"); val_A1 = getValue(serialData, "A1"); val_A2 = getValue(serialData, "A2"); val_A3 = getValue(serialData, "A3"); ret = true; } return ret; } int getValue(String str, String tk) { String buff = ""; int p0, p1; p0 = str.indexOf(tk); if (p0 != -1) { p0 = str.indexOf(":", p0) + 1; p1 = str.indexOf(";", p0); buff = str.substring(p0, p1); } return buff.toInt(); }
Lembre-se de mudar as variáveis SSID, PWD, USR e KEY para os valores correspondentes à sua configuração.
3.6) Mude os jumpers perto do ESP8266 conforme a imagem abaixo:
3.7) Pressione o botão "ESP_reset"
4) Carregar o programa no ATMega328P
O programa mbz_mqtt_atmega.ino lê os dados das portas analógicas A0, A1, A2 e A3 e os envia um uma mensagem ESP8266.4.1) Selecione no menu "Ferramentas" a placa "Generic ESP8266 Module":
4.2) Mude os jumpers perto do conector FDTI para a posição "atmega":
4.3) Compile e faça o upload do programa abaixo para o ATMega328P:
Programa mbz_mqtt_atmega.ino
/******************************************************************* MBZ MQTT example (ATMEGA328P) ----------------------------- Este programa lê dados das portas analógicas (A0, A1, A2 e A3) e envia para o módulo ESP8266. O ESP8266 recebe os dados e os envia o serviço de IOT da Adafruit via protocolo MQTT (Message Queuing Telemetry Transport ********************************************************************/ #include <SoftwareSerial.h> #define rxPin 2 #define txPin 3 SoftwareSerial EspSerial(rxPin, txPin); // RX, TX #define PIN_ENABLE_ESP8266 4 // variaveis dos sensores int val_A0 = 0; int val_A1 = 0; int val_A2 = 0; int val_A3 = 0; void setup() { // seta a velocidade das portas seriais Serial.begin(19200); EspSerial.begin(19200); // inicializa o ESP8266 Serial.println("Inicializando o ESP8266"); pinMode(PIN_ENABLE_ESP8266, OUTPUT); digitalWrite(PIN_ENABLE_ESP8266, LOW); delay(200); digitalWrite(PIN_ENABLE_ESP8266, HIGH); delay(200); // seta as portas A0, A2, A2 e A3 para leitura pinMode(A0, INPUT); pinMode(A1, INPUT); pinMode(A2, INPUT); pinMode(A3, INPUT); } void loop() { // lê os valores das portas analógicas updateSensors(); // envia os dados para o ESP8266 sendSensorsData(); // aguarda 5 segs para fazer a próxima transmissão, // pois a conta gratuita do Adafruit IO limita // a publicação de no máximo 60 posts por minuto delay(5000); } void updateSensors() { val_A0 = readSensor(A0); val_A1 = readSensor(A1); val_A2 = readSensor(A2); val_A3 = readSensor(A3); } int readSensor(int pinSensor) { int t = 0; int v = 0; int readings = 10; // faz 10 leituras e tira a média dos valores for (int i = 0; i < readings; i++) { t += analogRead(pinSensor); delay(5); } // limita os valores entre 0 e 255 v = map(t / readings, 0, 1023, 0, 255); return v; } void sendSensorsData() { int timeout = 2000; String strBuffer = ""; // envia os dados pela serial EspSerial.print("A0:"); EspSerial.print(val_A0); EspSerial.print(";"); EspSerial.print("A1:"); EspSerial.print(val_A1); EspSerial.print(";"); EspSerial.print("A2:"); EspSerial.print(val_A2); EspSerial.print(";"); EspSerial.print("A3:"); EspSerial.print(val_A3); EspSerial.print(";"); // espera por uma resposta do ESP8266 long int time = millis(); while ( (time + timeout) > millis()) { if (EspSerial.available() > 0) { strBuffer = EspSerial.readString(); break; } delay(1); } // verifica se o ESP8266 mandou uma mensagem 'ok' // indicando que recebeu os dados com sucesso if (strBuffer.equals("ok")) { Serial.println("Dados transmitidos com sucesso."); } else { Serial.println("Problemas na comunicação."); } }
5) Testar a comunicação
5.1) Selecione no menu "Ferramentas" a opção "Monitor Serial"5.2) Selecione a velocidade "19200"
5.3) Abra no seu browser o dashboard "mbz":
Agora você pode personalizar seu dashboard, configurando de acordo com as necessidades do seu projeto IOT.
Excelente post Marcelo Maximiano, sou do hardware mas muitas vezes tenho que programar e sofro bastante, essa tua publicação me salvou algumas coisas, modifiquei o código para utilizar em uma aplicação minha que comunica via serial, deu certo, mas eu gostaria de alimentar cada variável separadamente, porém com o teu código sempre que tento alimentar somente uma as outras zeram :/ , tem como resolver isso?
ResponderExcluirAbraço e obrigado pelo post. :D
Neste exemplo, o Arduino transmite simultaneamente os valores de 4 portas analógicas.
ExcluirE sendo assim, o ESP8266 espera receber esses valores em uma única transmissão.
Para passar valores individualmente, você deve alterar do lado do Arduino, o método sendSensorData(), para receber como parâmetro o nome da variável (A0,A1,A2,A3) e o seu respectivo valor, e depois enviar somente esses dados:
Exemplo:
void sendSensorData(String nomeVar, String valorVar)
{
int timeout = 2000;
String strBuffer = "";
// envia os dados pela serial
EspSerial.print(nomeVar + ":"); EspSerial.print(valorVar); EspSerial.print(";");
// espera por uma resposta do ESP8266
long int time = millis();
...
E no lado do ESP8266, você deve alterar a função getSerialData() para procurar na string serialData pelo nome de cada variável que pode ser recebida (A0,A1,A2,A3), ler o valor dela e executar o publish só do que foi recebido.
Obrigado pelo feedback!
Obrigado pelo retorno Marcelo, minha falta de habilidade em programação me faz ter um trabalhão rsrsrs, fico só remendando códigos, estou usando assim no arduino para ele receber dados e envio os dados via pc(futuro tablet) para o arduino:
ResponderExcluirvoid setup() {
Serial.begin(57600);
}
void loop() {
// variaveis dos sensores
// verifica se recebeu dados pela serial
if (getSerialData()) {
if (val_A0 != 0){
b0 = val_A0;}
if (val_A1 != 0){
b1 = val_A1;}
if (val_A2 != 0){
b2 = val_A2;}
if (val_A3 != 0){
b3 = val_A3;}
if (val_A4 != 0){
b4 = val_A4;}
if (val_A5 != 0){
b5 = val_A5;}
if (val_A6 != 0){
b6 = val_A6;}
if (val_A7 != 0){
b7 = val_A7;}
Serial.println("===========");
Serial.println(b0);
Serial.println(b1);
Serial.println(b2);
Serial.println(b3);
Serial.println(b4);
Serial.println(b5);
Serial.println(b6);
Serial.println(b7);
Serial.println("===========");
}
delay(10);
}
bool getSerialData() {
String serialData;
bool ret = false;
if (Serial.available()) {
// lê porta serial
serialData = Serial.readString();
// retorna 'ok' para sinalizar que recebeu os dados
Serial.println("ok");
}
if (!serialData.equals("")) {
val_A0 = getValue(serialData, "A0:");
val_A1 = getValue(serialData, "A1:");
val_A2 = getValue(serialData, "A2:");
val_A3 = getValue(serialData, "A3:");
val_A4 = getValue(serialData, "A4:");
val_A5 = getValue(serialData, "A5:");
val_A6 = getValue(serialData, "A6:");
val_A7 = getValue(serialData, "A7:");
ret = true;
}
return ret;
}
int getValue(String str, String tk) {
String buff = "";
int p0, p1;
p0 = str.indexOf(tk);
if (p0 != -1) {
p0 = str.indexOf(":", p0) + 1;
p1 = str.indexOf(";", p0);
buff = str.substring(p0, p1);
}
return buff.toInt();
}
A ideia é controlar um equipamento conectado ao arduino via tablet, o software do arduino está pronto e só quero alimentar suas variáveis e verificar alguns parâmetros. Teu exemplo foi o único que encontrei que lê mais de um valor pela serial, conforme acima consegui o problema de alimentar separadas, agora não sei porque se desconecto a serial e conecto denovo os valores zeram :/... Mas não vou desistir não :D
Olá,
ResponderExcluirMuito bom o seu passo a passo. Já tentou fazer o mesmo mas sem o Arduino? Digo utilizando o próprio ESP como microcontrolador?