mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
Merge branch 'dev' into cc1101-modulation-names-progmem
This commit is contained in:
@@ -47,6 +47,7 @@ CanMode = esp32_can_ns.enum("CanMode")
|
||||
CAN_MODES = {
|
||||
"NORMAL": CanMode.CAN_MODE_NORMAL,
|
||||
"LISTENONLY": CanMode.CAN_MODE_LISTEN_ONLY,
|
||||
"NO_ACK": CanMode.CAN_MODE_NO_ACK,
|
||||
}
|
||||
|
||||
# Currently the driver only supports a subset of the bit rates defined in canbus
|
||||
|
||||
@@ -79,10 +79,13 @@ bool ESP32Can::setup_internal() {
|
||||
}
|
||||
|
||||
// Select TWAI mode based on configuration
|
||||
twai_mode_t twai_mode = (this->mode_ == CAN_MODE_LISTEN_ONLY) ? TWAI_MODE_LISTEN_ONLY : TWAI_MODE_NORMAL;
|
||||
|
||||
twai_mode_t twai_mode = TWAI_MODE_NORMAL;
|
||||
if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
|
||||
twai_mode = TWAI_MODE_LISTEN_ONLY;
|
||||
ESP_LOGI(TAG, "CAN bus configured in LISTEN_ONLY mode (passive, no ACKs)");
|
||||
} else if (this->mode_ == CAN_MODE_NO_ACK) {
|
||||
twai_mode = TWAI_MODE_NO_ACK;
|
||||
ESP_LOGI(TAG, "CAN bus configured in NO_ACK mode (transmit without requiring ACK)");
|
||||
}
|
||||
|
||||
twai_general_config_t g_config =
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace esphome::esp32_can {
|
||||
enum CanMode : uint8_t {
|
||||
CAN_MODE_NORMAL = 0,
|
||||
CAN_MODE_LISTEN_ONLY = 1,
|
||||
CAN_MODE_NO_ACK = 2,
|
||||
};
|
||||
|
||||
class ESP32Can final : public canbus::Canbus {
|
||||
|
||||
@@ -126,8 +126,8 @@ CONFIG_SCHEMA = cv.All(
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = await climate_ir.new_climate_ir(config)
|
||||
cg.add(var.set_protocol(config[CONF_PROTOCOL]))
|
||||
tag = heatpumpir_ns.ProtocolTag.template(config[CONF_PROTOCOL])
|
||||
var = await climate_ir.new_climate_ir(config, tag())
|
||||
cg.add(var.set_horizontal_default(config[CONF_HORIZONTAL_DEFAULT]))
|
||||
cg.add(var.set_vertical_default(config[CONF_VERTICAL_DEFAULT]))
|
||||
cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE]))
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#if defined(USE_ARDUINO) || defined(USE_ESP32)
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <IRSender.h>
|
||||
#include <HeatpumpIRFactory.h>
|
||||
#include "esphome/components/remote_base/remote_base.h"
|
||||
@@ -45,71 +44,76 @@ class IRSenderESPHome : public IRSender {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "heatpumpir.climate");
|
||||
|
||||
const std::map<Protocol, std::function<HeatpumpIR *()>> PROTOCOL_CONSTRUCTOR_MAP = {
|
||||
{PROTOCOL_AUX, []() { return new AUXHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_BALLU, []() { return new BalluHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_CARRIER_MCA, []() { return new CarrierMCAHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_CARRIER_NQV, []() { return new CarrierNQVHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_DAIKIN_ARC417, []() { return new DaikinHeatpumpARC417IR(); }}, // NOLINT
|
||||
{PROTOCOL_DAIKIN_ARC480, []() { return new DaikinHeatpumpARC480A14IR(); }}, // NOLINT
|
||||
{PROTOCOL_DAIKIN, []() { return new DaikinHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_ELECTROLUXYAL, []() { return new ElectroluxYALHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_FUEGO, []() { return new FuegoHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_FUJITSU_AWYZ, []() { return new FujitsuHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_GREE, []() { return new GreeGenericHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_GREEYAA, []() { return new GreeYAAHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_GREEYAN, []() { return new GreeYANHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_GREEYAC, []() { return new GreeYACHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_GREEYT, []() { return new GreeYTHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_GREEYAP, []() { return new GreeYAPHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_HISENSE_AUD, []() { return new HisenseHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_HITACHI, []() { return new HitachiHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_HYUNDAI, []() { return new HyundaiHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_IVT, []() { return new IVTHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MIDEA, []() { return new MideaHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_FA, []() { return new MitsubishiFAHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_FD, []() { return new MitsubishiFDHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_FE, []() { return new MitsubishiFEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_HEAVY_FDTC, []() { return new MitsubishiHeavyFDTCHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_HEAVY_ZJ, []() { return new MitsubishiHeavyZJHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_HEAVY_ZM, []() { return new MitsubishiHeavyZMHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_HEAVY_ZMP, []() { return new MitsubishiHeavyZMPHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_KJ, []() { return new MitsubishiKJHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_MSC, []() { return new MitsubishiMSCHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_MSY, []() { return new MitsubishiMSYHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_MITSUBISHI_SEZ, []() { return new MitsubishiSEZKDXXHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_CKP, []() { return new PanasonicCKPHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_DKE, []() { return new PanasonicDKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_EKE, []() { return new PanasonicEKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_JKE, []() { return new PanasonicJKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_LKE, []() { return new PanasonicLKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_NKE, []() { return new PanasonicNKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_SAMSUNG_AQV, []() { return new SamsungAQVHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_SAMSUNG_FJM, []() { return new SamsungFJMHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_SHARP, []() { return new SharpHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_TOSHIBA_DAISEIKAI, []() { return new ToshibaDaiseikaiHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_TOSHIBA, []() { return new ToshibaHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_ZHLT01, []() { return new ZHLT01HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_NIBE, []() { return new NibeHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_QLIMA_1, []() { return new Qlima1HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_QLIMA_2, []() { return new Qlima2HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_SAMSUNG_AQV12MSAN, []() { return new SamsungAQV12MSANHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_ZHJG01, []() { return new ZHJG01HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_AIRWAY, []() { return new AIRWAYHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_BGH_AUD, []() { return new BGHHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_ALTDKE, []() { return new PanasonicAltDKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PHILCO_PHS32, []() { return new PhilcoPHS32HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_VAILLANTVAI8, []() { return new VaillantHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_R51M, []() { return new R51MHeatpumpIR(); }}, // NOLINT
|
||||
};
|
||||
template<Protocol P> struct ProtocolClass;
|
||||
|
||||
template<Protocol P> HeatpumpIR *create_heatpump_ir() {
|
||||
return new typename ProtocolClass<P>::type(); // NOLINT
|
||||
}
|
||||
|
||||
// Codegen calls only the configured protocols, so the linker drops the other classes
|
||||
#define HEATPUMPIR_PROTOCOL(protocol, cls) \
|
||||
template<> struct ProtocolClass<protocol> { using type = cls; }; \
|
||||
template HeatpumpIR *create_heatpump_ir<protocol>();
|
||||
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_AUX, AUXHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_BALLU, BalluHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_CARRIER_MCA, CarrierMCAHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_CARRIER_NQV, CarrierNQVHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_DAIKIN_ARC417, DaikinHeatpumpARC417IR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_DAIKIN_ARC480, DaikinHeatpumpARC480A14IR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_DAIKIN, DaikinHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_ELECTROLUXYAL, ElectroluxYALHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_FUEGO, FuegoHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_FUJITSU_AWYZ, FujitsuHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_GREE, GreeGenericHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_GREEYAA, GreeYAAHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_GREEYAN, GreeYANHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_GREEYAC, GreeYACHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_GREEYT, GreeYTHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_GREEYAP, GreeYAPHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_HISENSE_AUD, HisenseHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_HITACHI, HitachiHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_HYUNDAI, HyundaiHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_IVT, IVTHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MIDEA, MideaHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_FA, MitsubishiFAHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_FD, MitsubishiFDHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_FE, MitsubishiFEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_HEAVY_FDTC, MitsubishiHeavyFDTCHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_HEAVY_ZJ, MitsubishiHeavyZJHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_HEAVY_ZM, MitsubishiHeavyZMHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_HEAVY_ZMP, MitsubishiHeavyZMPHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_KJ, MitsubishiKJHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_MSC, MitsubishiMSCHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_MSY, MitsubishiMSYHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_MITSUBISHI_SEZ, MitsubishiSEZKDXXHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_CKP, PanasonicCKPHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_DKE, PanasonicDKEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_EKE, PanasonicEKEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_JKE, PanasonicJKEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_LKE, PanasonicLKEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_NKE, PanasonicNKEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_SAMSUNG_AQV, SamsungAQVHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_SAMSUNG_FJM, SamsungFJMHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_SHARP, SharpHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_TOSHIBA_DAISEIKAI, ToshibaDaiseikaiHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_TOSHIBA, ToshibaHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_ZHLT01, ZHLT01HeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_NIBE, NibeHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_QLIMA_1, Qlima1HeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_QLIMA_2, Qlima2HeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_SAMSUNG_AQV12MSAN, SamsungAQV12MSANHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_ZHJG01, ZHJG01HeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_AIRWAY, AIRWAYHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_BGH_AUD, BGHHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PANASONIC_ALTDKE, PanasonicAltDKEHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_PHILCO_PHS32, PhilcoPHS32HeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_VAILLANTVAI8, VaillantHeatpumpIR)
|
||||
HEATPUMPIR_PROTOCOL(PROTOCOL_R51M, R51MHeatpumpIR)
|
||||
|
||||
#undef HEATPUMPIR_PROTOCOL
|
||||
|
||||
void HeatpumpIRClimate::setup() {
|
||||
auto protocol_constructor = PROTOCOL_CONSTRUCTOR_MAP.find(protocol_);
|
||||
if (protocol_constructor == PROTOCOL_CONSTRUCTOR_MAP.end()) {
|
||||
ESP_LOGE(TAG, "Invalid protocol");
|
||||
return;
|
||||
}
|
||||
this->heatpump_ir_ = protocol_constructor->second();
|
||||
climate_ir::ClimateIR::setup();
|
||||
if (this->sensor_) {
|
||||
this->sensor_->add_on_state_callback([this](float state) {
|
||||
|
||||
@@ -89,25 +89,21 @@ enum VerticalDirection {
|
||||
VERTICAL_DIRECTION_DOWN = 5,
|
||||
};
|
||||
|
||||
/// Creates the HeatpumpIR library class for a protocol; instantiated in heatpumpir.cpp.
|
||||
template<Protocol P> HeatpumpIR *create_heatpump_ir();
|
||||
|
||||
/// Selects the protocol at compile time so the enum and the library object always match.
|
||||
template<Protocol P> struct ProtocolTag {};
|
||||
|
||||
// Temperature
|
||||
const float TEMP_MIN = 0; // Celsius
|
||||
const float TEMP_MAX = 100; // Celsius
|
||||
|
||||
class HeatpumpIRClimate final : public climate_ir::ClimateIR {
|
||||
public:
|
||||
HeatpumpIRClimate()
|
||||
: climate_ir::ClimateIR(TEMP_MIN, TEMP_MAX, 1.0f, true, true,
|
||||
{climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH,
|
||||
climate::CLIMATE_FAN_AUTO},
|
||||
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_HORIZONTAL,
|
||||
climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_BOTH}) {}
|
||||
template<Protocol P>
|
||||
explicit HeatpumpIRClimate(ProtocolTag<P> /*tag*/) : HeatpumpIRClimate(P, create_heatpump_ir<P>()) {}
|
||||
void setup() override;
|
||||
void set_protocol(Protocol protocol) {
|
||||
this->protocol_ = protocol;
|
||||
if (this->has_fan_byte_presets_()) {
|
||||
this->presets_ = {climate::CLIMATE_PRESET_NONE, climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_BOOST};
|
||||
}
|
||||
}
|
||||
void set_horizontal_default(HorizontalDirection horizontal_direction) {
|
||||
this->default_horizontal_direction_ = horizontal_direction;
|
||||
}
|
||||
@@ -119,6 +115,18 @@ class HeatpumpIRClimate final : public climate_ir::ClimateIR {
|
||||
void set_min_temperature(float temperature) { this->min_temperature_ = temperature; }
|
||||
|
||||
protected:
|
||||
HeatpumpIRClimate(Protocol protocol, HeatpumpIR *heatpump_ir)
|
||||
: climate_ir::ClimateIR(TEMP_MIN, TEMP_MAX, 1.0f, true, true,
|
||||
{climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH,
|
||||
climate::CLIMATE_FAN_AUTO},
|
||||
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_HORIZONTAL,
|
||||
climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_BOTH}),
|
||||
heatpump_ir_(heatpump_ir),
|
||||
protocol_(protocol) {
|
||||
if (this->has_fan_byte_presets_()) {
|
||||
this->presets_ = {climate::CLIMATE_PRESET_NONE, climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_BOOST};
|
||||
}
|
||||
}
|
||||
HeatpumpIR *heatpump_ir_;
|
||||
void control(const climate::ClimateCall &call) override;
|
||||
/// Transmit via IR the state of this climate controller.
|
||||
|
||||
+10
-4
@@ -1120,8 +1120,12 @@ def _load_yaml_internal(fname: Path, *, track_document_range: bool = True) -> An
|
||||
res = parse_yaml(fname, f_handle, track_document_range=track_document_range)
|
||||
except (UnicodeDecodeError, OSError) as err:
|
||||
raise EsphomeError(f"Error reading file {fname}: {err}") from err
|
||||
# Top-level !include returns a deferred IncludeFile; resolve it so
|
||||
# callers always receive the final content.
|
||||
return res
|
||||
|
||||
|
||||
def _resolve_include(res: Any) -> Any:
|
||||
# A document that is just `!include` parses to a deferred IncludeFile; resolve it so
|
||||
# every parse_yaml caller, including the VS Code and ACE loaders, gets the final content.
|
||||
if isinstance(res, IncludeFile):
|
||||
res = res.load() if res.should_load() else {}
|
||||
return res
|
||||
@@ -1147,7 +1151,7 @@ def parse_yaml(
|
||||
# tracked mode; reject the combination instead of half-applying it.
|
||||
raise ValueError("track_document_range=False requires the default yaml_loader")
|
||||
try:
|
||||
return _load_yaml_internal_with_type(
|
||||
res = _load_yaml_internal_with_type(
|
||||
ESPHomeLoader,
|
||||
file_name,
|
||||
file_handle,
|
||||
@@ -1159,13 +1163,15 @@ def parse_yaml(
|
||||
# readable exceptions
|
||||
# Rewind the stream so we can try again
|
||||
file_handle.seek(0, 0)
|
||||
return _load_yaml_internal_with_type(
|
||||
res = _load_yaml_internal_with_type(
|
||||
ESPHomePurePythonLoader,
|
||||
file_name,
|
||||
file_handle,
|
||||
yaml_loader,
|
||||
track_document_range=track_document_range,
|
||||
)
|
||||
# Resolved after the fallback so a failed first parse never loads the include twice
|
||||
return _resolve_include(res)
|
||||
|
||||
|
||||
def _load_yaml_internal_with_type(
|
||||
|
||||
@@ -18,7 +18,7 @@ canbus:
|
||||
tx_pin: ${tx_pin}
|
||||
can_id: 4
|
||||
bit_rate: 50kbps
|
||||
mode: NORMAL
|
||||
mode: NO_ACK
|
||||
on_frame:
|
||||
- can_id: 500
|
||||
then:
|
||||
|
||||
@@ -954,6 +954,23 @@ def test_yaml_merge_chain_include_resolves() -> None:
|
||||
assert config["base"]["existing"] == "value"
|
||||
|
||||
|
||||
def test_parse_yaml_custom_loader_resolves_root_include() -> None:
|
||||
"""A document that is only `!include` is resolved for a custom loader too."""
|
||||
parent = Path("/fake/main.yaml")
|
||||
loader_calls: list[Path] = []
|
||||
|
||||
def custom_loader(fname: Path) -> dict[str, int]:
|
||||
loader_calls.append(fname)
|
||||
return {"x": 1}
|
||||
|
||||
config = yaml_util.parse_yaml(
|
||||
parent, io.StringIO("!include inner.yaml\n"), custom_loader
|
||||
)
|
||||
|
||||
assert config == {"x": 1}
|
||||
assert loader_calls == [Path("/fake/inner.yaml")]
|
||||
|
||||
|
||||
def test_yaml_merge_chain_include_depth_exceeded() -> None:
|
||||
"""Chain includes in merge keys exceeding depth limit raise a clear error."""
|
||||
parent = Path("/fake/main.yaml")
|
||||
|
||||
Reference in New Issue
Block a user