mirror of
https://github.com/home-assistant/core.git
synced 2025-08-02 12:15:08 +02:00
change to simpler api
This commit is contained in:
@@ -4,8 +4,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/components/nws",
|
"documentation": "https://www.home-assistant.io/components/nws",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@MatthewFlamm"],
|
"codeowners": ["@MatthewFlamm"],
|
||||||
"requirements": [
|
"requirements": ["pynws==0.7.0"]
|
||||||
"pynws==0.6",
|
|
||||||
"metar==1.7.0"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
"""Support for NWS weather service."""
|
"""Support for NWS weather service."""
|
||||||
import asyncio
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
import logging
|
import logging
|
||||||
from statistics import mean
|
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import async_timeout
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
@@ -72,13 +69,7 @@ CONDITION_CLASSES = OrderedDict([
|
|||||||
'Partly cloudy']),
|
'Partly cloudy']),
|
||||||
])
|
])
|
||||||
|
|
||||||
ERRORS = (aiohttp.ClientError, JSONDecodeError, asyncio.CancelledError)
|
ERRORS = (aiohttp.ClientError, JSONDecodeError)
|
||||||
|
|
||||||
FORECAST_CLASSES = {
|
|
||||||
ATTR_FORECAST_DETAIL_DESCRIPTION: 'detailedForecast',
|
|
||||||
ATTR_FORECAST_TEMP: 'temperature',
|
|
||||||
ATTR_FORECAST_TIME: 'startTime',
|
|
||||||
}
|
|
||||||
|
|
||||||
FORECAST_MODE = ['daynight', 'hourly']
|
FORECAST_MODE = ['daynight', 'hourly']
|
||||||
|
|
||||||
@@ -88,7 +79,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||||||
vol.Optional(CONF_LONGITUDE): cv.longitude,
|
vol.Optional(CONF_LONGITUDE): cv.longitude,
|
||||||
vol.Optional(CONF_MODE, default='daynight'): vol.In(FORECAST_MODE),
|
vol.Optional(CONF_MODE, default='daynight'): vol.In(FORECAST_MODE),
|
||||||
vol.Optional(CONF_STATION): cv.string,
|
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 cond == 'clear':
|
||||||
if time == 'day':
|
if time == 'day':
|
||||||
return 'sunny', max(prec_prob)
|
return 'sunny', max(prec_probs)
|
||||||
if time == 'night':
|
if time == 'night':
|
||||||
return 'clear-night', max(prec_prob)
|
return 'clear-night', max(prec_probs)
|
||||||
return cond, max(prec_prob)
|
return cond, max(prec_probs)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities,
|
async def async_setup_platform(hass, config, async_add_entities,
|
||||||
discovery_info=None):
|
discovery_info=None):
|
||||||
"""Set up the NWS weather platform."""
|
"""Set up the NWS weather platform."""
|
||||||
from pynws import SimpleNws
|
from pynws import SimpleNWS
|
||||||
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
||||||
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
||||||
station = config.get(CONF_STATION)
|
station = config.get(CONF_STATION)
|
||||||
@@ -132,7 +123,7 @@ async def async_setup_platform(hass, config, async_add_entities,
|
|||||||
websession = async_get_clientsession(hass)
|
websession = async_get_clientsession(hass)
|
||||||
# ID request as being from HA, pynws prepends the api_key in addition
|
# ID request as being from HA, pynws prepends the api_key in addition
|
||||||
api_key_ha = f"{api_key} homeassistant"
|
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)
|
_LOGGER.debug("Setting up station: %s", station)
|
||||||
try:
|
try:
|
||||||
@@ -147,25 +138,29 @@ async def async_setup_platform(hass, config, async_add_entities,
|
|||||||
latitude, longitude, nws.station)
|
latitude, longitude, nws.station)
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[NWSWeather(nws, hass.config.units, config)],
|
[NWSWeather(nws, mode, hass.config.units, config)],
|
||||||
True)
|
True)
|
||||||
|
|
||||||
|
|
||||||
class NWSWeather(WeatherEntity):
|
class NWSWeather(WeatherEntity):
|
||||||
"""Representation of a weather condition."""
|
"""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."""
|
"""Initialise the platform with a data instance and station name."""
|
||||||
self.nws = nws
|
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.is_metric = units.is_metric
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
self.observation = None
|
||||||
|
self._forecast = None
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update Condition."""
|
"""Update Condition."""
|
||||||
_LOGGER.debug("Updating station observations %s", self.nws.station)
|
_LOGGER.debug("Updating station observations %s", self.nws.station)
|
||||||
try:
|
try:
|
||||||
await self.nws.update_observations()
|
await self.nws.update_observation()
|
||||||
except ERRORS as status:
|
except ERRORS as status:
|
||||||
_LOGGER.error("Error updating observation from station %s: %s",
|
_LOGGER.error("Error updating observation from station %s: %s",
|
||||||
self.nws.station, status)
|
self.nws.station, status)
|
||||||
@@ -178,7 +173,7 @@ class NWSWeather(WeatherEntity):
|
|||||||
_LOGGER.error("Error updating forecast from station %s: %s",
|
_LOGGER.error("Error updating forecast from station %s: %s",
|
||||||
self.nws.station, status)
|
self.nws.station, status)
|
||||||
else:
|
else:
|
||||||
self.forecast = self.nws.forecast
|
self._forecast = self.nws.forecast
|
||||||
return
|
return
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -205,7 +200,7 @@ class NWSWeather(WeatherEntity):
|
|||||||
def pressure(self):
|
def pressure(self):
|
||||||
"""Return the current pressure."""
|
"""Return the current pressure."""
|
||||||
pressure_pa = None
|
pressure_pa = None
|
||||||
if self._observation:
|
if self.observation:
|
||||||
pressure_pa = self.observation.get('seaLevelPressure')
|
pressure_pa = self.observation.get('seaLevelPressure')
|
||||||
if pressure_pa is None:
|
if pressure_pa is None:
|
||||||
return None
|
return None
|
||||||
@@ -237,7 +232,7 @@ class NWSWeather(WeatherEntity):
|
|||||||
return None
|
return None
|
||||||
wind_m_hr = wind_m_s * 3600
|
wind_m_hr = wind_m_s * 3600
|
||||||
|
|
||||||
if self._is_metric:
|
if self.is_metric:
|
||||||
wind = convert_distance(wind_m_hr,
|
wind = convert_distance(wind_m_hr,
|
||||||
LENGTH_METERS, LENGTH_KILOMETERS)
|
LENGTH_METERS, LENGTH_KILOMETERS)
|
||||||
else:
|
else:
|
||||||
@@ -275,11 +270,11 @@ class NWSWeather(WeatherEntity):
|
|||||||
"""Return visibility."""
|
"""Return visibility."""
|
||||||
vis_m = None
|
vis_m = None
|
||||||
if self.observation:
|
if self.observation:
|
||||||
vis_m = self._observation.get('visibility')
|
vis_m = self.observation.get('visibility')
|
||||||
if vis_m is None:
|
if vis_m is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self._is_metric:
|
if self.is_metric:
|
||||||
vis = convert_distance(vis_m, LENGTH_METERS, LENGTH_KILOMETERS)
|
vis = convert_distance(vis_m, LENGTH_METERS, LENGTH_KILOMETERS)
|
||||||
else:
|
else:
|
||||||
vis = convert_distance(vis_m, LENGTH_METERS, LENGTH_MILES)
|
vis = convert_distance(vis_m, LENGTH_METERS, LENGTH_MILES)
|
||||||
@@ -288,31 +283,39 @@ class NWSWeather(WeatherEntity):
|
|||||||
@property
|
@property
|
||||||
def forecast(self):
|
def forecast(self):
|
||||||
"""Return forecast."""
|
"""Return forecast."""
|
||||||
|
if self._forecast is None:
|
||||||
|
return None
|
||||||
forecast = []
|
forecast = []
|
||||||
for forecast_entry in self._forecast:
|
for forecast_entry in self._forecast:
|
||||||
data = {
|
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_TEMP: forecast_entry.get('temperature'),
|
||||||
ATTR_FORECAST_TIME: forecast_entry.get('startTime'),
|
ATTR_FORECAST_TIME: forecast_entry.get('startTime'),
|
||||||
}
|
}
|
||||||
|
|
||||||
if self._mode == 'daynight':
|
if self.mode == 'daynight':
|
||||||
data[ATTR_FORECAST_DAYTIME] = forecast_entry.get('isDaytime')
|
data[ATTR_FORECAST_DAYTIME] = forecast_entry.get('isDaytime')
|
||||||
time = forecast_entry.get('iconTime')
|
time = forecast_entry.get('iconTime')
|
||||||
weather = forecast_entry.get('iconWeather')
|
weather = forecast_entry.get('iconWeather')
|
||||||
|
if time and weather:
|
||||||
cond, precip = convert_condition(time, weather)
|
cond, precip = convert_condition(time, weather)
|
||||||
|
else:
|
||||||
|
cond, precip = None, None
|
||||||
data[ATTR_FORECAST_CONDITION] = cond
|
data[ATTR_FORECAST_CONDITION] = cond
|
||||||
data[ATTR_FORECAST_PRECIP_PROB] = precip
|
data[ATTR_FORECAST_PRECIP_PROB] = precip
|
||||||
|
|
||||||
data[ATTR_FORECAST_WIND_BEARING] = \
|
data[ATTR_FORECAST_WIND_BEARING] = \
|
||||||
WIND[forecast_entry['windDirection']]
|
forecast_entry.get('windBearing')
|
||||||
wind_speed = forecast_entry.get('windSpeedAvg')
|
wind_speed = forecast_entry.get('windSpeedAvg')
|
||||||
if self._is_metric:
|
if wind_speed:
|
||||||
|
if self.is_metric:
|
||||||
data[ATTR_FORECAST_WIND_SPEED] = round(
|
data[ATTR_FORECAST_WIND_SPEED] = round(
|
||||||
convert_distance(wind_speed,
|
convert_distance(wind_speed,
|
||||||
LENGTH_MILES, LENGTH_KILOMETERS))
|
LENGTH_MILES, LENGTH_KILOMETERS))
|
||||||
else:
|
else:
|
||||||
data[ATTR_FORECAST_WIND_SPEED] = round(wind_speed_avg)
|
data[ATTR_FORECAST_WIND_SPEED] = round(wind_speed)
|
||||||
|
else:
|
||||||
|
data[ATTR_FORECAST_WIND_SPEED] = None
|
||||||
forecast.append(data)
|
forecast.append(data)
|
||||||
return forecast
|
return forecast
|
||||||
|
@@ -765,9 +765,6 @@ mbddns==0.1.2
|
|||||||
# homeassistant.components.message_bird
|
# homeassistant.components.message_bird
|
||||||
messagebird==1.2.0
|
messagebird==1.2.0
|
||||||
|
|
||||||
# homeassistant.components.nws
|
|
||||||
metar==1.7.0
|
|
||||||
|
|
||||||
# homeassistant.components.meteoalarm
|
# homeassistant.components.meteoalarm
|
||||||
meteoalertapi==0.1.5
|
meteoalertapi==0.1.5
|
||||||
|
|
||||||
@@ -1292,7 +1289,7 @@ pynuki==1.3.3
|
|||||||
pynut2==2.1.2
|
pynut2==2.1.2
|
||||||
|
|
||||||
# homeassistant.components.nws
|
# homeassistant.components.nws
|
||||||
pynws==0.6
|
pynws==0.7.0
|
||||||
|
|
||||||
# homeassistant.components.nx584
|
# homeassistant.components.nx584
|
||||||
pynx584==0.4
|
pynx584==0.4
|
||||||
|
@@ -26,129 +26,74 @@ from homeassistant.setup import setup_component
|
|||||||
|
|
||||||
from tests.common import get_test_home_assistant, MockDependency
|
from tests.common import get_test_home_assistant, MockDependency
|
||||||
|
|
||||||
|
OBS = {
|
||||||
OBS = [{
|
'temperature': 7,
|
||||||
'temperature': {'value': 7, 'qualityControl': 'qc:V'},
|
'relativeHumidity': 10,
|
||||||
'relativeHumidity': {'value': 10, 'qualityControl': 'qc:V'},
|
'windBearing': 180,
|
||||||
'windChill': {'value': 10, 'qualityControl': 'qc:V'},
|
'visibility': 10000,
|
||||||
'heatIndex': {'value': 10, 'qualityControl': 'qc:V'},
|
'windSpeed': 10,
|
||||||
'windDirection': {'value': 180, 'qualityControl': 'qc:V'},
|
'seaLevelPressure': 30000,
|
||||||
'visibility': {'value': 10000, 'qualityControl': 'qc:V'},
|
'iconTime': 'day',
|
||||||
'windSpeed': {'value': 10, 'qualityControl': 'qc:V'},
|
'iconWeather': (('Fair/clear', None),),
|
||||||
'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"},
|
|
||||||
}]
|
|
||||||
|
|
||||||
|
|
||||||
FORE = [{
|
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,
|
'temperature': 41,
|
||||||
'temperatureUnit': 'F',
|
'windBearing': 180,
|
||||||
'detailedForecast': 'A detailed description',
|
'windSpeedAvg': 9,
|
||||||
'name': 'This Afternoon',
|
'iconTime': 'day',
|
||||||
'number': 1,
|
'startTime': '2018-12-21T15:00:00-05:00',
|
||||||
'icon': 'https://api.weather.gov/icons/land/day/skc/tsra,40?size=medium'
|
'iconWeather': (('Fair/Clear', None),
|
||||||
}]
|
('Thunderstorm (high cloud cover)', 40),),
|
||||||
|
|
||||||
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'
|
|
||||||
}]
|
}]
|
||||||
|
|
||||||
STN = 'STNA'
|
STN = 'STNA'
|
||||||
|
|
||||||
|
|
||||||
class MockNws():
|
class MockNws:
|
||||||
"""Mock Station from pynws."""
|
"""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."""
|
"""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."""
|
"""Mock Observation."""
|
||||||
return OBS
|
return self.data_obs
|
||||||
|
|
||||||
async def forecast(self):
|
@property
|
||||||
|
def forecast(self):
|
||||||
"""Mock Forecast."""
|
"""Mock Forecast."""
|
||||||
return FORE
|
return self.data_fore
|
||||||
|
|
||||||
async def forecast_hourly(self):
|
async def set_station(self, station=None):
|
||||||
"""Mock Hourly Forecast."""
|
|
||||||
return HOURLY_FORE
|
|
||||||
|
|
||||||
async def stations(self):
|
|
||||||
"""Mock stations."""
|
"""Mock stations."""
|
||||||
return [STN]
|
if self.error_stn:
|
||||||
|
raise aiohttp.ClientError
|
||||||
|
self.stations = [STN]
|
||||||
class Prop:
|
self.station = station or STN
|
||||||
"""Property data class for metar. Initialize with desired return value."""
|
return
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class TestNWS(unittest.TestCase):
|
class TestNWS(unittest.TestCase):
|
||||||
@@ -161,15 +106,25 @@ class TestNWS(unittest.TestCase):
|
|||||||
self.lat = self.hass.config.latitude = 40.00
|
self.lat = self.hass.config.latitude = 40.00
|
||||||
self.lon = self.hass.config.longitude = -8.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):
|
def tearDown(self):
|
||||||
"""Stop down everything that was started."""
|
"""Stop down everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
|
|
||||||
@MockDependency("metar")
|
@MockDependency('pynws')
|
||||||
@MockDependency("pynws")
|
@patch("pynws.SimpleNWS", new=MockNws)
|
||||||
@patch("pynws.Nws", new=MockNws)
|
def test_nws(self, mock_pynws):
|
||||||
def test_w_name(self, mock_metar, mock_pynws):
|
"""Test for successfully setting up with imperial."""
|
||||||
"""Test for successfully setting up the NWS platform with name."""
|
mock_pynws.SimpleNWS.data_obs = OBS
|
||||||
|
mock_pynws.SimpleNWS.data_fore = FORE
|
||||||
|
|
||||||
assert setup_component(self.hass, weather.DOMAIN, {
|
assert setup_component(self.hass, weather.DOMAIN, {
|
||||||
'weather': {
|
'weather': {
|
||||||
'name': 'HomeWeather',
|
'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_BEARING) == 180
|
||||||
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == 9
|
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == 9
|
||||||
|
|
||||||
@MockDependency("metar")
|
@MockDependency('pynws')
|
||||||
@MockDependency("pynws")
|
@patch("pynws.SimpleNWS", new=MockNws)
|
||||||
@patch("pynws.Nws", new=MockNws)
|
def test_nws_metric(self, mock_pynws):
|
||||||
def test_w_station(self, mock_metar, mock_pynws):
|
"""Test for successfully setting up with metric."""
|
||||||
"""Test for successfully setting up the NWS platform with station."""
|
mock_pynws.SimpleNWS.data_obs = OBS
|
||||||
assert setup_component(self.hass, weather.DOMAIN, {
|
mock_pynws.SimpleNWS.data_fore = FORE
|
||||||
'weather': {
|
|
||||||
'platform': 'nws',
|
|
||||||
'station': 'STNB',
|
|
||||||
'api_key': 'test_email',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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.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, {
|
assert setup_component(self.hass, weather.DOMAIN, {
|
||||||
'weather': {
|
'weather': {
|
||||||
'name': 'HomeWeather',
|
'name': 'HomeWeather',
|
||||||
@@ -346,14 +178,13 @@ class TestNwsMetric(unittest.TestCase):
|
|||||||
assert state.state == 'sunny'
|
assert state.state == 'sunny'
|
||||||
|
|
||||||
data = state.attributes
|
data = state.attributes
|
||||||
|
temp_f = convert_temperature(7, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||||
assert data.get(ATTR_WEATHER_TEMPERATURE) == \
|
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_HUMIDITY) == 10
|
||||||
assert data.get(ATTR_WEATHER_PRESSURE) == round(
|
assert data.get(ATTR_WEATHER_PRESSURE) == round(
|
||||||
convert_pressure(30000, PRESSURE_PA, PRESSURE_HPA))
|
convert_pressure(30000, PRESSURE_PA, PRESSURE_HPA))
|
||||||
# m/s to km/hr
|
assert data.get(ATTR_WEATHER_WIND_SPEED) == round(3.6 * 10)
|
||||||
assert data.get(ATTR_WEATHER_WIND_SPEED) == round(10 * 3.6)
|
|
||||||
assert data.get(ATTR_WEATHER_WIND_BEARING) == 180
|
assert data.get(ATTR_WEATHER_WIND_BEARING) == 180
|
||||||
assert data.get(ATTR_WEATHER_VISIBILITY) == round(
|
assert data.get(ATTR_WEATHER_VISIBILITY) == round(
|
||||||
convert_distance(10000, LENGTH_METERS, LENGTH_KILOMETERS))
|
convert_distance(10000, LENGTH_METERS, LENGTH_KILOMETERS))
|
||||||
@@ -362,47 +193,18 @@ class TestNwsMetric(unittest.TestCase):
|
|||||||
forecast = data.get(ATTR_FORECAST)
|
forecast = data.get(ATTR_FORECAST)
|
||||||
assert forecast[0].get(ATTR_FORECAST_CONDITION) == 'lightning-rainy'
|
assert forecast[0].get(ATTR_FORECAST_CONDITION) == 'lightning-rainy'
|
||||||
assert forecast[0].get(ATTR_FORECAST_PRECIP_PROB) == 40
|
assert forecast[0].get(ATTR_FORECAST_PRECIP_PROB) == 40
|
||||||
assert forecast[0].get(ATTR_FORECAST_TEMP) == round(
|
assert forecast[0].get(ATTR_FORECAST_TEMP) == convert_temperature(
|
||||||
convert_temperature(41, TEMP_FAHRENHEIT, TEMP_CELSIUS))
|
41, TEMP_FAHRENHEIT, TEMP_CELSIUS)
|
||||||
assert forecast[0].get(ATTR_FORECAST_TIME) == \
|
assert forecast[0].get(ATTR_FORECAST_TIME) == \
|
||||||
'2018-12-21T15:00:00-05:00'
|
'2018-12-21T15:00:00-05:00'
|
||||||
assert forecast[0].get(ATTR_FORECAST_WIND_BEARING) == 180
|
assert forecast[0].get(ATTR_FORECAST_WIND_BEARING) == 180
|
||||||
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == round(
|
assert forecast[0].get(ATTR_FORECAST_WIND_SPEED) == round(
|
||||||
convert_distance(9, LENGTH_MILES, LENGTH_KILOMETERS))
|
convert_distance(9, LENGTH_MILES, LENGTH_KILOMETERS))
|
||||||
|
|
||||||
|
@MockDependency('pynws')
|
||||||
class MockNws_Metar(MockNws):
|
@patch("pynws.SimpleNWS", new=MockNws)
|
||||||
"""Mock Station from pynws."""
|
def test_nws_no_obs_fore1x(self, mock_pynws):
|
||||||
|
"""Test with no data."""
|
||||||
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."""
|
|
||||||
assert setup_component(self.hass, weather.DOMAIN, {
|
assert setup_component(self.hass, weather.DOMAIN, {
|
||||||
'weather': {
|
'weather': {
|
||||||
'name': 'HomeWeather',
|
'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')
|
state = self.hass.states.get('weather.homeweather')
|
||||||
assert state.state == 'unknown'
|
assert state.state == 'unknown'
|
||||||
|
|
||||||
@MockDependency("metar")
|
@MockDependency('pynws')
|
||||||
@MockDependency("pynws")
|
@patch("pynws.SimpleNWS", new=MockNws)
|
||||||
@patch("pynws.Nws", new=MockNws)
|
def test_nws_missing_valuess(self, mock_pynws):
|
||||||
def test_no_lat(self, mock_metar, mock_pynws):
|
"""Test with missing data."""
|
||||||
"""Test for successfully setting up the NWS platform with name."""
|
mock_pynws.SimpleNWS.data_obs = {key: None for key in OBS}
|
||||||
hass = self.hass
|
mock_pynws.SimpleNWS.data_fore = [{key: None for key in FORE[0]}]
|
||||||
hass.config.latitude = None
|
|
||||||
|
|
||||||
assert setup_component(self.hass, weather.DOMAIN, {
|
assert setup_component(self.hass, weather.DOMAIN, {
|
||||||
'weather': {
|
'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')
|
state = self.hass.states.get('weather.homeweather')
|
||||||
assert state is None
|
assert state is None
|
||||||
|
Reference in New Issue
Block a user