diff --git a/homeassistant/components/binary_sensor/bmw_connected_drive.py b/homeassistant/components/binary_sensor/bmw_connected_drive.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c848a57fbf0832819ba8ea14dd837d56f6a1e8f
--- /dev/null
+++ b/homeassistant/components/binary_sensor/bmw_connected_drive.py
@@ -0,0 +1,117 @@
+"""
+Reads vehicle status from BMW connected drive portal.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/binary_sensor.bmw_connected_drive/
+"""
+import asyncio
+import logging
+
+from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN
+from homeassistant.components.binary_sensor import BinarySensorDevice
+
+DEPENDENCIES = ['bmw_connected_drive']
+
+_LOGGER = logging.getLogger(__name__)
+
+SENSOR_TYPES = {
+    'all_lids_closed': ['Doors', 'opening'],
+    'all_windows_closed': ['Windows', 'opening'],
+    'door_lock_state': ['Door lock state', 'safety']
+}
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the BMW sensors."""
+    accounts = hass.data[BMW_DOMAIN]
+    _LOGGER.debug('Found BMW accounts: %s',
+                  ', '.join([a.name for a in accounts]))
+    devices = []
+    for account in accounts:
+        for vehicle in account.account.vehicles:
+            for key, value in sorted(SENSOR_TYPES.items()):
+                device = BMWConnectedDriveSensor(account, vehicle, key,
+                                                 value[0], value[1])
+                devices.append(device)
+    add_devices(devices, True)
+
+
+class BMWConnectedDriveSensor(BinarySensorDevice):
+    """Representation of a BMW vehicle binary sensor."""
+
+    def __init__(self, account, vehicle, attribute: str, sensor_name,
+                 device_class):
+        """Constructor."""
+        self._account = account
+        self._vehicle = vehicle
+        self._attribute = attribute
+        self._name = sensor_name
+        self._device_class = device_class
+        self._state = None
+
+    @property
+    def should_poll(self) -> bool:
+        """Data update is triggered from BMWConnectedDriveEntity."""
+        return False
+
+    @property
+    def name(self):
+        """Return the name of the binary sensor."""
+        return self._name
+
+    @property
+    def device_class(self):
+        """Return the class of the binary sensor."""
+        return self._device_class
+
+    @property
+    def is_on(self):
+        """Return the state of the binary sensor."""
+        return self._state
+
+    @property
+    def device_state_attributes(self):
+        """Return the state attributes of the binary sensor."""
+        vehicle_state = self._vehicle.state
+        result = {
+            'car': self._vehicle.modelName
+        }
+
+        if self._attribute == 'all_lids_closed':
+            for lid in vehicle_state.lids:
+                result[lid.name] = lid.state.value
+        elif self._attribute == 'all_windows_closed':
+            for window in vehicle_state.windows:
+                result[window.name] = window.state.value
+        elif self._attribute == 'door_lock_state':
+            result['door_lock_state'] = vehicle_state.door_lock_state.value
+
+        return result
+
+    def update(self):
+        """Read new state data from the library."""
+        vehicle_state = self._vehicle.state
+
+        # device class opening: On means open, Off means closed
+        if self._attribute == 'all_lids_closed':
+            _LOGGER.debug("Status of lid: %s", vehicle_state.all_lids_closed)
+            self._state = not vehicle_state.all_lids_closed
+        if self._attribute == 'all_windows_closed':
+            self._state = not vehicle_state.all_windows_closed
+        # device class safety: On means unsafe, Off means safe
+        if self._attribute == 'door_lock_state':
+            # Possible values: LOCKED, SECURED, SELECTIVELOCKED, UNLOCKED
+            self._state = bool(vehicle_state.door_lock_state.value
+                               in ('SELECTIVELOCKED', 'UNLOCKED'))
+
+    def update_callback(self):
+        """Schedule a state update."""
+        self.schedule_update_ha_state(True)
+
+    @asyncio.coroutine
+    def async_added_to_hass(self):
+        """Add callback after being added to hass.
+
+        Show latest data after startup.
+        """
+        self._account.add_update_listener(self.update_callback)
diff --git a/homeassistant/components/bmw_connected_drive.py b/homeassistant/components/bmw_connected_drive.py
index 86048a56e2239de6d6fb35ec5a1163d3a4dcc02c..9e9e2bafac5c036f676e1940e1e2bbec4976fc2e 100644
--- a/homeassistant/components/bmw_connected_drive.py
+++ b/homeassistant/components/bmw_connected_drive.py
@@ -37,7 +37,7 @@ CONFIG_SCHEMA = vol.Schema({
 }, extra=vol.ALLOW_EXTRA)
 
 
-BMW_COMPONENTS = ['device_tracker', 'sensor']
+BMW_COMPONENTS = ['binary_sensor', 'device_tracker', 'lock', 'sensor']
 UPDATE_INTERVAL = 5  # in minutes
 
 
diff --git a/homeassistant/components/lock/bmw_connected_drive.py b/homeassistant/components/lock/bmw_connected_drive.py
new file mode 100644
index 0000000000000000000000000000000000000000..4592fd7cae9220bba2251d2341b76a538ef4bd8e
--- /dev/null
+++ b/homeassistant/components/lock/bmw_connected_drive.py
@@ -0,0 +1,108 @@
+"""
+Support for BMW cars with BMW ConnectedDrive.
+
+For more details about this component, please refer to the documentation at
+https://home-assistant.io/components/lock.bmw_connected_drive/
+"""
+import asyncio
+import logging
+
+from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN
+from homeassistant.components.lock import LockDevice
+from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
+
+DEPENDENCIES = ['bmw_connected_drive']
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Setup the BMW Connected Drive lock."""
+    accounts = hass.data[BMW_DOMAIN]
+    _LOGGER.debug('Found BMW accounts: %s',
+                  ', '.join([a.name for a in accounts]))
+    devices = []
+    for account in accounts:
+        for vehicle in account.account.vehicles:
+            device = BMWLock(account, vehicle, 'lock', 'BMW lock')
+            devices.append(device)
+    add_devices(devices, True)
+
+
+class BMWLock(LockDevice):
+    """Representation of a BMW vehicle lock."""
+
+    def __init__(self, account, vehicle, attribute: str, sensor_name):
+        """Initialize the lock."""
+        self._account = account
+        self._vehicle = vehicle
+        self._attribute = attribute
+        self._name = sensor_name
+        self._state = None
+
+    @property
+    def should_poll(self):
+        """Do not poll this class.
+
+        Updates are triggered from BMWConnectedDriveAccount.
+        """
+        return False
+
+    @property
+    def name(self):
+        """Return the name of the lock."""
+        return self._name
+
+    @property
+    def device_state_attributes(self):
+        """Return the state attributes of the lock."""
+        vehicle_state = self._vehicle.state
+        return {
+            'car': self._vehicle.modelName,
+            'door_lock_state': vehicle_state.door_lock_state.value
+        }
+
+    @property
+    def is_locked(self):
+        """Return true if lock is locked."""
+        return self._state == STATE_LOCKED
+
+    def lock(self, **kwargs):
+        """Lock the car."""
+        _LOGGER.debug("%s: locking doors", self._vehicle.modelName)
+        # Optimistic state set here because it takes some time before the
+        # update callback response
+        self._state = STATE_LOCKED
+        self.schedule_update_ha_state()
+        self._vehicle.remote_services.trigger_remote_door_lock()
+
+    def unlock(self, **kwargs):
+        """Unlock the car."""
+        _LOGGER.debug("%s: unlocking doors", self._vehicle.modelName)
+        # Optimistic state set here because it takes some time before the
+        # update callback response
+        self._state = STATE_UNLOCKED
+        self.schedule_update_ha_state()
+        self._vehicle.remote_services.trigger_remote_door_unlock()
+
+    def update(self):
+        """Update state of the lock."""
+        _LOGGER.debug("%s: updating data for %s", self._vehicle.modelName,
+                      self._attribute)
+        vehicle_state = self._vehicle.state
+
+        # Possible values: LOCKED, SECURED, SELECTIVELOCKED, UNLOCKED
+        self._state = (STATE_LOCKED if vehicle_state.door_lock_state.value
+                       in ('LOCKED', 'SECURED') else STATE_UNLOCKED)
+
+    def update_callback(self):
+        """Schedule a state update."""
+        self.schedule_update_ha_state(True)
+
+    @asyncio.coroutine
+    def async_added_to_hass(self):
+        """Add callback after being added to hass.
+
+        Show latest data after startup.
+        """
+        self._account.add_update_listener(self.update_callback)
diff --git a/homeassistant/components/sensor/bmw_connected_drive.py b/homeassistant/components/sensor/bmw_connected_drive.py
index 26bfd19e6fc6772bbf8168648e5d6acc3c3a64b1..76719763931fe84278f87508ea9671be01f15424 100644
--- a/homeassistant/components/sensor/bmw_connected_drive.py
+++ b/homeassistant/components/sensor/bmw_connected_drive.py
@@ -14,14 +14,16 @@ DEPENDENCIES = ['bmw_connected_drive']
 
 _LOGGER = logging.getLogger(__name__)
 
