Unify Supervisor event message functions (#5831)

* Unify Supervisor event message functions

Unify functions which send WebSocket messages of type
"supervisor/event". This deduplicates code and hopefully avoids further
diversication in the future.

While at it, remove unused HomeAssistantWSNotSupported exception. It
seems the only place this exception is used got removed in #3317.

* Test message delivery during shutdown states
This commit is contained in:
Stefan Agner 2025-04-23 10:40:25 +02:00 committed by GitHub
parent 5d07dd2c42
commit 122b73202b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 59 deletions

View File

@ -33,8 +33,6 @@ from ..const import (
ATTR_AUDIO_OUTPUT, ATTR_AUDIO_OUTPUT,
ATTR_AUTO_UPDATE, ATTR_AUTO_UPDATE,
ATTR_BOOT, ATTR_BOOT,
ATTR_DATA,
ATTR_EVENT,
ATTR_IMAGE, ATTR_IMAGE,
ATTR_INGRESS_ENTRY, ATTR_INGRESS_ENTRY,
ATTR_INGRESS_PANEL, ATTR_INGRESS_PANEL,
@ -50,7 +48,6 @@ from ..const import (
ATTR_SYSTEM, ATTR_SYSTEM,
ATTR_SYSTEM_MANAGED, ATTR_SYSTEM_MANAGED,
ATTR_SYSTEM_MANAGED_CONFIG_ENTRY, ATTR_SYSTEM_MANAGED_CONFIG_ENTRY,
ATTR_TYPE,
ATTR_USER, ATTR_USER,
ATTR_UUID, ATTR_UUID,
ATTR_VERSION, ATTR_VERSION,
@ -79,7 +76,7 @@ from ..exceptions import (
HostAppArmorError, HostAppArmorError,
) )
from ..hardware.data import Device from ..hardware.data import Device
from ..homeassistant.const import WSEvent, WSType from ..homeassistant.const import WSEvent
from ..jobs.const import JobExecutionLimit from ..jobs.const import JobExecutionLimit
from ..jobs.decorator import Job from ..jobs.decorator import Job
from ..resolution.const import ContextType, IssueType, UnhealthyReason from ..resolution.const import ContextType, IssueType, UnhealthyReason
@ -196,15 +193,12 @@ class Addon(AddonModel):
): ):
self.sys_resolution.dismiss_issue(self.device_access_missing_issue) self.sys_resolution.dismiss_issue(self.device_access_missing_issue)
self.sys_homeassistant.websocket.send_message( self.sys_homeassistant.websocket.supervisor_event_custom(
WSEvent.ADDON,
{ {
ATTR_TYPE: WSType.SUPERVISOR_EVENT,
ATTR_DATA: {
ATTR_EVENT: WSEvent.ADDON,
ATTR_SLUG: self.slug, ATTR_SLUG: self.slug,
ATTR_STATE: new_state, ATTR_STATE: new_state,
}, },
}
) )
@property @property

View File

@ -84,10 +84,6 @@ class HomeAssistantWSError(HomeAssistantAPIError):
"""Home Assistant websocket error.""" """Home Assistant websocket error."""
class HomeAssistantWSNotSupported(HomeAssistantWSError):
"""Raise when WebSockets are not supported."""
class HomeAssistantWSConnectionError(HomeAssistantWSError): class HomeAssistantWSConnectionError(HomeAssistantWSError):
"""Raise when the WebSocket connection has an error.""" """Raise when the WebSocket connection has an error."""

View File

