Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Use serial protocol of Acer projector to obtain state of the projector."""
2 
3 from __future__ import annotations
4 
5 import logging
6 import re
7 from typing import Any
8 
9 import serial
10 import voluptuous as vol
11 
13  PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
14  SwitchEntity,
15 )
16 from homeassistant.const import (
17  CONF_FILENAME,
18  CONF_NAME,
19  CONF_TIMEOUT,
20  STATE_OFF,
21  STATE_ON,
22  STATE_UNKNOWN,
23 )
24 from homeassistant.core import HomeAssistant
26 from homeassistant.helpers.entity_platform import AddEntitiesCallback
27 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
28 
29 from .const import (
30  CMD_DICT,
31  CONF_WRITE_TIMEOUT,
32  DEFAULT_NAME,
33  DEFAULT_TIMEOUT,
34  DEFAULT_WRITE_TIMEOUT,
35  ECO_MODE,
36  ICON,
37  INPUT_SOURCE,
38  LAMP,
39  LAMP_HOURS,
40 )
41 
42 _LOGGER = logging.getLogger(__name__)
43 
44 PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
45  {
46  vol.Required(CONF_FILENAME): cv.isdevice,
47  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
48  vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
49  vol.Optional(
50  CONF_WRITE_TIMEOUT, default=DEFAULT_WRITE_TIMEOUT
51  ): cv.positive_int,
52  }
53 )
54 
55 
57  hass: HomeAssistant,
58  config: ConfigType,
59  add_entities: AddEntitiesCallback,
60  discovery_info: DiscoveryInfoType | None = None,
61 ) -> None:
62  """Connect with serial port and return Acer Projector."""
63  serial_port = config[CONF_FILENAME]
64  name = config[CONF_NAME]
65  timeout = config[CONF_TIMEOUT]
66  write_timeout = config[CONF_WRITE_TIMEOUT]
67 
68  add_entities([AcerSwitch(serial_port, name, timeout, write_timeout)], True)
69 
70 
72  """Represents an Acer Projector as a switch."""
73 
74  _attr_icon = ICON
75 
76  def __init__(
77  self,
78  serial_port: str,
79  name: str,
80  timeout: int,
81  write_timeout: int,
82  ) -> None:
83  """Init of the Acer projector."""
84  self.serialserial = serial.Serial(
85  port=serial_port, timeout=timeout, write_timeout=write_timeout
86  )
87  self._serial_port_serial_port = serial_port
88  self._attr_name_attr_name = name
89  self._attributes_attributes = {
90  LAMP_HOURS: STATE_UNKNOWN,
91  INPUT_SOURCE: STATE_UNKNOWN,
92  ECO_MODE: STATE_UNKNOWN,
93  }
94 
95  def _write_read(self, msg: str) -> str:
96  """Write to the projector and read the return."""
97  ret = ""
98  # Sometimes the projector won't answer for no reason or the projector
99  # was disconnected during runtime.
100  # This way the projector can be reconnected and will still work
101  try:
102  if not self.serialserial.is_open:
103  self.serialserial.open()
104  self.serialserial.write(msg.encode("utf-8"))
105  # Size is an experience value there is no real limit.
106  # AFAIK there is no limit and no end character so we will usually
107  # need to wait for timeout
108  ret = self.serialserial.read_until(size=20).decode("utf-8")
109  except serial.SerialException:
110  _LOGGER.error("Problem communicating with %s", self._serial_port_serial_port)
111  self.serialserial.close()
112  return ret
113 
114  def _write_read_format(self, msg: str) -> str:
115  """Write msg, obtain answer and format output."""
116  # answers are formatted as ***\answer\r***
117  awns = self._write_read_write_read(msg)
118  if match := re.search(r"\r(.+)\r", awns):
119  return match.group(1)
120  return STATE_UNKNOWN
121 
122  def update(self) -> None:
123  """Get the latest state from the projector."""
124  awns = self._write_read_format_write_read_format(CMD_DICT[LAMP])
125  if awns == "Lamp 1":
126  self._attr_is_on_attr_is_on = True
127  self._attr_available_attr_available = True
128  elif awns == "Lamp 0":
129  self._attr_is_on_attr_is_on = False
130  self._attr_available_attr_available = True
131  else:
132  self._attr_available_attr_available = False
133 
134  for key in self._attributes_attributes:
135  if msg := CMD_DICT.get(key):
136  awns = self._write_read_format_write_read_format(msg)
137  self._attributes_attributes[key] = awns
138  self._attr_extra_state_attributes_attr_extra_state_attributes = self._attributes_attributes
139 
140  def turn_on(self, **kwargs: Any) -> None:
141  """Turn the projector on."""
142  msg = CMD_DICT[STATE_ON]
143  self._write_read_write_read(msg)
144  self._attr_is_on_attr_is_on = True
145 
146  def turn_off(self, **kwargs: Any) -> None:
147  """Turn the projector off."""
148  msg = CMD_DICT[STATE_OFF]
149  self._write_read_write_read(msg)
150  self._attr_is_on_attr_is_on = False
None __init__(self, str serial_port, str name, int timeout, int write_timeout)
Definition: switch.py:82
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:61
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
None open(self, **Any kwargs)
Definition: lock.py:86