diff --git a/.coveragerc b/.coveragerc
index f609b5cb053..1a8d8efc4ec 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -594,7 +594,6 @@ omit =
homeassistant/components/sensor/worldtidesinfo.py
homeassistant/components/sensor/worxlandroid.py
homeassistant/components/sensor/xbox_live.py
- homeassistant/components/sensor/yweather.py
homeassistant/components/sensor/zamg.py
homeassistant/components/shiftr.py
homeassistant/components/spc.py
diff --git a/homeassistant/components/sensor/yweather.py b/homeassistant/components/sensor/yweather.py
index 873e27975db..846b221d5e3 100644
--- a/homeassistant/components/sensor/yweather.py
+++ b/homeassistant/components/sensor/yweather.py
@@ -160,13 +160,15 @@ class YahooWeatherSensor(Entity):
self._code = self._data.yahoo.Forecast[self._forecast]['code']
self._state = self._data.yahoo.Forecast[self._forecast]['high']
elif self._type == 'wind_speed':
- self._state = self._data.yahoo.Wind['speed']
+ self._state = round(float(self._data.yahoo.Wind['speed'])/1.61, 2)
elif self._type == 'humidity':
self._state = self._data.yahoo.Atmosphere['humidity']
elif self._type == 'pressure':
- self._state = self._data.yahoo.Atmosphere['pressure']
+ self._state = round(
+ float(self._data.yahoo.Atmosphere['pressure'])/33.8637526, 2)
elif self._type == 'visibility':
- self._state = self._data.yahoo.Atmosphere['visibility']
+ self._state = round(
+ float(self._data.yahoo.Atmosphere['visibility'])/1.61, 2)
class YahooWeatherData(object):
diff --git a/tests/components/sensor/test_yweather.py b/tests/components/sensor/test_yweather.py
new file mode 100644
index 00000000000..88b94906a35
--- /dev/null
+++ b/tests/components/sensor/test_yweather.py
@@ -0,0 +1,247 @@
+"""The tests for the Yahoo weather sensor component."""
+import json
+
+import unittest
+from unittest.mock import patch
+
+from homeassistant.setup import setup_component
+
+from tests.common import (get_test_home_assistant, load_fixture,
+ MockDependency)
+
+VALID_CONFIG_MINIMAL = {
+ 'sensor': {
+ 'platform': 'yweather',
+ 'monitored_conditions': [
+ 'weather',
+ ],
+ }
+}
+
+VALID_CONFIG_ALL = {
+ 'sensor': {
+ 'platform': 'yweather',
+ 'monitored_conditions': [
+ 'weather',
+ 'weather_current',
+ 'temperature',
+ 'temp_min',
+ 'temp_max',
+ 'wind_speed',
+ 'pressure',
+ 'visibility',
+ 'humidity',
+ ],
+ }
+}
+
+BAD_CONF_RAW = {
+ 'sensor': {
+ 'platform': 'yweather',
+ 'woeid': '12345',
+ 'monitored_conditions': [
+ 'weather',
+ ],
+ }
+}
+
+BAD_CONF_DATA = {
+ 'sensor': {
+ 'platform': 'yweather',
+ 'woeid': '111',
+ 'monitored_conditions': [
+ 'weather',
+ ],
+ }
+}
+
+
+def _yql_queryMock(yql): # pylint: disable=invalid-name
+ """Mock yahoo query language query."""
+ return ('{"query": {"count": 1, "created": "2017-11-17T13:40:47Z", '
+ '"lang": "en-US", "results": {"place": {"woeid": "23511632"}}}}')
+
+
+def get_woeidMock(lat, lon): # pylint: disable=invalid-name
+ """Mock get woeid Where On Earth Identifiers."""
+ return '23511632'
+
+
+def get_woeidNoneMock(lat, lon): # pylint: disable=invalid-name
+ """Mock get woeid Where On Earth Identifiers."""
+ return None
+
+
+class YahooWeatherMock():
+ """Mock class for the YahooWeather object."""
+
+ def __init__(self, woeid, temp_unit):
+ """Initialize Telnet object."""
+ self.woeid = woeid
+ self.temp_unit = temp_unit
+ self._data = json.loads(load_fixture('yahooweather.json'))
+
+ # pylint: disable=no-self-use
+ def updateWeather(self): # pylint: disable=invalid-name
+ """Return sample values."""
+ return True
+
+ @property
+ def RawData(self): # pylint: disable=invalid-name
+ """Raw Data."""
+ if self.woeid == '12345':
+ return json.loads('[]')
+ return self._data
+
+ @property
+ def Units(self): # pylint: disable=invalid-name
+ """Return dict with units."""
+ return self._data['query']['results']['channel']['units']
+
+ @property
+ def Now(self): # pylint: disable=invalid-name
+ """Current weather data."""
+ if self.woeid == '111':
+ raise ValueError
+ return self._data['query']['results']['channel']['item']['condition']
+
+ @property
+ def Atmosphere(self): # pylint: disable=invalid-name
+ """Atmosphere weather data."""
+ return self._data['query']['results']['channel']['atmosphere']
+
+ @property
+ def Wind(self): # pylint: disable=invalid-name
+ """Wind weather data."""
+ return self._data['query']['results']['channel']['wind']
+
+ @property
+ def Forecast(self): # pylint: disable=invalid-name
+ """Forecast data 0-5 Days."""
+ return self._data['query']['results']['channel']['item']['forecast']
+
+ def getWeatherImage(self, code): # pylint: disable=invalid-name
+ """Create a link to weather image from yahoo code."""
+ return "https://l.yimg.com/a/i/us/we/52/{}.gif".format(code)
+
+
+class TestWeather(unittest.TestCase):
+ """Test the Yahoo weather component."""
+
+ def setUp(self):
+ """Setup things to be run when tests are started."""
+ self.hass = get_test_home_assistant()
+
+ def tearDown(self):
+ """Stop down everything that was started."""
+ self.hass.stop()
+
+ @MockDependency('yahooweather')
+ @patch('yahooweather._yql_query', new=_yql_queryMock)
+ @patch('yahooweather.get_woeid', new=get_woeidMock)
+ @patch('yahooweather.YahooWeather', new=YahooWeatherMock)
+ def test_setup_minimal(self, mock_yahooweather):
+ """Test for minimal weather sensor config."""
+ assert setup_component(self.hass, 'sensor', VALID_CONFIG_MINIMAL)
+
+ state = self.hass.states.get('sensor.yweather_condition')
+ assert state is not None
+
+ assert state.state == 'Mostly Cloudy'
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Condition')
+
+ @MockDependency('yahooweather')
+ @patch('yahooweather._yql_query', new=_yql_queryMock)
+ @patch('yahooweather.get_woeid', new=get_woeidMock)
+ @patch('yahooweather.YahooWeather', new=YahooWeatherMock)
+ def test_setup_all(self, mock_yahooweather):
+ """Test for all weather data attributes."""
+ assert setup_component(self.hass, 'sensor', VALID_CONFIG_ALL)
+
+ state = self.hass.states.get('sensor.yweather_condition')
+ assert state is not None
+ self.assertEqual(state.state, 'Mostly Cloudy')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Condition')
+
+ state = self.hass.states.get('sensor.yweather_current')
+ assert state is not None
+ self.assertEqual(state.state, 'Cloudy')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Current')
+
+ state = self.hass.states.get('sensor.yweather_temperature')
+ assert state is not None
+ self.assertEqual(state.state, '18')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Temperature')
+
+ state = self.hass.states.get('sensor.yweather_temperature_max')
+ assert state is not None
+ self.assertEqual(state.state, '23')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Temperature max')
+
+ state = self.hass.states.get('sensor.yweather_temperature_min')
+ assert state is not None
+ self.assertEqual(state.state, '16')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Temperature min')
+
+ state = self.hass.states.get('sensor.yweather_wind_speed')
+ assert state is not None
+ self.assertEqual(state.state, '3.94')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Wind speed')
+
+ state = self.hass.states.get('sensor.yweather_pressure')
+ assert state is not None
+ self.assertEqual(state.state, '1000.0')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Pressure')
+
+ state = self.hass.states.get('sensor.yweather_visibility')
+ assert state is not None
+ self.assertEqual(state.state, '14.23')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Visibility')
+
+ state = self.hass.states.get('sensor.yweather_humidity')
+ assert state is not None
+ self.assertEqual(state.state, '71')
+ self.assertEqual(state.attributes.get('friendly_name'),
+ 'Yweather Humidity')
+
+ @MockDependency('yahooweather')
+ @patch('yahooweather._yql_query', new=_yql_queryMock)
+ @patch('yahooweather.get_woeid', new=get_woeidNoneMock)
+ @patch('yahooweather.YahooWeather', new=YahooWeatherMock)
+ def test_setup_bad_woied(self, mock_yahooweather):
+ """Test for bad woeid."""
+ assert setup_component(self.hass, 'sensor', VALID_CONFIG_MINIMAL)
+
+ state = self.hass.states.get('sensor.yweather_condition')
+ assert state is None
+
+ @MockDependency('yahooweather')
+ @patch('yahooweather._yql_query', new=_yql_queryMock)
+ @patch('yahooweather.get_woeid', new=get_woeidMock)
+ @patch('yahooweather.YahooWeather', new=YahooWeatherMock)
+ def test_setup_bad_raw(self, mock_yahooweather):
+ """Test for bad RawData."""
+ assert setup_component(self.hass, 'sensor', BAD_CONF_RAW)
+
+ state = self.hass.states.get('sensor.yweather_condition')
+ assert state is not None
+
+ @MockDependency('yahooweather')
+ @patch('yahooweather._yql_query', new=_yql_queryMock)
+ @patch('yahooweather.get_woeid', new=get_woeidMock)
+ @patch('yahooweather.YahooWeather', new=YahooWeatherMock)
+ def test_setup_bad_data(self, mock_yahooweather):
+ """Test for bad data."""
+ assert setup_component(self.hass, 'sensor', BAD_CONF_DATA)
+
+ state = self.hass.states.get('sensor.yweather_condition')
+ assert state is None
diff --git a/tests/fixtures/yahooweather.json b/tests/fixtures/yahooweather.json
new file mode 100644
index 00000000000..f6ab2980618
--- /dev/null
+++ b/tests/fixtures/yahooweather.json
@@ -0,0 +1,138 @@
+{
+ "query": {
+ "count": 1,
+ "created": "2017-11-17T13:40:47Z",
+ "lang": "en-US",
+ "results": {
+ "channel": {
+ "units": {
+ "distance": "km",
+ "pressure": "mb",
+ "speed": "km/h",
+ "temperature": "C"
+ },
+ "title": "Yahoo! Weather - San Diego, CA, US",
+ "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-23511632/",
+ "description": "Yahoo! Weather for San Diego, CA, US",
+ "language": "en-us",
+ "lastBuildDate": "Fri, 17 Nov 2017 05:40 AM PST",
+ "ttl": "60",
+ "location": {
+ "city": "San Diego",
+ "country": "United States",
+ "region": " CA"
+ },
+ "wind": {
+ "chill": "56",
+ "direction": "0",
+ "speed": "6.34"
+ },
+ "atmosphere": {
+ "humidity": "71",
+ "pressure": "33863.75",
+ "rising": "0",
+ "visibility": "22.91"
+ },
+ "astronomy": {
+ "sunrise": "6:21 am",
+ "sunset": "4:47 pm"
+ },
+ "image": {
+ "title": "Yahoo! Weather",
+ "width": "142",
+ "height": "18",
+ "link": "http://weather.yahoo.com",
+ "url": "http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"
+ },
+ "item": {
+ "title": "Conditions for San Diego, CA, US at 05:00 AM PST",
+ "lat": "32.878101",
+ "long": "-117.23497",
+ "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-23511632/",
+ "pubDate": "Fri, 17 Nov 2017 05:00 AM PST",
+ "condition": {
+ "code": "26",
+ "date": "Fri, 17 Nov 2017 05:00 AM PST",
+ "temp": "18",
+ "text": "Cloudy"
+ },
+ "forecast": [{
+ "code": "28",
+ "date": "17 Nov 2017",
+ "day": "Fri",
+ "high": "23",
+ "low": "16",
+ "text": "Mostly Cloudy"
+ }, {
+ "code": "30",
+ "date": "18 Nov 2017",
+ "day": "Sat",
+ "high": "22",
+ "low": "13",
+ "text": "Partly Cloudy"
+ }, {
+ "code": "30",
+ "date": "19 Nov 2017",
+ "day": "Sun",
+ "high": "22",
+ "low": "12",
+ "text": "Partly Cloudy"
+ }, {
+ "code": "28",
+ "date": "20 Nov 2017",
+ "day": "Mon",
+ "high": "21",
+ "low": "11",
+ "text": "Mostly Cloudy"
+ }, {
+ "code": "28",
+ "date": "21 Nov 2017",
+ "day": "Tue",
+ "high": "24",
+ "low": "14",
+ "text": "Mostly Cloudy"
+ }, {
+ "code": "30",
+ "date": "22 Nov 2017",
+ "day": "Wed",
+ "high": "27",
+ "low": "15",
+ "text": "Partly Cloudy"
+ }, {
+ "code": "34",
+ "date": "23 Nov 2017",
+ "day": "Thu",
+ "high": "27",
+ "low": "15",
+ "text": "Mostly Sunny"
+ }, {
+ "code": "30",
+ "date": "24 Nov 2017",
+ "day": "Fri",
+ "high": "23",
+ "low": "16",
+ "text": "Partly Cloudy"
+ }, {
+ "code": "30",
+ "date": "25 Nov 2017",
+ "day": "Sat",
+ "high": "22",
+ "low": "15",
+ "text": "Partly Cloudy"
+ }, {
+ "code": "28",
+ "date": "26 Nov 2017",
+ "day": "Sun",
+ "high": "24",
+ "low": "13",
+ "text": "Mostly Cloudy"
+ }],
+ "description": "\n
\nCurrent Conditions:\n
Cloudy\n
\n
\nForecast:\n
Fri - Mostly Cloudy. High: 23Low: 16\n
Sat - Partly Cloudy. High: 22Low: 13\n
Sun - Partly Cloudy. High: 22Low: 12\n
Mon - Mostly Cloudy. High: 21Low: 11\n
Tue - Mostly Cloudy. High: 24Low: 14\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n
\n]]>",
+ "guid": {
+ "isPermaLink": "false"
+ }
+ }
+ }
+ }
+ }
+}