Merge branch 'dev' into duplicate_webserver_code

This commit is contained in:
J. Nick Koston 2025-06-27 16:01:32 +02:00 committed by GitHub
commit 5c8d6752fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 226 additions and 87 deletions

View File

@ -146,6 +146,7 @@ esphome/components/esp32_ble_client/* @jesserockz
esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_hosted/* @swoboda1337
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz

View File

@ -312,7 +312,7 @@ FileDecoderState AudioDecoder::decode_mp3_() {
if (err) {
switch (err) {
case esp_audio_libs::helix_decoder::ERR_MP3_OUT_OF_MEMORY:
// Intentional fallthrough
[[fallthrough]];
case esp_audio_libs::helix_decoder::ERR_MP3_NULL_POINTER:
return FileDecoderState::FAILED;
break;

View File

@ -610,7 +610,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
CONF_ENABLE_LWIP_DHCP_SERVER, "wifi", default=False
): cv.boolean,
cv.Optional(
CONF_ENABLE_LWIP_MDNS_QUERIES, default=False
CONF_ENABLE_LWIP_MDNS_QUERIES, default=True
): cv.boolean,
cv.Optional(
CONF_ENABLE_LWIP_BRIDGE_INTERFACE, default=False
@ -770,7 +770,7 @@ async def to_code(config):
and not advanced[CONF_ENABLE_LWIP_DHCP_SERVER]
):
add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False)
if not advanced.get(CONF_ENABLE_LWIP_MDNS_QUERIES, False):
if not advanced.get(CONF_ENABLE_LWIP_MDNS_QUERIES, True):
add_idf_sdkconfig_option("CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES", False)
if not advanced.get(CONF_ENABLE_LWIP_BRIDGE_INTERFACE, False):
add_idf_sdkconfig_option("CONFIG_LWIP_BRIDGEIF_MAX_PORTS", 0)

View File

@ -29,9 +29,9 @@ class ESP32InternalGPIOPin : public InternalGPIOPin {
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
gpio_num_t pin_;
bool inverted_;
gpio_drive_cap_t drive_strength_;
gpio::Flags flags_;
bool inverted_;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static bool isr_service_installed;
};

View File

@ -496,17 +496,17 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
if (length > 2) {
return (float) encode_uint16(value[1], value[2]);
}
// fall through
[[fallthrough]];
case 0x7: // uint24.
if (length > 3) {
return (float) encode_uint24(value[1], value[2], value[3]);
}
// fall through
[[fallthrough]];
case 0x8: // uint32.
if (length > 4) {
return (float) encode_uint32(value[1], value[2], value[3], value[4]);
}
// fall through
[[fallthrough]];
case 0xC: // int8.
return (float) ((int8_t) value[1]);
case 0xD: // int12.
@ -514,12 +514,12 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
if (length > 2) {
return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]);
}
// fall through
[[fallthrough]];
case 0xF: // int24.
if (length > 3) {
return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3]));
}
// fall through
[[fallthrough]];
case 0x10: // int32.
if (length > 4) {
return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) +

View File

@ -310,11 +310,7 @@ async def to_code(config):
cg.add_define("USE_ESP32_CAMERA")
if CORE.using_esp_idf:
add_idf_component(
name="esp32-camera",
repo="https://github.com/espressif/esp32-camera.git",
ref="v2.0.15",
)
add_idf_component(name="espressif/esp32-camera", ref="2.0.15")
for conf in config.get(CONF_ON_STREAM_START, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)

View File

@ -0,0 +1,101 @@
import os
from esphome import pins
from esphome.components import esp32
import esphome.config_validation as cv
from esphome.const import (
CONF_CLK_PIN,
CONF_RESET_PIN,
CONF_VARIANT,
KEY_CORE,
KEY_FRAMEWORK_VERSION,
)
from esphome.core import CORE
CODEOWNERS = ["@swoboda1337"]
CONF_ACTIVE_HIGH = "active_high"
CONF_CMD_PIN = "cmd_pin"
CONF_D0_PIN = "d0_pin"
CONF_D1_PIN = "d1_pin"
CONF_D2_PIN = "d2_pin"
CONF_D3_PIN = "d3_pin"
CONF_SLOT = "slot"
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.Required(CONF_VARIANT): cv.one_of(*esp32.VARIANTS, upper=True),
cv.Required(CONF_ACTIVE_HIGH): cv.boolean,
cv.Required(CONF_CLK_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_CMD_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D0_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D1_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D2_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D3_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_RESET_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_SLOT, default=1): cv.int_range(min=0, max=1),
}
),
)
async def to_code(config):
if config[CONF_ACTIVE_HIGH]:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SDIO_RESET_ACTIVE_HIGH",
True,
)
else:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SDIO_RESET_ACTIVE_LOW",
True,
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE", # NOLINT
config[CONF_RESET_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_SLAVE_IDF_TARGET_{config[CONF_VARIANT]}", # NOLINT
True,
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_SDIO_SLOT_{config[CONF_SLOT]}",
True,
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_{config[CONF_SLOT]}",
config[CONF_CLK_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_{config[CONF_SLOT]}",
config[CONF_CMD_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_{config[CONF_SLOT]}",
config[CONF_D0_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_{config[CONF_SLOT]}",
config[CONF_D1_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_{config[CONF_SLOT]}",
config[CONF_D2_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_{config[CONF_SLOT]}",
config[CONF_D3_PIN],
)
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_CUSTOM_SDIO_PINS", True)
framework_ver: cv.Version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]
os.environ["ESP_IDF_VERSION"] = f"{framework_ver.major}.{framework_ver.minor}"
esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="0.10.2")
esp32.add_idf_component(name="espressif/eppp_link", ref="0.2.0")
esp32.add_idf_component(name="espressif/esp_hosted", ref="2.0.11")
esp32.add_extra_script(
"post",
"esp32_hosted.py",
os.path.join(os.path.dirname(__file__), "esp32_hosted.py.script"),
)

View File

@ -0,0 +1,12 @@
# pylint: disable=E0602
Import("env") # noqa
# Workaround whole archive issue
if "__LIB_DEPS" in env and "libespressif__esp_hosted.a" in env["__LIB_DEPS"]:
env.Append(
LINKFLAGS=[
"-Wl,--whole-archive",
env["BUILD_DIR"] + "/esp-idf/espressif__esp_hosted/libespressif__esp_hosted.a",
"-Wl,--no-whole-archive",
]
)

View File

@ -15,7 +15,7 @@
namespace esphome {
namespace ethernet {
enum EthernetType {
enum EthernetType : uint8_t {
ETHERNET_TYPE_UNKNOWN = 0,
ETHERNET_TYPE_LAN8720,
ETHERNET_TYPE_RTL8201,
@ -42,7 +42,7 @@ struct PHYRegister {
uint32_t page;
};
enum class EthernetComponentState {
enum class EthernetComponentState : uint8_t {
STOPPED,
CONNECTING,
CONNECTED,
@ -119,25 +119,31 @@ class EthernetComponent : public Component {
uint32_t polling_interval_{0};
#endif
#else
uint8_t phy_addr_{0};
// Group all 32-bit members first
int power_pin_{-1};
uint8_t mdc_pin_{23};
uint8_t mdio_pin_{18};
emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
std::vector<PHYRegister> phy_registers_{};
#endif
EthernetType type_{ETHERNET_TYPE_UNKNOWN};
optional<ManualIP> manual_ip_{};
// Group all 8-bit members together
uint8_t phy_addr_{0};
uint8_t mdc_pin_{23};
uint8_t mdio_pin_{18};
#endif
optional<ManualIP> manual_ip_{};
uint32_t connect_begin_;
// Group all uint8_t types together (enums and bools)
EthernetType type_{ETHERNET_TYPE_UNKNOWN};
EthernetComponentState state_{EthernetComponentState::STOPPED};
bool started_{false};
bool connected_{false};
bool got_ipv4_address_{false};
#if LWIP_IPV6
uint8_t ipv6_count_{0};
#endif /* LWIP_IPV6 */
EthernetComponentState state_{EthernetComponentState::STOPPED};
uint32_t connect_begin_;
// Pointers at the end (naturally aligned)
esp_netif_t *eth_netif_{nullptr};
esp_eth_handle_t eth_handle_;
esp_eth_phy_t *phy_{nullptr};

