Compare commits

..
6 changed files with 66 additions and 30 deletions

No files matched your search

+5 -4
View File
@@ -212,10 +212,9 @@ file does, and it is the authority when they disagree. The most useful starting
logged with `get_log_str` and `LOG_STR_ARG`, copied out with `ESPHOME_strncpy_P` before `publish_state`.
A `dump_config` helper that picks a name returns `const LogString *` from `LOG_STR(...)`.
* **CRCs and bit tricks** come from `esphome/core/helpers.h` (`crc8`, `crc16`, `xor_bytes`, `sum16_bytes`,
`reverse_bits`, `encode_uint16`, `encode_value_le`, `sign_extend<BITS>`, `bcd_to_uint8`, `assign_bits`,
`bit_at`); pick the helper's arguments instead of writing a loop. 7-byte BCD RTC calendars use
`time::decode_bcd_calendar<LAYOUT>` and `encode_bcd_calendar<LAYOUT>` with `EPSON_BCD_CALENDAR`,
`DS_BCD_CALENDAR` or `PCF_BCD_CALENDAR`.
`reverse_bits`, `encode_uint16`, `encode_value_le`, `sign_extend<BITS>`, `bcd_to_uint8`, `assign_bits`); pick
the helper's arguments instead of writing a loop. 7-byte BCD RTC calendars use `time::decode_bcd_calendar<LAYOUT>`
and `encode_bcd_calendar<LAYOUT>` with `EPSON_BCD_CALENDAR`, `DS_BCD_CALENDAR` or `PCF_BCD_CALENDAR`.
* **Bus helpers:** UART drains with `read_available(on_byte)` and `discard_available()`, text lines with
`LineReader<N>`; I2C has `update_register`, `write_registers` (PROGMEM `I2CRegValue` table), `check_chip_id`
and `read_bytes_16_le`. `if (!this->status_comm_result(ok)) return;` sets or clears the warning.
@@ -447,6 +446,8 @@ file does, and it is the authority when they disagree. The most useful starting
switches = switch.sub_switches(config, parent=hub)
await switches(CONF_BLUETOOTH, None, apply="set_bluetooth(state)", publish="after")
```
Restore an owned or standalone switch in `setup()` with `sw->restore_state()`, or
`restore_state(default)` to still drive a state when the restore mode is disabled.
- **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`)
+7
View File
@@ -53,6 +53,13 @@ optional<bool> Switch::get_initial_state_with_restore_mode() {
}
return initial_state;
}
void Switch::restore_state() {
if (auto initial = this->get_initial_state_with_restore_mode())
this->control(*initial);
}
void Switch::restore_state(bool when_disabled) {
this->control(this->get_initial_state_with_restore_mode().value_or(when_disabled));
}
void Switch::publish_state(bool state) {
if (!this->publish_dedup_.next(state))
return;
+5
View File
@@ -110,6 +110,11 @@ class Switch : public EntityBase {
*/
optional<bool> get_initial_state_with_restore_mode();
/// Drive the switch to the state its restore mode yields, through control(), so inversion and
/// write_state() apply; a disabled restore mode drives `when_disabled`, or nothing without one.
void restore_state();
void restore_state(bool when_disabled);
/** Return whether this switch uses an assumed state - i.e. if both the ON/OFF actions should be displayed in Home
* Assistant because the real state is unknown.
*
-3
View File
@@ -1077,9 +1077,6 @@ template<typename T> ESPHOME_ALWAYS_INLINE constexpr void assign_bits(T &value,
}
}
/// Whether bit \p bit (0 is the LSB) of \p value is set; the read side of assign_bits().
template<typename T> ESPHOME_ALWAYS_INLINE constexpr bool bit_at(T value, unsigned bit) { return (value >> bit) & 1; }
/// Reverse the order of 8 bits.
inline uint8_t reverse_bits(uint8_t x) {
x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
-23
View File
@@ -1,23 +0,0 @@
#include <gtest/gtest.h>
#include "esphome/core/helpers.h"
namespace esphome::core::testing {
static_assert(bit_at(uint8_t{0b1010'0001}, 0));
static_assert(!bit_at(uint8_t{0b1010'0001}, 1));
static_assert(bit_at(uint8_t{0b1010'0001}, 7));
static_assert(bit_at(uint64_t{1} << 63, 63));
static_assert(!bit_at(uint64_t{1} << 63, 62));
static_assert(bit_at(int32_t{-1}, 31));
static_assert(!bit_at(int32_t{0x7FFF'FFFF}, 31));
TEST(BitAt, IsTheReadSideOfAssignBits) {
uint16_t reg = 0;
assign_bits(reg, 1 << 9, true);
EXPECT_TRUE(bit_at(reg, 9));
assign_bits(reg, 1 << 9, false);
EXPECT_FALSE(bit_at(reg, 9));
}
} // namespace esphome::core::testing
@@ -0,0 +1,49 @@
#include <gtest/gtest.h>
#include <vector>
#include "esphome/components/switch/switch.h"
namespace esphome::switch_::testing {
class RecordingSwitch : public Switch {
public:
std::vector<bool> writes;
protected:
void write_state(bool state) override {
this->writes.push_back(state);
this->publish_state(state);
}
};
TEST(RestoreState, DrivesTheRestoreModeStateThroughInversion) {
RecordingSwitch on, off, inverted;
on.set_restore_mode(SWITCH_ALWAYS_ON);
off.set_restore_mode(SWITCH_ALWAYS_OFF);
inverted.set_restore_mode(SWITCH_ALWAYS_ON);
inverted.set_inverted(true);
on.restore_state();
off.restore_state();
inverted.restore_state();
EXPECT_EQ(on.writes, std::vector<bool>{true});
EXPECT_EQ(off.writes, std::vector<bool>{false});
EXPECT_EQ(inverted.writes, std::vector<bool>{false}); // the hardware level
EXPECT_TRUE(on.state);
EXPECT_FALSE(off.state);
EXPECT_TRUE(inverted.state);
}
TEST(RestoreState, DefaultAppliesOnlyWhenTheModeIsDisabled) {
RecordingSwitch disabled, on;
disabled.set_restore_mode(SWITCH_RESTORE_DISABLED);
on.set_restore_mode(SWITCH_ALWAYS_ON);
disabled.restore_state();
EXPECT_TRUE(disabled.writes.empty());
disabled.restore_state(true);
on.restore_state(false);
EXPECT_EQ(disabled.writes, std::vector<bool>{true});
EXPECT_EQ(on.writes, std::vector<bool>{true});
}
} // namespace esphome::switch_::testing