Home Assistant Unofficial Reference 2024.12.1
schemas.py
Go to the documentation of this file.
1 """Shared schemas for MQTT discovery and YAML config items."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 import voluptuous as vol
8 
9 from homeassistant.const import (
10  CONF_DEVICE,
11  CONF_ENTITY_CATEGORY,
12  CONF_ICON,
13  CONF_MODEL,
14  CONF_MODEL_ID,
15  CONF_NAME,
16  CONF_PLATFORM,
17  CONF_UNIQUE_ID,
18  CONF_VALUE_TEMPLATE,
19 )
20 from homeassistant.helpers import config_validation as cv
21 from homeassistant.helpers.entity import ENTITY_CATEGORIES_SCHEMA
22 from homeassistant.helpers.typing import ConfigType
23 
24 from .const import (
25  AVAILABILITY_LATEST,
26  AVAILABILITY_MODES,
27  CONF_AVAILABILITY,
28  CONF_AVAILABILITY_MODE,
29  CONF_AVAILABILITY_TEMPLATE,
30  CONF_AVAILABILITY_TOPIC,
31  CONF_COMMAND_TOPIC,
32  CONF_COMPONENTS,
33  CONF_CONFIGURATION_URL,
34  CONF_CONNECTIONS,
35  CONF_DEPRECATED_VIA_HUB,
36  CONF_ENABLED_BY_DEFAULT,
37  CONF_ENCODING,
38  CONF_ENTITY_PICTURE,
39  CONF_HW_VERSION,
40  CONF_IDENTIFIERS,
41  CONF_JSON_ATTRS_TEMPLATE,
42  CONF_JSON_ATTRS_TOPIC,
43  CONF_MANUFACTURER,
44  CONF_OBJECT_ID,
45  CONF_ORIGIN,
46  CONF_PAYLOAD_AVAILABLE,
47  CONF_PAYLOAD_NOT_AVAILABLE,
48  CONF_QOS,
49  CONF_SERIAL_NUMBER,
50  CONF_STATE_TOPIC,
51  CONF_SUGGESTED_AREA,
52  CONF_SUPPORT_URL,
53  CONF_SW_VERSION,
54  CONF_TOPIC,
55  CONF_VIA_DEVICE,
56  DEFAULT_PAYLOAD_AVAILABLE,
57  DEFAULT_PAYLOAD_NOT_AVAILABLE,
58  ENTITY_PLATFORMS,
59  SUPPORTED_COMPONENTS,
60 )
61 from .util import valid_publish_topic, valid_qos_schema, valid_subscribe_topic
62 
63 # Device discovery options that are also available at entity component level
64 SHARED_OPTIONS = [
65  CONF_AVAILABILITY,
66  CONF_AVAILABILITY_MODE,
67  CONF_AVAILABILITY_TEMPLATE,
68  CONF_AVAILABILITY_TOPIC,
69  CONF_COMMAND_TOPIC,
70  CONF_PAYLOAD_AVAILABLE,
71  CONF_PAYLOAD_NOT_AVAILABLE,
72  CONF_STATE_TOPIC,
73 ]
74 
75 MQTT_ORIGIN_INFO_SCHEMA = vol.All(
76  vol.Schema(
77  {
78  vol.Required(CONF_NAME): cv.string,
79  vol.Optional(CONF_SW_VERSION): cv.string,
80  vol.Optional(CONF_SUPPORT_URL): cv.configuration_url,
81  }
82  ),
83 )
84 
85 _MQTT_AVAILABILITY_SINGLE_SCHEMA = vol.Schema(
86  {
87  vol.Exclusive(CONF_AVAILABILITY_TOPIC, "availability"): valid_subscribe_topic,
88  vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template,
89  vol.Optional(
90  CONF_PAYLOAD_AVAILABLE, default=DEFAULT_PAYLOAD_AVAILABLE
91  ): cv.string,
92  vol.Optional(
93  CONF_PAYLOAD_NOT_AVAILABLE, default=DEFAULT_PAYLOAD_NOT_AVAILABLE
94  ): cv.string,
95  }
96 )
97 
98 _MQTT_AVAILABILITY_LIST_SCHEMA = vol.Schema(
99  {
100  vol.Optional(CONF_AVAILABILITY_MODE, default=AVAILABILITY_LATEST): vol.All(
101  cv.string, vol.In(AVAILABILITY_MODES)
102  ),
103  vol.Exclusive(CONF_AVAILABILITY, "availability"): vol.All(
104  cv.ensure_list,
105  [
106  {
107  vol.Required(CONF_TOPIC): valid_subscribe_topic,
108  vol.Optional(
109  CONF_PAYLOAD_AVAILABLE, default=DEFAULT_PAYLOAD_AVAILABLE
110  ): cv.string,
111  vol.Optional(
112  CONF_PAYLOAD_NOT_AVAILABLE,
113  default=DEFAULT_PAYLOAD_NOT_AVAILABLE,
114  ): cv.string,
115  vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
116  }
117  ],
118  ),
119  }
120 )
121 
122 _MQTT_AVAILABILITY_SCHEMA = _MQTT_AVAILABILITY_SINGLE_SCHEMA.extend(
123  _MQTT_AVAILABILITY_LIST_SCHEMA.schema
124 )
125 
126 
127 def validate_device_has_at_least_one_identifier(value: ConfigType) -> ConfigType:
128  """Validate that a device info entry has at least one identifying value."""
129  if value.get(CONF_IDENTIFIERS) or value.get(CONF_CONNECTIONS):
130  return value
131  raise vol.Invalid(
132  "Device must have at least one identifying value in "
133  "'identifiers' and/or 'connections'"
134  )
135 
136 
137 MQTT_ENTITY_DEVICE_INFO_SCHEMA = vol.All(
138  cv.deprecated(CONF_DEPRECATED_VIA_HUB, CONF_VIA_DEVICE),
139  vol.Schema(
140  {
141  vol.Optional(CONF_IDENTIFIERS, default=list): vol.All(
142  cv.ensure_list, [cv.string]
143  ),
144  vol.Optional(CONF_CONNECTIONS, default=list): vol.All(
145  cv.ensure_list, [vol.All(vol.Length(2), [cv.string])]
146  ),
147  vol.Optional(CONF_MANUFACTURER): cv.string,
148  vol.Optional(CONF_MODEL): cv.string,
149  vol.Optional(CONF_MODEL_ID): cv.string,
150  vol.Optional(CONF_NAME): cv.string,
151  vol.Optional(CONF_HW_VERSION): cv.string,
152  vol.Optional(CONF_SERIAL_NUMBER): cv.string,
153  vol.Optional(CONF_SW_VERSION): cv.string,
154  vol.Optional(CONF_VIA_DEVICE): cv.string,
155  vol.Optional(CONF_SUGGESTED_AREA): cv.string,
156  vol.Optional(CONF_CONFIGURATION_URL): cv.configuration_url,
157  }
158  ),
159  validate_device_has_at_least_one_identifier,
160 )
161 
162 
163 MQTT_ORIGIN_INFO_SCHEMA = vol.All(
164  vol.Schema(
165  {
166  vol.Required(CONF_NAME): cv.string,
167  vol.Optional(CONF_SW_VERSION): cv.string,
168  vol.Optional(CONF_SUPPORT_URL): cv.configuration_url,
169  }
170  ),
171 )
172 
173 MQTT_ENTITY_COMMON_SCHEMA = _MQTT_AVAILABILITY_SCHEMA.extend(
174  {
175  vol.Optional(CONF_DEVICE): MQTT_ENTITY_DEVICE_INFO_SCHEMA,
176  vol.Optional(CONF_ENTITY_PICTURE): cv.url,
177  vol.Optional(CONF_ORIGIN): MQTT_ORIGIN_INFO_SCHEMA,
178  vol.Optional(CONF_ENABLED_BY_DEFAULT, default=True): cv.boolean,
179  vol.Optional(CONF_ENTITY_CATEGORY): ENTITY_CATEGORIES_SCHEMA,
180  vol.Optional(CONF_ICON): cv.icon,
181  vol.Optional(CONF_JSON_ATTRS_TOPIC): valid_subscribe_topic,
182  vol.Optional(CONF_JSON_ATTRS_TEMPLATE): cv.template,
183  vol.Optional(CONF_OBJECT_ID): cv.string,
184  vol.Optional(CONF_UNIQUE_ID): cv.string,
185  }
186 )
187 
188 _UNIQUE_ID_SCHEMA = vol.Schema(
189  {vol.Required(CONF_UNIQUE_ID): cv.string},
190 ).extend({}, extra=True)
191 
192 
193 def check_unique_id(config: dict[str, Any]) -> dict[str, Any]:
194  """Check if a unique ID is set in case an entity platform is configured."""
195  platform = config[CONF_PLATFORM]
196  if platform in ENTITY_PLATFORMS and len(config.keys()) > 1:
197  _UNIQUE_ID_SCHEMA(config)
198  return config
199 
200 
201 _COMPONENT_CONFIG_SCHEMA = vol.All(
202  vol.Schema(
203  {vol.Required(CONF_PLATFORM): vol.In(SUPPORTED_COMPONENTS)},
204  ).extend({}, extra=True),
205  check_unique_id,
206 )
207 
208 DEVICE_DISCOVERY_SCHEMA = _MQTT_AVAILABILITY_SCHEMA.extend(
209  {
210  vol.Required(CONF_DEVICE): MQTT_ENTITY_DEVICE_INFO_SCHEMA,
211  vol.Required(CONF_COMPONENTS): vol.Schema({str: _COMPONENT_CONFIG_SCHEMA}),
212  vol.Required(CONF_ORIGIN): MQTT_ORIGIN_INFO_SCHEMA,
213  vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
214  vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic,
215  vol.Optional(CONF_QOS): valid_qos_schema,
216  vol.Optional(CONF_ENCODING): cv.string,
217  }
218 )
dict[str, Any] check_unique_id(dict[str, Any] config)
Definition: schemas.py:193
ConfigType validate_device_has_at_least_one_identifier(ConfigType value)
Definition: schemas.py:127