core/homeassistant/components/sensor/viaggiatreno.py

183 lines
5.4 KiB
Python
Raw Normal View History

"""
Support for information about the Italian train system using ViaggiaTreno API.
For more details about this platform please refer to the documentation at
https://home-assistant.io/components/sensor.viaggiatreno
"""
import asyncio
import logging
import aiohttp
import async_timeout
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ATTR_ATTRIBUTION
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Powered by ViaggiaTreno Data"
VIAGGIATRENO_ENDPOINT = ("http://www.viaggiatreno.it/viaggiatrenonew/"
"resteasy/viaggiatreno/andamentoTreno/"
"{station_id}/{train_id}")
REQUEST_TIMEOUT = 5 # seconds
ICON = 'mdi:train'
MONITORED_INFO = [
'categoria',
'compOrarioArrivoZeroEffettivo',
'compOrarioPartenzaZeroEffettivo',
'destinazione',
'numeroTreno',
'orarioArrivo',
'orarioPartenza',
'origine',
'subTitle',
]
DEFAULT_NAME = "Train {}"
CONF_NAME = 'train_name'
CONF_STATION_ID = 'station_id'
CONF_STATION_NAME = 'station_name'
CONF_TRAIN_ID = 'train_id'
ARRIVED_STRING = 'Arrived'
CANCELLED_STRING = 'Cancelled'
NOT_DEPARTED_STRING = "Not departed yet"
NO_INFORMATION_STRING = "No information for this train now"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_TRAIN_ID): cv.string,
vol.Required(CONF_STATION_ID): cv.string,
vol.Optional(CONF_NAME): cv.string,
})
2018-10-01 06:55:43 +00:00
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the ViaggiaTreno platform."""
train_id = config.get(CONF_TRAIN_ID)
station_id = config.get(CONF_STATION_ID)
name = config.get(CONF_NAME)
if not name:
name = DEFAULT_NAME.format(train_id)
async_add_entities([ViaggiaTrenoSensor(train_id, station_id, name)])
2018-10-01 06:55:43 +00:00
async def async_http_request(hass, uri):
"""Perform actual request."""
try:
session = hass.helpers.aiohttp_client.async_get_clientsession(hass)
with async_timeout.timeout(REQUEST_TIMEOUT, loop=hass.loop):
2018-10-01 06:55:43 +00:00
req = await session.get(uri)
if req.status != 200:
return {'error': req.status}
2018-10-01 06:55:43 +00:00
json_response = await req.json()
return json_response
except (asyncio.TimeoutError, aiohttp.ClientError) as exc:
_LOGGER.error("Cannot connect to ViaggiaTreno API endpoint: %s", exc)
except ValueError:
_LOGGER.error("Received non-JSON data from ViaggiaTreno API endpoint")
class ViaggiaTrenoSensor(Entity):
"""Implementation of a ViaggiaTreno sensor."""
def __init__(self, train_id, station_id, name):
"""Initialize the sensor."""
self._state = None
self._attributes = {}
self._unit = ''
self._icon = ICON
self._station_id = station_id
self._name = name
self.uri = VIAGGIATRENO_ENDPOINT.format(
station_id=station_id, train_id=train_id)
@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 unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
@property
def device_state_attributes(self):
"""Return extra attributes."""
self._attributes[ATTR_ATTRIBUTION] = ATTRIBUTION
return self._attributes
@staticmethod
def has_departed(data):
"""Check if the train has actually departed."""
try:
first_station = data['fermate'][0]
if data['oraUltimoRilevamento'] or first_station['effettiva']:
return True
except ValueError:
_LOGGER.error("Cannot fetch first station: %s", data)
return False
@staticmethod
def has_arrived(data):
"""Check if the train has already arrived."""
last_station = data['fermate'][-1]
if not last_station['effettiva']:
return False
return True
@staticmethod
def is_cancelled(data):
"""Check if the train is cancelled."""
if data['tipoTreno'] == 'ST' and data['provvedimento'] == 1:
return True
return False
2018-10-01 06:55:43 +00:00
async def async_update(self):
"""Update state."""
uri = self.uri
2018-10-01 06:55:43 +00:00
res = await async_http_request(self.hass, uri)
if res.get('error', ''):
if res['error'] == 204:
self._state = NO_INFORMATION_STRING
self._unit = ''
else:
self._state = "Error: {}".format(res['error'])
self._unit = ''
else:
for i in MONITORED_INFO:
self._attributes[i] = res[i]
if self.is_cancelled(res):
self._state = CANCELLED_STRING
self._icon = 'mdi:cancel'
self._unit = ''
elif not self.has_departed(res):
self._state = NOT_DEPARTED_STRING
self._unit = ''
elif self.has_arrived(res):
self._state = ARRIVED_STRING
self._unit = ''
else:
self._state = res.get('ritardo')
self._unit = 'min'
self._icon = ICON