diff --git a/homeassistant/components/sensor/wunderground.py b/homeassistant/components/sensor/wunderground.py
new file mode 100644
index 00000000000..cb724247436
--- /dev/null
+++ b/homeassistant/components/sensor/wunderground.py
@@ -0,0 +1,159 @@
+"""Support for Wunderground weather service."""
+from datetime import timedelta
+import logging
+import requests
+
+import voluptuous as vol
+
+from homeassistant.helpers.entity import Entity
+from homeassistant.helpers.config_validation import ensure_list
+from homeassistant.util import Throttle
+from homeassistant.const import (CONF_PLATFORM, CONF_MONITORED_CONDITIONS,
+                                 CONF_API_KEY, TEMP_FAHRENHEIT, TEMP_CELSIUS,
+                                 STATE_UNKNOWN)
+
+CONF_PWS_ID = 'pws_id'
+_RESOURCE = 'http://api.wunderground.com/api/{}/conditions/q/'
+_LOGGER = logging.getLogger(__name__)
+
+# Return cached results if last scan was less then this time ago.
+MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=300)
+
+# Sensor types are defined like: Name, units
+SENSOR_TYPES = {
+    'weather': ['Weather Summary', None],
+    'station_id': ['Station ID', None],
+    'feelslike_c': ['Feels Like (°C)', TEMP_CELSIUS],
+    'feelslike_f': ['Feels Like (°F)', TEMP_FAHRENHEIT],
+    'feelslike_string': ['Feels Like', None],
+    'heat_index_c': ['Dewpoint (°C)', TEMP_CELSIUS],
+    'heat_index_f': ['Dewpoint (°F)', TEMP_FAHRENHEIT],
+    'heat_index_string': ['Heat Index Summary', None],
+    'dewpoint_c': ['Dewpoint (°C)', TEMP_CELSIUS],
+    'dewpoint_f': ['Dewpoint (°F)', TEMP_FAHRENHEIT],
+    'dewpoint_string': ['Dewpoint Summary', None],
+    'wind_kph': ['Wind Speed', 'kpH'],
+    'wind_mph': ['Wind Speed', 'mpH'],
+    'UV': ['UV', None],
+    'pressure_in': ['Pressure', 'in'],
+    'pressure_mb': ['Pressure', 'mbar'],
+    'wind_dir': ['Wind Direction', None],
+    'wind_string': ['Wind Summary', None],
+    'temp_c': ['Temperature (°C)', TEMP_CELSIUS],
+    'temp_f': ['Temperature (°F)', TEMP_FAHRENHEIT],
+    'relative_humidity': ['Relative Humidity', '%'],
+    'visibility_mi': ['Visibility (miles)', 'mi'],
+    'visibility_km': ['Visibility (km)', 'km'],
+    'precip_today_in': ['Precipation Today', 'in'],
+    'precip_today_metric': ['Precipitation Today', 'mm'],
+    'precip_today_string': ['Precipitation today', None],
+    'solarradiation': ['Solar Radiation', None]
+}
+
+PLATFORM_SCHEMA = vol.Schema({
+    vol.Required(CONF_PLATFORM): "wunderground",
+    vol.Required(CONF_API_KEY): vol.Coerce(str),
+    CONF_PWS_ID: vol.Coerce(str),
+    vol.Required(CONF_MONITORED_CONDITIONS,
+                 default=[]): vol.All(ensure_list, [vol.In(SENSOR_TYPES)]),
+})
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Setup the Wunderground sensor."""
+    rest = WUndergroundData(hass,
+                            config.get(CONF_API_KEY),
+                            config.get(CONF_PWS_ID, None))
+    sensors = []
+    for variable in config['monitored_conditions']:
+        if variable in SENSOR_TYPES:
+            sensors.append(WUndergroundSensor(rest, variable))
+        else:
+            _LOGGER.error('Wunderground sensor: "%s" does not exist', variable)
+
+    try:
+        rest.update()
+    except ValueError as err:
+        _LOGGER.error("Received error from WUnderground: %s", err)
+        return False
+
+    add_devices(sensors)
+
+    return True
+
+
+class WUndergroundSensor(Entity):
+    """Implementing the Wunderground sensor."""
+
+    def __init__(self, rest, condition):
+        """Initialize the sensor."""
+        self.rest = rest
+        self._condition = condition
+        self._unit_of_measurement = None
+
+    @property
+    def name(self):
+        """Return the name of the sensor."""
+        return "PWS_" + self._condition
+
+    @property
+    def state(self):
+        """Return the state of the sensor."""
+        if self.rest.data and self._condition in self.rest.data:
+            return self.rest.data[self._condition]
+        else:
+            return STATE_UNKNOWN
+
+    @property
+    def entity_picture(self):
+        """Return the entity picture."""
+        if self._condition == 'weather':
+            return self.rest.data['icon_url']
+
+    @property
+    def unit_of_measurement(self):
+        """Return the units of measurement."""
+        return SENSOR_TYPES[self._condition][1]
+
+    def update(self):
+        """Update current conditions."""
+        self.rest.update()
+
+# pylint: disable=too-few-public-methods
+
+
+class WUndergroundData(object):
+    """Get data from Wundeground."""
+
+    def __init__(self, hass, api_key, pws_id=None):
+        """Initialize the data object."""
+        self._hass = hass
+        self._api_key = api_key
+        self._pws_id = pws_id
+        self._latitude = hass.config.latitude
+        self._longitude = hass.config.longitude
+        self.data = None
+
+    def _build_url(self):
+        url = _RESOURCE.format(self._api_key)
+        if self._pws_id:
+            url = url + 'pws:' + self._pws_id
+        else:
+            url = url + '{},{}'.format(self._latitude, self._longitude)
+
+        return url + '.json'
+
+    @Throttle(MIN_TIME_BETWEEN_UPDATES)
+    def update(self):
+        """Get the latest data from wunderground."""
+        try:
+            result = requests.get(self._build_url(), timeout=10).json()
+            if "error" in result['response']:
+                raise ValueError(result['response']["error"]
+                                 ["description"])
+            else:
+                self.data = result["current_observation"]
+        except ValueError as err:
+            _LOGGER.error("Check Wunderground API %s", err.args)
+            self.data = None
+            raise
diff --git a/tests/components/sensor/test_wunderground.py b/tests/components/sensor/test_wunderground.py
new file mode 100644
index 00000000000..c6664b71254
--- /dev/null
+++ b/tests/components/sensor/test_wunderground.py
@@ -0,0 +1,138 @@
+"""The tests for the forecast.io platform."""
+import unittest
+
+from homeassistant.components.sensor import wunderground
+from homeassistant.const import TEMP_CELSIUS
+from homeassistant import core as ha
+
+VALID_CONFIG_PWS = {
+    'platform': 'wunderground',
+    'api_key': 'foo',
+    'pws_id': 'bar',
+    'monitored_conditions': [
+        'weather', 'feelslike_c'
+    ]
+}
+
+VALID_CONFIG = {
+    'platform': 'wunderground',
+    'api_key': 'foo',
+    'monitored_conditions': [
+        'weather', 'feelslike_c'
+    ]
+}
+
+FEELS_LIKE = '40'
+WEATHER = 'Clear'
+ICON_URL = 'http://icons.wxug.com/i/c/k/clear.gif'
+
+
+def mocked_requests_get(*args, **kwargs):
+    class MockResponse:
+        def __init__(self, json_data, status_code):
+            self.json_data = json_data
+            self.status_code = status_code
+
+        def json(self):
+            return self.json_data
+
+    if str(args[0]).startswith('http://api.wunderground.com/api/foo/'):
+        # Return valid response
+        print('VALID RESPONSE')
+        return MockResponse({
+            "response": {
+                "version": "0.1",
+                "termsofService":
+                    "http://www.wunderground.com/weather/api/d/terms.html",
+                "features": {
+                    "conditions": 1
+                }
+            }, "current_observation": {
+                "image": {
+                    "url":
+                        'http://icons.wxug.com/graphics/wu2/logo_130x80.png',
+                    "title": "Weather Underground",
+                    "link": "http://www.wunderground.com"
+                },
+                "feelslike_c": FEELS_LIKE,
+                "weather": WEATHER,
+                "icon_url": ICON_URL
+            }
+        }, 200)
+    else:
+        # Return invalid api key
+        print('INVALID RESPONSE')
+        return MockResponse({
+                "response": {
+                    "version": "0.1",
+                    "termsofService":
+                        "http://www.wunderground.com/weather/api/d/terms.html",
+                    "features": {},
+                    "error": {
+                        "type": "keynotfound",
+                        "description": "this key does not exist"
+                    }
+                }
+            }, 200)
+
+
+class TestWundergroundSetup(unittest.TestCase):
+    """Test the wunderground platform."""
+
+    DEVICES = []
+
+    def add_devices(self, devices):
+        for device in devices:
+            self.DEVICES.append(device)
+
+    def setUp(self):
+        """Initialize values for this testcase class."""
+        self.DEVICES = []
+        self.hass = ha.HomeAssistant()
+        self.key = 'foo'
+        self.config = VALID_CONFIG_PWS
+        self.lat = 37.8267
+        self.lon = -122.423
+        self.hass.config.latitude = self.lat
+        self.hass.config.longitude = self.lon
+
+    @unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
+    def test_setup(self, req_mock):
+        """Test that the component is loaded if passed in PSW Id."""
+        print('1')
+        self.assertTrue(
+            wunderground.setup_platform(self.hass, VALID_CONFIG_PWS,
+                                        self.add_devices, None))
+        print('2')
+        self.assertTrue(
+            wunderground.setup_platform(self.hass, VALID_CONFIG,
+                                        self.add_devices,
+                                        None))
+        invalid_config = {
+            'platform': 'wunderground',
+            'api_key': 'BOB',
+            'pws_id': 'bar',
+            'monitored_conditions': [
+                'weather', 'feelslike_c'
+            ]
+        }
+
+        self.assertFalse(
+            wunderground.setup_platform(self.hass, invalid_config,
+                                        self.add_devices, None))
+
+    @unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
+    def test_sensor(self, req_mock):
+        wunderground.setup_platform(self.hass, VALID_CONFIG, self.add_devices,
+                                    None)
+        print(str(self.DEVICES))
+        for device in self.DEVICES:
+            self.assertTrue(str(device.name).startswith('PWS_'))
+            if device.name == 'PWS_weather':
+                self.assertEqual(ICON_URL, device.entity_picture)
+                self.assertEqual(WEATHER, device.state)
+                self.assertIsNone(device.unit_of_measurement)
+            else:
+                self.assertIsNone(device.entity_picture)
+                self.assertEqual(FEELS_LIKE, device.state)
+                self.assertEqual(TEMP_CELSIUS, device.unit_of_measurement)