ESP32 Lora – Mudando as frequências




Que tal um programa, feito na linguagem C do Arduino IDE, que faz o rádio LoRa mudar de frequência? É isso que você pode conferir no meu vídeo e no meu artigo de hoje, nos quais você vai ver ainda a diferença entre rádio LoRa, protocolo LoRaWAN e criptografia.


Vamos, então, criar um projeto no qual teremos dois ESP32 Lora se comunicando e, a cada vez que pressionarmos um botão que estará ligado ao EMISSOR, ele mudará a frequência de comunicação, avisando através do pacote ao RECEPTOR para também mudar a frequência, mantendo, assim, a comunicação entre eles.
Já falei sobre LoRa – de Long Range, ou seja, Longa Distância – em um vídeo anterior e recebi sugestões para falar sobre o protocolo LoRaWAN. Então, aproveito aqui para explica que LoRa geralmente é a infraestrutura do radio, enquanto  LoRaWAN é a infraestrutura da IOT (Internet das Coisas), onde tem um protocolo, gateway, criptografia. Portanto, hoje vou falar de tudo isso, com destaque para a frequência.
Acho que não ficou claro no meu vídeo que a questão de mudar de frequência tem relação, mais com a possibilidade de uma aplicação proprietária LoRa usar canais com pequenos deslocamentos da frequência para criar canais,  do que mudar a frequência principal do radio LoRa, deslocando no espectro 125k, como fazem alguns gateways que usam canais para controle e transmissão. Entendo que mudar de 915Mhz para 433Mhz é um aberração, com certeza, para a antena e elementos passivos da placa. Um exemplo são os capacitores c1, c2,c3,c10 e indutores L1 a L3  , descritos no documento PDF da Semtech AN1200.19 SX127x Reference Design Overview. Se fizesse um salto tão grande de frequência teria que sair mudando os valores dos indutores e capacitores ligados ao chip LoRa e, sendo eles SMD, não seria tarefa fácil ou viável mesmo para um Maker.

Que fique claro aqui é que aconselho comprar o radio LoRa na frequência em que vai ser usado e apenas variar a frequência do canal.

LoRa® - LoRaWAN™

Nesse diagrama abaixo temos a figura do Gateway. Quando falamos em LoRaWAN, falamos no protocolo que roda neste Gateway e em determinados dispositivos ao lado esquerdo da figura. Quanto você utiliza esse tipo de protocolo é porque você já está com a infraestrutura montada. Portanto, geralmente, neste caso, você paga uma mensalidade ao proprietário do Gateway por esta possibilidade de tráfego. Neste caso do protocolo LoRaWAN, então, podemos exemplificar com o uso de um smartphone, que você habilita, contrata uma operadora e paga pela comunicação. Os equipamentos e infraestrutura, portanto, já estão prontos. Enfim, basta programar seu ESP LoRa que ele vai atingir seu objetivo a partir dessa infraestrutura já existente. Lembrando que, no Brasil, temos poucos Gateways disponíveis.


Só para vocês terem uma ideia de valores dos equipamentos utilizados neste vídeo, expomos a imagem abaixo. O kit de desenvolvimento de Portal LoRaWAN não sai barato e o da imagem utiliza um Raspberry Pi. Se na China ele está saindo por R$ 2,6 mil, deve chegar ao Brasil quase o dobro desse valor por conta dos impostos. No caso do rádio que usa chip SX1301, o qual opera em oito canais simultâneos, o cenário é o mesmo. Enquanto custa R$ 5,3 mil na China, deverá chegar ao Brasil por cerca de R$ 10 mil. 


Quando eu uso ESP32 Lora?


Nessa imagem acima demonstro claramente que, quando você está trabalhando com LoRaWAN você está no topo, em alto nível, ou seja, na camada em cor verde. Já na camada em cor laranja está o rádio LoRa. Portanto, eis aqui a diferença entre essas duas coisas de forma mais visível. Ainda não consegui fazer nenhum exemplo utilizando LoRaWAN porque, onde moro, no interior do estado de São Paulo, não temos nenhum Gateway deste tipo disponível. Qual a minha saída? Vou ter que comprar um para saber como ele funciona.

