Home Assistant Unofficial Reference 2024.12.1
schemas.py
Go to the documentation of this file.
1 """Schemas for the blueprint integration."""
2 
3 from typing import Any
4 
5 import voluptuous as vol
6 
7 from homeassistant.const import (
8  CONF_DEFAULT,
9  CONF_DESCRIPTION,
10  CONF_DOMAIN,
11  CONF_ICON,
12  CONF_NAME,
13  CONF_PATH,
14  CONF_SELECTOR,
15 )
16 from homeassistant.core import callback
17 from homeassistant.helpers import config_validation as cv, selector
18 
19 from .const import (
20  CONF_AUTHOR,
21  CONF_BLUEPRINT,
22  CONF_COLLAPSED,
23  CONF_HOMEASSISTANT,
24  CONF_INPUT,
25  CONF_MIN_VERSION,
26  CONF_SOURCE_URL,
27  CONF_USE_BLUEPRINT,
28 )
29 
30 
31 def version_validator(value: Any) -> str:
32  """Validate a Home Assistant version."""
33  if not isinstance(value, str):
34  raise vol.Invalid("Version needs to be a string")
35 
36  parts = value.split(".")
37 
38  if len(parts) != 3:
39  raise vol.Invalid("Version needs to be formatted as {major}.{minor}.{patch}")
40 
41  try:
42  [int(p) for p in parts]
43  except ValueError:
44  raise vol.Invalid(
45  "Major, minor and patch version needs to be an integer"
46  ) from None
47 
48  return value
49 
50 
51 def unique_input_validator(inputs: Any) -> Any:
52  """Validate the inputs don't have duplicate keys under different sections."""
53  all_inputs = set()
54  for key, value in inputs.items():
55  if value and CONF_INPUT in value:
56  for key in value[CONF_INPUT]:
57  if key in all_inputs:
58  raise vol.Invalid(f"Duplicate use of input key {key} in blueprint.")
59  all_inputs.add(key)
60  else:
61  if key in all_inputs:
62  raise vol.Invalid(f"Duplicate use of input key {key} in blueprint.")
63  all_inputs.add(key)
64 
65  return inputs
66 
67 
68 @callback
69 def is_blueprint_config(config: Any) -> bool:
70  """Return if it is a blueprint config."""
71  return isinstance(config, dict) and CONF_BLUEPRINT in config
72 
73 
74 @callback
75 def is_blueprint_instance_config(config: Any) -> bool:
76  """Return if it is a blueprint instance config."""
77  return isinstance(config, dict) and CONF_USE_BLUEPRINT in config
78 
79 
80 BLUEPRINT_INPUT_SCHEMA = vol.Schema(
81  {
82  vol.Optional(CONF_NAME): str,
83  vol.Optional(CONF_DESCRIPTION): str,
84  vol.Optional(CONF_DEFAULT): cv.match_all,
85  vol.Optional(CONF_SELECTOR): selector.validate_selector,
86  }
87 )
88 
89 BLUEPRINT_INPUT_SECTION_SCHEMA = vol.Schema(
90  {
91  vol.Optional(CONF_NAME): str,
92  vol.Optional(CONF_ICON): str,
93  vol.Optional(CONF_DESCRIPTION): str,
94  vol.Optional(CONF_COLLAPSED): bool,
95  vol.Required(CONF_INPUT, default=dict): {
96  str: vol.Any(
97  None,
98  BLUEPRINT_INPUT_SCHEMA,
99  )
100  },
101  }
102 )
103 
104 BLUEPRINT_SCHEMA = vol.Schema(
105  {
106  vol.Required(CONF_BLUEPRINT): vol.Schema(
107  {
108  vol.Required(CONF_NAME): str,
109  vol.Optional(CONF_DESCRIPTION): str,
110  vol.Required(CONF_DOMAIN): str,
111  vol.Optional(CONF_SOURCE_URL): cv.url,
112  vol.Optional(CONF_AUTHOR): str,
113  vol.Optional(CONF_HOMEASSISTANT): {
114  vol.Optional(CONF_MIN_VERSION): version_validator
115  },
116  vol.Optional(CONF_INPUT, default=dict): vol.All(
117  {
118  str: vol.Any(
119  None,
120  BLUEPRINT_INPUT_SCHEMA,
121  BLUEPRINT_INPUT_SECTION_SCHEMA,
122  )
123  },
124  unique_input_validator,
125  ),
126  }
127  ),
128  },
129  extra=vol.ALLOW_EXTRA,
130 )
131 
132 
133 def validate_yaml_suffix(value: str) -> str:
134  """Validate value has a YAML suffix."""
135  if not value.endswith(".yaml"):
136  raise vol.Invalid("Path needs to end in .yaml")
137  return value
138 
139 
140 BLUEPRINT_INSTANCE_FIELDS = vol.Schema(
141  {
142  vol.Required(CONF_USE_BLUEPRINT): vol.Schema(
143  {
144  vol.Required(CONF_PATH): vol.All(cv.path, validate_yaml_suffix),
145  vol.Required(CONF_INPUT, default=dict): {str: cv.match_all},
146  }
147  )
148  },
149  extra=vol.ALLOW_EXTRA,
150 )
bool is_blueprint_instance_config(Any config)
Definition: schemas.py:75