Skip to content

Commit 57568fd

Browse files
authored
Add standard event type for doorbell event entities (#167630)
1 parent 4c8a660 commit 57568fd

4 files changed

Lines changed: 100 additions & 2 deletions

File tree

homeassistant/components/event/__init__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from homeassistant.util import dt as dt_util
2121
from homeassistant.util.hass_dict import HassKey
2222

23-
from .const import ATTR_EVENT_TYPE, ATTR_EVENT_TYPES, DOMAIN
23+
from .const import ATTR_EVENT_TYPE, ATTR_EVENT_TYPES, DOMAIN, DoorbellEventType
2424

2525
_LOGGER = logging.getLogger(__name__)
2626
DATA_COMPONENT: HassKey[EntityComponent[EventEntity]] = HassKey(DOMAIN)
@@ -44,6 +44,7 @@ class EventDeviceClass(StrEnum):
4444
"DOMAIN",
4545
"PLATFORM_SCHEMA",
4646
"PLATFORM_SCHEMA_BASE",
47+
"DoorbellEventType",
4748
"EventDeviceClass",
4849
"EventEntity",
4950
"EventEntityDescription",
@@ -189,6 +190,21 @@ def state_attributes(self) -> dict[str, Any]:
189190
async def async_internal_added_to_hass(self) -> None:
190191
"""Call when the event entity is added to hass."""
191192
await super().async_internal_added_to_hass()
193+
194+
if (
195+
self.device_class == EventDeviceClass.DOORBELL
196+
and DoorbellEventType.RING not in self.event_types
197+
):
198+
report_issue = self._suggest_report_issue()
199+
_LOGGER.warning(
200+
"Entity %s is a doorbell event entity but does not support "
201+
"the '%s' event type. This will stop working in "
202+
"Home Assistant 2027.4, please %s",
203+
self.entity_id,
204+
DoorbellEventType.RING,
205+
report_issue,
206+
)
207+
192208
if (
193209
(state := await self.async_get_last_state())
194210
and state.state is not None
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
"""Provides the constants needed for the component."""
22

3+
from enum import StrEnum
4+
35
DOMAIN = "event"
46
ATTR_EVENT_TYPE = "event_type"
57
ATTR_EVENT_TYPES = "event_types"
8+
9+
10+
class DoorbellEventType(StrEnum):
11+
"""Standard event types for doorbell device class."""
12+
13+
RING = "ring"

homeassistant/components/event/strings.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@
1515
"name": "Button"
1616
},
1717
"doorbell": {
18-
"name": "Doorbell"
18+
"name": "Doorbell",
19+
"state_attributes": {
20+
"event_type": {
21+
"state": {
22+
"ring": "Ring"
23+
}
24+
}
25+
}
1926
},
2027
"motion": {
2128
"name": "Motion"

tests/components/event/test_init.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
ATTR_EVENT_TYPE,
1111
ATTR_EVENT_TYPES,
1212
DOMAIN,
13+
DoorbellEventType,
1314
EventDeviceClass,
1415
EventEntity,
1516
EventEntityDescription,
@@ -34,6 +35,7 @@
3435
mock_platform,
3536
mock_restore_cache,
3637
mock_restore_cache_with_extra_data,
38+
setup_test_component_platform,
3739
)
3840

3941

@@ -344,3 +346,68 @@ async def async_setup_entry_platform(
344346
"device_class": "doorbell",
345347
"friendly_name": "Doorbell",
346348
}
349+
350+
351+
@pytest.mark.usefixtures("config_flow_fixture")
352+
async def test_doorbell_missing_ring_event_type(
353+
hass: HomeAssistant,
354+
caplog: pytest.LogCaptureFixture,
355+
) -> None:
356+
"""Test warning when a doorbell entity does not include the standard ring event type."""
357+
358+
async def async_setup_entry_init(
359+
hass: HomeAssistant, config_entry: ConfigEntry
360+
) -> bool:
361+
"""Set up test config entry."""
362+
await hass.config_entries.async_forward_entry_setups(
363+
config_entry, [Platform.EVENT]
364+
)
365+
return True
366+
367+
mock_platform(hass, f"{TEST_DOMAIN}.config_flow")
368+
mock_integration(
369+
hass,
370+
MockModule(
371+
TEST_DOMAIN,
372+
async_setup_entry=async_setup_entry_init,
373+
),
374+
)
375+
376+
# Doorbell entity WITHOUT the standard "ring" event type
377+
entity_without_ring = EventEntity()
378+
entity_without_ring._attr_event_types = ["ding"]
379+
entity_without_ring._attr_device_class = EventDeviceClass.DOORBELL
380+
entity_without_ring._attr_has_entity_name = True
381+
entity_without_ring.entity_id = "event.doorbell_without_ring"
382+
383+
# Doorbell entity WITH the standard "ring" event type
384+
entity_with_ring = EventEntity()
385+
entity_with_ring._attr_event_types = [DoorbellEventType.RING, "ding"]
386+
entity_with_ring._attr_device_class = EventDeviceClass.DOORBELL
387+
entity_with_ring._attr_has_entity_name = True
388+
entity_with_ring.entity_id = "event.doorbell_with_ring"
389+
390+
# Non-doorbell entity should not warn
391+
entity_button = EventEntity()
392+
entity_button._attr_event_types = ["press"]
393+
entity_button._attr_device_class = EventDeviceClass.BUTTON
394+
entity_button._attr_has_entity_name = True
395+
entity_button.entity_id = "event.button"
396+
397+
setup_test_component_platform(
398+
hass,
399+
DOMAIN,
400+
[entity_without_ring, entity_with_ring, entity_button],
401+
from_config_entry=True,
402+
)
403+
config_entry = MockConfigEntry(domain=TEST_DOMAIN)
404+
config_entry.add_to_hass(hass)
405+
assert await hass.config_entries.async_setup(config_entry.entry_id)
406+
await hass.async_block_till_done()
407+
408+
assert (
409+
"Entity event.doorbell_without_ring is a doorbell event entity "
410+
"but does not support the 'ring' event type"
411+
) in caplog.text
412+
assert "event.doorbell_with_ring" not in caplog.text
413+
assert "event.button" not in caplog.text

0 commit comments

Comments
 (0)