From c6781650a055c6afae1f770b2bc8e2f8e167de54 Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 5 May 2024 17:58:09 +0000 Subject: [PATCH 1/7] Migrate tibber notify service --- homeassistant/components/tibber/__init__.py | 2 +- homeassistant/components/tibber/notify.py | 34 ++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tibber/__init__.py b/homeassistant/components/tibber/__init__.py index 7305cf835c554..58f7350155b3f 100644 --- a/homeassistant/components/tibber/__init__.py +++ b/homeassistant/components/tibber/__init__.py @@ -22,7 +22,7 @@ from .const import DATA_HASS_CONFIG, DOMAIN -PLATFORMS = [Platform.SENSOR] +PLATFORMS = [Platform.NOTIFY, Platform.SENSOR] CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False) diff --git a/homeassistant/components/tibber/notify.py b/homeassistant/components/tibber/notify.py index b0816de39e277..0c3a3f1465ac0 100644 --- a/homeassistant/components/tibber/notify.py +++ b/homeassistant/components/tibber/notify.py @@ -6,12 +6,18 @@ import logging from typing import Any +from tibber import Tibber + from homeassistant.components.notify import ( ATTR_TITLE, ATTR_TITLE_DEFAULT, BaseNotificationService, + NotifyEntity, + NotifyEntityFeature, ) +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import DOMAIN as TIBBER_DOMAIN @@ -25,10 +31,17 @@ async def async_get_service( discovery_info: DiscoveryInfoType | None = None, ) -> TibberNotificationService: """Get the Tibber notification service.""" - tibber_connection = hass.data[TIBBER_DOMAIN] + tibber_connection: Tibber = hass.data[TIBBER_DOMAIN] return TibberNotificationService(tibber_connection.send_notification) +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up the Tibber notification entity.""" + async_add_entities([TibberNotificationEntity()]) + + class TibberNotificationService(BaseNotificationService): """Implement the notification service for Tibber.""" @@ -43,3 +56,22 @@ async def async_send_message(self, message: str = "", **kwargs: Any) -> None: await self._notify(title=title, message=message) except TimeoutError: _LOGGER.error("Timeout sending message with Tibber") + + +class TibberNotificationEntity(NotifyEntity): + """Implement the notification entity service for Tibber.""" + + _attr_supported_features = NotifyEntityFeature.TITLE + _attr_unique_id = f"{TIBBER_DOMAIN}_notify" + _attr_name = TIBBER_DOMAIN + _attr_icon = "mdi:message-flash" + + async def async_send_message(self, message: str, title: str | None = None) -> None: + """Send a message to Tibber devices.""" + tibber_connection: Tibber = self.hass.data[TIBBER_DOMAIN] + try: + await tibber_connection.send_notification( + title or ATTR_TITLE_DEFAULT, message + ) + except TimeoutError: + _LOGGER.error("Timeout sending message with Tibber") From 39fe01d68f94d249584479c21eca6ec22bc36feb Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 5 May 2024 22:20:57 +0000 Subject: [PATCH 2/7] Tests and repair flow --- .coveragerc | 1 - homeassistant/components/tibber/__init__.py | 6 +- homeassistant/components/tibber/manifest.json | 2 +- homeassistant/components/tibber/notify.py | 18 +++-- homeassistant/components/tibber/repairs.py | 37 ++++++++++ homeassistant/components/tibber/strings.json | 18 +++++ tests/components/tibber/conftest.py | 27 +++++++- tests/components/tibber/test_init.py | 17 +++++ tests/components/tibber/test_notify.py | 61 +++++++++++++++++ tests/components/tibber/test_repairs.py | 67 +++++++++++++++++++ 10 files changed, 242 insertions(+), 12 deletions(-) create mode 100644 homeassistant/components/tibber/repairs.py create mode 100644 tests/components/tibber/test_init.py create mode 100644 tests/components/tibber/test_notify.py create mode 100644 tests/components/tibber/test_repairs.py diff --git a/.coveragerc b/.coveragerc index 7986785d86e7a..076ab46d41fb5 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1440,7 +1440,6 @@ omit = homeassistant/components/thinkingcleaner/* homeassistant/components/thomson/device_tracker.py homeassistant/components/tibber/__init__.py - homeassistant/components/tibber/notify.py homeassistant/components/tibber/sensor.py homeassistant/components/tikteck/light.py homeassistant/components/tile/__init__.py diff --git a/homeassistant/components/tibber/__init__.py b/homeassistant/components/tibber/__init__.py index 58f7350155b3f..1de70389114c0 100644 --- a/homeassistant/components/tibber/__init__.py +++ b/homeassistant/components/tibber/__init__.py @@ -68,8 +68,9 @@ async def _close(event: Event) -> None: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - # set up notify platform, no entry support for notify component yet, - # have to use discovery to load platform. + # Use discovery to load platform legacy notify platform + # The use of the legacy notify service was deprecated with HA Core 2024.6 + # Support will be removed with HA Core 2024.12 hass.async_create_task( discovery.async_load_platform( hass, @@ -79,6 +80,7 @@ async def _close(event: Event) -> None: hass.data[DATA_HASS_CONFIG], ) ) + return True diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index 1d8120a4321e3..70ec49794851d 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -3,7 +3,7 @@ "name": "Tibber", "codeowners": ["@danielhiversen"], "config_flow": true, - "dependencies": ["recorder"], + "dependencies": ["recorder", "http", "repairs"], "documentation": "https://www.home-assistant.io/integrations/tibber", "iot_class": "cloud_polling", "loggers": ["tibber"], diff --git a/homeassistant/components/tibber/notify.py b/homeassistant/components/tibber/notify.py index 0c3a3f1465ac0..583fd9eea276c 100644 --- a/homeassistant/components/tibber/notify.py +++ b/homeassistant/components/tibber/notify.py @@ -3,7 +3,6 @@ from __future__ import annotations from collections.abc import Callable -import logging from typing import Any from tibber import Tibber @@ -17,12 +16,12 @@ ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import DOMAIN as TIBBER_DOMAIN - -_LOGGER = logging.getLogger(__name__) +from .repairs import migrate_notify_issue async def async_get_service( @@ -51,11 +50,14 @@ def __init__(self, notify: Callable) -> None: async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to Tibber devices.""" + migrate_notify_issue(self.hass) title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) try: await self._notify(title=title, message=message) - except TimeoutError: - _LOGGER.error("Timeout sending message with Tibber") + except TimeoutError as exc: + raise ServiceValidationError( + translation_domain=TIBBER_DOMAIN, translation_key="send_message_timeout" + ) from exc class TibberNotificationEntity(NotifyEntity): @@ -73,5 +75,7 @@ async def async_send_message(self, message: str, title: str | None = None) -> No await tibber_connection.send_notification( title or ATTR_TITLE_DEFAULT, message ) - except TimeoutError: - _LOGGER.error("Timeout sending message with Tibber") + except TimeoutError as exc: + raise ServiceValidationError( + translation_domain=TIBBER_DOMAIN, translation_key="send_message_timeout" + ) from exc diff --git a/homeassistant/components/tibber/repairs.py b/homeassistant/components/tibber/repairs.py new file mode 100644 index 0000000000000..6c39f205549f7 --- /dev/null +++ b/homeassistant/components/tibber/repairs.py @@ -0,0 +1,37 @@ +"""Repairs support for Tibber.""" + +from __future__ import annotations + +from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN +from homeassistant.components.repairs import RepairsFlow +from homeassistant.components.repairs.issue_handler import ConfirmRepairFlow +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import issue_registry as ir + +from .const import DOMAIN + + +@callback +def migrate_notify_issue(hass: HomeAssistant) -> None: + """Ensure an issue is registered.""" + ir.async_create_issue( + hass, + DOMAIN, + "migrate_notify", + breaks_in_ha_version="2024.12.0", + issue_domain=NOTIFY_DOMAIN, + is_fixable=True, + is_persistent=True, + translation_key="migrate_notify", + severity=ir.IssueSeverity.WARNING, + ) + + +async def async_create_fix_flow( + hass: HomeAssistant, + issue_id: str, + data: dict[str, str | int | float | None] | None, +) -> RepairsFlow: + """Create flow.""" + assert issue_id == "migrate_notify" + return ConfirmRepairFlow() diff --git a/homeassistant/components/tibber/strings.json b/homeassistant/components/tibber/strings.json index af14c96674de2..12b255d818fb3 100644 --- a/homeassistant/components/tibber/strings.json +++ b/homeassistant/components/tibber/strings.json @@ -101,5 +101,23 @@ "description": "Enter your access token from {url}" } } + }, + "exceptions": { + "send_message_timeout": { + "message": "Timeout sending message with Tibber" + } + }, + "issues": { + "migrate_notify": { + "title": "Migration of Tibber notify service", + "fix_flow": { + "step": { + "confirm": { + "description": "The Tibber `notify` service has been migrated. A new `notify` entity is available now.\n\nUpdate any automations to use the new `notify.send_message` service exposed by this new entity. When this is done, fix this issue and restart Home Assistant.", + "title": "Migrate legacy Tibber notify service" + } + } + } + } } } diff --git a/tests/components/tibber/conftest.py b/tests/components/tibber/conftest.py index da3f3df1bd9c5..fc6596444c572 100644 --- a/tests/components/tibber/conftest.py +++ b/tests/components/tibber/conftest.py @@ -1,15 +1,19 @@ """Test helpers for Tibber.""" +from collections.abc import AsyncGenerator +from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch + import pytest from homeassistant.components.tibber.const import DOMAIN from homeassistant.const import CONF_ACCESS_TOKEN +from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry @pytest.fixture -def config_entry(hass): +def config_entry(hass: HomeAssistant) -> MockConfigEntry: """Tibber config entry.""" config_entry = MockConfigEntry( domain=DOMAIN, @@ -18,3 +22,24 @@ def config_entry(hass): ) config_entry.add_to_hass(hass) return config_entry + + +@pytest.fixture +async def mock_tibber_setup( + config_entry: MockConfigEntry, hass: HomeAssistant +) -> AsyncGenerator[None, MagicMock]: + """Mock tibber entry setup.""" + unique_user_id = "unique_user_id" + title = "title" + + tibber_mock = MagicMock() + tibber_mock.update_info = AsyncMock(return_value=True) + tibber_mock.user_id = PropertyMock(return_value=unique_user_id) + tibber_mock.name = PropertyMock(return_value=title) + tibber_mock.send_notification = AsyncMock() + tibber_mock.rt_disconnect = AsyncMock() + + with patch("tibber.Tibber", return_value=tibber_mock): + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + yield tibber_mock diff --git a/tests/components/tibber/test_init.py b/tests/components/tibber/test_init.py new file mode 100644 index 0000000000000..eb3d3e67763b6 --- /dev/null +++ b/tests/components/tibber/test_init.py @@ -0,0 +1,17 @@ +"""Test loading of the Tibber config entry.""" + +from unittest.mock import MagicMock + +from homeassistant.components.recorder import Recorder +from homeassistant.components.tibber import DOMAIN +from homeassistant.core import HomeAssistant + + +async def test_entry_unload( + recorder_mock: Recorder, hass: HomeAssistant, mock_tibber_setup: MagicMock +) -> None: + """Test unloading the entry.""" + entry = hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, "tibber") + await hass.config_entries.async_unload(entry.entry_id) + mock_tibber_setup.rt_disconnect.assert_called_once() + await hass.async_block_till_done(wait_background_tasks=True) diff --git a/tests/components/tibber/test_notify.py b/tests/components/tibber/test_notify.py new file mode 100644 index 0000000000000..fea6dc6e7593d --- /dev/null +++ b/tests/components/tibber/test_notify.py @@ -0,0 +1,61 @@ +"""Tests for tibber notification service.""" + +from asyncio import TimeoutError +from unittest.mock import MagicMock + +import pytest + +from homeassistant.components.recorder import Recorder +from homeassistant.components.tibber import DOMAIN +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError + + +async def test_notification_services( + recorder_mock: Recorder, hass: HomeAssistant, mock_tibber_setup: MagicMock +) -> None: + """Test create entry from user input.""" + # Assert notify entity has been added + notify_state = hass.states.get("notify.tibber") + assert notify_state is not None + + # Assert legacy notify service hass been added + assert hass.services.has_service("notify", DOMAIN) + + # Test legacy notify service + service = "tibber" + service_data = {"message": "The message", "title": "A title"} + await hass.services.async_call("notify", service, service_data, blocking=True) + calls: MagicMock = mock_tibber_setup.send_notification + + calls.assert_called_once_with(message="The message", title="A title") + calls.reset_mock() + + # Test notify entity service + service = "send_message" + service_data = { + "entity_id": "notify.tibber", + "message": "The message", + "title": "A title", + } + await hass.services.async_call("notify", service, service_data, blocking=True) + calls.assert_called_once_with("A title", "The message") + calls.reset_mock() + + calls.side_effect = TimeoutError + + with pytest.raises(ServiceValidationError): + # Test legacy notify service + service = "tibber" + service_data = {"message": "The message", "title": "A title"} + await hass.services.async_call("notify", service, service_data, blocking=True) + + with pytest.raises(ServiceValidationError): + # Test notify entity service + service = "send_message" + service_data = { + "entity_id": "notify.tibber", + "message": "The message", + "title": "A title", + } + await hass.services.async_call("notify", service, service_data, blocking=True) diff --git a/tests/components/tibber/test_repairs.py b/tests/components/tibber/test_repairs.py new file mode 100644 index 0000000000000..c5c269b54dcdd --- /dev/null +++ b/tests/components/tibber/test_repairs.py @@ -0,0 +1,67 @@ +"""Test loading of the Tibber config entry.""" + +from http import HTTPStatus +from unittest.mock import MagicMock + +from homeassistant.components.recorder import Recorder +from homeassistant.components.repairs.websocket_api import ( + RepairsFlowIndexView, + RepairsFlowResourceView, +) +from homeassistant.components.tibber import DOMAIN +from homeassistant.core import HomeAssistant +from homeassistant.helpers import issue_registry as ir + +from tests.typing import ClientSessionGenerator + + +async def test_repair_flow( + recorder_mock: Recorder, + hass: HomeAssistant, + issue_registry: ir.IssueRegistry, + mock_tibber_setup: MagicMock, + hass_client: ClientSessionGenerator, +) -> None: + """Test unloading the entry.""" + + # Test legacy notify service + service = "tibber" + service_data = {"message": "The message", "title": "A title"} + await hass.services.async_call("notify", service, service_data, blocking=True) + calls: MagicMock = mock_tibber_setup.send_notification + + calls.assert_called_once_with(message="The message", title="A title") + calls.reset_mock() + + http_client = await hass_client() + # Assert the issue is present + assert issue_registry.async_get_issue( + domain=DOMAIN, + issue_id="migrate_notify", + ) + assert len(issue_registry.issues) == 1 + + url = RepairsFlowIndexView.url + resp = await http_client.post( + url, json={"handler": DOMAIN, "issue_id": "migrate_notify"} + ) + assert resp.status == HTTPStatus.OK + data = await resp.json() + + flow_id = data["flow_id"] + assert data["step_id"] == "confirm" + + url = RepairsFlowResourceView.url.format(flow_id=flow_id) + resp = await http_client.post(url) + assert resp.status == HTTPStatus.OK + data = await resp.json() + assert data["type"] == "create_entry" + # Test confirm step in repair flow + await hass.async_block_till_done() + + # Assert the issue is no longer present + assert not issue_registry.async_get_issue( + domain=DOMAIN, + issue_id="migrate_notify", + ) + assert len(issue_registry.issues) == 0 From a169caf102f8fb41ee3849cebd789fd7f1985cee Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 12 May 2024 15:16:11 +0000 Subject: [PATCH 3/7] Use notify repair flow helper --- homeassistant/components/tibber/manifest.json | 2 +- homeassistant/components/tibber/notify.py | 4 +- homeassistant/components/tibber/repairs.py | 37 ------------------- tests/components/tibber/test_repairs.py | 11 +++--- 4 files changed, 8 insertions(+), 46 deletions(-) delete mode 100644 homeassistant/components/tibber/repairs.py diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index 70ec49794851d..1d8120a4321e3 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -3,7 +3,7 @@ "name": "Tibber", "codeowners": ["@danielhiversen"], "config_flow": true, - "dependencies": ["recorder", "http", "repairs"], + "dependencies": ["recorder"], "documentation": "https://www.home-assistant.io/integrations/tibber", "iot_class": "cloud_polling", "loggers": ["tibber"], diff --git a/homeassistant/components/tibber/notify.py b/homeassistant/components/tibber/notify.py index 583fd9eea276c..9ac3c0c1a8665 100644 --- a/homeassistant/components/tibber/notify.py +++ b/homeassistant/components/tibber/notify.py @@ -13,6 +13,7 @@ BaseNotificationService, NotifyEntity, NotifyEntityFeature, + migrate_notify_issue, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -21,7 +22,6 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import DOMAIN as TIBBER_DOMAIN -from .repairs import migrate_notify_issue async def async_get_service( @@ -50,7 +50,7 @@ def __init__(self, notify: Callable) -> None: async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to Tibber devices.""" - migrate_notify_issue(self.hass) + migrate_notify_issue(self.hass, TIBBER_DOMAIN, "Tibber", "2024.12.0") title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) try: await self._notify(title=title, message=message) diff --git a/homeassistant/components/tibber/repairs.py b/homeassistant/components/tibber/repairs.py deleted file mode 100644 index 6c39f205549f7..0000000000000 --- a/homeassistant/components/tibber/repairs.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Repairs support for Tibber.""" - -from __future__ import annotations - -from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN -from homeassistant.components.repairs import RepairsFlow -from homeassistant.components.repairs.issue_handler import ConfirmRepairFlow -from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers import issue_registry as ir - -from .const import DOMAIN - - -@callback -def migrate_notify_issue(hass: HomeAssistant) -> None: - """Ensure an issue is registered.""" - ir.async_create_issue( - hass, - DOMAIN, - "migrate_notify", - breaks_in_ha_version="2024.12.0", - issue_domain=NOTIFY_DOMAIN, - is_fixable=True, - is_persistent=True, - translation_key="migrate_notify", - severity=ir.IssueSeverity.WARNING, - ) - - -async def async_create_fix_flow( - hass: HomeAssistant, - issue_id: str, - data: dict[str, str | int | float | None] | None, -) -> RepairsFlow: - """Create flow.""" - assert issue_id == "migrate_notify" - return ConfirmRepairFlow() diff --git a/tests/components/tibber/test_repairs.py b/tests/components/tibber/test_repairs.py index c5c269b54dcdd..c2f176c801c70 100644 --- a/tests/components/tibber/test_repairs.py +++ b/tests/components/tibber/test_repairs.py @@ -8,7 +8,6 @@ RepairsFlowIndexView, RepairsFlowResourceView, ) -from homeassistant.components.tibber import DOMAIN from homeassistant.core import HomeAssistant from homeassistant.helpers import issue_registry as ir @@ -36,14 +35,14 @@ async def test_repair_flow( http_client = await hass_client() # Assert the issue is present assert issue_registry.async_get_issue( - domain=DOMAIN, - issue_id="migrate_notify", + domain="notify", + issue_id="migrate_notify_tibber", ) assert len(issue_registry.issues) == 1 url = RepairsFlowIndexView.url resp = await http_client.post( - url, json={"handler": DOMAIN, "issue_id": "migrate_notify"} + url, json={"handler": "notify", "issue_id": "migrate_notify_tibber"} ) assert resp.status == HTTPStatus.OK data = await resp.json() @@ -61,7 +60,7 @@ async def test_repair_flow( # Assert the issue is no longer present assert not issue_registry.async_get_issue( - domain=DOMAIN, - issue_id="migrate_notify", + domain="notify", + issue_id="migrate_notify_tibber", ) assert len(issue_registry.issues) == 0 From 183cb461155be2d786c1b907d447894317f47c5e Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 12 May 2024 17:24:58 +0000 Subject: [PATCH 4/7] Cleanup strings after using helper, use HomeAssistantError --- homeassistant/components/tibber/notify.py | 13 ++++++++----- homeassistant/components/tibber/strings.json | 13 ------------- tests/components/tibber/test_notify.py | 6 +++--- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/tibber/notify.py b/homeassistant/components/tibber/notify.py index 9ac3c0c1a8665..24ae86c9e7f39 100644 --- a/homeassistant/components/tibber/notify.py +++ b/homeassistant/components/tibber/notify.py @@ -17,7 +17,7 @@ ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ServiceValidationError +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -38,7 +38,7 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the Tibber notification entity.""" - async_add_entities([TibberNotificationEntity()]) + async_add_entities([TibberNotificationEntity(entry.entry_id)]) class TibberNotificationService(BaseNotificationService): @@ -55,7 +55,7 @@ async def async_send_message(self, message: str = "", **kwargs: Any) -> None: try: await self._notify(title=title, message=message) except TimeoutError as exc: - raise ServiceValidationError( + raise HomeAssistantError( translation_domain=TIBBER_DOMAIN, translation_key="send_message_timeout" ) from exc @@ -64,10 +64,13 @@ class TibberNotificationEntity(NotifyEntity): """Implement the notification entity service for Tibber.""" _attr_supported_features = NotifyEntityFeature.TITLE - _attr_unique_id = f"{TIBBER_DOMAIN}_notify" _attr_name = TIBBER_DOMAIN _attr_icon = "mdi:message-flash" + def __init__(self, unique_id: str) -> None: + """Initialize Tibber notify entity.""" + self._attr_unique_id = unique_id + async def async_send_message(self, message: str, title: str | None = None) -> None: """Send a message to Tibber devices.""" tibber_connection: Tibber = self.hass.data[TIBBER_DOMAIN] @@ -76,6 +79,6 @@ async def async_send_message(self, message: str, title: str | None = None) -> No title or ATTR_TITLE_DEFAULT, message ) except TimeoutError as exc: - raise ServiceValidationError( + raise HomeAssistantError( translation_domain=TIBBER_DOMAIN, translation_key="send_message_timeout" ) from exc diff --git a/homeassistant/components/tibber/strings.json b/homeassistant/components/tibber/strings.json index 12b255d818fb3..7647dcb9e9ac3 100644 --- a/homeassistant/components/tibber/strings.json +++ b/homeassistant/components/tibber/strings.json @@ -106,18 +106,5 @@ "send_message_timeout": { "message": "Timeout sending message with Tibber" } - }, - "issues": { - "migrate_notify": { - "title": "Migration of Tibber notify service", - "fix_flow": { - "step": { - "confirm": { - "description": "The Tibber `notify` service has been migrated. A new `notify` entity is available now.\n\nUpdate any automations to use the new `notify.send_message` service exposed by this new entity. When this is done, fix this issue and restart Home Assistant.", - "title": "Migrate legacy Tibber notify service" - } - } - } - } } } diff --git a/tests/components/tibber/test_notify.py b/tests/components/tibber/test_notify.py index fea6dc6e7593d..2e157e9415a0b 100644 --- a/tests/components/tibber/test_notify.py +++ b/tests/components/tibber/test_notify.py @@ -8,7 +8,7 @@ from homeassistant.components.recorder import Recorder from homeassistant.components.tibber import DOMAIN from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ServiceValidationError +from homeassistant.exceptions import HomeAssistantError async def test_notification_services( @@ -44,13 +44,13 @@ async def test_notification_services( calls.side_effect = TimeoutError - with pytest.raises(ServiceValidationError): + with pytest.raises(HomeAssistantError): # Test legacy notify service service = "tibber" service_data = {"message": "The message", "title": "A title"} await hass.services.async_call("notify", service, service_data, blocking=True) - with pytest.raises(ServiceValidationError): + with pytest.raises(HomeAssistantError): # Test notify entity service service = "send_message" service_data = { From 7e279f7d9bdc29846ecc479dde0641a9e73f4e17 Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 12 May 2024 17:30:15 +0000 Subject: [PATCH 5/7] Add entry state assertions to unload test --- tests/components/tibber/test_init.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/components/tibber/test_init.py b/tests/components/tibber/test_init.py index eb3d3e67763b6..dcc233070504c 100644 --- a/tests/components/tibber/test_init.py +++ b/tests/components/tibber/test_init.py @@ -4,6 +4,7 @@ from homeassistant.components.recorder import Recorder from homeassistant.components.tibber import DOMAIN +from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant @@ -12,6 +13,9 @@ async def test_entry_unload( ) -> None: """Test unloading the entry.""" entry = hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, "tibber") + assert entry.state == ConfigEntryState.LOADED + await hass.config_entries.async_unload(entry.entry_id) mock_tibber_setup.rt_disconnect.assert_called_once() await hass.async_block_till_done(wait_background_tasks=True) + assert entry.state == ConfigEntryState.NOT_LOADED From 0fabf08ea537bf29f05388c754c397853873fa82 Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 12 May 2024 17:32:35 +0000 Subject: [PATCH 6/7] Update comment --- tests/components/tibber/test_repairs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/tibber/test_repairs.py b/tests/components/tibber/test_repairs.py index c2f176c801c70..d427b68ca8557 100644 --- a/tests/components/tibber/test_repairs.py +++ b/tests/components/tibber/test_repairs.py @@ -54,8 +54,8 @@ async def test_repair_flow( resp = await http_client.post(url) assert resp.status == HTTPStatus.OK data = await resp.json() + # Assert the confirm step in repair flow (create_entry) assert data["type"] == "create_entry" - # Test confirm step in repair flow await hass.async_block_till_done() # Assert the issue is no longer present From 42f98f83428910cf5fce277c6933855aedfbe332 Mon Sep 17 00:00:00 2001 From: jbouwh Date: Sun, 12 May 2024 17:35:07 +0000 Subject: [PATCH 7/7] Update comment --- tests/components/tibber/test_repairs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/tibber/test_repairs.py b/tests/components/tibber/test_repairs.py index d427b68ca8557..9aaec81618db5 100644 --- a/tests/components/tibber/test_repairs.py +++ b/tests/components/tibber/test_repairs.py @@ -50,11 +50,11 @@ async def test_repair_flow( flow_id = data["flow_id"] assert data["step_id"] == "confirm" + # Simulate the users confirmed the repair flow url = RepairsFlowResourceView.url.format(flow_id=flow_id) resp = await http_client.post(url) assert resp.status == HTTPStatus.OK data = await resp.json() - # Assert the confirm step in repair flow (create_entry) assert data["type"] == "create_entry" await hass.async_block_till_done()