Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """KIRA interface to receive UDP packets from an IR-IP bridge."""
2 
3 import logging
4 import os
5 
6 import pykira
7 import voluptuous as vol
8 from voluptuous.error import Error as VoluptuousError
9 import yaml
10 
11 from homeassistant.const import (
12  CONF_CODE,
13  CONF_DEVICE,
14  CONF_HOST,
15  CONF_NAME,
16  CONF_PORT,
17  CONF_REPEAT,
18  CONF_SENSORS,
19  CONF_TYPE,
20  EVENT_HOMEASSISTANT_STOP,
21  STATE_UNKNOWN,
22 )
23 from homeassistant.core import HomeAssistant
24 from homeassistant.helpers import discovery
26 from homeassistant.helpers.typing import ConfigType
27 
28 DOMAIN = "kira"
29 
30 _LOGGER = logging.getLogger(__name__)
31 
32 DEFAULT_HOST = "0.0.0.0"
33 DEFAULT_PORT = 65432
34 
35 CONF_REMOTES = "remotes"
36 CONF_SENSOR = "sensor"
37 CONF_REMOTE = "remote"
38 
39 CODES_YAML = f"{DOMAIN}_codes.yaml"
40 
41 CODE_SCHEMA = vol.Schema(
42  {
43  vol.Required(CONF_NAME): cv.string,
44  vol.Required(CONF_CODE): cv.string,
45  vol.Optional(CONF_TYPE): cv.string,
46  vol.Optional(CONF_DEVICE): cv.string,
47  vol.Optional(CONF_REPEAT): cv.positive_int,
48  }
49 )
50 
51 SENSOR_SCHEMA = vol.Schema(
52  {
53  vol.Optional(CONF_NAME, default=DOMAIN): vol.Exclusive(cv.string, "sensors"),
54  vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
55  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
56  }
57 )
58 
59 REMOTE_SCHEMA = vol.Schema(
60  {
61  vol.Optional(CONF_NAME, default=DOMAIN): vol.Exclusive(cv.string, "remotes"),
62  vol.Required(CONF_HOST): cv.string,
63  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
64  }
65 )
66 
67 CONFIG_SCHEMA = vol.Schema(
68  {
69  DOMAIN: vol.Schema(
70  {
71  vol.Optional(CONF_SENSORS): [SENSOR_SCHEMA],
72  vol.Optional(CONF_REMOTES): [REMOTE_SCHEMA],
73  }
74  )
75  },
76  extra=vol.ALLOW_EXTRA,
77 )
78 
79 
80 def load_codes(path):
81  """Load KIRA codes from specified file."""
82  codes = []
83  if os.path.exists(path):
84  with open(path, encoding="utf8") as code_file:
85  data = yaml.safe_load(code_file) or []
86  for code in data:
87  try:
88  codes.append(CODE_SCHEMA(code))
89  except VoluptuousError as exception:
90  # keep going
91  _LOGGER.warning("KIRA code invalid data: %s", exception)
92  else:
93  with open(path, "w", encoding="utf8") as code_file:
94  code_file.write("")
95  return codes
96 
97 
98 def setup(hass: HomeAssistant, config: ConfigType) -> bool:
99  """Set up the KIRA component."""
100  sensors = config.get(DOMAIN, {}).get(CONF_SENSORS, [])
101  remotes = config.get(DOMAIN, {}).get(CONF_REMOTES, [])
102  # If no sensors or remotes were specified, add a sensor
103  if not (sensors or remotes):
104  sensors.append({})
105 
106  codes = load_codes(hass.config.path(CODES_YAML))
107 
108  hass.data[DOMAIN] = {CONF_SENSOR: {}, CONF_REMOTE: {}}
109 
110  def load_module(platform, idx, module_conf):
111  """Set up the KIRA module and load platform."""
112  # note: module_name is not the HA device name. it's just a unique name
113  # to ensure the component and platform can share information
114  module_name = f"{DOMAIN}_{idx}" if idx else DOMAIN
115  device_name = module_conf.get(CONF_NAME, DOMAIN)
116  port = module_conf.get(CONF_PORT, DEFAULT_PORT)
117  host = module_conf.get(CONF_HOST, DEFAULT_HOST)
118 
119  if platform == CONF_SENSOR:
120  module = pykira.KiraReceiver(host, port)
121  module.start()
122  else:
123  module = pykira.KiraModule(host, port)
124 
125  hass.data[DOMAIN][platform][module_name] = module
126  for code in codes:
127  code_tuple = (code.get(CONF_NAME), code.get(CONF_DEVICE, STATE_UNKNOWN))
128  module.registerCode(code_tuple, code.get(CONF_CODE))
129 
130  discovery.load_platform(
131  hass, platform, DOMAIN, {"name": module_name, "device": device_name}, config
132  )
133 
134  for idx, module_conf in enumerate(sensors):
135  load_module(CONF_SENSOR, idx, module_conf)
136 
137  for idx, module_conf in enumerate(remotes):
138  load_module(CONF_REMOTE, idx, module_conf)
139 
140  def _stop_kira(_event):
141  """Stop the KIRA receiver."""
142  for receiver in hass.data[DOMAIN][CONF_SENSOR].values():
143  receiver.stop()
144  _LOGGER.debug("Terminated receivers")
145 
146  hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, _stop_kira)
147 
148  return True
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
bool setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:98
None open(self, **Any kwargs)
Definition: lock.py:86