diff --git a/.coveragerc b/.coveragerc index 08b93aa4b7e..31232a6b3f1 100644 --- a/.coveragerc +++ b/.coveragerc @@ -311,6 +311,7 @@ omit = homeassistant/components/sensor/fitbit.py homeassistant/components/sensor/fixer.py homeassistant/components/sensor/fritzbox_callmonitor.py + homeassistant/components/sensor/fritzbox_netmonitor.py homeassistant/components/sensor/glances.py homeassistant/components/sensor/google_travel_time.py homeassistant/components/sensor/gpsd.py diff --git a/homeassistant/components/sensor/fritzbox_netmonitor.py b/homeassistant/components/sensor/fritzbox_netmonitor.py new file mode 100644 index 00000000000..82a0fa5fd9e --- /dev/null +++ b/homeassistant/components/sensor/fritzbox_netmonitor.py @@ -0,0 +1,133 @@ +""" +Support for monitoring an AVM Fritz!Box router. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.fritzbox_netmonitor/ +""" +import logging +from datetime import timedelta + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (CONF_HOST, STATE_UNAVAILABLE) +from homeassistant.helpers.entity import Entity +import homeassistant.helpers.config_validation as cv +from homeassistant.util import Throttle + +from requests.exceptions import RequestException + +REQUIREMENTS = ['fritzconnection==0.6'] + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5) + +CONF_DEFAULT_IP = '169.254.1.1' # This IP is valid for all FRITZ!Box routers. + +ATTR_IS_LINKED = "is_linked" +ATTR_IS_CONNECTED = "is_connected" +ATTR_WAN_ACCESS_TYPE = "wan_access_type" +ATTR_EXTERNAL_IP = "external_ip" +ATTR_UPTIME = "uptime" +ATTR_BYTES_SENT = "bytes_sent" +ATTR_BYTES_RECEIVED = "bytes_received" +ATTR_MAX_BYTE_RATE_UP = "max_byte_rate_up" +ATTR_MAX_BYTE_RATE_DOWN = "max_byte_rate_down" + +STATE_ONLINE = 'online' +STATE_OFFLINE = 'offline' + +ICON = 'mdi:web' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_HOST, default=CONF_DEFAULT_IP): cv.string, +}) + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the fritzbox monitor sensors.""" + # pylint: disable=import-error + import fritzconnection as fc + from fritzconnection.fritzconnection import FritzConnectionException + + host = config[CONF_HOST] + + try: + fstatus = fc.FritzStatus(address=host) + except (ValueError, TypeError, FritzConnectionException): + fstatus = None + + if fstatus is None: + _LOGGER.error('Failed to establish connection to FRITZ!Box ' + 'with IP: %s', host) + return 1 + else: + _LOGGER.info('Successfully connected to FRITZ!Box') + + sensor = FritzboxMonitorSensor(fstatus) + devices = [sensor] + add_devices(devices) + + +class FritzboxMonitorSensor(Entity): + """Implementation of a fritzbox monitor sensor.""" + + def __init__(self, fstatus): + """Initialize the sensor.""" + self._name = 'fritz_netmonitor' + self._fstatus = fstatus + self._state = STATE_UNAVAILABLE + self.update() + + @property + def name(self): + """Return the name of the sensor.""" + return self._name.rstrip() + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return ICON + + @property + def state(self): + """Return the state of the device.""" + return self._state + + @property + def state_attributes(self): + """Return the device state attributes.""" + # Don't return attributes if FritzBox is unreachable + if self._state == STATE_UNAVAILABLE: + return {} + attr = { + ATTR_IS_LINKED: self._is_linked, + ATTR_IS_CONNECTED: self._is_connected, + ATTR_WAN_ACCESS_TYPE: self._wan_access_type, + ATTR_EXTERNAL_IP: self._external_ip, + ATTR_UPTIME: self._uptime, + ATTR_BYTES_SENT: self._bytes_sent, + ATTR_BYTES_RECEIVED: self._bytes_received, + ATTR_MAX_BYTE_RATE_UP: self._max_byte_rate_up, + ATTR_MAX_BYTE_RATE_DOWN: self._max_byte_rate_down, + } + return attr + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Retrieve information from the FritzBox.""" + try: + self._is_linked = self._fstatus.is_linked + self._is_connected = self._fstatus.is_connected + self._wan_access_type = self._fstatus.wan_access_type + self._external_ip = self._fstatus.external_ip + self._uptime = self._fstatus.uptime + self._bytes_sent = self._fstatus.bytes_sent + self._bytes_received = self._fstatus.bytes_received + self._max_byte_rate_up = self._fstatus.max_byte_rate[0] + self._max_byte_rate_down = self._fstatus.max_byte_rate[1] + self._state = STATE_ONLINE if self._is_connected else STATE_OFFLINE + except RequestException as err: + self._state = STATE_UNAVAILABLE + _LOGGER.warning('Could not reach Fritzbox: %s', err) diff --git a/requirements_all.txt b/requirements_all.txt index 1f81829977b..dcf9289b16d 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -156,6 +156,7 @@ flux_led==0.13 freesms==0.1.1 # homeassistant.components.device_tracker.fritz +# homeassistant.components.sensor.fritzbox_netmonitor # fritzconnection==0.6 # homeassistant.components.switch.fritzdect