Mapping my car's history with InfluxDB and VersaTiles
My Homeassistant instance tracks my car's GPS position via device_tracker.car_location and stores it in InfluxDB.
Homeassistant uses the Renault integration which talks to the same API I used for downloading my charge history.
I wanted to see all historic positions on a map -- not just the current one in Homeassistant.

The positions are only updated when a journey ends, so the data shows parking locations, not routes. Still a lot of parking positions are stored in InfluxDB.
Querying InfluxDB with Flux
The InfluxDB query uses pivot to combine the separate latitude and longitude field rows into a single row per timestamp:
from(bucket: "home_assistant") |> range(start: 2025-10-01T00:00:00Z) |> filter(fn: (r) => r._measurement == "device_tracker.car_location") |> filter(fn: (r) => r._field == "latitude" or r._field == "longitude") |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
After a few months this returns tens of thousands of rows. Server-side deduplication in Python groups them by rounded coordinates into a much smaller set of unique locations with a visit count.
I tried doing the aggregation in Flux directly (group + count), but it timed out on my Raspberry Pi 4.
The Python-side dedup is fast enough -- the bottleneck is InfluxDB scanning the rows (~2 seconds).
VersaTiles as map provider
Trying VersaTiles was on my list after I attended a talk about it last summer at FrosCon.
It's an open-source stack serving OpenStreetMap vector tiles at tiles.versatiles.org.
So no need to selfhost anything. But I could if I want to.
On the frontend it works with MapLibre GL JS.
The @versatiles/style npm package provides ready-made map styles.
Both are loaded as ES modules from jsdelivr:
<script type="module"> import maplibregl from 'https://cdn.jsdelivr.net/npm/maplibre-gl@5/+esm'; import { colorful } from 'https://cdn.jsdelivr.net/npm/@versatiles/style@5/+esm'; const style = colorful({ baseUrl: 'https://tiles.versatiles.org', language: 'de' }); const map = new maplibregl.Map({ container: 'map', style }); </script>
Important: the baseUrl parameter is required, otherwise sprites and fonts resolve as relative URLs against my own server.
The backend
The whole backend is a single Flask file with one route for the API and has only two dependencies: flask and influxdb-client.
The positions are shown as red dots with a heatmap overlay -- the heatmap weight is based on how often the car was seen at each location. Hovering a dot shows the count.
Full Code (index.html + main.py) in a gist.