Neste artigo vou mostrar como enviar dados usando LoRaWAN com o Thinknode G1 Gateway. LoRa (Long Range) é um método sem fios para enviar pequenas quantidades de dados a distâncias muito maiores (vários quilómetros) do que as alcançadas pelo WiFi ou Bluetooth, por exemplo.
LoRaWAN é um protocolo de transmissão que usa LoRa. Permite construir sistemas IoT complexos com comunicação segura entre dispositivos e aplicações na cloud. Se quiser monitorizar sensores pela internet, LoRaWAN é o que precisa.
Os End Devices (sensores) enviam os seus dados para um Gateway, que os encaminha para um Network Server. Um Application Server pode então aceder ao Network Server para processar os dados, por exemplo, mostrar um gráfico com dados de temperatura.

Note que os Sensores transmitem dados para o Gateway via LoRa, enquanto o Gateway comunica com o Network Server via ligação Wi-Fi, Ethernet ou Celular. O Gateway é essencialmente uma ponte entre LoRa e a internet.
Nas secções seguintes vamos usar um ESP32 com um Módulo LoRa SX1276 para transmitir dados ambientais como temperatura e humidade medidos por um BME280 via LoRaWAN através de um Gateway Thinknode G1.
Vamos ligar este Gateway a um Network Server no The Things Network, onde poderá monitorizar os dados ambientais ou aceder a eles a partir de uma aplicação na internet para processamento adicional.
Vamos começar!
Peças Necessárias
Usei um ESP32 Lite como microprocessador para o nó LoRa, mas qualquer outro ESP32 também funciona bem. Se quiser usar um Arduino ou outro microprocessador, precisará de uma placa que funcione a 3.3V.
Quanto ao módulo transceptor LoRa SX1276, tenha atenção à versão que compra! Depending on the country as frequências permitidas são diferentes. É 868MHz na Europa, 915MHz na América do Norte e 433MHz na Ásia.
A descrição do módulo indica a frequência ou tem um número como 868 ou 915 no nome. Listei um módulo com 868MHz, pois estou na Europa. Mas pode obter este módulo também para a banda de 915MHz.
De forma semelhante, certifique-se de que o Gateway LoRaWAN que está a usar pode operar na banda de frequência necessária. O ThinkNode G1 Gateway listado abaixo suporta as frequências 868MHz e 915MHz.
Para o sensor ambiental, escolhi o BME280, que pode medir temperatura, humidade, pressão do ar e altitude. Certifique-se de comprar a versão 3.3V, pois vamos ligá-lo ao ESP32.

ThinkNode G1 LoRaWAN Gateway

Módulo LoRa 868/915M SX1276

ESP32 lite

Cabo de Dados USB

Sensor BME280

Conjunto de Fios Dupont

Breadboard
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
O que é LoRaWAN?
LoRaWAN significa Long Range Wide Area Network. É um protocolo sem fios desenhado especificamente para a Internet das Coisas (IoT), permitindo que dispositivos comuniquem a longas distâncias — estamos a falar de vários quilómetros, mesmo em áreas urbanas — usando muito pouca energia.
Ao contrário do WiFi ou Bluetooth, que são ótimos para comunicação de curto alcance e alta largura de banda, LoRaWAN foca-se no alcance e eficiência. Um sensor normalmente envia pequenos pacotes de dados a cada poucos minutos ou horas, mas pode funcionar com uma pequena bateria durante anos.
É ideal para dispositivos alimentados por bateria que enviam pouca informação, como sensores de temperatura, rastreadores GPS ou medidores de humidade do solo, em distâncias que Wi-Fi ou Bluetooth não alcançam. Por outro lado, não se pode enviar imagens ou vídeo via LoRa.
Suponha que tem um sensor de temperatura num local remoto. Não há WiFi, mas quer monitorizar a temperatura a cada 15 minutos. O que faz?
Liga um sensor de temperatura a um ESP32 conectado a um módulo LoRa (como o SX1276). Ele envia os dados sem fios via LoRa para um gateway LoRaWAN, no nosso caso um Thinknode G1. Este gateway pode ouvir sinais de múltiplos sensores a quilómetros de distância e encaminha os seus dados para o servidor de rede. O gateway é essencialmente uma ponte para a web.
Pode executar o seu próprio servidor de rede ou usar um público. Aqui vamos usar o The Things Network (TTN), uma infraestrutura LoRaWAN gratuita e open-source. A partir do TTN, os dados podem ser visualizados num dashboard, enviados para um serviço cloud, ou usados para disparar outras ações — como enviar alertas ou ligar um ventilador. E como o Network Server corre na Cloud, os seus dados podem ser processados, visualizados ou usados de qualquer lugar do mundo.
Nas próximas secções configuramos o Gateway, ligamo-lo ao The Things Network e construímos o nó final LoRa com um ESP32 como microcontrolador, o SX1276 como transceptor LoRa e o BME280 como sensor ambiental.
O ThinkNode G1 Gateway
O ThinkNode G1 da Elecrow é um gateway LoRaWAN para interior, desenhado para ligar a vários servidores de rede. Este gateway suporta múltiplos métodos de ligação para configuração, como WiFi, Bluetooth e Ethernet. Suporta transmissão em 8 canais e utiliza tecnologia wireless LoRa para alcançar transmissão de dados a longa distância.

