I'm working on a project where I need to build an app that connects to an ESP32 using BLE. Im using the TinyGPS++ library to parse GPS data, and I want to display this information (like latitude, longitude, and altitude) on the app in real-time.
Has anyone done something similar or have any advice on how to get started with this?
a possible resource
this is what i have so far but am unsure on how to implement strings received block to receive the data from the esp32 and display next to the each corresponding label
What labels?
Upload your exported .aia file AND the .ino sketch so we can see how the data should look coming and going.
I'm posting what you have so far for our BLE and GPS experts, in phone-friendly format:
Your sketch
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <TinyGPSPlus.h>
// GPS Setup
#define RX_PIN 23 // GPS TX connected to ESP32 RX
#define GPS_BAUD 38400 // For Beitian 880Q
HardwareSerial gpsSerial(1); // UART1 for GPS
TinyGPSPlus gps;
// BLE UUIDs
#define SERVICE_UUID "adc78270-9394-4fc6-9018-f3bb18a1d3e8"
#define CHARACTERISTIC_UUID_TX "adc78272-9394-4fc6-9018-f3bb18a1d3e8" // Notify
#define CHARACTERISTIC_UUID_RX "adc78271-9394-4fc6-9018-f3bb18a1d3e8" // Write
BLECharacteristic* pTxCharacteristic;
BLEServer* pServer;
bool deviceConnected = false;
bool oldDeviceConnected = false;
// BLE Server Callback
class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) {
deviceConnected = true;
pServer->updateConnParams(param->connect.remote_bda, 0, 0x20, 0x10, 2000);
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
// RX Write Callback (optional)
class MyCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) {
std::string rxCommand = pCharacteristic->getValue();
if (rxCommand.length() > 0) {
Serial.print("Received via BLE: ");
Serial.println(rxCommand.c_str());
}
}
};
void setupBLE() {
BLEDevice::init("ESP32-GPS");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());
BLEService* pService = pServer->createService(SERVICE_UUID);
// TX Characteristic (Notify)
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
// RX Characteristic (Write)
BLECharacteristic* pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
pService->start();
pServer->getAdvertising()->start();
Serial.println("BLE service started...");
}
void setup() {
Serial.begin(115200);
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RX_PIN, -1);
setupBLE();
}
void loop() {
while (gpsSerial.available()) {
char c = gpsSerial.read();
gps.encode(c);
if (gps.location.isUpdated() && deviceConnected) {
float lat = gps.location.lat();
float lng = gps.location.lng();
float alt = gps.altitude.meters();
// Adjust to UTC-4 (if needed)
int hour = gps.time.hour() - 4;
if (hour < 0) hour += 24;
char timeStr[9];
snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", hour, gps.time.minute(), gps.time.second());
// Format data into string
char message[64];
snprintf(message, sizeof(message), "Lat:%.6f,Lon:%.6f,Alt:%.1fm,Time:%s", lat, lng, alt, timeStr);
Serial.print("[BLE Notify] ");
Serial.println(message);
// Send as notification
pTxCharacteristic->setValue((uint8_t*)message, strlen(message));
pTxCharacteristic->notify();
delay(3000); // Wait before next broadcast
}
}
// Reconnect handling
if (!deviceConnected && oldDeviceConnected) {
delay(500);
pServer->startAdvertising();
Serial.println("Waiting for client to reconnect...");
oldDeviceConnected = false;
}
if (deviceConnected && !oldDeviceConnected) {
Serial.println("Client connected!");
oldDeviceConnected = true;
}
}
Your blocks:
Your target Label names:
Your formatting code from the ino:
if (gps.location.isUpdated() && deviceConnected) {
float lat = gps.location.lat();
float lng = gps.location.lng();
float alt = gps.altitude.meters();
// Adjust to UTC-4 (if needed)
int hour = gps.time.hour() - 4;
if (hour < 0) hour += 24;
char timeStr[9];
snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", hour, gps.time.minute(), gps.time.second());
// Format data into string
char message[64];
snprintf(message, sizeof(message), "Lat:%.6f,Lon:%.6f,Alt:%.1fm,Time:%s", lat, lng, alt, timeStr);
Serial.print("[BLE Notify] ");
Serial.println(message);
// Send as notification
pTxCharacteristic->setValue((uint8_t*)message, strlen(message));
pTxCharacteristic->notify();
delay(3000); // Wait before next broadcast
}
}
So I'm guessing your incoming message is a comma delimited string, with each part of the form label:value, but I don't know how many strings it will arrive in (stringValues is a list of strings).
I'm taking a moment to code up something to handle that ...
Here's some code to distribute the readings to appropriate Labels:
BLE_Esp32 (1).aia (202.9 KB)
I added a Label to catch the entire message, for transparency, assembling whatever parts it got broken into.
I split it into strings at commas, then each string into string parts at its ':'.
I filter out each string lacking a ':', and look up its Label from the text in item 1.
I set the .Text in that Label from item 2 (the part after the ':'.)
This has not been tested.