Home Assistant Unofficial Reference 2024.12.1
dongle.py
Go to the documentation of this file.
1 """Representation of an EnOcean dongle."""
2 
3 import glob
4 import logging
5 from os.path import basename, normpath
6 
7 from enocean.communicators import SerialCommunicator
8 from enocean.protocol.packet import RadioPacket
9 import serial
10 
11 from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
12 
13 from .const import SIGNAL_RECEIVE_MESSAGE, SIGNAL_SEND_MESSAGE
14 
15 _LOGGER = logging.getLogger(__name__)
16 
17 
19  """Representation of an EnOcean dongle.
20 
21  The dongle is responsible for receiving the ENOcean frames,
22  creating devices if needed, and dispatching messages to platforms.
23  """
24 
25  def __init__(self, hass, serial_path):
26  """Initialize the EnOcean dongle."""
27 
28  self._communicator_communicator = SerialCommunicator(
29  port=serial_path, callback=self.callbackcallback
30  )
31  self.serial_pathserial_path = serial_path
32  self.identifieridentifier = basename(normpath(serial_path))
33  self.hasshass = hass
34  self.dispatcher_disconnect_handledispatcher_disconnect_handle = None
35 
36  async def async_setup(self):
37  """Finish the setup of the bridge and supported platforms."""
38  self._communicator_communicator.start()
39  self.dispatcher_disconnect_handledispatcher_disconnect_handle = async_dispatcher_connect(
40  self.hasshass, SIGNAL_SEND_MESSAGE, self._send_message_callback_send_message_callback
41  )
42 
43  def unload(self):
44  """Disconnect callbacks established at init time."""
45  if self.dispatcher_disconnect_handledispatcher_disconnect_handle:
46  self.dispatcher_disconnect_handledispatcher_disconnect_handle()
47  self.dispatcher_disconnect_handledispatcher_disconnect_handle = None
48 
49  def _send_message_callback(self, command):
50  """Send a command through the EnOcean dongle."""
51  self._communicator_communicator.send(command)
52 
53  def callback(self, packet):
54  """Handle EnOcean device's callback.
55 
56  This is the callback function called by python-enocan whenever there
57  is an incoming packet.
58  """
59 
60  if isinstance(packet, RadioPacket):
61  _LOGGER.debug("Received radio packet: %s", packet)
62  dispatcher_send(self.hasshass, SIGNAL_RECEIVE_MESSAGE, packet)
63 
64 
65 def detect():
66  """Return a list of candidate paths for USB ENOcean dongles.
67 
68  This method is currently a bit simplistic, it may need to be
69  improved to support more configurations and OS.
70  """
71  globs_to_test = ["/dev/tty*FTOA2PV*", "/dev/serial/by-id/*EnOcean*"]
72  found_paths = []
73  for current_glob in globs_to_test:
74  found_paths.extend(glob.glob(current_glob))
75 
76  return found_paths
77 
78 
79 def validate_path(path: str):
80  """Return True if the provided path points to a valid serial port, False otherwise."""
81  try:
82  # Creating the serial communicator will raise an exception
83  # if it cannot connect
84  SerialCommunicator(port=path)
85  except serial.SerialException as exception:
86  _LOGGER.warning("Dongle path %s is invalid: %s", path, str(exception))
87  return False
88  return True
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103
None dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:137