O gateway está equipado com um concentrador LoRa SX1302 e dois chips SX1250, oferecendo 10 caminhos paralelos programáveis de demodulação. Suporta bandas globais ISM, com frequência entre 815MHz e 960MHz.
Especificações Técnicas
A tabela seguinte da página do produto Elecrow lista os detalhes técnicos do Thinknode G1 Gateway:
| Processador | CPU/SoC | MT7628N(MIPS24KEc@580MHz CPU) |
| Memória do Sistema | 128 MB DDR2 | |
| Armazenamento | 32MB Nor Flash | |
| Software de Configuração | WEB | |
| Comunicação | ||
| Wi-Fi | Suporta padrões IEEE 802.11 b/g/n, antena incorporada | |
| Com Fios | Suporta padrões IEEE 802.3, IEEE 802.3u, RJ45 (10M / 100M) | |
| Compatível com Bluetooth | Bluetooth dual-mode compatível (BR/EDR+BLE) 5.0 BLE, antena cerâmica incorporada | |
| LoRaWAN | Chip Baseband | SX1302, usando módulo baseband LR1302 |
| Canais | 8 Canais | |
| Protocolo do Nó | Suporta Classe A/Classe B/Classe C | |
| Banda de Frequência | EU868/US915 | |
| Sensibilidade | -125dBm @125KHz/SF7-139dBm @125KHz/SF12 | |
| Potência de Transmissão | Máximo 26 dBm | |
| Antena | 1. Antena de borracha (matching), ganho 3dBi, impedância 50 ohm; 2. Antena externa com base (opcional), ganho 3dBi, impedância 50 ohm; | |
| Interface Reservada | Tomada DC | Entrada de energia, DC 12V – 2A |
| Ethernet | RJ45 (10M / 100 M) | |
| Tomada Antena LoRa | Tomada fêmea RP-SMA | |
| Tomada Antena GPS | Tomada fêmea RP-SMA | |
| Interface Type-C | Usada para controlo de fundo, ligação ao painel de configuração ou gravação de firmware, depuração | |
| Slot para Cartão Micro SD | SIM | |
| Slot para Cartão Nano SIM | SIM | |
| Luz Indicadora Reservada | Luz de estado do dispositivo | SIM |
| 4G | SIM (Necessita personalização) | |
| WLAN | SIM | |
| LoRa | SIM | |
| PWR | SIM | |
| Botão | Botão Reset | |
| Dimensões | 140*140*38mm | |
| Material da Caixa | ABS+PC (Caixa), PC fosco (guia de luz) | |
| Entrada de Energia | 12V-2A | |
| Temperatura de Operação | -20℃~55℃ | |
| Temperatura de Armazenamento | -30℃~70℃ | |
Para mais informações veja o ThinkNode G1 Datasheet.
Luzes Indicadoras
O Thinknode G1 tem cinco luzes indicadoras. As quatro frontais indicam se o gateway tem energia, e está ligado a LoRa, WLAN ou LTE. A foto abaixo mostra o topo do G1 com as quatro luzes indicadoras na frente da caixa:

O grande LED em forma de Y no topo pode acender em diferentes cores e ritmos de piscar. A tabela abaixo descreve o significado dos diferentes sinais:

Conectores
Na parte traseira do Thinknode G1 encontrará os conectores para a alimentação, Ethernet (ETH), USB-C, a antena LoRa, slots para cartão Micro SD e Nano SIM:

Também na parte traseira há um botão para reiniciar ou entrar no modo de configuração. A tabela seguinte descreve como alternar entre modos:

Configuração do Hardware
Primeiro ligue a antena e depois a alimentação. O LED de energia deve ficar verde e o indicador superior ficará vermelho até o gateway estar configurado corretamente.

Para configuração, pode ligar ao gateway via cabo Ethernet (ETH) ou WIFI. O User Manual do ThinkNode G1 descreve ambos os métodos. Na próxima secção mostro como configurei o software do ThinkNode G1 usando a ligação WIFI.
Configuração do Software
Para configurar via Wi-Fi, pressione e segure o botão na parte traseira do ThinkNode G1 até o LED indicador no topo ficar azul (leva cerca de 5 segundos):

Login na UI
Depois procure a sua rede Wi-Fi por um novo Ponto de Acesso chamado ThinkNode-G1_XXXXXX e ligue-se a ele:

Abra o navegador e vá para o endereço IP 192.168.1.1. Deve ver uma tela de login, onde insere “root” como Nome de Utilizador e também como Palavra-passe:

Ligar ao Wi-Fi
Para ligar o Gateway à sua rede Wi-Fi vá a Network -> Wireless

e clique em Scan para procurar a sua rede Wi-Fi:

Na lista clique na sua rede Wi-Fi e na janela seguinte insira a palavra-passe para aceder.

Configurar LoRaWAN
De seguida precisamos configurar a interface LoRa e a frequência. Vá a LoRaWAN -> LoRa Gateway

Na janela seguinte selecione WIFI como interface LoRa, e EU868 como Plano de Frequência para a Europa. Na América do Norte deve selecionar US915. Defina o Modo LoRa para Packet Forwarder:

(Alternativamente, se quiser configurar o gateway como Base Station veja o Webtutorial).
Mantenha os outros parâmetros como estão, mas certifique-se que o Endereço do Servidor está definido para eu1.cloud.thethings.network (se estiver na Europa). Precisamos disto para ligar o gateway ao The Things Network.
Finalmente pressione Save & Apply, que irá reiniciar o Gateway e, se tiver sorte, está feito.

No entanto, tive problemas e tive de inserir também o Servidor DNS, caso contrário o meu G1 não se ligava ao The Things Network.
Servidor DNS
Para adicionar ou editar o Servidor DNS vá a Network -> Interfaces e pressione o botão Edit para a LAN:

Na janela clique no separador Advanced Settings e edite os campos Use custom DNS servers:

Adicionei 8.8.8.8 (Google) e 1.1.1.1 (Cloudflare) como servidores DNS e finalmente o meu gateway ligou-se ao The Things Network.
Ligando o Gateway ao The Things Network
The Things Network (TTN) oferece um Network Server público que permite enviar dados de sensores de um dispositivo LoRa, por exemplo temperatura, para um website, onde pode visualizar ou processar os dados com uma aplicação web.
O primeiro passo é ligar o nosso ThinkNode G1 Gateway ao TTN. Vá para o URL: https://eu1.cloud.thethings.network/console/, clique no botão azul Add e selecione Add new gateway:

Insira o Gateway EUI, que está impresso na parte traseira do ThinkNode G1 Gateway ou pode ser encontrado na página de Estado da UI de configuração do gateway. Depois de inserir o EUI pressione Confirm:

Isto vai expandir a janela e poderá então inserir um ID único para o Gateway, por exemplo o EUI do gateway com o prefixo ‘eui’ e um nome para o Gateway, eu escolhi Maet-ThinkNode-G1 para este teste. Também deve selecionar um plano de frequência que corresponda à frequência do seu gateway (Europa 863-870 MHz), por exemplo:

Mantenha o resto como está e pressione Register gateway. Se tudo correr bem verá uma página de estado com um status verde indicando que o Gateway está ligado:

Se chegou até aqui, parabéns. O pior já passou ; )
Criar uma Aplicação
O The Things Network (TTN) organiza os End Devices (sensores, atuadores) em chamadas “Applications”. O papel delas é decodificar dados e opcionalmente encaminhá-los para servidores externos via Webhooks ou MQTT.
Applications, Gateways e End Devices interagem da seguinte forma: O End Device envia dados (uplink) via LoRa. Depois o Gateway recebe os dados e encaminha para o TTN. Finalmente o Network Server do TTN encaminha os dados para uma Application específica usando o DevEUI do dispositivo.
[End Device] ←→ [Gateway] ←→ [TTN Network Server] ←→ [Application]
Portanto, antes de podermos receber e monitorizar dados de sensores no TTN, precisamos criar uma Application. Para isso vá a https://eu1.cloud.thethings.network/console/applications/add, que abrirá a seguinte janela:

Insira um Application ID, por exemplo env-sensor-network e um nome para a Application, por exemplo Environmental Sensors como mostrado acima.
Registar End Device
De seguida vamos adicionar e registar o nosso End Device. Na página da sua aplicação (https://eu1.cloud.thethings.network/console/applications/env-sensor-network) verá uma caixa com um botão azul rotulado “+ Register end device”:

Pressione este botão e verá a seguinte janela:

Insira os dados do seu End Device, principalmente o Plano de Frequência, a versão LoRaWAN e o JoinEUI. O JoinEUI (antigamente AppEUI) é um número com o seguinte formato: 70B3D57EDxxxxxxx. Substitua ‘xxxxxxx’ por um número hexadecimal para criar um JoinEUI único para o seu End Device, por exemplo 70B3D57ED0000001.
Quando terminar clique no botão Confirm à direita, que expandirá a janela e permitirá gerar um DevEUI e um AppKey. Finalmente, precisa dar ao seu End Device um ID único:

Pressione Register end device e deverá ver a informação do dispositivo criado:

As informações mais importantes são o AppEUI, DevEUI e AppKey. Vai precisar destas credenciais no código do End Device. Elas permitem que o End Device se autentique no The Things Network.
Construir um End Device LoRaWAN com SX1276 e ESP32
Pode comprar muitos dispositivos LoRaWAN pré-construídos com vários sensores e funções, mas são caros. Para uma visão geral veja o Device Repository for LoRaWAN do The Things Network. Neste tutorial vamos construir o nosso próprio end device, que não é difícil e muito mais barato ; )
Vamos usar um ESP32 como microcontrolador e um módulo transceptor SX1276 para transmitir dados via LoRa. Se precisar de mais informações sobre o SX1276 veja o Long range communication with LoRa SX1276 and ESP32 tutorial. A seguir, vou ser breve e mostrar como ligar o SX1276 ao ESP32. Aqui está a tabela de ligações:
| SX1276 | ESP32 |
|---|---|
| MOSI | 23 |
| MSIO | 19 |
| SCK | 18 |
| RST | 17 |
| NSS | 5 |
| DIO0 | 4 |
| DIO1 | 16 |
| GND | GND |
| VCC | 3.3V |
Certifique-se de ligar o VCC ao pino de saída 3.3V do seu ESP32. Além da interface SPI (MOSI, MISO, SCK, RST, NSS), as ligações digitais IO nos pinos DIO0 e DIO1 também são essenciais. A imagem abaixo mostra o diagrama completo de ligações:

