diff --git a/README.md b/README.md index 40c06dc..b3a544d 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,11 @@ sensor: platform: wienerlinien firstnext: first stops: - - '4429' - - '3230' + - 4429 + - stop: 4429 + line: 100 + firstnext: next + - 3230 ``` ## Configuration variables @@ -22,8 +25,9 @@ sensor: key | description -- | -- **platform (Required)** | The platform name. -**stops (Required)** | RBL stop ID's -**firstnext (Optional)** | `first` or `next` departure. +**stops (Required)** | List of stopids or a stop with extended settings (see above) +**lineid (Optional)** | ID of a Wiener Linien transport line - some stops have more than one line so its always good to add the lineid to get the correct data +**firstnext (Optional)** | `first` or `next` departure. Default: `first` (can be defined at a specific stop as well to "overrule" the global setting) ## Sample overview @@ -31,7 +35,9 @@ key | description ## Notes -You can find out the Stop ID (rbl number) thanks to [Matthias Bendel](https://github.com/mabe-at) [https://till.mabe.at/rbl/](https://till.mabe.at/rbl/) +You can find out the Stop ID thanks to [Matthias Bendel](https://github.com/mabe-at) [https://till.mabe.at/rbl/](https://till.mabe.at/rbl/) +The Line ID you can get from the URL in your browser after selecting a Line on the site (https://till.mabe.at/rbl/?**line=301**) or in this csv: +[wienerlinien-ogd-linien.csv](https://www.wienerlinien.at/ogd_realtime/doku/ogd/wienerlinien-ogd-linien.csv) This platform is using the [Wienerlinien API](http://www.wienerlinien.at) API to get the information. diff --git a/custom_components/wienerlinien/const.py b/custom_components/wienerlinien/const.py index 17a101b..34cf49b 100644 --- a/custom_components/wienerlinien/const.py +++ b/custom_components/wienerlinien/const.py @@ -1,5 +1,5 @@ """Constants""" -BASE_URL = "http://www.wienerlinien.at/ogd_realtime/monitor?rbl={}" +BASE_URL = "https://www.wienerlinien.at/ogd_realtime/monitor?stopid={}" DEPARTURES = { "first": {"key": 0, "name": "{} first departure"}, diff --git a/custom_components/wienerlinien/manifest.json b/custom_components/wienerlinien/manifest.json index 3061ab6..30c7180 100644 --- a/custom_components/wienerlinien/manifest.json +++ b/custom_components/wienerlinien/manifest.json @@ -1,7 +1,7 @@ { "domain": "wienerlinien", "name": "Wienerlinien", - "version": "1.2.0", + "version": "1.3.0", "documentation": "https://github.com/tofuSCHNITZEL/home-assistant-wienerlinien", "issue_tracker": "https://github.com/tofuSCHNITZEL/home-assistant-wienerlinien/issues", "dependencies": [], diff --git a/custom_components/wienerlinien/sensor.py b/custom_components/wienerlinien/sensor.py index 2a156ec..6506077 100644 --- a/custom_components/wienerlinien/sensor.py +++ b/custom_components/wienerlinien/sensor.py @@ -17,49 +17,100 @@ from custom_components.wienerlinien.const import BASE_URL, DEPARTURES CONF_STOPS = "stops" +CONF_STOP = "stop" CONF_APIKEY = "apikey" CONF_FIRST_NEXT = "firstnext" +CONF_LINEID = "line" +CONF_FIRST = "first" +CONF_NEXT = "next" SCAN_INTERVAL = timedelta(seconds=30) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Optional(CONF_APIKEY): cv.string, - vol.Optional(CONF_STOPS, default=None): vol.All(cv.ensure_list, [cv.string]), - vol.Optional(CONF_FIRST_NEXT, default="first"): cv.string, + vol.Required(CONF_STOPS): vol.All( + cv.ensure_list, + [ + { + vol.Required(CONF_STOP): vol.Coerce(int), + vol.Optional(CONF_LINEID): vol.Coerce(int), + vol.Optional(CONF_FIRST_NEXT, default="first"): vol.In({CONF_FIRST,CONF_NEXT}), + }, + vol.Coerce(int) + ] + ), + vol.Optional(CONF_FIRST_NEXT, default="first"): vol.In({CONF_FIRST,CONF_NEXT}), } ) _LOGGER = logging.getLogger(__name__) +UNIQUE_MONITORS = set() async def async_setup_platform(hass, config, add_devices_callback, discovery_info=None): """Setup.""" stops = config.get(CONF_STOPS) - firstnext = config.get(CONF_FIRST_NEXT) + globalfirstnext = config.get(CONF_FIRST_NEXT) dev = [] - for stopid in stops: + monitorid = 0 + lineid = None + + for stop in stops: + if type(stop) is int: + stopid = stop + firstnext = globalfirstnext + else: + stopid = stop[CONF_STOP] + lineid = stop.get(CONF_LINEID) + firstnext = stop[CONF_FIRST_NEXT] + api = WienerlinienAPI(async_create_clientsession(hass), hass.loop, stopid) data = await api.get_json() try: - name = data["data"]["monitors"][0]["locationStop"]["properties"]["title"] + monitors = data["data"]["monitors"] except Exception: raise PlatformNotReady() - dev.append(WienerlinienSensor(api, name, firstnext)) + + if len(monitors) == 0: + _LOGGER.error(f"Invalid stopid provided - there are no monitors for stopid {stopid}") + continue + + if lineid: + for monitorCount, monitor in enumerate(monitors): + if monitor["lines"][0].get("lineId") == lineid: + monitorid = monitorCount + + stopname = monitors[monitorid]["locationStop"]["properties"]["title"].strip() + linename = monitors[monitorid]["lines"][0]["name"].strip() + destination = monitors[monitorid]["lines"][0]["towards"].strip() + vehicle_type = monitors[monitorid]["lines"][0]["type"] + + name = f"{stopname} {linename} -> {destination}" + monitorID = name+firstnext + + if monitorID not in UNIQUE_MONITORS: + UNIQUE_MONITORS.add(monitorID) + dev.append(WienerlinienSensor(api, name, firstnext, monitorid, vehicle_type)) + else: + _LOGGER.warn("Skipping already existing monitor") + add_devices_callback(dev, True) - class WienerlinienSensor(Entity): """WienerlinienSensor.""" - def __init__(self, api, name, firstnext): + def __init__(self, api, name, firstnext, monitorid, vehicle_type): """Initialize.""" self.api = api self.firstnext = firstnext + self.monitorid = monitorid + self.vehicle_type = vehicle_type self._name = name self._state = None self.attributes = {} + self._attr_unique_id = f"{name}-{firstnext}".replace(" ", "-") async def async_update(self): """Update data.""" @@ -76,7 +127,7 @@ async def async_update(self): if data is None: return try: - line = data["monitors"][0]["lines"][0] + line = data["monitors"][self.monitorid]["lines"][0] departure = line["departures"]["departure"][ DEPARTURES[self.firstnext]["key"] ] @@ -92,7 +143,10 @@ async def async_update(self): "platform": line["platform"], "direction": line["direction"], "name": line["name"], - "countdown": departure["departureTime"]["countdown"], + "stopid": self.api.my_stopid(), + "lineid": line["lineId"], + "barrierFree": line["barrierFree"], + "trafficjam": line["trafficjam"], } except Exception: pass @@ -112,8 +166,22 @@ def state(self): @property def icon(self): - """Return icon.""" - return "mdi:bus" + """Return icon according to vehicle.""" + match self.vehicle_type: + case "ptMetro": + return "mdi:subway" + case "ptTram": + return "mdi:tram" + case "ptTramWLB": + return "mdi:train-variant" + case "ptBusCity": + return "mdi:bus" + case "ptBusNight": + return "mdi:bus-clock" + case "ptTrainS": + return "mdi:train" + case _: + return "mdi:bus" @property def extra_state_attributes(self): @@ -147,3 +215,6 @@ async def get_json(self): pass return value + + def my_stopid(self): + return self.stopid