mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 14:16:40 +00:00
commit
16a0f9db97
2
Doxyfile
2
Doxyfile
@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2025.6.0b2
|
||||
PROJECT_NUMBER = 2025.6.0b3
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
@ -18,7 +18,7 @@ void I2SAudioComponent::setup() {
|
||||
|
||||
static i2s_port_t next_port_num = I2S_NUM_0;
|
||||
if (next_port_num >= I2S_NUM_MAX) {
|
||||
ESP_LOGE(TAG, "Too many I2S Audio components");
|
||||
ESP_LOGE(TAG, "Too many components");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ void I2SAudioMicrophone::setup() {
|
||||
#if SOC_I2S_SUPPORTS_ADC
|
||||
if (this->adc_) {
|
||||
if (this->parent_->get_port() != I2S_NUM_0) {
|
||||
ESP_LOGE(TAG, "Internal ADC only works on I2S0!");
|
||||
ESP_LOGE(TAG, "Internal ADC only works on I2S0");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@ -55,7 +55,7 @@ void I2SAudioMicrophone::setup() {
|
||||
{
|
||||
if (this->pdm_) {
|
||||
if (this->parent_->get_port() != I2S_NUM_0) {
|
||||
ESP_LOGE(TAG, "PDM only works on I2S0!");
|
||||
ESP_LOGE(TAG, "PDM only works on I2S0");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@ -64,14 +64,14 @@ void I2SAudioMicrophone::setup() {
|
||||
|
||||
this->active_listeners_semaphore_ = xSemaphoreCreateCounting(MAX_LISTENERS, MAX_LISTENERS);
|
||||
if (this->active_listeners_semaphore_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create semaphore");
|
||||
ESP_LOGE(TAG, "Creating semaphore failed");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
this->event_group_ = xEventGroupCreate();
|
||||
if (this->event_group_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create event group");
|
||||
ESP_LOGE(TAG, "Creating event group failed");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@ -79,6 +79,15 @@ void I2SAudioMicrophone::setup() {
|
||||
this->configure_stream_settings_();
|
||||
}
|
||||
|
||||
void I2SAudioMicrophone::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Microphone:\n"
|
||||
" Pin: %d\n"
|
||||
" PDM: %s\n"
|
||||
" DC offset correction: %s",
|
||||
static_cast<int8_t>(this->din_pin_), YESNO(this->pdm_), YESNO(this->correct_dc_offset_));
|
||||
}
|
||||
|
||||
void I2SAudioMicrophone::configure_stream_settings_() {
|
||||
uint8_t channel_count = 1;
|
||||
#ifdef USE_I2S_LEGACY
|
||||
@ -127,6 +136,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
||||
if (!this->parent_->try_lock()) {
|
||||
return false; // Waiting for another i2s to return lock
|
||||
}
|
||||
this->locked_driver_ = true;
|
||||
esp_err_t err;
|
||||
|
||||
#ifdef USE_I2S_LEGACY
|
||||
@ -151,7 +161,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
||||
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN);
|
||||
err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error installing I2S driver: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Error installing driver: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -174,7 +184,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
||||
|
||||
err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error installing I2S driver: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Error installing driver: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -183,7 +193,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
||||
|
||||
err = i2s_set_pin(this->parent_->get_port(), &pin_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error setting I2S pin: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Error setting pin: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -198,7 +208,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
||||
/* Allocate a new RX channel and get the handle of this channel */
|
||||
err = i2s_new_channel(&chan_cfg, NULL, &this->rx_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error creating new I2S channel: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Error creating channel: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -270,14 +280,14 @@ bool I2SAudioMicrophone::start_driver_() {
|
||||
err = i2s_channel_init_std_mode(this->rx_handle_, &std_cfg);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error initializing I2S channel: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Error initializing channel: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Before reading data, start the RX channel first */
|
||||
i2s_channel_enable(this->rx_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error enabling I2S Microphone: %s", esp_err_to_name(err));
|
||||
ESP_LOGE(TAG, "Enabling failed: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@ -304,34 +314,37 @@ void I2SAudioMicrophone::stop_driver_() {
|
||||
if (this->adc_) {
|
||||
err = i2s_adc_disable(this->parent_->get_port());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Error disabling ADC - it may not have started: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Error disabling ADC: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
err = i2s_stop(this->parent_->get_port());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Error stopping I2S microphone - it may not have started: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Error stopping: %s", esp_err_to_name(err));
|
||||
}
|
||||
err = i2s_driver_uninstall(this->parent_->get_port());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Error uninstalling I2S driver - it may not have started: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Error uninstalling driver: %s", esp_err_to_name(err));
|
||||
}
|
||||
#else
|
||||
if (this->rx_handle_ != nullptr) {
|
||||
/* Have to stop the channel before deleting it */
|
||||
err = i2s_channel_disable(this->rx_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Error stopping I2S microphone - it may not have started: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Error stopping: %s", esp_err_to_name(err));
|
||||
}
|
||||
/* If the handle is not needed any more, delete it to release the channel resources */
|
||||
err = i2s_del_channel(this->rx_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Error deleting I2S channel - it may not have started: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Error deleting channel: %s", esp_err_to_name(err));
|
||||
}
|
||||
this->rx_handle_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
this->parent_->unlock();
|
||||
if (this->locked_driver_) {
|
||||
this->parent_->unlock();
|
||||
this->locked_driver_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void I2SAudioMicrophone::mic_task(void *params) {
|
||||
@ -403,7 +416,7 @@ size_t I2SAudioMicrophone::read_(uint8_t *buf, size_t len, TickType_t ticks_to_w
|
||||
// Ignore ESP_ERR_TIMEOUT if ticks_to_wait = 0, as it will read the data on the next call
|
||||
if (!this->status_has_warning()) {
|
||||
// Avoid spamming the logs with the error message if its repeated
|
||||
ESP_LOGW(TAG, "Error reading from I2S microphone: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Read error: %s", esp_err_to_name(err));
|
||||
}
|
||||
this->status_set_warning();
|
||||
return 0;
|
||||
@ -431,19 +444,19 @@ void I2SAudioMicrophone::loop() {
|
||||
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
||||
|
||||
if (event_group_bits & MicrophoneEventGroupBits::TASK_STARTING) {
|
||||
ESP_LOGD(TAG, "Task started, attempting to allocate buffer");
|
||||
ESP_LOGV(TAG, "Task started, attempting to allocate buffer");
|
||||
xEventGroupClearBits(this->event_group_, MicrophoneEventGroupBits::TASK_STARTING);
|
||||
}
|
||||
|
||||
if (event_group_bits & MicrophoneEventGroupBits::TASK_RUNNING) {
|
||||
ESP_LOGD(TAG, "Task is running and reading data");
|
||||
ESP_LOGV(TAG, "Task is running and reading data");
|
||||
|
||||
xEventGroupClearBits(this->event_group_, MicrophoneEventGroupBits::TASK_RUNNING);
|
||||
this->state_ = microphone::STATE_RUNNING;
|
||||
}
|
||||
|
||||
if ((event_group_bits & MicrophoneEventGroupBits::TASK_STOPPED)) {
|
||||
ESP_LOGD(TAG, "Task finished, freeing resources and uninstalling I2S driver");
|
||||
ESP_LOGV(TAG, "Task finished, freeing resources and uninstalling driver");
|
||||
|
||||
vTaskDelete(this->task_handle_);
|
||||
this->task_handle_ = nullptr;
|
||||
@ -473,7 +486,8 @@ void I2SAudioMicrophone::loop() {
|
||||
}
|
||||
|
||||
if (!this->start_driver_()) {
|
||||
this->status_momentary_error("I2S driver failed to start, unloading it and attempting again in 1 second", 1000);
|
||||
ESP_LOGE(TAG, "Driver failed to start; retrying in 1 second");
|
||||
this->status_momentary_error("driver_fail", 1000);
|
||||
this->stop_driver_(); // Stop/frees whatever possibly started
|
||||
break;
|
||||
}
|
||||
@ -483,7 +497,8 @@ void I2SAudioMicrophone::loop() {
|
||||
&this->task_handle_);
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
this->status_momentary_error("Task failed to start, attempting again in 1 second", 1000);
|
||||
ESP_LOGE(TAG, "Task failed to start, retrying in 1 second");
|
||||
this->status_momentary_error("task_fail", 1000);
|
||||
this->stop_driver_(); // Stops the driver to return the lock; will be reloaded in next attempt
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace i2s_audio {
|
||||
class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
||||
@ -80,6 +81,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
|
||||
bool pdm_{false};
|
||||
|
||||
bool correct_dc_offset_;
|
||||
bool locked_driver_{false};
|
||||
int32_t dc_offset_{0};
|
||||
};
|
||||
|
||||
|
@ -110,29 +110,48 @@ void I2SAudioSpeaker::setup() {
|
||||
}
|
||||
}
|
||||
|
||||
void I2SAudioSpeaker::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Speaker:\n"
|
||||
" Pin: %d\n"
|
||||
" Buffer duration: %" PRIu32,
|
||||
static_cast<int8_t>(this->dout_pin_), this->buffer_duration_ms_);
|
||||
if (this->timeout_.has_value()) {
|
||||
ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 " ms", this->timeout_.value());
|
||||
}
|
||||
#ifdef USE_I2S_LEGACY
|
||||
#if SOC_I2S_SUPPORTS_DAC
|
||||
ESP_LOGCONFIG(TAG, " Internal DAC mode: %d", static_cast<int8_t>(this->internal_dac_mode_));
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG, " Communication format: %d", static_cast<int8_t>(this->i2s_comm_fmt_));
|
||||
#else
|
||||
ESP_LOGCONFIG(TAG, " Communication format: %s", this->i2s_comm_fmt_.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void I2SAudioSpeaker::loop() {
|
||||
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
||||
|
||||
if (event_group_bits & SpeakerEventGroupBits::STATE_STARTING) {
|
||||
ESP_LOGD(TAG, "Starting Speaker");
|
||||
ESP_LOGD(TAG, "Starting");
|
||||
this->state_ = speaker::STATE_STARTING;
|
||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
||||
}
|
||||
if (event_group_bits & SpeakerEventGroupBits::STATE_RUNNING) {
|
||||
ESP_LOGD(TAG, "Started Speaker");
|
||||
ESP_LOGD(TAG, "Started");
|
||||
this->state_ = speaker::STATE_RUNNING;
|
||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
||||
this->status_clear_warning();
|
||||
this->status_clear_error();
|
||||
}
|
||||
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPING) {
|
||||
ESP_LOGD(TAG, "Stopping Speaker");
|
||||
ESP_LOGD(TAG, "Stopping");
|
||||
this->state_ = speaker::STATE_STOPPING;
|
||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
||||
}
|
||||
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPED) {
|
||||
if (!this->task_created_) {
|
||||
ESP_LOGD(TAG, "Stopped Speaker");
|
||||
ESP_LOGD(TAG, "Stopped");
|
||||
this->state_ = speaker::STATE_STOPPED;
|
||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
|
||||
this->speaker_task_handle_ = nullptr;
|
||||
@ -140,20 +159,19 @@ void I2SAudioSpeaker::loop() {
|
||||
}
|
||||
|
||||
if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) {
|
||||
this->status_set_error("Failed to start speaker task");
|
||||
this->status_set_error("Failed to start task");
|
||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
||||
}
|
||||
|
||||
if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
|
||||
uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
|
||||
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
|
||||
ESP_LOGW(TAG, "Writing failed: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
|
||||
this->status_set_warning();
|
||||
}
|
||||
|
||||
if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED) {
|
||||
this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
|
||||
ESP_LOGE(TAG,
|
||||
"Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
|
||||
this->status_set_error("Failed to adjust bus to match incoming audio");
|
||||
ESP_LOGE(TAG, "Incompatible audio format: sample rate = %" PRIu32 ", channels = %u, bits per sample = %u",
|
||||
this->audio_stream_info_.get_sample_rate(), this->audio_stream_info_.get_channels(),
|
||||
this->audio_stream_info_.get_bits_per_sample());
|
||||
}
|
||||
@ -202,7 +220,7 @@ void I2SAudioSpeaker::set_mute_state(bool mute_state) {
|
||||
|
||||
size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup");
|
||||
ESP_LOGE(TAG, "Setup failed; cannot play audio");
|
||||
return 0;
|
||||
}
|
||||
if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) {
|
||||
|
@ -24,6 +24,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
||||
float get_setup_priority() const override { return esphome::setup_priority::PROCESSOR; }
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void loop() override;
|
||||
|
||||
void set_buffer_duration(uint32_t buffer_duration_ms) { this->buffer_duration_ms_ = buffer_duration_ms; }
|
||||
|
@ -17,7 +17,7 @@ namespace light {
|
||||
|
||||
class LightOutput;
|
||||
|
||||
enum LightRestoreMode {
|
||||
enum LightRestoreMode : uint8_t {
|
||||
LIGHT_RESTORE_DEFAULT_OFF,
|
||||
LIGHT_RESTORE_DEFAULT_ON,
|
||||
LIGHT_ALWAYS_OFF,
|
||||
@ -212,12 +212,18 @@ class LightState : public EntityBase, public Component {
|
||||
|
||||
/// Store the output to allow effects to have more access.
|
||||
LightOutput *output_;
|
||||
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
||||
uint32_t active_effect_index_{};
|
||||
/// The currently active transformer for this light (transition/flash).
|
||||
std::unique_ptr<LightTransformer> transformer_{nullptr};
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
/// List of effects for this light.
|
||||
std::vector<LightEffect *> effects_;
|
||||
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
||||
uint32_t active_effect_index_{};
|
||||
/// Default transition length for all transitions in ms.
|
||||
uint32_t default_transition_length_{};
|
||||
/// Transition length to use for flash transitions.
|
||||
uint32_t flash_transition_length_{};
|
||||
/// Gamma correction factor for the light.
|
||||
float gamma_correct_{};
|
||||
|
||||
/// Object used to store the persisted values of the light.
|
||||
ESPPreferenceObject rtc_;
|
||||
@ -236,19 +242,13 @@ class LightState : public EntityBase, public Component {
|
||||
*/
|
||||
CallbackManager<void()> target_state_reached_callback_{};
|
||||
|
||||
/// Default transition length for all transitions in ms.
|
||||
uint32_t default_transition_length_{};
|
||||
/// Transition length to use for flash transitions.
|
||||
uint32_t flash_transition_length_{};
|
||||
/// Gamma correction factor for the light.
|
||||
float gamma_correct_{};
|
||||
/// Restore mode of the light.
|
||||
LightRestoreMode restore_mode_;
|
||||
/// Initial state of the light.
|
||||
optional<LightStateRTCState> initial_state_{};
|
||||
/// List of effects for this light.
|
||||
std::vector<LightEffect *> effects_;
|
||||
|
||||
/// Restore mode of the light.
|
||||
LightRestoreMode restore_mode_;
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
// for effects, true if a transformer (transition) is active.
|
||||
bool is_transformer_active_ = false;
|
||||
};
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
namespace esphome {
|
||||
namespace spi {
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
static const char *const TAG = "spi-esp-arduino";
|
||||
@ -38,17 +37,31 @@ class SPIDelegateHw : public SPIDelegate {
|
||||
|
||||
void write16(uint16_t data) override { this->channel_->transfer16(data); }
|
||||
|
||||
#ifdef USE_RP2040
|
||||
void write_array(const uint8_t *ptr, size_t length) override {
|
||||
// avoid overwriting the supplied buffer
|
||||
uint8_t *rxbuf = new uint8_t[length]; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
memcpy(rxbuf, ptr, length);
|
||||
this->channel_->transfer((void *) rxbuf, length);
|
||||
delete[] rxbuf; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
if (length == 1) {
|
||||
this->channel_->transfer(*ptr);
|
||||
return;
|
||||
}
|
||||
#ifdef USE_RP2040
|
||||
// avoid overwriting the supplied buffer. Use vector for automatic deallocation
|
||||
auto rxbuf = std::vector<uint8_t>(length);
|
||||
memcpy(rxbuf.data(), ptr, length);
|
||||
this->channel_->transfer((void *) rxbuf.data(), length);
|
||||
#elif defined(USE_ESP8266)
|
||||
// ESP8266 SPI library requires the pointer to be word aligned, but the data may not be
|
||||
// so we need to copy the data to a temporary buffer
|
||||
if (reinterpret_cast<uintptr_t>(ptr) & 0x3) {
|
||||
ESP_LOGVV(TAG, "SPI write buffer not word aligned, copying to temporary buffer");
|
||||
auto txbuf = std::vector<uint8_t>(length);
|
||||
memcpy(txbuf.data(), ptr, length);
|
||||
this->channel_->writeBytes(txbuf.data(), length);
|
||||
} else {
|
||||
this->channel_->writeBytes(ptr, length);
|
||||
}
|
||||
#else
|
||||
void write_array(const uint8_t *ptr, size_t length) override { this->channel_->writeBytes(ptr, length); }
|
||||
this->channel_->writeBytes(ptr, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void read_array(uint8_t *ptr, size_t length) override { this->channel_->transfer(ptr, length); }
|
||||
|
||||
|
@ -21,7 +21,7 @@ const int RESTORE_MODE_PERSISTENT_MASK = 0x02;
|
||||
const int RESTORE_MODE_INVERTED_MASK = 0x04;
|
||||
const int RESTORE_MODE_DISABLED_MASK = 0x08;
|
||||
|
||||
enum SwitchRestoreMode {
|
||||
enum SwitchRestoreMode : uint8_t {
|
||||
SWITCH_ALWAYS_OFF = !RESTORE_MODE_ON_MASK,
|
||||
SWITCH_ALWAYS_ON = RESTORE_MODE_ON_MASK,
|
||||
SWITCH_RESTORE_DEFAULT_OFF = RESTORE_MODE_PERSISTENT_MASK,
|
||||
@ -49,12 +49,12 @@ class Switch : public EntityBase, public EntityBase_DeviceClass {
|
||||
*/
|
||||
void publish_state(bool state);
|
||||
|
||||
/// The current reported state of the binary sensor.
|
||||
bool state;
|
||||
|
||||
/// Indicates whether or not state is to be retrieved from flash and how
|
||||
SwitchRestoreMode restore_mode{SWITCH_RESTORE_DEFAULT_OFF};
|
||||
|
||||
/// The current reported state of the binary sensor.
|
||||
bool state;
|
||||
|
||||
/** Turn this switch on. This is called by the front-end.
|
||||
*
|
||||
* For implementing switches, please override write_state.
|
||||
@ -123,10 +123,16 @@ class Switch : public EntityBase, public EntityBase_DeviceClass {
|
||||
*/
|
||||
virtual void write_state(bool state) = 0;
|
||||
|
||||
CallbackManager<void(bool)> state_callback_{};
|
||||
bool inverted_{false};
|
||||
Deduplicator<bool> publish_dedup_;
|
||||
// Pointer first (4 bytes)
|
||||
ESPPreferenceObject rtc_;
|
||||
|
||||
// CallbackManager (12 bytes on 32-bit - contains vector)
|
||||
CallbackManager<void(bool)> state_callback_{};
|
||||
|
||||
// Small types grouped together
|
||||
Deduplicator<bool> publish_dedup_; // 2 bytes (bool has_value_ + bool last_value_)
|
||||
bool inverted_{false}; // 1 byte
|
||||
// Total: 3 bytes, 1 byte padding
|
||||
};
|
||||
|
||||
#define LOG_SWITCH(prefix, type, obj) log_switch((TAG), (prefix), LOG_STR_LITERAL(type), (obj))
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2025.6.0b2"
|
||||
__version__ = "2025.6.0b3"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
Loading…
x
Reference in New Issue
Block a user