diff --git a/homeassistant/components/mythicbeastsdns.py b/homeassistant/components/mythicbeastsdns.py new file mode 100644 index 00000000000..ff45fc8a530 --- /dev/null +++ b/homeassistant/components/mythicbeastsdns.py @@ -0,0 +1,59 @@ +""" +Integrate with Mythic Beasts Dynamic DNS service. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/mythicbeastsdns/ +""" +from datetime import timedelta +import logging +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.const import CONF_HOST, CONF_DOMAIN, CONF_PASSWORD +from homeassistant.helpers.event import async_track_time_interval +from homeassistant.helpers.aiohttp_client import async_get_clientsession + +REQUIREMENTS = ['mbddns==0.1.2'] + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = 'mythicbeastsdns' + +DEFAULT_INTERVAL = timedelta(minutes=10) + +CONF_UPDATE_INTERVAL = 'update_interval' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_DOMAIN): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_UPDATE_INTERVAL, default=DEFAULT_INTERVAL): vol.All( + cv.time_period, cv.positive_timedelta), + }) +}, extra=vol.ALLOW_EXTRA) + + +async def async_setup(hass, config): + """Initialize the Mythic Beasts component.""" + import mbddns + + domain = config[DOMAIN][CONF_DOMAIN] + password = config[DOMAIN][CONF_PASSWORD] + host = config[DOMAIN][CONF_HOST] + update_interval = config[DOMAIN][CONF_UPDATE_INTERVAL] + + session = async_get_clientsession(hass) + + result = await mbddns.update(domain, password, host, session=session) + + if not result: + return False + + async def update_domain_interval(now): + """Update the DNS entry.""" + await mbddns.update(domain, password, host, session=session) + + async_track_time_interval(hass, update_domain_interval, update_interval) + + return True diff --git a/requirements_all.txt b/requirements_all.txt index 76605fa11af..1a3698a6310 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -645,6 +645,9 @@ matrix-client==0.2.0 # homeassistant.components.maxcube maxcube-api==0.1.0 +# homeassistant.components.mythicbeastsdns +mbddns==0.1.2 + # homeassistant.components.notify.message_bird messagebird==1.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 72a9ca7da43..deda940d5d0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -122,6 +122,9 @@ libsoundtouch==0.7.2 # homeassistant.components.luftdaten luftdaten==0.3.4 +# homeassistant.components.mythicbeastsdns +mbddns==0.1.2 + # homeassistant.components.sensor.mfi # homeassistant.components.switch.mfi mficlient==0.3.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index cc81341e91b..5cd1d4b22d1 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -68,6 +68,7 @@ TEST_REQUIREMENTS = ( 'libpurecoollink', 'libsoundtouch', 'luftdaten', + 'mbddns', 'mficlient', 'numpy', 'paho-mqtt', diff --git a/tests/components/test_mythicbeastsdns.py b/tests/components/test_mythicbeastsdns.py new file mode 100644 index 00000000000..ab801e6e6e5 --- /dev/null +++ b/tests/components/test_mythicbeastsdns.py @@ -0,0 +1,70 @@ +"""Test the Mythic Beasts DNS component.""" +import logging +import asynctest + +from homeassistant.setup import async_setup_component +from homeassistant.components import mythicbeastsdns + +_LOGGER = logging.getLogger(__name__) + + +async def mbddns_update_mock(domain, password, host, ttl=60, session=None): + """Mock out mythic beasts updater.""" + if password == 'incorrect': + _LOGGER.error("Updating Mythic Beasts failed: Not authenticated") + return False + if host[0] == '$': + _LOGGER.error("Updating Mythic Beasts failed: Invalid Character") + return False + return True + + +@asynctest.mock.patch('mbddns.update', new=mbddns_update_mock) +async def test_update(hass): + """Run with correct values and check true is returned.""" + result = await async_setup_component( + hass, + mythicbeastsdns.DOMAIN, + { + mythicbeastsdns.DOMAIN: { + 'domain': 'example.org', + 'password': 'correct', + 'host': 'hass' + } + } + ) + assert result + + +@asynctest.mock.patch('mbddns.update', new=mbddns_update_mock) +async def test_update_fails_if_wrong_token(hass): + """Run with incorrect token and check false is returned.""" + result = await async_setup_component( + hass, + mythicbeastsdns.DOMAIN, + { + mythicbeastsdns.DOMAIN: { + 'domain': 'example.org', + 'password': 'incorrect', + 'host': 'hass' + } + } + ) + assert not result + + +@asynctest.mock.patch('mbddns.update', new=mbddns_update_mock) +async def test_update_fails_if_invalid_host(hass): + """Run with invalid characters in host and check false is returned.""" + result = await async_setup_component( + hass, + mythicbeastsdns.DOMAIN, + { + mythicbeastsdns.DOMAIN: { + 'domain': 'example.org', + 'password': 'correct', + 'host': '$hass' + } + } + ) + assert not result