diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index db24b9aa29..d84663b2d6 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -147,8 +147,9 @@ def _arduino_check_versions(value): value[CONF_VERSION] = str(version) value[CONF_SOURCE] = source or _format_framework_arduino_version(version) - platform_version = value.get(CONF_PLATFORM_VERSION, ARDUINO_PLATFORM_VERSION) - value[CONF_PLATFORM_VERSION] = str(platform_version) + value[CONF_PLATFORM_VERSION] = value.get( + CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION)) + ) if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION: _LOGGER.warning( @@ -184,8 +185,9 @@ def _esp_idf_check_versions(value): value[CONF_VERSION] = str(version) value[CONF_SOURCE] = source or _format_framework_espidf_version(version) - platform_version = value.get(CONF_PLATFORM_VERSION, ESP_IDF_PLATFORM_VERSION) - value[CONF_PLATFORM_VERSION] = str(platform_version) + value[CONF_PLATFORM_VERSION] = value.get( + CONF_PLATFORM_VERSION, _parse_platform_version(str(ESP_IDF_PLATFORM_VERSION)) + ) if version != RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION: _LOGGER.warning( @@ -196,6 +198,15 @@ def _esp_idf_check_versions(value): return value +def _parse_platform_version(value): + try: + # if platform version is a valid version constraint, prefix the default package + cv.platformio_version_constraint(value) + return f"platformio/espressif32 @ {value}" + except cv.Invalid: + return value + + def _detect_variant(value): if CONF_VARIANT not in value: board = value[CONF_BOARD] @@ -218,7 +229,7 @@ ARDUINO_FRAMEWORK_SCHEMA = cv.All( { cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, cv.Optional(CONF_SOURCE): cv.string_strict, - cv.Optional(CONF_PLATFORM_VERSION): cv.string_strict, + cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, } ), _arduino_check_versions, @@ -230,7 +241,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All( { cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, cv.Optional(CONF_SOURCE): cv.string_strict, - cv.Optional(CONF_PLATFORM_VERSION): cv.string_strict, + cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, cv.Optional(CONF_SDKCONFIG_OPTIONS, default={}): { cv.string_strict: cv.string_strict }, @@ -280,10 +291,9 @@ async def to_code(config): cg.add_platformio_option("lib_ldf_mode", "off") conf = config[CONF_FRAMEWORK] + cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) + if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: - cg.add_platformio_option( - "platform", f"espressif32 @ {conf[CONF_PLATFORM_VERSION]}" - ) cg.add_platformio_option("framework", "espidf") cg.add_build_flag("-DUSE_ESP_IDF") cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ESP_IDF") @@ -314,9 +324,6 @@ async def to_code(config): ) elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO: - cg.add_platformio_option( - "platform", f"espressif32 @ {conf[CONF_PLATFORM_VERSION]}" - ) cg.add_platformio_option("framework", "arduino") cg.add_build_flag("-DUSE_ARDUINO") cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ARDUINO") diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 7c7758b943..5b97d2d9d5 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -93,12 +93,12 @@ def _arduino_check_versions(value): platform_version = value.get(CONF_PLATFORM_VERSION) if platform_version is None: if version >= cv.Version(3, 0, 0): - platform_version = ARDUINO_3_PLATFORM_VERSION + platform_version = _parse_platform_version(str(ARDUINO_3_PLATFORM_VERSION)) elif version >= cv.Version(2, 5, 0): - platform_version = ARDUINO_2_PLATFORM_VERSION + platform_version = _parse_platform_version(str(ARDUINO_2_PLATFORM_VERSION)) else: - platform_version = cv.Version(1, 8, 0) - value[CONF_PLATFORM_VERSION] = str(platform_version) + platform_version = _parse_platform_version(str(cv.Version(1, 8, 0))) + value[CONF_PLATFORM_VERSION] = platform_version if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION: _LOGGER.warning( @@ -109,13 +109,22 @@ def _arduino_check_versions(value): return value +def _parse_platform_version(value): + try: + # if platform version is a valid version constraint, prefix the default package + cv.platformio_version_constraint(value) + return f"platformio/espressif8266 @ {value}" + except cv.Invalid: + return value + + CONF_PLATFORM_VERSION = "platform_version" ARDUINO_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, cv.Optional(CONF_SOURCE): cv.string_strict, - cv.Optional(CONF_PLATFORM_VERSION): cv.string_strict, + cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, } ), _arduino_check_versions, @@ -152,13 +161,11 @@ async def to_code(config): cg.add_platformio_option("framework", "arduino") cg.add_build_flag("-DUSE_ARDUINO") cg.add_build_flag("-DUSE_ESP8266_FRAMEWORK_ARDUINO") + cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) cg.add_platformio_option( "platform_packages", [f"platformio/framework-arduinoespressif8266 @ {conf[CONF_SOURCE]}"], ) - cg.add_platformio_option( - "platform", f"platformio/espressif8266 @ {conf[CONF_PLATFORM_VERSION]}" - ) # Default for platformio is LWIP2_LOW_MEMORY with: # - MSS=536 diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 5d4ff64193..fcd014f62d 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1668,6 +1668,25 @@ def version_number(value): raise Invalid("Not a version number") from e +def platformio_version_constraint(value): + # for documentation on valid version constraints: + # https://docs.platformio.org/en/latest/core/userguide/platforms/cmd_install.html#cmd-platform-install + + value = string_strict(value) + constraints = [] + for item in value.split(","): + # find and strip prefix operator + op = None + for test_op in ("^", "~", ">=", ">", "<=", "<", "!="): + if item.startswith(test_op): + op = test_op + item = item[len(test_op) :] + break + + constraints.append((op, version_number(item))) + return constraints + + def require_framework_version( *, esp_idf=None,