View File

@ -88,12 +88,7 @@ async def to_code(config):
if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(
5, 0, 0
):
add_idf_component(
name="mdns",
repo="https://github.com/espressif/esp-protocols.git",
ref="mdns-v1.8.2",
path="components/mdns",
)
add_idf_component(name="espressif/mdns", ref="1.8.2")
cg.add_define("USE_MDNS")

View File

@ -449,11 +449,7 @@ async def to_code(config):
cg.add_define("USE_MICRO_WAKE_WORD")
cg.add_define("USE_OTA_STATE_CALLBACK")
esp32.add_idf_component(
name="esp-tflite-micro",
repo="https://github.com/espressif/esp-tflite-micro",
ref="v1.3.3.1",
)
esp32.add_idf_component(name="espressif/esp-tflite-micro", ref="1.3.3~1")
cg.add_build_flag("-DTF_LITE_STATIC_MEMORY")
cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON")

View File

@ -584,7 +584,7 @@ void PN7150::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::NFCC_INIT);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_INIT:
if (this->init_core_() != nfc::STATUS_OK) {
@ -594,7 +594,7 @@ void PN7150::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::NFCC_CONFIG);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_CONFIG:
if (this->send_init_config_() != nfc::STATUS_OK) {
@ -605,7 +605,7 @@ void PN7150::nci_fsm_transition_() {
this->config_refresh_pending_ = false;
this->nci_fsm_set_state_(NCIState::NFCC_SET_DISCOVER_MAP);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_SET_DISCOVER_MAP:
if (this->set_discover_map_() != nfc::STATUS_OK) {
@ -615,7 +615,7 @@ void PN7150::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::NFCC_SET_LISTEN_MODE_ROUTING);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_SET_LISTEN_MODE_ROUTING:
if (this->set_listen_mode_routing_() != nfc::STATUS_OK) {
@ -625,7 +625,7 @@ void PN7150::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::RFST_IDLE);
}
// fall through
[[fallthrough]];
case NCIState::RFST_IDLE:
if (this->nci_state_error_ == NCIState::RFST_DISCOVERY) {
@ -650,14 +650,14 @@ void PN7150::nci_fsm_transition_() {
case NCIState::RFST_W4_HOST_SELECT:
select_endpoint_();
// fall through
[[fallthrough]];
// All cases below are waiting for NOTIFICATION messages
case NCIState::RFST_DISCOVERY:
if (this->config_refresh_pending_) {
this->refresh_core_config_();
}
// fall through
[[fallthrough]];
case NCIState::RFST_LISTEN_ACTIVE:
case NCIState::RFST_LISTEN_SLEEP:

View File

@ -609,7 +609,7 @@ void PN7160::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::NFCC_INIT);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_INIT:
if (this->init_core_() != nfc::STATUS_OK) {
@ -619,7 +619,7 @@ void PN7160::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::NFCC_CONFIG);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_CONFIG:
if (this->send_init_config_() != nfc::STATUS_OK) {
@ -630,7 +630,7 @@ void PN7160::nci_fsm_transition_() {
this->config_refresh_pending_ = false;
this->nci_fsm_set_state_(NCIState::NFCC_SET_DISCOVER_MAP);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_SET_DISCOVER_MAP:
if (this->set_discover_map_() != nfc::STATUS_OK) {
@ -640,7 +640,7 @@ void PN7160::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::NFCC_SET_LISTEN_MODE_ROUTING);
}
// fall through
[[fallthrough]];
case NCIState::NFCC_SET_LISTEN_MODE_ROUTING:
if (this->set_listen_mode_routing_() != nfc::STATUS_OK) {
@ -650,7 +650,7 @@ void PN7160::nci_fsm_transition_() {
} else {
this->nci_fsm_set_state_(NCIState::RFST_IDLE);
}
// fall through
[[fallthrough]];
case NCIState::RFST_IDLE:
if (this->nci_state_error_ == NCIState::RFST_DISCOVERY) {
@ -675,14 +675,14 @@ void PN7160::nci_fsm_transition_() {
case NCIState::RFST_W4_HOST_SELECT:
select_endpoint_();
// fall through
[[fallthrough]];
// All cases below are waiting for NOTIFICATION messages
case NCIState::RFST_DISCOVERY:
if (this->config_refresh_pending_) {
this->refresh_core_config_();
}
// fall through
[[fallthrough]];
case NCIState::RFST_LISTEN_ACTIVE:
case NCIState::RFST_LISTEN_SLEEP:

View File

@ -33,12 +33,15 @@ class SafeModeComponent : public Component {
void write_rtc_(uint32_t val);
uint32_t read_rtc_();
bool boot_successful_{false}; ///< set to true after boot is considered successful
// Group all 4-byte aligned members together to avoid padding
uint32_t safe_mode_boot_is_good_after_{60000}; ///< The amount of time after which the boot is considered successful
uint32_t safe_mode_enable_time_{60000}; ///< The time safe mode should remain active for
uint32_t safe_mode_rtc_value_{0};
uint32_t safe_mode_start_time_{0}; ///< stores when safe mode was enabled
// Group 1-byte members together to minimize padding
bool boot_successful_{false}; ///< set to true after boot is considered successful
uint8_t safe_mode_num_attempts_{0};
// Larger objects at the end
ESPPreferenceObject rtc_;
CallbackManager<void()> safe_mode_callback_{};

View File

@ -445,8 +445,7 @@ template<typename T> stm32_err_t stm32_check_ack_timeout(const stm32_err_t s_err
return STM32_ERR_OK;
case STM32_ERR_NACK:
log();
// TODO: c++17 [[fallthrough]]
/* fallthrough */
[[fallthrough]];
default:
return STM32_ERR_UNKNOWN;
}

View File

@ -62,7 +62,7 @@ struct SavedWifiFastConnectSettings {
uint8_t channel;
} PACKED; // NOLINT
enum WiFiComponentState {
enum WiFiComponentState : uint8_t {
/** Nothing has been initialized yet. Internal AP, if configured, is disabled at this point. */
WIFI_COMPONENT_STATE_OFF = 0,
/** WiFi is disabled. */
@ -146,14 +146,14 @@ class WiFiAP {
protected:
std::string ssid_;
optional<bssid_t> bssid_;
std::string password_;
optional<bssid_t> bssid_;
#ifdef USE_WIFI_WPA2_EAP
optional<EAPAuth> eap_;
#endif // USE_WIFI_WPA2_EAP
optional<uint8_t> channel_;
float priority_{0};
optional<ManualIP> manual_ip_;
float priority_{0};
optional<uint8_t> channel_;
bool hidden_{false};
};
@ -177,14 +177,14 @@ class WiFiScanResult {
bool operator==(const WiFiScanResult &rhs) const;
protected:
bool matches_{false};
bssid_t bssid_;
std::string ssid_;
float priority_{0.0f};
uint8_t channel_;
int8_t rssi_;
bool matches_{false};
bool with_auth_;
bool is_hidden_;
float priority_{0.0f};
};
struct WiFiSTAPriority {
@ -192,7 +192,7 @@ struct WiFiSTAPriority {
float priority;
};
enum WiFiPowerSaveMode {
enum WiFiPowerSaveMode : uint8_t {
WIFI_POWER_SAVE_NONE = 0,
WIFI_POWER_SAVE_LIGHT,
WIFI_POWER_SAVE_HIGH,
@ -383,28 +383,36 @@ class WiFiComponent : public Component {
std::string use_address_;
std::vector<WiFiAP> sta_;
std::vector<WiFiSTAPriority> sta_priorities_;
std::vector<WiFiScanResult> scan_result_;
WiFiAP selected_ap_;
bool fast_connect_{false};
bool retry_hidden_{false};
bool has_ap_{false};
WiFiAP ap_;
WiFiComponentState state_{WIFI_COMPONENT_STATE_OFF};
bool handled_connected_state_{false};
optional<float> output_power_;
ESPPreferenceObject pref_;
ESPPreferenceObject fast_connect_pref_;
// Group all 32-bit integers together
uint32_t action_started_;
uint8_t num_retried_{0};
uint32_t last_connected_{0};
uint32_t reboot_timeout_{};
uint32_t ap_timeout_{};
// Group all 8-bit values together
WiFiComponentState state_{WIFI_COMPONENT_STATE_OFF};
WiFiPowerSaveMode power_save_{WIFI_POWER_SAVE_NONE};
uint8_t num_retried_{0};
#if USE_NETWORK_IPV6
uint8_t num_ipv6_addresses_{0};
#endif /* USE_NETWORK_IPV6 */
// Group all boolean values together
bool fast_connect_{false};
bool retry_hidden_{false};
bool has_ap_{false};
bool handled_connected_state_{false};
bool error_from_callback_{false};
std::vector<WiFiScanResult> scan_result_;
bool scan_done_{false};
bool ap_setup_{false};
optional<float> output_power_;
bool passive_scan_{false};
ESPPreferenceObject pref_;
ESPPreferenceObject fast_connect_pref_;
bool has_saved_wifi_settings_{false};
#ifdef USE_WIFI_11KV_SUPPORT
bool btm_{false};
@ -412,10 +420,8 @@ class WiFiComponent : public Component {
#endif
bool enable_on_boot_;
bool got_ipv4_address_{false};
#if USE_NETWORK_IPV6
uint8_t num_ipv6_addresses_{0};
#endif /* USE_NETWORK_IPV6 */
// Pointers at the end (naturally aligned)
Trigger<> *connect_trigger_{new Trigger<>()};
Trigger<> *disconnect_trigger_{new Trigger<>()};
};

View File

@ -375,7 +375,7 @@ void ComponentIterator::advance() {
}
if (advance_platform) {
this->state_ = static_cast<IteratorState>(static_cast<uint32_t>(this->state_) + 1);
this->state_ = static_cast<IteratorState>(static_cast<uint8_t>(this->state_) + 1);
this->at_ = 0;
} else if (success) {
this->at_++;

View File

@ -93,7 +93,9 @@ class ComponentIterator {
virtual bool on_end();
protected:
enum class IteratorState {
// Iterates over all ESPHome entities (sensors, switches, lights, etc.)
// Supports up to 256 entity types and up to 65,535 entities of each type
enum class IteratorState : uint8_t {
NONE = 0,
BEGIN,
#ifdef USE_BINARY_SENSOR
@ -167,7 +169,7 @@ class ComponentIterator {
#endif
MAX,
} state_{IteratorState::NONE};
size_t at_{0};
uint16_t at_{0}; // Supports up to 65,535 entities per type
bool include_internal_{false};
};

View File

@ -1,13 +1,19 @@
dependencies:
esp-tflite-micro:
git: https://github.com/espressif/esp-tflite-micro.git
version: v1.3.1
esp32_camera:
git: https://github.com/espressif/esp32-camera.git
version: v2.0.15
mdns:
git: https://github.com/espressif/esp-protocols.git
version: mdns-v1.8.2
path: components/mdns
espressif/esp-tflite-micro:
version: 1.3.3~1
espressif/esp32-camera:
version: 2.0.15
espressif/mdns:
version: 1.8.2
espressif/esp_wifi_remote:
version: 0.10.2
rules:
- if: "idf_version >=5.0"
- if: "target in [esp32h2, esp32p4]"
espressif/eppp_link:
version: 0.2.0
rules:
- if: "target in [esp32h2, esp32p4]"
espressif/esp_hosted:
version: 2.0.11
rules:
- if: "target in [esp32h2, esp32p4]"

View File

@ -0,0 +1,15 @@
esp32_hosted:
variant: ESP32C6
slot: 1
active_high: true
reset_pin: GPIO15
cmd_pin: GPIO13
clk_pin: GPIO12
d0_pin: GPIO11
d1_pin: GPIO10
d2_pin: GPIO9
d3_pin: GPIO8
wifi:
ssid: MySSID
password: password1

View File

@ -0,0 +1 @@
<<: !include common.yaml