@ -25,7 +25,6 @@ from ..exceptions import (
HomeAssistantAPIError, HomeAssistantAPIError,
HomeAssistantWSConnectionError, HomeAssistantWSConnectionError,
HomeAssistantWSError, HomeAssistantWSError,
HomeAssistantWSNotSupported,
) )
from ..utils.json import json_dumps from ..utils.json import json_dumps
from .const import CLOSING_STATES, WSEvent, WSType from .const import CLOSING_STATES, WSEvent, WSType
@ -254,7 +253,7 @@ class HomeAssistantWebSocket(CoreSysAttributes):
) )
async def async_send_message(self, message: dict[str, Any]) -> None: async def async_send_message(self, message: dict[str, Any]) -> None:
"""Send a command with the WS client.""" """Send a message with the WS client."""
# Only commands allowed during startup as those tell Home Assistant to do something. # Only commands allowed during startup as those tell Home Assistant to do something.
# Messages may cause clients to make follow-up API calls so those wait. # Messages may cause clients to make follow-up API calls so those wait.
if self.sys_core.state in STARTING_STATES: if self.sys_core.state in STARTING_STATES:
@ -288,67 +287,67 @@ class HomeAssistantWebSocket(CoreSysAttributes):
raise raise
return None return None
async def async_supervisor_update_event(
self,
key: str,
data: dict[str, Any] | None = None,
) -> None:
"""Send a supervisor/event command."""
try:
await self.async_send_message(
{
ATTR_TYPE: WSType.SUPERVISOR_EVENT,
ATTR_DATA: {
ATTR_EVENT: WSEvent.SUPERVISOR_UPDATE,
ATTR_UPDATE_KEY: key,
ATTR_DATA: data or {},
},
}
)
except HomeAssistantWSNotSupported:
pass
except HomeAssistantWSError as err:
_LOGGER.error("Could not send message to Home Assistant due to %s", err)
def supervisor_update_event(
self,
key: str,
data: dict[str, Any] | None = None,
) -> None:
"""Send a supervisor/event command."""
if self.sys_core.state in CLOSING_STATES:
return
self.sys_create_task(self.async_supervisor_update_event(key, data))
def send_message(self, message: dict[str, Any]) -> None: def send_message(self, message: dict[str, Any]) -> None:
"""Send a supervisor/event command.""" """Send a supervisor/event message."""
if self.sys_core.state in CLOSING_STATES: if self.sys_core.state in CLOSING_STATES:
return return
self.sys_create_task(self.async_send_message(message)) self.sys_create_task(self.async_send_message(message))
async def async_supervisor_event( async def async_supervisor_event_custom(
self, event: WSEvent, data: dict[str, Any] | None = None self, event: WSEvent, extra_data: dict[str, Any] | None = None
) -> None: ) -> None:
"""Send a supervisor/event command to Home Assistant.""" """Send a supervisor/event message to Home Assistant with custom data."""
try: try:
await self.async_send_message( await self.async_send_message(
{ {
ATTR_TYPE: WSType.SUPERVISOR_EVENT, ATTR_TYPE: WSType.SUPERVISOR_EVENT,
ATTR_DATA: { ATTR_DATA: {
ATTR_EVENT: event, ATTR_EVENT: event,
ATTR_DATA: data or {}, **(extra_data or {}),
}, },
} }
) )
except HomeAssistantWSNotSupported:
pass
except HomeAssistantWSError as err: except HomeAssistantWSError as err:
_LOGGER.error("Could not send message to Home Assistant due to %s", err) _LOGGER.error("Could not send message to Home Assistant due to %s", err)
def supervisor_event_custom(
self, event: WSEvent, extra_data: dict[str, Any] | None = None
) -> None:
"""Send a supervisor/event message to Home Assistant with custom data."""
if self.sys_core.state in CLOSING_STATES:
return
self.sys_create_task(self.async_supervisor_event_custom(event, extra_data))
def supervisor_event( def supervisor_event(
self, event: WSEvent, data: dict[str, Any] | None = None self, event: WSEvent, data: dict[str, Any] | None = None
) -> None: ) -> None:
"""Send a supervisor/event command to Home Assistant.""" """Send a supervisor/event message to Home Assistant."""
if self.sys_core.state in CLOSING_STATES: if self.sys_core.state in CLOSING_STATES:
return return
self.sys_create_task(self.async_supervisor_event(event, data)) self.sys_create_task(
self.async_supervisor_event_custom(event, {ATTR_DATA: data or {}})
)
async def async_supervisor_update_event(
self,
key: str,
data: dict[str, Any] | None = None,
) -> None:
"""Send an update supervisor/event message."""
await self.async_supervisor_event_custom(
WSEvent.SUPERVISOR_UPDATE,
{
ATTR_UPDATE_KEY: key,
ATTR_DATA: data or {},
},
)
def supervisor_update_event(
self,
key: str,
data: dict[str, Any] | None = None,
) -> None:
"""Send an update supervisor/event message."""
if self.sys_core.state in CLOSING_STATES:
return
self.sys_create_task(self.async_supervisor_update_event(key, data))

View File

@ -84,3 +84,11 @@ async def test_send_message_during_startup(coresys: CoreSys, ha_ws_client: Async
"data": {"state": "running"}, "data": {"state": "running"},
}, },
} }
ha_ws_client.reset_mock()
await coresys.core.set_state(CoreState.SHUTDOWN)
await coresys.homeassistant.websocket.async_supervisor_update_event(
"test", {"lorem": "ipsum"}
)
ha_ws_client.async_send_command.assert_not_called()