I recently installed NSPanel Blueprint and one of the must-have features for me was to display public transportation timetables in nspanel.
Unfortunately, there is no ready-to-use page with transport timetables available.
The source of data in my case is hslhrt-hass-custom integration with HSL/HRT - Helsinki Regional Transport Authority. But the same approach can be used with other sources of transport data.
Step 1: bring the data into Home Assistant
In case of HSL/HRT this is simply about installing and configuring hslhrt-hass-custom integration. You also need to register in the digitransit service and receive an API key (free of charge).
This step is pretty trivial - just follow instructions from the hslhrt-hass-custom github.
Validate that you have the sensors with the name of the stop. E.g., sensor.kauniainen_ka0101_all
and that these sensors have attributes with the data you need to display in the nspanel (formatted in a totally different way of course).
Step 2: activate python integration in Home Assistant
Add the line
python_script:
to configuration.yaml
and restart Home Assistant.
Create directory python_scripts
in the folder where configuration.yaml
is located.
Step 3: develop python script which formats the data for nspanel
NSPanel Blueprint has an entity page and it can be used for displaying public transport timetable.
This is how my timetable looks in nspanel after the configuration is done:
Every line represents a stop. But in order to display this data we need to make a small hack: we need to create a sensor with friendly name containing the long text (departure times) and to put the shorter text (destination) into value.
E.g., in the image above we have three elements in every transport table row:
- Icon (
mdi:bus
ormdi:train
), set in the NSPanel Blueprint entity page configuration. - Long string with departure times. This is the friendly name of the sensor we’ll create later using python script.
- Short string with the destination name. This is the sensor’s value!
So, now we need to really format this data - create sensors which we can later configure to b e displayed in the entity page.
python_scripts/create_hsl_nspanel_timeteable.py
:
# Parse key/value in a format (example): "DESTINATION: Jorvi via Kauniainen"
def parse_kv(kv):
lst = kv.split(":")
key = lst[0].strip()
value = ":".join(lst[1:]).strip("' ")
return [key, value]
# Creates a route description in the format
# "HH:MM route" (if cut_hours is False)
# OR
# ":MM route" (if cut_hours is True)
def fmt_route(route, tm, cut_hours=False):
# tm: HH:MM:SS
hh_mm_lst = tm.split(":")[:2]
tm_str = ""
if not cut_hours:
tm_str = hh_mm_lst[0]
tm_str = tm_str + ":" + hh_mm_lst[1]
return f"{tm_str} {route}"
# Returns a string: time_route ("," time_route){1,n} where time_route is "HH:MM ROUTE"
def fmt_n_departures(route, arrival_tm, routes, n=3):
# Maximal length of the output string - otherwise it doesn't fit to EU nspanel
max_chars_qty = 28
res = fmt_route(route, arrival_tm)
prev_hour = arrival_tm.split(":")[0]
sep = ", "
for r in routes[: n - 1]:
curr_hour = r["ARRIVAL TIME"].split(":")[0]
cut_hour = curr_hour == prev_hour
next_route = fmt_route(r["ROUTE"], r["ARRIVAL TIME"], cut_hour)
if len(res) + len(sep) + len(next_route) <= max_chars_qty:
res += sep + next_route
else:
break
prev_hour = curr_hour
return res
# names of the HSL/HRT integration sensors (without prefix "sensor.")
entity_ids = [
"replace_with_yours",
"replace_with_yoursl",
"replace_with_yoursl",
# Example!
"kauniainen_ka0101_all",
]
for entity_id in entity_ids:
nm = "sensor." + entity_id
state = hass.states.get(nm)
if state:
route = state.attributes.get("ROUTE")
dest = state.attributes.get("DESTINATION")
# We limit the max. length of a destination field to fit into EU nspanel
max_dest_len = 15
if len(dest) > max_dest_len:
if " " in dest:
dest = dest.split(" ")[0]
arr_tm_first = state.attributes.get("ARRIVAL TIME")
routes = state.attributes.get("ROUTES", "")
next_departures = fmt_n_departures(route, arr_tm_first, routes)
hass.states.set(
nm + "_next_departures", dest, {"friendly_name": next_departures}
)
If you want to display HSL/HRT timetable, then you can just use the same script and modify the entity_ids
values to match those you have configured in hslhrt-hass-custom integration.
If your data provider is different, you need to modify the script to parse your data format.
The idea of the script is pretty obvious - for every hslhrt
sensor XYZ
with the raw schedule data, it creates a sensor with the name XYZ_next_departures
. This sensor’s friendly name has a real timetable for the stop and the value is set to the destination.
Useful docs about python scripts in Home Assistant: https://www.home-assistant.io/integrations/python_script/
Step 4: update our custom sensors when the raw data is updated
Now you can call this script from Home Assistant by calling an action: python_script.create_hsl_nspanel_timeteable
Setup an automation to call the python_scripts/create_hsl_nspanel_timeteable.py
when the raw data is changed:
alias: HSLHRT nspanel page updater
description: "Update HSL/HRT page in the nspanel "
trigger:
- platform: state
entity_id:
# List all your hslhrt sensors here!!!
- sensor.kauniainen_ka0151_all
condition: []
action:
- action: python_script.create_hsl_nspanel_timeteable
metadata: {}
data: {}
mode: single
Step 5: configure NSPanel Blueprint
Now the easiest part: configure these new sensors to be displayed in your entity page.
That’s it!
Have fun!