Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timetable data from GTFS files #8

Merged
merged 6 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,45 @@ Each station creates a sensor which contains data for departures from that stati

`realtime` - Indicates if the data is pulled from realtime vehicle monitoring or timetable data

## Frontend example
## Frontend examples

Simple frontend examples using [custom:html-template-card](https://github.com/PiotrMachowski/Home-Assistant-Lovelace-HTML-Jinja2-Template-card)

Simple frontend example using [custom:html-template-card](https://github.com/PiotrMachowski/Home-Assistant-Lovelace-HTML-Jinja2-Template-card)
![Example](https://github.com/warrior25/HA-Nysse/raw/main/docs/frontend_example.jpg)

```yaml
type: custom:html-template-card
title: Keskustori D
ignore_line_breaks: true
content: >
{% set departures = state_attr('sensor.keskustori_d_0015','departures')
%} {% for i in range(0, departures | count, 1) %}

<div style="display:grid; grid-template-columns: 2fr 1fr; font-size: 20px;
padding: 10px 0px 0px 0px"> <div>{{ departures[i].line }} - {{
departures[i].destination }}</div><div style="text-align: right">{% if
departures[i].realtime %}<ha-icon style="color:green; padding: 0px 10px 0px
0px" icon="mdi:signal-variant"></ha-icon>{% endif %} {% if
departures[i].time_to_station | int < 21 %} {{departures[i].time_to_station}}
min {% else %}{{departures[i].departure}}{% endif %}</div></div>

{% endfor %}
{% set departures = state_attr('sensor.keskustori_d_0015','departures')
%} {% for i in range(0, departures | count, 1) %}

<div style="display:grid; grid-template-columns: 2fr 1fr; font-size: 20px;
padding: 10px 0px 0px 0px"> <div>{{ departures[i].line }} - {{
departures[i].destination }}</div><div style="text-align: right">{% if
departures[i].realtime %}<ha-icon style="color:green; padding: 0px 10px 0px
0px" icon="mdi:signal-variant"></ha-icon>{% endif %} {% if
departures[i].time_to_station | int < 21 %} {{departures[i].time_to_station}}
min {% else %}{{departures[i].departure}}{% endif %}</div></div>

{% endfor %}
```

![Service Alerts](https://github.com/warrior25/HA-Nysse/blob/d8fe99019902ee1c8edbfe302f086c5f6c5a6a5c/docs/service_alerts.jpg)

```yaml
type: custom:html-template-card
ignore_line_breaks: true
title: Service Alerts
content: >
{% set alerts = state_attr('sensor.nysse_service_alerts','alerts')
%} {% for i in range(0, alerts | count, 1) %}

<b>{{ alerts[i].start.strftime('%d.%m.%Y') }} - {{ alerts[i].end.strftime('%d.%m.%Y') }}</b><br>
{{ alerts[i].description }}<br><br>

{% endfor %}
```

## Advanced usage
Expand All @@ -63,5 +80,5 @@ content: >

## Known issues / limitations

- Nysse API sometimes functions incorrectly. Errors logged with `Nysse API error` can be resolved on their own over time.
- Line icons are resolved from a hardcoded list of tram lines. If new tram lines are built, the list needs to be updated in `const.py`.
- Nysse API sometimes functions incorrectly. Errors logged with `Nysse API error` can be resolved on their own over time.
- Line icons are resolved from a hardcoded list of tram lines. If new tram lines are built, the list needs to be updated in `const.py`.
30 changes: 24 additions & 6 deletions custom_components/nysse/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@
DEFAULT_TIMELIMIT,
DOMAIN,
)
from .fetch_api import fetch_lines, fetch_stop_points
from .fetch_api import get_route_ids, get_stops


def format_stops(stops):
"""Format the stops data into a list of dictionaries with label and value."""
return sorted(
[
{
"label": f"{stop['stop_name']} ({stop['stop_id']})",
"value": stop["stop_id"],
}
for stop in stops
],
key=lambda x: x["label"],
)


@config_entries.HANDLERS.register(DOMAIN)
Expand All @@ -32,9 +46,11 @@ def __init__(self) -> None:
async def async_step_user(self, user_input: Optional[dict[str, Any]] = None):
errors = {}

self.stations = await fetch_stop_points(True)
if len(self.stations) == 0:
stops = await get_stops()
# TODO: check error handling
if len(stops) == 0:
errors["base"] = "no_stop_points"
self.stations = format_stops(stops)

data_schema = {
vol.Required(CONF_STATION): selector(
Expand Down Expand Up @@ -75,7 +91,7 @@ async def async_step_user(self, user_input: Optional[dict[str, Any]] = None):
async def async_step_options(self, user_input: Optional[dict[str, Any]] = None):
errors = {}

lines = await fetch_lines(self.data[CONF_STATION])
lines = await get_route_ids(self.data[CONF_STATION])
if len(lines) == 0:
errors["base"] = "no_lines"

Expand Down Expand Up @@ -148,9 +164,11 @@ async def async_step_init(
errors: dict[str, str] = {}

if user_input is not None:
self.stations = await fetch_stop_points(True)
if len(self.stations) == 0:
stops = await get_stops()
# TODO: check error handling
if len(stops) == 0:
errors["base"] = "no_stop_points"
self.stations = format_stops(stops)

for station in self.stations:
if station["value"] == self.config_entry.data[CONF_STATION]:
Expand Down
27 changes: 5 additions & 22 deletions custom_components/nysse/const.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Constants for the Nysse component."""

DOMAIN = "nysse"

PLATFORM_NAME = "Nysse"
Expand All @@ -11,29 +13,10 @@
DEFAULT_ICON = "mdi:bus-clock"
TRAM_LINES = ["1", "3"]

WEEKDAYS = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
]

DEFAULT_TIME_ZONE = "Europe/Helsinki"

JOURNEY = "journey"
DEPARTURE = "departure"
AIMED_ARRIVAL_TIME = "aimedArrivalTime"
AIMED_DEPARTURE_TIME = "aimedDepartureTime"
EXPECTED_ARRIVAL_TIME = "expectedArrivalTime"
EXPECTED_DEPARTURE_TIME = "expectedDepartureTime"

STOP_URL = "https://data.itsfactory.fi/journeys/api/1/stop-monitoring?stops={0}"
STOP_POINTS_URL = "http://data.itsfactory.fi/journeys/api/1/stop-points/"
JOURNEYS_URL = "http://data.itsfactory.fi/journeys/api/1/journeys?stopPointId={0}&dayTypes={1}&startIndex={2}"
LINES_URL = "https://data.itsfactory.fi/journeys/api/1/lines?stopPointId={0}"
SERVICE_ALERTS_URL = (
"https://data.itsfactory.fi/journeys/api/1/gtfs-rt/service-alerts/json"
)
GTFS_URL = (
"https://data.itsfactory.fi/journeys/files/gtfs/latest/extended_gtfs_tampere.zip"
)
Loading
Loading