-
-
Notifications
You must be signed in to change notification settings - Fork 20
06: Visualizing the data
Once GTFS has been configured, Home Assistant has entities packed with public transit data that you can use to visualize that data.
Using 'multiple entity row' card with pop-up:

Clicking on the card would show details (though this example is not synced on data):
type: entities
entities:
- entity: sensor.653_mouans_sophia
type: custom:multiple-entity-row
state_header: RealTime
attribute: next_departure_realtime
name: Mouans > Sophia 653
format: time
secondary_info: last-updated
entities:
- entity: sensor.653_mouans_sophia
attribute: day
name: Day
format: time
- entity: sensor.653_mouans_sophia
name: 653
format: time
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
content:
type: custom:button-card
entity: sensor.653_mouans_sophia
show_icon: false
show_state: true
show_name: false
tap_action: none
styles:
grid:
- grid-template-areas: "\"next\" \"s\""
custom_fields:
next:
- font-size: 20px
- font-weight: bold
custom_fields:
next: |
[[[ return 'Next departures :' ]]]
state_display: |
[[[
return entity.attributes.next_departures.map((entry) => {
return '<br>' + [ helpers.formatShortDateTimeWithYear(entry) ] ;
} ).join("").toString();
]]]
- entity: sensor.653_mouans_antibes
type: custom:multiple-entity-row
state_header: RealTime
attribute: next_departure_realtime
name: Mouans > Antibes 653
format: time
secondary_info: last-updated
entities:
- entity: sensor.653_mouans_antibes
attribute: day
name: Day
format: time
- entity: sensor.653_mouans_antibes
name: 653
format: time
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
content:
type: custom:button-card
entity: sensor.653_mouans_antibes
show_icon: false
show_state: true
show_name: false
tap_action: none
styles:
grid:
- grid-template-areas: "\"next\" \"s\""
custom_fields:
next:
- font-size: 20px
- font-weight: bold
custom_fields:
next: |
[[[ return 'Next departures :' ]]]
state_display: |
[[[
return entity.attributes.next_departures.map((entry) => {
return '<br>' + [ helpers.formatShortDateTimeWithYear(entry) ] ;
} ).join("").toString();
]]]
card_mod:
style:
.: |
ha-card {
border-width: 0px !important;
background: none;
} When vehicle positions have been added to the GTFS2 configuration, a geojson file is created in your www/gtfs2 folder. You can create HA entities with position, using the geojson integration, by refering to the file in www/gtfs2.
Important
The geojson file is in www for access by integrations like geojson. This means you need to use '/local', e.g. http://Your-HA-IP:8123/local/gtfs2/filename.json
Important
The filename is case sensitive.


Note
To ensure that the HA entity is unique, the name of the entity is a combination of: The route 'B' The direction '(0)' The last three digits of a crc32 of the trip_id
Once you have the geojson entity configured, you can configure a Map card to show the positions of active vehicles along that route:

Note
The geojson integration currently only updates every 5 minutes, but can be refreshed by a call to a geojson Action.
Use customize_glob to display a different entity_picture, in this case a svg of a bus:

Note
SVG images are not supplied by GTFS2
Tweak the card to make full use of the SVG, i.e. to remove the circle, the background:

type: custom:auto-entities
filter:
include:
- entity_id: geo_location.b_0*
exclude:
- state: unavailable
show_empty: true
card:
type: map
hours_to_show: 2
auto_fit: true
card_mod:
style:
ha-map:
$:
.leaflet-marker-icon:
ha-entity-marker $: |
.marker {
vertical-align: right !important;
width: 25px !important;
height: 25px !important;
border: 0px solid var(--ha-marker-color,var(--primary-color)) !important;
background-color: var(--ha-marker-color,none) !important;
}
.div:hover {
--webkit-transform: scale(0.1);
--ms-transform: scale(0.1);
transform: scale(0.1);
}

