Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Get your own public IP address or that of any host."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 from ipaddress import IPv4Address, IPv6Address
7 import logging
8 
9 import aiodns
10 from aiodns.error import DNSError
11 
12 from homeassistant.components.sensor import SensorEntity
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.const import CONF_NAME, CONF_PORT
15 from homeassistant.core import HomeAssistant
16 from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 
19 from .const import (
20  CONF_HOSTNAME,
21  CONF_IPV4,
22  CONF_IPV6,
23  CONF_PORT_IPV6,
24  CONF_RESOLVER,
25  CONF_RESOLVER_IPV6,
26  DOMAIN,
27 )
28 
29 DEFAULT_RETRIES = 2
30 MAX_RESULTS = 10
31 
32 _LOGGER = logging.getLogger(__name__)
33 
34 SCAN_INTERVAL = timedelta(seconds=120)
35 
36 
37 def sort_ips(ips: list, querytype: str) -> list:
38  """Join IPs into a single string."""
39 
40  if querytype == "AAAA":
41  ips = [IPv6Address(ip) for ip in ips]
42  else:
43  ips = [IPv4Address(ip) for ip in ips]
44  return [str(ip) for ip in sorted(ips)][:MAX_RESULTS]
45 
46 
48  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
49 ) -> None:
50  """Set up the dnsip sensor entry."""
51 
52  hostname = entry.data[CONF_HOSTNAME]
53  name = entry.data[CONF_NAME]
54 
55  resolver_ipv4 = entry.options[CONF_RESOLVER]
56  resolver_ipv6 = entry.options[CONF_RESOLVER_IPV6]
57  port_ipv4 = entry.options[CONF_PORT]
58  port_ipv6 = entry.options[CONF_PORT_IPV6]
59 
60  entities = []
61  if entry.data[CONF_IPV4]:
62  entities.append(WanIpSensor(name, hostname, resolver_ipv4, False, port_ipv4))
63  if entry.data[CONF_IPV6]:
64  entities.append(WanIpSensor(name, hostname, resolver_ipv6, True, port_ipv6))
65 
66  async_add_entities(entities, update_before_add=True)
67 
68 
70  """Implementation of a DNS IP sensor."""
71 
72  _attr_has_entity_name = True
73  _attr_translation_key = "dnsip"
74  _unrecorded_attributes = frozenset({"resolver", "querytype", "ip_addresses"})
75 
76  def __init__(
77  self,
78  name: str,
79  hostname: str,
80  resolver: str,
81  ipv6: bool,
82  port: int,
83  ) -> None:
84  """Initialize the DNS IP sensor."""
85  self._attr_name_attr_name = "IPv6" if ipv6 else None
86  self._attr_unique_id_attr_unique_id = f"{hostname}_{ipv6}"
87  self.hostnamehostname = hostname
88  self.resolverresolver = aiodns.DNSResolver(tcp_port=port, udp_port=port)
89  self.resolverresolver.nameservers = [resolver]
90  self.querytypequerytype = "AAAA" if ipv6 else "A"
91  self._retries_retries = DEFAULT_RETRIES
92  self._attr_extra_state_attributes_attr_extra_state_attributes = {
93  "resolver": resolver,
94  "querytype": self.querytypequerytype,
95  }
96  self._attr_device_info_attr_device_info = DeviceInfo(
97  entry_type=DeviceEntryType.SERVICE,
98  identifiers={(DOMAIN, hostname)},
99  manufacturer="DNS",
100  model=aiodns.__version__,
101  name=name,
102  )
103 
104  async def async_update(self) -> None:
105  """Get the current DNS IP address for hostname."""
106  try:
107  response = await self.resolverresolver.query(self.hostnamehostname, self.querytypequerytype)
108  except DNSError as err:
109  _LOGGER.warning("Exception while resolving host: %s", err)
110  response = None
111 
112  if response:
113  sorted_ips = sort_ips(
114  [res.host for res in response], querytype=self.querytypequerytype
115  )
116  self._attr_native_value_attr_native_value = sorted_ips[0]
117  self._attr_extra_state_attributes_attr_extra_state_attributes["ip_addresses"] = sorted_ips
118  self._attr_available_attr_available = True
119  self._retries_retries = DEFAULT_RETRIES
120  elif self._retries_retries > 0:
121  self._retries_retries -= 1
122  else:
123  self._attr_available_attr_available = False
None __init__(self, str name, str hostname, str resolver, bool ipv6, int port)
Definition: sensor.py:83
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:49
list sort_ips(list ips, str querytype)
Definition: sensor.py:37