Workday only update once a day (#116419)

* Workday only update once a day

* Fix tests
This commit is contained in:
G Johansson 2024-05-01 17:11:47 +02:00 committed by GitHub
parent b7a138b02a
commit 51f9e661a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 62 additions and 20 deletions

View file

@ -2,7 +2,7 @@
from __future__ import annotations from __future__ import annotations
from datetime import date, timedelta from datetime import date, datetime, timedelta
from typing import Final from typing import Final
from holidays import ( from holidays import (
@ -15,13 +15,20 @@ import voluptuous as vol
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_COUNTRY, CONF_LANGUAGE, CONF_NAME from homeassistant.const import CONF_COUNTRY, CONF_LANGUAGE, CONF_NAME
from homeassistant.core import HomeAssistant, ServiceResponse, SupportsResponse from homeassistant.core import (
CALLBACK_TYPE,
HomeAssistant,
ServiceResponse,
SupportsResponse,
callback,
)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import ( from homeassistant.helpers.entity_platform import (
AddEntitiesCallback, AddEntitiesCallback,
async_get_current_platform, async_get_current_platform,
) )
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.util import dt as dt_util, slugify from homeassistant.util import dt as dt_util, slugify
@ -201,6 +208,8 @@ class IsWorkdaySensor(BinarySensorEntity):
_attr_has_entity_name = True _attr_has_entity_name = True
_attr_name = None _attr_name = None
_attr_translation_key = DOMAIN _attr_translation_key = DOMAIN
_attr_should_poll = False
unsub: CALLBACK_TYPE | None = None
def __init__( def __init__(
self, self,
@ -248,11 +257,34 @@ class IsWorkdaySensor(BinarySensorEntity):
return False return False
async def async_update(self) -> None: def get_next_interval(self, now: datetime) -> datetime:
"""Get date and look whether it is a holiday.""" """Compute next time an update should occur."""
self._attr_is_on = self.date_is_workday(dt_util.now()) tomorrow = dt_util.as_local(now) + timedelta(days=1)
return dt_util.start_of_local_day(tomorrow)
async def check_date(self, check_date: date) -> ServiceResponse: def _update_state_and_setup_listener(self) -> None:
"""Update state and setup listener for next interval."""
now = dt_util.utcnow()
self.update_data(now)
self.unsub = async_track_point_in_utc_time(
self.hass, self.point_in_time_listener, self.get_next_interval(now)
)
@callback
def point_in_time_listener(self, time_date: datetime) -> None:
"""Get the latest data and update state."""
self._update_state_and_setup_listener()
self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""Set up first update."""
self._update_state_and_setup_listener()
def update_data(self, now: datetime) -> None:
"""Get date and look whether it is a holiday."""
self._attr_is_on = self.date_is_workday(now)
def check_date(self, check_date: date) -> ServiceResponse:
"""Service to check if date is workday or not.""" """Service to check if date is workday or not."""
return {"workday": self.date_is_workday(check_date)} return {"workday": self.date_is_workday(check_date)}

View file

@ -1,6 +1,6 @@
"""Tests the Home Assistant workday binary sensor.""" """Tests the Home Assistant workday binary sensor."""
from datetime import date, datetime from datetime import date, datetime, timedelta
from typing import Any from typing import Any
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
@ -41,31 +41,34 @@ from . import (
init_integration, init_integration,
) )
from tests.common import async_fire_time_changed
@pytest.mark.parametrize( @pytest.mark.parametrize(
("config", "expected_state"), ("config", "expected_state", "expected_state_weekend"),
[ [
(TEST_CONFIG_NO_COUNTRY, "on"), (TEST_CONFIG_NO_COUNTRY, "on", "off"),
(TEST_CONFIG_WITH_PROVINCE, "off"), (TEST_CONFIG_WITH_PROVINCE, "off", "off"),
(TEST_CONFIG_NO_PROVINCE, "off"), (TEST_CONFIG_NO_PROVINCE, "off", "off"),
(TEST_CONFIG_WITH_STATE, "on"), (TEST_CONFIG_WITH_STATE, "on", "off"),
(TEST_CONFIG_NO_STATE, "on"), (TEST_CONFIG_NO_STATE, "on", "off"),
(TEST_CONFIG_EXAMPLE_1, "on"), (TEST_CONFIG_EXAMPLE_1, "on", "off"),
(TEST_CONFIG_EXAMPLE_2, "off"), (TEST_CONFIG_EXAMPLE_2, "off", "off"),
(TEST_CONFIG_TOMORROW, "off"), (TEST_CONFIG_TOMORROW, "off", "off"),
(TEST_CONFIG_DAY_AFTER_TOMORROW, "off"), (TEST_CONFIG_DAY_AFTER_TOMORROW, "off", "off"),
(TEST_CONFIG_YESTERDAY, "on"), (TEST_CONFIG_YESTERDAY, "on", "off"), # Friday was good Friday
(TEST_CONFIG_NO_LANGUAGE_CONFIGURED, "off"), (TEST_CONFIG_NO_LANGUAGE_CONFIGURED, "off", "off"),
], ],
) )
async def test_setup( async def test_setup(
hass: HomeAssistant, hass: HomeAssistant,
config: dict[str, Any], config: dict[str, Any],
expected_state: str, expected_state: str,
expected_state_weekend: str,
freezer: FrozenDateTimeFactory, freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test setup from various configs.""" """Test setup from various configs."""
freezer.move_to(datetime(2022, 4, 15, 12, tzinfo=UTC)) # Monday freezer.move_to(datetime(2022, 4, 15, 12, tzinfo=UTC)) # Friday
await init_integration(hass, config) await init_integration(hass, config)
state = hass.states.get("binary_sensor.workday_sensor") state = hass.states.get("binary_sensor.workday_sensor")
@ -78,6 +81,13 @@ async def test_setup(
"days_offset": config["days_offset"], "days_offset": config["days_offset"],
} }
freezer.tick(timedelta(days=1)) # Saturday
async_fire_time_changed(hass)
state = hass.states.get("binary_sensor.workday_sensor")
assert state is not None
assert state.state == expected_state_weekend
async def test_setup_with_invalid_province_from_yaml(hass: HomeAssistant) -> None: async def test_setup_with_invalid_province_from_yaml(hass: HomeAssistant) -> None:
"""Test setup invalid province with import.""" """Test setup invalid province with import."""