diff --git a/README.md b/README.md index 7945194..9281784 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ To get there in one click, use this button: [![Open your Home Assistant instance and start setting up this integration.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=dwd) -This adds one device and two entities (one with hourly forecast and one with daily forceast) for the selected station. To add more stations, just repeat the "Add Integration" step. +This adds one device and three entities for the selected station. By default, only the entity that provides all forecasts in one entity is enabled. However, if you still need the weather entities with daily and houry forecasts separately or via the old mechanism, you can just enable them. To add more stations, just repeat the "Add Integration" step. ## Questions & Answers @@ -97,13 +97,13 @@ For issues with measurement data (current condition, current temperature, ...), - When the problem occurs, download immediately `https://opendata.dwd.de/weather/weather_reports/poi/{station_id}-BEOB.csv`. Replace `{station_id}` with your actual station ID. If your station ID has less than 5 characters, it has to be padded with trailing underscores, so e.g. "A191" becomes "A191_" here. ### Issues with Hourly Forecasts -For issues with hourly forecasts (i.e. the forecasts of the entity ending with "\_hourly"), please include the following items in your bug report. +For issues with hourly forecasts, please include the following items in your bug report. - Always include the station ID. - When the problem occurs, go to the Developer Tools and copy immediately all state attributes (YAML) of the hourly entity (the entity ending with "\_hourly"). - When the problem occurs, download immediately `https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_L/single_stations/{station_id}/kml/MOSMIX_L_LATEST_{station_id}.kmz`. Replace `{station_id}` with your actual station ID. No padding needed here. ### Issues with Daily Forecasts -For issues with daily forecasts (i.e. the forecasts of the entity ending with "\_daily"), please include the following items in your bug report. +For issues with daily forecasts, please include the following items in your bug report. - Always include the station ID. - When the problem occurs, go to the Developer Tools and copy immediately all state attributes (YAML) of the hourly entity (the entity ending with "\_hourly"). This is important, because the daily forecasts are calculated from hourly forecasts. - When the problem occurs, go to the Developer Tools and copy immediately all state attributes (YAML) of the daily entity (the entity ending with "\_daily"). diff --git a/custom_components/dwd/const.py b/custom_components/dwd/const.py index d3637f0..f5e39d0 100644 --- a/custom_components/dwd/const.py +++ b/custom_components/dwd/const.py @@ -45,9 +45,6 @@ MEASUREMENTS_MAX_AGE = 3 -FORECAST_MODE_DAILY = 0 -FORECAST_MODE_HOURLY = 1 - DWD_MEASUREMENT = 0 DWD_FORECAST = 1 diff --git a/custom_components/dwd/manifest.json b/custom_components/dwd/manifest.json index 2fdce16..5daa20b 100644 --- a/custom_components/dwd/manifest.json +++ b/custom_components/dwd/manifest.json @@ -9,5 +9,5 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/hg1337/homeassistant-dwd/issues", "requirements": [], - "version": "2023.8.0" + "version": "2023.8.1" } \ No newline at end of file diff --git a/custom_components/dwd/weather.py b/custom_components/dwd/weather.py index 35f3c07..7db6834 100644 --- a/custom_components/dwd/weather.py +++ b/custom_components/dwd/weather.py @@ -2,6 +2,7 @@ from __future__ import annotations from datetime import date, datetime, time, timedelta, timezone +from enum import Enum import logging from typing import Any, Optional from homeassistant.components.weather import WeatherEntityFeature @@ -73,13 +74,17 @@ DWD_MEASUREMENT_PRESSURE, DWD_MEASUREMENT_TEMPERATURE, DWD_MEASUREMENT_VISIBILITY, - FORECAST_MODE_DAILY, - FORECAST_MODE_HOURLY, ) _LOGGER = logging.getLogger(__name__) +class ForecastMode(Enum): + STANDARD = 0 + DAILY = 1 + HOURLY = 2 + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -98,12 +103,20 @@ async def async_setup_entry( async_add_entities( [ + DwdWeather( + hass, + coordinator, + config_entry.unique_id, + config_entry, + ForecastMode.STANDARD, + device, + ), DwdWeather( hass, coordinator, f"{config_entry.unique_id}-daily", config_entry, - FORECAST_MODE_DAILY, + ForecastMode.DAILY, device, ), DwdWeather( @@ -111,7 +124,7 @@ async def async_setup_entry( coordinator, f"{config_entry.unique_id}-hourly", config_entry, - FORECAST_MODE_HOURLY, + ForecastMode.HOURLY, device, ), ] @@ -127,7 +140,7 @@ def __init__( coordinator: DwdDataUpdateCoordinator, unique_id: str, config: ConfigEntry, - forecast_mode: int, + forecast_mode: ForecastMode, device: DeviceInfo, ) -> None: """Initialise the platform with a data instance and site.""" @@ -135,7 +148,7 @@ def __init__( self._hass: HomeAssistant = hass self._unique_id: str = unique_id self._config: ConfigEntry = config - self._forecast_mode: int = forecast_mode + self._forecast_mode: ForecastMode = forecast_mode self._device: DeviceInfo = device self._conf_current_weather: str = self._config.options.get( CONF_CURRENT_WEATHER, CONF_CURRENT_WEATHER_DEFAULT @@ -143,10 +156,16 @@ def __init__( self._attr_supported_features = 0 if self._config.options.get(CONF_FORECAST, CONF_FORECAST_DEFAULT): - if self._forecast_mode == FORECAST_MODE_HOURLY: - self._attr_supported_features |= WeatherEntityFeature.FORECAST_HOURLY - if self._forecast_mode == FORECAST_MODE_DAILY: + if ( + self._forecast_mode == ForecastMode.STANDARD + or self._forecast_mode == ForecastMode.DAILY + ): self._attr_supported_features |= WeatherEntityFeature.FORECAST_DAILY + if ( + self._forecast_mode == ForecastMode.STANDARD + or self._forecast_mode == ForecastMode.HOURLY + ): + self._attr_supported_features |= WeatherEntityFeature.FORECAST_HOURLY @property def unique_id(self) -> str: @@ -160,9 +179,9 @@ def name(self) -> str: name = self._config.title name_appendix = "" - if self._forecast_mode == FORECAST_MODE_HOURLY: + if self._forecast_mode == ForecastMode.HOURLY: name_appendix = " Hourly" - if self._forecast_mode == FORECAST_MODE_DAILY: + if self._forecast_mode == ForecastMode.DAILY: name_appendix = " Daily" if name is None: @@ -183,6 +202,11 @@ def device_info(self) -> DeviceInfo: """Device info.""" return self._device + @property + def entity_registry_enabled_default(self) -> bool: + """Return if the entity should be enabled when first added to the entity registry.""" + return self._forecast_mode == ForecastMode.STANDARD + @property def condition(self) -> str | None: """Return the current condition.""" @@ -197,7 +221,7 @@ def condition(self) -> str | None: if self._conf_current_weather == CONF_CURRENT_WEATHER_MEASUREMENT: return None else: - forecast = self._get_forecast(FORECAST_MODE_HOURLY, 1) + forecast = self._get_forecast(ForecastMode.HOURLY, 1) if forecast is None or len(forecast) < 1: return None else: @@ -208,7 +232,7 @@ def condition(self) -> str | None: condition = ATTR_CONDITION_CLEAR_NIGHT return condition elif self._conf_current_weather == CONF_CURRENT_WEATHER_FORECAST: - forecast = self._get_forecast(FORECAST_MODE_HOURLY, 1) + forecast = self._get_forecast(ForecastMode.HOURLY, 1) if forecast is None or len(forecast) < 1: return None else: @@ -289,7 +313,7 @@ def _get_float_measurement_with_fallback( if self._conf_current_weather == CONF_CURRENT_WEATHER_MEASUREMENT: return None else: - forecast = self._get_forecast(FORECAST_MODE_HOURLY, 1) + forecast = self._get_forecast(ForecastMode.HOURLY, 1) if forecast is None or len(forecast) < 1: return None else: @@ -297,7 +321,7 @@ def _get_float_measurement_with_fallback( else: return DwdWeather._str_to_float(str_value) elif self._conf_current_weather == CONF_CURRENT_WEATHER_FORECAST: - forecast = self._get_forecast(FORECAST_MODE_HOURLY, 1) + forecast = self._get_forecast(ForecastMode.HOURLY, 1) if forecast is None or len(forecast) < 1: return None else: @@ -334,6 +358,9 @@ def forecast(self): if not self._config.options.get(CONF_FORECAST, CONF_FORECAST_DEFAULT): return None + if self._forecast_mode == ForecastMode.STANDARD: + return None + return self._get_forecast(self._forecast_mode) async def async_forecast_daily(self): @@ -342,7 +369,7 @@ async def async_forecast_daily(self): if not self._config.options.get(CONF_FORECAST, CONF_FORECAST_DEFAULT): return None - return self._get_forecast(FORECAST_MODE_DAILY) + return self._get_forecast(ForecastMode.DAILY) async def async_forecast_hourly(self): """Return the daily forecast.""" @@ -350,9 +377,9 @@ async def async_forecast_hourly(self): if not self._config.options.get(CONF_FORECAST, CONF_FORECAST_DEFAULT): return None - return self._get_forecast(FORECAST_MODE_HOURLY) + return self._get_forecast(ForecastMode.HOURLY) - def _get_forecast(self, forecast_mode: int, max_hours: int = 0): + def _get_forecast(self, forecast_mode: ForecastMode, max_hours: int = 0): # We build both lists in parallel and just return the needed one. Although it's a small # overhead, it still makes thinks easier, because there is still much in common, because to # calculate the days most of the hourly stuff has to be done again. @@ -756,7 +783,7 @@ def _get_forecast(self, forecast_mode: int, max_hours: int = 0): if max_hours > 0 and len(hourly_list) >= max_hours: break - if forecast_mode == FORECAST_MODE_DAILY: + if forecast_mode == ForecastMode.DAILY: result = [] if len(daily_list) > 0: # Always add current day: @@ -766,7 +793,7 @@ def _get_forecast(self, forecast_mode: int, max_hours: int = 0): if daily_list[i].has_enough_hours: result.append(daily_list[i].values) return result - if forecast_mode == FORECAST_MODE_HOURLY: + if forecast_mode == ForecastMode.HOURLY: return hourly_list @staticmethod diff --git a/images/screenshot_entities.png b/images/screenshot_entities.png index fdaf480..9eb0d3f 100644 Binary files a/images/screenshot_entities.png and b/images/screenshot_entities.png differ diff --git a/images/screenshot_weather-forecast-card-configuration.png b/images/screenshot_weather-forecast-card-configuration.png index 234af32..78c3c94 100644 Binary files a/images/screenshot_weather-forecast-card-configuration.png and b/images/screenshot_weather-forecast-card-configuration.png differ diff --git a/setup.md b/setup.md index 0d10c6b..bfdf138 100644 --- a/setup.md +++ b/setup.md @@ -64,7 +64,7 @@ If you don't want to use the My Home Assistant button or if it doesn't work in y Follow the instructions, select a different station or enter a custom one if needed. By default, the closest station that provides measurement as well as forcast data is preselected, if it is not more than 20 km away and if the difference in elevation is less than 500 m. Otherwise the closest available station is preselected. -After that, you should have one new device and two new weather entities for the selected station, one entity with hourly forecast and one entity with daily forceast. Both have the same measurement data. You may repeat these steps if you want to add more stations. +After that, you should have one new device and three new weather entities for the selected station. By default, only the entity that provides all forecasts in one entity is enabled. However, if you still need the weather entities with daily and houry forecasts separately or via the old mechanism, you can just enable them. All have the same measurement data. You may repeat these steps if you want to add more stations. ![Screenshot Entities](./images/screenshot_entities.png)