diff --git a/.coveragerc b/.coveragerc index 0cd866b321e9267ea8a0fc063128a1e73e8844bc..ec03242880c2f98f5430f4396a6114e8b4f96793 100644 --- a/.coveragerc +++ b/.coveragerc @@ -505,6 +505,7 @@ omit = homeassistant/components/sensor/imap.py homeassistant/components/sensor/imap_email_content.py homeassistant/components/sensor/influxdb.py + homeassistant/components/sensor/irish_rail_transport.py homeassistant/components/sensor/kwb.py homeassistant/components/sensor/lastfm.py homeassistant/components/sensor/linux_battery.py diff --git a/CODEOWNERS b/CODEOWNERS index 0560f5d53109c1c29e4a7eab5a66dde174dc5f2c..0830adcc355421acdca094e27e5b632a9480c801 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -51,6 +51,7 @@ homeassistant/components/light/yeelight.py @rytilahti homeassistant/components/media_player/kodi.py @armills homeassistant/components/media_player/monoprice.py @etsinko homeassistant/components/sensor/airvisual.py @bachya +homeassistant/components/sensor/irish_rail_transport.py @ttroy50 homeassistant/components/sensor/miflora.py @danielhiversen homeassistant/components/sensor/tibber.py @danielhiversen homeassistant/components/sensor/waqi.py @andrey-git diff --git a/homeassistant/components/sensor/irish_rail_transport.py b/homeassistant/components/sensor/irish_rail_transport.py new file mode 100644 index 0000000000000000000000000000000000000000..ad2a312ce632ab21c739ae12614e76d7118519a0 --- /dev/null +++ b/homeassistant/components/sensor/irish_rail_transport.py @@ -0,0 +1,182 @@ +""" +Support for Irish Rail RTPI information. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.irish_rail_transport/ +""" +import logging +from datetime import timedelta + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import CONF_NAME +from homeassistant.helpers.entity import Entity + +REQUIREMENTS = ['pyirishrail==0.0.2'] + +_LOGGER = logging.getLogger(__name__) + +ATTR_STATION = "Station" +ATTR_ORIGIN = "Origin" +ATTR_DESTINATION = "Destination" +ATTR_DIRECTION = "Direction" +ATTR_STOPS_AT = "Stops at" +ATTR_DUE_IN = "Due in" +ATTR_DUE_AT = "Due at" +ATTR_EXPECT_AT = "Expected at" +ATTR_NEXT_UP = "Later Train" +ATTR_TRAIN_TYPE = "Train type" + +CONF_STATION = 'station' +CONF_DESTINATION = 'destination' +CONF_DIRECTION = 'direction' +CONF_STOPS_AT = 'stops_at' + +DEFAULT_NAME = 'Next Train' +ICON = 'mdi:train' + +SCAN_INTERVAL = timedelta(minutes=2) +TIME_STR_FORMAT = '%H:%M' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_STATION): cv.string, + vol.Optional(CONF_DIRECTION, default=None): cv.string, + vol.Optional(CONF_DESTINATION, default=None): cv.string, + vol.Optional(CONF_STOPS_AT, default=None): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Irish Rail transport sensor.""" + from pyirishrail.pyirishrail import IrishRailRTPI + station = config.get(CONF_STATION) + direction = config.get(CONF_DIRECTION) + destination = config.get(CONF_DESTINATION) + stops_at = config.get(CONF_STOPS_AT) + name = config.get(CONF_NAME) + + irish_rail = IrishRailRTPI() + data = IrishRailTransportData( + irish_rail, station, direction, destination, stops_at) + add_devices([IrishRailTransportSensor( + data, station, direction, destination, stops_at, name)], True) + + +class IrishRailTransportSensor(Entity): + """Implementation of an irish rail public transport sensor.""" + + def __init__(self, data, station, direction, destination, stops_at, name): + """Initialize the sensor.""" + self.data = data + self._station = station + self._direction = direction + self._direction = direction + self._stops_at = stops_at + self._name = name + self._state = None + self._times = [] + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if len(self._times) > 0: + next_up = "None" + if len(self._times) > 1: + next_up = self._times[1][ATTR_ORIGIN] + " to " + next_up += self._times[1][ATTR_DESTINATION] + " in " + next_up += self._times[1][ATTR_DUE_IN] + + return { + ATTR_STATION: self._station, + ATTR_ORIGIN: self._times[0][ATTR_ORIGIN], + ATTR_DESTINATION: self._times[0][ATTR_DESTINATION], + ATTR_DUE_IN: self._times[0][ATTR_DUE_IN], + ATTR_DUE_AT: self._times[0][ATTR_DUE_AT], + ATTR_EXPECT_AT: self._times[0][ATTR_EXPECT_AT], + ATTR_DIRECTION: self._times[0][ATTR_DIRECTION], + ATTR_STOPS_AT: self._times[0][ATTR_STOPS_AT], + ATTR_NEXT_UP: next_up, + ATTR_TRAIN_TYPE: self._times[0][ATTR_TRAIN_TYPE] + } + + @property + def unit_of_measurement(self): + """Return the unit this state is expressed in.""" + return 'min' + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return ICON + + def update(self): + """Get the latest data and update the states.""" + self.data.update() + self._times = self.data.info + if len(self._times) > 0: + self._state = self._times[0][ATTR_DUE_IN] + else: + self._state = None + + +class IrishRailTransportData(object): + """The Class for handling the data retrieval.""" + + def __init__(self, irish_rail, station, direction, destination, stops_at): + """Initialize the data object.""" + self._ir_api = irish_rail + self.station = station + self.direction = direction + self.destination = destination + self.stops_at = stops_at + self.info = self._empty_train_data() + + def update(self): + """Get the latest data from irishrail.""" + trains = self._ir_api.get_station_by_name(self.station, + direction=self.direction, + destination=self.destination) + stops_at = self.stops_at if self.stops_at else '' + self.info = [] + for train in trains: + train_data = {ATTR_STATION: self.station, + ATTR_ORIGIN: train.get('origin'), + ATTR_DESTINATION: train.get('destination'), + ATTR_DUE_IN: train.get('due_in_mins'), + ATTR_DUE_AT: train.get('scheduled_arrival_time'), + ATTR_EXPECT_AT: train.get('expected_departure_time'), + ATTR_DIRECTION: train.get('direction'), + ATTR_STOPS_AT: stops_at, + ATTR_TRAIN_TYPE: train.get('type')} + self.info.append(train_data) + + if not self.info or len(self.info) == 0: + self.info = self._empty_train_data() + + def _empty_train_data(self): + """Generate info for an empty train.""" + dest = self.destination if self.destination else '' + direction = self.direction if self.direction else '' + stops_at = self.stops_at if self.stops_at else '' + return [{ATTR_STATION: self.station, + ATTR_ORIGIN: '', + ATTR_DESTINATION: dest, + ATTR_DUE_IN: 'n/a', + ATTR_DUE_AT: 'n/a', + ATTR_EXPECT_AT: 'n/a', + ATTR_DIRECTION: direction, + ATTR_STOPS_AT: stops_at, + ATTR_TRAIN_TYPE: ''}] diff --git a/requirements_all.txt b/requirements_all.txt index 2de5f2a41f0eb5f582eccb2d0da6933ac0a62f40..52cf67716934f7c3d339ae03f1e8dbf62d2ad0f7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -650,6 +650,9 @@ pyhydroquebec==1.2.0 # homeassistant.components.device_tracker.icloud pyicloud==0.9.1 +# homeassistant.components.sensor.irish_rail_transport +pyirishrail==0.0.2 + # homeassistant.components.binary_sensor.iss pyiss==1.0.1