Semua Tentang Belajar Teknologi Digital Dalam Kehidupan Sehari - Hari

Sabtu, 15 Juni 2024

IOT - GPS dengan bantuan apps smartphone netGPS

 


Kalau kita kembali belajar IOT di awal-awal maka akan dikenalkan dengan yang namanya piramida IOT. Bagian paling ujung dari piramida ini adalah pelaporan ke orang yang akan membutuhkan informasi melalui IOT. Salah satu contoh pelaporan adalah GIS (Geographic Information System) dimana data yang diambil oleh sensor dan dikirimkan secara IOT akan ditampilkan pada peta. Tentunya cuap-cuap saya diawal ini akan terasa omong kosong kalau alat GPS nya seperti yang pernah saya bahas disini, susah di koneksikan...ala mak jang !

Sadar atau tidak sadar, pada kenyataannya, smartphone yang kita pakai mesti ada penerima GPS lho mas broo ! nah..benda yang selalu kita pegang tiap saat ini seharusnya dan pastinya dapat memberikan koordinat bujur dan lintang selama berada pada lokasi terbuka. Masalahnya bagaimana cara membagi pembacaan hardware GPS pada smartphone android ke perangkat IOT? 



Aplikasi android yang saya gunakan adalah netGPS yang akan mengirimkan data GPS secara TCP (berfungsi sebagai TCP server) dan mengirimkan sebagai teks log dari berbagai macam standar data GPS yang digunakan oleh smartphone android. Aplikasi ini cukup jadul jadi jika ingin menginstallnya harap gunakan cara selain google play jika ternyata HP kamu ditolak.




Contoh standar pembacaan teks NMEA (National Marine Electronics Association)  yang saya gunakan sederhana saja cukup sebaris ( karena saya butuhnya hanya koordinat saja) dan saya pilihkan standar $GPRMC. Saya butuh membayar 15ribu rupiah ke aplikasi ini untuk dapat memilih secara custom pesannya seperti pada gambar diatas. Dari sebuah website saya dapatkan standar pesannya adalah sebagai berikut:


$GPRMC

Recommended minimum specific GPS/Transit data

eg1. $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
eg2. $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68

225446 Time of fix 22:54:46 UTC A Navigation receiver warning A = OK, V = warning 4916.45,N Latitude 49 deg. 16.45 min North 12311.12,W Longitude 123 deg. 11.12 min West 000.5 Speed over ground, Knots 054.7 Course Made Good, True 191194 Date of fix 19 November 1994 020.3,E Magnetic variation 20.3 deg East *68 mandatory checksum

Dan kemudian saya parsing data dari teks $GPRMC, namun karena saya tukang koding abal-abal, butuh bantuan chatGPT dan hasilnya saya diberikan script yang sangat jitu !


#include <ESP8266WiFi.h>

const char* ssid = "YourHotspotSSID";
const char* password = "YourHotspotPassword";

// Example NMEA GPRMC string
String nmeaString = "$GPRMC,043652,A,0713.64753,S,11243.78,E,,,290524,000.7,E,A*33";

void setup() {
  Serial.begin(115200);
  parseNMEA(nmeaString);
}

void loop() {
  // No code needed here for this example
}

double convertNMEACoordinate(String nmeaCoord, bool isLongitude) {
  // Determine the length of degrees part (3 for longitude, 2 for latitude)
  int degreesLength = isLongitude ? 3 : 2;
  // Extract the degrees part
  double degrees = nmeaCoord.substring(0, degreesLength).toInt();
  // Extract the minutes part and convert to decimal
  double minutes = nmeaCoord.substring(degreesLength).toFloat();
  degrees += minutes / 60.0;
  return degrees;
}

