6 min read
I Forgot to Pay for Parking, So My Tesla Reminds Me Now
A family ice cream trip, a forgotten PAAS parking payment, and the weekend project that came out of it: TeslaMate, MQTT, and Bratislava's open parking data.

Last week we drove to the city center for ice cream with the family. Nice evening, kid happy, sun out. We found a spot, walked to I Nonni Gelateria (if you’re in Bratislava, go, it’s the real deal) and I did what I apparently always do: completely forgot that half of Bratislava is now a paid parking zone.

If you don’t live here: Bratislava has a regulated parking system called PAAS. You park on the street, you look up the zone code, and you pay in the app, on the web, or by SMS. It works fine. The problem isn’t the system. The problem is me. There are ticket machines and signs everywhere, but I was busy talking with the family and weighing much more important questions, like pistachio or hazelnut. So I walked right past all of them.

Somewhere between the second and third scoop it hit me. I paid immediately from my phone, right there at the table, and it still wasn’t fast enough. Back at the car, there was a sticker on the window warning us that we hadn’t paid. Enforcement had beaten me to it by minutes.

The car knows where it’s parked. The city publishes where the paid zones are. Why am I the integration layer?

So I built the thing that should obviously exist: a service that notices when my Tesla parks inside a PAAS zone and immediately pings my phone with the zone code, the price, and a pre-filled payment message.

The pieces were all already there

The car’s location was the easy part. I’ve been running TeslaMate self-hosted for a while, and it publishes everything over MQTT, including state and location topics per car. One non-obvious detail: there is no “parked” state. You detect parking as a transition: the state was driving, and now it’s anything else.

I briefly considered using Tesla’s Fleet API directly, but it went pay-per-use in 2025, and polling one car costs real money for something TeslaMate already does on my own hardware for free.

The zones were the part I expected to be painful, and it turned out to be the nicest surprise of the whole project. The paas.sk map and the official PAAS app are both open source, and they load their data from the city’s public ArcGIS server. There’s a layer called UDR_P with every paid street segment as a polygon, including the zone code, the hourly price, the weekend tariff, and the regulated hours as text. No API key, no auth, no scraping. You can even ask the server directly “which zone is this GPS point in?”

Even better: zones that are planned but not yet launched are already in the data with status: inactive. So the service refreshes once a day, and when the city flips a zone to active, it just starts working. Hats off to Bratislava’s city hall developers: this is what open data is supposed to look like.

The gotchas

The service itself is small: one Python container next to TeslaMate, subscribed to MQTT, doing a point-in-polygon test against the cached zone data. But a few details were fun:

Regulated hours are display text. The data says things like workdays 12-24, sunday 18-24. That’s meant for humans, not machines. Luckily the whole city currently uses only six distinct patterns, so I parse them with a tiny grammar. If the city ever invents a pattern my parser doesn’t understand, the affected zone is treated as always paid and a warning is logged. Failing safe means the worst case is an unnecessary reminder, never a missed one.

Public holidays are not workdays. “Workdays 12-24” zones are free on national holidays, so I used the holidays package instead of hardcoding dates.

Geometry is weird. My first test used a polygon’s centroid as the “obviously inside” point. But the street segment was banana-shaped, and the centroid of a banana is not inside the banana. Shapely’s representative_point() exists precisely for this.

GPS is fuzzy. The zone polygons trace street segments, not parking bays, so a car parked at the curb can land a few meters outside the polygon. If nothing matches exactly, the service retries with a ~15 meter buffer and phrases the notification as “you’re near zone SM1, double-check.”

All of this (research, code, tests, a live run against real city data) took about two hours of actual work with Claude Code, from “I keep forgetting to pay for parking” to a container running next to TeslaMate.

What it does now

I park, and a few seconds later my phone buzzes:

💶 Paid parking: zone NM2
You parked on Sliačska (NM2, Nové Mesto). Payment required now.
Tariff: 1 €/h (workdays 12-24, sunday 18-24)
Pay by SMS to 2200: "NM2 BL123AB 1", in the PAAS app, or at paas.sk

And if I park on a Saturday in a workdays-only zone, it tells me it’s free right now, and when the paid hours start. That one came straight from the ice cream incident: it was the “wait, is this even paid at this hour?” confusion that made the whole thing feel necessary.

There’s no automatic payment, by design. PAAS has no public payment API (hourly tickets run through a partner platform), and honestly, I don’t want a daemon with my credit card. A one-tap reminder is the right amount of automation: the machine does the remembering, I do the paying.

Notifications are the honest MVP of automation: do the remembering, leave the deciding.

The whole thing is maybe 400 lines of Python, runs as one more container in my TeslaMate compose stack, and the code is on GitHub. It’s the kind of project that only became reasonable because everyone else did the hard parts: TeslaMate solved the car, the city solved the data, ntfy solved the phone. I just had to stop being the integration layer.

Next time we go for ice cream, the only thing I want to worry about is whether three scoops was a mistake.