Fetch sunrise and sunset time for daily forecast

This commit is contained in:
Jules 2024-06-09 17:53:27 +02:00
parent 48ad275cf9
commit 0059b2f78f
Signed by: jdejaegh
GPG key ID: 99D6D184CA66933A
3 changed files with 75 additions and 7 deletions

View file

@ -19,16 +19,18 @@ from homeassistant.util import dt
from homeassistant.util.dt import utcnow
from .api import IrmKmiApiClient, IrmKmiApiError
from .const import CONF_DARK_MODE, CONF_STYLE, DOMAIN, IRM_KMI_NAME, WEEKDAYS
from .const import CONF_DARK_MODE, CONF_STYLE, DOMAIN, IRM_KMI_NAME
from .const import IRM_KMI_TO_HA_CONDITION_MAP as CDT_MAP
from .const import MAP_WARNING_ID_TO_SLUG as SLUG_MAP
from .const import OPTION_STYLE_SATELLITE, OUT_OF_BENELUX, STYLE_TO_PARAM_MAP
from .const import (OPTION_STYLE_SATELLITE, OUT_OF_BENELUX, STYLE_TO_PARAM_MAP,
WEEKDAYS)
from .data import (AnimationFrameData, CurrentWeatherData, IrmKmiForecast,
IrmKmiRadarForecast, ProcessedCoordinatorData,
RadarAnimationData, WarningData)
from .pollen import PollenParser
from .rain_graph import RainGraph
from .utils import disable_from_config, get_config_value, preferred_language, next_weekday
from .utils import (disable_from_config, get_config_value, next_weekday,
preferred_language)
_LOGGER = logging.getLogger(__name__)
@ -351,14 +353,14 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
IrmKmiRadarForecast(
datetime=f.get("time"),
native_precipitation=f.get('value'),
rain_forecast_max=round(f.get('positionHigher')*ratio, 2),
rain_forecast_min=round(f.get('positionLower')*ratio, 2),
rain_forecast_max=round(f.get('positionHigher') * ratio, 2),
rain_forecast_min=round(f.get('positionLower') * ratio, 2),
might_rain=f.get('positionHigher') > 0
)
)
return forecast
async def daily_list_to_forecast(self, data: List[dict] | None) -> List[Forecast] | None:
async def daily_list_to_forecast(self, data: List[dict] | None) -> List[IrmKmiForecast] | None:
"""Parse data from the API to create a list of daily forecasts"""
if data is None or not isinstance(data, list) or len(data) == 0:
return None
@ -403,6 +405,28 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
elif day_name == 'Tomorrow':
forecast_day = dt.now(tz) + timedelta(days=1)
sunrise_sec = f.get('dawnRiseSeconds', None)
if sunrise_sec is None:
sunrise_sec = f.get('sunRise', None)
sunrise = None
if sunrise_sec is not None:
try:
sunrise = (forecast_day.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=tz)
+ timedelta(seconds=float(sunrise_sec)))
except (TypeError, ValueError):
pass
sunset_sec = f.get('dawnSetSeconds', None)
if sunset_sec is None:
sunset_sec = f.get('sunSet', None)
sunset = None
if sunset_sec is not None:
try:
sunset = (forecast_day.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=tz)
+ timedelta(seconds=float(sunset_sec)))
except (TypeError, ValueError):
pass
forecast = IrmKmiForecast(
datetime=(forecast_day.strftime('%Y-%m-%d')),
condition=CDT_MAP.get((f.get('ww1', None), f.get('dayNight', None)), None),
@ -415,6 +439,8 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
wind_bearing=wind_bearing,
is_daytime=is_daytime,
text=f.get('text', {}).get(lang, ""),
sunrise=sunrise,
sunset=sunset
)
# Swap temperature and templow if needed
if (forecast['native_templow'] is not None

View file

@ -10,6 +10,8 @@ class IrmKmiForecast(Forecast):
# TODO: add condition_2 as well and evolution to match data from the API?
text: str | None
sunrise: datetime | None
sunset: datetime | None
class IrmKmiRadarForecast(Forecast):

View file

@ -1,3 +1,4 @@
import zoneinfo
from datetime import datetime, timedelta
from freezegun import freeze_time
@ -101,7 +102,7 @@ async def test_daily_forecast(
assert len(result) == 8
assert result[0]['datetime'] == '2023-12-26'
assert not result[0]['is_daytime']
tz = zoneinfo.ZoneInfo(key='Europe/Brussels')
expected = IrmKmiForecast(
datetime='2023-12-27',
condition=ATTR_CONDITION_PARTLYCLOUDY,
@ -114,6 +115,8 @@ async def test_daily_forecast(
wind_bearing=180,
is_daytime=True,
text='Bar',
sunrise=datetime.fromisoformat("2023-12-27T08:44:00+01:00").astimezone(tz),
sunset=datetime.fromisoformat("2023-12-27T16:43:00+01:00").astimezone(tz)
)
assert result[1] == expected
@ -350,3 +353,40 @@ async def test_current_condition_forecast_nl() -> None:
uv_index=6
)
assert result == expected
@freeze_time("2024-06-09T13:40:00+00:00")
async def test_sunrise_sunset_nl(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry
) -> None:
api_data = get_api_data("forecast_ams_no_ww.json").get('for', {}).get('daily')
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
result = await coordinator.daily_list_to_forecast(api_data)
assert result[0]['sunrise'].isoformat() == '2024-06-09T05:19:28+02:00'
assert result[0]['sunset'].isoformat() == '2024-06-09T22:01:09+02:00'
assert result[1]['sunrise'] is None
assert result[1]['sunset'] is None
assert result[2]['sunrise'].isoformat() == '2024-06-10T05:19:08+02:00'
assert result[2]['sunset'].isoformat() == '2024-06-10T22:01:53+02:00'
@freeze_time("2023-12-26T18:30:00+01:00")
async def test_sunrise_sunset_be(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry
) -> None:
api_data = get_api_data("forecast.json").get('for', {}).get('daily')
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
result = await coordinator.daily_list_to_forecast(api_data)
assert result[1]['sunrise'].isoformat() == '2023-12-27T08:44:00+01:00'
assert result[1]['sunset'].isoformat() == '2023-12-27T16:43:00+01:00'
assert result[2]['sunrise'].isoformat() == '2023-12-28T08:45:00+01:00'
assert result[2]['sunset'].isoformat() == '2023-12-28T16:43:00+01:00'