Como mencionado, deve usar um módulo transceptor SX1276 que opere na LoRa frequency that is permitted in your country. No diagrama de ligações acima pode ver que o SX1276 está marcado como 868M, significando que usa a banda 868MHz para a Europa. Para a América do Norte, precisará de um módulo 915MHz.
A frequência do SX1276, do Gateway e as configurações no The Things Network devem coincidir! No meu caso estão todos definidos para 868MHz.
Enviar Dados de Teste via LoRaWAN
Agora vamos escrever o código para enviar alguns dados de teste do nosso End Device (ESP32 + SX1276) via LoRaWAN para o TTN.
Mas primeiro precisa instalar uma biblioteca para LoRaWAN e vamos usar a MCCI LoRaWAN LMIC library. Basta abrir o LIBRARY MANAGER, procurar por “mcci lorawan lmic library” e pressionar INSTALL. A imagem abaixo mostra uma instalação bem-sucedida:

Note que LoRaWAN define três classes de dispositivos: Classe A, Classe B e Classe C, cada uma oferecendo diferentes compromissos entre consumo de energia e disponibilidade de downlink. Classe A é o modo padrão e mais eficiente em energia, onde um dispositivo só pode receber mensagens downlink em duas janelas curtas após transmitir um uplink. Esta classe é ideal para sensores alimentados por bateria e é totalmente suportada pela biblioteca LMIC.
Classe B adiciona janelas de receção agendadas usando beacons periódicos enviados pelo gateway, permitindo acesso downlink mais previsível ao custo de maior consumo de energia. Dispositivos Classe C mantêm as janelas de receção quase sempre abertas, permitindo comunicação downlink de baixa latência, mas requerendo energia constante (ex: dispositivos ligados à rede). No entanto, a biblioteca LMIC suporta apenas Classe A.
Configuração da Biblioteca
De seguida precisamos configurar a biblioteca LMIC para a frequência LoRa, versão e chip que estamos a usar. A biblioteca LMIC contém um ficheiro lmic_project_config.h que normalmente encontra no seguinte caminho no Windows:
...\OneDrive\Documents\Arduino\libraries\MCCI_LoRaWAN_LMIC_library\project_config
Abra este ficheiro e edite o seu conteúdo conforme mostrado abaixo:
#define CFG_eu868 1 //#define CFG_us915 1 //#define CFG_au915 1 //#define CFG_as923 1 //#define CFG_kr920 1 //#define CFG_in866 1 #define CFG_sx1276_radio 1 //#define CFG_sx1261_radio 1 //#define CFG_sx1262_radio 1 //#define ARDUINO_heltec_wifi_lora_32_V3 //#define LMIC_USE_INTERRUPTS #define LMIC_LORAWAN_SPEC_VERSION LMIC_LORAWAN_SPEC_VERSION_1_0_3
Novamente, se não estiver na Europa, terá de escolher a frequência LoRa para o seu país (Europa -> CFG_eu868, América do Norte -> CFG_us915, …). Certifique-se de comentar todas as outras frequências.
Estamos a usar o chip SX1276, por isso também definimos CFG_sx1276_radio 1. Se usar um chip LoRa diferente, terá de alterar isto aqui também.
Código para enviar dados com LoRaWAN
O código seguinte envia a cada minuto um valor de contador como string, por exemplo “Counter = 5” do nosso End Device (ESP32 + SX1276) via ThinkNode Gateway para o TTN, onde podemos inspecioná-lo. Mais sobre isso depois. Por agora, dê uma olhada rápida no código antes de discutirmos os detalhes:
#include <lmic.h>
#include <hal/hal.h>
static const u1_t PROGMEM APPEUI[8] = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui(u1_t* buf) {
memcpy_P(buf, APPEUI, 8);
}
static const u1_t PROGMEM DEVEUI[8] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
void os_getDevEui(u1_t* buf) {
memcpy_P(buf, DEVEUI, 8);
}
static const u1_t PROGMEM APPKEY[16] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getDevKey(u1_t* buf) {
memcpy_P(buf, APPKEY, 16);
}
static osjob_t sendjob;
const unsigned TX_INTERVAL = 60; // Send every minute
const lmic_pinmap lmic_pins = {
.nss = 5,
.rxtx = LMIC_UNUSED_PIN,
.rst = 17,
.dio = { 4, 16, LMIC_UNUSED_PIN }
};
void onEvent(ev_t ev) {
Serial.printf("%d: ", os_getTime());
switch (ev) {
case EV_JOINING:
Serial.println("EV_JOINING");
break;
case EV_JOINED:
Serial.println("EV_JOINED");
LMIC_setLinkCheckMode(0);
break;
case EV_JOIN_FAILED:
Serial.println("EV_JOIN_FAILED");
break;
case EV_TXCOMPLETE:
Serial.println("EV_TXCOMPLETE");
if (LMIC.dataLen) {
Serial.printf("> Downlink %d bytes\n", LMIC.dataLen);
Serial.print("> Data: ");
for (int i = 0; i < LMIC.dataLen; i++) {
Serial.printf("%02X ", LMIC.frame[LMIC.dataBeg + i]);
}
Serial.println();
}
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
case EV_TXCANCELED:
Serial.println("EV_TXCANCELED");
break;
case EV_JOIN_TXCOMPLETE:
Serial.println("EV_JOIN_TXCOMPLETE: no JoinAccept");
break;
default:
Serial.print("Unknown event: ");
Serial.println((unsigned)ev);
break;
}
}
void do_send(osjob_t* j) {
static uint16_t counter = 0;
static char mydata[25];
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
snprintf(mydata, sizeof(mydata), "Counter = %u", counter);
LMIC_setTxData2(1, (uint8_t*)mydata, strlen(mydata), 0);
Serial.printf("> Data: %s\n", mydata);
counter++;
}
}
void setup() {
Serial.begin(115200);
os_init_ex(&lmic_pins);
LMIC_reset();
do_send(&sendjob);
}
void loop() {
os_runloop_once();
}
Bibliotecas
O código começa por incluir as bibliotecas LMIC necessárias:
#include <lmic.h> #include <hal/hal.h>
Estas bibliotecas dão-nos tudo o que precisamos para comunicar com o chip SX1276 e gerir a funcionalidade LoRaWAN. O cabeçalho lmic.h trata da lógica do protocolo, enquanto hal/hal.h conecta o LMIC ao hardware (neste caso, o nosso ESP32 e SX1276).
Autenticação
A autenticação LoRaWAN começa com três chaves críticas: APPEUI, DEVEUI, e APPKEY. Estas são credenciais do dispositivo usadas para entrar numa rede LoRaWAN usando OTAA (Over-The-Air Activation). Inseriu/gerou estas chaves quando criou o End Device no TTN e pode vê-las na Informação do Dispositivo:

