diff --git a/.coveragerc b/.coveragerc index 303a7907329..8916c8fd251 100644 --- a/.coveragerc +++ b/.coveragerc @@ -226,6 +226,7 @@ omit = homeassistant/components/scene/hunterdouglas_powerview.py homeassistant/components/sensor/arest.py homeassistant/components/sensor/arwn.py + homeassistant/components/sensor/bbox.py homeassistant/components/sensor/bitcoin.py homeassistant/components/sensor/bom.py homeassistant/components/sensor/coinmarketcap.py diff --git a/homeassistant/components/sensor/bbox.py b/homeassistant/components/sensor/bbox.py new file mode 100644 index 00000000000..c79fa904c5d --- /dev/null +++ b/homeassistant/components/sensor/bbox.py @@ -0,0 +1,151 @@ +""" +Support for Bbox Bouygues Modem Router. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.bbox/ +""" +import logging +from datetime import timedelta +import requests +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (CONF_NAME, CONF_MONITORED_VARIABLES, + ATTR_ATTRIBUTION) +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle +import homeassistant.helpers.config_validation as cv + +# Return cached results if last scan was less then this time ago +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) + +REQUIREMENTS = ['pybbox==0.0.5-alpha'] + +_LOGGER = logging.getLogger(__name__) + +CONF_ATTRIBUTION = "Powered by Bouygues Telecom" +DEFAULT_NAME = 'Bbox' + +# Bandwidth units +BANDWIDTH_MEGABITS_SECONDS = 'Mb/s' # type: str + +# Sensor types are defined like so: +# Name, unit, icon +SENSOR_TYPES = { + 'down_max_bandwidth': ['Maximum Download Bandwidth', + BANDWIDTH_MEGABITS_SECONDS, 'mdi:download'], + 'up_max_bandwidth': ['Maximum Upload Bandwidth', + BANDWIDTH_MEGABITS_SECONDS, 'mdi:upload'], + 'current_down_bandwidth': ['Currently Used Download Bandwidth', + BANDWIDTH_MEGABITS_SECONDS, 'mdi:download'], + 'current_up_bandwidth': ['Currently Used Upload Bandwidth', + BANDWIDTH_MEGABITS_SECONDS, 'mdi:upload'], +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_MONITORED_VARIABLES): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +# pylint: disable=too-many-arguments +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Bbox sensor.""" + # Create a data fetcher to support all of the configured sensors. Then make + # the first call to init the data. + try: + bbox_data = BboxData() + bbox_data.update() + except requests.exceptions.HTTPError as error: + _LOGGER.error(error) + return False + + name = config.get(CONF_NAME) + + sensors = [] + for variable in config[CONF_MONITORED_VARIABLES]: + sensors.append(BboxSensor(bbox_data, variable, name)) + + add_devices(sensors) + + +class BboxSensor(Entity): + """Implementation of a Bbox sensor.""" + + def __init__(self, bbox_data, sensor_type, name): + """Initialize the sensor.""" + self.client_name = name + self.type = sensor_type + self._name = SENSOR_TYPES[sensor_type][0] + self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] + self._icon = SENSOR_TYPES[sensor_type][2] + self.bbox_data = bbox_data + self._state = None + + self.update() + + @property + def name(self): + """Return the name of the sensor.""" + return '{} {}'.format(self.client_name, self._name) + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + return self._unit_of_measurement + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return self._icon + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + ATTR_ATTRIBUTION: CONF_ATTRIBUTION, + } + + def update(self): + """Get the latest data from Bbox and update the state.""" + self.bbox_data.update() + if self.type == 'down_max_bandwidth': + self._state = round( + self.bbox_data.data['rx']['maxBandwidth'] / 1000, 2) + elif self.type == 'up_max_bandwidth': + self._state = round( + self.bbox_data.data['tx']['maxBandwidth'] / 1000, 2) + elif self.type == 'current_down_bandwidth': + self._state = round(self.bbox_data.data['rx']['bandwidth'] / 1000, + 2) + elif self.type == 'current_up_bandwidth': + self._state = round(self.bbox_data.data['tx']['bandwidth'] / 1000, + 2) + + +# pylint: disable=too-few-public-methods +class BboxData(object): + """Get data from the Bbox.""" + + def __init__(self): + """Initialize the data object.""" + self.data = None + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Get the latest data from the Bbox.""" + import pybbox + + try: + box = pybbox.Bbox() + self.data = box.get_ip_stats() + except requests.exceptions.HTTPError as error: + _LOGGER.error(error) + self.data = None + return False diff --git a/requirements_all.txt b/requirements_all.txt index 00953ca1e46..48506711f8d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -339,6 +339,7 @@ pyasn1-modules==0.0.8 pyasn1==0.1.9 # homeassistant.components.device_tracker.bbox +# homeassistant.components.sensor.bbox pybbox==0.0.5-alpha # homeassistant.components.device_tracker.bluetooth_tracker