Releases: AlexanderBabel/ul-transport
Release list
UL Transport 2.3.1
Fixes the setup text shipped in 2.3.0. The strings were valid and rendered correctly, but embedded a link directly rather than as a placeholder, which Home Assistant's own hassfest rejects.
If you are on 2.3.0 the integration works — this is a validation and maintainability fix.
Fixed
- The Trafiklab link in the setup steps is passed as a description placeholder, so
hassfestvalidates again and the link lives in one place rather than in every translation. CONFIG_SCHEMAdeclares the integration config-entry-only. 2.3.0 added anasync_setupfor the key migration without it, whichhassfestwarns about.
Full changelog: 2.3.0...2.3.1
UL Transport 2.3.0
The Trafiklab keys move into a config entry of their own. Before this they lived on whichever stop happened to be set up first, so removing that stop took the live map down for every other stop on the install.
Nothing to do on upgrade: the keys are moved automatically the first time Home Assistant restarts, and the quota sensors keep their entity ids and their history.
Added
- Setup now opens by offering the live map and saying what it needs and why, with a Skip that goes straight to adding a stop. Departure sensors have never needed the keys, and the flow no longer implies otherwise.
- The keys are checked against Trafiklab before they are saved, and a refused key is reported on the field it belongs to — so the commonest mistake, the two keys swapped between the boxes, is caught at setup rather than by the map silently never appearing.
Changed
- The Trafiklab keys live in their own entry. One place to enter them, one place to edit them, and stops can be added or removed without touching them.
- The realtime and static quota sensors hang off that entry instead of moving house whenever a stop was removed. Their entity ids and history are kept.
- The per-stop options no longer show the key fields; they carry only lines and the refresh interval.
- Once the keys are set up the first question stops being asked, so adding a second stop goes straight to the search.
Full changelog: 2.2.0...2.3.0
UL Transport 2.2.0
Housekeeping against Home Assistant's integration quality scale, a proper documentation set, and the logo redrawn from UL's own vector artwork.
Added
- A diagnostics download on the integration's menu. It reports what UL advertises against what you selected — the usual reason a sensor is missing — alongside the GTFS index and quota state. The Trafiklab keys are redacted.
- Entity icons now come from
icons.json(icon translations) rather than being set in code, so they can be overridden the way any core integration's can. docs/live-map.md: every card option, the quota arithmetic and the known limitations, in one reference.- Screenshots of the card in the README.
Changed
- The logo is UL's round profile mark, rendered from the official vector at Pantone 116 C (
#FFD300). The previous bitmap carried a yellow gradient. - The coordinator is handed its config entry explicitly instead of relying on the context variable the base class falls back on.
- Both platforms declare
PARALLEL_UPDATES = 0: the coordinator owns the polling and the entities only read what it already has.
Full changelog: 2.1.0...2.2.0
UL Transport 2.1.0
Trafiklab quota tracking, a list card that fits inside that quota, and correct
direction names on the map.
Important
sensor.ul_transport_api_requests is removed and cleaned out of the entity
registry on upgrade. Repoint anything referencing it at
sensor.trafiklab_api_realtime_requests_30_days.
Added
sensor.trafiklab_api_realtime_requests_30_days(limit 30,000) and
sensor.trafiklab_api_static_requests_30_days(limit 60), on their own
Trafiklab API device. Each reports what its quota has seen over the same
trailing 30 days the quota is measured over, withlimit,remainingand
percent_usedalongside the per-feed breakdown. Counts are persisted, so a
restart no longer resets them.- A hard stop before Trafiklab's: at 30,000 realtime requests the integration
serves the feed it already has instead of collecting 429s.
Changed
- A
content: listcard refreshes every 90 seconds instead of 20 and skips the
vehicle positions feed by default — 960 requests a day left up around the
clock, against 8,640 before. Setinclude_positions: trueto get the
"already on the road" marker back. - Arrival countdowns are worked out in the browser, so they tick down by the
second between polls instead of freezing and jumping. - The card editor's refresh slider reaches 300 seconds.
Fixed
- Direction names no longer fall back to their GTFS terminus ("Uppsala
Naturstensvägen" where the UL app says "Flogsta Stenhagen"). Names are pooled
across every configured stop, and via-prefixed variants are folded onto the
destination they share.
See CHANGELOG.md for detail.
Full Changelog: 2.0.3...2.1.0
UL Transport 2.0.3
Full Changelog: 2.0.2...2.0.3
UL Transport 2.0.2
Maintenance release. Nothing about the integration's behaviour changed — 2.0.1 users gain the packaging and repository fixes below.
Fixed
manifest.jsonkey order. 2.0.1 shipped withafter_dependenciesin the wrong place, whichhassfestrejects (keys must be domain, name, then alphabetical).gtfs-realtime-bindingsraised to>=2.2.0from>=1.0.0. 1.0.0 declares no dependencies at all, so it could be installed without theprotobufthe live map's realtime feeds need. 2.2.0 declares it and leaves the version unpinned, so nothing else in Home Assistant is disturbed — and it is the version CI actually tests, which the old floor did not describe.
Added
- Brand assets under
custom_components/ul_transport/brand/, so HACS shows an icon rather than falling back to the core-only brands repository. - A
LICENSEfile. The README andpyproject.tomlalready said MIT; now the repository does too.
Changed
Repository housekeeping with no effect on the installed integration: CI actions pinned to commit SHAs and updated to current majors, Dependabot configured to keep them moving, ruff format applied and enforced in CI, and the test suite given the home-assistant-frontend wheel it needs to run outside a full Home Assistant install.
Upgrading from 2.0.1 is a straight HACS update — no configuration changes, and every entity keeps its id, history and name. If you are coming from 2.0.0, read the 2.0.1 notes as well: that release fixed the double reload on saving options, the per-request HTTP sessions, and the mangled rate-limit error.
Full changelog: 2.0.1...2.0.2
UL Transport 2.0.1
2.0.1 - 2026-08-15
Hardening release: no new features, and every entity keeps its id, its history
and its friendly name.
Fixed
- Saving options reloaded the integration twice. Both
__init__and the
sensor platform registered an update listener, so every change to lines,
interval or API keys kicked off two concurrent reloads of the same entry. - Every API call opened its own HTTP session. The coordinator, the config
flow and the static GTFS download each built anaiohttp.ClientSessionper
request and the live feed held one of its own. They now share Home
Assistant's session, which is what keeps connection pooling, the shared DNS
cache and clean shutdown working. - A rate-limited poll reported the wrong error. A catch-all handler in the
coordinator re-wrapped its ownUpdateFailed, so "UL API rate limit
exceeded" reached the log as "Unexpected error: ...". Timeouts said nothing
useful either; both now report themselves. - A malformed departure payload raised
KeyErrorout of the coordinator
instead of failing the update cleanly. - The stop search sent its query unencoded, so a stop name containing
&or
#searched for the wrong thing. - The card is now registered as a dashboard resource as well as an extra module
URL.add_extra_js_urlonly reaches a browser through a freshly rendered
index.html, so a session that loaded the page before the integration set up
showed a configuration error until a hard reload - and a kiosk tablet serving
its index from the service-worker cache never recovered at all. Resources are
fetched over the websocket every time a dashboard opens. content: listcards no longer label a bus that is out on the road "no live
data". They read the positions feed too;include_positions: falserestores
the cheaper behaviour, and now says "timetabled arrival" rather than claiming
a position is missing.
Changed
- Entities now belong to a device per stop, named after the stop, with the
refresh button and every sensor grouped under it. Renaming the device renames
its entities together. Friendly names are unchanged
(Centralstationen Line 2 to Uppsala Central), and unique ids are untouched,
so history carries over. Last Updatemoved to the diagnostic category, where a
last-successful-fetch timestamp belongs. It keeps its entity id.- The
Next departureandLast Updatesensors and the refresh button are now
named fromstrings.json, so they follow the Home Assistant language setting
(Swedish translations included). - Dropped the undeclared
async_timeoutdependency in favour of
asyncio.timeout, and stopped listingaiohttpas a requirement - Home
Assistant provides it, and declaring it failshassfest. - The coordinator is handed to the platforms through
entry.runtime_data
rather thanhass.data, so "which stops exist" is answered by the config
entry register instead of by type-sniffing a shared dict.
Added
sensor.ul_transport_api_requests. Upstream requests since Home Assistant
started, broken down per feed, withtrafiklab_totalandtrafiklab_per_hour
as the numbers the quota sees. Counts calls rather than successes: a 304 or a
429 is spent quota too.- CI on every push:
hassfest, HACS validation,ruffand the test suite. ruffconfiguration inpyproject.toml, and tests for the config and
options flows and for end-to-end entry setup, device creation, entity naming
and unload (155 tests, 81% coverage).
UL Transport 2.0.0
The integration no longer leans on an external departures card. Departures are drawn by the live map card that ships with it, and the sensors changed shape to suit automations rather than that card - see Removed.
Added
- Live map card (
custom:ul-transport-map). Shows the buses actually heading to your configured stops, with real-time position, arrival time and how many stops away they are. Has a visual editor and a live preview in the card picker. Needs two Trafiklab keys - GTFS Regional and GTFS Regional Realtime - entered once under Configure on any stop. - The card's list continues from the static timetable once the realtime feed runs dry, so
list_minutes: 1440turns it into a departure board for the whole service day at no extra request. - Assist tool.
get_next_departuresis exposed as the UL Transport departures LLM API, so a conversation agent can answer "when does the next bus go?". Its result carries a live map config for a satellite with a screen to draw. - Refresh button per stop, for pulling the departure board by hand.
Changed
- Sensor states are now the number of minutes until departure, floored, so a
numeric_statetrigger is all an automation needs. Timestamps moved to thedeparture/scheduled_departureattributes. - Polling moved to a
DataUpdateCoordinator, so all sensors for a stop share one request.
Removed
- Breaking: the departures-card sensors - ISO-timestamp states with
planned_departure_time_*attributes - are gone, along with support forha-departure-map. They are removed on upgrade. Use the live map card instead.