diff --git a/.coveragerc b/.coveragerc
index 3d1bbab84567ed7c01ef70c98a64eae13d7e592c..8d884dc53e62ba453c62c55a8038a8cc27b9f460 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -219,7 +219,7 @@ omit =
     homeassistant/components/raincloud.py
     homeassistant/components/*/raincloud.py
 
-    homeassistant/components/rainmachine.py
+    homeassistant/components/rainmachine/*
     homeassistant/components/*/rainmachine.py
 
     homeassistant/components/raspihats.py
diff --git a/CODEOWNERS b/CODEOWNERS
index 32639fed43c4976fb8b40fdca943d0af1e93df8b..0da8353e5aa84d81b64b2b76a159da02a43d55a4 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -78,7 +78,6 @@ homeassistant/components/sensor/sytadin.py @gautric
 homeassistant/components/sensor/tibber.py @danielhiversen
 homeassistant/components/sensor/upnp.py @dgomes
 homeassistant/components/sensor/waqi.py @andrey-git
-homeassistant/components/switch/rainmachine.py @bachya
 homeassistant/components/switch/tplink.py @rytilahti
 homeassistant/components/vacuum/roomba.py @pschmitt
 homeassistant/components/xiaomi_aqara.py @danielhiversen @syssi
@@ -100,6 +99,8 @@ homeassistant/components/matrix.py @tinloaf
 homeassistant/components/*/matrix.py @tinloaf
 homeassistant/components/qwikswitch.py @kellerza
 homeassistant/components/*/qwikswitch.py @kellerza
+homeassistant/components/rainmachine/* @bachya
+homeassistant/components/*/rainmachine.py @bachya
 homeassistant/components/*/rfxtrx.py @danielhiversen
 homeassistant/components/tahoma.py @philklei
 homeassistant/components/*/tahoma.py @philklei
