Home Assistant: EP3 Stockholms Lokaltrafik (SL) voice enabled departures
Author
Norbert TakΓ‘cs
Date Published

The idea came upon to me one day when I was running to the bus and had to check when the next bus was going, knowing that fiddling with my phone, or any other screen make me certainly miss the bus. If I could just ask my voice assistant as I scramble around to get ready it would solve all my problems. At least in this scenario.
This script has been adjusted over the years of using it. Asking the voice assistant "When is the next bus?" results in an announcement which states over my voice assistant the following:
next bus leaves in 28, and 58 minutes, and to the mall it leaves in, 16, and 46 minutes
It picks up the two lines that are near my apartment and crafts a human understandable message.
π SL Stockholms lokaltrafik API

I cant take for-granted that I live in a city which has an open API for its public transport. This couldn't be possible without it. This is a great use of our tax money.
Open data rules because:
- developers get to build on top of the data for free (like this article)
- more eyes allow for issues and errors in API-s being caught faster. As opposed to Security through obscurity
π¦ Home assistant setup
The two add-ons that I used can be both installed from HACS, just make sure to install the newest pre-release versions wherever possible. In my case this worked with

ποΈ HASL sensor 3.2.0b2+
This project uses the new versions of the hasl-sensor it can be found on HACS just make sure to install the pre-release version. Since at the time of writing, that is the only version that works.
To use it we will need a key from developer.trafiklab.se, api we need is SL Realtidsinformation 4, grab a copy of it.
Add a new HASL integration in the Settings -> Devices & Services -> Add Integration
Fill in the UI the API key, location, select departures. Set the directions between 0,1,2
I left mine on default 0
This will create a sensor which contains the information about the upcoming departures.
π΄ HASL departure card 3.4.1+

For the UI I used the updated lovelace-hasl-departure-card.
Setting it up was easy, just add to lovelace and choose the sensor you created earlier.
π₯ Node-red setup overview

The only extra package I had to install was node-red-contrib-home-assistant-websocket in node-red. Make sure to connect it to your home assistant instance.
The node-s are laid out above on the screenshot and their breakdown is below
βΆοΈ Triggering the flow with button-node
Home assistant button node, this creates a button in home assistant. Add the timestamp node also which can be used to trigger the flow from within node-red.
The created button entity in home assistant will be used to by Alexa to trigger the flow. Id of the button can be adjusted.
Don't forget to tie this button to an action in your voice assistant.
π Payload to message with function-node
Function nodes are built into node-red and run javascript, useful for manipulating objects/arrays.
The node-red setup is rather easy,
1const payload = msg.data.attributes.departures23const buses = payload.map((bus) => {4 // Create a Date object from the specific date string5 const specificDate = new Date(bus.scheduled);67 // Get the current date and time8 const currentDate = new Date();910 // Calculate the difference in milliseconds11 const differenceInMs = specificDate.getTime() - currentDate.getTime();1213 // Convert milliseconds to minutes14 const differenceInMinutes = Math.floor(differenceInMs / (1000 * 60));1516 return {...bus, timeLeft: differenceInMinutes}1718}).filter((bus) => bus.timeLeft > 0 )1920const bus401 = buses.filter(bus => bus.line.id === 401)21const bus402 = buses.filter(bus => bus.line.id === 402)2223let getMessage = () => {24 let base = ""2526 if (bus401[0]?.timeLeft){27 base = base + `leaves in ${bus401[0].timeLeft}`28 }2930 if (bus401[1]?.timeLeft){31 base = base + `, and ${bus401[1].timeLeft} minutes`32 }3334 if (bus402[0]?.timeLeft){35 if (base) {36 base = base + `, and `37 }38 base = base + `to the mall it leaves in, ${bus402[0].timeLeft}`39 }4041 if (bus402[1]?.timeLeft){42 base = base + `, and ${bus402[1].timeLeft} minutes`43 }4445 return base46}4748return { message: getMessage()}
The script is rather crude. It does the following:
- filters hardcoded 2 busses,
401,402
in my case from the payload - calculates each bus how much time they have left and saves this in
timeLeft
property - removes the busses which have no
timeLeft
anymore - picks out first 2 busses from each bus number
- crafts the string message for the next node
I can recommend using node.error()
to log parts of the code for debugging. These messages end up in the debug tab of node-red.

π£ Message to the Voice assistant with action node

Once again we are using a node from the home assistant palette. Action node -> Action -> tts.cloud_say
with the following Jinja command
1{"message":msg.message, "entity_id": "media_player.dining_room"}
Run the full script either by triggering it from the timestamp node or by asking your voice assistant and get greeted by the following message over your speaker
next bus leaves in 28, and 58 minutes, and to the mall it leaves in, 16, and 46 minutes
Join the Discussion on github

The best touch screen I found for my home assistant dashboard. 18.5" portable IPS Full HD screen, VESA with wide viewing angles, magnet attached.

The platform is extensible by third-party add-ons where each add-on can be developed by an independent person or team published and consumed freely.