Arduino Code for GPS Data via Lora Node to MQTT Server

Hello There, I am trying it hard to extract the GPS lat/long data from the lora receivered incoming string to publish it to MQTT server, but no idea what arduino code required to working out for this?

// This sketch displays information every time a new sentence is correctly encoded.
            
  if (Serial2.available()) {            
    String incomming =  Serial2.readString();
    Serial.println(incomming);
    double latitude;
    double longitude;
    Serial.println("********** Publish MQTT data");
char mqtt_payload[50] = "";
snprintf (mqtt_payload, 50, "m1=%lf;%lf", latitude, longitude);
Serial.print("Publish message: ");
Serial.println(mqtt_payload);
client.publish(pubTopic, mqtt_payload);
Serial.println("> MQTT data published");
Serial.println("********** End ");
Serial.println("*****************************************************");

delay(writeInterval);// delay
} else {
Serial.println(F("INVALID"));
}
}

gps_data_serial monitor_screenshot_1

For any Arduino code adding/updating help will be greatly appreciated to make it work. Thanking you.

have a look at how-to-get-the-best-out-of-this-forum
in particular what microcontroller are you using
what Lora board are you using
are you using LoRaWAN or Lora point-to-point communication
upload a schematic of your wiring

Hello @horace ! Thanks for your feedback.

in particular what microcontroller are you using
I am using ESP-32S microcontroller.

what Lora board are you using
I am using Reyax RYLR998 Lora Modules

are you using LoRaWAN or Lora point-to-point communication
I am using Lora point-to-point communication

upload a schematic of your wiring

just confirm you are receiving the GPS location OK as follows
image
and need to parse it to extract the lat/log
if so upload a sample of the received string as text (you can put dummy data in lat/long)

Hello @horace !

Please have the received string as below:

+RCV=2,20,41.000583,21.134611|,-34,11

+RCV=2,20,41.000583,00+RCV=2,20,41.000580,21.134611|,-34,11

********** Publish MQTT data

Publish message: m1=0.000000;0.000000

MQTT data published

********** End


assuming the format of the received data is consistent try using the string tokeniser, e.g.

// strtok example - parse tokens

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  char str[] = "+RCV=2,20,41.000583,21.134611|,-34,11";
  char* pch;  // pointer to tokens
  Serial.print("Splitting string ");
  Serial.print(str);
  Serial.println(" into tokens:");
  pch = strtok(str, ",=");  // get first token
  int count = 0;
  String latitude, longitude;
  while (pch != NULL) {
    Serial.print("string found ");
    Serial.println(pch);  // print it
    if (count == 3) {
      Serial.println("lat found");
      latitude = pch;
    }
    if (count == 4) {
      Serial.println("long found");
      longitude = pch;
    }
    count++;
    pch = strtok(NULL, ",|");  // get next token
  }
  Serial.print("latitude ");
  Serial.println(latitude);
  Serial.print("longitude ");
  Serial.println(longitude);
}

void loop() {}

the serial montor prints

Splitting string +RCV=2,20,41.000583,21.134611|,-34,11 into tokens:
string found +RCV
string found 2
string found 20
string found 41.000583
lat found
string found 21.134611
long found
string found -34
string found 11
latitude 41.000583
longitude 21.134611

after tokenising the Strins latitude and longitude contains the values with you can then transmit over MQTT - no need to convert to doubles

if you received packets are terminated by newline you could try

String incomming =  Serial2.readStringUntil('\n');

Hello @horace ! Thanks for keep supporting. I appreciated.

Please allow me sometime to upload and run with your provided code. Thanks.

a better alternative may be to use sscanf() and check it has converted the two values OK

// strtok example - parse tokens

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  char str1[] = "+RCV=2,20,41.000583,21.134611|,-34,11";
  double latitude, longitude;
  if (sscanf(str1, "+RCV=%*d,%*d,%lf,%lf", &latitude, &longitude) == 2) {
    Serial.println("converted two doubles OK");
    Serial.print("latitude ");
    Serial.println(latitude,10);
    Serial.print("longitude ");
    Serial.println(longitude,10);
  }
}

