Skip to content

Commit

Permalink
Local stop sensor, fix bugs and tune
Browse files Browse the repository at this point in the history
Local stops were not presenting correctly, bug in query-approach
- proper data shown
- added date to departure, in case of departures past midnight
- organised stops under one service
  • Loading branch information
vingerha committed Mar 15, 2024
1 parent 4d91a04 commit 25d6b31
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 35 deletions.
2 changes: 1 addition & 1 deletion custom_components/gtfs2/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
self._data: dict[str, str] = {}

async def _async_update_data(self) -> dict[str, str]:
"""Get the latest data from GTFS and GTFS relatime, depending refresh interval"""
"""Get the latest data from GTFS and GTFS relatime, depending refresh interval"""
data = self.config_entry.data
options = self.config_entry.options
previous_data = None if self.data is None else self.data.copy()
Expand Down
52 changes: 28 additions & 24 deletions custom_components/gtfs2/gtfs_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,14 +707,15 @@ def get_local_stops_next_departures(self):
schedule = self._data["schedule"]
now = dt_util.now().replace(tzinfo=None)
now_date = now.strftime(dt_util.DATE_STR_FORMAT)
now_time = now.strftime(TIME_STR_FORMAT)
tomorrow = now + datetime.timedelta(days=1)
tomorrow_date = tomorrow.strftime(dt_util.DATE_STR_FORMAT)
device_tracker = self.hass.states.get(self._data['device_tracker_id'])
latitude = device_tracker.attributes.get("latitude", None)
longitude = device_tracker.attributes.get("longitude", None)
include_tomorrow = self._data["include_tomorrow"]
tomorrow_select = tomorrow_select2 = tomorrow_where = tomorrow_order = ""
tomorrow_calendar_date_where = f"AND (calendar_date_today.date = :today)"
tomorrow_calendar_date_where = f"AND (calendar_date_today.date = date('now'))"
time_range = str('+' + str(self._data.get("timerange", DEFAULT_LOCAL_STOP_TIMERANGE)) + ' minute')
radius = self._data.get("radius", DEFAULT_LOCAL_STOP_RADIUS) / 130000
_LOGGER.debug("Time Range: %s", time_range)
Expand All @@ -725,18 +726,19 @@ def get_local_stops_next_departures(self):
_LOGGER.debug("Includes Tomorrow")
tomorrow_name = tomorrow.strftime("%A").lower()
tomorrow_select = f"calendar.{tomorrow_name} AS tomorrow,"
tomorrow_calendar_date_where = f"AND (calendar_date_today.date = :today or calendar_date_today.date = :tomorrow)"
tomorrow_calendar_date_where = f"AND (calendar_date_today.date = date('now') or calendar_date_today.date = :tomorrow)"
tomorrow_select2 = f"'0' AS tomorrow,"

