Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Voice over IP integration."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from collections.abc import Callable
7 from dataclasses import dataclass
8 import logging
9 
10 from voip_utils import SIP_PORT
11 
12 from homeassistant.auth.const import GROUP_ID_USER
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.const import Platform
15 from homeassistant.core import HomeAssistant
16 from homeassistant.helpers import device_registry as dr
17 
18 from .const import CONF_SIP_PORT, DOMAIN
19 from .devices import VoIPDevices
20 from .voip import HassVoipDatagramProtocol
21 
22 PLATFORMS = (
23  Platform.ASSIST_SATELLITE,
24  Platform.BINARY_SENSOR,
25  Platform.SELECT,
26  Platform.SWITCH,
27 )
28 _LOGGER = logging.getLogger(__name__)
29 _IP_WILDCARD = "0.0.0.0"
30 
31 __all__ = [
32  "DOMAIN",
33  "async_setup_entry",
34  "async_unload_entry",
35  "async_remove_config_entry_device",
36 ]
37 
38 
39 @dataclass
40 class DomainData:
41  """Domain data."""
42 
43  transport: asyncio.DatagramTransport
44  protocol: HassVoipDatagramProtocol
45  devices: VoIPDevices
46 
47 
48 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
49  """Set up VoIP integration from a config entry."""
50  # Make sure there is a valid user ID for VoIP in the config entry
51  if (
52  "user" not in entry.data
53  or (await hass.auth.async_get_user(entry.data["user"])) is None
54  ):
55  voip_user = await hass.auth.async_create_system_user(
56  "Voice over IP", group_ids=[GROUP_ID_USER]
57  )
58  hass.config_entries.async_update_entry(
59  entry, data={**entry.data, "user": voip_user.id}
60  )
61 
62  sip_port = entry.options.get(CONF_SIP_PORT, SIP_PORT)
63  devices = VoIPDevices(hass, entry)
64  devices.async_setup()
65  transport, protocol = await _create_sip_server(
66  hass,
67  lambda: HassVoipDatagramProtocol(hass, devices),
68  sip_port,
69  )
70  _LOGGER.debug("Listening for VoIP calls on port %s", sip_port)
71 
72  hass.data[DOMAIN] = DomainData(transport, protocol, devices)
73 
74  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
75 
76  entry.async_on_unload(entry.add_update_listener(update_listener))
77 
78  return True
79 
80 
81 async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
82  """Handle options update."""
83  await hass.config_entries.async_reload(entry.entry_id)
84 
85 
87  hass: HomeAssistant,
88  protocol_factory: Callable[
89  [],
90  asyncio.DatagramProtocol,
91  ],
92  sip_port: int,
93 ) -> tuple[asyncio.DatagramTransport, HassVoipDatagramProtocol]:
94  transport, protocol = await hass.loop.create_datagram_endpoint(
95  protocol_factory,
96  local_addr=(_IP_WILDCARD, sip_port),
97  )
98 
99  if not isinstance(protocol, HassVoipDatagramProtocol):
100  raise TypeError(f"Expected HassVoipDatagramProtocol, got {protocol}")
101 
102  return transport, protocol
103 
104 
105 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
106  """Unload VoIP."""
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")
113 
114  return unload_ok
115 
116 
118  hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
119 ) -> bool:
120  """Remove device from a config entry."""
121  return True
122 
123 
124 async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
125  """Remove VoIP entry."""
126  if "user" in entry.data and (
127  user := await hass.auth.async_get_user(entry.data["user"])
128  ):
129  await hass.auth.async_remove_user(user)
def update_listener(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:81
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:105
None async_remove_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:124
tuple[asyncio.DatagramTransport, HassVoipDatagramProtocol] _create_sip_server(HomeAssistant hass, Callable[[], asyncio.DatagramProtocol,] protocol_factory, int sip_port)
Definition: __init__.py:93
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:48
bool async_remove_config_entry_device(HomeAssistant hass, ConfigEntry config_entry, dr.DeviceEntry device_entry)
Definition: __init__.py:119