void loop() {}

gives

converted two doubles OK
latitude 41.0005830000
longitude 21.1346110000

if you receive corrupt data the sscanf() will fail and you don't transmit rubish over MQTT

just for interest how far apart are your transmitter and receiver?

Hello @horace ! I have tried to uplaod your first one provided code, but sorry to say that nothing happned, even got an error run time error i.e. latitude & longitude is not declared in this scope.

hello @horace ! they are just 10meter apart only to working out with them.

I guess you did not define them

String latitude, longitude;

try the sscanf() version - it is simpler and does error checking

Now i defined them as,
String latitude, longitude;

Now upload and run the code and there is no change in the serial monitor output , its just sending the same data as mentioned earlier.

try the scanf() version
if it does not work post the code

Hello @horace ! Please have review the code to fix the issue. Thanks.

#include <WiFi.h>
#include <PubSubClient.h>
#define RXD2 16
#define TXD2 17



//TODO: ESP32 MQTT user config
const char* ssid = " "; // Wifi SSID
const char* password = " "; // Wifi Password
const char* mqtt_username = "user"; // username
const char* mqtt_password = " ";
const char* pubTopic = " "; // topic
const unsigned int writeInterval = 25000; // write interval (in ms)


//MQTT config
const char* mqtt_server = "mqtt";
unsigned int mqtt_port = 1883;

// objects
WiFiClient askClient;
PubSubClient client(askClient);


// setup
void setup() {
Serial.begin(115200);
 char str1[] = "+RCV=2,20,41.000583,21.134611|,-34,11";
  double latitude, longitude;
  if (sscanf(str1, "+RCV=%*d,%*d,%lf,%lf", &latitude, &longitude) == 2) {
    Serial.println("converted two doubles OK");
    Serial.print("latitude ");
    Serial.println(latitude,10);
    Serial.print("longitude ");
    Serial.println(longitude,10);
  }

Serial.println("*****************************************************");
Serial.println("********** Program Start : ESP32 publishes GPS position to MQTT");
Serial.print("********** connecting to WIFI : ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("->WiFi connected");
Serial.println("->IP address: ");
Serial.println(WiFi.localIP());

client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);

Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);
}

// loop
void loop() {

if (!client.connected())
reconnect();
client.loop();
// This sketch displays information every time a new sentence is correctly encoded.
            
  if (Serial2.available()) {            
    String incomming =  Serial2.readString();
    Serial.println(incomming);
    
    Serial.println("********** Publish MQTT data");
char mqtt_payload[50] = "";
printf (mqtt_payload, 50, "m1=%lf;%lf", latitude, longitude);
Serial.print("Publish message: ");
Serial.println(mqtt_payload);
client.publish(pubTopic, mqtt_payload);
Serial.println("> MQTT data published");
Serial.println("********** End ");
Serial.println("*****************************************************");

delay(writeInterval);// delay
} else {
Serial.println(F("INVALID"));
}
}



