mirror of
https://github.com/jdejaegh/irm-kmi-ha.git
synced 2025-06-27 11:39:26 +02:00
Merge pull request #48 from jdejaegh/next_sunrise_sunset
Add next sunset sunrise sensors
This commit is contained in:
commit
da512c5f37
7 changed files with 100 additions and 2 deletions
|
@ -176,7 +176,8 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
|
||||||
radar_forecast=IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation', {})),
|
radar_forecast=IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation', {})),
|
||||||
animation=await self._async_animation_data(api_data=api_data),
|
animation=await self._async_animation_data(api_data=api_data),
|
||||||
warnings=self.warnings_from_data(api_data.get('for', {}).get('warning')),
|
warnings=self.warnings_from_data(api_data.get('for', {}).get('warning')),
|
||||||
pollen=await self._async_pollen_data(api_data=api_data)
|
pollen=await self._async_pollen_data(api_data=api_data),
|
||||||
|
country=api_data.get('country')
|
||||||
)
|
)
|
||||||
|
|
||||||
async def download_images_from_api(self,
|
async def download_images_from_api(self,
|
||||||
|
|
|
@ -73,3 +73,4 @@ class ProcessedCoordinatorData(TypedDict, total=False):
|
||||||
animation: RadarAnimationData
|
animation: RadarAnimationData
|
||||||
warnings: List[WarningData]
|
warnings: List[WarningData]
|
||||||
pollen: dict
|
pollen: dict
|
||||||
|
country: str
|
||||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.util import dt
|
||||||
|
|
||||||
from custom_components.irm_kmi import DOMAIN, IrmKmiCoordinator
|
from custom_components.irm_kmi import DOMAIN, IrmKmiCoordinator
|
||||||
from custom_components.irm_kmi.const import POLLEN_NAMES, POLLEN_TO_ICON_MAP
|
from custom_components.irm_kmi.const import POLLEN_NAMES, POLLEN_TO_ICON_MAP
|
||||||
|
from custom_components.irm_kmi.data import IrmKmiForecast
|
||||||
from custom_components.irm_kmi.pollen import PollenParser
|
from custom_components.irm_kmi.pollen import PollenParser
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -23,6 +24,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
|
||||||
async_add_entities([IrmKmiPollen(coordinator, entry, pollen.lower()) for pollen in POLLEN_NAMES])
|
async_add_entities([IrmKmiPollen(coordinator, entry, pollen.lower()) for pollen in POLLEN_NAMES])
|
||||||
async_add_entities([IrmKmiNextWarning(coordinator, entry),])
|
async_add_entities([IrmKmiNextWarning(coordinator, entry),])
|
||||||
|
|
||||||
|
if coordinator.data.get('country') != 'NL':
|
||||||
|
async_add_entities([IrmKmiNextSunMove(coordinator, entry, move) for move in ['sunset', 'sunrise']])
|
||||||
|
|
||||||
|
|
||||||
class IrmKmiPollen(CoordinatorEntity, SensorEntity):
|
class IrmKmiPollen(CoordinatorEntity, SensorEntity):
|
||||||
"""Representation of a pollen sensor"""
|
"""Representation of a pollen sensor"""
|
||||||
|
@ -96,3 +100,37 @@ class IrmKmiNextWarning(CoordinatorEntity, SensorEntity):
|
||||||
[warning['friendly_name'] for warning in attrs['next_warnings'] if warning['friendly_name'] != ''])
|
[warning['friendly_name'] for warning in attrs['next_warnings'] if warning['friendly_name'] != ''])
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
class IrmKmiNextSunMove(CoordinatorEntity, SensorEntity):
|
||||||
|
"""Representation of the next sunrise or sunset"""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_device_class = SensorDeviceClass.TIMESTAMP
|
||||||
|
_attr_attribution = "Weather data from the Royal Meteorological Institute of Belgium meteo.be"
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
coordinator: IrmKmiCoordinator,
|
||||||
|
entry: ConfigEntry,
|
||||||
|
move: str) -> None:
|
||||||
|
assert move in ['sunset', 'sunrise']
|
||||||
|
super().__init__(coordinator)
|
||||||
|
SensorEntity.__init__(self)
|
||||||
|
self._attr_unique_id = f"{entry.entry_id}-next-{move}"
|
||||||
|
self.entity_id = sensor.ENTITY_ID_FORMAT.format(f"{str(entry.title).lower()}_next_{move}")
|
||||||
|
self._attr_device_info = coordinator.shared_device_info
|
||||||
|
self._attr_translation_key = f"next_{move}"
|
||||||
|
self._move: str = move
|
||||||
|
self._attr_icon = 'mdi:weather-sunset-down' if move == 'sunset' else 'mdi:weather-sunset-up'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> datetime.datetime | None:
|
||||||
|
"""Return the timestamp for the next sunrise or sunset"""
|
||||||
|
now = dt.now()
|
||||||
|
data: list[IrmKmiForecast] = self.coordinator.data.get('daily_forecast')
|
||||||
|
|
||||||
|
upcoming = [f.get(self._move) for f in data if f.get(self._move) >= now]
|
||||||
|
|
||||||
|
if len(upcoming) > 0:
|
||||||
|
return upcoming[0]
|
||||||
|
return None
|
||||||
|
|
|
@ -93,6 +93,12 @@
|
||||||
"next_warning": {
|
"next_warning": {
|
||||||
"name": "Next warning"
|
"name": "Next warning"
|
||||||
},
|
},
|
||||||
|
"next_sunrise": {
|
||||||
|
"name": "Next sunrise"
|
||||||
|
},
|
||||||
|
"next_sunset": {
|
||||||
|
"name": "Next sunset"
|
||||||
|
},
|
||||||
"pollen_alder": {
|
"pollen_alder": {
|
||||||
"name": "Alder pollen",
|
"name": "Alder pollen",
|
||||||
"state": {
|
"state": {
|
||||||
|
|
|
@ -93,6 +93,12 @@
|
||||||
"next_warning": {
|
"next_warning": {
|
||||||
"name": "Prochain avertissement"
|
"name": "Prochain avertissement"
|
||||||
},
|
},
|
||||||
|
"next_sunrise": {
|
||||||
|
"name": "Prochain lever de soleil"
|
||||||
|
},
|
||||||
|
"next_sunset": {
|
||||||
|
"name": "Prochain coucher de soleil"
|
||||||
|
},
|
||||||
"pollen_alder": {
|
"pollen_alder": {
|
||||||
"name": "Pollen d'aulne",
|
"name": "Pollen d'aulne",
|
||||||
"state": {
|
"state": {
|
||||||
|
|
|
@ -93,6 +93,12 @@
|
||||||
"next_warning": {
|
"next_warning": {
|
||||||
"name": "Volgende waarschuwing"
|
"name": "Volgende waarschuwing"
|
||||||
},
|
},
|
||||||
|
"next_sunrise": {
|
||||||
|
"name": "Volgende zonsopkomst"
|
||||||
|
},
|
||||||
|
"next_sunset": {
|
||||||
|
"name": "Volgende zonsondergang"
|
||||||
|
},
|
||||||
"pollen_alder": {
|
"pollen_alder": {
|
||||||
"name": "Elzenpollen",
|
"name": "Elzenpollen",
|
||||||
"state": {
|
"state": {
|
||||||
|
|
|
@ -7,7 +7,7 @@ from pytest_homeassistant_custom_component.common import MockConfigEntry
|
||||||
from custom_components.irm_kmi import IrmKmiCoordinator
|
from custom_components.irm_kmi import IrmKmiCoordinator
|
||||||
from custom_components.irm_kmi.binary_sensor import IrmKmiWarning
|
from custom_components.irm_kmi.binary_sensor import IrmKmiWarning
|
||||||
from custom_components.irm_kmi.const import CONF_LANGUAGE_OVERRIDE
|
from custom_components.irm_kmi.const import CONF_LANGUAGE_OVERRIDE
|
||||||
from custom_components.irm_kmi.sensor import IrmKmiNextWarning
|
from custom_components.irm_kmi.sensor import IrmKmiNextWarning, IrmKmiNextSunMove
|
||||||
from tests.conftest import get_api_data
|
from tests.conftest import get_api_data
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,3 +126,43 @@ async def test_next_warning_none_when_no_warnings(
|
||||||
assert len(warning.extra_state_attributes['next_warnings']) == 0
|
assert len(warning.extra_state_attributes['next_warnings']) == 0
|
||||||
|
|
||||||
assert warning.extra_state_attributes['next_warnings_friendly_names'] == ""
|
assert warning.extra_state_attributes['next_warnings_friendly_names'] == ""
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time(datetime.fromisoformat('2023-12-26T18:30:00+01:00'))
|
||||||
|
async def test_next_sunrise_sunset(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry
|
||||||
|
) -> None:
|
||||||
|
api_data = get_api_data("forecast.json")
|
||||||
|
|
||||||
|
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
|
||||||
|
|
||||||
|
result = await coordinator.daily_list_to_forecast(api_data.get('for', {}).get('daily'))
|
||||||
|
|
||||||
|
coordinator.data = {'daily_forecast': result}
|
||||||
|
|
||||||
|
sunset = IrmKmiNextSunMove(coordinator, mock_config_entry, 'sunset')
|
||||||
|
sunrise = IrmKmiNextSunMove(coordinator, mock_config_entry, 'sunrise')
|
||||||
|
|
||||||
|
assert datetime.fromisoformat(sunrise.state) == datetime.fromisoformat('2023-12-27T08:44:00+01:00')
|
||||||
|
assert datetime.fromisoformat(sunset.state) == datetime.fromisoformat('2023-12-27T16:43:00+01:00')
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time(datetime.fromisoformat('2023-12-26T15:30:00+01:00'))
|
||||||
|
async def test_next_sunrise_sunset_bis(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry
|
||||||
|
) -> None:
|
||||||
|
api_data = get_api_data("forecast.json")
|
||||||
|
|
||||||
|
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
|
||||||
|
|
||||||
|
result = await coordinator.daily_list_to_forecast(api_data.get('for', {}).get('daily'))
|
||||||
|
|
||||||
|
coordinator.data = {'daily_forecast': result}
|
||||||
|
|
||||||
|
sunset = IrmKmiNextSunMove(coordinator, mock_config_entry, 'sunset')
|
||||||
|
sunrise = IrmKmiNextSunMove(coordinator, mock_config_entry, 'sunrise')
|
||||||
|
|
||||||
|
assert datetime.fromisoformat(sunrise.state) == datetime.fromisoformat('2023-12-27T08:44:00+01:00')
|
||||||
|
assert datetime.fromisoformat(sunset.state) == datetime.fromisoformat('2023-12-26T16:42:00+01:00')
|
Loading…
Add table
Reference in a new issue