Skip to content

Commit

Permalink
Improve error logging
Browse files Browse the repository at this point in the history
  • Loading branch information
warrior25 committed Feb 22, 2024
1 parent 6938766 commit 79a4f8a
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 46 deletions.
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ 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 %}
```

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

## Known issues / limitations

- 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`.
3 changes: 0 additions & 3 deletions custom_components/nysse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ async def async_unload_entry(
*[hass.config_entries.async_forward_entry_unload(entry, "sensor")]
)
)
# Remove options_update_listener.
# hass.data[DOMAIN][entry.entry_id]["unsub_options_update_listener"]()

# Remove config entry from domain.
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)

Expand Down
14 changes: 12 additions & 2 deletions custom_components/nysse/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ def __init__(self) -> None:
self.title = "Nysse"

async def async_step_user(self, user_input: Optional[dict[str, Any]] = None):
errors: dict[str, str] = {}
errors = {}

self.stations = await fetch_stop_points(True)
if len(self.stations) == 0:
errors["base"] = "no_stop_points"

data_schema = {
vol.Required(CONF_STATION): selector(
{
Expand Down Expand Up @@ -70,9 +73,12 @@ 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: dict[str, str] = {}
errors = {}

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

options_schema = {
vol.Required(CONF_LINES, default=lines): cv.multi_select(lines),
vol.Optional(CONF_TIMELIMIT, default=DEFAULT_TIMELIMIT): selector(
Expand Down Expand Up @@ -134,6 +140,7 @@ def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
self.config_entry = config_entry
self.data: dict[str, Any] = {}
self.title = ""
self.stations = []

async def async_step_init(
self, user_input: dict[str, Any] = None
Expand All @@ -142,6 +149,9 @@ async def async_step_init(

if user_input is not None:
self.stations = await fetch_stop_points(True)
if len(self.stations) == 0:
errors["base"] = "no_stop_points"

for station in self.stations:
if station["value"] == self.config_entry.data[CONF_STATION]:
self.title = station["label"]
Expand Down
1 change: 0 additions & 1 deletion custom_components/nysse/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
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:https://data.itsfactory.fi/journeys/api/1/stop-points/"
JOURNEYS_URL = "http:https://data.itsfactory.fi/journeys/api/1/journeys?stopPointId={0}&dayTypes={1}&startIndex={2}"
Expand Down
21 changes: 14 additions & 7 deletions custom_components/nysse/fetch_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ async def fetch_stop_points(has_id):
try:
result = await get(STOP_POINTS_URL)
if not result:
_LOGGER.error("Could not fetch stop points")
return
_LOGGER.error("Nysse API error: failed to fetch stops: no data received")
return stations
result = json.loads(result)
for stop in result["body"]:
if has_id:
Expand All @@ -33,8 +33,12 @@ async def fetch_stop_points(has_id):

return sorted(stations, key=lambda item: item["label"])

except (OSError, KeyError):
return []
except KeyError as err:
_LOGGER.error("Nysse API error: failed to fetch stops: %s", err)
return stations
except OSError as err:
_LOGGER.error("Failed to fetch stops: %s", err)
return stations


async def fetch_lines(stop):
Expand All @@ -44,13 +48,16 @@ async def fetch_lines(stop):
lines_url = LINES_URL.format(stop)
result = await get(lines_url)
if not result:
_LOGGER.error("Could not fetch lines")
_LOGGER.error("Nysse API error: failed to fetch lines: no data received")
return
result = json.loads(result)
for line in result["body"]:
lines.append(line["name"])
return lines

except (OSError, KeyError) as err:
except KeyError as err:
_LOGGER.error("Nysse API error: failed to fetch lines: %s", err)
return []
except OSError as err:
_LOGGER.error("Failed to fetch lines: %s", err)
return
return []
4 changes: 2 additions & 2 deletions custom_components/nysse/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async def get(url):
) as response:
if response.status == 200:
return await response.text()
_LOGGER.error("GET %s: %s", url, response.status)
_LOGGER.debug("Incorrect status for GET %s: %s", url, response.status)
return
except aiohttp.ClientConnectorError as err:
_LOGGER.error("Connection error: %s", err)
_LOGGER.error("Network connection error: %s", err)
41 changes: 29 additions & 12 deletions custom_components/nysse/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ async def fetch_departures(self):
data = await get(url)
if not data:
_LOGGER.warning(
"%s: Can't fetch departures. Incorrect response from %s",
"%s: Nysse API error: failed to fetch realtime data: no data received from %s",
self.stop_code,
url,
)
Expand All @@ -195,8 +195,8 @@ async def fetch_data_for_weekday(weekday_index):
)
data = await get(url)
if not data:
_LOGGER.error(
"%s: Can't fetch timetables. Incorrect response from %s",
_LOGGER.warning(
"%s: Nysse API error: failed to fetch timetables: no data received from %s",
self.stop_code,
url + "&indent=yes",
)
Expand Down Expand Up @@ -245,10 +245,19 @@ def format_departures(self, departures):
):
formatted_data.append(formatted_departure)
except KeyError as err:
_LOGGER.info("Incorrect response structure: %s", err)
_LOGGER.info(
"%s: Failed to process realtime departure: %s",
self.stop_code,
err,
)
continue
return formatted_data
except KeyError:
except KeyError as err:
_LOGGER.info(
"%s: Nysse API error: failed to process realtime data: %s",
self.stop_code,
err,
)
return []

def format_journeys(self, journeys, weekday):
Expand Down Expand Up @@ -280,10 +289,18 @@ def format_journeys(self, journeys, weekday):
if formatted_journey["departureTime"] is not None:
formatted_data.append(formatted_journey)
except KeyError as err:
_LOGGER.info("Incorrect response structure: %s", err)
_LOGGER.info(
"%s: Failed to process timetable departure: %s",
self.stop_code,
err,
)
continue
except KeyError as err:
_LOGGER.info("Incorrect response structure: %s", err)
_LOGGER.info(
"%s: Nysse API error: failed to fetch timetable data: %s",
self.stop_code,
err,
)
return formatted_data

def get_departure_time(
Expand Down Expand Up @@ -329,7 +346,6 @@ async def async_update(self) -> None:
try:
await self.fetch_stops()
if len(self._stops) == 0:
_LOGGER.error("%s: Failed to fetch stops", self.stop_code)
return

departures = await self.fetch_departures()
Expand All @@ -352,14 +368,14 @@ async def async_update(self) -> None:
if len(self._journeys) == 0:
self._fetch_fail_counter += 1
_LOGGER.warning(
"%s: No valid timetable data received from API. This is likely not a problem with the integration. Failed %s time(s) already",
"%s: Nysse API error: failed to fetch timetable data: %s",
self.stop_code,
self._fetch_fail_counter,
)
if self._fetch_fail_counter == 10:
self._fetch_fail_counter = 0
self._fetch_pause_counter = 30
_LOGGER.warning(
_LOGGER.error(
"%s: Getting timetable data failed too many times. Next attempt in %s minutes. Reload integration to retry immediately",
self.stop_code,
self._fetch_pause_counter * SCAN_INTERVAL.seconds / 60,
Expand Down Expand Up @@ -469,6 +485,7 @@ def timestamp_to_local(self, timestamp):

def conditionally_clear_alerts(self):
"""Clear alerts if none received in 20 tries."""
# TODO: Individual alerts may never be removed
if self._empty_response_counter >= 20:
self._empty_response_counter = 0
self._alerts.clear()
Expand All @@ -480,7 +497,7 @@ async def fetch_service_alerts(self):
data = await get(SERVICE_ALERTS_URL)
if not data:
_LOGGER.warning(
"Can't fetch service alerts. Incorrect response from %s",
"Nysse API error: failed to fetch service alerts: no data received from %s",
SERVICE_ALERTS_URL,
)
return
Expand Down Expand Up @@ -515,7 +532,7 @@ async def fetch_service_alerts(self):
self.conditionally_clear_alerts()
return self._alerts
except OSError as err:
_LOGGER.error("Failed to update service alerts: %s", err)
_LOGGER.error("Failed to fetch service alerts: %s", err)
return []

async def async_update(self) -> None:
Expand Down
5 changes: 3 additions & 2 deletions custom_components/nysse/strings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"config": {
"error": {
"request": "Failed to connect to Nysse servers to retrieve data",
"invalid_station": "Invalid station",
"invalid_lines": "Select at least one line"
"invalid_lines": "Select at least one line",
"no_stop_points": "Failed to fetch stops. Please try again later",
"no_lines": "Failed to fetch lines. Please try again later"
},
"abort": {
"already_configured": "Stop is already configured"
Expand Down
5 changes: 3 additions & 2 deletions custom_components/nysse/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"error": {
"invalid_lines": "Select at least one line",
"invalid_station": "Invalid station",
"request": "Failed to connect to Nysse servers to retrieve data"
"no_stop_points": "Failed to fetch stops. Please try again later",
"no_lines": "Failed to fetch lines. Please try again later"
},
"step": {
"options": {
Expand All @@ -22,7 +23,7 @@
"data": {
"station": "Station"
},
"description": "Enter the station and line you would like to follow",
"description": "Enter the station you would like to track",
"title": "Nysse Tampere"
}
}
Expand Down
5 changes: 3 additions & 2 deletions custom_components/nysse/translations/fi.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"config": {
"error": {
"request": "Yhteys Nysse-palvelimiin epäonnistui",
"invalid_station": "Virheellinen pysäkki",
"invalid_lines": "Valitse ainakin yksi linja"
"invalid_lines": "Valitse vähintään yksi linja",
"no_stop_points": "Pysäkkien hakeminen epäonnistui. Yritä uudelleen myöhemmin",
"no_lines": "Linjojen hakeminen epäonnistui. Yritä uudelleen myöhemmin"
},
"abort": {
"already_configured": "Pysäkki on jo lisätty"
Expand Down

0 comments on commit 79a4f8a

Please sign in to comment.