Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Common code for TCP component."""
2 
3 from __future__ import annotations
4 
5 import logging
6 import select
7 import socket
8 import ssl
9 from typing import Final
10 
11 from homeassistant.const import (
12  CONF_HOST,
13  CONF_NAME,
14  CONF_PAYLOAD,
15  CONF_PORT,
16  CONF_SSL,
17  CONF_TIMEOUT,
18  CONF_UNIT_OF_MEASUREMENT,
19  CONF_VALUE_TEMPLATE,
20  CONF_VERIFY_SSL,
21 )
22 from homeassistant.core import HomeAssistant
23 from homeassistant.exceptions import TemplateError
24 from homeassistant.helpers.entity import Entity
25 from homeassistant.helpers.typing import ConfigType
26 
27 from .const import CONF_BUFFER_SIZE, CONF_VALUE_ON
28 from .model import TcpSensorConfig
29 
30 _LOGGER: Final = logging.getLogger(__name__)
31 
32 
34  """Base entity class for TCP platform."""
35 
36  def __init__(self, hass: HomeAssistant, config: ConfigType) -> None:
37  """Set all the config values if they exist and get initial state."""
38 
39  self._hass_hass = hass
40  self._config: TcpSensorConfig = {
41  CONF_NAME: config[CONF_NAME],
42  CONF_HOST: config[CONF_HOST],
43  CONF_PORT: config[CONF_PORT],
44  CONF_TIMEOUT: config[CONF_TIMEOUT],
45  CONF_PAYLOAD: config[CONF_PAYLOAD],
46  CONF_UNIT_OF_MEASUREMENT: config.get(CONF_UNIT_OF_MEASUREMENT),
47  CONF_VALUE_TEMPLATE: config.get(CONF_VALUE_TEMPLATE),
48  CONF_VALUE_ON: config.get(CONF_VALUE_ON),
49  CONF_BUFFER_SIZE: config[CONF_BUFFER_SIZE],
50  CONF_SSL: config[CONF_SSL],
51  CONF_VERIFY_SSL: config[CONF_VERIFY_SSL],
52  }
53 
54  self._ssl_context_ssl_context: ssl.SSLContext | None = None
55  if self._config[CONF_SSL]:
56  self._ssl_context_ssl_context = ssl.create_default_context()
57  if not self._config[CONF_VERIFY_SSL]:
58  self._ssl_context_ssl_context.check_hostname = False
59  self._ssl_context_ssl_context.verify_mode = ssl.CERT_NONE
60 
61  self._state_state: str | None = None
62  self.updateupdate()
63 
64  @property
65  def name(self) -> str:
66  """Return the name of this sensor."""
67  return self._config[CONF_NAME]
68 
69  def update(self) -> None:
70  """Get the latest value for this sensor."""
71  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
72  sock.settimeout(self._config[CONF_TIMEOUT])
73  try:
74  sock.connect((self._config[CONF_HOST], self._config[CONF_PORT]))
75  except OSError as err:
76  _LOGGER.error(
77  "Unable to connect to %s on port %s: %s",
78  self._config[CONF_HOST],
79  self._config[CONF_PORT],
80  err,
81  )
82  return
83 
84  if self._ssl_context_ssl_context is not None:
85  sock = self._ssl_context_ssl_context.wrap_socket(
86  sock, server_hostname=self._config[CONF_HOST]
87  )
88 
89  try:
90  sock.send(self._config[CONF_PAYLOAD].encode())
91  except OSError as err:
92  _LOGGER.error(
93  "Unable to send payload %r to %s on port %s: %s",
94  self._config[CONF_PAYLOAD],
95  self._config[CONF_HOST],
96  self._config[CONF_PORT],
97  err,
98  )
99  return
100 
101  readable, _, _ = select.select([sock], [], [], self._config[CONF_TIMEOUT])
102  if not readable:
103  _LOGGER.warning(
104  (
105  "Timeout (%s second(s)) waiting for a response after "
106  "sending %r to %s on port %s"
107  ),
108  self._config[CONF_TIMEOUT],
109  self._config[CONF_PAYLOAD],
110  self._config[CONF_HOST],
111  self._config[CONF_PORT],
112  )
113  return
114 
115  value = sock.recv(self._config[CONF_BUFFER_SIZE]).decode()
116 
117  value_template = self._config[CONF_VALUE_TEMPLATE]
118  if value_template is not None:
119  try:
120  self._state_state = value_template.render(parse_result=False, value=value)
121  except TemplateError:
122  _LOGGER.error(
123  "Unable to render template of %r with value: %r",
124  self._config[CONF_VALUE_TEMPLATE],
125  value,
126  )
127  return
128  return
129 
130  self._state_state = value
None __init__(self, HomeAssistant hass, ConfigType config)
Definition: entity.py:36