1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-14 06:38:17 +00:00

Add support for template variables in remote packages from Github

This commit is contained in:
Nate Clark 2025-02-18 18:50:32 -05:00
parent 74f7197543
commit 2f892b97ce
3 changed files with 44 additions and 35 deletions

View File

@ -1,8 +1,8 @@
from pathlib import Path
import esphome.config_validation as cv
from esphome import git, yaml_util
from esphome.config_helpers import merge_config
import esphome.config_validation as cv
from esphome.const import (
CONF_ESPHOME,
CONF_FILE,
@ -14,8 +14,9 @@ from esphome.const import (
CONF_REFRESH,
CONF_URL,
CONF_USERNAME,
CONF_VARS,
__version__ as ESPHOME_VERSION,
)
from esphome.const import __version__ as ESPHOME_VERSION
from esphome.core import EsphomeError
DOMAIN = CONF_PACKAGES
@ -81,6 +82,7 @@ BASE_SCHEMA = cv.All(
cv.Optional(CONF_REFRESH, default="1d"): cv.All(
cv.string, cv.source_refresh
),
cv.Optional(CONF_VARS): dict,
}
),
cv.has_at_least_one_key(CONF_FILE, CONF_FILES),
@ -107,6 +109,11 @@ def _process_base_package(config: dict) -> dict:
password=config.get(CONF_PASSWORD),
)
files: list[str] = config[CONF_FILES]
vars: dict = config.get(CONF_VARS)
if vars:
vars = {k: str(v) for k, v in vars.items()}
else:
vars = {}
def get_packages(files) -> dict:
packages = {}
@ -132,7 +139,7 @@ def _process_base_package(config: dict) -> dict:
f"Current ESPHome Version is too old to use this package: {ESPHOME_VERSION} < {min_version}"
)
packages[file] = new_yaml
packages[file] = yaml_util.substitute_vars(new_yaml, vars)
except EsphomeError as e:
raise cv.Invalid(
f"{file} is not a valid YAML file. Please check the file contents.\n{e}"

View File

@ -927,6 +927,7 @@ CONF_VALUE = "value"
CONF_VALUE_FONT = "value_font"
CONF_VARIABLES = "variables"
CONF_VARIANT = "variant"
CONF_VARS = "vars"
CONF_VERSION = "version"
CONF_VIBRATIONS = "vibrations"
CONF_VISIBLE = "visible"

View File

@ -283,38 +283,6 @@ class ESPHomeLoaderMixin:
vars = {k: str(v) for k, v in vars.items()}
return file, vars
def substitute_vars(config, vars):
from esphome.components import substitutions
from esphome.const import CONF_DEFAULTS, CONF_SUBSTITUTIONS
org_subs = None
result = config
if not isinstance(config, dict):
# when the included yaml contains a list or a scalar
# wrap it into an OrderedDict because do_substitution_pass expects it
result = OrderedDict([("yaml", config)])
elif CONF_SUBSTITUTIONS in result:
org_subs = result.pop(CONF_SUBSTITUTIONS)
defaults = {}
if CONF_DEFAULTS in result:
defaults = result.pop(CONF_DEFAULTS)
result[CONF_SUBSTITUTIONS] = vars
for k, v in defaults.items():
if k not in result[CONF_SUBSTITUTIONS]:
result[CONF_SUBSTITUTIONS][k] = v
# Ignore missing vars that refer to the top level substitutions
substitutions.do_substitution_pass(result, None, ignore_missing=True)
result.pop(CONF_SUBSTITUTIONS)
if not isinstance(config, dict):
result = result["yaml"] # unwrap the result
elif org_subs:
result[CONF_SUBSTITUTIONS] = org_subs
return result
if isinstance(node, yaml.nodes.MappingNode):
file, vars = extract_file_vars(node)
else:
@ -482,6 +450,39 @@ def _find_files(directory, pattern):
yield filename
def substitute_vars(config, vars):
from esphome.components import substitutions
from esphome.const import CONF_DEFAULTS, CONF_SUBSTITUTIONS
org_subs = None
result = config
if not isinstance(config, dict):
# when the included yaml contains a list or a scalar
# wrap it into an OrderedDict because do_substitution_pass expects it
result = OrderedDict([("yaml", config)])
elif CONF_SUBSTITUTIONS in result:
org_subs = result.pop(CONF_SUBSTITUTIONS)
defaults = {}
if CONF_DEFAULTS in result:
defaults = result.pop(CONF_DEFAULTS)
result[CONF_SUBSTITUTIONS] = vars
for k, v in defaults.items():
if k not in result[CONF_SUBSTITUTIONS]:
result[CONF_SUBSTITUTIONS][k] = v
# Ignore missing vars that refer to the top level substitutions
substitutions.do_substitution_pass(result, None, ignore_missing=True)
result.pop(CONF_SUBSTITUTIONS)
if not isinstance(config, dict):
result = result["yaml"] # unwrap the result
elif org_subs:
result[CONF_SUBSTITUTIONS] = org_subs
return result
def is_secret(value):
try:
return _SECRET_VALUES[str(value)]