mirror of
https://github.com/home-assistant/core.git
synced 2025-09-06 21:31:34 +02:00
Add calendar to Workday
This commit is contained in:
98
homeassistant/components/workday/calendar.py
Normal file
98
homeassistant/components/workday/calendar.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
"""Workday Calendar."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from holidays import HolidayBase
|
||||||
|
|
||||||
|
from homeassistant.components.calendar import CalendarEntity, CalendarEvent
|
||||||
|
from homeassistant.const import CONF_NAME
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
|
||||||
|
from . import WorkdayConfigEntry
|
||||||
|
from .const import CONF_EXCLUDES, CONF_OFFSET, CONF_WORKDAYS
|
||||||
|
from .entity import BaseWorkdayEntity
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: WorkdayConfigEntry,
|
||||||
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the Holiday Calendar config entry."""
|
||||||
|
days_offset: int = int(entry.options[CONF_OFFSET])
|
||||||
|
excludes: list[str] = entry.options[CONF_EXCLUDES]
|
||||||
|
sensor_name: str = entry.options[CONF_NAME]
|
||||||
|
workdays: list[str] = entry.options[CONF_WORKDAYS]
|
||||||
|
obj_holidays = entry.runtime_data
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
WorkdayCalendarEntity(
|
||||||
|
obj_holidays,
|
||||||
|
workdays,
|
||||||
|
excludes,
|
||||||
|
days_offset,
|
||||||
|
sensor_name,
|
||||||
|
entry.entry_id,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WorkdayCalendarEntity(BaseWorkdayEntity, CalendarEntity):
|
||||||
|
"""Representation of a Wokrday Calendar."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
obj_holidays: HolidayBase,
|
||||||
|
workdays: list[str],
|
||||||
|
excludes: list[str],
|
||||||
|
days_offset: int,
|
||||||
|
name: str,
|
||||||
|
entry_id: str,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize WorkdayCalendarEntity."""
|
||||||
|
super().__init__(
|
||||||
|
obj_holidays,
|
||||||
|
workdays,
|
||||||
|
excludes,
|
||||||
|
days_offset,
|
||||||
|
name,
|
||||||
|
entry_id,
|
||||||
|
)
|
||||||
|
self._attr_unique_id = f"{entry_id}-calender"
|
||||||
|
self._attr_event = None
|
||||||
|
self.event_list: list[CalendarEvent] = []
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def update_data(self, now: datetime) -> None:
|
||||||
|
"""Update data."""
|
||||||
|
event_list = []
|
||||||
|
for i in range(365):
|
||||||
|
future_date = now.date() + timedelta(days=i)
|
||||||
|
if self.date_is_workday(future_date):
|
||||||
|
event = CalendarEvent(
|
||||||
|
summary=self._name,
|
||||||
|
start=future_date,
|
||||||
|
end=future_date,
|
||||||
|
)
|
||||||
|
event_list.append(event)
|
||||||
|
self.event_list = event_list
|
||||||
|
|
||||||
|
@property
|
||||||
|
def event(self) -> CalendarEvent | None:
|
||||||
|
"""Return the next upcoming event."""
|
||||||
|
return (
|
||||||
|
sorted(self.event_list, key=lambda e: e.start)[0]
|
||||||
|
if self.event_list
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_get_events(
|
||||||
|
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
|
||||||
|
) -> list[CalendarEvent]:
|
||||||
|
"""Get all events in a specific time frame."""
|
||||||
|
return self.event_list
|
@@ -11,7 +11,7 @@ LOGGER = logging.getLogger(__package__)
|
|||||||
ALLOWED_DAYS = [*WEEKDAYS, "holiday"]
|
ALLOWED_DAYS = [*WEEKDAYS, "holiday"]
|
||||||
|
|
||||||
DOMAIN = "workday"
|
DOMAIN = "workday"
|
||||||
PLATFORMS = [Platform.BINARY_SENSOR]
|
PLATFORMS = [Platform.BINARY_SENSOR, Platform.CALENDAR]
|
||||||
|
|
||||||
CONF_PROVINCE = "province"
|
CONF_PROVINCE = "province"
|
||||||
CONF_WORKDAYS = "workdays"
|
CONF_WORKDAYS = "workdays"
|
||||||
|
@@ -212,6 +212,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"calendar": {
|
||||||
|
"workday": {
|
||||||
|
"name": "[%key:component::calendar::title%]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
79
tests/components/workday/test_calendar.py
Normal file
79
tests/components/workday/test_calendar.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"""Tests for calendar platform of Workday integration."""
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.calendar import (
|
||||||
|
DOMAIN as CALENDAR_DOMAIN,
|
||||||
|
SERVICE_GET_EVENTS,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
|
from . import TEST_CONFIG_WITH_PROVINCE, init_integration
|
||||||
|
|
||||||
|
from tests.common import async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"time_zone", ["Asia/Tokyo", "Europe/Berlin", "America/Chicago", "US/Hawaii"]
|
||||||
|
)
|
||||||
|
async def test_holiday_calendar_entity(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
time_zone: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test HolidayCalendarEntity functionality."""
|
||||||
|
await hass.config.async_set_time_zone(time_zone)
|
||||||
|
zone = await dt_util.async_get_time_zone(time_zone)
|
||||||
|
freezer.move_to(datetime(2023, 1, 1, 0, 1, 1, tzinfo=zone)) # New Years Day
|
||||||
|
await init_integration(hass, TEST_CONFIG_WITH_PROVINCE)
|
||||||
|
|
||||||
|
await async_setup_component(hass, "calendar", {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
response = await hass.services.async_call(
|
||||||
|
CALENDAR_DOMAIN,
|
||||||
|
SERVICE_GET_EVENTS,
|
||||||
|
{
|
||||||
|
"entity_id": "calendar.workday_sensor_calendar",
|
||||||
|
"end_date_time": dt_util.now() + timedelta(hours=1),
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
assert {
|
||||||
|
"end": "2023-01-01",
|
||||||
|
"start": "2023-01-02",
|
||||||
|
"summary": "Workday Sensor",
|
||||||
|
} not in response["calendar.workday_sensor_calendar"]["events"]
|
||||||
|
assert {
|
||||||
|
"end": "2023-01-04",
|
||||||
|
"start": "2023-01-03",
|
||||||
|
"summary": "Workday Sensor",
|
||||||
|
} in response["calendar.workday_sensor_calendar"]["events"]
|
||||||
|
|
||||||
|
state = hass.states.get("calendar.workday_sensor_calendar")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
freezer.move_to(
|
||||||
|
datetime(2023, 1, 2, 0, 1, 1, tzinfo=zone)
|
||||||
|
) # Day after New Years Day
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("calendar.workday_sensor_calendar")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
freezer.move_to(datetime(2023, 1, 7, 0, 1, 1, tzinfo=zone)) # Workday
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("calendar.workday_sensor_calendar")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == "off"
|
Reference in New Issue
Block a user