Então, quando eu uso ESP32 Lora?


1.            Quando preciso de velocidade “tempo de resposta”
2.            Não quero pagar mensalidade ou tráfego
3.            Não existe cobertura pública de gateways
4.            Aplicação específica, por exemplo: Controle remoto
5.            Sensores exóticos incompatíveis com hardware padrão
     * Devem existir muitos mais motivos que apenas não me lembro agora.

LoRa® - LoRaWAN™ - e as Frequências

Abaixo mostro uma tabela que indica como os países se organizaram em relação às frequências da rede LoRa. A aliança LoRa tenta de todo jeito manter o padrão LoRa o mais coeso possível, mas isso não é fácil. Vemos que a frequência nos Estados Unidos é de 902 a 928 MHz, uma faixa relativamente larga, que possibilita pendurar 64 canais. A Austrália já tem uma faixa um pouco mais estreita, enquanto na China e na Europa são duas faixas cada.
No Brasil deveria ser igual ao EUA, o que está previsto na resolução 680 da Anatel, de junho de 2017. Porém, uma outra resolução em análise pode trazer novidades sobre esse assunto. Mas, retomando, por que aqui a frequência não é igual a dos Estados Unidos? No Brasil, a administração de frequências está sob a responsabilidade da Anatel, que regulamentou a banda de 900 MHz para operação GSM. Isso quer dizer que o intervalo entre 907,5 a 915 MHz, o equivalente a 40 canais, não está disponível, pois pertence a uma empresa de telefonia. Somando o que sobra, temos 24 canais.
Isso significa que, se você for instalar aqui no Brasil um Gateway LoRaWAN, você vai precisar configurar esse Gateway para não utilizar a faixa de frequência indisponível.


Frequências:
Estados Unidos :  902-928 mHz
Austrália :             915-928 mHz
China :         779-787 e 470-510 mHz
Europa :       863-870 e 433 mHz
Brasil :                  902-928 mHz

Criptografia LoRaWan

LoRaWAN conhece três chaves de segurança distintas de 128 bits. A chave da aplicação AppKey só é conhecida pelo dispositivo e pelo aplicativo. Quando um dispositivo se une à rede (isto é chamado de associação ou ativação), uma chave de sessão de aplicativo AppSKey e uma chave de sessão de rede NwkSKey são geradas. O NwkSKey é compartilhado com a rede, enquanto o AppSKey é mantido em privado. Estas chaves de sessão serão usadas durante o período da sessão.


A figura acima mostra como essas chaves são usadas. O AppSKey é usado para criptografia de ponta a ponta da carga útil do quadro. O algoritmo usado para isso é AES-128, semelhante ao algoritmo usado no padrão 802.15.4. O NwkSKey é conhecido pela rede e pelo dispositivo e é usado para validar a integridade de cada mensagem pelo seu Código de integridade da mensagem (MIC). Este MIC é semelhante a uma soma de verificação, exceto que impede a adulteração intencional de uma mensagem. Para isso, o LoRaWAN usa AES-CMAC.

Lora Esp32 Oled


Montagem


Na montagem, peguei um ESP da TTGO, 915 MHz, e outro da Heltec, de 433 MHz. E, ambos conversaram muito bem. A primeira frequência é usada na Europa, enquanto a segunda é difundida mais no Brasil e nos Estados Unidos. Então, vou mostrar como vocês podem mudar a frequência do rádio LoRa. O alcance do rádio LoRa é de cerca de 15 km, podendo chegar a 100 km.
No emissor tem um botão e outras ligações que exponho aqui o diagrama para facilitar a montagem. O receptor só precisa ser ligado na USB para alimentação e a frequência mudar. Ambos contam com displays que exibem os dados a serem analisados.

Bibliotecas

Adicione a seguinte biblioteca “Adafruit SSD1306”, que é do display que vai no ESP.
Basta acessar “Sketch >> Incluir Bibliotecas >> Gerenciar Bibliotecas...”


Programas

Criaremos dois programas, um para o ESP32 Lora que trabalhará como EMISSOR e outro programa para o ESP32 Lora que trabalhará como RECEPTOR.