void parseNMEA(String nmea) {
  // Check if the string starts with "$GPRMC"
  if (nmea.startsWith("$GPRMC")) {
    // Buffer for each field in the NMEA string
    char buf[75];
    nmea.toCharArray(buf, 75);

    // Tokenize the NMEA string by comma
    char* token = strtok(buf, ",");
    
    // Index to track the position in the NMEA string
    int index = 0;
    
    // Variables to hold parsed data
    String time, status, latitude, latitudeDirection;
    String longitude, longitudeDirection, date;

    while (token != NULL) {
      switch (index) {
        case 1: time = String(token); break;
        case 2: status = String(token); break;
        case 3: latitude = String(token); break;
        case 4: latitudeDirection = String(token); break;
        case 5: longitude = String(token); break;
        case 6: longitudeDirection = String(token); break;
        case 9: date = String(token); break;
      }
      token = strtok(NULL, ",");
      index++;
    }

    // Convert latitude and longitude
    double latitudeDegrees = convertNMEACoordinate(latitude, false);
    if (latitudeDirection == "S") {
      latitudeDegrees = -latitudeDegrees;
    }

    double longitudeDegrees = convertNMEACoordinate(longitude, true);
    if (longitudeDirection == "W") {
      longitudeDegrees = -longitudeDegrees;
    }

    // Prepare buffer for formatted longitude
    char longitudeStr[20];
    dtostrf(longitudeDegrees, 1, 7, longitudeStr);

    // Prepare buffer for the final concatenated string
    char resultStr[40];  // Adjust size based on expected combined length
    strcpy(resultStr, "latitude ");
    strcat(resultStr, longitudeStr);

    // Print the parsed data
    Serial.println("Time: " + time);
    Serial.println("Status: " + status);
    Serial.print("Latitude: ");
    Serial.println(latitudeDegrees, 7);
    Serial.print("Longitude: ");
    Serial.println(longitudeDegrees, 7);
    Serial.print("Concatenated String: ");
    Serial.println(resultStr);  // Print concatenated string
    Serial.println("Date: " + date);

    // Convert and print additional data if necessary
    // Convert time to HH:MM:SS format
    String hours = time.substring(0, 2);
    String minutes = time.substring(2, 4);
    String seconds = time.substring(4, 6);
    Serial.println("Formatted Time: " + hours + ":" + minutes + ":" + seconds);

    // Convert date to DD/MM/YY format
    String day = date.substring(0, 2);
    String month = date.substring(2, 4);
    String year = date.substring(4, 6);
    Serial.println("Formatted Date: " + day + "/" + month + "/" + year);
  } else {
    Serial.println("Invalid NMEA string");
  }
}

Penjelasan:

1. Function konversi NMEA  (convertNMEACoordinate): 

  • Mengonversi koordinat NMEA ke format derajat desimal.


2. Function Penguraian (parseNMEA):

  • Memberi token pada string NMEA dan mengekstrak bidang yang relevan.
  • Mengonversi lintang dan bujur menjadi derajat desimal.
  • Menyesuaikan tanda berdasarkan arah (N/S untuk garis lintang, E/W untuk garis bujur).

3. Memformat Bujur/Lintang:

  • Fungsi dtostrf memformat garis bujur/lintang menjadi string dengan 7 tempat desimal.

4. Concatenate string:

  • Buffer resultStr disiapkan untuk menampung hasil gabungan.
  • Fungsi strcpy menginisialisasi resultStr dengan label "latitude".
  • Fungsi strcat menambahkan string garis bujur yang diformat ke resultStr.

5. Print / output :

  • String gabungan dicetak ke Serial Monitor.

Kode ini mem-parsing string NMEA GPRMC, mengubah garis lintang dan garis bujur menjadi derajat desimal, memformat garis bujur menjadi string dengan 7 tempat desimal, dan menggabungkannya dengan label longitude dan latitude. String gabungan kemudian dicetak pada serial monitor.




Untuk menerima pesan $GPRMC dari smartphone, saya akan membuat ESP8266-wemos saya sebagai client dan terhubung dengan hotpsot dari Smartphone yang saya gunakan. Hal ini akan memudahkan saya karena Smartphone saya fungsikan sebagai TCP server di IP Gatewaynya ( 192.168.43.1) pada port yg saya pilih 8088. IP ini adalah IP umum yang digunakan oleh hotspot smartphone android, namun sudah saya akali pada script agar TCP server yang di-bind-kan adalah IP gatewaynya, selanjutnya menunggu data GPS berupa teks $GPRMC.


/* GPS SMARTPHONE (netGPS Android) to ESP8266
Hardware : DHT 11 & OLED SSD1306 128x64
This script is incomplete, you should add data sending 
via IOT protocol, MQTT, HTTP  or Lora
www.aisi555.com 
*/


#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "DHT.h"


#define SCREEN_WIDTH 128 // display display width, in pixels
#define SCREEN_HEIGHT 64 // display display height, in pixels

#define DHT_PIN D4   // pin sensor DS18B20


#define display_RESET     -1 // Reset pin 
#define SCREEN_ADDRESS 0x3C ///address i2c oled 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, display_RESET);



#define DHTTYPE DHT11  //Sensor DHT11
DHT dht(DHT_PIN, DHTTYPE); 


const char* ssid = "myHotspot";
const char* password = "99999999";

