diff --git a/homeassistant/components/namecheapdns.py b/homeassistant/components/namecheapdns.py
new file mode 100644
index 00000000000..8397fcd0033
--- /dev/null
+++ b/homeassistant/components/namecheapdns.py
@@ -0,0 +1,76 @@
+"""Integrate with NamecheapDNS."""
+import asyncio
+from datetime import timedelta
+import logging
+
+import voluptuous as vol
+
+from homeassistant.const import CONF_HOST, CONF_ACCESS_TOKEN, CONF_DOMAIN
+import homeassistant.helpers.config_validation as cv
+from homeassistant.helpers.event import async_track_time_interval
+from homeassistant.helpers.aiohttp_client import async_get_clientsession
+
+DOMAIN = 'namecheapdns'
+UPDATE_URL = 'https://dynamicdns.park-your-domain.com/update'
+INTERVAL = timedelta(minutes=5)
+_LOGGER = logging.getLogger(__name__)
+
+CONFIG_SCHEMA = vol.Schema({
+ DOMAIN: vol.Schema({
+ vol.Required(CONF_HOST): cv.string,
+ vol.Required(CONF_DOMAIN): cv.string,
+ vol.Required(CONF_ACCESS_TOKEN): cv.string,
+ })
+}, extra=vol.ALLOW_EXTRA)
+
+
+@asyncio.coroutine
+def async_setup(hass, config):
+ """Initialize the NamecheapDNS component."""
+ host = config[DOMAIN][CONF_HOST]
+ domain = config[DOMAIN][CONF_DOMAIN]
+ token = config[DOMAIN][CONF_ACCESS_TOKEN]
+ session = async_get_clientsession(hass)
+
+ result = yield from _update_namecheapdns(session, host, domain, token)
+
+ if not result:
+ return False
+
+ @asyncio.coroutine
+ def update_domain_interval(now):
+ """Update the NamecheapDNS entry."""
+ yield from _update_namecheapdns(session, host, domain, token)
+
+ @asyncio.coroutine
+ def update_domain_service(call):
+ """Update the NamecheapDNS entry."""
+ yield from _update_namecheapdns(session, host, domain, token)
+
+ async_track_time_interval(hass, update_domain_interval, INTERVAL)
+ hass.services.async_register(DOMAIN, 'update dns', update_domain_service)
+
+ return result
+
+
+@asyncio.coroutine
+def _update_namecheapdns(session, host, domain, token):
+ """Update NamecheapDNS."""
+ import xml.etree.ElementTree as ET
+
+ params = {
+ 'host': host,
+ 'domain': domain,
+ 'password': token,
+ }
+
+ resp = yield from session.get(UPDATE_URL, params=params)
+ xml_string = yield from resp.text()
+ root = ET.fromstring(xml_string)
+ err_count = root.find('ErrCount').text
+
+ if int(err_count) != 0:
+ _LOGGER.warning('Updating Namecheap domain %s failed', domain)
+ return False
+
+ return True
diff --git a/tests/components/test_namecheapdns.py b/tests/components/test_namecheapdns.py
new file mode 100644
index 00000000000..b225c0af7c8
--- /dev/null
+++ b/tests/components/test_namecheapdns.py
@@ -0,0 +1,78 @@
+"""Test the NamecheapDNS component."""
+import asyncio
+from datetime import timedelta
+
+import pytest
+
+from homeassistant.setup import async_setup_component
+from homeassistant.components import namecheapdns
+from homeassistant.util.dt import utcnow
+
+from tests.common import async_fire_time_changed
+
+HOST = 'test'
+DOMAIN = 'bla'
+TOKEN = 'abcdefgh'
+
+
+@pytest.fixture
+def setup_namecheapdns(hass, aioclient_mock):
+ """Fixture that sets up NamecheapDNS."""
+ aioclient_mock.get(namecheapdns.UPDATE_URL, params={
+ 'host': HOST,
+ 'domain': DOMAIN,
+ 'password': TOKEN
+ }, text='0')
+
+ hass.loop.run_until_complete(async_setup_component(
+ hass, namecheapdns.DOMAIN, {
+ 'namecheapdns': {
+ 'host': HOST,
+ 'domain': DOMAIN,
+ 'access_token': TOKEN
+ }
+ }))
+
+
+@asyncio.coroutine
+def test_setup(hass, aioclient_mock):
+ """Test setup works if update passes."""
+ aioclient_mock.get(namecheapdns.UPDATE_URL, params={
+ 'host': HOST,
+ 'domain': DOMAIN,
+ 'password': TOKEN
+ }, text='0')
+
+ result = yield from async_setup_component(hass, namecheapdns.DOMAIN, {
+ 'namecheapdns': {
+ 'host': HOST,
+ 'domain': DOMAIN,
+ 'access_token': TOKEN
+ }
+ })
+ assert result
+ assert aioclient_mock.call_count == 1
+
+ async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
+ yield from hass.async_block_till_done()
+ assert aioclient_mock.call_count == 2
+
+
+@asyncio.coroutine
+def test_setup_fails_if_update_fails(hass, aioclient_mock):
+ """Test setup fails if first update fails."""
+ aioclient_mock.get(namecheapdns.UPDATE_URL, params={
+ 'host': HOST,
+ 'domain': DOMAIN,
+ 'password': TOKEN
+ }, text='1')
+
+ result = yield from async_setup_component(hass, namecheapdns.DOMAIN, {
+ 'namecheapdns': {
+ 'host': HOST,
+ 'domain': DOMAIN,
+ 'access_token': TOKEN
+ }
+ })
+ assert not result
+ assert aioclient_mock.call_count == 1