Pacote: Sender -> Receiver
                                      byte  0: índice  de frequência
                                      byte  1: # delimitador
                                      byte  2: unsigned int
                                      byte  3: unsigned int


No vídeo você pode ver a nossa montagem. Temos os dois ESPs, sendo que um deles já veio como rádio 915 MHz. Esse rádio, então, já está ligado e enviando pacote ao segundo dispositivo. Ambos começam na frequência do nosso Array, que tem seis posições, de 915 a 433 MHz. Lembrando que as antenas que temos na montagem são de 433. Olhando o sinal em dB é -119, como se estivessem distantes um do outro, isso porque a antena está errada. Nosso exemplo, porém, só serve para mostrar que vocês podem variar muito a frequência desse rádio LoRa. Ainda no vídeo dou comandos para alterar a frequência.

Programa EMISSOR

O programa EMISSOR ficará configurado para iniciar na frequência 915Mhz e ficar enviando pacotes. A cada vez que o botão ligado a ele for pressionado, a frequência mudará e um comando será enviado para o RECEPTOR mudar também.

Programa EMISSOR Sender
#include <SPI.h>
#include <LoRa.h>
#include <Wire.h>  
#include "SSD1306.h" 

//pino Botão
#define PIN_BTN 23 
//pino LED
#define PIN_LED 22

//armazenam estado do botão
int estadoBtn, ultimoEstadoBtn;

// Pin definetion of WIFI LoRa 32
// HelTec AutoMation 2017 support@heltec.cn 
#define SCK     5    // GPIO5  -- SX127x's SCK
#define MISO    19   // GPIO19 -- SX127x's MISO
#define MOSI    27   // GPIO27 -- SX127x's MOSI
#define SS      18   // GPIO18 -- SX127x's CS
#define RST     14   // GPIO14 -- SX127x's RESET
#define DI00    26   // GPIO26 -- SX127x's IRQ(Interrupt Request)

#define PABOOST true

//array de frequencias válidas que utilizaremos para trocar
long int frequencia[6] = {915000000, 915125000, 868000000, 868125000, 433000000, 433125000};
//controla o indice da frequencia atual no array 
int indice = 0;

unsigned int counter = 0;

SSD1306 display(0x3c, 4, 15);

Setup
LoRa.begin(frequencia[indice],PABOOST)
Aqui no Setup temos uma chamada de método. Temos o (!Lora.begin(frequência[índice],PABOOST)) que inicializa o rádio em uma frequência determinada e essa frequência é aquele Array. Então, qual vai ser a primeira frequência que ele vai por aqui? 915 MHz. Ainda nesta parte, habilito o CRC, que é um dígito verificador que você coloca no final da informação para saber se todos os dados chegaram corretamente ao destino.
void setup() {
  pinMode(16,OUTPUT);
  pinMode(2,OUTPUT);

  Serial.begin(115200);

  pinMode(PIN_BTN, INPUT);
  pinMode(PIN_LED, OUTPUT);
  
  digitalWrite(16, LOW);    // set GPIO16 low to reset OLED
  delay(50); 
  digitalWrite(16, HIGH); // while OLED is running, must set GPIO16 in high

  display.init();
  display.flipScreenVertically();  
  display.setFont(ArialMT_Plain_10);
  delay(1500);
  display.clear();
  
  SPI.begin(SCK,MISO,MOSI,SS);
  LoRa.setPins(SS,RST,DI00);
  
  if (!LoRa.begin(frequencia[indice],PABOOST))
  {
    display.drawString(0, 0, "Starting LoRa failed!");
    display.display();
    while (1);
  }
  LoRa.enableCrc();
  display.drawString(0, 0, "LoRa Initial success!");
  display.display();
  delay(1000);

  //define estado do botao como desligado
  estadoBtn = ultimoEstadoBtn = LOW;
  digitalWrite(PIN_LED, LOW);

}