//MQTT callback
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
//MQTT reconnect
void reconnect() {

// Loop until we're reconnected
while (!client.connected()) {
Serial.print("********** Attempting MQTT connection...");

// Attempt to connect
if (client.connect("ESP32Client", mqtt_username, mqtt_password)) {
Serial.println("-> MQTT client connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println("-> try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}

try

#include <WiFi.h>
#include <PubSubClient.h>
#define RXD2 16
#define TXD2 17



//TODO: ESP32 MQTT user config
const char* ssid = " ";              // Wifi SSID
const char* password = " ";          // Wifi Password
const char* mqtt_username = "user";  // username
const char* mqtt_password = " ";
const char* pubTopic = " ";                // topic
const unsigned int writeInterval = 25000;  // write interval (in ms)
//MQTT config
const char* mqtt_server = "mqtt";
unsigned int mqtt_port = 1883;

// objects
WiFiClient askClient;
PubSubClient client(askClient);


// setup
void setup() {
  Serial.begin(115200);
  Serial.println("*****************************************************");
  Serial.println("********** Program Start : ESP32 publishes GPS position to MQTT");
  Serial.print("********** connecting to WIFI : ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("->WiFi connected");
  Serial.println("->IP address: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);
}

// loop
void loop() {

  if (!client.connected())
    reconnect();
  client.loop();
  // This sketch displays information every time a new sentence is correctly encoded.

  // read packet into incomming array
  if (Serial2.available()) {
    char incomming[100] = { 0 };
    Serial2.readBytes(incomming, 100);
    Serial.print("incomming ");
    Serial.println(incomming);
    // parse incomming for lat and long
    double latitude, longitude;
    if (sscanf(incomming, "+RCV=%*d,%*d,%lf,%lf", &latitude, &longitude) == 2) {
      Serial.println("converted two doubles OK");
      Serial.print("latitude ");
      Serial.println(latitude, 10);
      Serial.print("longitude ");
      Serial.println(longitude, 10);


      Serial.println("********** Publish MQTT data");
      char mqtt_payload[50] = "";
      printf(mqtt_payload, 50, "m1=%lf;%lf", latitude, longitude);
      Serial.print("Publish message: ");
      Serial.println(mqtt_payload);
      client.publish(pubTopic, mqtt_payload);
      Serial.println("> MQTT data published");
      Serial.println("********** End ");
      Serial.println("*****************************************************");

      delay(writeInterval);  // delay
    } else {
      Serial.println(F("INVALID"));
    }
  }
}


//MQTT callback
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}
//MQTT reconnect
void reconnect() {

  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("********** Attempting MQTT connection...");

    // Attempt to connect
    if (client.connect("ESP32Client", mqtt_username, mqtt_password)) {
      Serial.println("-> MQTT client connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println("-> try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

Hello @horace ! i have uploaded and run your updated code, but sorry to say that its not working properly receiving corrupt data and mqqt server is sending error msg. Thanks.

gps_data_serial_monitor_screenshot_3

MQTT server payload output:

try replace the printf()

printf(mqtt_payload, 50, "m1=%lf;%lf", latitude, longitude);

with sprintf()

      sprintf(mqtt_payload,"m1=%lf;%lf", latitude, longitude);

you should then see the message being sent over MQTT

********** Publish MQTT data
Publish message: m1=41.000583;21.134611

Hello @horace ! Thanks a lot. fixed the issue. Now getting data smoothly at serial monitor and mqtt server. I really appreciated your support to fix the issue.

Hello @horace! Next could you please assist me a bit more further that what LoRaWAN gateway to use with many of these Reyax based remote GPS lora transmitter nodes moving at different locations to monitor the different objects' locations on a cloud based plateform? Would be any LoRaWAN gateways are compitable with this and/or need to be compitable with this Reyax based lora module required for LoRaWAN gateway? Thanking you.

as you have indicated the problem of the current thread is solved and if you are moving to a new topic perhaps you should start a new thread

which LoRa modules are you planning to use?
the rylr998 documentation does not mention LoRaWAN just long range LoRa communication
Due to its complexity LoRaWAN requires a much more powerful internal processor than simple LoRa peer-to-peer hence you find some LoRa devices do not support LoRaWAN

if the device does support LoRaWAN any Gateway of the correct frequency etc should work with it
if setting the LoRaWAN device up in a city you may well find there are Gateways in range and it just works.
If there are none you need to set up your own gateway -

  1. if you have access to local WiFi there are LoRaWAN gateways which connect to the TTN network, e.g. I have The Things Gateway and a The Things Indoor Gateway which I use when traveling
  2. there are LoRaWAN gateways with GSM Modems - you would require power which may be mains or solar etc

have a look at LoRaWAN gateways