-LENGTH_ATTRIBUTES = [
-    'remaining_range_fuel',
-    'mileage',
-    ]
+LENGTH_ATTRIBUTES = {
+    'remaining_range_fuel': ['Range (fuel)', 'mdi:ruler'],
+    'mileage': ['Mileage', 'mdi:speedometer']
+}
 
-VALID_ATTRIBUTES = LENGTH_ATTRIBUTES + [
-    'remaining_fuel',
-]
+VALID_ATTRIBUTES = {
+    'remaining_fuel': ['Remaining Fuel', 'mdi:gas-station']
+}
+
+VALID_ATTRIBUTES.update(LENGTH_ATTRIBUTES)
 
 
 def setup_platform(hass, config, add_devices, discovery_info=None):
@@ -32,23 +34,25 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
     devices = []
     for account in accounts:
         for vehicle in account.account.vehicles:
-            for sensor in VALID_ATTRIBUTES:
-                device = BMWConnectedDriveSensor(account, vehicle, sensor)
+            for key, value in sorted(VALID_ATTRIBUTES.items()):
+                device = BMWConnectedDriveSensor(account, vehicle, key,
+                                                 value[0], value[1])
                 devices.append(device)
-    add_devices(devices)
+    add_devices(devices, True)
 
 
 class BMWConnectedDriveSensor(Entity):
     """Representation of a BMW vehicle sensor."""
 
