mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 17:49:37 +01:00
Add initial_color property to CalendarEntity (#145606)
Co-authored-by: Allen Porter <allen.porter@gmail.com>
This commit is contained in:
@@ -32,7 +32,7 @@ from homeassistant.core import (
|
||||
callback,
|
||||
)
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers.entity import Entity, EntityDescription
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.event import async_track_point_in_time
|
||||
@@ -516,6 +516,26 @@ class CalendarEntity(Entity):
|
||||
|
||||
_alarm_unsubs: list[CALLBACK_TYPE] | None = None
|
||||
|
||||
_attr_initial_color: str | None = None
|
||||
|
||||
@property
|
||||
def initial_color(self) -> str | None:
|
||||
"""Return the initial color for the calendar entity."""
|
||||
return self._attr_initial_color
|
||||
|
||||
def get_initial_entity_options(self) -> er.EntityOptionsType | None:
|
||||
"""Return initial entity options."""
|
||||
if self.initial_color is None:
|
||||
return None
|
||||
|
||||
# Validate that it's a valid hex color string with # prefix
|
||||
try:
|
||||
validated_color = cv.color_hex(self.initial_color)
|
||||
except vol.Invalid:
|
||||
return None
|
||||
|
||||
return {DOMAIN: {"color": validated_color}}
|
||||
|
||||
@property
|
||||
def event(self) -> CalendarEvent | None:
|
||||
"""Return the next upcoming event."""
|
||||
@@ -533,8 +553,8 @@ class CalendarEntity(Entity):
|
||||
"all_day": event.all_day,
|
||||
"start_time": event.start_datetime_local.strftime(DATE_STR_FORMAT),
|
||||
"end_time": event.end_datetime_local.strftime(DATE_STR_FORMAT),
|
||||
"location": event.location if event.location else "",
|
||||
"description": event.description if event.description else "",
|
||||
"location": event.location or "",
|
||||
"description": event.description or "",
|
||||
}
|
||||
|
||||
@final
|
||||
|
||||
@@ -48,11 +48,13 @@ class MockCalendarEntity(CalendarEntity):
|
||||
self,
|
||||
name: str,
|
||||
events: list[CalendarEvent] | None = None,
|
||||
initial_color: str | None = None,
|
||||
unique_id: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize entity."""
|
||||
self._attr_name = name.capitalize()
|
||||
self._events = events or []
|
||||
self._attr_initial_color = initial_color
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
@property
|
||||
@@ -206,4 +208,9 @@ def create_test_entities() -> list[MockCalendarEntity]:
|
||||
)
|
||||
entity2.async_get_events = AsyncMock(wraps=entity2.async_get_events)
|
||||
|
||||
return [entity1, entity2]
|
||||
entity3 = MockCalendarEntity(
|
||||
"Calendar 3", [], initial_color="#FF0000", unique_id="calendar_3"
|
||||
)
|
||||
entity3.async_get_events = AsyncMock(wraps=entity3.async_get_events)
|
||||
|
||||
return [entity1, entity2, entity3]
|
||||
|
||||
@@ -16,6 +16,7 @@ import voluptuous as vol
|
||||
from homeassistant.components.calendar import DOMAIN, SERVICE_GET_EVENTS
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceNotSupported
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
@@ -123,6 +124,7 @@ async def test_calendars_http_api(
|
||||
assert data == [
|
||||
{"entity_id": "calendar.calendar_1", "name": "Calendar 1"},
|
||||
{"entity_id": "calendar.calendar_2", "name": "Calendar 2"},
|
||||
{"entity_id": "calendar.calendar_3", "name": "Calendar 3"},
|
||||
]
|
||||
|
||||
|
||||
@@ -604,3 +606,54 @@ async def test_list_events_service_same_dates(
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
|
||||
|
||||
async def test_calendar_initial_color_valid(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
test_entities: list[MockCalendarEntity],
|
||||
) -> None:
|
||||
"""Test that initial_color creates initial entity options."""
|
||||
# Entity 3 was created with an initial_color
|
||||
entity = test_entities[2]
|
||||
|
||||
# Check that entity registry was populated with the initial_color
|
||||
entry = entity_registry.async_get(entity.entity_id)
|
||||
assert entry is not None
|
||||
assert entry.options.get(DOMAIN, {}).get("color") == "#FF0000"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_initial_color",
|
||||
[
|
||||
"FF0000", # Missing #
|
||||
"#FF00", # Too short
|
||||
"#FF00000", # Too long
|
||||
"#GGGGGG", # Invalid hex
|
||||
"red", # Not hex
|
||||
"", # Empty
|
||||
],
|
||||
)
|
||||
async def test_calendar_initial_color_invalid(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
invalid_initial_color: str,
|
||||
) -> None:
|
||||
"""Test that invalid initial_color is ignored."""
|
||||
entity = MockCalendarEntity(
|
||||
"Invalid Color Test",
|
||||
[],
|
||||
initial_color=invalid_initial_color,
|
||||
unique_id=f"test_{invalid_initial_color}",
|
||||
)
|
||||
assert entity.get_initial_entity_options() is None
|
||||
|
||||
|
||||
async def test_calendar_initial_color_none(
|
||||
hass: HomeAssistant,
|
||||
test_entities: list[MockCalendarEntity],
|
||||
) -> None:
|
||||
"""Test that entities without initial_color return None."""
|
||||
# Entities 1 and 2 were created without an initial_color
|
||||
entity = test_entities[0]
|
||||
assert entity.get_initial_entity_options() is None
|
||||
|
||||
@@ -705,7 +705,7 @@ async def test_legacy_entity_type(
|
||||
"action": TEST_AUTOMATION_ACTION,
|
||||
"trigger": {
|
||||
"platform": calendar.DOMAIN,
|
||||
"entity_id": "calendar.calendar_3",
|
||||
"entity_id": "calendar.calendar_4",
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user