mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add contact vip info to fritzbox_callmonitor sensor (#132913)
This commit is contained in:
parent
c0f6535d11
commit
7e2d3eb482
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import suppress
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import re
|
||||
@ -19,12 +20,33 @@ _LOGGER = logging.getLogger(__name__)
|
||||
MIN_TIME_PHONEBOOK_UPDATE = timedelta(hours=6)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Contact:
|
||||
"""Store details for one phonebook contact."""
|
||||
|
||||
name: str
|
||||
numbers: list[str]
|
||||
vip: bool
|
||||
|
||||
def __init__(
|
||||
self, name: str, numbers: list[str] | None = None, category: str | None = None
|
||||
) -> None:
|
||||
"""Initialize the class."""
|
||||
self.name = name
|
||||
self.numbers = [re.sub(REGEX_NUMBER, "", nr) for nr in numbers or ()]
|
||||
self.vip = category == "1"
|
||||
|
||||
|
||||
unknown_contact = Contact(UNKNOWN_NAME)
|
||||
|
||||
|
||||
class FritzBoxPhonebook:
|
||||
"""Connects to a FritzBox router and downloads its phone book."""
|
||||
|
||||
fph: FritzPhonebook
|
||||
phonebook_dict: dict[str, list[str]]
|
||||
number_dict: dict[str, str]
|
||||
contacts: list[Contact]
|
||||
number_dict: dict[str, Contact]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -56,27 +78,27 @@ class FritzBoxPhonebook:
|
||||
if self.phonebook_id is None:
|
||||
return
|
||||
|
||||
self.phonebook_dict = self.fph.get_all_names(self.phonebook_id)
|
||||
self.number_dict = {
|
||||
re.sub(REGEX_NUMBER, "", nr): name
|
||||
for name, nrs in self.phonebook_dict.items()
|
||||
for nr in nrs
|
||||
}
|
||||
self.fph.get_all_name_numbers(self.phonebook_id)
|
||||
self.contacts = [
|
||||
Contact(c.name, c.numbers, getattr(c, "category", None))
|
||||
for c in self.fph.phonebook.contacts
|
||||
]
|
||||
self.number_dict = {nr: c for c in self.contacts for nr in c.numbers}
|
||||
_LOGGER.debug("Fritz!Box phone book successfully updated")
|
||||
|
||||
def get_phonebook_ids(self) -> list[int]:
|
||||
"""Return list of phonebook ids."""
|
||||
return self.fph.phonebook_ids # type: ignore[no-any-return]
|
||||
|
||||
def get_name(self, number: str) -> str:
|
||||
"""Return a name for a given phone number."""
|
||||
def get_contact(self, number: str) -> Contact:
|
||||
"""Return a contact for a given phone number."""
|
||||
number = re.sub(REGEX_NUMBER, "", str(number))
|
||||
|
||||
with suppress(KeyError):
|
||||
return self.number_dict[number]
|
||||
|
||||
if not self.prefixes:
|
||||
return UNKNOWN_NAME
|
||||
return unknown_contact
|
||||
|
||||
for prefix in self.prefixes:
|
||||
with suppress(KeyError):
|
||||
@ -84,4 +106,4 @@ class FritzBoxPhonebook:
|
||||
with suppress(KeyError):
|
||||
return self.number_dict[prefix + number.lstrip("0")]
|
||||
|
||||
return UNKNOWN_NAME
|
||||
return unknown_contact
|
||||
|
@ -20,7 +20,7 @@ from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import FritzBoxCallMonitorConfigEntry
|
||||
from .base import FritzBoxPhonebook
|
||||
from .base import Contact, FritzBoxPhonebook
|
||||
from .const import (
|
||||
ATTR_PREFIXES,
|
||||
CONF_PHONEBOOK,
|
||||
@ -96,7 +96,7 @@ class FritzBoxCallSensor(SensorEntity):
|
||||
self._host = host
|
||||
self._port = port
|
||||
self._monitor: FritzBoxCallMonitor | None = None
|
||||
self._attributes: dict[str, str | list[str]] = {}
|
||||
self._attributes: dict[str, str | list[str] | bool] = {}
|
||||
|
||||
self._attr_translation_placeholders = {"phonebook_name": phonebook_name}
|
||||
self._attr_unique_id = unique_id
|
||||
@ -152,20 +152,20 @@ class FritzBoxCallSensor(SensorEntity):
|
||||
"""Set the state."""
|
||||
self._attr_native_value = state
|
||||
|
||||
def set_attributes(self, attributes: Mapping[str, str]) -> None:
|
||||
def set_attributes(self, attributes: Mapping[str, str | bool]) -> None:
|
||||
"""Set the state attributes."""
|
||||
self._attributes = {**attributes}
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, str | list[str]]:
|
||||
def extra_state_attributes(self) -> dict[str, str | list[str] | bool]:
|
||||
"""Return the state attributes."""
|
||||
if self._prefixes:
|
||||
self._attributes[ATTR_PREFIXES] = self._prefixes
|
||||
return self._attributes
|
||||
|
||||
def number_to_name(self, number: str) -> str:
|
||||
"""Return a name for a given phone number."""
|
||||
return self._fritzbox_phonebook.get_name(number)
|
||||
def number_to_contact(self, number: str) -> Contact:
|
||||
"""Return a contact for a given phone number."""
|
||||
return self._fritzbox_phonebook.get_contact(number)
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update the phonebook if it is defined."""
|
||||
@ -225,35 +225,42 @@ class FritzBoxCallMonitor:
|
||||
df_in = "%d.%m.%y %H:%M:%S"
|
||||
df_out = "%Y-%m-%dT%H:%M:%S"
|
||||
isotime = datetime.strptime(line[0], df_in).strftime(df_out)
|
||||
att: dict[str, str | bool]
|
||||
if line[1] == FritzState.RING:
|
||||
self._sensor.set_state(CallState.RINGING)
|
||||
contact = self._sensor.number_to_contact(line[3])
|
||||
att = {
|
||||
"type": "incoming",
|
||||
"from": line[3],
|
||||
"to": line[4],
|
||||
"device": line[5],
|
||||
"initiated": isotime,
|
||||
"from_name": self._sensor.number_to_name(line[3]),
|
||||
"from_name": contact.name,
|
||||
"vip": contact.vip,
|
||||
}
|
||||
self._sensor.set_attributes(att)
|
||||
elif line[1] == FritzState.CALL:
|
||||
self._sensor.set_state(CallState.DIALING)
|
||||
contact = self._sensor.number_to_contact(line[5])
|
||||
att = {
|
||||
"type": "outgoing",
|
||||
"from": line[4],
|
||||
"to": line[5],
|
||||
"device": line[6],
|
||||
"initiated": isotime,
|
||||
"to_name": self._sensor.number_to_name(line[5]),
|
||||
"to_name": contact.name,
|
||||
"vip": contact.vip,
|
||||
}
|
||||
self._sensor.set_attributes(att)
|
||||
elif line[1] == FritzState.CONNECT:
|
||||
self._sensor.set_state(CallState.TALKING)
|
||||
contact = self._sensor.number_to_contact(line[4])
|
||||
att = {
|
||||
"with": line[4],
|
||||
"device": line[3],
|
||||
"accepted": isotime,
|
||||
"with_name": self._sensor.number_to_name(line[4]),
|
||||
"with_name": contact.name,
|
||||
"vip": contact.vip,
|
||||
}
|
||||
self._sensor.set_attributes(att)
|
||||
elif line[1] == FritzState.DISCONNECT:
|
||||
|
@ -78,7 +78,8 @@
|
||||
"accepted": { "name": "Accepted" },
|
||||
"with_name": { "name": "With name" },
|
||||
"duration": { "name": "Duration" },
|
||||
"closed": { "name": "Closed" }
|
||||
"closed": { "name": "Closed" },
|
||||
"vip": { "name": "Important" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user