Search code examples
arduinogpsarduino-unoarduino-esp8266app-inventor

Connecting ESP8266 (NodeMCU) with Android app (MIT APP inventor) especially the longitude and latitude from a gps module


This is the value of latitude and longitude in my serial Arduino.

enter image description here]1

This is my example design in Mit App inventor enter image description here

This is the blocks of my design in Mit app enter image description here

Gps Code:

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

static const int RXPin = 3, TXPin = 4;
static const uint32_t GPSBaud = 9600;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

void setup(){
  Serial.begin(9600);
  ss.begin(GPSBaud);
}

void loop(){
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0){
    gps.encode(ss.read());
    if (gps.location.isUpdated()){
      Serial.print("Latitude= "); 
      Serial.print(gps.location.lat(), 6);
      Serial.print(" Longitude= "); 
      Serial.println(gps.location.lng(), 6);
    }
  }
}

Nodemcu Esp8266

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>

const char* host = "GPS_NodeMCU";
const char* ssid = "GPS_BOT";

ESP8266WebServer server(80);

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


// Connecting WiFi

  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid);
// Starting WEB-server

     server.on ( "/", HTTP_handleRoot );
     server.onNotFound ( HTTP_handleRoot );
     server.begin();    

}

void loop() {
  server.handleClient();
   delay(50);
}

void HTTP_handleRoot(void) {

if( server.hasArg("State") ){
       Serial.println(server.arg("State"));
  }
  server.send ( 200, "text/html", "" );
}

How to send the value of latitude and longitude in my serial using Arduino to my Map in my android application created in Mit App. The connection is using nodemcu esp8266.

Is it Possible to do?. Sorry, I'm just a beginner in the Arduino :) :)


Solution

  • There are many ways to implement this but roughly speaking there are several problems to solve:

    1. Read GPS data and make this accessible remotely
    2. Fetch the data in the MIT app
    3. (Bonus - part of the question in the comment) Lookup the address for the co-ordinates and display in the map

    The example below implements a minumum solution and assumes that the MIT app has access to the ESP8266 on the same network.

    Read GPS data and make this accessible remotely

    The ESP8266 can read the GPS data in a loop and make this accessible via the ESP8266WebServer. Here we implement a REST endpoint that returns the location as a JSON payload. So this location is available when a client does an HTTP GET on http://esp8266-ip-address/location.

    You can test this with:

    curl -XGET http://esp8266-ip-address/location
    

    The key to combining the GPS and web server code is to combine the code in loop() and ensure that it is non-blocking. This allows both functions to do their tasks. e.g.

    void loop() {
      server.handleClient();
      handleGpsData();
    }
    
    void handleGpsData() {
      while (ss.available() > 0) {
        gps.encode(ss.read());
        printGpsLocation();
      }
    }
    

    The full example Arduino code for this is:

    #include <ESP8266WiFi.h>
    #include <ESP8266WebServer.h>
    #include <ArduinoJson.h>
    #include <TinyGPS++.h>
    #include <SoftwareSerial.h>
    
    ESP8266WebServer server(80);
    
    struct GpsLocation {
      float latitude;
      float longitude;
    };
    
    StaticJsonDocument<200> GpsLocationJson;
    
    static const int RXPin = 3, TXPin = 4;
    static const uint32_t GPSBaud = 9600;
    
    TinyGPSPlus gps;
    
    SoftwareSerial ss(RXPin, TXPin);
    
    const char* SSID = "GPS_NodeMCU";
    const char* PASSWORD = "GPS_BOT";
    
    void setup() {
      Serial.begin(115200);
      ss.begin(GPSBaud);
    
      Serial.print("Connecting to ");
      Serial.println(SSID);
      WiFi.begin(SSID, PASSWORD);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
    
      Serial.print("Connected. IP address: ");
      IPAddress ipAddress = WiFi.localIP();
    
      Serial.println(ipAddress);
    
      server.on("/location", handleLocation);
      server.begin();
    }
    
    void loop() {
      server.handleClient();
      handleGpsData();
    }
    
    void handleGpsData() {
      while (ss.available() > 0) {
        gps.encode(ss.read());
        printGpsLocation();
      }
    }
    
    void printGpsLocation() {
      if (gps.location.isUpdated()) {
        Serial.print("Latitude =");
        Serial.print(gps.location.lat(), 6);
        Serial.print(" Longitude = ");
        Serial.println(gps.location.lng(), 6); 
      }
    }
    
    void handleLocation()
    {
      auto requestMethod = server.method();
      if (requestMethod == HTTP_GET)
      {
        sendLocation();
      }
    }
    
    void sendLocation() {
      if (isGpsDataValid()) {
        auto location = getGpsLocation();
        GpsLocationJson["latitude"] = location.latitude;
        GpsLocationJson["longitude"] = location.longitude;
    
        String jsonString;
        serializeJson(GpsLocationJson, jsonString);
    
        server.send(200, "application/json", jsonString);
      } else {
        Serial.println("404: No GPS co-ordinates");
        server.send(404);
      }
    }
    
    bool isGpsDataValid() {
      return gps.location.isValid();
    }
    
    struct GpsLocation
    getGpsLocation() {
      struct GpsLocation gpsLocation = {
        gps.location.lat(),
        gps.location.lng()
      };
    
      return gpsLocation;
    }
    

    Fetch the data in the MIT app

    The MIT App Inventor has a Web Connectivity component that can query the REST endpoint that was created in the previous step.

    As an example, create a screen with these components:

    • text box
    • button
    • map
    • map marker
    • web connectivity

    The text box allows you to enter the IP address of the ESP8266.

    Pressing the button retrieves the location from the ESP8266, pans the map location and moves the map marker.

    See screenshots below. The example app has been published to http://ai2.appinventor.mit.edu/?galleryId=5471748170055680

    The screen components:

    enter image description here

    Initialize the co-ordinates and create some helper procedures to manipulate co-ordinates and move the marker:

    enter image description here

    Handle the button click and the response from the ESP8266:

    enter image description here

    Lookup the address for the co-ordinates and display in the map

    This part was asked as a question in the comment.

    There are many services to reverse geocode the co-ordinates. One example is the Open Street Map Nominatim API.

    This provides a simple GET endpoint that can be used like:

    https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=-34.44076&lon=144
    

    The display_name property in the response has a formatted address.

    This can be used by adding a second web connectivity component to the MIT app inventor screen. This component is named ReverseGeocode in this example.

    Then create a function to get the address from the API:

    enter image description here

    and handle the response from the API:

    enter image description here

    Finally, modify the code that handles the response from the ESP8266 to invoke the new function:

    enter image description here

    The example code for this step is available at http://ai2.appinventor.mit.edu/?galleryId=5471748170055680#5320688868655104

    Screenshot of the app:

    enter image description here