type: custom:auto-entities
filter:
include:
- name: '*_local_stop'
exclude:
- state: unavailable
card:
type: custom:flex-table-card
clickable: true
max_rows: 30
title: Local Stop dep.
strict: true
sort_by:
- next_departures_lines
columns:
- hidden: true
data: next_departures_lines
modify: x.departure
- name: Route
data: next_departures_lines
modify: '''<ha-icon icon='' + x.icon + ''></ha-icon>'' + x.route'
- name: Time
data: next_departures_lines
modify: x.departure
- name: Stop
data: next_departures_lines
modify: x.stop_name
- name: Headsign
data: next_departures_lines
modify: x.headsign
css:
table+: 'padding: 0px'
card_mod:
style: |
ha-card {
overflow: auto;
max-height: 500px;
}[!NOTE} I have not been able to get this to work with flex-table-card

type: vertical-stack
cards:
- type: entities
entities:
- entity: input_text.local_stops_filter
- type: markdown
content: >-
<table> {% set next =
state_attr('sensor.01254_0608400_local_stop_person_abcd','next_departures_lines')%}
{% for i in range(0, next | count, 1) %} {%- if
state_attr('sensor.01254_0608400_local_stop_person_abcd','next_departures_lines')[i].route
== states("input_text.local_stops_filter") -%}
<tr> <td>{{
state_attr('sensor.01254_0608400_local_stop_person_abcd','next_departures_lines')[i].route
}}</td> <td>{{
state_attr('sensor.01254_0608400_local_stop_person_abcd','next_departures_lines')[i].departure
}}</td> <td>{{
state_attr('sensor.01254_0608400_local_stop_person_abcd','next_departures_lines')[i].stop_name
}}</td> <td>{{
state_attr('sensor.01254_0608400_local_stop_person_abcd','next_departures_lines')[i].headsign
}}</td> {% endif %} {% endfor %}
card_mod:
style:
.: |
ha-card ha-markdown {
padding:0px
border-top: 1px groove var(--divider-color);
overflow-y: scroll;
height: 300px;
}
ha-card ha-markdown.no-header {
padding:0px
}
$: |
h1.card-header {
background-color:rgb(100, 100, 100);
padding: 0px 0px 0px 12px !important;
color: white !important;
font-weight: normal;
font-size: 1.5em !important;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
height: 100%;
}
ha-markdown $: |
h1 {
font-weight: normal;
font-size: 24px;
}
table{
border-collapse: collapse;
font-size: 0.9em;
font-family: Roboto;
width: 100%;
outline: 0px solid #393c3d;
margin-top: 10px;
}
td {
padding: 5px 5px 5px 5px;
text-align: left;
border-bottom: 0px solid #1c2020;
}
tr:nth-of-type(even) {
background-color: rgb(54, 54, 54, 0.3);
}In this exmaple, I tied the dynamic route sensor to my person.abc entity, which contains the lat/lon of my phone. When I move around I click two buttons to see what is near me:
-
Location update: This causes HA to updat the lat/lon of my
person.abcentity, in case it is not fast in updating my person/position (i.e. with my iPhone it is slow). - Local stops update: This causes HA to update every entity with local stops tied to my name. I have this setup for France, Switzerland, and Netherlands. The map nicely follows me around and adds the stops.
Note
You can also automate those actions, but since I am not that mobile, nor do I need it all day long, the button-update suffices for me.

Use an entities card and be able to click on a single entry, showing the next known departures.
[!IMPORTANT] This requires the browser_mod integration be installed in your HA

Change YOURSENSOR to whatever your entity is called.
type: entities
entities:
- entity: YOURSENSOR
format: datetime
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
content:
type: custom:button-card
entity: YOURSENSOR
show_icon: false
show_state: true
show_name: false
tap_action: none
styles:
grid:
- grid-template-areas: "\"next\" \"s\""
custom_fields:
next:
- font-size: 20px
- font-weight: bold
custom_fields:
next: |
[[[ return 'Next departures :' ]]]
state_display: |
[[[
return entity.attributes.next_departures.map((entry) => {
return '<br>' + [ helpers.formatShortDateTimeWithYear(entry) ];
} ).join("").toString();
]]]