// Server details
IPAddress serverIP;  // Define server IP address (gateway IP)
const uint16_t serverPort = 8088;

WiFiClient client;

bool gpsOK = false;
char longitudeStr[20];
char latitudeStr[20];

void setup() {
  Serial.begin(9600);
   Serial.println("");
  Serial.println(F(" ...www.aisi555.com GPS From Smartphone ...."));

    // initialize display display with address 0x3C for 128x64
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    while (true);
  }

  delay(2000);         // wait for initializing
  display.clearDisplay(); // clear display

  
  display.setTextSize(1);          // text size
  display.setTextColor(WHITE);     // text color
  
  displayDisplayCenter("www.aisi555.com", 4);
  displayDisplayCenter("Connecting to wifi.. ",56);

  
    // Connect to Wi-Fi network
  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());
  delay(1000);



  display.clearDisplay(); // clear display
  displayDisplayCenter("www.aisi555.com", 4);
  displayDisplayCenter("Connecting to Aps..",56);
  
  IPAddress gatewayIP = WiFi.gatewayIP();
  serverIP = gatewayIP;  // Use the gateway IP as server IP

  // Attempt to connect to the server
  if (!client.connect(serverIP, serverPort)) {
    Serial.println("Connection to server failed");
  } else {
    Serial.println("Connected to server");
  }


  dht.begin();

  
}


void writeTempHumid(){ //kirim data pengukuran DHT
   
 
    float h = dht.readHumidity();
    float t = dht.readTemperature();

    if (isnan(h) || isnan(t)) {
      Serial.println("Failed to read from DHT sensor!");
    }
    
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" °C ");
  
    String tempString;
  
    tempString  = String(t, 1); // 
    tempString += (char)247;
    tempString += "C | ";
    tempString += String(h, 0);;
    tempString += " %";
  
    //biar ketumpuk hitam dulu biar bersih

    display.fillRect(0,17,128,48,BLACK);
    
  //lanjut tulis warna putih
   display.setTextColor(WHITE);
   
   String latString;
   latString  = "Lat: ";
   latString += String(latitudeStr);
   displayDisplayCenter(latString,20);

   String lonString;
   lonString  = "Lon: ";
   lonString += String(longitudeStr);
   displayDisplayCenter(lonString,30);
   displayDisplayCenter(tempString,42);

   if(gpsOK)displayDisplayCenter("GPS is Connected",56);
   else displayDisplayCenter("GPS disconnected !",56);


   /* ADD YOUR IOT DATA SENDING SCRIPT BELOW  */
   
  }


void loop() {

  if (runEvery(5000)) {
    writeTempHumid();
  }
  
  if (client.connected()) {
    // Check if data is available to read
    
    gpsOK=true;
    
    while (client.available()) {
      String receivedData = client.readStringUntil('\n');  // Read data until newline
      Serial.print("Received data: ");
      Serial.println(receivedData);

      // Process the received data
      // Add your data processing logic here

      parseNMEA(receivedData);
    }
  } else {
    // Reconnect if connection is lost
    if (!client.connect(serverIP, serverPort)) {
      Serial.println("Reconnection to server failed");
      gpsOK=false;
      delay(1000);  // Wait before retrying
    } else {
      Serial.println("Reconnected to server");
    }
  }
}

//function agar tulisan rata tengah (center)

void displayDisplayCenter(String text, int posisi) {
  int16_t x1;
  int16_t y1;
  uint16_t width;
  uint16_t height;

  display.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);

  display.setCursor((SCREEN_WIDTH - width) / 2, posisi);
  display.println(text); // text to display
  display.display();
}



double convertNMEACoordinate(String nmeaCoord, bool isLongitude) {
  // Determine the length of degrees part (3 for longitude, 2 for latitude)
  int degreesLength = isLongitude ? 3 : 2;
  // Extract the degrees part
  double degrees = nmeaCoord.substring(0, degreesLength).toInt();
  // Extract the minutes part and convert to decimal
  double minutes = nmeaCoord.substring(degreesLength).toFloat();
  degrees += minutes / 60.0;
  return degrees;
}

