mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00:00 
			
		
		
		
	Allow validation of pins based on hub config (#5647)
This commit is contained in:
		| @@ -64,7 +64,7 @@ PCA6416A_PIN_SCHEMA = cv.All( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pins.PIN_SCHEMA_REGISTRY.register("pca6416a", PCA6416A_PIN_SCHEMA) | @pins.PIN_SCHEMA_REGISTRY.register(CONF_PCA6416A, PCA6416A_PIN_SCHEMA) | ||||||
| async def pca6416a_pin_to_code(config): | async def pca6416a_pin_to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     parent = await cg.get_variable(config[CONF_PCA6416A]) |     parent = await cg.get_variable(config[CONF_PCA6416A]) | ||||||
|   | |||||||
| @@ -92,7 +92,7 @@ PCA9554_PIN_SCHEMA = cv.All( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pins.PIN_SCHEMA_REGISTRY.register("pca9554", PCA9554_PIN_SCHEMA) | @pins.PIN_SCHEMA_REGISTRY.register(CONF_PCA9554, PCA9554_PIN_SCHEMA) | ||||||
| async def pca9554_pin_to_code(config): | async def pca9554_pin_to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     parent = await cg.get_variable(config[CONF_PCA9554]) |     parent = await cg.get_variable(config[CONF_PCA9554]) | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ PCF8574_PIN_SCHEMA = cv.All( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pins.PIN_SCHEMA_REGISTRY.register("pcf8574", PCF8574_PIN_SCHEMA) | @pins.PIN_SCHEMA_REGISTRY.register(CONF_PCF8574, PCF8574_PIN_SCHEMA) | ||||||
| async def pcf8574_pin_to_code(config): | async def pcf8574_pin_to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     parent = await cg.get_variable(config[CONF_PCF8574]) |     parent = await cg.get_variable(config[CONF_PCF8574]) | ||||||
|   | |||||||
| @@ -77,7 +77,15 @@ SN74HC165_PIN_SCHEMA = cv.All( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pins.PIN_SCHEMA_REGISTRY.register(CONF_SN74HC165, SN74HC165_PIN_SCHEMA) | def sn74hc165_pin_final_validate(pin_config, parent_config): | ||||||
|  |     max_pins = parent_config[CONF_SR_COUNT] * 8 | ||||||
|  |     if pin_config[CONF_NUMBER] >= max_pins: | ||||||
|  |         raise cv.Invalid(f"Pin number must be less than {max_pins}") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register( | ||||||
|  |     CONF_SN74HC165, SN74HC165_PIN_SCHEMA, sn74hc165_pin_final_validate | ||||||
|  | ) | ||||||
| async def sn74hc165_pin_to_code(config): | async def sn74hc165_pin_to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     await cg.register_parented(var, config[CONF_SN74HC165]) |     await cg.register_parented(var, config[CONF_SN74HC165]) | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ from contextlib import contextmanager | |||||||
|  |  | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
|  |  | ||||||
| from esphome import core, yaml_util, loader | from esphome import core, yaml_util, loader, pins | ||||||
| import esphome.core.config as core_config | import esphome.core.config as core_config | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_ESPHOME, |     CONF_ESPHOME, | ||||||
| @@ -645,14 +645,40 @@ class FinalValidateValidationStep(ConfigValidationStep): | |||||||
|             # If result already has errors, skip this step |             # If result already has errors, skip this step | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         if self.comp.final_validate_schema is None: |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         token = fv.full_config.set(result) |         token = fv.full_config.set(result) | ||||||
|  |  | ||||||
|         conf = result.get_nested_item(self.path) |         conf = result.get_nested_item(self.path) | ||||||
|         with result.catch_error(self.path): |         with result.catch_error(self.path): | ||||||
|             self.comp.final_validate_schema(conf) |             if self.comp.final_validate_schema is not None: | ||||||
|  |                 self.comp.final_validate_schema(conf) | ||||||
|  |  | ||||||
|  |             fconf = fv.full_config.get() | ||||||
|  |  | ||||||
|  |             def _check_pins(c): | ||||||
|  |                 for value in c.values(): | ||||||
|  |                     if not isinstance(value, dict): | ||||||
|  |                         continue | ||||||
|  |                     for key, ( | ||||||
|  |                         _, | ||||||
|  |                         _, | ||||||
|  |                         pin_final_validate, | ||||||
|  |                     ) in pins.PIN_SCHEMA_REGISTRY.items(): | ||||||
|  |                         if ( | ||||||
|  |                             key != CORE.target_platform | ||||||
|  |                             and key in value | ||||||
|  |                             and pin_final_validate is not None | ||||||
|  |                         ): | ||||||
|  |                             pin_final_validate(fconf, value) | ||||||
|  |  | ||||||
|  |             # Check for pin configs and a final_validate schema in the pin registry | ||||||
|  |             confs = conf | ||||||
|  |             if not isinstance( | ||||||
|  |                 confs, list | ||||||
|  |             ):  # Handle components like SPI that have a list instead of MULTI_CONF | ||||||
|  |                 confs = [conf] | ||||||
|  |             for c in confs: | ||||||
|  |                 if c:  # Some component have None or empty schemas | ||||||
|  |                     _check_pins(c) | ||||||
|  |  | ||||||
|         fv.full_config.reset(token) |         fv.full_config.reset(token) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ async def gpio_pin_expression(conf): | |||||||
|         return None |         return None | ||||||
|     from esphome import pins |     from esphome import pins | ||||||
|  |  | ||||||
|     for key, (func, _) in pins.PIN_SCHEMA_REGISTRY.items(): |     for key, (func, _, _) in pins.PIN_SCHEMA_REGISTRY.items(): | ||||||
|         if key in conf: |         if key in conf: | ||||||
|             return await coroutine(func)(conf) |             return await coroutine(func)(conf) | ||||||
|     return await coroutine(pins.PIN_SCHEMA_REGISTRY[CORE.target_platform][0])(conf) |     return await coroutine(pins.PIN_SCHEMA_REGISTRY[CORE.target_platform][0])(conf) | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ from esphome.const import ( | |||||||
|     CONF_PULLUP, |     CONF_PULLUP, | ||||||
|     CONF_IGNORE_STRAPPING_WARNING, |     CONF_IGNORE_STRAPPING_WARNING, | ||||||
| ) | ) | ||||||
| from esphome.util import SimpleRegistry | from esphome.util import PinRegistry | ||||||
| from esphome.core import CORE | from esphome.core import CORE | ||||||
|  |  | ||||||
| PIN_SCHEMA_REGISTRY = SimpleRegistry() | PIN_SCHEMA_REGISTRY = PinRegistry() | ||||||
|  |  | ||||||
|  |  | ||||||
| def _set_mode(value, default_mode): | def _set_mode(value, default_mode): | ||||||
|   | |||||||
| @@ -57,6 +57,32 @@ class SimpleRegistry(dict): | |||||||
|         return decorator |         return decorator | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _final_validate(parent_id_key, fun): | ||||||
|  |     def validator(fconf, pin_config): | ||||||
|  |         import esphome.config_validation as cv | ||||||
|  |  | ||||||
|  |         parent_path = fconf.get_path_for_id(pin_config[parent_id_key])[:-1] | ||||||
|  |         parent_config = fconf.get_config_for_path(parent_path) | ||||||
|  |  | ||||||
|  |         pin_path = fconf.get_path_for_id(pin_config[const.CONF_ID])[:-1] | ||||||
|  |         with cv.prepend_path([cv.ROOT_CONFIG_PATH] + pin_path): | ||||||
|  |             fun(pin_config, parent_config) | ||||||
|  |  | ||||||
|  |     return validator | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class PinRegistry(dict): | ||||||
|  |     def register(self, name, schema, final_validate=None): | ||||||
|  |         if final_validate is not None: | ||||||
|  |             final_validate = _final_validate(name, final_validate) | ||||||
|  |  | ||||||
|  |         def decorator(fun): | ||||||
|  |             self[name] = (fun, schema, final_validate) | ||||||
|  |             return fun | ||||||
|  |  | ||||||
|  |         return decorator | ||||||
|  |  | ||||||
|  |  | ||||||
| def safe_print(message="", end="\n"): | def safe_print(message="", end="\n"): | ||||||
|     from esphome.core import CORE |     from esphome.core import CORE | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user