diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py
index c3e13047aad246f2a1af93d6d7f3601ff96a0141..313ae86581692db225d4a4e6e148f0230edbe323 100644
--- a/homeassistant/components/binary_sensor/__init__.py
+++ b/homeassistant/components/binary_sensor/__init__.py
@@ -26,6 +26,9 @@ SENSOR_CLASSES = [
     'light',     # Lightness threshold
     'power',     # Power, over-current, etc
     'safety',    # Generic on=unsafe, off=safe
+    'heat',      # On means hot (or too hot)
+    'cold',      # On means cold (or too cold)
+    'moving',    # On means moving, Off means stopped
 ]
 
 # Maps discovered services to their platforms
diff --git a/homeassistant/components/binary_sensor/template.py b/homeassistant/components/binary_sensor/template.py
new file mode 100644
index 0000000000000000000000000000000000000000..f5a8899af964d0b8efe504b0aad113e60be2f02d
--- /dev/null
+++ b/homeassistant/components/binary_sensor/template.py
@@ -0,0 +1,122 @@
+"""
+homeassistant.components.binary_sensor.template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Support for exposing a templated binary_sensor
+"""
+import logging
+
+from homeassistant.components.binary_sensor import (BinarySensorDevice,
+                                                    DOMAIN,
+                                                    SENSOR_CLASSES)
+from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_VALUE_TEMPLATE
+from homeassistant.core import EVENT_STATE_CHANGED
+from homeassistant.exceptions import TemplateError
+from homeassistant.helpers.entity import generate_entity_id
+from homeassistant.helpers import template
+from homeassistant.util import slugify
+
+ENTITY_ID_FORMAT = DOMAIN + '.{}'
+CONF_SENSORS = 'sensors'
+_LOGGER = logging.getLogger(__name__)
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Setup template binary sensors."""
+
+    sensors = []
+    if config.get(CONF_SENSORS) is None:
+        _LOGGER.error('Missing configuration data for binary_sensor platform')
+        return False
+
+    for device, device_config in config[CONF_SENSORS].items():
+
+        if device != slugify(device):
+            _LOGGER.error('Found invalid key for binary_sensor.template: %s. '
+                          'Use %s instead', device, slugify(device))
+            continue
+
+        if not isinstance(device_config, dict):
+            _LOGGER.error('Missing configuration data for binary_sensor %s',
+                          device)
+            continue
+
+        friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device)
+        sensor_class = device_config.get('sensor_class')
+        value_template = device_config.get(CONF_VALUE_TEMPLATE)
+
+        if sensor_class not in SENSOR_CLASSES:
+            _LOGGER.error('Sensor class is not valid')
+            continue
+
+        if value_template is None:
+            _LOGGER.error(
+                'Missing %s for sensor %s', CONF_VALUE_TEMPLATE, device)
+            continue
+
+        sensors.append(
+            BinarySensorTemplate(
+                hass,
+                device,
+                friendly_name,
+                sensor_class,
+                value_template)
+            )
+    if not sensors:
+        _LOGGER.error('No sensors added')
+        return False
+    add_devices(sensors)
+
+    return True
+
+
+class BinarySensorTemplate(BinarySensorDevice):
+    """A virtual binary_sensor that triggers from another sensor."""
+
+    # pylint: disable=too-many-arguments
+    def __init__(self, hass, device, friendly_name, sensor_class,
+                 value_template):
+        self._hass = hass
+        self._device = device
+        self._name = friendly_name
+        self._sensor_class = sensor_class
+        self._template = value_template
+        self._state = None
+
+        self.entity_id = generate_entity_id(
+            ENTITY_ID_FORMAT, device,
+            hass=hass)
+
+        _LOGGER.info('Started template sensor %s', device)
+        hass.bus.listen(EVENT_STATE_CHANGED, self._event_listener)
+
+    def _event_listener(self, event):
+        self.update_ha_state(True)
+
+    @property
+    def should_poll(self):
+        return False
+
+    @property
+    def sensor_class(self):
+        return self._sensor_class
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def is_on(self):
+        return self._state
+
+    def update(self):
+        try:
+            value = template.render(self._hass, self._template)
+        except TemplateError as ex:
+            if ex.args and ex.args[0].startswith(
+                    "UndefinedError: 'None' has no attribute"):
+                # Common during HA startup - so just a warning
+                _LOGGER.warning(ex)
+                return
+            _LOGGER.error(ex)
+            value = 'false'
+        self._state = value.lower() == 'true'
diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py
index bc80fd89a81713935b0b8bc6a9ed4d8c7300d2de..9c9ebd429137633104db74f404d65bf5f17d8785 100644
--- a/homeassistant/helpers/template.py
+++ b/homeassistant/helpers/template.py
@@ -52,6 +52,7 @@ def render(hass, template, variables=None, **kwargs):
         return ENV.from_string(template, {
             'closest': location_methods.closest,
             'distance': location_methods.distance,
+            'float': forgiving_float,
             'is_state': hass.states.is_state,
             'is_state_attr': hass.states.is_state_attr,
             'now': dt_util.as_local(utcnow),
@@ -240,6 +241,14 @@ def multiply(value, amount):
         return value
 
 
+def forgiving_float(value):
+    """Try to convert value to a float."""
+    try:
+        return float(value)
+    except (ValueError, TypeError):
+        return value
+
+
 class TemplateEnvironment(ImmutableSandboxedEnvironment):
     """Home Assistant template environment."""
 
diff --git a/tests/components/binary_sensor/test_template.py b/tests/components/binary_sensor/test_template.py
new file mode 100644
index 0000000000000000000000000000000000000000..7fc18a930f1f09ab0658dbe1f5934b1fccdfabf0
--- /dev/null
+++ b/tests/components/binary_sensor/test_template.py
@@ -0,0 +1,111 @@
+"""
+tests.components.binary_sensor.test_template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Tests for template binary_sensor.
+"""
+
+import unittest
+from unittest import mock
+
+from homeassistant.components.binary_sensor import template
+from homeassistant.exceptions import TemplateError
+
+
+class TestBinarySensorTemplate(unittest.TestCase):
+    @mock.patch.object(template, 'BinarySensorTemplate')
+    def test_setup(self, mock_template):
+        config = {
+            'sensors': {
+                'test': {
+                    'friendly_name': 'virtual thingy',
+                    'value_template': '{{ foo }}',
+                    'sensor_class': 'motion',
+                },
+            }
+        }
+        hass = mock.MagicMock()
+        add_devices = mock.MagicMock()
+        result = template.setup_platform(hass, config, add_devices)
+        self.assertTrue(result)
+        mock_template.assert_called_once_with(hass, 'test', 'virtual thingy',
+                                              'motion', '{{ foo }}')
+        add_devices.assert_called_once_with([mock_template.return_value])
+
+    def test_setup_no_sensors(self):
+        config = {}
+        result = template.setup_platform(None, config, None)
+        self.assertFalse(result)
+
+    def test_setup_invalid_device(self):
+        config = {
+            'sensors': {
+                'foo bar': {},
+            },
+        }
+        result = template.setup_platform(None, config, None)
+        self.assertFalse(result)
+
+    def test_setup_invalid_sensor_class(self):
+        config = {
+            'sensors': {
+                'test': {
+                    'value_template': '{{ foo }}',
+                    'sensor_class': 'foobarnotreal',
+                },
+            },
+        }
+        result = template.setup_platform(None, config, None)
+        self.assertFalse(result)
+
+    def test_setup_invalid_missing_template(self):
+        config = {
+            'sensors': {
+                'test': {
+                    'sensor_class': 'motion',
+                },
+            },
+        }
+        result = template.setup_platform(None, config, None)
+        self.assertFalse(result)
+
+    def test_attributes(self):
+        hass = mock.MagicMock()
+        vs = template.BinarySensorTemplate(hass, 'parent', 'Parent',
+                                           'motion', '{{ 1 > 1 }}')
+        self.assertFalse(vs.should_poll)
+        self.assertEqual('motion', vs.sensor_class)
+        self.assertEqual('Parent', vs.name)
+
+        vs.update()
+        self.assertFalse(vs.is_on)
+
+        vs._template = "{{ 2 > 1 }}"
+        vs.update()
+        self.assertTrue(vs.is_on)
+
+    def test_event(self):
+        hass = mock.MagicMock()
+        vs = template.BinarySensorTemplate(hass, 'parent', 'Parent',
+                                           'motion', '{{ 1 > 1 }}')
+        with mock.patch.object(vs, 'update_ha_state') as mock_update:
+            vs._event_listener(None)
+            mock_update.assert_called_once_with(True)
+
+    def test_update(self):
+        hass = mock.MagicMock()
+        vs = template.BinarySensorTemplate(hass, 'parent', 'Parent',
+                                           'motion', '{{ 2 > 1 }}')
+        self.assertEqual(None, vs._state)
+        vs.update()
+        self.assertTrue(vs._state)
+
+    @mock.patch('homeassistant.helpers.template.render')
+    def test_update_template_error(self, mock_render):
+        hass = mock.MagicMock()
+        vs = template.BinarySensorTemplate(hass, 'parent', 'Parent',
+                                           'motion', '{{ 1 > 1 }}')
+        mock_render.side_effect = TemplateError('foo')
+        vs.update()
+        mock_render.side_effect = TemplateError(
+            "UndefinedError: 'None' has no attribute")
+        vs.update()
diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py
index 1420ac44b6bf367492682e82ebdab801986f4d90..4aefdcf4fc5cd5aff93dcaf0f797c3495d92effa 100644
--- a/tests/helpers/test_template.py
+++ b/tests/helpers/test_template.py
@@ -51,6 +51,21 @@ class TestUtilTemplate(unittest.TestCase):
 {% for state in states.sensor %}{{ state.state }}{% endfor %}
                 """))
 
+    def test_float(self):
+        self.hass.states.set('sensor.temperature', '12')
+
+        self.assertEqual(
+            '12.0',
+            template.render(
+                self.hass,
+                '{{ float(states.sensor.temperature.state) }}'))
+
+        self.assertEqual(
+            'True',
+            template.render(
+                self.hass,
+                '{{ float(states.sensor.temperature.state) > 11 }}'))
+
     def test_rounding_value(self):
         self.hass.states.set('sensor.temperature', 12.78)