mirror of
https://github.com/esphome/esphome.git
synced 2025-01-30 23:02:14 +01:00
[core] add support for custom platform (#7616)
Co-authored-by: Tomasz Duda <tomaszduda23@gmai.com>
This commit is contained in:
parent
5a103543c4
commit
0c032bc431
@ -19,6 +19,7 @@ from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS
|
||||
|
||||
CODEOWNERS = ["@kuba2k2"]
|
||||
AUTO_LOAD = ["libretiny"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
COMPONENT_DATA = LibreTinyComponent(
|
||||
name=COMPONENT_BK72XX,
|
||||
|
@ -64,6 +64,7 @@ from .gpio import esp32_pin_to_code # noqa
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
AUTO_LOAD = ["preferences"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
CONF_RELEASE = "release"
|
||||
|
||||
|
@ -34,6 +34,7 @@ from .gpio import PinInitialState, add_pin_initial_states_array
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
AUTO_LOAD = ["preferences"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
|
||||
def set_core_data(config):
|
||||
|
@ -17,6 +17,7 @@ from .gpio import host_pin_to_code # noqa
|
||||
|
||||
CODEOWNERS = ["@esphome/core", "@clydebarrow"]
|
||||
AUTO_LOAD = ["network", "preferences"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
|
||||
def set_core_data(config):
|
||||
|
@ -47,6 +47,7 @@ from .const import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CODEOWNERS = ["@kuba2k2"]
|
||||
AUTO_LOAD = ["preferences"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
|
||||
def _detect_variant(value):
|
||||
|
@ -27,6 +27,7 @@ from .gpio import rp2040_pin_to_code # noqa
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
AUTO_LOAD = ["preferences"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
|
||||
def set_core_data(config):
|
||||
|
@ -19,6 +19,8 @@ from .boards import RTL87XX_BOARD_PINS, RTL87XX_BOARDS
|
||||
|
||||
CODEOWNERS = ["@kuba2k2"]
|
||||
AUTO_LOAD = ["libretiny"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
|
||||
|
||||
COMPONENT_DATA = LibreTinyComponent(
|
||||
name=COMPONENT_RTL87XX,
|
||||
|
@ -22,7 +22,6 @@ from esphome.const import (
|
||||
CONF_PACKAGES,
|
||||
CONF_PLATFORM,
|
||||
CONF_SUBSTITUTIONS,
|
||||
TARGET_PLATFORMS,
|
||||
)
|
||||
from esphome.core import CORE, DocumentRange, EsphomeError
|
||||
import esphome.core.config as core_config
|
||||
@ -833,7 +832,7 @@ def validate_config(
|
||||
result[CONF_ESPHOME] = config[CONF_ESPHOME]
|
||||
result.add_output_path([CONF_ESPHOME], CONF_ESPHOME)
|
||||
try:
|
||||
core_config.preload_core_config(config, result)
|
||||
target_platform = core_config.preload_core_config(config, result)
|
||||
except vol.Invalid as err:
|
||||
result.add_error(err)
|
||||
return result
|
||||
@ -845,9 +844,9 @@ def validate_config(
|
||||
cv.All(cv.version_number, cv.validate_esphome_version)(min_version)
|
||||
|
||||
# First run platform validation steps
|
||||
for key in TARGET_PLATFORMS:
|
||||
if key in config:
|
||||
result.add_validation_step(LoadValidationStep(key, config[key]))
|
||||
result.add_validation_step(
|
||||
LoadValidationStep(target_platform, config[target_platform])
|
||||
)
|
||||
result.run_validation_steps()
|
||||
|
||||
if result.errors:
|
||||
|
@ -15,15 +15,6 @@ PLATFORM_LIBRETINY_OLDSTYLE = "libretiny"
|
||||
PLATFORM_RP2040 = "rp2040"
|
||||
PLATFORM_RTL87XX = "rtl87xx"
|
||||
|
||||
TARGET_PLATFORMS = [
|
||||
PLATFORM_BK72XX,
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
PLATFORM_HOST,
|
||||
PLATFORM_LIBRETINY_OLDSTYLE,
|
||||
PLATFORM_RP2040,
|
||||
PLATFORM_RTL87XX,
|
||||
]
|
||||
|
||||
SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"}
|
||||
HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
@ -28,7 +29,6 @@ from esphome.const import (
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_VERSION,
|
||||
KEY_CORE,
|
||||
TARGET_PLATFORMS,
|
||||
__version__ as ESPHOME_VERSION,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
@ -174,7 +174,31 @@ PRELOAD_CONFIG_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
def preload_core_config(config, result):
|
||||
def _is_target_platform(name):
|
||||
from esphome.loader import get_component
|
||||
|
||||
try:
|
||||
if get_component(name, True).is_target_platform:
|
||||
return True
|
||||
except KeyError:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def _list_target_platforms():
|
||||
target_platforms = []
|
||||
root = Path(__file__).parents[1]
|
||||
for path in (root / "components").iterdir():
|
||||
if not path.is_dir():
|
||||
continue
|
||||
if not (path / "__init__.py").is_file():
|
||||
continue
|
||||
if _is_target_platform(path.name):
|
||||
target_platforms += [path.name]
|
||||
return target_platforms
|
||||
|
||||
|
||||
def preload_core_config(config, result) -> str:
|
||||
with cv.prepend_path(CONF_ESPHOME):
|
||||
conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME])
|
||||
|
||||
@ -187,12 +211,16 @@ def preload_core_config(config, result):
|
||||
conf[CONF_BUILD_PATH] = os.path.join(build_path, CORE.name)
|
||||
CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH])
|
||||
|
||||
target_platforms = [key for key in TARGET_PLATFORMS if key in config]
|
||||
target_platforms = []
|
||||
|
||||
for domain, _ in config.items():
|
||||
if _is_target_platform(domain):
|
||||
target_platforms += [domain]
|
||||
|
||||
if not target_platforms:
|
||||
raise cv.Invalid(
|
||||
"Platform missing. You must include one of the available platform keys: "
|
||||
+ ", ".join(TARGET_PLATFORMS),
|
||||
+ ", ".join(_list_target_platforms()),
|
||||
[CONF_ESPHOME],
|
||||
)
|
||||
if len(target_platforms) > 1:
|
||||
@ -202,6 +230,7 @@ def preload_core_config(config, result):
|
||||
)
|
||||
|
||||
config[CONF_ESPHOME] = conf
|
||||
return target_platforms[0]
|
||||
|
||||
|
||||
def include_file(path, basename):
|
||||
|
@ -52,6 +52,10 @@ class ComponentManifest:
|
||||
def is_platform_component(self) -> bool:
|
||||
return getattr(self.module, "IS_PLATFORM_COMPONENT", False)
|
||||
|
||||
@property
|
||||
def is_target_platform(self) -> bool:
|
||||
return getattr(self.module, "IS_TARGET_PLATFORM", False)
|
||||
|
||||
@property
|
||||
def config_schema(self) -> Optional[Any]:
|
||||
return getattr(self.module, "CONFIG_SCHEMA", None)
|
||||
@ -169,13 +173,15 @@ def install_custom_components_meta_finder():
|
||||
install_meta_finder(custom_components_dir)
|
||||
|
||||
|
||||
def _lookup_module(domain):
|
||||
def _lookup_module(domain, exception):
|
||||
if domain in _COMPONENT_CACHE:
|
||||
return _COMPONENT_CACHE[domain]
|
||||
|
||||
try:
|
||||
module = importlib.import_module(f"esphome.components.{domain}")
|
||||
except ImportError as e:
|
||||
if exception:
|
||||
raise
|
||||
if "No module named" in str(e):
|
||||
_LOGGER.info(
|
||||
"Unable to import component %s: %s", domain, str(e), exc_info=False
|
||||
@ -184,6 +190,8 @@ def _lookup_module(domain):
|
||||
_LOGGER.error("Unable to import component %s:", domain, exc_info=True)
|
||||
return None
|
||||
except Exception: # pylint: disable=broad-except
|
||||
if exception:
|
||||
raise
|
||||
_LOGGER.error("Unable to load component %s:", domain, exc_info=True)
|
||||
return None
|
||||
|
||||
@ -192,14 +200,14 @@ def _lookup_module(domain):
|
||||
return manif
|
||||
|
||||
|
||||
def get_component(domain):
|
||||
def get_component(domain, exception=False):
|
||||
assert "." not in domain
|
||||
return _lookup_module(domain)
|
||||
return _lookup_module(domain, exception)
|
||||
|
||||
|
||||
def get_platform(domain, platform):
|
||||
full = f"{platform}.{domain}"
|
||||
return _lookup_module(full)
|
||||
return _lookup_module(full, False)
|
||||
|
||||
|
||||
_COMPONENT_CACHE = {}
|
||||
|
Loading…
Reference in New Issue
Block a user