check and test for missing observations

This commit is contained in:
ktdad
2019-06-01 07:20:59 -04:00
parent 63055f949c
commit ef687d3d7f
3 changed files with 201 additions and 35 deletions

View File

@@ -18,7 +18,7 @@ from homeassistant.const import (
CONF_API_KEY, CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE,
LENGTH_KILOMETERS, LENGTH_METERS, LENGTH_MILES, PRESSURE_HPA, PRESSURE_PA,
PRESSURE_INHG, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from homeassistant.exceptions import PlatformNotReady
from homeassistant.exceptions import PlatformNotReady, ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers import config_validation as cv
from homeassistant.util import Throttle
@@ -139,7 +139,7 @@ async def async_setup_platform(hass, config, async_add_entities,
if None in (latitude, longitude):
_LOGGER.error("Latitude/longitude not set in Home Assistant config")
return
return ConfigEntryNotReady
websession = async_get_clientsession(hass)
# ID request as being from HA, pynws prepends the api_key in addition
@@ -154,7 +154,7 @@ async def async_setup_platform(hass, config, async_add_entities,
stations = await nws.stations()
except ERRORS as status:
_LOGGER.error("Error getting station list for %s: %s",
nws.latlon, status)
(latitude, longitude), status)
raise PlatformNotReady
_LOGGER.debug("Station list: %s", stations)
nws.station = stations[0]
@@ -197,9 +197,9 @@ class NWSWeather(WeatherEntity):
self._nws.station, status)
else:
self._observation = obs[0]
if 'rawMessage' in self._observation.keys():
self._metar_obs = self._metar(
self._observation['rawMessage'])
metar_msg = self._observation.get('rawMessage')
if metar_msg:
self._metar_obs = self._metar(metar_msg)
else:
self._metar_obs = None
_LOGGER.debug("Observations: %s", self._observation)
@@ -229,7 +229,9 @@ class NWSWeather(WeatherEntity):
@property
def temperature(self):
"""Return the current temperature."""
temp_c = self._observation['temperature']['value']
temp_c = None
if self._observation:
temp_c = self._observation.get('temperature', {}).get('value')
if temp_c is None and self._metar_obs and self._metar_obs.temp:
temp_c = self._metar_obs.temp.value(units='C')
if temp_c is not None:
@@ -239,7 +241,10 @@ class NWSWeather(WeatherEntity):
@property
def pressure(self):
"""Return the current pressure."""
pressure_pa = self._observation['seaLevelPressure']['value']
pressure_pa = None
if self._observation:
pressure_pa = self._observation.get('seaLevelPressure',
{}).get('value')
if pressure_pa is None and self._metar_obs and self._metar_obs.press:
pressure_hpa = self._metar_obs.press.value(units='HPA')
@@ -247,9 +252,11 @@ class NWSWeather(WeatherEntity):
return None
pressure_pa = convert_pressure(pressure_hpa, PRESSURE_HPA,
PRESSURE_PA)
if pressure_pa is None:
return None
if self._is_metric:
pressure = convert_pressure(pressure_pa, PRESSURE_PA, PRESSURE_HPA)
pressure = convert_pressure(pressure_pa,
PRESSURE_PA, PRESSURE_HPA)
pressure = round(pressure)
else:
pressure = convert_pressure(pressure_pa,
@@ -260,12 +267,18 @@ class NWSWeather(WeatherEntity):
@property
def humidity(self):
"""Return the name of the sensor."""
return self._observation['relativeHumidity']['value']
humidity = None
if self._observation:
humidity = self._observation.get('relativeHumidity',
{}).get('value')
return humidity
@property
def wind_speed(self):
"""Return the current windspeed."""
wind_m_s = self._observation['windSpeed']['value']
wind_m_s = None
if self._observation:
wind_m_s = self._observation.get('windSpeed', {}).get('value')
if wind_m_s is None and self._metar_obs and self._metar_obs.wind_speed:
wind_m_s = self._metar_obs.wind_speed.value(units='MPS')
if wind_m_s is None:
@@ -282,7 +295,10 @@ class NWSWeather(WeatherEntity):
@property
def wind_bearing(self):
"""Return the current wind bearing (degrees)."""
wind_bearing = self._observation['windDirection']['value']
wind_bearing = None
if self._observation:
wind_bearing = self._observation.get('windDirection',
{}).get('value')
if wind_bearing is None and (self._metar_obs
and self._metar_obs.wind_dir):
wind_bearing = self._metar_obs.wind_dir.value()
@@ -296,14 +312,21 @@ class NWSWeather(WeatherEntity):
@property
def condition(self):
"""Return current condition."""
time, weather = parse_icon(self._observation['icon'])
cond, _ = convert_condition(time, weather)
return cond
icon = None
if self._observation:
icon = self._observation.get('icon')
if icon:
time, weather = parse_icon(self._observation['icon'])
cond, _ = convert_condition(time, weather)
return cond
return
@property
def visibility(self):
"""Return visibility."""
vis_m = self._observation['visibility']['value']
vis_m = None
if self._observation:
vis_m = self._observation.get('visibility', {}).get('value')
if vis_m is None and self._metar_obs and self._metar_obs.vis:
vis_m = self._metar_obs.vis.value(units='M')
if vis_m is None:

View File

@@ -116,11 +116,13 @@ class WeatherEntity(Entity):
@property
def state_attributes(self):
"""Return the state attributes."""
data = {
ATTR_WEATHER_TEMPERATURE: show_temp(
self.hass, self.temperature, self.temperature_unit,
self.precision),
}
data = {}
if self.temperature is not None:
data = {
ATTR_WEATHER_TEMPERATURE: show_temp(
self.hass, self.temperature, self.temperature_unit,
self.precision),
}
humidity = self.humidity
if humidity is not None:

View File

@@ -2,6 +2,8 @@
import unittest
from unittest.mock import patch
import aiohttp
from homeassistant.components import weather
from homeassistant.components.nws.weather import ATTR_FORECAST_PRECIP_PROB
from homeassistant.components.weather import (
@@ -55,6 +57,19 @@ OBS_METAR = [{
"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"},
}]
FORE = [{
'endTime': '2018-12-21T18:00:00-05:00',
'windSpeed': '8 to 10 mph',
@@ -356,7 +371,7 @@ class TestNwsMetric(unittest.TestCase):
convert_distance(9, LENGTH_MILES, LENGTH_KILOMETERS))
class MockNws_Metar():
class MockNws_Metar(MockNws):
"""Mock Station from pynws."""
def __init__(self, websession, latlon, userid):
@@ -367,18 +382,6 @@ class MockNws_Metar():
"""Mock Observation."""
return OBS_METAR
async def forecast(self):
"""Mock Forecast."""
return FORE
async def forecast_hourly(self):
"""Mock Hourly Forecast."""
return HOURLY_FORE
async def stations(self):
"""Mock stations."""
return [STN]
class TestNWS_Metar(unittest.TestCase):
"""Test the NWS weather component with metar code."""
@@ -429,3 +432,141 @@ class TestNWS_Metar(unittest.TestCase):
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
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