mirror of
https://github.com/esphome/esphome.git
synced 2025-11-15 06:15:47 +00:00
Merge branch 'integration' into memory_api
This commit is contained in:
@@ -480,6 +480,7 @@ esphome/components/template/fan/* @ssieb
|
|||||||
esphome/components/text/* @mauritskorse
|
esphome/components/text/* @mauritskorse
|
||||||
esphome/components/thermostat/* @kbx81
|
esphome/components/thermostat/* @kbx81
|
||||||
esphome/components/time/* @esphome/core
|
esphome/components/time/* @esphome/core
|
||||||
|
esphome/components/tinyusb/* @kbx81
|
||||||
esphome/components/tlc5947/* @rnauber
|
esphome/components/tlc5947/* @rnauber
|
||||||
esphome/components/tlc5971/* @IJIJI
|
esphome/components/tlc5971/* @IJIJI
|
||||||
esphome/components/tm1621/* @Philippe12
|
esphome/components/tm1621/* @Philippe12
|
||||||
|
|||||||
60
esphome/components/tinyusb/__init__.py
Normal file
60
esphome/components/tinyusb/__init__.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import esp32
|
||||||
|
from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option
|
||||||
|
from esphome.components.esp32.const import (
|
||||||
|
VARIANT_ESP32P4,
|
||||||
|
VARIANT_ESP32S2,
|
||||||
|
VARIANT_ESP32S3,
|
||||||
|
)
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
|
CODEOWNERS = ["@kbx81"]
|
||||||
|
CONFLICTS_WITH = ["usb_host"]
|
||||||
|
|
||||||
|
CONF_USB_LANG_ID = "usb_lang_id"
|
||||||
|
CONF_USB_MANUFACTURER_STR = "usb_manufacturer_str"
|
||||||
|
CONF_USB_PRODUCT_ID = "usb_product_id"
|
||||||
|
CONF_USB_PRODUCT_STR = "usb_product_str"
|
||||||
|
CONF_USB_SERIAL_STR = "usb_serial_str"
|
||||||
|
CONF_USB_VENDOR_ID = "usb_vendor_id"
|
||||||
|
|
||||||
|
tinyusb_ns = cg.esphome_ns.namespace("tinyusb")
|
||||||
|
TinyUSB = tinyusb_ns.class_("TinyUSB", cg.Component)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TinyUSB),
|
||||||
|
cv.Optional(CONF_USB_PRODUCT_ID, default=0x4001): cv.uint16_t,
|
||||||
|
cv.Optional(CONF_USB_VENDOR_ID, default=0x303A): cv.uint16_t,
|
||||||
|
cv.Optional(CONF_USB_LANG_ID, default=0x0409): cv.uint16_t,
|
||||||
|
cv.Optional(CONF_USB_MANUFACTURER_STR, default="ESPHome"): cv.string,
|
||||||
|
cv.Optional(CONF_USB_PRODUCT_STR, default="ESPHome"): cv.string,
|
||||||
|
cv.Optional(CONF_USB_SERIAL_STR, default=""): cv.string,
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
|
esp32.only_on_variant(
|
||||||
|
supported=[VARIANT_ESP32P4, VARIANT_ESP32S2, VARIANT_ESP32S3],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
# Set USB device descriptor properties
|
||||||
|
cg.add(var.set_usb_desc_product_id(config[CONF_USB_PRODUCT_ID]))
|
||||||
|
cg.add(var.set_usb_desc_vendor_id(config[CONF_USB_VENDOR_ID]))
|
||||||
|
cg.add(var.set_usb_desc_lang_id(config[CONF_USB_LANG_ID]))
|
||||||
|
cg.add(var.set_usb_desc_manufacturer(config[CONF_USB_MANUFACTURER_STR]))
|
||||||
|
cg.add(var.set_usb_desc_product(config[CONF_USB_PRODUCT_STR]))
|
||||||
|
if config[CONF_USB_SERIAL_STR]:
|
||||||
|
cg.add(var.set_usb_desc_serial(config[CONF_USB_SERIAL_STR]))
|
||||||
|
|
||||||
|
add_idf_component(name="espressif/esp_tinyusb", ref="1.7.6~1")
|
||||||
|
|
||||||
|
add_idf_sdkconfig_option("CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID", False)
|
||||||
|
add_idf_sdkconfig_option("CONFIG_TINYUSB_DESC_USE_DEFAULT_PID", False)
|
||||||
|
add_idf_sdkconfig_option("CONFIG_TINYUSB_DESC_BCD_DEVICE", 0x0100)
|
||||||
44
esphome/components/tinyusb/tinyusb_component.cpp
Normal file
44
esphome/components/tinyusb/tinyusb_component.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||||
|
#include "tinyusb_component.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome::tinyusb {
|
||||||
|
|
||||||
|
static const char *TAG = "tinyusb";
|
||||||
|
|
||||||
|
void TinyUSB::setup() {
|
||||||
|
// Use the device's MAC address as its serial number if no serial number is defined
|
||||||
|
if (this->string_descriptor_[SERIAL_NUMBER] == nullptr) {
|
||||||
|
static char mac_addr_buf[13];
|
||||||
|
get_mac_address_into_buffer(mac_addr_buf);
|
||||||
|
this->string_descriptor_[SERIAL_NUMBER] = mac_addr_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->tusb_cfg_ = {
|
||||||
|
.descriptor = &this->usb_descriptor_,
|
||||||
|
.string_descriptor = this->string_descriptor_,
|
||||||
|
.string_descriptor_count = SIZE,
|
||||||
|
.external_phy = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_err_t result = tinyusb_driver_install(&this->tusb_cfg_);
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
this->mark_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TinyUSB::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG,
|
||||||
|
"TinyUSB:\n"
|
||||||
|
" Product ID: 0x%04X\n"
|
||||||
|
" Vendor ID: 0x%04X\n"
|
||||||
|
" Manufacturer: '%s'\n"
|
||||||
|
" Product: '%s'\n"
|
||||||
|
" Serial: '%s'\n",
|
||||||
|
this->usb_descriptor_.idProduct, this->usb_descriptor_.idVendor, this->string_descriptor_[MANUFACTURER],
|
||||||
|
this->string_descriptor_[PRODUCT], this->string_descriptor_[SERIAL_NUMBER]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome::tinyusb
|
||||||
|
#endif
|
||||||
72
esphome/components/tinyusb/tinyusb_component.h
Normal file
72
esphome/components/tinyusb/tinyusb_component.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
|
#include "tinyusb.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
namespace esphome::tinyusb {
|
||||||
|
|
||||||
|
enum USBDStringDescriptor : uint8_t {
|
||||||
|
LANGUAGE_ID = 0,
|
||||||
|
MANUFACTURER = 1,
|
||||||
|
PRODUCT = 2,
|
||||||
|
SERIAL_NUMBER = 3,
|
||||||
|
INTERFACE = 4,
|
||||||
|
TERMINATOR = 5,
|
||||||
|
SIZE = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *DEFAULT_USB_STR = "ESPHome";
|
||||||
|
|
||||||
|
class TinyUSB : public Component {
|
||||||
|
public:
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::BUS; }
|
||||||
|
|
||||||
|
void set_usb_desc_product_id(uint16_t product_id) { this->usb_descriptor_.idProduct = product_id; }
|
||||||
|
void set_usb_desc_vendor_id(uint16_t vendor_id) { this->usb_descriptor_.idVendor = vendor_id; }
|
||||||
|
void set_usb_desc_lang_id(uint16_t lang_id) {
|
||||||
|
this->usb_desc_lang_id_[0] = lang_id & 0xFF;
|
||||||
|
this->usb_desc_lang_id_[1] = lang_id >> 8;
|
||||||
|
}
|
||||||
|
void set_usb_desc_manufacturer(const char *usb_desc_manufacturer) {
|
||||||
|
this->string_descriptor_[MANUFACTURER] = usb_desc_manufacturer;
|
||||||
|
}
|
||||||
|
void set_usb_desc_product(const char *usb_desc_product) { this->string_descriptor_[PRODUCT] = usb_desc_product; }
|
||||||
|
void set_usb_desc_serial(const char *usb_desc_serial) { this->string_descriptor_[SERIAL_NUMBER] = usb_desc_serial; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char usb_desc_lang_id_[2] = {0x09, 0x04}; // defaults to english
|
||||||
|
|
||||||
|
const char *string_descriptor_[SIZE] = {
|
||||||
|
this->usb_desc_lang_id_, // 0: supported language is English (0x0409)
|
||||||
|
DEFAULT_USB_STR, // 1: Manufacturer
|
||||||
|
DEFAULT_USB_STR, // 2: Product
|
||||||
|
nullptr, // 3: Serial Number
|
||||||
|
nullptr, // 4: Interface
|
||||||
|
nullptr, // 5: Terminator
|
||||||
|
};
|
||||||
|
|
||||||
|
tinyusb_config_t tusb_cfg_{};
|
||||||
|
tusb_desc_device_t usb_descriptor_{
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
.idVendor = 0x303A,
|
||||||
|
.idProduct = 0x4001,
|
||||||
|
.bcdDevice = CONFIG_TINYUSB_DESC_BCD_DEVICE,
|
||||||
|
.iManufacturer = 1,
|
||||||
|
.iProduct = 2,
|
||||||
|
.iSerialNumber = 3,
|
||||||
|
.bNumConfigurations = 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace esphome::tinyusb
|
||||||
|
#endif
|
||||||
@@ -641,6 +641,12 @@ std::string get_mac_address_pretty() {
|
|||||||
return format_mac_address_pretty(mac);
|
return format_mac_address_pretty(mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_mac_address_into_buffer(std::span<char, 13> buf) {
|
||||||
|
uint8_t mac[6];
|
||||||
|
get_mac_address_raw(mac);
|
||||||
|
format_mac_addr_lower_no_sep(mac, buf.data());
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef USE_ESP32
|
#ifndef USE_ESP32
|
||||||
bool has_custom_mac_address() { return false; }
|
bool has_custom_mac_address() { return false; }
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -1030,6 +1031,10 @@ std::string get_mac_address();
|
|||||||
/// Get the device MAC address as a string, in colon-separated uppercase hex notation.
|
/// Get the device MAC address as a string, in colon-separated uppercase hex notation.
|
||||||
std::string get_mac_address_pretty();
|
std::string get_mac_address_pretty();
|
||||||
|
|
||||||
|
/// Get the device MAC address into the given buffer, in lowercase hex notation.
|
||||||
|
/// Assumes buffer length is 13 (12 digits for hexadecimal representation followed by null terminator).
|
||||||
|
void get_mac_address_into_buffer(std::span<char, 13> buf);
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
/// Set the MAC address to use from the provided byte array (6 bytes).
|
/// Set the MAC address to use from the provided byte array (6 bytes).
|
||||||
void set_mac_address(uint8_t *mac);
|
void set_mac_address(uint8_t *mac);
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ struct ESPTime {
|
|||||||
*/
|
*/
|
||||||
static ESPTime from_epoch_local(time_t epoch) {
|
static ESPTime from_epoch_local(time_t epoch) {
|
||||||
struct tm *c_tm = ::localtime(&epoch);
|
struct tm *c_tm = ::localtime(&epoch);
|
||||||
|
if (c_tm == nullptr) {
|
||||||
|
return ESPTime{}; // Return an invalid ESPTime
|
||||||
|
}
|
||||||
return ESPTime::from_c_tm(c_tm, epoch);
|
return ESPTime::from_c_tm(c_tm, epoch);
|
||||||
}
|
}
|
||||||
/** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
|
/** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
|
||||||
@@ -93,6 +96,9 @@ struct ESPTime {
|
|||||||
*/
|
*/
|
||||||
static ESPTime from_epoch_utc(time_t epoch) {
|
static ESPTime from_epoch_utc(time_t epoch) {
|
||||||
struct tm *c_tm = ::gmtime(&epoch);
|
struct tm *c_tm = ::gmtime(&epoch);
|
||||||
|
if (c_tm == nullptr) {
|
||||||
|
return ESPTime{}; // Return an invalid ESPTime
|
||||||
|
}
|
||||||
return ESPTime::from_c_tm(c_tm, epoch);
|
return ESPTime::from_c_tm(c_tm, epoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,7 @@ dependencies:
|
|||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
rules:
|
rules:
|
||||||
- if: "target in [esp32, esp32p4]"
|
- if: "target in [esp32, esp32p4]"
|
||||||
|
espressif/esp_tinyusb:
|
||||||
|
version: "1.7.6~1"
|
||||||
|
rules:
|
||||||
|
- if: "target in [esp32s2, esp32s3, esp32p4]"
|
||||||
|
|||||||
@@ -94,6 +94,22 @@ class Platform(StrEnum):
|
|||||||
MEMORY_IMPACT_FALLBACK_COMPONENT = "api" # Representative component for core changes
|
MEMORY_IMPACT_FALLBACK_COMPONENT = "api" # Representative component for core changes
|
||||||
MEMORY_IMPACT_FALLBACK_PLATFORM = Platform.ESP32_IDF # Most representative platform
|
MEMORY_IMPACT_FALLBACK_PLATFORM = Platform.ESP32_IDF # Most representative platform
|
||||||
|
|
||||||
|
# Platform-specific components that can only be built on their respective platforms
|
||||||
|
# These components contain platform-specific code and cannot be cross-compiled
|
||||||
|
# Regular components (wifi, logger, api, etc.) are cross-platform and not listed here
|
||||||
|
PLATFORM_SPECIFIC_COMPONENTS = frozenset(
|
||||||
|
{
|
||||||
|
"esp32", # ESP32 platform implementation
|
||||||
|
"esp8266", # ESP8266 platform implementation
|
||||||
|
"rp2040", # Raspberry Pi Pico / RP2040 platform implementation
|
||||||
|
"bk72xx", # Beken BK72xx platform implementation (uses LibreTiny)
|
||||||
|
"rtl87xx", # Realtek RTL87xx platform implementation (uses LibreTiny)
|
||||||
|
"ln882x", # Winner Micro LN882x platform implementation (uses LibreTiny)
|
||||||
|
"host", # Host platform (for testing on development machine)
|
||||||
|
"nrf52", # Nordic nRF52 platform implementation
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# Platform preference order for memory impact analysis
|
# Platform preference order for memory impact analysis
|
||||||
# This order is used when no platform-specific hints are detected from filenames
|
# This order is used when no platform-specific hints are detected from filenames
|
||||||
# Priority rationale:
|
# Priority rationale:
|
||||||
@@ -568,6 +584,20 @@ def detect_memory_impact_config(
|
|||||||
)
|
)
|
||||||
platform = _select_platform_by_count(platform_counts)
|
platform = _select_platform_by_count(platform_counts)
|
||||||
|
|
||||||
|
# Filter out platform-specific components that are incompatible with selected platform
|
||||||
|
# Platform components (esp32, esp8266, rp2040, etc.) can only build on their own platform
|
||||||
|
# Other components (wifi, logger, etc.) are cross-platform and can build anywhere
|
||||||
|
compatible_components = [
|
||||||
|
component
|
||||||
|
for component in components_with_tests
|
||||||
|
if component not in PLATFORM_SPECIFIC_COMPONENTS
|
||||||
|
or platform in component_platforms_map.get(component, set())
|
||||||
|
]
|
||||||
|
|
||||||
|
# If no components are compatible with the selected platform, don't run
|
||||||
|
if not compatible_components:
|
||||||
|
return {"should_run": "false"}
|
||||||
|
|
||||||
# Debug output
|
# Debug output
|
||||||
print("Memory impact analysis:", file=sys.stderr)
|
print("Memory impact analysis:", file=sys.stderr)
|
||||||
print(f" Changed components: {sorted(changed_component_set)}", file=sys.stderr)
|
print(f" Changed components: {sorted(changed_component_set)}", file=sys.stderr)
|
||||||
@@ -579,10 +609,11 @@ def detect_memory_impact_config(
|
|||||||
print(f" Platform hints from filenames: {platform_hints}", file=sys.stderr)
|
print(f" Platform hints from filenames: {platform_hints}", file=sys.stderr)
|
||||||
print(f" Common platforms: {sorted(common_platforms)}", file=sys.stderr)
|
print(f" Common platforms: {sorted(common_platforms)}", file=sys.stderr)
|
||||||
print(f" Selected platform: {platform}", file=sys.stderr)
|
print(f" Selected platform: {platform}", file=sys.stderr)
|
||||||
|
print(f" Compatible components: {compatible_components}", file=sys.stderr)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"should_run": "true",
|
"should_run": "true",
|
||||||
"components": components_with_tests,
|
"components": compatible_components,
|
||||||
"platform": platform,
|
"platform": platform,
|
||||||
"use_merged_config": "true",
|
"use_merged_config": "true",
|
||||||
}
|
}
|
||||||
|
|||||||
8
tests/components/tinyusb/common.yaml
Normal file
8
tests/components/tinyusb/common.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
tinyusb:
|
||||||
|
id: tinyusb_test
|
||||||
|
usb_lang_id: 0x0123
|
||||||
|
usb_manufacturer_str: ESPHomeTestManufacturer
|
||||||
|
usb_product_id: 0x1234
|
||||||
|
usb_product_str: ESPHomeTestProduct
|
||||||
|
usb_serial_str: ESPHomeTestSerialNumber
|
||||||
|
usb_vendor_id: 0x2345
|
||||||
1
tests/components/tinyusb/test.esp32-p4-idf.yaml
Normal file
1
tests/components/tinyusb/test.esp32-p4-idf.yaml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<<: !include common.yaml
|
||||||
1
tests/components/tinyusb/test.esp32-s2-idf.yaml
Normal file
1
tests/components/tinyusb/test.esp32-s2-idf.yaml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<<: !include common.yaml
|
||||||
1
tests/components/tinyusb/test.esp32-s3-idf.yaml
Normal file
1
tests/components/tinyusb/test.esp32-s3-idf.yaml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<<: !include common.yaml
|
||||||
@@ -1130,3 +1130,111 @@ def test_main_core_files_changed_still_detects_components(
|
|||||||
assert "select" in output["changed_components"]
|
assert "select" in output["changed_components"]
|
||||||
assert "api" in output["changed_components"]
|
assert "api" in output["changed_components"]
|
||||||
assert len(output["changed_components"]) > 0
|
assert len(output["changed_components"]) > 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_detect_memory_impact_config_filters_incompatible_esp32_on_esp8266(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
"""Test that ESP32 components are filtered out when ESP8266 platform is selected.
|
||||||
|
|
||||||
|
This test verifies the fix for the issue where ESP32 components were being included
|
||||||
|
when ESP8266 was selected as the platform, causing build failures in PR 10387.
|
||||||
|
"""
|
||||||
|
# Create test directory structure
|
||||||
|
tests_dir = tmp_path / "tests" / "components"
|
||||||
|
|
||||||
|
# esp32 component only has esp32-idf tests (NOT compatible with esp8266)
|
||||||
|
esp32_dir = tests_dir / "esp32"
|
||||||
|
esp32_dir.mkdir(parents=True)
|
||||||
|
(esp32_dir / "test.esp32-idf.yaml").write_text("test: esp32")
|
||||||
|
(esp32_dir / "test.esp32-s3-idf.yaml").write_text("test: esp32")
|
||||||
|
|
||||||
|
# esp8266 component only has esp8266-ard test (NOT compatible with esp32)
|
||||||
|
esp8266_dir = tests_dir / "esp8266"
|
||||||
|
esp8266_dir.mkdir(parents=True)
|
||||||
|
(esp8266_dir / "test.esp8266-ard.yaml").write_text("test: esp8266")
|
||||||
|
|
||||||
|
# Mock changed_files to return both esp32 and esp8266 component changes
|
||||||
|
# Include esp8266-specific filename to trigger esp8266 platform hint
|
||||||
|
with (
|
||||||
|
patch.object(determine_jobs, "root_path", str(tmp_path)),
|
||||||
|
patch.object(helpers, "root_path", str(tmp_path)),
|
||||||
|
patch.object(determine_jobs, "changed_files") as mock_changed_files,
|
||||||
|
):
|
||||||
|
mock_changed_files.return_value = [
|
||||||
|
"tests/components/esp32/common.yaml",
|
||||||
|
"tests/components/esp8266/test.esp8266-ard.yaml",
|
||||||
|
"esphome/core/helpers_esp8266.h", # ESP8266-specific file to hint platform
|
||||||
|
]
|
||||||
|
determine_jobs._component_has_tests.cache_clear()
|
||||||
|
|
||||||
|
result = determine_jobs.detect_memory_impact_config()
|
||||||
|
|
||||||
|
# Memory impact should run
|
||||||
|
assert result["should_run"] == "true"
|
||||||
|
|
||||||
|
# Platform should be esp8266-ard (due to ESP8266 filename hint)
|
||||||
|
assert result["platform"] == "esp8266-ard"
|
||||||
|
|
||||||
|
# CRITICAL: Only esp8266 component should be included, not esp32
|
||||||
|
# This prevents trying to build ESP32 components on ESP8266 platform
|
||||||
|
assert result["components"] == ["esp8266"], (
|
||||||
|
"When esp8266-ard platform is selected, only esp8266 component should be included, "
|
||||||
|
"not esp32. This prevents trying to build ESP32 components on ESP8266 platform."
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["use_merged_config"] == "true"
|
||||||
|
|
||||||
|
|
||||||
|
def test_detect_memory_impact_config_filters_incompatible_esp8266_on_esp32(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
"""Test that ESP8266 components are filtered out when ESP32 platform is selected.
|
||||||
|
|
||||||
|
This is the inverse of the ESP8266 test - ensures filtering works both ways.
|
||||||
|
"""
|
||||||
|
# Create test directory structure
|
||||||
|
tests_dir = tmp_path / "tests" / "components"
|
||||||
|
|
||||||
|
# esp32 component only has esp32-idf tests (NOT compatible with esp8266)
|
||||||
|
esp32_dir = tests_dir / "esp32"
|
||||||
|
esp32_dir.mkdir(parents=True)
|
||||||
|
(esp32_dir / "test.esp32-idf.yaml").write_text("test: esp32")
|
||||||
|
(esp32_dir / "test.esp32-s3-idf.yaml").write_text("test: esp32")
|
||||||
|
|
||||||
|
# esp8266 component only has esp8266-ard test (NOT compatible with esp32)
|
||||||
|
esp8266_dir = tests_dir / "esp8266"
|
||||||
|
esp8266_dir.mkdir(parents=True)
|
||||||
|
(esp8266_dir / "test.esp8266-ard.yaml").write_text("test: esp8266")
|
||||||
|
|
||||||
|
# Mock changed_files to return both esp32 and esp8266 component changes
|
||||||
|
# Include MORE esp32-specific filenames to ensure esp32-idf wins the hint count
|
||||||
|
with (
|
||||||
|
patch.object(determine_jobs, "root_path", str(tmp_path)),
|
||||||
|
patch.object(helpers, "root_path", str(tmp_path)),
|
||||||
|
patch.object(determine_jobs, "changed_files") as mock_changed_files,
|
||||||
|
):
|
||||||
|
mock_changed_files.return_value = [
|
||||||
|
"tests/components/esp32/common.yaml",
|
||||||
|
"tests/components/esp8266/test.esp8266-ard.yaml",
|
||||||
|
"esphome/components/wifi/wifi_component_esp_idf.cpp", # ESP-IDF hint
|
||||||
|
"esphome/components/ethernet/ethernet_esp32.cpp", # ESP32 hint
|
||||||
|
]
|
||||||
|
determine_jobs._component_has_tests.cache_clear()
|
||||||
|
|
||||||
|
result = determine_jobs.detect_memory_impact_config()
|
||||||
|
|
||||||
|
# Memory impact should run
|
||||||
|
assert result["should_run"] == "true"
|
||||||
|
|
||||||
|
# Platform should be esp32-idf (due to more ESP32-IDF hints)
|
||||||
|
assert result["platform"] == "esp32-idf"
|
||||||
|
|
||||||
|
# CRITICAL: Only esp32 component should be included, not esp8266
|
||||||
|
# This prevents trying to build ESP8266 components on ESP32 platform
|
||||||
|
assert result["components"] == ["esp32"], (
|
||||||
|
"When esp32-idf platform is selected, only esp32 component should be included, "
|
||||||
|
"not esp8266. This prevents trying to build ESP8266 components on ESP32 platform."
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["use_merged_config"] == "true"
|
||||||
|
|||||||
Reference in New Issue
Block a user