_LOGGER.debug("today: %s", now.strftime("%A").lower())
_LOGGER.debug("today: %s", tomorrow.strftime("%A").lower())
sql_query = f"""
SELECT * FROM (
SELECT stop.stop_id, stop.stop_name,stop.stop_lat as latitude, stop.stop_lon as longitude, trip.trip_id, trip.trip_headsign, time(st.departure_time) as departure_time,
SELECT stop.stop_id, stop.stop_name,stop.stop_lat as latitude, stop.stop_lon as longitude, trip.trip_id, trip.trip_headsign, trip.direction_id, time(st.departure_time) as departure_time,
route.route_long_name,route.route_short_name,route.route_type,
calendar.{now.strftime("%A").lower()} AS today,
{tomorrow_select}
calendar.start_date AS start_date,
calendar.end_date AS end_date,
:today as calendar_date,
date('now') as calendar_date,
0 as today_cd
FROM trips trip
INNER JOIN calendar calendar
Expand All @@ -748,19 +750,19 @@ def get_local_stops_next_departures(self):
INNER JOIN routes route
ON route.route_id = trip.route_id
WHERE
trip.service_id not in (select service_id from calendar_dates where date = :today and exception_type = 2)
and datetime(calendar_date || ' ' || time(st.departure_time) ) between datetime('now','localtime') and datetime('now','localtime',:timerange)
AND calendar.start_date <= :today
AND calendar.end_date >= :today
trip.service_id not in (select service_id from calendar_dates where date = date('now') and exception_type = 2)
and datetime(date('now') || ' ' || time(st.departure_time) ) between datetime('now','localtime') and datetime('now','localtime',:timerange)
AND calendar.start_date <= date('now')
AND calendar.end_date >= date('now')
)
UNION ALL
SELECT * FROM (
SELECT stop.stop_id, stop.stop_name,stop.stop_lat as latitude, stop.stop_lon as longitude, trip.trip_id, trip.trip_headsign, time(st.departure_time) as departure_time,
SELECT stop.stop_id, stop.stop_name,stop.stop_lat as latitude, stop.stop_lon as longitude, trip.trip_id, trip.trip_headsign, trip.direction_id, time(st.departure_time) as departure_time,
route.route_long_name,route.route_short_name,route.route_type,
'0' AS today,
{tomorrow_select2}
:today AS start_date,
:today AS end_date,
date('now') AS start_date,
date('now') AS end_date,
calendar_date_today.date as calendar_date,
calendar_date_today.exception_type as today_cd
FROM trips trip
Expand All @@ -774,10 +776,10 @@ def get_local_stops_next_departures(self):
ON trip.service_id = calendar_date_today.service_id
WHERE
today_cd = 1
and datetime(calendar_date || ' ' || time(st.departure_time) ) between datetime('now','localtime') and datetime('now','localtime',:timerange)
and datetime(date('now') || ' ' || time(st.departure_time) ) between datetime('now','localtime') and datetime('now','localtime',:timerange)
{tomorrow_calendar_date_where}
)
order by stop_id, departure_time
order by stop_id, tomorrow, departure_time
""" # noqa: S608
result = schedule.engine.connect().execute(
text(sql_query),
Expand All @@ -796,28 +798,30 @@ def get_local_stops_next_departures(self):
prev_entry = entry = {}
for row_cursor in result:
row = row_cursor._asdict()
entry = {"stop_id": row['stop_id'], "stop_name": row['stop_name'], "latitude": row['latitude'], "longitude": row['longitude'], "departure": timetable}

if row["stop_id"] != prev_stop_id and prev_stop_id != "":
local_stops_list.append(prev_entry)
timetable = []
entry = {"stop_id": row['stop_id'], "stop_name": row['stop_name'], "latitude": row['latitude'], "longitude": row['longitude'], "departure": timetable}
self._icon = ICONS.get(row['route_type'], ICON)
if row["today"] == 1 or row["today_cd"] == 1:
timetable.append({"departure": row["departure_time"], "stop_name": row['stop_name'], "route": row["route_short_name"], "route_long": row["route_long_name"], "headsign": row["trip_headsign"], "trip_id": row["trip_id"], "icon": self._icon})
timetable.append({"departure": row["departure_time"], "date": now_date, "stop_name": row['stop_name'], "route": row["route_short_name"], "route_long": row["route_long_name"], "headsign": row.["trip_headsign"], "trip_id": row["trip_id"], "direction_id": row["direction_id"], "icon": self._icon})

if (
"tomorrow" in row
and row["tomorrow"] == 1
and row["today"] == 0
and tomorrow_date <= row["end_date"]
and now_time > row["departure_time"]
):
timetable.append({"departure": row["departure_time"], "stop_name": row['stop_name'], "route": row["route_short_name"], "route_long": row["route_long_name"], "headsign": row["trip_headsign"], "trip_id": row["trip_id"], "icon": self._icon})
timetable.append({"departure": row["departure_time"], "date": tomorrow_date, "stop_name": row['stop_name'], "route": row["route_short_name"], "route_long": row["route_long_name"], "headsign": row.["trip_headsign"], "trip_id": row["trip_id"], "direction_id": row["direction_id"], "icon": self._icon})
entry["departure"] = timetable
prev_entry = entry

if row["stop_id"] != prev_stop_id and prev_stop_id != "":
local_stops_list.append(prev_entry)
timetable = []


prev_entry = entry.copy()
prev_stop_id = str(row["stop_id"])

if entry:

local_stops_list.append(entry)
data_returned = local_stops_list
_LOGGER.debug("Stop data returned: %s", data_returned)
Expand Down
3 changes: 3 additions & 0 deletions custom_components/gtfs2/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"name": "GTFS 2 (General Transit Feed Specification)",
"codeowners": ["@vingerha"],
"config_flow": true,
"dependencies": [
"zone"
],
"documentation": "https://github.com/vingerha/gtfs2/wiki",
"iot_class": "local_polling",
"issue_tracker": "https://github.com/vingerha/gtfs2/issues",
Expand Down
20 changes: 10 additions & 10 deletions custom_components/gtfs2/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()
for stop in coordinator.data["local_stops_next_departures"]:
sensors.append(
GTFSLocalStopSensor(stop, coordinator)
GTFSLocalStopSensor(stop, coordinator, coordinator.data.get("name", "No Name"))
)

else:
Expand Down Expand Up @@ -467,19 +467,20 @@ def remove_keys(self, prefix: str) -> None:
class GTFSLocalStopSensor(CoordinatorEntity, SensorEntity):
"""Implementation of a GTFS local stops departures sensor."""

def __init__(self, stop, coordinator) -> None:
def __init__(self, stop, coordinator, name) -> None:
"""Initialize the GTFSsensor."""
super().__init__(coordinator)
self._name = stop["stop_id"]
self._stop = stop
self._name = self._stop["stop_id"] + "_local_stop_" + self.coordinator.data['device_tracker_id']
self._attributes: dict[str, Any] = {}

self._attr_unique_id = f"gtfs-{self._name}_{self.coordinator.data['device_tracker_id']}"
self._attr_unique_id = self._name
self._attr_device_info = DeviceInfo(
name=f"GTFS - {self._name}",
name=f"GTFS - {name}",
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, f"GTFS - {self._name}")},
identifiers={(DOMAIN, f"GTFS - {name}")},
manufacturer="GTFS",
model=self._name,
model=name,
)
self._stop = stop
self._attributes = self._update_attrs()
Expand All @@ -488,8 +489,7 @@ def __init__(self, stop, coordinator) -> None:
@property
def name(self) -> str:
"""Return the name of the sensor."""
return self._name + "_local_stop_" + self.coordinator.data[
'device_tracker_id']
return self._name

@callback
def _handle_coordinator_update(self) -> None:
Expand Down Expand Up @@ -518,7 +518,7 @@ def _update_attrs(self): # noqa: C901 PLR0911
self._attributes["next_departures_lines"] = {}
if self._departure:
for stop in self._departure:
if stop["stop_id"] == self._name:
if self._name.startswith(stop["stop_id"]):
self._attributes["next_departures_lines"] = stop["departure"]
self._attributes["latitude"] = stop["latitude"]
self._attributes["longitude"] = stop["longitude"]
Expand Down

0 comments on commit 25d6b31

Please sign in to comment.