sandeepmistry / arduino-LoRa

An Arduino library for sending and receiving data using LoRa radios.
MIT License
1.64k stars 627 forks source link

multiples nodes, but recieving just one #298

Closed augusto3691 closed 3 years ago

augusto3691 commented 4 years ago

I have a system that have multiples nodes and one broker, when i have 1 broker and 1 node everything is fine but wen i put one more, the broker recieve data just from the last one...

here is my code:

Node:

include

include

include

include "SSD1306.h"

include <TinyGPS++.h>

include

define OLED_SDA 21

define OLED_SLA 22

define LORA_SCK 5

define LORA_MISO 19

define LORA_MOSI 27

define LORA_SS 18

define LORA_RST 14

define LORA_DI0 26

define LORA_BAND 915E6

define NODE_ID "gco89770" // Aqui vai o ID unico desse device, deve seguir o modelo aaa99999 (3 letras, 5 numeros)

define REBOOT_EEPROM_ADDRESS 0

SSD1306 display(0x3c, OLED_SDA, OLED_SLA); TinyGPSPlus gps;

void setup() { Serial.begin(115200); display.init(); display.flipScreenVertically();

Serial1.begin(9600, SERIAL_8N1, 12, 15); //12-15 para placa ESP32-LORA, para o ESP32 Stand-alone use 16-17

SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS); LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0); if (!LoRa.begin(LORA_BAND)) { display.clear(); display.drawString(0, 0, "LoRa falhou ao iniciar"); display.display(); return; } if (!EEPROM.begin(64)) { display.clear(); display.drawString(0, 0, "Flash Memory falhou"); display.drawString(0, 15, "Reiniciando..."); display.display(); delay(1000); ESP.restart(); }

int reboots = EEPROM.read(REBOOT_EEPROM_ADDRESS); int nextReboot = reboots + 1; if ( reboots < 0) { EEPROM.write(REBOOT_EEPROM_ADDRESS, 0); EEPROM.commit(); } else { EEPROM.write(REBOOT_EEPROM_ADDRESS, nextReboot); EEPROM.commit(); }

delay(1500);

}

void loop() { char v_millis_b[10]; int v_reboot = EEPROM.read(REBOOT_EEPROM_ADDRESS); String v_separator = "/"; int v_millis = millis(); sprintf(v_millis_b,"%08d", v_millis); String Version = v_reboot + v_separator + v_millis_b;

if (v_millis >= 86400000) { ESP.restart(); }

display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_10); display.drawString(0, 0, "Enviando pacote..."); display.drawString(0, 15, "Versão:"); display.drawString(40, 15, Version); display.display();

Serial.print("lat: "); Serial.println(gps.location.lat(), 5); Serial.print("lng: "); Serial.println(gps.location.lng(), 5); Serial.print("sat: "); Serial.println(gps.satellites.value()); Serial.print("Versão: "); Serial.println(Version);

//Send packet LoRa.beginPacket(); LoRa.print(NODE_ID); LoRa.print(","); LoRa.print(gps.location.lat(), 5); LoRa.print(","); LoRa.print(gps.location.lng(), 5); LoRa.print(","); LoRa.print(Version); LoRa.endPacket();

smartDelay(1000); }

//delay mais preciso static void smartDelay(unsigned long ms) { unsigned long start = millis(); do { while (Serial1.available()) gps.encode(Serial1.read()); } while (millis() - start < ms); }

Broker:

include

include

include "SSD1306.h"

include

include

include

include

include

include

SSD1306 display(0x3c, 21, 22); HTTPClient http;

define SS 18

define RST 14

define DI0 26

define BAND 915E6

define PACK_SIZE_FROM_NODE 40

define PACK_SIZE_FROM_COLECTOR 49

define BROKER_ID "5c8c3229" // Aqui vai o ID unico desse device, deve seguir o modelo aaa99999 (3 letras, 5 numeros)

define WIFI_NAME "Klabin Broker"

define API "http://us-central1-klabin-waze-florestal.cloudfunctions.net/pois"

void setup() { Serial.begin(115200);

display.init(); display.flipScreenVertically(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_LEFT);

WiFiManager wifiManager; wifiManager.setAPCallback(configModeCallback); wifiManager.setSaveConfigCallback(saveConfigCallback); wifiManager.autoConnect(WIFI_NAME);

delay(1000); Serial.println("LoRa Receiver"); display.drawString(5, 5, "LoRa Receiver"); display.display(); SPI.begin(5, 19, 27, 18); LoRa.setPins(SS, RST, DI0);

if (!LoRa.begin(BAND)) { display.drawString(5, 25, "Starting LoRa failed!"); while (1); } Serial.println("LoRa Initial OK!"); display.drawString(5, 25, "LoRa Initializing OK!"); display.display(); }