void parseNMEA(String nmea) {
  // Check if the string starts with "$GPRMC"
  if (nmea.startsWith("$GPRMC")) {
    // Buffer for each field in the NMEA string
    char buf[75];
    nmea.toCharArray(buf, 75);

    // Tokenize the NMEA string by comma
    char* token = strtok(buf, ",");
    
    // Index to track the position in the NMEA string
    int index = 0;
    
    // Variables to hold parsed data
    String time, status, latitude, latitudeDirection;
    String longitude, longitudeDirection,date;

    while (token != NULL) {
      switch (index) {
        case 1: time = String(token); break;
        case 2: status = String(token); break;
        case 3: latitude = String(token); break;
        case 4: latitudeDirection = String(token); break;
        case 5: longitude = String(token); break;
        case 6: longitudeDirection = String(token); break;
        case 9: date = String(token); break;
      }
      token = strtok(NULL, ",");
      index++;
    }

    // Convert latitude and longitude
    double latitudeDegrees = convertNMEACoordinate(latitude, false);
    if (latitudeDirection == "S") {
      latitudeDegrees = -latitudeDegrees;
    }

    double longitudeDegrees = convertNMEACoordinate(longitude, true);
    if (longitudeDirection == "W") {
      longitudeDegrees = -longitudeDegrees;
    }

    //kirim ke display 
    dtostrf(longitudeDegrees, 1, 7, longitudeStr);
    dtostrf(latitudeDegrees, 1, 7, latitudeStr);
    

    // Print the parsed data
    Serial.println("Time: " + time);
    Serial.println("Status: " + status);
    Serial.print("Latitude: ");
    Serial.println(latitudeDegrees, 7);
    Serial.print("Longitude: ");
    Serial.println(longitudeDegrees, 7);
    Serial.println("Date: " + date);

    // Convert and print additional data if necessary
    // Convert time to HH:MM:SS format
    String hours = time.substring(0, 2);
    String minutes = time.substring(2, 4);
    String seconds = time.substring(4, 6);
    Serial.println("Formatted Time: " + hours + ":" + minutes + ":" + seconds);

    // Convert date to DD/MM/YY format
    String day = date.substring(0, 2);
    String month = date.substring(2, 4);
    String year = date.substring(4, 6);
    Serial.println("Formatted Date: " + day + "/" + month + "/" + year);
  } else {
    Serial.println("Invalid NMEA string");
  }
}

//timer
boolean runEvery(unsigned long interval)
{
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;
    return true;
  }
  return false;
}

Dan jika script kamu benar dapat mengirimkan data GPS menggunakan lorawan seperti berikut :
 


Dan kemudian pengolahan data GIS nya kita dapat manfaatkan google maps atau yang secara online yaitu kepler.gl (lihat gambar paling atas). Keberhasilan pengaplikasian trik saya ini sangat bergantung pada sensitifitas GPS receiver pada smartphone, sehingga syarat mutlak adalah HP kamu berada pada lokasi yg open space / langit terbuka.

SELAMAT MENCOBA
Share:

0 komentar:

Posting Komentar

Kontak Penulis



12179018.png (60×60)
+628155737755

Mail : ahocool@gmail.com

Site View

Categories

555 (8) 7 segmen (3) adc (4) amplifier (2) analog (19) android (12) antares (11) arduino (26) artikel (11) attiny (3) attiny2313 (19) audio (5) baterai (5) blog (1) bluetooth (1) chatgpt (2) cmos (2) crypto (2) dasar (46) digital (11) dimmer (5) display (3) esp8266 (26) euro2020 (13) gcc (1) iklan (1) infrared (2) Input Output (3) iot (68) jam (7) jualan (12) kereta api (1) keyboard (1) keypad (3) kios pulsa (2) kit (6) komponen (17) komputer (3) komunikasi (1) kontrol (8) lain-lain (8) lcd (2) led (14) led matrix (6) line tracer (1) lm35 (1) lora (11) MATV (1) memory (1) metal detector (4) microcontroller (70) micropython (6) mikrokontroler (1) mikrokontroller (14) mikrotik (5) modbus (9) mqtt (3) ninmedia (5) ntp (1) paket belajar (19) palang pintu otomatis (1) parabola (88) pcb (2) power (1) praktek (2) project (33) proyek (1) python (8) radio (28) raspberry pi (9) remote (1) revisi (1) rfid (1) robot (1) rpm (2) rs232 (1) script break down (3) sdcard (3) sensor (2) sharing (3) signage (1) sinyal (1) sms (6) software (18) solar (1) solusi (1) tachometer (2) technology (1) teknologi (2) telegram (2) telepon (9) televisi (167) television (28) transistor (2) troubleshoot (3) tulisan (93) tutorial (108) tv digital (6) tvri (2) vu meter (2) vumeter (2) wav player (3) wayang (1) wifi (3) yolo (7)

Arsip Blog

Diskusi


kaskus
Forum Hobby Elektronika