No entanto, a biblioteca LMIC espera os bytes para APPEUI e DEVEUI na ordem LSB-first (Least Significant Byte first), o que significa que tem de inverter os bytes para APPEUI e DEVEUI no código. Por exemplo, se o AppEUI na Informação do Dispositivo no TTN for 70 B3 D5 7E D0 00 00 01 como mostrado acima, no código fica:
APPEUI[8] = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
O mesmo é válido para DEVUI, mas não para o APPKEY – este mantém a mesma ordem de bytes!
Constantes das Chaves
O código cria arrays constantes para estas chaves de autenticação na ordem correta de bytes e depois chama uma função que copia a chave para um buffer que o LMIC usa durante o processo de join. Estas funções garantem que o seu ESP32 pode autenticar-se de forma segura com o servidor de rede LoRaWAN, como o The Things Network.
Abaixo da constante para o APPEUI com a função “copy” os_getArtEui():
static const u1_t PROGMEM APPEUI[8] = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui(u1_t* buf) {
memcpy_P(buf, APPEUI, 8);
}
A diretiva PROGMEM armazena os dados na memória flash para poupar RAM. Lógica semelhante aplica-se ao device EUI e à chave da aplicação. Apenas lembre-se que APPEUI e DEVEUI estão em ordem invertida, mas não o APPKEY:
static const u1_t PROGMEM DEVEUI[8] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
void os_getDevEui(u1_t* buf) {
memcpy_P(buf, DEVEUI, 8);
}
static const u1_t PROGMEM APPKEY[16] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getDevKey(u1_t* buf) {
memcpy_P(buf, APPKEY, 16);
}
Obviamente, terá de usar os valores APPEUI, DEVEUI e APPKEY para o seu TTN Application e End Device!
Constantes
De seguida, o código define um objeto global de tarefa e um intervalo de transmissão.
static osjob_t sendjob; const unsigned TX_INTERVAL = 60; // Send every minute
O sendjob mantém a tarefa agendada para execução posterior, enquanto TX_INTERVAL define com que frequência quer transmitir dados — neste caso, uma vez a cada 60 segundos.
Mapeamento de Pinos
Agora definimos o mapeamento de pinos entre o ESP32 e o módulo LoRa SX1276:
const lmic_pinmap lmic_pins = {
.nss = 5,
.rxtx = LMIC_UNUSED_PIN,
.rst = 17,
.dio = { 4, 16, LMIC_UNUSED_PIN }
};
Esta estrutura indica ao LMIC quais os pinos GPIO ligados às linhas de controlo do SX1276. Por exemplo, nss é o pino chip-select SPI, rst é Reset, e dio corresponde aos pinos de interrupção usados pelo rádio.
onEvent
A função onEvent() trata vários eventos LoRaWAN — desde pedidos de join até transmissões concluídas.
void onEvent(ev_t ev) {
Serial.printf("%d: ", os_getTime());
switch (ev) {
case EV_JOINING:
Serial.println("EV_JOINING");
break;
case EV_JOINED:
Serial.println("EV_JOINED");
LMIC_setLinkCheckMode(0);
break;
...
}
}
Esta função ajuda a monitorizar o que o dispositivo está a fazer. Por exemplo, EV_JOINED significa que o dispositivo se ligou com sucesso à rede, e desligamos o modo de verificação de ligação com LMIC_setLinkCheckMode(0) para poupar tempo de transmissão. Quando EV_TXCOMPLETE é acionado, o dispositivo terminou de enviar dados, e enfileiramos a próxima transmissão:
case EV_TXCOMPLETE:
Serial.println("EV_TXCOMPLETE");
if (LMIC.dataLen) {
Serial.printf("> Downlink %d bytes\n", LMIC.dataLen);
Serial.print("> Data: ");
for (int i = 0; i < LMIC.dataLen; i++) {
Serial.printf("%02X ", LMIC.frame[LMIC.dataBeg + i]);
}
Serial.println();
}
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
O caso EV_TXCOMPLETE também verifica se o módulo LoRa recebeu dados (downlink). Se houver downlink (LMIC.dataLen > 0) o código imprime os bytes dos dados como números hexadecimais.
Pode enviar dados a partir do TTN clicando no separador Messaging do seu End Device:

do_send
A lógica principal da transmissão acontece dentro da função do_send().
void do_send(osjob_t* j) {
static uint16_t counter = 0;
static char mydata[25];
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
snprintf(mydata, sizeof(mydata), "Counter = %u", counter);
LMIC_setTxData2(1, (uint8_t*)mydata, strlen(mydata), 0);
Serial.printf("> Data: %s\n", mydata);
counter++;
}
}
Esta função constrói uma string como "Counter = 23" e enfileira-a para transmissão. Primeiro verifica se outra transmissão está pendente — LoRaWAN é rigoroso quanto ao timing. Se estiver livre, envia o pacote na porta 1 sem confirmação (o último argumento 0 significa uplink não confirmado).
setup
A função setup() inicia tudo:
void setup() {
Serial.begin(115200);
os_init_ex(&lmic_pins);
LMIC_reset();
do_send(&sendjob);
}
Inicializa a porta serial para debugging, configura a stack LMIC com o mapeamento de pinos correto, reinicia o estado interno do LMIC e enfileira a primeira transmissão.
loop
Finalmente, a função loop() mantém o runtime do LMIC a funcionar.
void loop() {
os_runloop_once();
}
Ao contrário dos loops tradicionais do Arduino, o LMIC requer esta chamada dentro do loop() para manter o agendador de tarefas e o sistema de eventos a funcionar corretamente.
Monitor Serial
Se carregar o código e abrir o Monitor Serial deverá ver as seguintes mensagens a aparecer:

Mensagens Uplink
Com esta configuração, o seu ESP32 e SX1276 enviarão uma string de contador via LoRaWAN a cada minuto. Se for ao TTN pode escolher ver as mensagens de dados uplink enviadas pelo nosso End Device. Selecione Applications e clique em Live data:

No lado direito verá então a mensagem com timestamp enviada pelo nosso ESP32:

Formatador de Payload
No entanto, não mostra os dados reais da mensagem, o valor do contador. Isto porque o TTN não sabe como decodificar os dados na mensagem. Terá de especificar ou implementar um Payload Formatter para poder ver os dados.
Abra a Sidebar, selecione Application, clique em Payload formatters e selecione Uplink:

Pode então selecionar um Payload Formatter existente ou implementar o seu próprio. Vamos implementar o nosso e por isso selecionamos “Custom Javascript formatter” como Tipo de Formatter:

Para “Formatter code” insira o seguinte código, que simplesmente converte os bytes que enviamos de volta para caracteres:
function decodeUplink(input) {
let str = "";
for (let i = 0; i < input.bytes.length; i++) {
str += String.fromCharCode(input.bytes[i]);
}
return { data: { message: str } };
}
Se agora olhar novamente para as mensagens uplink verá um campo Payload no final, que mostra a string com o valor do contador que o End Device envia:

Na próxima secção adicionamos um sensor ambiental ao ESP32 e alteramos o código para enviar dados de temperatura, humidade e pressão do ar via LoRaWAN para o TTN.
Enviar Dados Ambientais via LoRaWAN
Uma aplicação clássica para LoRaWAN é enviar dados ambientais como temperatura, humidade e pressão do ar de um End Device LoRa para o TTN. Nesta secção, vamos adicionar o sensor BME280 ao nosso circuito e estender o código para enviar os dados medidos pelo sensor.
Se quiser mais informações sobre o BME280 veja o How To Use BME280 Pressure Sensor ou os Temperature Plotter on e-Paper Display tutoriais.
Ligar BME280 ao ESP32
O sensor BME280 tem uma interface I2C e é fácil de adicionar ao circuito. A tabela seguinte mostra todas as ligações que tem de fazer, incluindo as existentes para o SX1276:
| SX1276 | BME280 | ESP32 |
|---|---|---|
| MOSI | – | 23 |
| MSIO | – | 19 |
| SCK | – | 18 |
| RST | – | 17 |
| NSS | – | 5 |
| DIO0 | – | 4 |
| DIO1 | – | 16 |
| – | SCL | 25 |
| – | SDA | 33 |
| GND | GND | GND |
| VCC | VCC | 3.3V |
E aqui a ligação completa entre BME280, SX1276 e ESP32:

Código para Enviar Dados Ambientais via LoRaWAN
De seguida vamos instalar duas bibliotecas: A Adafruit_BME280 para ler dados do BME280:

e a CayenneLPP library, que formata dados do sensor para transmissões LoRaWAN:

O código seguinte é uma simples alteração e extensão do código anterior. Em vez de enviar um contador, enviamos medições de temperatura, humidade e pressão do ar do sensor BME280. Dê uma olhada rápida e depois discutimos as diferenças em relação ao código anterior:
#include <lmic.h>
#include <hal/hal.h>
#include <CayenneLPP.h>
#include <Adafruit_BME280.h>
static const u1_t PROGMEM APPEUI[8] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getArtEui(u1_t* buf) {
memcpy_P(buf, APPEUI, 8);
}
static const u1_t PROGMEM DEVEUI[8] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
void os_getDevEui(u1_t* buf) {
memcpy_P(buf, DEVEUI, 8);
}
static const u1_t PROGMEM APPKEY[16] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getDevKey(u1_t* buf) {
memcpy_P(buf, APPKEY, 16);
}
static osjob_t sendjob;
const unsigned TX_INTERVAL = 60; // Send every minute
const lmic_pinmap lmic_pins = {
.nss = 5,
.rxtx = LMIC_UNUSED_PIN,
.rst = 17,
.dio = { 4, 16, LMIC_UNUSED_PIN }
};
CayenneLPP lpp(16);
Adafruit_BME280 bme;
void initBMESensor() {
Wire.begin(33, 25); // Software I2C for BME280
bme.begin(0x76, &Wire);
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF);
}
void onEvent(ev_t ev) {
Serial.printf("%d: ", os_getTime());
switch (ev) {
case EV_JOINING:
Serial.println("EV_JOINING");
break;
case EV_JOINED:
Serial.println("EV_JOINED");
LMIC_setLinkCheckMode(0);
break;
case EV_JOIN_FAILED:
Serial.println("EV_JOIN_FAILED");
break;
case EV_TXCOMPLETE:
Serial.println("EV_TXCOMPLETE");
if (LMIC.dataLen) {
Serial.printf("> Downlink %d bytes\n", LMIC.dataLen);
Serial.print("> Data: ");
for (int i = 0; i < LMIC.dataLen; i++) {
Serial.printf("%02X ", LMIC.frame[LMIC.dataBeg + i]);
}
Serial.println();
}
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
case EV_TXCANCELED:
Serial.println("EV_TXCANCELED");
break;
case EV_JOIN_TXCOMPLETE:
Serial.println("EV_JOIN_TXCOMPLETE: no JoinAccept");
break;
default:
Serial.print("Unknown event: ");
Serial.println((unsigned)ev);
break;
}
}
void do_send(osjob_t* j) {
bme.takeForcedMeasurement();
float temp = bme.readTemperature();
float hum = bme.readHumidity();
float pres = bme.readPressure() / 100.0;
lpp.reset();
lpp.addTemperature(1, temp); // channel 1
lpp.addRelativeHumidity(2, hum); // channel 2
lpp.addBarometricPressure(3, pres); // channel 3
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0);
Serial.printf("> Temperature: %.2f\n", temp);
Serial.printf("> Humidity: %.2f\n", hum);
Serial.printf("> Pressure: %.2f\n", pres);
}
}
void setup() {
Serial.begin(115200);
initBMESensor();
os_init_ex(&lmic_pins);
LMIC_reset();
do_send(&sendjob);
}
void loop() {
os_runloop_once();
}
O código usa as mesmas chaves para APPEUI, DEVEUI e APPKEY que antes. A principal extensão é uma função que inicializa o sensor BME280 e uma alteração na função que envia os dados.
initBMESensor
A função initBMESensor() inicializa o BME280 usando I2C por software. Em vez dos pinos I2C padrão do ESP32, especifica GPIO 33 para SDA e GPIO 25 para SCL:
void initBMESensor() {
Wire.begin(33, 25); // Software I2C for BME280
bme.begin(0x76, &Wire);
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF);
}
Note que estou a usar o endereço I2C 0x76, ao configurar o sensor via bme.begin(0x76, &Wire). O seu sensor pode ter um endereço I2C diferente. Por exemplo, 0x77 também é comum para o BME280.
O sensor está configurado em “modo forçado”, o que significa que só mede quando explicitamente instruído. Esta abordagem poupa energia. A amostragem está no mínimo (1x) para temperatura, pressão e humidade, e o filtro interno está desativado.
do_send
A função do_send() obtém primeiro medições de temperatura, humidade e pressão do ar do sensor BME280
void do_send(osjob_t* j) {
bme.takeForcedMeasurement();
float temp = bme.readTemperature();
float hum = bme.readHumidity();
float pres = bme.readPressure() / 100.0;
Depois formata os dados para a transmissão LoRaWAN adicionando temperatura, humidade e pressão do ar como canais diferentes ao pacote de dados:
lpp.reset(); lpp.addTemperature(1, temp); // channel 1 lpp.addRelativeHumidity(2, hum); // channel 2 lpp.addBarometricPressure(3, pres); // channel 3
Finalmente, os dados são enviados como o habitual pacote de bytes. Além disso, o código imprime os dados no Monitor Serial:
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0);
Serial.printf("> Temperature: %.2f\n", temp);
Serial.printf("> Humidity: %.2f\n", hum);
Serial.printf("> Pressure: %.2f\n", pres);
}
}
Para mais informações veja o Send Environmental Data with LoRa tutorial que faz algo semelhante mas usa LoRa puro em vez de LoRaWAN.
Monitor Serial
Se carregar e executar o código deverá ver a seguinte saída no seu Monitor Serial:

Formatador de Payload
Se quiser inspecionar os dados no TTN terá de especificar um Payload Formatter como antes. No entanto, neste caso é mais simples. Não precisamos de escrever o nosso próprio Custom Javascript Formatter, mas podemos usar o formatador CayenneLPP:

Na Visão Geral do Dispositivo pode então ver os dados ambientais formatados nos três canais:

E é isso. Agora sabe como construir o seu próprio End Device LoRaWAN para enviar dados ambientais através do ThinkNode G1 Gateway para o TTN.
Conclusões
Este artigo apresentou o Thinknode G1 Gateway. Um gateway LoRaWAN permite essencialmente enviar dados de sensores LoRa para a internet. Construímos o nosso sensor LoRa com um ESP32, SX1276 e sensor BME280 e usamos para enviar temperatura, humidade e pressão para The Things Network.
Mal arranhámos a superfície do LoRaWAN e encorajo-o a explorar a informação no www.thethingsnetwork.org/docs/lorawan para aprender mais. Para mais orientação sobre como configurar o ThinkNode G1 veja o Manual e o Webtutorial.
Se só quer transmitir dados entre dois dispositivos LoRa, LoRaWAN é provavelmente exagerado e é melhor usar LoRa puro. Veja o Long range communication with LoRa SX1276 and ESP32 e o Send Environmental Data with LoRa.
Finalmente, se preferir um Arduino em vez do ESP32, precisa usar um conversor de nível lógico ou um Arduino que funcione a 3.3 Volts, pois o módulo SX1276 não funciona com 5V! Veja o Interface Arduino Uno with ST7735 TFT using Level Shifter tutorial para mais informações.
Se tiver dúvidas, sinta-se à vontade para deixá-las na secção de comentários.
Boas experiências ; )
Links
Alguns links que achei úteis ao escrever este artigo:
- ThinkNode G1 Gateway Setup
- ThinkNode G1 LoRaWAN gateway setup and testing
- Maximizing LoRaWAN coverage with an indoor gateway – ThinkNode G1 setup and review
- 5 Things You Need to Know about LoRaWAN-based Gateways
- Set Up the LoRa Module Network to Communicate with the ThinkNode Gateway
- How to use ESP32 for LoRa communication with the Things Network
- MCCI LoRaWAN LMIC Library
- CayenneLPP Library

