1 """The Voice over IP integration."""
3 from __future__
import annotations
6 from collections.abc
import Callable
7 from dataclasses
import dataclass
10 from voip_utils
import SIP_PORT
18 from .const
import CONF_SIP_PORT, DOMAIN
19 from .devices
import VoIPDevices
20 from .voip
import HassVoipDatagramProtocol
23 Platform.ASSIST_SATELLITE,
24 Platform.BINARY_SENSOR,
28 _LOGGER = logging.getLogger(__name__)
29 _IP_WILDCARD =
"0.0.0.0"
35 "async_remove_config_entry_device",
43 transport: asyncio.DatagramTransport
44 protocol: HassVoipDatagramProtocol
49 """Set up VoIP integration from a config entry."""
52 "user" not in entry.data
53 or (await hass.auth.async_get_user(entry.data[
"user"]))
is None
55 voip_user = await hass.auth.async_create_system_user(
56 "Voice over IP", group_ids=[GROUP_ID_USER]
58 hass.config_entries.async_update_entry(
59 entry, data={**entry.data,
"user": voip_user.id}
62 sip_port = entry.options.get(CONF_SIP_PORT, SIP_PORT)
70 _LOGGER.debug(
"Listening for VoIP calls on port %s", sip_port)
72 hass.data[DOMAIN] =
DomainData(transport, protocol, devices)
74 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
76 entry.async_on_unload(entry.add_update_listener(update_listener))
82 """Handle options update."""
83 await hass.config_entries.async_reload(entry.entry_id)
88 protocol_factory: Callable[
90 asyncio.DatagramProtocol,
93 ) -> tuple[asyncio.DatagramTransport, HassVoipDatagramProtocol]:
94 transport, protocol = await hass.loop.create_datagram_endpoint(
96 local_addr=(_IP_WILDCARD, sip_port),
99 if not isinstance(protocol, HassVoipDatagramProtocol):
100 raise TypeError(f
"Expected HassVoipDatagramProtocol, got {protocol}")
102 return transport, protocol
107 if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
108 _LOGGER.debug(
"Shutting down VoIP server")
109 data = hass.data.pop(DOMAIN)
110 data.transport.close()
111 await data.protocol.wait_closed()
112 _LOGGER.debug(
"VoIP server shut down successfully")
118 hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
120 """Remove device from a config entry."""
125 """Remove VoIP entry."""
126 if "user" in entry.data
and (
127 user := await hass.auth.async_get_user(entry.data[
"user"])
129 await hass.auth.async_remove_user(user)
def update_listener(HomeAssistant hass, ConfigEntry entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
None async_remove_entry(HomeAssistant hass, ConfigEntry entry)
tuple[asyncio.DatagramTransport, HassVoipDatagramProtocol] _create_sip_server(HomeAssistant hass, Callable[[], asyncio.DatagramProtocol,] protocol_factory, int sip_port)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
bool async_remove_config_entry_device(HomeAssistant hass, ConfigEntry config_entry, dr.DeviceEntry device_entry)