void sendData(String nodeId, String colectorId, String lat, String lng,String v) { StaticJsonBuffer<400> JSONbuffer; JsonObject& JSONencoder = JSONbuffer.createObject();

JSONencoder["brokerId"] = BROKER_ID; JSONencoder["colectorId"] = colectorId; JSONencoder["nodeId"] = nodeId; JSONencoder["lat"] = lat; JSONencoder["lng"] = lng; JSONencoder["version"] = v; char JSONBuffer[300]; JSONencoder.prettyPrintTo(JSONBuffer, sizeof(JSONBuffer)); Serial.println(JSONBuffer); http.begin(API); http.addHeader("Content-Type", "application/json"); int httpResponseCode = http.POST(JSONBuffer); if (httpResponseCode > 0) { String response = http.getString(); Serial.println(httpResponseCode); Serial.println(response); } else { Serial.print("Error on sending POST: "); Serial.println(httpResponseCode); } http.end(); //Free resources }

void loop() { int packetSize = LoRa.parsePacket(); if (WiFi.status() == WL_CONNECTED) { if (packetSize == PACK_SIZE_FROM_NODE || packetSize == PACK_SIZE_FROM_COLECTOR) { // received a packets display.clear(); display.drawString(0, 0, "Pacote recebido "); // read packet while (LoRa.available()) { String data = LoRa.readString(); display.drawString(0, 15, getValueInString(data, ',', 0)); display.drawString(0, 30, "Sinal:"); display.drawString(30, 30, (String)LoRa.packetRssi()); display.display(); if (packetSize == PACK_SIZE_FROM_COLECTOR) { sendData(getValueInString(data, ',', 0), getValueInString(data, ',', 4), getValueInString(data, ',', 1), getValueInString(data, ',', 2),getValueInString(data, ',', 3)); } else { sendData(getValueInString(data, ',', 0), "0", getValueInString(data, ',', 1), getValueInString(data, ',', 2),getValueInString(data, ',', 3)); } delay(3000); } } else { display.clear(); display.drawString(0, 0, "Procurando POIs..."); display.display();; } } else { display.clear(); display.drawString(0, 0, "Aguardando config. WiFi..."); display.display();; } }

String getValueInString(String data, char separator, int index) { int found = 0; int strIndex[] = { 0, -1 }; int maxIndex = data.length() - 1;

for (int i = 0; i <= maxIndex && found <= index; i++) { if (data.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i + 1 : i; } } return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; }

//callback que indica que o ESP entrou no modo AP void configModeCallback(WiFiManager *myWiFiManager){ display.drawString(0, 0, "Modo de configuração"); display.drawString(0, 15, myWiFiManager->getConfigPortalSSID()); display.display(); }

//callback que indica que salvamos uma nova rede para se conectar (modo estação) void saveConfigCallback(){ display.drawString(0, 0, "Configuração salva!"); display.display(); delay(2000); }

lethanhtung01011980 commented 4 years ago

To complement to the original post.

I understood that SX1278 can only receive ONE message at a time. So you CAN NOT receive multiple messages from multiple nodes.

When you have 2 nodes, by right, 50% - 50% for each of them.

But when I enableCrc(), it seems that the node with higher RSSI wins all the time. image

From the photo, I have 2 nodes (ESP32 + AIThinker SX1278). When node 1 (...AE60) is on, can not receive anything from node 2 (...114C)

image

By right, it should be 50%-50% chance for two nodes?

lethanhtung01011980 commented 4 years ago

So you can check if the one with higher RSSI wins the battle?

faahiero commented 4 years ago

I have issues with RSSI too. The further I move away from the gateway, the rssi increase, allowing the other node to send.

augusto3691 commented 4 years ago

i found a solution, it's not a big deal actually, i build a FIFO array in my broker...

like that:

start recieve->recieve for X seconds and store everything recieved in a array->enter in iddle->send everything to the internet and empty the array->start again...

in that way i recieve one at time and leave the connection open to recieve a N more nodes

IoTThinks commented 4 years ago

I'm doing the polling. The master polls the first node then wait a while, then polls the second node.... 99% of the messages can reach the master.

augusto3691 commented 4 years ago

I'm doing the polling. The master polls the first node then wait a while, then polls the second node.... 99% of the messages can reach the master.

This actually is a pretty good solution, are you nodes in sleep mode? And when they're call, they wake and send the data ?

IoTThinks commented 4 years ago

I'm doing the polling. The master polls the first node then wait a while, then polls the second node.... 99% of the messages can reach the master.

This actually is a pretty good solution, are you nodes in sleep mode? And when they're call, they wake and send the data ?

My nodes are always active. For sleep nodes, may be you need to let the nodes awake LONGER than one polling cycle? For example, the master takes 5s to complete polling 5 nodes regardless the nodes are active or not. When a node is active, let it active for at least 5s. Hopefully, the node can get 1 polling request for it. :D

huaminghuangtw commented 3 years ago

@IoTThinks Can you please share how you implement the "polling" from the master side? I am doing a project with 3 wifi sniffer nodes as 3 slaves. They will always be active, keeping sniffering/listening to the nearby packets data. They send the data to the server only when a specific request has been sent by the master. The workflow will be like: master send requests to slave 1 and wait for answer from slave 1 at 0~1s. When the slave 1 got the request, it will send the data to the server. Same applies to slave 2 and 3 in every second afterwards.

My problem is that not every request sent by master will be answered by the specific slave. I.e., it might request 5 times and only got 1 response, like the picture below. Also, the program became blocked forever when around 32 packets have been set to the master (Not sure if it's relevant to LoRa.endPacket()) 2020-12-21 13 54 18

The (part of) master code is:

loop()
{
if (millis() - lastRequestSentTime > 500)
{
      if (turn == 1)
      {
            SendRequest("1#");     // Send request to Client 1
            receiveFromSlaveDevice("1#");      // This is data from Client 1
            lastRequestSentTime = millis();
            // trun = 2;
            // contintues to turn 2 and 3
      }
 }

vTaskDelay( 100 / portTICK_PERIOD_MS );
}
void SendRequest( String request )
{
  LoRa.beginPacket();           // start packet
  LoRa.print(request);          // send request
  LoRa.endPacket();             // finish packet and send it

} // SendRequest
void receiveFromSlaveDevice( String nodeID )
{
  int packetSize = LoRa.parsePacket();
  if (packetSize)
  {
    Serial.println( "Received packet from: " + nodeID );

    String incomingMessage = "";                 // payload of incoming packet
    while ( LoRa.available() )
    {            
      String incomingMessage = LoRa.readString();
      // incomingMessage (WiFi device data) format: Timestamp \t MAC Address \t RSSI \n

      int pos1 = incomingMessage.indexOf('\t');
      int pos2 = incomingMessage.indexOf('\t', pos1 + 1);
      int pos3 = incomingMessage.indexOf('\n', pos2 + 1);

      std::vector<String> wifiDevicePayload(3);
      wifiDevicePayload[0] = incomingMessage.substring(0, pos1);                        // Timestamp
      wifiDevicePayload[1] = incomingMessage.substring(pos1 + 1, pos2);            // MAC Address
      wifiDevicePayload[2] = incomingMessage.substring(pos2 + 1, pos3);            // RSSI
      Serial.println("Index 1: " + wifiDevicePayload[0]);

      printWiFiDeviceData( wifiDevicePayload );
      xQueueSend( g_queueBetweenReceiveAndWebServer, &wifiDevicePayload, portMAX_DELAY ); 
    }
  }
}

The (part of) slave code is:

int packetSize = LoRa.parsePacket();
if (packetSize)
{
  while ( LoRa.available() )
  {            
    String request = LoRa.readString();
    if ( request == "1#" )
    {
      Serial.println( "Client 1 got request, answering Server..." );
      sendToMasterDevice( WiFiDeviceData );
    }
    else
    {
      Serial.println( "ERROR - No requests from Server." );
    }
  }
}

It seems there is some transition time needed for the LoRa chip to switch from sending mode to receiving mode. But there is not a function can be used to wait until a message is received... (Like RF95.waitAvailableTimeout() in RadioHead Library, http://www.airspayce.com/mikem/arduino/RadioHead/classRHGenericDriver.html#a8ed545cecc22196a325333dc9637e4cf).

Any suggestions or ideas will be of highly appreciated!

IoTThinks commented 3 years ago

I use callback to listen for LoRa packet.

For gateway, I use esp32 with 2 cores. Core 1 to listen for packet and spin off a vTask to process at core 0.

In your code, I see you process a lot of things after receiving a packet. That may make your node miss incoming packets.