change to simpler api

This commit is contained in:
ktdad
2019-07-18 06:50:03 -04:00
parent b5727c84a7
commit fd3a90a91e
4 changed files with 178 additions and 468 deletions

View File

@@ -4,8 +4,5 @@
"documentation": "https://www.home-assistant.io/components/nws",
"dependencies": [],
"codeowners": ["@MatthewFlamm"],
"requirements": [
"pynws==0.6",
"metar==1.7.0"
]
"requirements": ["pynws==0.7.0"]
}

View File

@@ -1,13 +1,10 @@
"""Support for NWS weather service."""
import asyncio
from collections import OrderedDict
from datetime import timedelta
from json import JSONDecodeError
import logging
from statistics import mean
import aiohttp
import async_timeout
import voluptuous as vol
from homeassistant.components.weather import (
@@ -72,13 +69,7 @@ CONDITION_CLASSES = OrderedDict([
'Partly cloudy']),
])
ERRORS = (aiohttp.ClientError, JSONDecodeError, asyncio.CancelledError)
FORECAST_CLASSES = {
ATTR_FORECAST_DETAIL_DESCRIPTION: 'detailedForecast',
ATTR_FORECAST_TEMP: 'temperature',
ATTR_FORECAST_TIME: 'startTime',
}
ERRORS = (aiohttp.ClientError, JSONDecodeError)
FORECAST_MODE = ['daynight', 'hourly']
@@ -88,7 +79,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_MODE, default='daynight'): vol.In(FORECAST_MODE),
vol.Optional(CONF_STATION): cv.string,
vol.Required(CONF_API_KEY): cv.string
vol.Required(CONF_API_KEY): cv.string,
})
@@ -109,16 +100,16 @@ def convert_condition(time, weather):
if cond == 'clear':
if time == 'day':
return 'sunny', max(prec_prob)
return 'sunny', max(prec_probs)
if time == 'night':
return 'clear-night', max(prec_prob)
return cond, max(prec_prob)
return 'clear-night', max(prec_probs)
return cond, max(prec_probs)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the NWS weather platform."""
from pynws import SimpleNws
from pynws import SimpleNWS
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
station = config.get(CONF_STATION)
@@ -132,7 +123,7 @@ async def async_setup_platform(hass, config, async_add_entities,
websession = async_get_clientsession(hass)
# ID request as being from HA, pynws prepends the api_key in addition
api_key_ha = f"{api_key} homeassistant"
nws = simple_nws(lat, lon, userid=api_key_ha, mode, websession)
nws = SimpleNWS(latitude, longitude, api_key_ha, mode, websession)
_LOGGER.debug("Setting up station: %s", station)
try:
@@ -147,25 +138,29 @@ async def async_setup_platform(hass, config, async_add_entities,
latitude, longitude, nws.station)
async_add_entities(
[NWSWeather(nws, hass.config.units, config)],
[NWSWeather(nws, mode, hass.config.units, config)],
True)
class NWSWeather(WeatherEntity):
"""Representation of a weather condition."""
def __init__(self, nws, units, config):
def __init__(self, nws, mode, units, config):
"""Initialise the platform with a data instance and station name."""
self.nws = nws
self.station_name = config.get(CONF_NAME, self._nws.station)
self.station_name = config.get(CONF_NAME, self.nws.station)
self.is_metric = units.is_metric
self.mode = mode
self.observation = None
self._forecast = None
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self):
"""Update Condition."""
_LOGGER.debug("Updating station observations %s", self.nws.station)
try:
await self.nws.update_observations()
await self.nws.update_observation()
except ERRORS as status:
_LOGGER.error("Error updating observation from station %s: %s",
self.nws.station, status)
@@ -178,7 +173,7 @@ class NWSWeather(WeatherEntity):
_LOGGER.error("Error updating forecast from station %s: %s",
self.nws.station, status)
else:
self.forecast = self.nws.forecast
self._forecast = self.nws.forecast
return
@property
@@ -205,7 +200,7 @@ class NWSWeather(WeatherEntity):
def pressure(self):
"""Return the current pressure."""
pressure_pa = None
if self._observation:
if self.observation:
pressure_pa = self.observation.get('seaLevelPressure')
if pressure_pa is None:
return None
@@ -237,7 +232,7 @@ class NWSWeather(WeatherEntity):
return None
wind_m_hr = wind_m_s * 3600
if self._is_metric:
if self.is_metric:
wind = convert_distance(wind_m_hr,
LENGTH_METERS, LENGTH_KILOMETERS)
else:
@@ -275,11 +270,11 @@ class NWSWeather(WeatherEntity):
"""Return visibility."""
vis_m = None
if self.observation:
vis_m = self._observation.get('visibility')
vis_m = self.observation.get('visibility')
if vis_m is None:
return None
if self._is_metric:
if self.is_metric:
vis = convert_distance(vis_m, LENGTH_METERS, LENGTH_KILOMETERS)
else:
vis = convert_distance(vis_m, LENGTH_METERS, LENGTH_MILES)
@@ -288,31 +283,39 @@ class NWSWeather(WeatherEntity):
@property
def forecast(self):
"""Return forecast."""
if self._forecast is None:
return None
forecast = []
for forecast_entry in self._forecast:
data = {
ATTR_FORECAST_DETAIL_DESCRIPTION: forecast_entry.get('detailedForecast'),
ATTR_FORECAST_DETAIL_DESCRIPTION: forecast_entry.get(
'detailedForecast'),
ATTR_FORECAST_TEMP: forecast_entry.get('temperature'),
ATTR_FORECAST_TIME: forecast_entry.get('startTime'),
}
if self._mode == 'daynight':
if self.mode == 'daynight':
data[ATTR_FORECAST_DAYTIME] = forecast_entry.get('isDaytime')
time = forecast_entry.get('iconTime')
weather = forecast_entry.get('iconWeather')
cond, precip = convert_condition(time, weather)
if time and weather:
cond, precip = convert_condition(time, weather)
else:
cond, precip = None, None
data[ATTR_FORECAST_CONDITION] = cond
data[ATTR_FORECAST_PRECIP_PROB] = precip
data[ATTR_FORECAST_WIND_BEARING] = \
WIND[forecast_entry['windDirection']]
forecast_entry.get('windBearing')
wind_speed = forecast_entry.get('windSpeedAvg')
if self._is_metric:
data[ATTR_FORECAST_WIND_SPEED] = round(
convert_distance(wind_speed,
LENGTH_MILES, LENGTH_KILOMETERS))
if wind_speed:
if self.is_metric:
data[ATTR_FORECAST_WIND_SPEED] = round(
convert_distance(wind_speed,
LENGTH_MILES, LENGTH_KILOMETERS))
else:
data[ATTR_FORECAST_WIND_SPEED] = round(wind_speed)
else:
data[ATTR_FORECAST_WIND_SPEED] = round(wind_speed_avg)
data[ATTR_FORECAST_WIND_SPEED] = None
forecast.append(data)
return forecast

View File

@@ -765,9 +765,6 @@ mbddns==0.1.2
# homeassistant.components.message_bird
messagebird==1.2.0
# homeassistant.components.nws
metar==1.7.0
# homeassistant.components.meteoalarm
meteoalertapi==0.1.5
@@ -1292,7 +1289,7 @@ pynuki==1.3.3
pynut2==2.1.2
# homeassistant.components.nws
pynws==0.6
pynws==0.7.0
# homeassistant.components.nx584
pynx584==0.4

View File

@@ -26,129 +26,74 @@ from homeassistant.setup import setup_component
from tests.common import get_test_home_assistant, MockDependency
OBS = [{
'temperature': {'value': 7, 'qualityControl': 'qc:V'},
'relativeHumidity': {'value': 10, 'qualityControl': 'qc:V'},
'windChill': {'value': 10, 'qualityControl': 'qc:V'},
'heatIndex': {'value': 10, 'qualityControl': 'qc:V'},
'windDirection': {'value': 180, 'qualityControl': 'qc:V'},
'visibility': {'value': 10000, 'qualityControl': 'qc:V'},
'windSpeed': {'value': 10, 'qualityControl': 'qc:V'},
'seaLevelPressure': {'value': 30000, 'qualityControl': 'qc:V'},
'windGust': {'value': 10, 'qualityControl': 'qc:V'},
'dewpoint': {'value': 10, 'qualityControl': 'qc:V'},
'icon': 'https://api.weather.gov/icons/land/day/skc?size=medium',
'textDescription': 'Sunny'
}]
METAR_MSG = ("PHNG 182257Z 06012KT 10SM FEW020 SCT026 SCT035 "
"28/22 A3007 RMK AO2 SLP177 T02780217")
OBS_METAR = [{
"rawMessage": METAR_MSG,
"textDescription": "Partly Cloudy",
"icon": "https://api.weather.gov/icons/land/day/sct?size=medium",
"temperature": {"value": None, "qualityControl": "qc:Z"},
"windDirection": {"value": None, "qualityControl": "qc:Z"},
"windSpeed": {"value": None, "qualityControl": "qc:Z"},
"seaLevelPressure": {"value": None, "qualityControl": "qc:Z"},
"visibility": {"value": None, "qualityControl": "qc:Z"},
"relativeHumidity": {"value": None, "qualityControl": "qc:Z"},
}]
OBS_NONE = [{
"rawMessage": None,
"textDescription": None,
"icon": None,
"temperature": {"value": None, "qualityControl": "qc:Z"},
"windDirection": {"value": None, "qualityControl": "qc:Z"},
"windSpeed": {"value": None, "qualityControl": "qc:Z"},
"seaLevelPressure": {"value": None, "qualityControl": "qc:Z"},
"visibility": {"value": None, "qualityControl": "qc:Z"},
"relativeHumidity": {"value": None, "qualityControl": "qc:Z"},
}]
OBS = {
'temperature': 7,
'relativeHumidity': 10,
'windBearing': 180,
'visibility': 10000,
'windSpeed': 10,
'seaLevelPressure': 30000,
'iconTime': 'day',
'iconWeather': (('Fair/clear', None),),
}
FORE = [{
'endTime': '2018-12-21T18:00:00-05:00',
'windSpeed': '8 to 10 mph',
'windDirection': 'S',
'shortForecast': 'Chance Showers And Thunderstorms',
'isDaytime': True,
'startTime': '2018-12-21T15:00:00-05:00',
'temperatureTrend': None,
'temperature': 41,
'temperatureUnit': 'F',
'detailedForecast': 'A detailed description',
'name': 'This Afternoon',
'number': 1,
'icon': 'https://api.weather.gov/icons/land/day/skc/tsra,40?size=medium'
}]
HOURLY_FORE = [{
'endTime': '2018-12-22T05:00:00-05:00',
'windSpeed': '4 mph',
'windDirection': 'N',
'shortForecast': 'Chance Showers And Thunderstorms',
'startTime': '2018-12-22T04:00:00-05:00',
'temperatureTrend': None,
'temperature': 32,
'temperatureUnit': 'F',
'detailedForecast': '',
'number': 2,
'icon': 'https://api.weather.gov/icons/land/night/skc?size=medium'
'windBearing': 180,
'windSpeedAvg': 9,
'iconTime': 'day',
'startTime': '2018-12-21T15:00:00-05:00',
'iconWeather': (('Fair/Clear', None),
('Thunderstorm (high cloud cover)', 40),),
}]
STN = 'STNA'
class MockNws():
class MockNws:
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
data_obs = None
data_fore = None
error_obs = False
error_fore = False
error_stn = False
def __init__(self, lat, lon, userid, mode, session):
"""Init mock nws."""
pass
self.station = None
self.stations = None
async def observations(self, limit):
async def update_observation(self):
"""Mock observation update."""
if self.error_obs:
raise aiohttp.ClientError
return
async def update_forecast(self):
"""Mock forecast update."""
if self.error_fore:
raise aiohttp.ClientError
return
@property
def observation(self):
"""Mock Observation."""
return OBS
return self.data_obs
async def forecast(self):
@property
def forecast(self):
"""Mock Forecast."""
return FORE
return self.data_fore
async def forecast_hourly(self):
"""Mock Hourly Forecast."""
return HOURLY_FORE
async def stations(self):
async def set_station(self, station=None):
"""Mock stations."""
return [STN]
class Prop:
"""Property data class for metar. Initialize with desired return value."""
def __init__(self, value_return):
"""Initialize with desired return."""
self.value_return = value_return
def value(self, units=''):
"""Return provided value."""
return self.value_return
class MockMetar:
"""Mock Metar parser."""
def __init__(self, code):
"""Set up mocked return values."""
self.temp = Prop(27)
self.press = Prop(1111)
self.wind_speed = Prop(27)
self.wind_dir = Prop(175)
self.vis = Prop(5000)
if self.error_stn:
raise aiohttp.ClientError
self.stations = [STN]
self.station = station or STN
return
class TestNWS(unittest.TestCase):
@@ -161,15 +106,25 @@ class TestNWS(unittest.TestCase):
self.lat = self.hass.config.latitude = 40.00
self.lon = self.hass.config.longitude = -8.00
# Initialize class variables as tests modify them
MockNws.data_obs = None
MockNws.data_fore = None
MockNws.error_obs = False
MockNws.error_fore = False
MockNws.error_stn = False
def tearDown(self):
"""Stop down everything that was started."""
self.hass.stop()
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_w_name(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws(self, mock_pynws):
"""Test for successfully setting up with imperial."""
mock_pynws.SimpleNWS.data_obs = OBS
mock_pynws.SimpleNWS.data_fore = FORE
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
@@ -203,137 +158,14 @@ class TestNWS(unittest.TestCase):
assert forecast[0].get(ATTR_FORECAST_WIND_BEARING) == 180
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == 9
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_w_station(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with station."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'platform': 'nws',
'station': 'STNB',
'api_key': 'test_email',
}
})
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws_metric(self, mock_pynws):
"""Test for successfully setting up with metric."""
mock_pynws.SimpleNWS.data_obs = OBS
mock_pynws.SimpleNWS.data_fore = FORE
assert self.hass.states.get('weather.stnb')
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_w_no_name(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform w no name."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'platform': 'nws',
'api_key': 'test_email',
}
})
assert self.hass.states.get('weather.' + STN)
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test__hourly(self, mock_metar, mock_pynws):
"""Test for successfully setting up hourly forecast."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HourlyWeather',
'platform': 'nws',
'api_key': 'test_email',
'mode': 'hourly',
}
})
state = self.hass.states.get('weather.hourlyweather')
data = state.attributes
forecast = data.get(ATTR_FORECAST)
assert forecast[0].get(ATTR_FORECAST_CONDITION) == 'clear-night'
assert forecast[0].get(ATTR_FORECAST_PRECIP_PROB) is None
assert forecast[0].get(ATTR_FORECAST_TEMP) == 32
assert forecast[0].get(ATTR_FORECAST_TIME) == \
'2018-12-22T04:00:00-05:00'
assert forecast[0].get(ATTR_FORECAST_WIND_BEARING) == 0
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == 4
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_daynight(self, mock_metar, mock_pynws):
"""Test for successfully setting up daynight forecast."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'platform': 'nws',
'api_key': 'test_email',
'mode': 'daynight',
}
})
assert self.hass.states.get('weather.' + STN)
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_latlon(self, mock_metar, mock_pynws):
"""Test for successsfully setting up the NWS platform with lat/lon."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'platform': 'nws',
'api_key': 'test_email',
'latitude': self.lat,
'longitude': self.lon,
}
})
assert self.hass.states.get('weather.' + STN)
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_setup_failure_mode(self, mock_metar, mock_pynws):
"""Test for unsuccessfully setting up incorrect mode."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'platform': 'nws',
'api_key': 'test_email',
'mode': 'abc',
}
})
assert self.hass.states.get('weather.' + STN) is None
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_setup_failure_no_apikey(self, mock_metar, mock_pynws):
"""Test for unsuccessfully setting up without api_key."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'platform': 'nws',
}
})
assert self.hass.states.get('weather.' + STN) is None
class TestNwsMetric(unittest.TestCase):
"""Test the NWS weather component using metric units."""
def setUp(self):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.units = METRIC_SYSTEM
self.lat = self.hass.config.latitude = 40.00
self.lon = self.hass.config.longitude = -8.00
def tearDown(self):
"""Stop down everything that was started."""
self.hass.stop()
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_metric(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
@@ -346,14 +178,13 @@ class TestNwsMetric(unittest.TestCase):
assert state.state == 'sunny'
data = state.attributes
temp_f = convert_temperature(7, TEMP_CELSIUS, TEMP_FAHRENHEIT)
assert data.get(ATTR_WEATHER_TEMPERATURE) == \
display_temp(self.hass, 7, TEMP_CELSIUS, PRECISION_WHOLE)
display_temp(self.hass, temp_f, TEMP_FAHRENHEIT, PRECISION_WHOLE)
assert data.get(ATTR_WEATHER_HUMIDITY) == 10
assert data.get(ATTR_WEATHER_PRESSURE) == round(
convert_pressure(30000, PRESSURE_PA, PRESSURE_HPA))
# m/s to km/hr
assert data.get(ATTR_WEATHER_WIND_SPEED) == round(10 * 3.6)
assert data.get(ATTR_WEATHER_WIND_SPEED) == round(3.6 * 10)
assert data.get(ATTR_WEATHER_WIND_BEARING) == 180
assert data.get(ATTR_WEATHER_VISIBILITY) == round(
convert_distance(10000, LENGTH_METERS, LENGTH_KILOMETERS))
@@ -362,47 +193,18 @@ class TestNwsMetric(unittest.TestCase):
forecast = data.get(ATTR_FORECAST)
assert forecast[0].get(ATTR_FORECAST_CONDITION) == 'lightning-rainy'
assert forecast[0].get(ATTR_FORECAST_PRECIP_PROB) == 40
assert forecast[0].get(ATTR_FORECAST_TEMP) == round(
convert_temperature(41, TEMP_FAHRENHEIT, TEMP_CELSIUS))
assert forecast[0].get(ATTR_FORECAST_TEMP) == convert_temperature(
41, TEMP_FAHRENHEIT, TEMP_CELSIUS)
assert forecast[0].get(ATTR_FORECAST_TIME) == \
'2018-12-21T15:00:00-05:00'
assert forecast[0].get(ATTR_FORECAST_WIND_BEARING) == 180
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == round(
convert_distance(9, LENGTH_MILES, LENGTH_KILOMETERS))
class MockNws_Metar(MockNws):
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
"""Init mock nws."""
pass
async def observations(self, limit):
"""Mock Observation."""
return OBS_METAR
class TestNWS_Metar(unittest.TestCase):
"""Test the NWS weather component with metar code."""
def setUp(self):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.units = IMPERIAL_SYSTEM
self.lat = self.hass.config.latitude = 40.00
self.lon = self.hass.config.longitude = -8.00
def tearDown(self):
"""Stop down everything that was started."""
self.hass.stop()
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws_Metar)
@patch("metar.Metar.Metar", new=MockMetar)
def test_metar(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws_no_obs_fore1x(self, mock_pynws):
"""Test with no data."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
@@ -411,154 +213,15 @@ class TestNWS_Metar(unittest.TestCase):
}
})
from metar import Metar
truth = Metar.Metar(METAR_MSG)
state = self.hass.states.get('weather.homeweather')
data = state.attributes
temp_f = convert_temperature(truth.temp.value(), TEMP_CELSIUS,
TEMP_FAHRENHEIT)
assert data.get(ATTR_WEATHER_TEMPERATURE) == \
display_temp(self.hass, temp_f, TEMP_FAHRENHEIT, PRECISION_WHOLE)
assert data.get(ATTR_WEATHER_HUMIDITY) is None
assert data.get(ATTR_WEATHER_PRESSURE) == round(
convert_pressure(truth.press.value(), PRESSURE_HPA, PRESSURE_INHG),
2)
wind_speed_mi_s = convert_distance(
truth.wind_speed.value(), LENGTH_METERS, LENGTH_MILES)
assert data.get(ATTR_WEATHER_WIND_SPEED) == round(
wind_speed_mi_s * 3600)
assert data.get(ATTR_WEATHER_WIND_BEARING) == truth.wind_dir.value()
vis = convert_distance(truth.vis.value(), LENGTH_METERS, LENGTH_MILES)
assert data.get(ATTR_WEATHER_VISIBILITY) == round(vis)
class MockNwsFailObs(MockNws):
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
"""Init mock nws."""
pass
async def observations(self, limit):
"""Mock Observation."""
raise aiohttp.ClientError
class MockNwsFailStn(MockNws):
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
"""Init mock nws."""
pass
async def stations(self):
"""Mock Observation."""
raise aiohttp.ClientError
class MockNwsFailFore(MockNws):
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
"""Init mock nws."""
pass
async def forecast(self):
"""Mock Observation."""
raise aiohttp.ClientError
class MockNws_NoObs(MockNws):
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
"""Init mock nws."""
pass
async def observations(self, limit):
"""Mock Observation."""
return OBS_NONE
class TestFailures(unittest.TestCase):
"""Test the NWS weather component."""
def setUp(self):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.units = IMPERIAL_SYSTEM
self.lat = self.hass.config.latitude = 40.00
self.lon = self.hass.config.longitude = -8.00
def tearDown(self):
"""Stop down everything that was started."""
self.hass.stop()
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNwsFailObs)
def test_obs_fail(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNwsFailStn)
def test_fail_stn(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
state = self.hass.states.get('weather.homeweather')
assert state is None
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNwsFailFore)
def test_fail_fore(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws_NoObs)
def test_no_obs(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
state = self.hass.states.get('weather.homeweather')
assert state.state == 'unknown'
@MockDependency("metar")
@MockDependency("pynws")
@patch("pynws.Nws", new=MockNws)
def test_no_lat(self, mock_metar, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
hass = self.hass
hass.config.latitude = None
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws_missing_valuess(self, mock_pynws):
"""Test with missing data."""
mock_pynws.SimpleNWS.data_obs = {key: None for key in OBS}
mock_pynws.SimpleNWS.data_fore = [{key: None for key in FORE[0]}]
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
@@ -568,5 +231,55 @@ class TestFailures(unittest.TestCase):
}
})
state = self.hass.states.get('weather.homeweather')
assert state.state == 'unknown'
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws_error_obs(self, mock_pynws):
"""Test for successfully setting up the NWS platform with name."""
mock_pynws.SimpleNWS.error_obs = True
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
state = self.hass.states.get('weather.homeweather')
assert state.state == 'unknown'
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws_error_fore(self, mock_pynws):
"""Test error forecast."""
mock_pynws.SimpleNWS.error_fore = True
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
state = self.hass.states.get('weather.homeweather')
data = state.attributes
assert data.get('forecast') is None
@MockDependency('pynws')
@patch("pynws.SimpleNWS", new=MockNws)
def test_nws_error_stn(self, mock_pynws):
"""Test station error.."""
mock_pynws.SimpleNWS.error_stn = True
assert setup_component(self.hass, weather.DOMAIN, {
'weather': {
'name': 'HomeWeather',
'platform': 'nws',
'api_key': 'test_email',
}
})
state = self.hass.states.get('weather.homeweather')
assert state is None