From 2258c56d34ae905f33171b285d53894c0e5d30c2 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Sun, 23 Sep 2018 18:58:09 +0200 Subject: [PATCH] Handle netgear_lte connection errors (#16806) --- homeassistant/components/netgear_lte.py | 39 ++++++++++++++----- .../components/notify/netgear_lte.py | 26 +++++++++---- .../components/sensor/netgear_lte.py | 7 ++++ requirements_all.txt | 2 +- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/netgear_lte.py b/homeassistant/components/netgear_lte.py index 7f54e6fd6f9..e5e9a0fc2e9 100644 --- a/homeassistant/components/netgear_lte.py +++ b/homeassistant/components/netgear_lte.py @@ -6,6 +6,7 @@ https://home-assistant.io/components/netgear_lte/ """ import asyncio from datetime import timedelta +import logging import voluptuous as vol import attr @@ -17,7 +18,9 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_create_clientsession from homeassistant.util import Throttle -REQUIREMENTS = ['eternalegypt==0.0.3'] +REQUIREMENTS = ['eternalegypt==0.0.5'] + +_LOGGER = logging.getLogger(__name__) MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=10) @@ -37,17 +40,23 @@ class ModemData: """Class for modem state.""" modem = attr.ib() - serial_number = attr.ib(init=False) - unread_count = attr.ib(init=False) - usage = attr.ib(init=False) + + serial_number = attr.ib(init=False, default=None) + unread_count = attr.ib(init=False, default=None) + usage = attr.ib(init=False, default=None) @Throttle(MIN_TIME_BETWEEN_UPDATES) async def async_update(self): """Call the API to update the data.""" - information = await self.modem.information() - self.serial_number = information.serial_number - self.unread_count = sum(1 for x in information.sms if x.unread) - self.usage = information.usage + import eternalegypt + try: + information = await self.modem.information() + self.serial_number = information.serial_number + self.unread_count = sum(1 for x in information.sms if x.unread) + self.usage = information.usage + except eternalegypt.Error: + self.unread_count = None + self.usage = None @attr.s @@ -81,17 +90,27 @@ async def async_setup(hass, config): return True -async def _setup_lte(hass, lte_config): +async def _setup_lte(hass, lte_config, delay=0): """Set up a Netgear LTE modem.""" import eternalegypt + if delay: + await asyncio.sleep(delay) + host = lte_config[CONF_HOST] password = lte_config[CONF_PASSWORD] websession = hass.data[DATA_KEY].websession modem = eternalegypt.Modem(hostname=host, websession=websession) - await modem.login(password=password) + + try: + await modem.login(password=password) + except eternalegypt.Error: + delay = max(15, min(2*delay, 300)) + _LOGGER.warning("Retrying %s in %d seconds", host, delay) + hass.loop.create_task(_setup_lte(hass, lte_config, delay)) + return modem_data = ModemData(modem) await modem_data.async_update() diff --git a/homeassistant/components/notify/netgear_lte.py b/homeassistant/components/notify/netgear_lte.py index 97dfe504a51..9ba804e193d 100644 --- a/homeassistant/components/notify/netgear_lte.py +++ b/homeassistant/components/notify/netgear_lte.py @@ -4,6 +4,8 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/notify.netgear_lte/ """ +import logging + import voluptuous as vol import attr @@ -17,6 +19,8 @@ from ..netgear_lte import DATA_KEY DEPENDENCIES = ['netgear_lte'] +_LOGGER = logging.getLogger(__name__) + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST): cv.string, vol.Required(ATTR_TARGET): vol.All(cv.ensure_list, [cv.string]), @@ -25,21 +29,29 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_get_service(hass, config, discovery_info=None): """Get the notification service.""" - modem_data = hass.data[DATA_KEY].get_modem_data(config) - phone = config.get(ATTR_TARGET) - return NetgearNotifyService(modem_data, phone) + return NetgearNotifyService(hass, config) @attr.s class NetgearNotifyService(BaseNotificationService): """Implementation of a notification service.""" - modem_data = attr.ib() - phone = attr.ib() + hass = attr.ib() + config = attr.ib() async def async_send_message(self, message="", **kwargs): """Send a message to a user.""" - targets = kwargs.get(ATTR_TARGET, self.phone) + modem_data = self.hass.data[DATA_KEY].get_modem_data(self.config) + if not modem_data: + _LOGGER.error("No modem available") + return + + phone = self.config.get(ATTR_TARGET) + targets = kwargs.get(ATTR_TARGET, phone) if targets and message: for target in targets: - await self.modem_data.modem.sms(target, message) + import eternalegypt + try: + await modem_data.modem.sms(target, message) + except eternalegypt.Error: + _LOGGER.error("Unable to send to %s", target) diff --git a/homeassistant/components/sensor/netgear_lte.py b/homeassistant/components/sensor/netgear_lte.py index b13a8e39132..3c17750d6ad 100644 --- a/homeassistant/components/sensor/netgear_lte.py +++ b/homeassistant/components/sensor/netgear_lte.py @@ -9,6 +9,7 @@ import attr from homeassistant.const import CONF_HOST, CONF_SENSORS from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv @@ -31,6 +32,9 @@ async def async_setup_platform( """Set up Netgear LTE sensor devices.""" modem_data = hass.data[DATA_KEY].get_modem_data(config) + if not modem_data: + raise PlatformNotReady + sensors = [] for sensor_type in config[CONF_SENSORS]: if sensor_type == SENSOR_SMS: @@ -88,4 +92,7 @@ class UsageSensor(LTESensor): @property def state(self): """Return the state of the sensor.""" + if self.modem_data.usage is None: + return None + return round(self.modem_data.usage / 1024**2, 1) diff --git a/requirements_all.txt b/requirements_all.txt index 152440d52f3..8e29b7eb74b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -333,7 +333,7 @@ ephem==3.7.6.0 epson-projector==0.1.3 # homeassistant.components.netgear_lte -eternalegypt==0.0.3 +eternalegypt==0.0.5 # homeassistant.components.keyboard_remote # evdev==0.6.1