Loop
Nesta parte verificamos e ajustamos o estado do botão. Tratamos do envio do pacote, atualização do display e mudança de frequência.
void loop() 
{
  //recupera o estado do botao
  estadoBtn = digitalRead(PIN_BTN);
  //verifica se o estado do botão mudou e se mudou para LIGADO
  if( (estadoBtn != ultimoEstadoBtn) && (estadoBtn == HIGH) )
  {
    //liga o LED indicador de mudança de frequencia
    digitalWrite(PIN_LED, HIGH);  
    //verificação para não estourar o indice do array   
     if( (indice+1) > 5){ 
        indice = 0; 
     }
     else indice++; 
     
     enviarPacote();    
     atualizarDisplay();
     mudarFrequencia();     
  }
  //caso nao tenha apertado o botão, ou seja, seu estado é DESLIGADO, então a frequencia permanece a mesma
  else {
    enviarPacote();  
    atualizarDisplay();
  }
  //contador que é enviado (DADO)
  counter++;

  //copia o estado atual do botão na variável de verificação da mudança de estado
  ultimoEstadoBtn = estadoBtn;

  //acende LED interno para indicar que enviou o pacote e da um delay
  digitalWrite(2, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(700);               // wait for a second
  digitalWrite(2, LOW);    // turn the LED off by making the voltage LOW
  delay(500);               // wait for a second
}


mudarFrequencia e enviarPacote
Tenho uma função mudarFrequencia e, nela, temos o (!Lora.begin(frequência[índice],PABOOST)). Lembrando que, sempre que inicializo o rádio tenho que dar um enable no CRC. Trabalhamos novamente o envio de pacote.
//muda a frequencia do Lora, a nova frequencia será de acordo com a variável "INDICE" que pegará no array a nova frequencia
void mudarFrequencia()
{
  if (!LoRa.begin(frequencia[indice],PABOOST))
  { 
    display.drawString(0, 0, "Starting LoRa failed!");
    display.display();
    while (1);
  }
  LoRa.enableCrc();
  digitalWrite(PIN_LED, LOW); //desliga o LED indicador da mudança de frequência
}

//envia o pacote na rede Lora
void enviarPacote()
{
  // envia u pacote
  LoRa.beginPacket(); 
  LoRa.print(indice); //indice do array que contem as frequencias
  LoRa.print("#"); //delimitador
  LoRa.print(counter); //dado
  LoRa.endPacket();
}


atualizarDisplay
Aqui tratamos da atualização de display.
//atualiza as informações no display
void atualizarDisplay()
{
  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  
  display.drawString(0, 0, "Enviando Pacote: ");
  display.drawString(90, 0, String(counter));
  display.drawString(0, 20, String(frequencia[indice]));
  display.drawString(90, 20, "I: "+String(indice));  
  display.display();
}


Programa RECEPTOR

O programa RECEPTOR ficará configurado para iniciar na freqüência 915Mhz e a cada pacote recebido, verificará se o comando para mudança de freqüência está presente para se reconfigurar.

Programa RECEPTOR
#include <SPI.h>
#include <LoRa.h>
#include <Wire.h>  
#include "SSD1306.h" 

// Pin definetion of WIFI LoRa 32
// HelTec AutoMation 2017 support@heltec.cn 
#define SCK     5    // GPIO5  -- SX127x's SCK
#define MISO    19   // GPIO19 -- SX127x's MISO
#define MOSI    27   // GPIO27 -- SX127x's MOSI
#define SS      18   // GPIO18 -- SX127x's CS
#define RST     14   // GPIO14 -- SX127x's RESET
#define DI00    26   // GPIO26 -- SX127x's IRQ(Interrupt Request)

#define PABOOST true

//array de frequencias válidas que utilizaremos para trocar
long int frequencia[6] = {915000000, 915125000, 868000000, 868125000, 433000000, 433125000};
//controla o indice da frequencia atual no array 
int indice = 0;

SSD1306 display(0x3c, 4, 15);
String rssi = "RSSI --";
String packSize = "--";
String packet ;


Setup
Temos aqui o (!Lora.begin(frequência[índice],PABOOST)) na posição 0 da frequência, que é 915 MHz. Lembramos que, o que não pode acontecer? É um ESP mudar de frequência e o outro não. Se isso ocorrer, os dispositivos vão ficar cada um em uma frequência e não haverá mais comunicação entre eles. Novamente tratamos do enable do CRC e do display.
void setup() {
  Serial.begin(115200);
  
  pinMode(16,OUTPUT);
  digitalWrite(16, LOW);    // set GPIO16 low to reset OLED
  delay(50); 
  digitalWrite(16, HIGH); // while OLED is running, must set GPIO16 in high、
  display.init();
  display.flipScreenVertically();  
  display.setFont(ArialMT_Plain_10);

  delay(1500);
  display.clear();
  
  SPI.begin(SCK,MISO,MOSI,SS);
  LoRa.setPins(SS,RST,DI00);
  
  if (!LoRa.begin(frequencia[indice],PABOOST)) {
    display.drawString(0, 0, "Starting LoRa failed!");
    display.display();
    while (1);
  }
  LoRa.enableCrc();
  display.drawString(0, 0, "LoRa Initial success!");
  display.drawString(0, 10, "Wait for incomm data...");
  display.display();
  delay(1000);
  //LoRa.onReceive(cbk);
  LoRa.receive();


}


Loop e parserPacket
No loop principal, verificamos se existe algum pacote disponível e, caso exista, faremos um parser do pacote para tratar os dados recebidos.
void loop() 
{
  int packetSize = LoRa.parsePacket();
  //imprime na tela a frequencia atual que está configurada
  display.drawString(0,45,"Freq: "+String(frequencia[indice]));
  display.display();
   
  if (packetSize) {
    parserPacket(packetSize); 
  }
}

//faz o parser do pacote recebido para tratar os dados
void parserPacket(int packetSize) {
  packet ="";
  packSize = String(packetSize,DEC);
  for (int i = 0; i < packetSize; i++) { 
    packet += (char) LoRa.read(); 
  }
  rssi = "RSSI " + String(LoRa.packetRssi(), DEC) ;
  verificaFrequencia();
  loraData();
}


verificarFrequencia e loraData
Após o parser teremos os dados do pacote para trabalhar, chamaremos então a função verificarFrequencia, que verificará se o índice do array de frequência enviado pelo EMISSOR é diferente do atual. Caso seja, então faremos a mudança de frequência.
//verifica se no pacote recebido tem um comando para trocar de frequencia
void verificaFrequencia()
{
//  Serial.println(packet);
//o primeiro byte do pacote tem o indice da frequencia que o emissor está usando,
// colocamos esse valor em CMD para fazeras verificações
  String cmd = String(packet.charAt(0));
  //se o indice recebido é diferente do atual, então trocamos a frequencia
  if(cmd.toInt() != indice) 
  {
      if (!LoRa.begin(frequencia[cmd.toInt()],PABOOST))
      {
        display.drawString(0, 0, "Starting LoRa failed!");
        display.display();
        while (1);
      }
      indice = cmd.toInt();
      LoRa.enableCrc();
  }
}

void loraData(){
  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  display.drawString(0 , 15 , "Received "+ packSize + " bytes");
  display.drawStringMaxWidth(0 , 26 , 128, packet);
  display.drawString(0, 0, rssi);  
  display.display();
}



Faça download dos arquivos:




4 comentários:

  1. Boa tarde Fernando.
    Sobre seu comentario : " Qual a minha saída? Vou ter que comprar um para saber como ele funciona. "
    Tenho aqui na empresa um gateway e dois endpoints LoRa, pretendia iniciar testes nesse inicio de ano mas entraram outros projetos na frente e estou postergando. Vc teria interesse em fazer testes com eles e depois compartilhamos resultados?
    Se sim, por favor, me contate, estamos aqui em Mogi Mirim/SP, e-mail --> rmarango@marangoni.com.br
    Abracos,
    Ricardo.

    ResponderExcluir
  2. Amigo aonde você comprou essa maravilha de placa, tem como me passar o site.

    ResponderExcluir
  3. Which LoRa Library are you using ? I keep getting the error

    "C:\Users\User\Documents\Arduino\libraries\LoRa\src/LoRa.h:31:7:
    ........
    no matching function for call to 'LoRaClass::begin(float&, bool)"

    ResponderExcluir

Tecnologia do Blogger.