diff --git a/.coveragerc b/.coveragerc
index 70cfbded98fd08d3e6c38e42242f4cb49437910f..3da28762df0c616fd16e814e5cb135fb8c792a5a 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -94,6 +94,9 @@ omit =
     homeassistant/components/envisalink.py
     homeassistant/components/*/envisalink.py
 
+    homeassistant/components/fritzbox.py
+    homeassistant/components/*/fritzbox.py
+
     homeassistant/components/eufy.py
     homeassistant/components/*/eufy.py
 
diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py
index 7ea23f4fd65128ea187d5e13ec34370365fc6645..550d4035ddd148f1376b6b5fdd63f78c93a1e061 100644
--- a/homeassistant/components/climate/__init__.py
+++ b/homeassistant/components/climate/__init__.py
@@ -40,6 +40,7 @@ STATE_HEAT = 'heat'
 STATE_COOL = 'cool'
 STATE_IDLE = 'idle'
 STATE_AUTO = 'auto'
+STATE_MANUAL = 'manual'
 STATE_DRY = 'dry'
 STATE_FAN_ONLY = 'fan_only'
 STATE_ECO = 'eco'
diff --git a/homeassistant/components/climate/fritzbox.py b/homeassistant/components/climate/fritzbox.py
new file mode 100755
index 0000000000000000000000000000000000000000..839da8c9d533311752a2c52c74f4287426e4d39a
--- /dev/null
+++ b/homeassistant/components/climate/fritzbox.py
@@ -0,0 +1,153 @@
+"""
+Support for AVM Fritz!Box smarthome thermostate devices.
+
+For more details about this component, please refer to the documentation at
+http://home-assistant.io/components/climate.fritzbox/
+"""
+import logging
+
+import requests
+
+from homeassistant.components.fritzbox import DOMAIN as FRITZBOX_DOMAIN
+from homeassistant.components.fritzbox import (
+    ATTR_STATE_DEVICE_LOCKED, ATTR_STATE_BATTERY_LOW, ATTR_STATE_LOCKED)
+from homeassistant.components.climate import (
+    ATTR_OPERATION_MODE, ClimateDevice, STATE_ECO, STATE_HEAT, STATE_MANUAL,
+    SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE)
+from homeassistant.const import (
+    ATTR_TEMPERATURE, PRECISION_HALVES, TEMP_CELSIUS)
+
+DEPENDENCIES = ['fritzbox']
+
+_LOGGER = logging.getLogger(__name__)
+
+SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE)
+
+OPERATION_LIST = [STATE_HEAT, STATE_ECO]
+
+MIN_TEMPERATURE = 8
+MAX_TEMPERATURE = 28
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the Fritzbox smarthome thermostat platform."""
+    devices = []
+    fritz_list = hass.data[FRITZBOX_DOMAIN]
+
+    for fritz in fritz_list:
+        device_list = fritz.get_devices()
+        for device in device_list:
+            if device.has_thermostat:
+                devices.append(FritzboxThermostat(device, fritz))
+
+    add_devices(devices)
+
+
+class FritzboxThermostat(ClimateDevice):
+    """The thermostat class for Fritzbox smarthome thermostates."""
+
+    def __init__(self, device, fritz):
+        """Initialize the thermostat."""
+        self._device = device
+        self._fritz = fritz
+        self._current_temperature = self._device.actual_temperature
+        self._target_temperature = self._device.target_temperature
+        self._comfort_temperature = self._device.comfort_temperature
+        self._eco_temperature = self._device.eco_temperature
+
+    @property
+    def supported_features(self):
+        """Return the list of supported features."""
+        return SUPPORT_FLAGS
+
+    @property
+    def available(self):
+        """Return if thermostat is available."""
+        return self._device.present
+
+    @property
+    def name(self):
+        """Return the name of the device."""
+        return self._device.name
+
+    @property
+    def temperature_unit(self):
+        """Return the unit of measurement that is used."""
+        return TEMP_CELSIUS
+
+    @property
+    def precision(self):
+        """Return precision 0.5."""
+        return PRECISION_HALVES
+
+    @property
+    def current_temperature(self):
+        """Return the current temperature."""
+        return self._current_temperature
+
+    @property
+    def target_temperature(self):
+        """Return the temperature we try to reach."""
+        return self._target_temperature
+
+    def set_temperature(self, **kwargs):
+        """Set new target temperature."""
+        if ATTR_OPERATION_MODE in kwargs:
+            operation_mode = kwargs.get(ATTR_OPERATION_MODE)
+            self.set_operation_mode(operation_mode)
+        elif ATTR_TEMPERATURE in kwargs:
+            temperature = kwargs.get(ATTR_TEMPERATURE)
+            self._device.set_target_temperature(temperature)
+
+    @property
+    def current_operation(self):
+        """Return the current operation mode."""
+        if self._target_temperature == self._comfort_temperature:
+            return STATE_HEAT
+        elif self._target_temperature == self._eco_temperature:
+            return STATE_ECO
+        return STATE_MANUAL
+
+    @property
+    def operation_list(self):
+        """Return the list of available operation modes."""
+        return OPERATION_LIST
+
+    def set_operation_mode(self, operation_mode):
+        """Set new operation mode."""
+        if operation_mode == STATE_HEAT:
+            self.set_temperature(temperature=self._comfort_temperature)
+        elif operation_mode == STATE_ECO:
+            self.set_temperature(temperature=self._eco_temperature)
+
+    @property
+    def min_temp(self):
+        """Return the minimum temperature."""
+        return MIN_TEMPERATURE
+
+    @property
+    def max_temp(self):
+        """Return the maximum temperature."""
+        return MAX_TEMPERATURE
+
+    @property
+    def device_state_attributes(self):
+        """Return the device specific state attributes."""
+        attrs = {
+            ATTR_STATE_DEVICE_LOCKED: self._device.device_lock,
+            ATTR_STATE_LOCKED: self._device.lock,
+            ATTR_STATE_BATTERY_LOW: self._device.battery_low,
+        }
+        return attrs
+
+    def update(self):
+        """Update the data from the thermostat."""
+        try:
+            self._device.update()
+            self._current_temperature = self._device.actual_temperature
+            self._target_temperature = self._device.target_temperature
+            self._comfort_temperature = self._device.comfort_temperature
+            self._eco_temperature = self._device.eco_temperature
+        except requests.exceptions.HTTPError as ex:
+            _LOGGER.warning("Fritzbox connection error: %s", ex)
+            self._fritz.login()
diff --git a/homeassistant/components/fritzbox.py b/homeassistant/components/fritzbox.py
new file mode 100755
index 0000000000000000000000000000000000000000..a3c35aaa59719c9aa261a4a9b973f782424033ad
--- /dev/null
+++ b/homeassistant/components/fritzbox.py
@@ -0,0 +1,83 @@
+"""
+Support for AVM Fritz!Box smarthome devices.
+
+For more details about this component, please refer to the documentation at
+http://home-assistant.io/components/fritzbox/
+"""
+import logging
+
+import voluptuous as vol
+
+import homeassistant.helpers.config_validation as cv
+from homeassistant.const import (
+    CONF_DEVICES, CONF_HOST, CONF_PASSWORD, CONF_USERNAME,
+    EVENT_HOMEASSISTANT_STOP)
+from homeassistant.helpers import discovery
+
+_LOGGER = logging.getLogger(__name__)
+
+REQUIREMENTS = ['pyfritzhome==0.3.7']
+
+SUPPORTED_DOMAINS = ['climate', 'switch']
+
+DOMAIN = 'fritzbox'
+
+ATTR_STATE_DEVICE_LOCKED = 'device_locked'
+ATTR_STATE_LOCKED = 'locked'
+ATTR_STATE_BATTERY_LOW = 'battery_low'
+
+
+CONFIG_SCHEMA = vol.Schema({
+    DOMAIN: vol.Schema({
+        vol.Required(CONF_DEVICES):
+            vol.All(cv.ensure_list, [
+                vol.Schema({
+                    vol.Required(CONF_HOST): cv.string,
+                    vol.Required(CONF_PASSWORD): cv.string,
+                    vol.Required(CONF_USERNAME): cv.string,
+                }),
+            ]),
+    })
+}, extra=vol.ALLOW_EXTRA)
+
+
+def setup(hass, config):
+    """Set up the fritzbox component."""
+    from pyfritzhome import Fritzhome, LoginError
+
+    fritz_list = []
+
+    configured_devices = config[DOMAIN].get(CONF_DEVICES)
+    for device in configured_devices:
+        host = device.get(CONF_HOST)
+        username = device.get(CONF_USERNAME)
+        password = device.get(CONF_PASSWORD)
+        fritzbox = Fritzhome(host=host, user=username,
+                             password=password)
+        try:
+            fritzbox.login()
+            _LOGGER.info("Connected to device %s", device)
+        except LoginError:
+            _LOGGER.warning("Login to Fritz!Box %s as %s failed",
+                            host, username)
+            continue
+
+        fritz_list.append(fritzbox)
+
+    if not fritz_list:
+        _LOGGER.info("No fritzboxes configured")
+        return False
+
+    hass.data[DOMAIN] = fritz_list
+
+    def logout_fritzboxes(event):
+        """Close all connections to the fritzboxes."""
+        for fritz in fritz_list:
+            fritz.logout()
+
+    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, logout_fritzboxes)
+
+    for domain in SUPPORTED_DOMAINS:
+        discovery.load_platform(hass, domain, DOMAIN, {}, config)
+
+    return True
diff --git a/homeassistant/components/switch/fritzbox.py b/homeassistant/components/switch/fritzbox.py
new file mode 100755
index 0000000000000000000000000000000000000000..c8313b0dfef5b2eb90d6b2a8d012751ce4ecc018
--- /dev/null
+++ b/homeassistant/components/switch/fritzbox.py
@@ -0,0 +1,104 @@
+"""
+Support for AVM Fritz!Box smarthome switch devices.
+
+For more details about this component, please refer to the documentation at
+http://home-assistant.io/components/switch.fritzbox/
+"""
+import logging
+
+import requests
+
+from homeassistant.components.fritzbox import DOMAIN as FRITZBOX_DOMAIN
+from homeassistant.components.fritzbox import (
+    ATTR_STATE_DEVICE_LOCKED, ATTR_STATE_LOCKED)
+from homeassistant.components.switch import SwitchDevice
+from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
+
+DEPENDENCIES = ['fritzbox']
+
+_LOGGER = logging.getLogger(__name__)
+
+ATTR_TOTAL_CONSUMPTION = 'total_consumption'
+ATTR_TOTAL_CONSUMPTION_UNIT = 'total_consumption_unit'
+ATTR_TOTAL_CONSUMPTION_UNIT_VALUE = 'kWh'
+
+ATTR_TEMPERATURE_UNIT = 'temperature_unit'
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the Fritzbox smarthome switch platform."""
+    devices = []
+    fritz_list = hass.data[FRITZBOX_DOMAIN]
+
+    for fritz in fritz_list:
+        device_list = fritz.get_devices()
+        for device in device_list:
+            if device.has_switch:
+                devices.append(FritzboxSwitch(device, fritz))
+
+    add_devices(devices)
+
+
+class FritzboxSwitch(SwitchDevice):
+    """The switch class for Fritzbox switches."""
+
+    def __init__(self, device, fritz):
+        """Initialize the switch."""
+        self._device = device
+        self._fritz = fritz
+
+    @property
+    def available(self):
+        """Return if switch is available."""
+        return self._device.present
+
+    @property
+    def name(self):
+        """Return the name of the device."""
+        return self._device.name
+
+    @property
+    def is_on(self):
+        """Return true if the switch is on."""
+        return self._device.switch_state
+
+    def turn_on(self, **kwargs):
+        """Turn the switch on."""
+        self._device.set_switch_state_on()
+
+    def turn_off(self, **kwargs):
+        """Turn the switch off."""
+        self._device.set_switch_state_off()
+
+    def update(self):
+        """Get latest data and states from the device."""
+        try:
+            self._device.update()
+        except requests.exceptions.HTTPError as ex:
+            _LOGGER.warning("Fritzhome connection error: %s", ex)
+            self._fritz.login()
+
+    @property
+    def device_state_attributes(self):
+        """Return the state attributes of the device."""
+        attrs = {}
+        attrs[ATTR_STATE_DEVICE_LOCKED] = self._device.device_lock
+        attrs[ATTR_STATE_LOCKED] = self._device.lock
+
+        if self._device.has_powermeter:
+            attrs[ATTR_TOTAL_CONSUMPTION] = "{:.3f}".format(
+                (self._device.energy or 0.0) / 100000)
+            attrs[ATTR_TOTAL_CONSUMPTION_UNIT] = \
+                ATTR_TOTAL_CONSUMPTION_UNIT_VALUE
+        if self._device.has_temperature_sensor:
+            attrs[ATTR_TEMPERATURE] = \
+                str(self.hass.config.units.temperature(
+                    self._device.temperature, TEMP_CELSIUS))
+            attrs[ATTR_TEMPERATURE_UNIT] = \
+                self.hass.config.units.temperature_unit
+        return attrs
+
+    @property
+    def current_power_w(self):
+        """Return the current power usage in W."""
+        return self._device.power / 1000
diff --git a/requirements_all.txt b/requirements_all.txt
index c2ee5814d7bf3d10f8cdd0afa2a306a14e7c797b..b3cf4dbeec1cb83ff963040ad37d227f1367389c 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -765,6 +765,9 @@ pyfido==2.1.1
 # homeassistant.components.climate.flexit
 pyflexit==0.3
 
+# homeassistant.components.fritzbox
+pyfritzhome==0.3.7
+
 # homeassistant.components.ifttt
 pyfttt==0.3