diff --git a/homeassistant/components/demo/__init__.py b/homeassistant/components/demo/__init__.py index 6fa7e0d973b..738f6af38dd 100644 --- a/homeassistant/components/demo/__init__.py +++ b/homeassistant/components/demo/__init__.py @@ -38,6 +38,7 @@ COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM = [ Platform.LIGHT, Platform.LOCK, Platform.MEDIA_PLAYER, + Platform.NOTIFY, Platform.NUMBER, Platform.SELECT, Platform.SENSOR, @@ -55,7 +56,6 @@ COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM = [ COMPONENTS_WITH_DEMO_PLATFORM = [ Platform.TTS, Platform.MAILBOX, - Platform.NOTIFY, Platform.IMAGE_PROCESSING, Platform.DEVICE_TRACKER, ] diff --git a/homeassistant/components/demo/notify.py b/homeassistant/components/demo/notify.py index c6a9483b328..94999d26d10 100644 --- a/homeassistant/components/demo/notify.py +++ b/homeassistant/components/demo/notify.py @@ -1,38 +1,44 @@ -"""Demo notification service.""" +"""Demo notification entity.""" from __future__ import annotations -from typing import Any - -from homeassistant.components.notify import BaseNotificationService +from homeassistant.components.notify import DOMAIN, NotifyEntity +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback EVENT_NOTIFY = "notify" -def get_service( +async def async_setup_entry( hass: HomeAssistant, - config: ConfigType, - discovery_info: DiscoveryInfoType | None = None, -) -> BaseNotificationService: - """Get the demo notification service.""" - return DemoNotificationService(hass) + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up the demo entity platform.""" + async_add_entities([DemoNotifyEntity(unique_id="notify", device_name="Notifier")]) -class DemoNotificationService(BaseNotificationService): - """Implement demo notification service.""" +class DemoNotifyEntity(NotifyEntity): + """Implement demo notification platform.""" - def __init__(self, hass: HomeAssistant) -> None: - """Initialize the service.""" - self.hass = hass + _attr_has_entity_name = True + _attr_name = None - @property - def targets(self) -> dict[str, str]: - """Return a dictionary of registered targets.""" - return {"test target name": "test target id"} + def __init__( + self, + unique_id: str, + device_name: str, + ) -> None: + """Initialize the Demo button entity.""" + self._attr_unique_id = unique_id + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, unique_id)}, + name=device_name, + ) - def send_message(self, message: str = "", **kwargs: Any) -> None: + async def async_send_message(self, message: str) -> None: """Send a message to a user.""" - kwargs["message"] = message - self.hass.bus.fire(EVENT_NOTIFY, kwargs) + event_notitifcation = {"message": message} + self.hass.bus.async_fire(EVENT_NOTIFY, event_notitifcation) diff --git a/tests/components/demo/test_notify.py b/tests/components/demo/test_notify.py index 0bc7a8bc1d8..b0536873d66 100644 --- a/tests/components/demo/test_notify.py +++ b/tests/components/demo/test_notify.py @@ -1,29 +1,43 @@ """The tests for the notify demo platform.""" -import logging +from collections.abc import Generator from unittest.mock import patch import pytest -import voluptuous as vol from homeassistant.components import notify +from homeassistant.components.demo import DOMAIN import homeassistant.components.demo.notify as demo -from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers import discovery +from homeassistant.const import Platform +from homeassistant.core import Event, HomeAssistant, callback from homeassistant.setup import async_setup_component -from tests.common import assert_setup_component, async_capture_events - -CONFIG = {notify.DOMAIN: {"platform": "demo"}} - - -@pytest.fixture(autouse=True) -def autouse_disable_platforms(disable_platforms): - """Auto use the disable_platforms fixture.""" +from tests.common import MockConfigEntry, async_capture_events @pytest.fixture -def events(hass): +def notify_only() -> Generator[None, None]: + """Enable only the notify platform.""" + with patch( + "homeassistant.components.demo.COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM", + [Platform.NOTIFY], + ): + yield + + +@pytest.fixture(autouse=True) +async def setup_notify(hass: HomeAssistant, notify_only: None) -> None: + """Initialize setup demo Notify entity.""" + entry = MockConfigEntry(domain=DOMAIN) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + state = hass.states.get("notify.notifier") + assert state is not None + + +@pytest.fixture +def events(hass: HomeAssistant) -> list[Event]: """Fixture that catches notify events.""" return async_capture_events(hass, demo.EVENT_NOTIFY) @@ -46,104 +60,26 @@ def record_calls(calls): return record_calls -@pytest.fixture(name="mock_demo_notify") -def mock_demo_notify_fixture(): - """Mock demo notify service.""" - with patch("homeassistant.components.demo.notify.get_service", autospec=True) as ns: - yield ns - - -async def setup_notify(hass): - """Test setup.""" - with assert_setup_component(1, notify.DOMAIN) as config: - assert await async_setup_component(hass, notify.DOMAIN, CONFIG) - assert config[notify.DOMAIN] - await hass.async_block_till_done() - - -async def test_no_notify_service( - hass: HomeAssistant, mock_demo_notify, caplog: pytest.LogCaptureFixture -) -> None: - """Test missing platform notify service instance.""" - caplog.set_level(logging.ERROR) - mock_demo_notify.return_value = None - await setup_notify(hass) - await hass.async_block_till_done() - assert mock_demo_notify.called - assert "Failed to initialize notification service demo" in caplog.text - - -async def test_discover_notify(hass: HomeAssistant, mock_demo_notify) -> None: - """Test discovery of notify demo platform.""" - assert notify.DOMAIN not in hass.config.components - mock_demo_notify.return_value = None - await discovery.async_load_platform( - hass, "notify", "demo", {"test_key": "test_val"}, {"notify": {}} - ) - await hass.async_block_till_done() - assert notify.DOMAIN in hass.config.components - assert mock_demo_notify.called - assert mock_demo_notify.mock_calls[0][1] == ( - hass, - {}, - {"test_key": "test_val"}, - ) - - -async def test_sending_none_message(hass: HomeAssistant, events) -> None: - """Test send with None as message.""" - await setup_notify(hass) - with pytest.raises(vol.Invalid): - await hass.services.async_call( - notify.DOMAIN, notify.SERVICE_NOTIFY, {notify.ATTR_MESSAGE: None} - ) - await hass.async_block_till_done() - assert len(events) == 0 - - -async def test_sending_templated_message(hass: HomeAssistant, events) -> None: - """Send a templated message.""" - await setup_notify(hass) - hass.states.async_set("sensor.temperature", 10) +async def test_sending_message(hass: HomeAssistant, events: list[Event]) -> None: + """Test sending a message.""" data = { - notify.ATTR_MESSAGE: "{{states.sensor.temperature.state}}", - notify.ATTR_TITLE: "{{ states.sensor.temperature.name }}", + "entity_id": "notify.notifier", + notify.ATTR_MESSAGE: "Test message", } - await hass.services.async_call(notify.DOMAIN, notify.SERVICE_NOTIFY, data) + await hass.services.async_call(notify.DOMAIN, notify.SERVICE_SEND_MESSAGE, data) await hass.async_block_till_done() last_event = events[-1] - assert last_event.data[notify.ATTR_TITLE] == "temperature" - assert last_event.data[notify.ATTR_MESSAGE] == "10" + assert last_event.data[notify.ATTR_MESSAGE] == "Test message" -async def test_method_forwards_correct_data(hass: HomeAssistant, events) -> None: - """Test that all data from the service gets forwarded to service.""" - await setup_notify(hass) - data = { - notify.ATTR_MESSAGE: "my message", - notify.ATTR_TITLE: "my title", - notify.ATTR_DATA: {"hello": "world"}, - } - await hass.services.async_call(notify.DOMAIN, notify.SERVICE_NOTIFY, data) - await hass.async_block_till_done() - assert len(events) == 1 - data = events[0].data - assert { - "message": "my message", - "title": "my title", - "data": {"hello": "world"}, - } == data - - -async def test_calling_notify_from_script_loaded_from_yaml_without_title( - hass: HomeAssistant, events +async def test_calling_notify_from_script_loaded_from_yaml( + hass: HomeAssistant, events: list[Event] ) -> None: """Test if we can call a notify from a script.""" - await setup_notify(hass) step = { - "service": "notify.notify", + "service": "notify.send_message", "data": { - "data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}} + "entity_id": "notify.notifier", }, "data_template": {"message": "Test 123 {{ 2 + 2 }}\n"}, } @@ -155,63 +91,4 @@ async def test_calling_notify_from_script_loaded_from_yaml_without_title( assert len(events) == 1 assert { "message": "Test 123 4", - "data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}}, } == events[0].data - - -async def test_calling_notify_from_script_loaded_from_yaml_with_title( - hass: HomeAssistant, events -) -> None: - """Test if we can call a notify from a script.""" - await setup_notify(hass) - step = { - "service": "notify.notify", - "data": { - "data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}} - }, - "data_template": {"message": "Test 123 {{ 2 + 2 }}\n", "title": "Test"}, - } - await async_setup_component( - hass, "script", {"script": {"test": {"sequence": step}}} - ) - await hass.services.async_call("script", "test") - await hass.async_block_till_done() - assert len(events) == 1 - assert { - "message": "Test 123 4", - "title": "Test", - "data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}}, - } == events[0].data - - -async def test_targets_are_services(hass: HomeAssistant) -> None: - """Test that all targets are exposed as individual services.""" - await setup_notify(hass) - assert hass.services.has_service("notify", "demo") is not None - service = "demo_test_target_name" - assert hass.services.has_service("notify", service) is not None - - -async def test_messages_to_targets_route( - hass: HomeAssistant, calls, record_calls -) -> None: - """Test message routing to specific target services.""" - await setup_notify(hass) - hass.bus.async_listen_once("notify", record_calls) - - await hass.services.async_call( - "notify", - "demo_test_target_name", - {"message": "my message", "title": "my title", "data": {"hello": "world"}}, - ) - - await hass.async_block_till_done() - - data = calls[0][0].data - - assert { - "message": "my message", - "target": ["test target id"], - "title": "my title", - "data": {"hello": "world"}, - } == data