-    def __init__(self, account, vehicle, attribute: str):
+    def __init__(self, account, vehicle, attribute: str, sensor_name, icon):
         """Constructor."""
         self._vehicle = vehicle
         self._account = account
         self._attribute = attribute
         self._state = None
         self._unit_of_measurement = None
-        self._name = '{} {}'.format(self._vehicle.modelName, self._attribute)
+        self._name = sensor_name
+        self._icon = icon
 
     @property
     def should_poll(self) -> bool:
@@ -60,6 +64,11 @@ class BMWConnectedDriveSensor(Entity):
         """Return the name of the sensor."""
         return self._name
 
+    @property
+    def icon(self):
+        """Icon to use in the frontend, if any."""
+        return self._icon
+
     @property
     def state(self):
         """Return the state of the sensor.
@@ -74,9 +83,16 @@ class BMWConnectedDriveSensor(Entity):
         """Get the unit of measurement."""
         return self._unit_of_measurement
 
+    @property
+    def device_state_attributes(self):
+        """Return the state attributes of the binary sensor."""
+        return {
+            'car': self._vehicle.modelName
+        }
+
     def update(self) -> None:
         """Read new state data from the library."""
-        _LOGGER.debug('Updating %s', self.entity_id)
+        _LOGGER.debug('Updating %s', self._vehicle.modelName)
         vehicle_state = self._vehicle.state
         self._state = getattr(vehicle_state, self._attribute)
 
@@ -87,7 +103,9 @@ class BMWConnectedDriveSensor(Entity):
         else:
             self._unit_of_measurement = None
 
-        self.schedule_update_ha_state()
+    def update_callback(self):
+        """Schedule a state update."""
+        self.schedule_update_ha_state(True)
 
     @asyncio.coroutine
     def async_added_to_hass(self):
@@ -95,5 +113,4 @@ class BMWConnectedDriveSensor(Entity):
 
         Show latest data after startup.
         """
-        self._account.add_update_listener(self.update)
-        yield from self.hass.async_add_job(self.update)
+        self._account.add_update_listener(self.update_callback)