diff --git a/.coveragerc b/.coveragerc
index 094d2dc193a4345b4f512034a93f743e8d66b4bb..e358dbcab75c00ca2e46b51e2b2c68efb8a28ee2 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -158,6 +158,9 @@ omit =
     homeassistant/components/zha/const.py
     homeassistant/components/*/zha.py
 
+    homeassistant/components/eight_sleep.py
+    homeassistant/components/*/eight_sleep.py
+
     homeassistant/components/alarm_control_panel/alarmdotcom.py
     homeassistant/components/alarm_control_panel/concord232.py
     homeassistant/components/alarm_control_panel/nx584.py
diff --git a/homeassistant/components/binary_sensor/eight_sleep.py b/homeassistant/components/binary_sensor/eight_sleep.py
new file mode 100644
index 0000000000000000000000000000000000000000..08f33997c3f7e7bdac74bba23b7b1c0e60411dad
--- /dev/null
+++ b/homeassistant/components/binary_sensor/eight_sleep.py
@@ -0,0 +1,69 @@
+"""
+Support for Eight Sleep binary sensors.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/binary_sensor.eight_sleep/
+"""
+import logging
+import asyncio
+
+from homeassistant.components.binary_sensor import BinarySensorDevice
+from homeassistant.components.eight_sleep import (
+    DATA_EIGHT, EightSleepHeatEntity, CONF_BINARY_SENSORS, NAME_MAP)
+
+DEPENDENCIES = ['eight_sleep']
+
+_LOGGER = logging.getLogger(__name__)
+
+
+@asyncio.coroutine
+def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
+    """Setup the eight sleep binary sensor."""
+    if discovery_info is None:
+        return
+
+    name = 'Eight'
+    sensors = discovery_info[CONF_BINARY_SENSORS]
+    eight = hass.data[DATA_EIGHT]
+
+    all_sensors = []
+
+    for sensor in sensors:
+        all_sensors.append(EightHeatSensor(name, eight, sensor))
+
+    async_add_devices(all_sensors, True)
+
+
+class EightHeatSensor(EightSleepHeatEntity, BinarySensorDevice):
+    """Representation of a eight sleep heat-based sensor."""
+
+    def __init__(self, name, eight, sensor):
+        """Initialize the sensor."""
+        super().__init__(eight)
+
+        self._sensor = sensor
+        self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
+        self._name = '{} {}'.format(name, self._mapped_name)
+        self._state = None
+
+        self._side = self._sensor.split('_')[0]
+        self._userid = self._eight.fetch_userid(self._side)
+        self._usrobj = self._eight.users[self._userid]
+
+        _LOGGER.debug('Presence Sensor: %s, Side: %s, User: %s',
+                      self._sensor, self._side, self._userid)
+
+    @property
+    def name(self):
+        """Return the name of the sensor, if any."""
+        return self._name
+
+    @property
+    def is_on(self):
+        """Return true if the binary sensor is on."""
+        return self._state
+
+    @asyncio.coroutine
+    def async_update(self):
+        """Retrieve latest state."""
+        self._state = self._usrobj.bed_presence
diff --git a/homeassistant/components/eight_sleep.py b/homeassistant/components/eight_sleep.py
new file mode 100644
index 0000000000000000000000000000000000000000..db718aec05e98349eca36302090d82ef0b485551
--- /dev/null
+++ b/homeassistant/components/eight_sleep.py
@@ -0,0 +1,241 @@
+"""
+Support for Eight smart mattress covers and mattresses.
+
+For more details about this component, please refer to the documentation at
+https://home-assistant.io/components/eight_sleep/
+"""
+import asyncio
+import logging
+import os
+from datetime import timedelta
+
+import voluptuous as vol
+
+from homeassistant.core import callback
+from homeassistant.config import load_yaml_config_file
+from homeassistant.const import (
+    CONF_USERNAME, CONF_PASSWORD, CONF_SENSORS, CONF_BINARY_SENSORS,
+    ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_STOP)
+from homeassistant.helpers import discovery
+import homeassistant.helpers.config_validation as cv
+from homeassistant.helpers.dispatcher import (
+    async_dispatcher_send, async_dispatcher_connect)
+from homeassistant.helpers.entity import Entity
+from homeassistant.helpers.event import async_track_point_in_utc_time
+from homeassistant.util.dt import utcnow
+
+REQUIREMENTS = ['pyeight==0.0.4']
+
+_LOGGER = logging.getLogger(__name__)
+
+CONF_PARTNER = 'partner'
+
+DATA_EIGHT = 'eight_sleep'
+DEFAULT_PARTNER = False
+DOMAIN = 'eight_sleep'
+
+HEAT_ENTITY = 'heat'
+USER_ENTITY = 'user'
+
+HEAT_SCAN_INTERVAL = timedelta(seconds=60)
+USER_SCAN_INTERVAL = timedelta(seconds=300)
+
+SIGNAL_UPDATE_HEAT = 'eight_heat_update'
+SIGNAL_UPDATE_USER = 'eight_user_update'
+
+NAME_MAP = {
+    'left_current_sleep': 'Left Sleep Session',
+    'left_last_sleep': 'Left Previous Sleep Session',
+    'left_bed_state': 'Left Bed State',
+    'left_presence': 'Left Bed Presence',
+    'left_bed_temp': 'Left Bed Temperature',
+    'left_sleep_stage': 'Left Sleep Stage',
+    'right_current_sleep': 'Right Sleep Session',
+    'right_last_sleep': 'Right Previous Sleep Session',
+    'right_bed_state': 'Right Bed State',
+    'right_presence': 'Right Bed Presence',
+    'right_bed_temp': 'Right Bed Temperature',
+    'right_sleep_stage': 'Right Sleep Stage',
+    'room_temp': 'Room Temperature',
+}
+
+SENSORS = ['current_sleep',
+           'last_sleep',
+           'bed_state',
+           'bed_temp',
+           'sleep_stage']
+
+SERVICE_HEAT_SET = 'heat_set'
+
+ATTR_TARGET_HEAT = 'target'
+ATTR_HEAT_DURATION = 'duration'
+
+VALID_TARGET_HEAT = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=100))
+VALID_DURATION = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=28800))
+
+SERVICE_EIGHT_SCHEMA = vol.Schema({
+    ATTR_ENTITY_ID: cv.entity_ids,
+    ATTR_TARGET_HEAT: VALID_TARGET_HEAT,
+    ATTR_HEAT_DURATION: VALID_DURATION,
+    })
+
+CONFIG_SCHEMA = vol.Schema({
+    DOMAIN: vol.Schema({
+        vol.Required(CONF_USERNAME): cv.string,
+        vol.Required(CONF_PASSWORD): cv.string,
+        vol.Optional(CONF_PARTNER, default=DEFAULT_PARTNER): cv.boolean,
+    }),
+}, extra=vol.ALLOW_EXTRA)
+
+
+@asyncio.coroutine
+def async_setup(hass, config):
+    """Set up the Eight Sleep component."""
+    from pyeight.eight import EightSleep
+
+    conf = config.get(DOMAIN)
+    user = conf.get(CONF_USERNAME)
+    password = conf.get(CONF_PASSWORD)
+    partner = conf.get(CONF_PARTNER)
+
+    if hass.config.time_zone is None:
+        _LOGGER.error('Timezone is not set in Home Assistant.')
+        return False
+
+    timezone = hass.config.time_zone
+
+    eight = EightSleep(user, password, timezone, partner, None, hass.loop)
+
+    hass.data[DATA_EIGHT] = eight
+
+    # Authenticate, build sensors
+    success = yield from eight.start()
+    if not success:
+        # Authentication failed, cannot continue
+        return False
+
+    @asyncio.coroutine
+    def async_update_heat_data(now):
+        """Update heat data from eight in HEAT_SCAN_INTERVAL."""
+        yield from eight.update_device_data()
+        async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT)
+
+        async_track_point_in_utc_time(
+            hass, async_update_heat_data, utcnow() + HEAT_SCAN_INTERVAL)
+
+    @asyncio.coroutine
+    def async_update_user_data(now):
+        """Update user data from eight in USER_SCAN_INTERVAL."""
+        yield from eight.update_user_data()
+        async_dispatcher_send(hass, SIGNAL_UPDATE_USER)
+
+        async_track_point_in_utc_time(
+            hass, async_update_user_data, utcnow() + USER_SCAN_INTERVAL)
+
+    yield from async_update_heat_data(None)
+    yield from async_update_user_data(None)
+
+    # Load sub components
+    sensors = []
+    binary_sensors = []
+    if eight.users:
+        for user in eight.users:
+            obj = eight.users[user]
+            for sensor in SENSORS:
+                sensors.append('{}_{}'.format(obj.side, sensor))
+            binary_sensors.append('{}_presence'.format(obj.side))
+        sensors.append('room_temp')
+
+    hass.async_add_job(discovery.async_load_platform(
+        hass, 'sensor', DOMAIN, {
+            CONF_SENSORS: sensors,
+        }, config))
+
+    hass.async_add_job(discovery.async_load_platform(
+        hass, 'binary_sensor', DOMAIN, {
+            CONF_BINARY_SENSORS: binary_sensors,
+        }, config))
+
+    descriptions = yield from hass.loop.run_in_executor(
+        None, load_yaml_config_file,
+        os.path.join(os.path.dirname(__file__), 'services.yaml'))
+
+    @asyncio.coroutine
+    def async_service_handler(service):
+        """Handle eight sleep service calls."""
+        params = service.data.copy()
+
+        sensor = params.pop(ATTR_ENTITY_ID, None)
+        target = params.pop(ATTR_TARGET_HEAT, None)
+        duration = params.pop(ATTR_HEAT_DURATION, 0)
+
+        for sens in sensor:
+            side = sens.split('_')[1]
+            userid = eight.fetch_userid(side)
+            usrobj = eight.users[userid]
+            yield from usrobj.set_heating_level(target, duration)
+
+        async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT)
+
+    # Register services
+    hass.services.async_register(
+        DOMAIN, SERVICE_HEAT_SET, async_service_handler,
+        descriptions[DOMAIN].get(SERVICE_HEAT_SET),
+        schema=SERVICE_EIGHT_SCHEMA)
+
+    @asyncio.coroutine
+    def stop_eight(event):
+        """Handle stopping eight api session."""
+        yield from eight.stop()
+
+    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_eight)
+
+    return True
+
+
+class EightSleepUserEntity(Entity):
+    """The Eight Sleep device entity."""
+
+    def __init__(self, eight):
+        """Initialize the data oject."""
+        self._eight = eight
+
+    @asyncio.coroutine
+    def async_added_to_hass(self):
+        """Register update dispatcher."""
+        @callback
+        def async_eight_user_update():
+            """Update callback."""
+            self.hass.async_add_job(self.async_update_ha_state(True))
+
+        async_dispatcher_connect(
+            self.hass, SIGNAL_UPDATE_USER, async_eight_user_update)
+
+    @property
+    def should_poll(self):
+        """Return True if entity has to be polled for state."""
+        return False
+
+
+class EightSleepHeatEntity(Entity):
+    """The Eight Sleep device entity."""
+
+    def __init__(self, eight):
+        """Initialize the data oject."""
+        self._eight = eight
+
+    @asyncio.coroutine
+    def async_added_to_hass(self):
+        """Register update dispatcher."""
+        @callback
+        def async_eight_heat_update():
+            """Update callback."""
+            self.hass.async_add_job(self.async_update_ha_state(True))
+
+        async_dispatcher_connect(
+            self.hass, SIGNAL_UPDATE_HEAT, async_eight_heat_update)
+
+    @property
+    def should_poll(self):
+        """Return True if entity has to be polled for state."""
+        return False
diff --git a/homeassistant/components/sensor/eight_sleep.py b/homeassistant/components/sensor/eight_sleep.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7d3e2407017906c343a0415d5669713b5b7c9ed
--- /dev/null
+++ b/homeassistant/components/sensor/eight_sleep.py
@@ -0,0 +1,273 @@
+"""
+Support for Eight Sleep sensors.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/sensor.eight_sleep/
+"""
+import logging
+import asyncio
+
+from homeassistant.components.eight_sleep import (
+    DATA_EIGHT, EightSleepHeatEntity, EightSleepUserEntity,
+    CONF_SENSORS, NAME_MAP)
+
+DEPENDENCIES = ['eight_sleep']
+
+ATTR_ROOM_TEMP = 'Room Temperature'
+ATTR_AVG_ROOM_TEMP = 'Average Room Temperature'
+ATTR_BED_TEMP = 'Bed Temperature'
+ATTR_AVG_BED_TEMP = 'Average Bed Temperature'
+ATTR_RESP_RATE = 'Respiratory Rate'
+ATTR_AVG_RESP_RATE = 'Average Respiratory Rate'
+ATTR_HEART_RATE = 'Heart Rate'
+ATTR_AVG_HEART_RATE = 'Average Heart Rate'
+ATTR_SLEEP_DUR = 'Time Slept'
+ATTR_LIGHT_PERC = 'Light Sleep %'
+ATTR_DEEP_PERC = 'Deep Sleep %'
+ATTR_TNT = 'Tosses & Turns'
+ATTR_SLEEP_STAGE = 'Sleep Stage'
+ATTR_TARGET_HEAT = 'Target Heating Level'
+ATTR_ACTIVE_HEAT = 'Heating Active'
+ATTR_DURATION_HEAT = 'Heating Time Remaining'
+ATTR_LAST_SEEN = 'Last In Bed'
+ATTR_PROCESSING = 'Processing'
+ATTR_SESSION_START = 'Session Start'
+
+_LOGGER = logging.getLogger(__name__)
+
+
+@asyncio.coroutine
+def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
+    """Setup the eight sleep sensors."""
+    if discovery_info is None:
+        return
+
+    name = 'Eight'
+    sensors = discovery_info[CONF_SENSORS]
+    eight = hass.data[DATA_EIGHT]
+
+    if hass.config.units.is_metric:
+        units = 'si'
+    else:
+        units = 'us'
+
+    all_sensors = []
+
+    for sensor in sensors:
+        if 'bed_state' in sensor:
+            all_sensors.append(EightHeatSensor(name, eight, sensor))
+        elif 'room_temp' in sensor:
+            all_sensors.append(EightRoomSensor(name, eight, sensor, units))
+        else:
+            all_sensors.append(EightUserSensor(name, eight, sensor, units))
+
+    async_add_devices(all_sensors, True)
+
+
+class EightHeatSensor(EightSleepHeatEntity):
+    """Representation of a eight sleep heat-based sensor."""
+
+    def __init__(self, name, eight, sensor):
+        """Initialize the sensor."""
+        super().__init__(eight)
+
+        self._sensor = sensor
+        self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
+        self._name = '{} {}'.format(name, self._mapped_name)
+        self._state = None
+
+        self._side = self._sensor.split('_')[0]
+        self._userid = self._eight.fetch_userid(self._side)
+        self._usrobj = self._eight.users[self._userid]
+
+        _LOGGER.debug('Heat Sensor: %s, Side: %s, User: %s',
+                      self._sensor, self._side, self._userid)
+
+    @property
+    def name(self):
+        """Return the name of the sensor, if any."""
+        return self._name
+
+    @property
+    def state(self):
+        """Return the state of the sensor."""
+        return self._state
+
+    @property
+    def unit_of_measurement(self):
+        """Return the unit the value is expressed in."""
+        return '%'
+
+    @asyncio.coroutine
+    def async_update(self):
+        """Retrieve latest state."""
+        _LOGGER.debug('Updating Heat sensor: %s', self._sensor)
+        self._state = self._usrobj.heating_level
+
+    @property
+    def device_state_attributes(self):
+        """Return device state attributes."""
+        state_attr = {ATTR_TARGET_HEAT: self._usrobj.target_heating_level}
+        state_attr[ATTR_ACTIVE_HEAT] = self._usrobj.now_heating
+        state_attr[ATTR_DURATION_HEAT] = self._usrobj.heating_remaining
+        state_attr[ATTR_LAST_SEEN] = self._usrobj.last_seen
+
+        return state_attr
+
+
+class EightUserSensor(EightSleepUserEntity):
+    """Representation of a eight sleep user-based sensor."""
+
+    def __init__(self, name, eight, sensor, units):
+        """Initialize the sensor."""
+        super().__init__(eight)
+
+        self._sensor = sensor
+        self._sensor_root = self._sensor.split('_', 1)[1]
+        self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
+        self._name = '{} {}'.format(name, self._mapped_name)
+        self._state = None
+        self._attr = None
+        self._units = units
+
+        self._side = self._sensor.split('_', 1)[0]
+        self._userid = self._eight.fetch_userid(self._side)
+        self._usrobj = self._eight.users[self._userid]
+
+        _LOGGER.debug('User Sensor: %s, Side: %s, User: %s',
+                      self._sensor, self._side, self._userid)
+
+    @property
+    def name(self):
+        """Return the name of the sensor, if any."""
+        return self._name
+
+    @property
+    def state(self):
+        """Return the state of the sensor."""
+        return self._state
+
+    @property
+    def unit_of_measurement(self):
+        """Return the unit the value is expressed in."""
+        if 'current_sleep' in self._sensor or 'last_sleep' in self._sensor:
+            return 'Score'
+        elif 'bed_temp' in self._sensor:
+            if self._units == 'si':
+                return '°C'
+            else:
+                return '°F'
+
+    @property
+    def icon(self):
+        """Icon to use in the frontend, if any."""
+        if 'bed_temp' in self._sensor:
+            return 'mdi:thermometer'
+
+    @asyncio.coroutine
+    def async_update(self):
+        """Retrieve latest state."""
+        _LOGGER.debug('Updating User sensor: %s', self._sensor)
+        if 'current' in self._sensor:
+            self._state = self._usrobj.current_sleep_score
+            self._attr = self._usrobj.current_values
+        elif 'last' in self._sensor:
+            self._state = self._usrobj.last_sleep_score
+            self._attr = self._usrobj.last_values
+        elif 'bed_temp' in self._sensor:
+            temp = self._usrobj.current_values['bed_temp']
+            if self._units == 'si':
+                self._state = round(temp, 2)
+            else:
+                self._state = round((temp*1.8)+32, 2)
+        elif 'sleep_stage' in self._sensor:
+            self._state = self._usrobj.current_values['stage']
+
+    @property
+    def device_state_attributes(self):
+        """Return device state attributes."""
+        if self._attr is None:
+            # Skip attributes if sensor type doesn't support
+            return None
+
+        state_attr = {ATTR_SESSION_START: self._attr['date']}
+        state_attr[ATTR_TNT] = self._attr['tnt']
+        state_attr[ATTR_PROCESSING] = self._attr['processing']
+
+        sleep_time = sum(self._attr['breakdown'].values()) - \
+            self._attr['breakdown']['awake']
+        state_attr[ATTR_SLEEP_DUR] = sleep_time
+        state_attr[ATTR_LIGHT_PERC] = round((
+            self._attr['breakdown']['light'] / sleep_time) * 100, 2)
+        state_attr[ATTR_DEEP_PERC] = round((
+            self._attr['breakdown']['deep'] / sleep_time) * 100, 2)
+
+        if self._units == 'si':
+            room_temp = round(self._attr['room_temp'], 2)
+            bed_temp = round(self._attr['bed_temp'], 2)
+        else:
+            room_temp = round((self._attr['room_temp']*1.8)+32, 2)
+            bed_temp = round((self._attr['bed_temp']*1.8)+32, 2)
+
+        if 'current' in self._sensor_root:
+            state_attr[ATTR_RESP_RATE] = round(self._attr['resp_rate'], 2)
+            state_attr[ATTR_HEART_RATE] = round(self._attr['heart_rate'], 2)
+            state_attr[ATTR_SLEEP_STAGE] = self._attr['stage']
+            state_attr[ATTR_ROOM_TEMP] = room_temp
+            state_attr[ATTR_BED_TEMP] = bed_temp
+        elif 'last' in self._sensor_root:
+            state_attr[ATTR_AVG_RESP_RATE] = round(self._attr['resp_rate'], 2)
+            state_attr[ATTR_AVG_HEART_RATE] = round(
+                self._attr['heart_rate'], 2)
+            state_attr[ATTR_AVG_ROOM_TEMP] = room_temp
+            state_attr[ATTR_AVG_BED_TEMP] = bed_temp
+
+        return state_attr
+
+
+class EightRoomSensor(EightSleepUserEntity):
+    """Representation of a eight sleep room sensor."""
+
+    def __init__(self, name, eight, sensor, units):
+        """Initialize the sensor."""
+        super().__init__(eight)
+
+        self._sensor = sensor
+        self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
+        self._name = '{} {}'.format(name, self._mapped_name)
+        self._state = None
+        self._attr = None
+        self._units = units
+
+    @property
+    def name(self):
+        """Return the name of the sensor, if any."""
+        return self._name
+
+    @property
+    def state(self):
+        """Return the state of the sensor."""
+        return self._state
+
+    @asyncio.coroutine
+    def async_update(self):
+        """Retrieve latest state."""
+        _LOGGER.debug('Updating Room sensor: %s', self._sensor)
+        temp = self._eight.room_temperature()
+        if self._units == 'si':
+            self._state = round(temp, 2)
+        else:
+            self._state = round((temp*1.8)+32, 2)
+
+    @property
+    def unit_of_measurement(self):
+        """Return the unit the value is expressed in."""
+        if self._units == 'si':
+            return '°C'
+        else:
+            return '°F'
+
+    @property
+    def icon(self):
+        """Icon to use in the frontend, if any."""
+        return 'mdi:thermometer'
diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml
index 6cff6d5f4f45801cf3beaa0f5b6bfed87ede6540..0807eb617eebed71f2a2ca3b7ba29f6c3c56d4c6 100644
--- a/homeassistant/components/services.yaml
+++ b/homeassistant/components/services.yaml
@@ -388,3 +388,17 @@ hassio:
       addon:
         description: Name of addon.
         example: 'smb_config'
+
+eight_sleep:
+  heat_set:
+    description: Set heating level for eight sleep.
+    fields:
+      entity_id:
+        description: Entity id of the bed state to adjust.
+        example: 'sensor.eight_left_bed_state'
+      target:
+        description: Target heating level from 0-100.
+        example: 35
+      duration:
+        description: Duration to heat at the target level in seconds.
+        example: 3600
diff --git a/requirements_all.txt b/requirements_all.txt
index 03bebd8ddaf51602bab740d812776fdbb761dfe9..5ee8aa61ef52a7c95bd5e802c62b6489cc5ddd71 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -530,6 +530,9 @@ pydroid-ipcam==0.8
 # homeassistant.components.sensor.ebox
 pyebox==0.1.0
 
+# homeassistant.components.eight_sleep
+pyeight==0.0.4
+
 # homeassistant.components.notify.html5
 pyelliptic==1.5.7