Skip to content

Commit b7e7e3b

Browse files
committed
Fix start/stop not showing all rt-departures
RT departures were limited to the route with which the entity was defined whereas it covers all direct trips between start/stop locations, also for other routes
1 parent c56c840 commit b7e7e3b

2 files changed

Lines changed: 33 additions & 13 deletions

File tree

custom_components/gtfs2/coordinator.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ async def _async_update_data(self) -> dict[str, str]:
154154
self._trip_id = self._data.get('next_departure', {}).get('trip_id', None)
155155
self._trip_short_name = self._data.get('next_departure', {}).get('trip_short_name', None)
156156
self._direction = str(self._data.get('next_departure', {}).get('trip_direction_id', data["direction"]))
157+
self._trip_list = self._data["next_departure"].get("next_departures_trip_id", [])[:10]
157158
self._relative = False
158159
try:
159160
self._get_rt_alerts = await self.hass.async_add_executor_job(get_rt_alerts, self)
@@ -204,6 +205,7 @@ async def _async_update_data(self) -> dict[str, str]:
204205
"""Initialize the info object."""
205206
self._route_delimiter = None
206207
self._headers = {}
208+
self._rt_group = "trip"
207209
self._trip_update_url = options.get("trip_update_url", None)
208210
self._vehicle_position_url = options.get("vehicle_position_url", None)
209211
self._alerts_url = options.get("alerts_url", None)
@@ -251,6 +253,7 @@ async def _async_update_data(self) -> dict[str, str]:
251253
get_local_stops_next_departures, self
252254
)
253255
except Exception as ex:
256+
_LOGGER.error("Error getting local stops data: %s", ex)
254257
raise UpdateFailed(f"Error in getting local stops data: {ex}")
255258
_LOGGER.debug("Data from coordinator: %s", self._data)
256259
return self._data

custom_components/gtfs2/gtfs_rt_helper.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@
5959
)
6060

6161
def due_in_minutes(timestamp):
62-
"""Get the remaining minutes from now until a given datetime object."""
63-
diff = timestamp - dt_util.now().replace(tzinfo=None)
62+
"""Get the remaining minutes from now until a given (aware, UTC) datetime object."""
63+
if timestamp.tzinfo is None:
64+
timestamp = dt_util.utc_from_timestamp(timestamp.timestamp())
65+
diff = timestamp - dt_util.utcnow()
66+
_LOGGER.debug(f"GTFS RT due in minutes, timestamp: %s, now_utc: %s", timestamp, dt_util.utcnow())
6467
return int(diff.total_seconds() / 60)
6568

6669
def get_gtfs_feed_entities(url: str, headers, label: str):
@@ -171,7 +174,7 @@ def get_next_services(self):
171174
def get_rt_route_trip_statuses(self):
172175
''' Get next rt departure for route (multiple) or trip (single) '''
173176
# explanatory logic
174-
# sources can provide tip_id with or without route, route with or without direction hence a lot of conditions as the resultset has (!) to include the direction
177+
# sources can provide trip_id with or without route, route with or without direction hence a lot of conditions as the resultset has (!) to include the direction
175178
# if route-based info is required, for start/end stops, then one needs to cover also for routes without direction_id and thus trip
176179
# if response does not provide a direction_id then use trip_id, make directon temporarily nn and when the stop is identified make it equal to the requesting direction
177180
# in this case the trip still covers the direction
@@ -190,7 +193,11 @@ def get_rt_route_trip_statuses(self):
190193
_LOGGER.debug("No proper RT feed entities: %s", feed_entities)
191194
return {}
192195

193-
_LOGGER.debug("Search departure times for route: %s, trip: %s, type: %s, direction: %s, short_name: %s", self._route_id, self._trip_id, self._rt_group, self._direction, self._trip_short_name)
196+
if self._rt_group == "route":
197+
_LOGGER.debug("Search departure times for route: %s, trip: %s, type: %s, direction: %s, short_name: %s, trip_list: %s", self._route_id, self._trip_id, self._rt_group, self._direction, self._trip_short_name, self._trip_list)
198+
else:
199+
_LOGGER.debug("Search departure times for trip: %s, type: %s, short_name: %s", self._trip_id, self._rt_group, self._trip_short_name)
200+
194201
for entity in feed_entities:
195202

196203
if entity.get('trip_update', False):
@@ -228,8 +235,20 @@ def get_rt_route_trip_statuses(self):
228235

229236
# first part covers start/end and thus multiple RT are possible for the same stop, also, for SIRI route_id do not match so a 'in' is used
230237
# the second part covers local stops, i.e. per trip, so only one RT possible for that stop
231-
if (self._rt_group == "route" and (str(direction_id) == str(self._direction) and (route_id == self._route_id or self._route_id in route_id)) or (direction_id == "nn" and trip_id == self._trip_id) or (self._trip_id in trip_id)) or (self._rt_group == "trip" and (trip_id == self._trip_id or self._trip_id in trip_id)) or entity_id == self._trip_short_name:
232-
238+
if self._rt_group == "route":
239+
# route-mode, between predefined start/stop
240+
if direction_id != "nn":
241+
matched = (
242+
str(direction_id) == str(self._direction)
243+
and (route_id == self._route_id or self._route_id in route_id)
244+
) or trip_id in self._trip_list
245+
else:
246+
matched = trip_id == self._trip_id or self._trip_id in trip_id or (trip_id in self._trip_list)
247+
else:
248+
# trip-mode, for local stops which can have multiple routes
249+
matched = trip_id == self._trip_id or entity_id == self._trip_short_name
250+
251+
if matched:
233252
_LOGGER.debug("Entity found params - group: %s, route_id: %s, direction_id: %s, self_trip_id: %s, with rt trip: %s, rt id: %s", self._rt_group, route_id, direction_id, self._trip_id, entity["trip_update"]["trip"], entity_id)
234253

235254
for stop in entity["trip_update"]["stop_time_update"]:
@@ -275,14 +294,12 @@ def get_rt_route_trip_statuses(self):
275294
delay = stop["arrival"].get("delay",0)
276295

277296
# Ignore arrival times in the past
278-
279-
if due_in_minutes(datetime.fromtimestamp(stop_time)) >= 0:
280-
departure_times[self._route_id][direction_id][
281-
stop_id
282-
]["departures"].append(datetime.utcfromtimestamp(stop_time).replace(tzinfo=dt_util.get_time_zone("UTC")))
283-
_LOGGER.debug("RT stoptime: %s, utcfromtimestamp: %s, format utc: %s", stop_time, datetime.utcfromtimestamp(stop_time), datetime.utcfromtimestamp(stop_time).replace(tzinfo=dt_util.get_time_zone("UTC")))
297+
departure_dt = dt_util.utc_from_timestamp(stop_time) # aware UTC, epoch is always UTC
298+
if due_in_minutes(departure_dt) >= 0:
299+
departure_times[self._route_id][direction_id][stop_id]["departures"].append(departure_dt)
300+
_LOGGER.debug("RT stoptime: %s, in utcfromtimestamp: %s", stop_time, departure_dt)
284301
else:
285-
_LOGGER.debug("Not using realtime stop data for old due-in-minutes: %s", due_in_minutes(datetime.fromtimestamp(stop_time)))
302+
_LOGGER.debug("Not using realtime stop data for old due-in-minutes: %s", due_in_minutes(departure_dt))
286303

287304
departure_times[self._route_id][direction_id][stop_id]["delays"].append(delay)
288305

0 commit comments

Comments
 (0)