diff --git a/homeassistant/components/nws/__init__.py b/homeassistant/components/nws/__init__.py index f6cdc7c57cd..9f0579dc20e 100644 --- a/homeassistant/components/nws/__init__.py +++ b/homeassistant/components/nws/__init__.py @@ -4,13 +4,12 @@ import datetime import logging from pynws import SimpleNWS -import voluptuous as vol from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE from homeassistant.core import HomeAssistant +from homeassistant.helpers import debounce from homeassistant.helpers.aiohttp_client import async_get_clientsession -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import ( @@ -24,27 +23,12 @@ from .const import ( _LOGGER = logging.getLogger(__name__) -_INDIVIDUAL_SCHEMA = vol.Schema( - { - vol.Required(CONF_API_KEY): cv.string, - vol.Inclusive( - CONF_LATITUDE, "coordinates", "Latitude and longitude must exist together" - ): cv.latitude, - vol.Inclusive( - CONF_LONGITUDE, "coordinates", "Latitude and longitude must exist together" - ): cv.longitude, - vol.Optional(CONF_STATION): cv.string, - } -) - -CONFIG_SCHEMA = vol.Schema( - {DOMAIN: vol.All(cv.ensure_list, [_INDIVIDUAL_SCHEMA])}, extra=vol.ALLOW_EXTRA, -) - PLATFORMS = ["weather"] DEFAULT_SCAN_INTERVAL = datetime.timedelta(minutes=10) +DEBOUNCE_TIME = 60 # in seconds + def base_unique_id(latitude, longitude): """Return unique id for entries in configuration.""" @@ -75,6 +59,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): name=f"NWS observation station {station}", update_method=nws_data.update_observation, update_interval=DEFAULT_SCAN_INTERVAL, + request_refresh_debouncer=debounce.Debouncer( + hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True + ), ) coordinator_forecast = DataUpdateCoordinator( @@ -83,6 +70,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): name=f"NWS forecast station {station}", update_method=nws_data.update_forecast, update_interval=DEFAULT_SCAN_INTERVAL, + request_refresh_debouncer=debounce.Debouncer( + hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True + ), ) coordinator_forecast_hourly = DataUpdateCoordinator( @@ -91,6 +81,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): name=f"NWS forecast hourly station {station}", update_method=nws_data.update_forecast_hourly, update_interval=DEFAULT_SCAN_INTERVAL, + request_refresh_debouncer=debounce.Debouncer( + hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True + ), ) nws_hass_data = hass.data.setdefault(DOMAIN, {}) nws_hass_data[entry.entry_id] = { diff --git a/homeassistant/components/nws/manifest.json b/homeassistant/components/nws/manifest.json index 2aa783f7a28..da465b0eea5 100644 --- a/homeassistant/components/nws/manifest.json +++ b/homeassistant/components/nws/manifest.json @@ -4,6 +4,6 @@ "documentation": "https://www.home-assistant.io/integrations/nws", "codeowners": ["@MatthewFlamm"], "requirements": ["pynws==0.10.4"], - "quality_scale": "silver", + "quality_scale": "platinum", "config_flow": true } diff --git a/homeassistant/components/nws/weather.py b/homeassistant/components/nws/weather.py index afccebfbccd..807591e0c2b 100644 --- a/homeassistant/components/nws/weather.py +++ b/homeassistant/components/nws/weather.py @@ -45,6 +45,8 @@ from .const import ( _LOGGER = logging.getLogger(__name__) +PARALLEL_UPDATES = 0 + def convert_condition(time, weather): """ @@ -289,3 +291,11 @@ class NWSWeather(WeatherEntity): self.coordinator_observation.last_update_success and self.coordinator_forecast.last_update_success ) + + async def async_update(self): + """Update the entity. + + Only used by the generic entity update service. + """ + await self.coordinator_observation.async_request_refresh() + await self.coordinator_forecast.async_request_refresh() diff --git a/tests/components/nws/test_weather.py b/tests/components/nws/test_weather.py index f1054104a4a..667f40db137 100644 --- a/tests/components/nws/test_weather.py +++ b/tests/components/nws/test_weather.py @@ -6,6 +6,7 @@ import pytest from homeassistant.components import nws from homeassistant.components.weather import ATTR_FORECAST +from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM @@ -125,6 +126,32 @@ async def test_error_station(hass, mock_simple_nws): assert hass.states.get("weather.abc_daynight") is None +async def test_entity_refresh(hass, mock_simple_nws): + """Test manual refresh.""" + instance = mock_simple_nws.return_value + + await async_setup_component(hass, "homeassistant", {}) + + entry = MockConfigEntry(domain=nws.DOMAIN, data=NWS_CONFIG,) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + instance.update_observation.assert_called_once() + instance.update_forecast.assert_called_once() + instance.update_forecast_hourly.assert_called_once() + + await hass.services.async_call( + "homeassistant", + "update_entity", + {"entity_id": "weather.abc_daynight"}, + blocking=True, + ) + await hass.async_block_till_done() + assert instance.update_observation.call_count == 2 + assert instance.update_forecast.call_count == 2 + instance.update_forecast_hourly.assert_called_once() + + async def test_error_observation(hass, mock_simple_nws): """Test error during update observation.""" instance = mock_simple_nws.return_value