DIY Camper GPS
As we travel, we wanted accurate location updates for our camper's Home Assistant — not just to see where we’ve been, but also to make sure automations respond correctly to our current location. With precise GPS data, our Home Assistant server can adjust for time zone changes, pull accurate local weather, and make sure any location-based or time-sensitive automations run exactly when they should.
Why I Needed a Dedicated GPS for the Camper
At first, I was using the GPS built into the Quectel EM12-G modem of my LTE router (a MikroTik WAP R AC), but every time the GPS was active, the LTE interface would act up. This would sometimes cause the GPS to go offline, so I had to write a script on the MikroTik to check the GPS status and restart it if it was dead — but that didn’t always work. In some cases, the GPS would stop reporting latitude, longitude, speed, and other positioning data, yet still show the data age as current, which is what I was triggering the script on. From the router’s point of view, everything looked fine, even though no usable location data was coming in. I needed a solution that gave me reliable GPS data without interfering with our internet connection, so I decided to build a dedicated GPS for the camper.
Building a Standalone GPS for the Camper
First, I flashed the ESP32 with a basic ESPHome config that didn’t include GPS. I did this so I could update the firmware over Wi-Fi remotely, without having to be inside the camper. Once that was working, I added a static IP and configured the GPS to report latitude, longitude, speed, altitude, and course. I also added logic to only update the stored coordinates when we moved more than 50 meters — this prevents small GPS drift from constantly updating Home Assistant when the camper isn’t really moving.
![]() |
| Prototype of my DIY GPS |
Here’s the full YAML I use. I keep this as a reference for myself, you are more than welcome to use it on your own build, and it also shows exactly how the GPS is configured:
esphome:
name: esphome-web-3bb178
friendly_name: camper-gps
min_version: 2025.11.0
name_add_mac_suffix: false
esp32:
variant: esp32
framework:
type: esp-idf
logger:
api:
ota:
- platform: esphome
wifi:
ssid: "!secret"
password: "!secret"
manual_ip:
static_ip: 10.0.10.206
gateway: 10.0.10.1
subnet: 255.255.255.0
uart:
id: uart_gps
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 9600
globals:
- id: last_lat
type: float
restore_value: yes
initial_value: '0.0'
- id: last_lon
type: float
restore_value: yes
initial_value: '0.0'
- id: has_fix
type: bool
restore_value: yes
initial_value: 'false'
gps:
uart_id: uart_gps
update_interval: 20s
latitude:
id: gps_lat
internal: true
longitude:
id: gps_lon
internal: true
interval:
- interval: 20s
then:
lambda: |-
if (!id(gps_lat).has_state() || !id(gps_lon).has_state()) {
return;
}
// First GPS fix
if (!id(has_fix)) {
id(last_lat) = id(gps_lat).state;
id(last_lon) = id(gps_lon).state;
id(has_fix) = true;
return;
}
// Distance calculation
const float R = 6371000.0;
float lat1 = id(last_lat) * (M_PI / 180.0);
float lon1 = id(last_lon) * (M_PI / 180.0);
float lat2 = id(gps_lat).state * (M_PI / 180.0);
float lon2 = id(gps_lon).state * (M_PI / 180.0);
float dlat = lat2 - lat1;
float dlon = lon2 - lon1;
float a = sin(dlat / 2) * sin(dlat / 2) +
cos(lat1) * cos(lat2) *
sin(dlon / 2) * sin(dlon / 2);
float distance = R * 2 * atan2(sqrt(a), sqrt(1 - a));
// Update both coordinates if moved ≥50 m
if (distance >= 50) {
id(last_lat) = id(gps_lat).state;
id(last_lon) = id(gps_lon).state;
}
sensor:
- platform: template
id: latitude_sensor
name: "Latitude"
unit_of_measurement: "°"
accuracy_decimals: 6
icon: mdi:latitude
lambda: |-
return id(last_lat);
- platform: template
id: longitude_sensor
name: "Longitude"
unit_of_measurement: "°"
accuracy_decimals: 6
icon: mdi:longitude
lambda: |-
return id(last_lon);
With this setup, the GPS feeds directly into Home Assistant and updates automatically while driving, without spamming location changes when we’re stopped as GPS data tends to "dance around" as satellites come and go and the GPS gets a lock on different ones.
Hardware Setup
The NEO-6M GPS module is connected to the ESP32 over UART, using GPIO17 for TX and GPIO16 for RX (be sure to reverse TX and RCV on the GPS module ie Tx to RCV and RCV to TX). The module uses a very small ceramic antenna that plugs directly into the GPS board, keeping the overall footprint compact.
The GPS module is powered from the 3.3V pin on the ESP32, while the ESP32 itself is powered through its USB port using a very small buck converter tied into the USB power lines. This lets me run the entire setup directly off the camper’s 12V system without needing any extra power adapters.
With the GPS separated from the router, the LTE modem is much more stable now, and the ESP32 integrates cleanly into Home Assistant using ESPHome’s API and OTA updates. That means I can update firmware, adjust sensors, or tweak logic from remote, without physically accessing the hardware.
Integration with Home Assistant
All GPS data flows straight into Home Assistant. Latitude and longitude are exposed as sensors, making them easy to use in dashboards and automations. Speed, altitude, course, satellite count, and GPS-provided time are also available.
Right now, the system updates the coordinates only when we’ve moved a significant distance, which keeps the data clean and intentional. Going forward, I plan to use Home Assistant itself to detect when the camper is parked — for example, by monitoring speed and assuming we’re stationary if it stays below 1 mph for a set amount of time — and then treating that last GPS update as the final parked location.
Lessons Learned
- Dedicated GPS is worth it: It removes reliability issues and keeps the LTE modem stable.
- My router-based GPS can lie: You can have “fresh” data age while latitude and longitude are no longer updating.
- ESPHome makes this easy: Template logic and internal variables work well for smoothing GPS updates.
- Keep a backup of your YAML: ESPHome’s dashboard sometimes hides the full config, so having a local copy saves headaches if you need to tweak the code at all.
- Flash a basic config first: Getting OTA working early lets you finish everything else from remote if you desire. In my case, the comfort of my living room instead of the camper. 😀
- Reuse what you have: I already had the ESP32, which made this solution simple and cost-effective. And having a 3d Printer allows me to make a housing for the project when I'm ready
- I still need to make it so that the GPS does one final update once the camper comes to rest for more than 10 minutes or so. Currently it can be up to 49 meters off if it updates right before I park.
How Are you Doing GPS?
How do you get GPS coordinates into your mobile Home Assistant setup? Are you running a router module, a standalone board, or some trick I haven’t discovered yet? Drop your setup below — I’m always curious how other campers keep their coordinates in check!