diff --git a/homeassistant/components/binary_sensor/rainmachine.py b/homeassistant/components/binary_sensor/rainmachine.py
new file mode 100644
index 0000000000000000000000000000000000000000..601a73298af0dea96c59de2e6ba8dcfaf7c26864
--- /dev/null
+++ b/homeassistant/components/binary_sensor/rainmachine.py
@@ -0,0 +1,102 @@
+"""
+This platform provides binary sensors for key RainMachine data.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/binary_sensor.rainmachine/
+"""
+import logging
+
+from homeassistant.components.binary_sensor import BinarySensorDevice
+from homeassistant.components.rainmachine import (
+    BINARY_SENSORS, DATA_RAINMACHINE, DATA_UPDATE_TOPIC, TYPE_FREEZE,
+    TYPE_FREEZE_PROTECTION, TYPE_HOT_DAYS, TYPE_HOURLY, TYPE_MONTH,
+    TYPE_RAINDELAY, TYPE_RAINSENSOR, TYPE_WEEKDAY, RainMachineEntity)
+from homeassistant.const import CONF_MONITORED_CONDITIONS
+from homeassistant.core import callback
+from homeassistant.helpers.dispatcher import async_dispatcher_connect
+
+DEPENDENCIES = ['rainmachine']
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the RainMachine Switch platform."""
+    if discovery_info is None:
+        return
+
+    rainmachine = hass.data[DATA_RAINMACHINE]
+
+    binary_sensors = []
+    for sensor_type in discovery_info[CONF_MONITORED_CONDITIONS]:
+        name, icon = BINARY_SENSORS[sensor_type]
+        binary_sensors.append(
+            RainMachineBinarySensor(rainmachine, sensor_type, name, icon))
+
+    add_devices(binary_sensors, True)
+
+
+class RainMachineBinarySensor(RainMachineEntity, BinarySensorDevice):
+    """A sensor implementation for raincloud device."""
+
+    def __init__(self, rainmachine, sensor_type, name, icon):
+        """Initialize the sensor."""
+        super().__init__(rainmachine)
+
+        self._icon = icon
+        self._name = name
+        self._sensor_type = sensor_type
+        self._state = None
+
+    @property
+    def icon(self) -> str:
+        """Return the icon."""
+        return self._icon
+
+    @property
+    def is_on(self):
+        """Return the status of the sensor."""
+        return self._state
+
+    @property
+    def should_poll(self):
+        """Disable polling."""
+        return False
+
+    @property
+    def unique_id(self) -> str:
+        """Return a unique, HASS-friendly identifier for this entity."""
+        return '{0}_{1}'.format(
+            self.rainmachine.device_mac.replace(':', ''), self._sensor_type)
+
+    @callback
+    def update_data(self):
+        """Update the state."""
+        self.async_schedule_update_ha_state(True)
+
+    async def async_added_to_hass(self):
+        """Register callbacks."""
+        async_dispatcher_connect(self.hass, DATA_UPDATE_TOPIC,
+                                 self.update_data)
+
+    def update(self):
+        """Update the state."""
+        if self._sensor_type == TYPE_FREEZE:
+            self._state = self.rainmachine.restrictions['current']['freeze']
+        elif self._sensor_type == TYPE_FREEZE_PROTECTION:
+            self._state = self.rainmachine.restrictions['global'][
+                'freezeProtectEnabled']
+        elif self._sensor_type == TYPE_HOT_DAYS:
+            self._state = self.rainmachine.restrictions['global'][
+                'hotDaysExtraWatering']
+        elif self._sensor_type == TYPE_HOURLY:
+            self._state = self.rainmachine.restrictions['current']['hourly']
+        elif self._sensor_type == TYPE_MONTH:
+            self._state = self.rainmachine.restrictions['current']['month']
+        elif self._sensor_type == TYPE_RAINDELAY:
+            self._state = self.rainmachine.restrictions['current']['rainDelay']
+        elif self._sensor_type == TYPE_RAINSENSOR:
+            self._state = self.rainmachine.restrictions['current'][
+                'rainSensor']
+        elif self._sensor_type == TYPE_WEEKDAY:
+            self._state = self.rainmachine.restrictions['current']['weekDay']
diff --git a/homeassistant/components/rainmachine.py b/homeassistant/components/rainmachine.py
deleted file mode 100644
index f2d5893d60bb959f7cd908a20cd0866f45ecd225..0000000000000000000000000000000000000000
--- a/homeassistant/components/rainmachine.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-This component provides support for RainMachine sprinkler controllers.
-
-For more details about this component, please refer to the documentation at
-https://home-assistant.io/components/rainmachine/
-"""
-import logging
-
-import voluptuous as vol
-
-from homeassistant.const import (
-    ATTR_ATTRIBUTION, CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL,
-    CONF_SWITCHES)
-from homeassistant.helpers import config_validation as cv, discovery
-from homeassistant.helpers.entity import Entity
-
-REQUIREMENTS = ['regenmaschine==0.4.1']
-
-_LOGGER = logging.getLogger(__name__)
-
-DATA_RAINMACHINE = 'data_rainmachine'
-DOMAIN = 'rainmachine'
-
-NOTIFICATION_ID = 'rainmachine_notification'
-NOTIFICATION_TITLE = 'RainMachine Component Setup'
-
-CONF_ZONE_RUN_TIME = 'zone_run_time'
-
-DEFAULT_ATTRIBUTION = 'Data provided by Green Electronics LLC'
-DEFAULT_ICON = 'mdi:water'
-DEFAULT_PORT = 8080
-DEFAULT_SSL = True
-
-PROGRAM_UPDATE_TOPIC = '{0}_program_update'.format(DOMAIN)
-
-SWITCH_SCHEMA = vol.Schema({
-    vol.Optional(CONF_ZONE_RUN_TIME):
-        cv.positive_int
-})
-
-CONFIG_SCHEMA = vol.Schema(
-    {
-        DOMAIN: vol.Schema({
-            vol.Required(CONF_IP_ADDRESS): cv.string,
-            vol.Required(CONF_PASSWORD): cv.string,
-            vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
-            vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
-            vol.Optional(CONF_SWITCHES): SWITCH_SCHEMA,
-        })
-    },
-    extra=vol.ALLOW_EXTRA)
-
-
-def setup(hass, config):
-    """Set up the RainMachine component."""
-    from regenmaschine import Authenticator, Client
-    from regenmaschine.exceptions import HTTPError
-    from requests.exceptions import ConnectTimeout
-
-    conf = config[DOMAIN]
-    ip_address = conf[CONF_IP_ADDRESS]
-    password = conf[CONF_PASSWORD]
-    port = conf[CONF_PORT]
-    ssl = conf[CONF_SSL]
-
-    _LOGGER.debug('Setting up RainMachine client')
-
-    try:
-        auth = Authenticator.create_local(
-            ip_address, password, port=port, https=ssl)
-        client = Client(auth)
-        hass.data[DATA_RAINMACHINE] = RainMachine(client)
-    except (HTTPError, ConnectTimeout, UnboundLocalError) as exc_info:
-        _LOGGER.error('An error occurred: %s', str(exc_info))
-        hass.components.persistent_notification.create(
-            'Error: {0}<br />'
-            'You will need to restart hass after fixing.'
-            ''.format(exc_info),
-            title=NOTIFICATION_TITLE,
-            notification_id=NOTIFICATION_ID)
-        return False
-
-    _LOGGER.debug('Setting up switch platform')
-    switch_config = conf.get(CONF_SWITCHES, {})
-    discovery.load_platform(hass, 'switch', DOMAIN, switch_config, config)
-
-    _LOGGER.debug('Setup complete')
-
-    return True
-
-
-class RainMachine(object):
-    """Define a generic RainMachine object."""
-
-    def __init__(self, client):
-        """Initialize."""
-        self.client = client
-        self.device_mac = self.client.provision.wifi()['macAddress']
-
-
-class RainMachineEntity(Entity):
-    """Define a generic RainMachine entity."""
-
-    def __init__(self,
-                 rainmachine,
-                 rainmachine_type,
-                 rainmachine_entity_id,
-                 icon=DEFAULT_ICON):
-        """Initialize."""
-        self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
-        self._icon = icon
-        self._rainmachine_type = rainmachine_type
-        self._rainmachine_entity_id = rainmachine_entity_id
-        self.rainmachine = rainmachine
-
-    @property
-    def device_state_attributes(self) -> dict:
-        """Return the state attributes."""
-        return self._attrs
-
-    @property
-    def icon(self) -> str:
-        """Return the icon."""
-        return self._icon
-
-    @property
-    def unique_id(self) -> str:
-        """Return a unique, HASS-friendly identifier for this entity."""
-        return '{0}_{1}_{2}'.format(
-            self.rainmachine.device_mac.replace(
-                ':', ''), self._rainmachine_type,
-            self._rainmachine_entity_id)
diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ee6b06372008f6c9f24cd76c42c884590fec54e
--- /dev/null
+++ b/homeassistant/components/rainmachine/__init__.py
@@ -0,0 +1,226 @@
+"""
+Support for RainMachine devices.
+
+For more details about this component, please refer to the documentation at
+https://home-assistant.io/components/rainmachine/
+"""
+import logging
+from datetime import timedelta
+
+import voluptuous as vol
+
+from homeassistant.const import (
+    ATTR_ATTRIBUTION, CONF_BINARY_SENSORS, CONF_IP_ADDRESS, CONF_PASSWORD,
+    CONF_PORT, CONF_SENSORS, CONF_SSL, CONF_MONITORED_CONDITIONS,
+    CONF_SWITCHES)
+from homeassistant.helpers import config_validation as cv, discovery
+from homeassistant.helpers.dispatcher import dispatcher_send
+from homeassistant.helpers.entity import Entity
+from homeassistant.helpers.event import track_time_interval
+
+REQUIREMENTS = ['regenmaschine==0.4.2']
+
+_LOGGER = logging.getLogger(__name__)
+
+DATA_RAINMACHINE = 'data_rainmachine'
+DOMAIN = 'rainmachine'
+
+NOTIFICATION_ID = 'rainmachine_notification'
+NOTIFICATION_TITLE = 'RainMachine Component Setup'
+
+DATA_UPDATE_TOPIC = '{0}_data_update'.format(DOMAIN)
+PROGRAM_UPDATE_TOPIC = '{0}_program_update'.format(DOMAIN)
+
+CONF_PROGRAM_ID = 'program_id'
+CONF_ZONE_ID = 'zone_id'
+CONF_ZONE_RUN_TIME = 'zone_run_time'
+
+DEFAULT_ATTRIBUTION = 'Data provided by Green Electronics LLC'
+DEFAULT_ICON = 'mdi:water'
+DEFAULT_PORT = 8080
+DEFAULT_SCAN_INTERVAL = timedelta(seconds=60)
+DEFAULT_SSL = True
+DEFAULT_ZONE_RUN = 60 * 10
+
+TYPE_FREEZE = 'freeze'
+TYPE_FREEZE_PROTECTION = 'freeze_protection'
+TYPE_FREEZE_TEMP = 'freeze_protect_temp'
+TYPE_HOT_DAYS = 'extra_water_on_hot_days'
+TYPE_HOURLY = 'hourly'
+TYPE_MONTH = 'month'
+TYPE_RAINDELAY = 'raindelay'
+TYPE_RAINSENSOR = 'rainsensor'
+TYPE_WEEKDAY = 'weekday'
+
+BINARY_SENSORS = {
+    TYPE_FREEZE: ('Freeze Restrictions', 'mdi:cancel'),
+    TYPE_FREEZE_PROTECTION: ('Freeze Protection', 'mdi:weather-snowy'),
+    TYPE_HOT_DAYS: ('Extra Water on Hot Days', 'mdi:thermometer-lines'),
+    TYPE_HOURLY: ('Hourly Restrictions', 'mdi:cancel'),
+    TYPE_MONTH: ('Month Restrictions', 'mdi:cancel'),
+    TYPE_RAINDELAY: ('Rain Delay Restrictions', 'mdi:cancel'),
+    TYPE_RAINSENSOR: ('Rain Sensor Restrictions', 'mdi:cancel'),
+    TYPE_WEEKDAY: ('Weekday Restrictions', 'mdi:cancel'),
+}
+
+SENSORS = {
+    TYPE_FREEZE_TEMP: ('Freeze Protect Temperature', 'mdi:thermometer', '°C'),
+}
+
+BINARY_SENSOR_SCHEMA = vol.Schema({
+    vol.Optional(CONF_MONITORED_CONDITIONS, default=list(BINARY_SENSORS)):
+        vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)])
+})
+
+SENSOR_SCHEMA = vol.Schema({
+    vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSORS)):
+        vol.All(cv.ensure_list, [vol.In(SENSORS)])
+})
+
+SERVICE_START_PROGRAM_SCHEMA = vol.Schema({
+    vol.Required(CONF_PROGRAM_ID): cv.positive_int,
+})
+
+SERVICE_START_ZONE_SCHEMA = vol.Schema({
+    vol.Required(CONF_ZONE_ID): cv.positive_int,
+    vol.Optional(CONF_ZONE_RUN_TIME, default=DEFAULT_ZONE_RUN):
+        cv.positive_int,
+})
+
+SERVICE_STOP_PROGRAM_SCHEMA = vol.Schema({
+    vol.Required(CONF_PROGRAM_ID): cv.positive_int,
+})
+
+SERVICE_STOP_ZONE_SCHEMA = vol.Schema({
+    vol.Required(CONF_ZONE_ID): cv.positive_int,
+})
+
+SWITCH_SCHEMA = vol.Schema({vol.Optional(CONF_ZONE_RUN_TIME): cv.positive_int})
+
+CONFIG_SCHEMA = vol.Schema(
+    {
+        DOMAIN:
+        vol.Schema({
+            vol.Required(CONF_IP_ADDRESS): cv.string,
+            vol.Required(CONF_PASSWORD): cv.string,
+            vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
+            vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
+            vol.Optional(CONF_BINARY_SENSORS, default={}):
+                BINARY_SENSOR_SCHEMA,
+            vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA,
+            vol.Optional(CONF_SWITCHES, default={}): SWITCH_SCHEMA,
+        })
+    },
+    extra=vol.ALLOW_EXTRA)
+
+
+def setup(hass, config):
+    """Set up the RainMachine component."""
+    from regenmaschine import Authenticator, Client
+    from regenmaschine.exceptions import RainMachineError
+
+    conf = config[DOMAIN]
+    ip_address = conf[CONF_IP_ADDRESS]
+    password = conf[CONF_PASSWORD]
+    port = conf[CONF_PORT]
+    ssl = conf[CONF_SSL]
+
+    try:
+        auth = Authenticator.create_local(
+            ip_address, password, port=port, https=ssl)
+        rainmachine = RainMachine(hass, Client(auth))
+        rainmachine.update()
+        hass.data[DATA_RAINMACHINE] = rainmachine
+    except RainMachineError as exc:
+        _LOGGER.error('An error occurred: %s', str(exc))
+        hass.components.persistent_notification.create(
+            'Error: {0}<br />'
+            'You will need to restart hass after fixing.'
+            ''.format(exc),
+            title=NOTIFICATION_TITLE,
+            notification_id=NOTIFICATION_ID)
+        return False
+
+    for component, schema in [
+            ('binary_sensor', conf[CONF_BINARY_SENSORS]),
+            ('sensor', conf[CONF_SENSORS]),
+            ('switch', conf[CONF_SWITCHES]),
+    ]:
+        discovery.load_platform(hass, component, DOMAIN, schema, config)
+
+    def refresh(event_time):
+        """Refresh RainMachine data."""
+        _LOGGER.debug('Updating RainMachine data')
+        hass.data[DATA_RAINMACHINE].update()
+        dispatcher_send(hass, DATA_UPDATE_TOPIC)
+
+    track_time_interval(hass, refresh, DEFAULT_SCAN_INTERVAL)
+
+    def start_program(service):
+        """Start a particular program."""
+        rainmachine.client.programs.start(service.data[CONF_PROGRAM_ID])
+
+    def start_zone(service):
+        """Start a particular zone for a certain amount of time."""
+        rainmachine.client.zones.start(service.data[CONF_ZONE_ID],
+                                       service.data[CONF_ZONE_RUN_TIME])
+
+    def stop_all(service):
+        """Stop all watering."""
+        rainmachine.client.watering.stop_all()
+
+    def stop_program(service):
+        """Stop a program."""
+        rainmachine.client.programs.stop(service.data[CONF_PROGRAM_ID])
+
+    def stop_zone(service):
+        """Stop a zone."""
+        rainmachine.client.zones.stop(service.data[CONF_ZONE_ID])
+
+    for service, method, schema in [
+            ('start_program', start_program, SERVICE_START_PROGRAM_SCHEMA),
+            ('start_zone', start_zone, SERVICE_START_ZONE_SCHEMA),
+            ('stop_all', stop_all, {}),
+            ('stop_program', stop_program, SERVICE_STOP_PROGRAM_SCHEMA),
+            ('stop_zone', stop_zone, SERVICE_STOP_ZONE_SCHEMA)
+    ]:
+        hass.services.register(DOMAIN, service, method, schema=schema)
+
+    return True
+
+
+class RainMachine(object):
+    """Define a generic RainMachine object."""
+
+    def __init__(self, hass, client):
+        """Initialize."""
+        self.client = client
+        self.device_mac = self.client.provision.wifi()['macAddress']
+        self.restrictions = {}
+
+    def update(self):
+        """Update sensor/binary sensor data."""
+        self.restrictions.update({
+            'current': self.client.restrictions.current(),
+            'global': self.client.restrictions.universal()
+        })
+
+
+class RainMachineEntity(Entity):
+    """Define a generic RainMachine entity."""
+
+    def __init__(self, rainmachine):
+        """Initialize."""
+        self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
+        self._name = None
+        self.rainmachine = rainmachine
+
+    @property
+    def device_state_attributes(self) -> dict:
+        """Return the state attributes."""
+        return self._attrs
+
+    @property
+    def name(self) -> str:
+        """Return the name of the entity."""
+        return self._name
diff --git a/homeassistant/components/rainmachine/services.yaml b/homeassistant/components/rainmachine/services.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a8c77628c8f23abefa2cc041b4874292e7cbb58b
--- /dev/null
+++ b/homeassistant/components/rainmachine/services.yaml
@@ -0,0 +1,32 @@
+# Describes the format for available RainMachine services
+
+---
+start_program:
+  description: Start a program.
+  fields:
+    program_id:
+      description: The program to start.
+      example: 3
+start_zone:
+  description: Start a zone for a set number of seconds.
+  fields:
+    zone_id:
+      description: The zone to start.
+      example: 3
+    zone_run_time:
+      description: The number of seconds to run the zone.
+      example: 120
+stop_all:
+  description: Stop all watering activities.
+stop_program:
+  description: Stop a program.
+  fields:
+    program_id:
+      description: The program to stop.
+      example: 3
+stop_zone:
+  description: Stop a zone.
+  fields:
+    zone_id:
+      description: The zone to stop.
+      example: 3
diff --git a/homeassistant/components/sensor/rainmachine.py b/homeassistant/components/sensor/rainmachine.py
new file mode 100644
index 0000000000000000000000000000000000000000..8faf30acc3899d8be8dbb266e66918cd0ea07062
--- /dev/null
+++ b/homeassistant/components/sensor/rainmachine.py
@@ -0,0 +1,88 @@
+"""
+This platform provides support for sensor data from RainMachine.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/sensor.rainmachine/
+"""
+import logging
+
+from homeassistant.components.rainmachine import (
+    DATA_RAINMACHINE, DATA_UPDATE_TOPIC, SENSORS, RainMachineEntity)
+from homeassistant.const import CONF_MONITORED_CONDITIONS
+from homeassistant.core import callback
+from homeassistant.helpers.dispatcher import async_dispatcher_connect
+
+DEPENDENCIES = ['rainmachine']
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the RainMachine Switch platform."""
+    if discovery_info is None:
+        return
+
+    rainmachine = hass.data[DATA_RAINMACHINE]
+
+    sensors = []
+    for sensor_type in discovery_info[CONF_MONITORED_CONDITIONS]:
+        name, icon, unit = SENSORS[sensor_type]
+        sensors.append(
+            RainMachineSensor(rainmachine, sensor_type, name, icon, unit))
+
+    add_devices(sensors, True)
+
+
+class RainMachineSensor(RainMachineEntity):
+    """A sensor implementation for raincloud device."""
+
+    def __init__(self, rainmachine, sensor_type, name, icon, unit):
+        """Initialize."""
+        super().__init__(rainmachine)
+
+        self._icon = icon
+        self._name = name
+        self._sensor_type = sensor_type
+        self._state = None
+        self._unit = unit
+
+    @property
+    def icon(self) -> str:
+        """Return the icon."""
+        return self._icon
+
+    @property
+    def should_poll(self):
+        """Disable polling."""
+        return False
+
+    @property
+    def state(self) -> str:
+        """Return the name of the entity."""
+        return self._state
+
+    @property
+    def unique_id(self) -> str:
+        """Return a unique, HASS-friendly identifier for this entity."""
+        return '{0}_{1}'.format(
+            self.rainmachine.device_mac.replace(':', ''), self._sensor_type)
+
+    @property
+    def unit_of_measurement(self):
+        """Return the unit the value is expressed in."""
+        return self._unit
+
+    @callback
+    def update_data(self):
+        """Update the state."""
+        self.async_schedule_update_ha_state(True)
+
+    async def async_added_to_hass(self):
+        """Register callbacks."""
+        async_dispatcher_connect(self.hass, DATA_UPDATE_TOPIC,
+                                 self.update_data)
+
+    def update(self):
+        """Update the sensor's state."""
+        self._state = self.rainmachine.restrictions['global'][
+            'freezeProtectTemp']
diff --git a/homeassistant/components/switch/rainmachine.py b/homeassistant/components/switch/rainmachine.py
index beb00eeca441bf2e52ef3f20ed1663db42fc997f..f4b2d780a9a162fa9a4546df124db58cb7426318 100644
--- a/homeassistant/components/switch/rainmachine.py
+++ b/homeassistant/components/switch/rainmachine.py
@@ -4,12 +4,11 @@ This component provides support for RainMachine programs and zones.
 For more details about this component, please refer to the documentation at
 https://home-assistant.io/components/switch.rainmachine/
 """
-
-from logging import getLogger
+import logging
 
 from homeassistant.components.rainmachine import (
-    CONF_ZONE_RUN_TIME, DATA_RAINMACHINE, PROGRAM_UPDATE_TOPIC,
-    RainMachineEntity)
+    CONF_ZONE_RUN_TIME, DATA_RAINMACHINE, DEFAULT_ZONE_RUN,
+    PROGRAM_UPDATE_TOPIC, RainMachineEntity)
 from homeassistant.const import ATTR_ID
 from homeassistant.components.switch import SwitchDevice
 from homeassistant.core import callback
@@ -18,7 +17,7 @@ from homeassistant.helpers.dispatcher import (
 
 DEPENDENCIES = ['rainmachine']
 
-_LOGGER = getLogger(__name__)
+_LOGGER = logging.getLogger(__name__)
 
 ATTR_AREA = 'area'
 ATTR_CS_ON = 'cs_on'
@@ -39,8 +38,6 @@ ATTR_SUN_EXPOSURE = 'sun_exposure'
 ATTR_VEGETATION_TYPE = 'vegetation_type'
 ATTR_ZONES = 'zones'
 
-DEFAULT_ZONE_RUN = 60 * 10
-
 DAYS = [
     'Monday',
     'Tuesday',
@@ -141,26 +138,41 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
 
 
 class RainMachineSwitch(RainMachineEntity, SwitchDevice):
-    """A class to represent a generic RainMachine entity."""
+    """A class to represent a generic RainMachine switch."""
+
+    def __init__(self, rainmachine, switch_type, obj):
+        """Initialize a generic RainMachine switch."""
+        super().__init__(rainmachine)
 
-    def __init__(self, rainmachine, rainmachine_type, obj):
-        """Initialize a generic RainMachine entity."""
+        self._name = obj['name']
         self._obj = obj
-        self._type = rainmachine_type
+        self._rainmachine_entity_id = obj['uid']
+        self._switch_type = switch_type
 
-        super().__init__(rainmachine, rainmachine_type, obj.get('uid'))
+    @property
+    def icon(self) -> str:
+        """Return the icon."""
+        return 'mdi:water'
 
     @property
     def is_enabled(self) -> bool:
         """Return whether the entity is enabled."""
         return self._obj.get('active')
 
+    @property
+    def unique_id(self) -> str:
+        """Return a unique, HASS-friendly identifier for this entity."""
+        return '{0}_{1}_{2}'.format(
+            self.rainmachine.device_mac.replace(':', ''),
+            self._switch_type,
+            self._rainmachine_entity_id)
+
 
 class RainMachineProgram(RainMachineSwitch):
     """A RainMachine program."""
 
     def __init__(self, rainmachine, obj):
-        """Initialize."""
+        """Initialize a generic RainMachine switch."""
         super().__init__(rainmachine, 'program', obj)
 
     @property
@@ -168,11 +180,6 @@ class RainMachineProgram(RainMachineSwitch):
         """Return whether the program is running."""
         return bool(self._obj.get('status'))
 
-    @property
-    def name(self) -> str:
-        """Return the name of the program."""
-        return 'Program: {0}'.format(self._obj.get('name'))
-
     @property
     def zones(self) -> list:
         """Return a list of active zones associated with this program."""
@@ -180,29 +187,29 @@ class RainMachineProgram(RainMachineSwitch):
 
     def turn_off(self, **kwargs) -> None:
         """Turn the program off."""
-        from regenmaschine.exceptions import HTTPError
+        from regenmaschine.exceptions import RainMachineError
 
         try:
             self.rainmachine.client.programs.stop(self._rainmachine_entity_id)
             dispatcher_send(self.hass, PROGRAM_UPDATE_TOPIC)
-        except HTTPError as exc_info:
+        except RainMachineError as exc_info:
             _LOGGER.error('Unable to turn off program "%s"', self.unique_id)
             _LOGGER.debug(exc_info)
 
     def turn_on(self, **kwargs) -> None:
         """Turn the program on."""
-        from regenmaschine.exceptions import HTTPError
+        from regenmaschine.exceptions import RainMachineError
 
         try:
             self.rainmachine.client.programs.start(self._rainmachine_entity_id)
             dispatcher_send(self.hass, PROGRAM_UPDATE_TOPIC)
-        except HTTPError as exc_info:
+        except RainMachineError as exc_info:
             _LOGGER.error('Unable to turn on program "%s"', self.unique_id)
             _LOGGER.debug(exc_info)
 
     def update(self) -> None:
         """Update info for the program."""
-        from regenmaschine.exceptions import HTTPError
+        from regenmaschine.exceptions import RainMachineError
 
         try:
             self._obj = self.rainmachine.client.programs.get(
@@ -210,16 +217,11 @@ class RainMachineProgram(RainMachineSwitch):
 
             self._attrs.update({
                 ATTR_ID: self._obj['uid'],
-                ATTR_CS_ON: self._obj.get('cs_on'),
-                ATTR_CYCLES: self._obj.get('cycles'),
-                ATTR_DELAY: self._obj.get('delay'),
-                ATTR_DELAY_ON: self._obj.get('delay_on'),
                 ATTR_SOAK: self._obj.get('soak'),
-                ATTR_STATUS:
-                    PROGRAM_STATUS_MAP[self._obj.get('status')],
+                ATTR_STATUS: PROGRAM_STATUS_MAP[self._obj.get('status')],
                 ATTR_ZONES: ', '.join(z['name'] for z in self.zones)
             })
-        except HTTPError as exc_info:
+        except RainMachineError as exc_info:
             _LOGGER.error('Unable to update info for program "%s"',
                           self.unique_id)
             _LOGGER.debug(exc_info)
@@ -240,11 +242,6 @@ class RainMachineZone(RainMachineSwitch):
         """Return whether the zone is running."""
         return bool(self._obj.get('state'))
 
-    @property
-    def name(self) -> str:
-        """Return the name of the zone."""
-        return 'Zone: {0}'.format(self._obj.get('name'))
-
     @callback
     def _program_updated(self):
         """Update state, trigger updates."""
@@ -257,28 +254,28 @@ class RainMachineZone(RainMachineSwitch):
 
     def turn_off(self, **kwargs) -> None:
         """Turn the zone off."""
-        from regenmaschine.exceptions import HTTPError
+        from regenmaschine.exceptions import RainMachineError
 
         try:
             self.rainmachine.client.zones.stop(self._rainmachine_entity_id)
-        except HTTPError as exc_info:
+        except RainMachineError as exc_info:
             _LOGGER.error('Unable to turn off zone "%s"', self.unique_id)
             _LOGGER.debug(exc_info)
 
     def turn_on(self, **kwargs) -> None:
         """Turn the zone on."""
-        from regenmaschine.exceptions import HTTPError
+        from regenmaschine.exceptions import RainMachineError
 
         try:
             self.rainmachine.client.zones.start(self._rainmachine_entity_id,
                                                 self._run_time)
-        except HTTPError as exc_info:
+        except RainMachineError as exc_info:
             _LOGGER.error('Unable to turn on zone "%s"', self.unique_id)
             _LOGGER.debug(exc_info)
 
     def update(self) -> None:
         """Update info for the zone."""
-        from regenmaschine.exceptions import HTTPError
+        from regenmaschine.exceptions import RainMachineError
 
         try:
             self._obj = self.rainmachine.client.zones.get(
@@ -309,7 +306,7 @@ class RainMachineZone(RainMachineSwitch):
                 ATTR_VEGETATION_TYPE:
                     VEGETATION_MAP[self._obj.get('type')],
             })
-        except HTTPError as exc_info:
+        except RainMachineError as exc_info:
             _LOGGER.error('Unable to update info for zone "%s"',
                           self.unique_id)
             _LOGGER.debug(exc_info)
diff --git a/requirements_all.txt b/requirements_all.txt
index 958b0f1027e98a56c253f313bef47609fae6cbcc..1b1db52daef34ffd911ef5639dfc87ee4314f687 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -1147,7 +1147,7 @@ raincloudy==0.0.4
 # raspihats==2.2.3
 
 # homeassistant.components.rainmachine
-regenmaschine==0.4.1
+regenmaschine==0.4.2
 
 # homeassistant.components.python_script
 restrictedpython==4.0b4