Manual
do
Maker
.
com
Os rádios subgiga são incríveis - em particular, o LoRa (e mais intrinsecamente, o ESP32 LoRA) . A grande questão é que tudo tem contrapartida; quanto maior a banda, maior a velocidade de transmissão, mas menor alcance. Quanto menor a banda, menor velocidade de transmissão, mas maior alcance.
Um rádio LoRa rodando em 915MHz consegue transferir pouco mais de 37kbps. Não é pouco para mensagem, porém para arquivos binários é algo impactante. Mas ainda que venhamos a utilizar apenas mensagens, devemos ter determinados cuidados para evitar que sobrecarreguemos a banda de transmissão, não apenas do transmissor para o receptor, mas cuidando também para não sobrecarregar o receptor, ainda mais se ele for um concentrador de rádios.
Lhe parece bastante intuitivo uma mensagem como essa abaixo?
temp=32,umid=40,rele1=on,rele2=off,ad0=524
Parece um ótimo protocolo. Fazendo split em "," já temos os campos separados. Depois, só validar os campos e fazer split no sinal "=". Daí o segundo campo é o valor, a ser convertido para inteiro. Mas vamos às considerações;
de todos esses 43 Bytes, apenas 12 serão utilizados. E pior, poderiam ser apenas 8 (desconsiderando algo importante que falta nessa mensagem).
Usar mensagens nesse formato é péssimo para a transmissão e para o processamento. Se chegar uma mensagem de ruído de outro dispositivo que não pertença à sua rede LoRa, essa mensagem passará por processamento desnecessariamente.
Mais uma coisa importantíssima; esse formato é ótimo para leitura humana, mas quem vai "ver" a mensagem é uma microcontroladora, nada disso é necessário. Depois de recebido, se for necessário exibir para o usuário, então adiciona-se o respectivo texto, fora da transmissão do ESP32 LoRa.
Pode parecer exagero pensando 1 para 1, mas em indústria, agro-negócio, condomínios, muito provavelmente diversos dispositivos poderão estar se comunicando com um concentrador. E pode ser pior.
Imagine se toda a informação do seu dispositivo for enviada para um broker MQTT na nuvem, onde clientes do país inteiro concentram seus dados em um sistema de gerenciamento. Por isso, "menos é mais". Fui claro?
Vejamos uma mensagem em um formato mais adequado:
32 40 1 0 524
Os valores sempre serão posicionais, portanto não há razão para usar identificadores.
Parece bem pequena a mensagem, mas o ideal é mandar os bytes. Desse modo (como mostrado anteriormente), ainda consome-se mais recursos do que o necessário. Então o formato melhorado seria:
20 28 1 0 00 ff ff 0e
"Hummm, aumentou de tamanho!" - Você pode ter pensado. Se mandarmos em formato literal, cada caractere será 1 Byte, totalizando 13 Bytes. Mandando em Bytes, cada Byte é, bem; 1 Byte.
Não se incomode em ver o formato em hexa. Você não precisará calcular nada disso, o trabalho será todo do programa, como pode ser visto no código mais adiante.
Para finalizar, ainda será necessário garantir a origem da mensagem minimamente. Não podemos ler qualquer coisa que chegar e considerar verdadeira, por isso o ideal é colocar um identificador de início e um de fim de mensagem. Explico.
$ 32 40 1 0 524 \n
Voltando ao formato literal, podemos fazer interpretação humana, por isso o fiz na mensagem acima. Repare que ela inicia com "$". Isso é, se a mensagem que chegar não tiver esse primeiro Byte, descarta-se imediatamente.
Se a mensagem que chegar iniciar com "$", validamos o último Byte. Se a mensagem não terminar com "\n", descarta-se a mensagem. Mas antes de tudo, temos que ler o buffer de qualquer maneira, então a primeira validação deveria ser o tamanho da mensagem.
Agora sim, temos um protocolo definido! Vejamos: 0 - início da mensagem 1 - temperatura 2 - umidade 3 - relay 1 4 - relay 2 5, 6, 7 e 8 - leitura do AD, que vai de 0 a 1023, portanto 4 Bytes. 9 - terminador
Desse modo, nossa mensagem final seria parecido com:
24 20 28 1 0 00 ff ff 0e 0a
Agora podemos escrever nosso código.
As bibliotecas estão disponíveis no repositório do Arduino, portanto não há o que se falar a respeito da instalação. Já em relação à configuração, um pequeno ajuste deve ser feito para funcionar adequadamente o rádio LoRa. Siga esse tutorial, suba o sketch. Tendo funcionado, apenas substitua o código de teste pelo código a seguir:
#include <Arduino.h>
#include <SPI.h>
#include <LoRa.h>
#include <WiFi.h>
#include "SSD1306.h"
#include "board_def.h"
#define OLED_ADDRESS 0x3c
#define I2C_SDA 21
#define I2C_SCL 22
SSD1306Wire display(OLED_ADDRESS, I2C_SDA, I2C_SCL, GEOMETRY_128_32);
#define WIFI_SSID "SuhankoFamily"
#define WIFI_PASSWORD "fsjmr112"
String topics[5];
int adc_sum = 0;
struct msgRecv {
uint8_t start = '$';
uint8_t temperature = 0;
uint8_t humidity = 0;
uint8_t relay_1 = 0;
uint8_t relay_2 = 0;
int adc_value = 0;
uint8_t end = '\n';
} msg_recv;
uint8_t msg_array[10] = {0};
void setup()
{
topics[0] = "Temp: ";
topics[1] = "Umidade: ";
topics[2] = "Rele 1: ";
topics[3] = "Rele 2: ";
topics[4] = "AD: ";
Serial.begin(9600);
while (!Serial);
if (OLED_RST > 0) {
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, HIGH);
delay(100);
digitalWrite(OLED_RST, LOW);
delay(100);
digitalWrite(OLED_RST, HIGH);
}
display.init();
display.flipScreenVertically();
display.clear();
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(display.getWidth() / 2, display.getHeight() / 2, LORA_SENDER ? "LoRa Sender" : "LoRa Receiver");
display.display();
delay(2000);
String info = "(bB)";
if (info != "") {
display.clear();
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(display.getWidth() / 2, display.getHeight() / 2, info);
display.display();
delay(2000);
}
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
display.clear();
Serial.println("WiFi Connect Fail");
display.drawString(display.getWidth() / 2, display.getHeight() / 2, "WiFi Connect Fail");
display.display();
delay(2000);
esp_restart();
}
Serial.print("Connected : ");
Serial.println(WiFi.SSID());
Serial.print("IP:");
Serial.println(WiFi.localIP().toString());
display.clear();
display.drawString(display.getWidth() / 2, display.getHeight() / 2, "IP:" + WiFi.localIP().toString());
display.display();
delay(2000);
SPI.begin(CONFIG_CLK, CONFIG_MISO, CONFIG_MOSI, CONFIG_NSS);
LoRa.setPins(CONFIG_NSS, CONFIG_RST, CONFIG_DIO0);
if (!LoRa.begin(BAND)) {
Serial.println("Starting LoRa failed!");
while (1);
}
if (!LORA_SENDER) {
display.clear();
display.drawString(display.getWidth() / 2, display.getHeight() / 2, "LoraRecv Ready");
display.display();
}
}
void loop()
{
#if LORA_SENDER
int32_t rssi;
if (WiFi.status() == WL_CONNECTED) {
rssi = WiFi.RSSI();
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(display.getWidth() / 2, display.getHeight() / 2, "Send RSSI:" + String(rssi));
display.display();
LoRa.beginPacket();
LoRa.print("WiFi RSSI: ");
LoRa.print(rssi);
LoRa.endPacket();
} else {
Serial.println("WiFi Connect lost ...");
}
delay(2500);
#else
if (LoRa.parsePacket()){
memset(msg_array,0,10);
uint8_t counter = 0;
//enquanto tiver dados para ler, tem que ler.
while (LoRa.available()){
//armazena no buffer...
msg_array[counter] = (char)LoRa.read();
if (msg_array[0] == '$'){
//...mas só incrementa a posição se o primeiro Byte for $
counter++;
}
//Se a mensagem chegou ao Byte 9 sem o LF, então sai do loop, porque o buffer está limitado a 10 Bytes
if (counter > 9){
break; //mensagem alem do tamanho permitido
}
}
//Saiu do loop. A mensagem que está no buffer parece ser legítima?
if (msg_array[0] == msg_recv.start && msg_array[9] == msg_recv.end){
//Então compõe uma string para o usuário com o resultado de cada valor
for (uint8_t i=1;i<5;i++){
display.clear();
String msg = topics[i-1] + String(msg_array[i]);
display.drawString(display.getWidth() / 2, display.getHeight() / 2, msg.c_str());
display.display();
delay(800);
}
//E o valor AD tem 4 Bytes, portanto é necessário somá-los para entregar o valor correto ao usuário
adc_sum = msg_array[5] + msg_array[6] + msg_array[7] + msg_array[8];
Serial.println(adc_sum);
display.clear();
String msg2 = topics[4] + String(adc_sum);
display.drawString(display.getWidth() / 2, display.getHeight() / 2, msg2.c_str());
display.display();
delay(800);
}
}
#endif
}
Repare que no código adicionei comentários nos tratamentos feitos na função loop().
Esse lindíssimo ESP32 LoRa está disponível na UsinaInfo, e você pode conferir preço e disponibilidade através desse link. Não perca a oportunidade de ter um TTGO, você vai amar!
Para fazer os testes, utilizei o AFMultiRadio Black Edition da AFEletronica, desse outro artigo. Essa é outra placa indescritível, a qualidade é espetacular e é a primeira no mundo (pelo menos de todas as pesquisas que fiz) que possui 3 rádios LoRa 1276 e também a primeira do mundo que se comunica com os rádios diretamente pelo barramento SPI. Se quiser dar uma conferida na loja, clique nesse link.
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.