1 """Class to manage devices."""
3 from __future__
import annotations
5 from collections.abc
import Callable, Iterator
6 from dataclasses
import dataclass, field
8 from voip_utils
import CallInfo, VoipDatagramProtocol
14 from .const
import DOMAIN
19 """Class to store device."""
23 is_active: bool =
False
24 update_listeners: list[Callable[[VoIPDevice],
None]] = field(default_factory=list)
25 protocol: VoipDatagramProtocol |
None =
None
29 """Set active state."""
31 for listener
in self.update_listeners:
36 self, listener: Callable[[VoIPDevice],
None]
37 ) -> Callable[[],
None]:
38 """Listen for updates."""
39 self.update_listeners.append(listener)
40 return lambda: self.update_listeners.
remove(listener)
44 """Return if call is allowed."""
45 ent_reg = er.async_get(hass)
47 allowed_call_entity_id = ent_reg.async_get_entity_id(
48 "switch", DOMAIN, f
"{self.voip_id}-allow_call"
52 if allowed_call_entity_id
is None:
55 if state := hass.states.get(allowed_call_entity_id):
56 return state.state ==
"on"
61 """Return entity id for pipeline select."""
62 ent_reg = er.async_get(hass)
63 return ent_reg.async_get_entity_id(
"select", DOMAIN, f
"{self.voip_id}-pipeline")
66 """Return entity id for VAD sensitivity."""
67 ent_reg = er.async_get(hass)
68 return ent_reg.async_get_entity_id(
69 "select", DOMAIN, f
"{self.voip_id}-vad_sensitivity"
74 """Class to store devices."""
76 def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) ->
None:
77 """Initialize VoIP devices."""
80 self._new_device_listeners: list[Callable[[VoIPDevice],
None]] = []
81 self.
devicesdevices: dict[str, VoIPDevice] = {}
86 for device
in dr.async_entries_for_config_entry(
90 (item[1]
for item
in device.identifiers
if item[0] == DOMAIN),
None
100 def async_device_removed(ev: Event[dr.EventDeviceRegistryUpdatedData]) ->
None:
101 """Handle device removed."""
102 removed_id = ev.data[
"device_id"]
105 for voip_id, voip_device
in self.
devicesdevices.items()
106 if voip_device.device_id != removed_id
110 self.
hasshass.bus.async_listen(
111 dr.EVENT_DEVICE_REGISTRY_UPDATED,
112 async_device_removed,
113 callback(
lambda event_data: event_data[
"action"] ==
"remove"),
119 self, listener: Callable[[VoIPDevice],
None]
121 """Add a new device listener."""
122 self._new_device_listeners.append(listener)
126 """Get or create a device."""
127 user_agent = call_info.headers.get(
"user-agent",
"")
128 user_agent_parts = user_agent.split()
129 if len(user_agent_parts) == 3
and user_agent_parts[0] ==
"Grandstream":
130 manuf = user_agent_parts[0]
131 model = user_agent_parts[1]
132 fw_version = user_agent_parts[2]
135 model = user_agent
if user_agent
else None
138 dev_reg = dr.async_get(self.
hasshass)
139 voip_id = call_info.caller_ip
140 voip_device = self.
devicesdevices.
get(voip_id)
142 if voip_device
is not None:
143 device = dev_reg.async_get(voip_device.device_id)
144 if device
and fw_version
and device.sw_version != fw_version:
145 dev_reg.async_update_device(device.id, sw_version=fw_version)
149 device = dev_reg.async_get_or_create(
151 identifiers={(DOMAIN, voip_id)},
155 sw_version=fw_version,
156 configuration_url=f
"http://{call_info.caller_ip}",
162 for listener
in self._new_device_listeners:
163 listener(voip_device)
168 """Iterate over devices."""
169 return iter(self.
devicesdevices.values())
Callable[[], None] async_listen_update(self, Callable[[VoIPDevice], None] listener)
bool async_allow_call(self, HomeAssistant hass)
str|None get_vad_sensitivity_entity_id(self, HomeAssistant hass)
None set_is_active(self, bool active)
str|None get_pipeline_entity_id(self, HomeAssistant hass)
Iterator[VoIPDevice] __iter__(self)
None async_add_new_device_listener(self, Callable[[VoIPDevice], None] listener)
VoIPDevice async_get_or_create(self, CallInfo call_info)
None __init__(self, HomeAssistant hass, ConfigEntry config_entry)
bool remove(self, _T matcher)
web.Response get(self, web.Request request, str config_key)