core/homeassistant/components/sensor/london_underground.py

136 lines
3.5 KiB
Python
Raw Normal View History

"""
Sensor for checking the status of London Underground tube lines.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.london_underground/
"""
import logging
from datetime import timedelta
import voluptuous as vol
import requests
import homeassistant.helpers.config_validation as cv
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Powered by TfL Open Data"
CONF_LINE = 'line'
SCAN_INTERVAL = timedelta(seconds=30)
TUBE_LINES = [
'Bakerloo',
'Central',
'Circle',
'District',
'DLR',
'Hammersmith & City',
'Jubilee',
'London Overground',
'Metropolitan',
'Northern',
'Piccadilly',
'TfL Rail',
'Victoria',
'Waterloo & City']
URL = 'https://api.tfl.gov.uk/line/mode/tube,overground,dlr,tflrail/status'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_LINE):
vol.All(cv.ensure_list, [vol.In(list(TUBE_LINES))]),
})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Tube sensor."""
data = TubeData()
data.update()
sensors = []
for line in config.get(CONF_LINE):
sensors.append(LondonTubeSensor(line, data))
add_entities(sensors, True)
class LondonTubeSensor(Entity):
"""Sensor that reads the status of a line from TubeData."""
ICON = 'mdi:subway'
def __init__(self, name, data):
"""Initialize the sensor."""
self._name = name
self._data = data
self._state = None
self._description = None
@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 icon(self):
"""Icon to use in the frontend, if any."""
return self.ICON
@property
def device_state_attributes(self):
"""Return other details about the sensor state."""
attrs = {}
attrs['Description'] = self._description
return attrs
def update(self):
"""Update the sensor."""
self._data.update()
self._state = self._data.data[self.name]['State']
self._description = self._data.data[self.name]['Description']
class TubeData:
"""Get the latest tube data from TFL."""
def __init__(self):
"""Initialize the TubeData object."""
self.data = None
# Update only once in scan interval.
@Throttle(SCAN_INTERVAL)
def update(self):
"""Get the latest data from TFL."""
response = requests.get(URL)
if response.status_code != 200:
_LOGGER.warning("Invalid response from API")
else:
self.data = parse_api_response(response.json())
def parse_api_response(response):
"""Take in the TFL API json response."""
lines = [line['name'] for line in response]
data_dict = dict.fromkeys(lines)
for line in response:
statuses = [status['statusSeverityDescription']
for status in line['lineStatuses']]
state = ' + '.join(sorted(set(statuses)))
if state == 'Good Service':
reason = 'Nothing to report'
else:
reason = ' *** '.join(
[status['reason'] for status in line['lineStatuses']])
attr = {'State': state, 'Description': reason}
data_dict[line['name']] = attr
return data_dict