mirror of
https://github.com/home-assistant/core.git
synced 2025-08-03 12:45:28 +02:00
check and test for missing observations
This commit is contained in:
@@ -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:
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user