Compare commits

..
10 changed files with 41 additions and 29 deletions

No files matched your search

-2
View File
@@ -449,8 +449,6 @@ file does, and it is the authority when they disagree. The most useful starting
```
Restore an owned or standalone switch in `setup()` with `sw->restore()`, or `restore(default)`
to still drive a state when the restore mode is disabled.
A hub that applies its switches' restored states itself reads `sw->get_initial_write_state()`, which
already applies `inverted`.
- **Other codegen helpers:** `uart.new_uart_component(config, *ctor_args)` (and `i2c.new_i2c_component`,
`spi.new_spi_component`, `modbus.new_modbus_client_component`, `ble_client.new_ble_node_component`)
@@ -173,8 +173,8 @@ void DFRobotSEN0609Component::setup() {
switch_::Switch *sw = this->switches_[i];
if (sw == nullptr)
continue;
// A disabled restore mode leaves the switch on, which an inverted switch writes as off
this->publish_switch_(static_cast<SwitchSetting>(i), sw->get_initial_write_state().value_or(!sw->is_inverted()));
const bool on = sw->get_initial_state_with_restore_mode().value_or(true);
this->publish_switch_(static_cast<SwitchSetting>(i), on != sw->is_inverted());
}
#endif
this->queue_configuration_();
@@ -155,9 +155,12 @@ void HitachiClimate::setup() {
set_swing_v_(swing_vertical(restore->swing_mode));
}
#ifdef USE_SWITCH
// The restored value is the switch state, which an inverted switch flips relative to the frame bit
if (this->mildew_proof_switch_ != nullptr) {
if (auto initial = this->mildew_proof_switch_->get_initial_write_state())
assign_bits(this->remote_state_[HITACHI_AC344_MILDEWPROOF_BYTE], 1 << HITACHI_AC344_MILDEWPROOF_OFFSET, *initial);
if (auto initial = this->mildew_proof_switch_->get_initial_state_with_restore_mode()) {
assign_bits(this->remote_state_[HITACHI_AC344_MILDEWPROOF_BYTE], 1 << HITACHI_AC344_MILDEWPROOF_OFFSET,
*initial != this->mildew_proof_switch_->is_inverted());
}
}
#endif
this->setup_(restore);
@@ -25,7 +25,7 @@ void SeeedMultiChannelRelay::setup() {
switch_::Switch *sw = this->switches_[channel];
if (sw == nullptr)
continue;
const bool on = sw->get_initial_write_state().value_or(false);
const bool on = sw->get_initial_state_with_restore_mode().value_or(sw->is_inverted()) != sw->is_inverted();
assign_bits(value, 1 << channel, on);
}
if (!this->status_comm_result(this->write_byte(CMD_CHANNEL_CTRL, value)))
-5
View File
@@ -60,11 +60,6 @@ optional<bool> Switch::get_initial_state_with_restore_mode() {
}
return initial_state;
}
optional<bool> Switch::get_initial_write_state() {
if (auto initial = this->get_initial_state_with_restore_mode())
return *initial != this->inverted_;
return {};
}
void Switch::restore() {
if (auto initial = this->get_initial_state_with_restore_mode())
this->control(*initial);
-2
View File
@@ -114,8 +114,6 @@ class Switch : public EntityBase {
* state.
*/
optional<bool> get_initial_state_with_restore_mode();
/// get_initial_state_with_restore_mode() with inverted applied: the level write_state() takes.
optional<bool> get_initial_write_state();
/// Drive the switch to the state its restore mode yields, through control(), so inversion and
/// write_state() apply; a disabled restore mode drives \p when_disabled, or nothing without one.
+3 -1
View File
@@ -296,7 +296,9 @@ def _external_manifests() -> list[dict[str, Any]]:
found[component_dir] = source
break
else:
if not component_dir.is_relative_to(loader.CORE_COMPONENTS_PATH):
# Built in means anywhere in the package: the esphome domain itself
# is esphome/core, not under esphome/components
if not component_dir.is_relative_to(loader.CORE_COMPONENTS_PATH.parent):
_LOGGER.warning(
"SBOM: component '%s' in %s matches no external component "
"source and is listed as part of ESPHome",
+17
View File
@@ -72,6 +72,23 @@ button:
id(ota_update).set_source_url(std::string("http://my.ha.net:8123/local/esphome/manifest.json"));
ESP_LOGI("test", "Manifest is now %s", id(ota_update).get_source_url());
- component.update: ota_update
# The OTA component's public setters and getters as lambdas use them; every shape must compile.
- platform: template
name: Flash from lambda
on_press:
then:
- lambda: |-
std::string url = "http://my.ha.net:8123/local/esphome/";
url += "firmware.bin";
id(http_request_ota).set_md5_url("http://my.ha.net:8123/local/esphome/firmware.md5");
id(http_request_ota).set_md5(std::string("0123456789abcdef0123456789abcdef"));
id(http_request_ota).set_username("user");
id(http_request_ota).set_password(std::string("pass"));
id(http_request_ota).set_url(url);
id(http_request_ota).set_url(url.c_str());
ESP_LOGI("test", "MD5 %s / %s", id(http_request_ota).md5_expected().c_str(),
id(http_request_ota).md5_computed().c_str());
id(http_request_ota).flash();
update:
- platform: http_request
-12
View File
@@ -46,16 +46,4 @@ TEST(SwitchRestore, DefaultAppliesOnlyWhenTheModeIsDisabled) {
EXPECT_EQ(on.writes, std::vector<bool>{true});
}
TEST(SwitchRestore, InitialWriteStateAppliesInversion) {
RecordingSwitch on, inverted, disabled;
on.set_restore_mode(SWITCH_ALWAYS_ON);
inverted.set_restore_mode(SWITCH_ALWAYS_ON);
inverted.set_inverted(true);
disabled.set_restore_mode(SWITCH_RESTORE_DISABLED);
disabled.set_inverted(true);
EXPECT_EQ(on.get_initial_write_state(), optional<bool>(true));
EXPECT_EQ(inverted.get_initial_write_state(), optional<bool>(false));
EXPECT_FALSE(disabled.get_initial_write_state().has_value());
}
} // namespace esphome::switch_::testing
+13 -2
View File
@@ -386,7 +386,7 @@ def test_external_manifests_skip_other_components(
components_dir = tmp_path / "components"
get_sources().append(ExternalSource(components_dir=components_dir))
_add_external_component(components_dir, "widget")
_add_external_component(tmp_path / "builtin", "wifi")
_add_external_component(tmp_path / "pkg" / "components", "wifi")
CORE.loaded_integrations.update({"missing", "namespace"})
sbom.loader._COMPONENT_CACHE["namespace"] = SimpleNamespace(
module=SimpleNamespace()
@@ -399,7 +399,9 @@ def test_external_manifests_skip_other_components(
side_effect=sbom.loader._COMPONENT_CACHE.get,
),
patch.object(
sbom.loader, "CORE_COMPONENTS_PATH", (tmp_path / "builtin").resolve()
sbom.loader,
"CORE_COMPONENTS_PATH",
(tmp_path / "pkg" / "components").resolve(),
),
):
manifests = sbom._external_manifests()
@@ -703,3 +705,12 @@ def test_checkout_remote_detached(tmp_path: Path) -> None:
"https://user:token@github.com/someone/esphome.git",
)
assert not any(call.args[0][1] == "config" for call in run.call_args_list)
def test_external_manifests_esphome_core_is_built_in(
caplog: pytest.LogCaptureFixture,
) -> None:
"""The esphome domain resolves to esphome/core, which is still part of ESPHome."""
CORE.loaded_integrations.add("esphome")
assert sbom._external_manifests() == []
assert "SBOM" not in caplog.text