Merge remote-tracking branch 'upstream/dev' into HEAD

This commit is contained in:
J. Nick Koston
2026-09-16 09:30:09 -05:00
155 changed files with 772 additions and 413 deletions
+1 -1
View File
@@ -182,7 +182,6 @@ esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_hosted/* @swoboda1337
esphome/components/esp32_hosted/update/* @swoboda1337
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz
esphome/components/esp8266/* @esphome/core
@@ -268,6 +267,7 @@ esphome/components/i2s_audio/speaker/* @jesserockz @kahrendt
esphome/components/iaqcore/* @yozik04
esphome/components/ili9xxx/* @clydebarrow @nielsnl68
esphome/components/improv_base/* @esphome/core
esphome/components/improv_ble/* @jesserockz
esphome/components/improv_serial/* @esphome/core
esphome/components/ina226/* @latonita @Sergio303
esphome/components/ina260/* @mreditor97
+1
View File
@@ -6,5 +6,6 @@ See the component-alias section of esphome/loader.py.
# alias -> (canonical component, removal version or None)
COMPONENT_ALIASES: dict[str, tuple[str, str | None]] = {
"esp32_improv": ("improv_ble", "2027.4.0"),
"rp2040": ("rp2", "2027.7.0"),
}
+1 -1
View File
@@ -94,7 +94,7 @@ class ADCSensor final : public sensor::Sensor, public PollingComponent, public v
/// - SamplingMode::MIN: Use the lowest sample value
/// - SamplingMode::MAX: Use the highest sample value
/// @param sampling_mode The desired sampling mode to use for aggregating ADC samples.
void set_sampling_mode(SamplingMode sampling_mode);
void set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
/// Perform a single ADC sampling operation and return the measured value.
/// This function handles raw readings, calibration, and averaging as needed.
@@ -76,6 +76,4 @@ void ADCSensor::set_sample_count(uint8_t sample_count) {
}
}
void ADCSensor::set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
} // namespace esphome::adc
@@ -138,11 +138,11 @@ class AlarmControlPanel : public EntityBase {
// in order to store last panel state in flash
ESPPreferenceObject pref_;
// current state
AlarmControlPanelState current_state_;
AlarmControlPanelState current_state_{ACP_STATE_DISARMED};
// the desired (or previous) state
AlarmControlPanelState desired_state_;
AlarmControlPanelState desired_state_{ACP_STATE_DISARMED};
// last time the state was updated
uint32_t last_update_;
uint32_t last_update_{0};
// the call control function
virtual void control(const AlarmControlPanelCall &call) = 0;
// state callback - passes the new state to listeners
+18 -6
View File
@@ -136,6 +136,12 @@ CONF_LISTEN_BACKLOG = "listen_backlog"
CONF_MAX_SEND_QUEUE = "max_send_queue"
CONF_STATE_SUBSCRIPTION_ONLY = "state_subscription_only"
# Schema defaults that also match the C++ initializers in api_server.h; codegen
# skips the setter when the config equals them.
DEFAULT_PORT = 6053
DEFAULT_REBOOT_TIMEOUT = "15min"
DEFAULT_BATCH_DELAY = "100ms"
def _register_provisioning_source(config: ConfigType) -> ConfigType:
"""Register the API as a provisioning source when encryption is enabled.
@@ -292,7 +298,7 @@ CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(APIServer),
cv.Optional(CONF_PORT, default=6053): cv.port,
cv.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
# Removed in 2026.1.0 - kept to provide helpful error message
cv.Optional(CONF_PASSWORD): cv.invalid(
"The 'password' option has been removed in ESPHome 2026.1.0.\n"
@@ -305,14 +311,14 @@ CONFIG_SCHEMA = cv.All(
"Or visit https://esphome.io/components/api/#configuration-variables"
),
cv.Optional(
CONF_REBOOT_TIMEOUT, default="15min"
CONF_REBOOT_TIMEOUT, default=DEFAULT_REBOOT_TIMEOUT
): cv.positive_time_period_milliseconds,
cv.Exclusive(
CONF_SERVICES, group_of_exclusion=CONF_ACTIONS
): ACTIONS_SCHEMA,
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
cv.Optional(CONF_ENCRYPTION): encryption_schema,
cv.Optional(CONF_BATCH_DELAY, default="100ms"): cv.All(
cv.Optional(CONF_BATCH_DELAY, default=DEFAULT_BATCH_DELAY): cv.All(
cv.positive_time_period_milliseconds,
cv.Range(max=cv.TimePeriod(milliseconds=65535)),
),
@@ -462,9 +468,15 @@ async def to_code(config: ConfigType) -> None:
# Request a log listener slot for API log streaming
request_log_listener()
cg.add(var.set_port(config[CONF_PORT]))
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
# Skip the setters when the config matches the C++ initializers (DEFAULT_*).
if (port := config[CONF_PORT]) != DEFAULT_PORT:
cg.add(var.set_port(port))
if (reboot_timeout := config[CONF_REBOOT_TIMEOUT]) != cv.time_period(
DEFAULT_REBOOT_TIMEOUT
):
cg.add(var.set_reboot_timeout(reboot_timeout))
if (batch_delay := config[CONF_BATCH_DELAY]) != cv.time_period(DEFAULT_BATCH_DELAY):
cg.add(var.set_batch_delay(batch_delay))
if CONF_LISTEN_BACKLOG in config:
cg.add(var.set_listen_backlog(config[CONF_LISTEN_BACKLOG]))
cg.add_define("MAX_API_CONNECTIONS", config[CONF_MAX_CONNECTIONS])
+3 -3
View File
@@ -314,7 +314,7 @@ class APIServer final : public Component,
#endif
// 4-byte aligned types
uint32_t reboot_timeout_{300000};
uint32_t reboot_timeout_{900000}; // Keep in sync with DEFAULT_REBOOT_TIMEOUT in __init__.py
uint32_t last_connected_{0};
// Slots [0, api_connection_count_) are populated; trailing slots are always nullptr.
@@ -351,8 +351,8 @@ class APIServer final : public Component,
#endif
// Group smaller types together
uint16_t port_{6053};
uint16_t batch_delay_{100};
uint16_t port_{6053}; // Keep in sync with DEFAULT_PORT in __init__.py
uint16_t batch_delay_{100}; // Keep in sync with DEFAULT_BATCH_DELAY in __init__.py
// Connection limits - these defaults will be overridden by config values
// from cv.SplitDefault in __init__.py which sets platform-specific defaults.
uint8_t listen_backlog_{4};
@@ -203,16 +203,10 @@ void BangBangClimate::set_away_config(const BangBangClimateTargetTempConfig &awa
this->away_config_ = away_config;
}
void BangBangClimate::set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
void BangBangClimate::set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
Trigger<> *BangBangClimate::get_idle_trigger() { return &this->idle_trigger_; }
Trigger<> *BangBangClimate::get_cool_trigger() { return &this->cool_trigger_; }
Trigger<> *BangBangClimate::get_heat_trigger() { return &this->heat_trigger_; }
void BangBangClimate::set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
void BangBangClimate::set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
void BangBangClimate::dump_config() {
LOG_CLIMATE("", "Bang Bang Climate", this);
ESP_LOGCONFIG(TAG,
@@ -22,10 +22,10 @@ class BangBangClimate final : public climate::Climate, public Component {
void setup() override;
void dump_config() override;
void set_sensor(sensor::Sensor *sensor);
void set_humidity_sensor(sensor::Sensor *humidity_sensor);
void set_supports_cool(bool supports_cool);
void set_supports_heat(bool supports_heat);
void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
void set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
void set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
void set_normal_config(const BangBangClimateTargetTempConfig &normal_config);
void set_away_config(const BangBangClimateTargetTempConfig &away_config);
@@ -32,7 +32,8 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi
*/
class BinarySensor : public StatefulEntityBase<bool> {
public:
explicit BinarySensor() = default;
// User provided, not "= default": `new(p) BinarySensor()` would zero-fill .bss that is already zero.
explicit BinarySensor() {}
const bool &get_state() const override { return this->state; }
void set_trigger_on_initial_state(bool value) { this->trigger_on_initial_state_ = value; }
@@ -53,6 +53,9 @@ class DelayedOnOffFilter final : public Filter {
class DelayedOnFilter : public Filter {
public:
// User provided, not "= default": `new(p) DelayedOnFilter()` would zero-fill .bss that is already zero.
DelayedOnFilter() {}
optional<bool> new_value(bool value) override;
template<typename T> void set_delay(T delay) { this->delay_ = delay; }
@@ -63,6 +66,9 @@ class DelayedOnFilter : public Filter {
class DelayedOffFilter : public Filter {
public:
// User provided, not "= default": `new(p) DelayedOffFilter()` would zero-fill .bss that is already zero.
DelayedOffFilter() {}
optional<bool> new_value(bool value) override;
template<typename T> void set_delay(T delay) { this->delay_ = delay; }
@@ -143,6 +149,8 @@ class StatelessLambdaFilter : public Filter {
class SettleFilter : public Filter {
public:
// User provided, not "= default": `new(p) SettleFilter()` would zero-fill .bss that is already zero.
SettleFilter() {}
optional<bool> new_value(bool value) override;
template<typename T> void set_delay(T delay) { this->delay_ = delay; }
@@ -31,6 +31,9 @@ class BluetoothConnection;
// void disconnect() cannot overload with an int-returning twin.
class BluedroidGattClient final : public esp32_ble_tracker::ESPBTClient, public Component {
public:
// User provided, not "= default": `new(p) BluedroidGattClient()` would zero-fill .bss that is already zero.
BluedroidGattClient() {}
static constexpr uint16_t UNSET_CONN_ID = 0xFFFF;
// Lifecycle of one connection attempt's service search.
@@ -37,6 +37,9 @@ enum class PendingAck : uint8_t {
class BluetoothConnection final : public ble_device_base::GattClientListener {
public:
// User provided, not "= default": `new(p) BluetoothConnection()` would zero-fill .bss that is already zero.
BluetoothConnection() {}
/// Wire the platform backend. Called from codegen before setup.
void set_backend(ble_device_base::BLEGattConnection *backend) {
this->backend_ = backend;
@@ -341,7 +341,6 @@ void BME280Component::set_pressure_oversampling(BME280Oversampling pressure_over
void BME280Component::set_humidity_oversampling(BME280Oversampling humidity_over_sampling) {
this->humidity_oversampling_ = humidity_over_sampling;
}
void BME280Component::set_iir_filter(BME280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
uint8_t BME280Component::read_u8_(uint8_t a_register) {
uint8_t data = 0;
this->read_byte(a_register, &data);
+1 -1
View File
@@ -69,7 +69,7 @@ class BME280Component : public PollingComponent {
/// Set the oversampling value for the humidity sensor. Default is 16x.
void set_humidity_oversampling(BME280Oversampling humidity_over_sampling);
/// Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
void set_iir_filter(BME280IIRFilter iir_filter);
void set_iir_filter(BME280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
// ========== INTERNAL METHODS ==========
// (In most use cases you won't need these)
-1
View File
@@ -503,7 +503,6 @@ void BME680Component::set_pressure_oversampling(BME680Oversampling pressure_over
void BME680Component::set_humidity_oversampling(BME680Oversampling humidity_oversampling) {
this->humidity_oversampling_ = humidity_oversampling;
}
void BME680Component::set_iir_filter(BME680IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
void BME680Component::set_heater(uint16_t heater_temperature, uint16_t heater_duration) {
this->heater_temperature_ = heater_temperature;
this->heater_duration_ = heater_duration;
+1 -1
View File
@@ -74,7 +74,7 @@ class BME680Component final : public PollingComponent, public i2c::I2CDevice {
/// Set the humidity oversampling value. Defaults to 16X.
void set_humidity_oversampling(BME680Oversampling humidity_oversampling);
/// Set the IIR Filter value. Defaults to no IIR Filter.
void set_iir_filter(BME680IIRFilter iir_filter);
void set_iir_filter(BME680IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
@@ -254,7 +254,6 @@ void BMP280Component::set_temperature_oversampling(BMP280Oversampling temperatur
void BMP280Component::set_pressure_oversampling(BMP280Oversampling pressure_over_sampling) {
this->pressure_oversampling_ = pressure_over_sampling;
}
void BMP280Component::set_iir_filter(BMP280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
uint8_t BMP280Component::read_u8_(uint8_t a_register) {
uint8_t data = 0;
this->bmp_read_byte(a_register, &data);
+1 -1
View File
@@ -59,7 +59,7 @@ class BMP280Component : public PollingComponent {
/// Set the oversampling value for the pressure sensor. Default is 16x.
void set_pressure_oversampling(BMP280Oversampling pressure_over_sampling);
/// Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
void set_iir_filter(BMP280IIRFilter iir_filter);
void set_iir_filter(BMP280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
void setup() override;
void dump_config() override;
@@ -597,7 +597,7 @@ async def to_code(config):
cg.add(parent.advertising_set_appearance(config[CONF_APPEARANCE]))
cg.add(var.set_max_clients(config[CONF_MAX_CLIENTS]))
# Only advertise for the server itself when the configuration gives clients something to
# find. A server that is auto-loaded purely to host a runtime service (esp32_improv) stays
# find. A server that is auto-loaded purely to host a runtime service (improv_ble) stays
# silent until that service asks for advertising.
cg.add(
var.set_advertising_required(
@@ -40,7 +40,7 @@ class BLEServer final : public Component, public Parented<ESP32BLE> {
/** Whether this server needs the device to advertise so clients can find and connect to it.
*
* False for a server that only hosts services created at runtime (e.g. esp32_improv), which
* False for a server that only hosts services created at runtime (e.g. improv_ble), which
* request advertising themselves for as long as they need it.
*/
void set_advertising_required(bool required) { this->advertising_required_ = required; }
@@ -135,7 +135,7 @@ class ESPBTClient : public ESPBTDeviceListener {
void set_tracker_state_version(uint8_t *version) { this->tracker_state_version_ = version; }
// Memory optimized layout
uint8_t app_id; // App IDs are small integers assigned sequentially
uint8_t app_id{0}; // App IDs are small integers assigned sequentially
protected:
/// Set state without IDLE handling - use for direct state transitions.
@@ -433,25 +433,10 @@ void ESP32Camera::set_pixel_format(ESP32CameraPixelFormat format) {
}
}
void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; }
void ESP32Camera::set_vertical_flip(bool vertical_flip) { this->vertical_flip_ = vertical_flip; }
void ESP32Camera::set_horizontal_mirror(bool horizontal_mirror) { this->horizontal_mirror_ = horizontal_mirror; }
void ESP32Camera::set_contrast(int contrast) { this->contrast_ = contrast; }
void ESP32Camera::set_brightness(int brightness) { this->brightness_ = brightness; }
void ESP32Camera::set_saturation(int saturation) { this->saturation_ = saturation; }
void ESP32Camera::set_special_effect(ESP32SpecialEffect effect) { this->special_effect_ = effect; }
/* set exposure parameters */
void ESP32Camera::set_aec_mode(ESP32GainControlMode mode) { this->aec_mode_ = mode; }
void ESP32Camera::set_aec2(bool aec2) { this->aec2_ = aec2; }
void ESP32Camera::set_ae_level(int ae_level) { this->ae_level_ = ae_level; }
void ESP32Camera::set_aec_value(uint32_t aec_value) { this->aec_value_ = aec_value; }
/* set gains parameters */
void ESP32Camera::set_agc_mode(ESP32GainControlMode mode) { this->agc_mode_ = mode; }
void ESP32Camera::set_agc_value(uint8_t agc_value) { this->agc_value_ = agc_value; }
void ESP32Camera::set_agc_gain_ceiling(ESP32AgcGainCeiling gain_ceiling) { this->agc_gain_ceiling_ = gain_ceiling; }
/* set white balance */
void ESP32Camera::set_wb_mode(ESP32WhiteBalanceMode mode) { this->wb_mode_ = mode; }
/* set test mode */
void ESP32Camera::set_test_pattern(bool test_pattern) { this->test_pattern_ = test_pattern; }
/* set fps */
void ESP32Camera::set_max_update_interval(uint32_t max_update_interval) {
this->max_update_interval_ = max_update_interval;
+15 -15
View File
@@ -140,25 +140,25 @@ class ESP32Camera final : public camera::Camera {
void set_pixel_format(ESP32CameraPixelFormat format);
void set_frame_size(ESP32CameraFrameSize size);
void set_jpeg_quality(uint8_t quality);
void set_vertical_flip(bool vertical_flip);
void set_horizontal_mirror(bool horizontal_mirror);
void set_contrast(int contrast);
void set_brightness(int brightness);
void set_saturation(int saturation);
void set_special_effect(ESP32SpecialEffect effect);
void set_vertical_flip(bool vertical_flip) { this->vertical_flip_ = vertical_flip; }
void set_horizontal_mirror(bool horizontal_mirror) { this->horizontal_mirror_ = horizontal_mirror; }
void set_contrast(int contrast) { this->contrast_ = contrast; }
void set_brightness(int brightness) { this->brightness_ = brightness; }
void set_saturation(int saturation) { this->saturation_ = saturation; }
void set_special_effect(ESP32SpecialEffect effect) { this->special_effect_ = effect; }
/* -- exposure */
void set_aec_mode(ESP32GainControlMode mode);
void set_aec2(bool aec2);
void set_ae_level(int ae_level);
void set_aec_value(uint32_t aec_value);
void set_aec_mode(ESP32GainControlMode mode) { this->aec_mode_ = mode; }
void set_aec2(bool aec2) { this->aec2_ = aec2; }
void set_ae_level(int ae_level) { this->ae_level_ = ae_level; }
void set_aec_value(uint32_t aec_value) { this->aec_value_ = aec_value; }
/* -- gains */
void set_agc_mode(ESP32GainControlMode mode);
void set_agc_value(uint8_t agc_value);
void set_agc_gain_ceiling(ESP32AgcGainCeiling gain_ceiling);
void set_agc_mode(ESP32GainControlMode mode) { this->agc_mode_ = mode; }
void set_agc_value(uint8_t agc_value) { this->agc_value_ = agc_value; }
void set_agc_gain_ceiling(ESP32AgcGainCeiling gain_ceiling) { this->agc_gain_ceiling_ = gain_ceiling; }
/* -- white balance */
void set_wb_mode(ESP32WhiteBalanceMode mode);
void set_wb_mode(ESP32WhiteBalanceMode mode) { this->wb_mode_ = mode; }
/* -- test */
void set_test_pattern(bool test_pattern);
void set_test_pattern(bool test_pattern) { this->test_pattern_ = test_pattern; }
/* -- framerates */
void set_max_update_interval(uint32_t max_update_interval);
void set_idle_update_interval(uint32_t idle_update_interval);
+4 -1
View File
@@ -11,6 +11,9 @@ namespace esphome::esp8266_pwm {
class ESP8266PWM final : public output::FloatOutput, public Component {
public:
// User provided, not "= default": `new(p) ESP8266PWM()` would zero-fill .bss that is already zero.
ESP8266PWM() {}
void set_pin(InternalGPIOPin *pin) { pin_ = pin; }
void set_frequency(float frequency) { this->frequency_ = frequency; }
/// Dynamically update frequency
@@ -28,7 +31,7 @@ class ESP8266PWM final : public output::FloatOutput, public Component {
protected:
void write_state(float state) override;
InternalGPIOPin *pin_;
InternalGPIOPin *pin_{nullptr};
float frequency_{1000.0}; // Keep in sync with DEFAULT_FREQUENCY in output.py
/// Cache last output level for dynamic frequency updating
float last_output_{0.0};
@@ -13,6 +13,9 @@ class IPAddressEthernetInfo final : public Component,
public text_sensor::TextSensor,
public ethernet::EthernetIPStateListener {
public:
// User provided, not "= default": `new(p) IPAddressEthernetInfo()` would zero-fill .bss that is already zero.
IPAddressEthernetInfo() {}
void setup() override;
void dump_config() override;
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
+1 -1
View File
@@ -183,7 +183,7 @@ class Fan : public EntityBase {
LazyCallbackManager<void()> state_callback_{};
ESPPreferenceObject rtc_;
FanRestoreMode restore_mode_;
FanRestoreMode restore_mode_{FanRestoreMode::NO_RESTORE};
private:
/// Lazy-allocate preset modes vector (never freed — entity lives forever).
@@ -47,6 +47,9 @@ class GPIOBinarySensorStore {
class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Component {
public:
// User provided, not "= default": `new(p) GPIOBinarySensor()` would zero-fill .bss that is already zero.
GPIOBinarySensor() {}
// No destructor needed: ESPHome components are created at boot and live forever.
// Interrupts are only detached on reboot when memory is cleared anyway.
@@ -70,7 +73,7 @@ class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Compon
void loop() override;
protected:
GPIOPin *pin_;
GPIOPin *pin_{nullptr};
GPIOBinarySensorStore store_;
};
+4 -1
View File
@@ -9,6 +9,9 @@ namespace esphome::gpio {
class GPIOSwitch final : public switch_::Switch, public Component {
public:
// User provided, not "= default": `new(p) GPIOSwitch()` would zero-fill .bss that is already zero.
GPIOSwitch() {}
void set_pin(GPIOPin *pin) { pin_ = pin; }
// ========== INTERNAL METHODS ==========
@@ -25,7 +28,7 @@ class GPIOSwitch final : public switch_::Switch, public Component {
protected:
void write_state(bool state) override;
GPIOPin *pin_;
GPIOPin *pin_{nullptr};
#ifdef USE_GPIO_SWITCH_INTERLOCK
FixedVector<Switch *> interlock_;
uint32_t interlock_wait_time_{0};
@@ -57,10 +57,6 @@ void GraphicalDisplayMenu::dump_config() {
}
}
void GraphicalDisplayMenu::set_display(display::Display *display) { this->display_ = display; }
void GraphicalDisplayMenu::set_font(display::BaseFont *font) { this->font_ = font; }
void GraphicalDisplayMenu::set_foreground_color(Color foreground_color) { this->foreground_color_ = foreground_color; }
void GraphicalDisplayMenu::set_background_color(Color background_color) { this->background_color_ = background_color; }
@@ -38,8 +38,8 @@ class GraphicalDisplayMenu final : public display_menu_base::DisplayMenuComponen
void setup() override;
void dump_config() override;
void set_display(display::Display *display);
void set_font(display::BaseFont *font);
void set_display(display::Display *display) { this->display_ = display; }
void set_font(display::BaseFont *font) { this->font_ = font; }
template<typename V> void set_menu_item_value(V menu_item_value) { this->menu_item_value_ = menu_item_value; }
void set_foreground_color(Color foreground_color);
void set_background_color(Color background_color);
-2
View File
@@ -190,8 +190,6 @@ void HaierClimateBase::set_supported_presets(climate::ClimatePresetMask presets)
this->traits_.add_supported_preset(climate::CLIMATE_PRESET_NONE);
}
void HaierClimateBase::set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; }
void HaierClimateBase::send_custom_command(const haier_protocol::HaierMessage &message) {
this->action_request_ = PendingAction({ActionRequest::SEND_CUSTOM_COMMAND, message});
}
+1 -1
View File
@@ -71,7 +71,7 @@ class HaierClimateBase : public esphome::Component,
};
bool can_send_message() const { return haier_protocol_.get_outgoing_queue_size() == 0; };
void set_answer_timeout(uint32_t timeout);
void set_send_wifi(bool send_wifi);
void set_send_wifi(bool send_wifi) { this->send_wifi_signal_ = send_wifi; }
void send_custom_command(const haier_protocol::HaierMessage &message);
template<typename F> void add_status_message_callback(F &&callback) {
this->status_message_callback_.add(std::forward<F>(callback));
+47 -17
View File
@@ -331,27 +331,46 @@ class HttpRequestComponent : public Component {
void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; }
void set_redirect_limit(uint16_t limit) { this->redirect_limit_ = limit; }
std::shared_ptr<HttpContainer> get(const std::string &url) {
return this->start(url, "GET", "", std::vector<Header>{});
}
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers) {
std::shared_ptr<HttpContainer> get(const char *url) { return this->start(url, "GET", "", std::vector<Header>{}); }
std::shared_ptr<HttpContainer> get(const char *url, const std::vector<Header> &request_headers) {
return this->start(url, "GET", "", request_headers);
}
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
std::shared_ptr<HttpContainer> get(const char *url, const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "GET", "", request_headers, lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
std::shared_ptr<HttpContainer> post(const char *url, const std::string &body) {
return this->start(url, "POST", body, std::vector<Header>{});
}
std::shared_ptr<HttpContainer> post(const char *url, const std::string &body,
const std::vector<Header> &request_headers) {
return this->start(url, "POST", body, request_headers);
}
std::shared_ptr<HttpContainer> post(const char *url, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> get(const std::string &url) { return this->get(url.c_str()); }
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers) {
return this->get(url.c_str(), request_headers);
}
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->get(url.c_str(), request_headers, lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
return this->post(url.c_str(), body);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::vector<Header> &request_headers) {
return this->start(url, "POST", body, request_headers);
return this->post(url.c_str(), body, request_headers);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
return this->post(url.c_str(), body, request_headers, lower_case_collect_headers);
}
// Remove before 2027.1.0
@@ -379,11 +398,15 @@ class HttpRequestComponent : public Component {
return this->post(url, body, std::vector<Header>(request_headers.begin(), request_headers.end()), collect_headers);
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
std::shared_ptr<HttpContainer> start(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers) {
// Call perform() directly to avoid ambiguity with the deprecated overloads
return this->perform(url, method, body, request_headers, {});
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers) {
return this->start(url.c_str(), method.c_str(), body, request_headers);
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
@@ -403,7 +426,7 @@ class HttpRequestComponent : public Component {
for (const auto &h : collect_headers) {
lower.push_back(str_lower_case(h)); // NOLINT
}
return this->perform(url, method, body, request_headers, lower);
return this->perform(url.c_str(), method.c_str(), body, request_headers, lower);
}
// Remove before 2027.1.0
@@ -418,7 +441,8 @@ class HttpRequestComponent : public Component {
for (const auto &h : collect_headers) {
lower.push_back(str_lower_case(h)); // NOLINT
}
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
return this->perform(url.c_str(), method.c_str(), body,
std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
}
// Remove before 2027.1.0
@@ -426,19 +450,25 @@ class HttpRequestComponent : public Component {
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
return this->perform(url.c_str(), method.c_str(), body,
std::vector<Header>(request_headers.begin(), request_headers.end()),
lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
std::shared_ptr<HttpContainer> start(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->perform(url, method, body, request_headers, lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url.c_str(), method.c_str(), body, request_headers, lower_case_collect_headers);
}
protected:
virtual std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method,
const std::string &body, const std::vector<Header> &request_headers,
virtual std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) = 0;
const char *useragent_{nullptr};
bool follow_redirects_{};
@@ -499,8 +529,8 @@ template<typename... Ts> class HttpRequestSendAction final : public Action<Ts...
request_headers.push_back({key, val.value(x...)});
}
auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, request_headers,
this->lower_case_collect_headers_);
auto container = this->parent_->start(this->url_.value(x...).c_str(), this->method_.value(x...), body,
request_headers, this->lower_case_collect_headers_);
auto captured_args = std::make_tuple(x...);
@@ -2,6 +2,8 @@
#if defined(USE_ARDUINO) && !defined(USE_ESP32) && !defined(USE_LIBRETINY)
#include <cstring>
#include "esphome/components/network/util.h"
#include "esphome/components/watchdog/watchdog.h"
@@ -22,8 +24,7 @@ static const char *const TAG = "http_request";
static constexpr int ESP8266_SSL_ERR_OOM = -1000;
#endif
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &url, const std::string &method,
const std::string &body,
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
@@ -37,7 +38,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
const uint32_t start = millis();
bool secure = url.find("https:") != std::string::npos;
bool secure = strstr(url, "https:") != nullptr;
container->set_secure(secure);
watchdog::WatchdogManager wdm(this->get_watchdog_timeout());
@@ -70,19 +71,19 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
stream_ptr = std::make_unique<WiFiClient>();
#endif // USE_HTTP_REQUEST_ESP8266_HTTPS
bool status = container->client_.begin(*stream_ptr, url.c_str());
bool status = container->client_.begin(*stream_ptr, url);
#elif defined(USE_RP2)
if (secure) {
container->client_.setInsecure();
}
bool status = container->client_.begin(url.c_str());
bool status = container->client_.begin(url);
#endif
App.feed_wdt();
if (!status) {
ESP_LOGW(TAG, "HTTP Request failed; URL: %s", url.c_str());
ESP_LOGW(TAG, "HTTP Request failed; URL: %s", url);
container->end();
this->status_momentary_error("failed", 1000);
return nullptr;
@@ -107,7 +108,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
container->client_.collectHeaders(header_keys, index);
App.feed_wdt();
container->status_code = container->client_.sendRequest(method.c_str(), body.c_str());
container->status_code = container->client_.sendRequest(method, body.c_str());
App.feed_wdt();
if (container->status_code < 0) {
#if defined(USE_ESP8266) && defined(USE_HTTP_REQUEST_ESP8266_HTTPS)
@@ -139,7 +140,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
}
#endif
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url.c_str(),
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url,
HTTPClient::errorToString(container->status_code).c_str());
this->status_momentary_error("failed", 1000);
@@ -147,7 +148,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
return nullptr;
}
if (!is_success(container->status_code)) {
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code);
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url, container->status_code);
this->status_momentary_error("failed", 1000);
// Still return the container, so it can be used to get the status code and error message
}
@@ -54,7 +54,7 @@ class HttpRequestArduino final : public HttpRequestComponent {
#endif
protected:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) override;
#ifdef USE_ESP8266
@@ -5,6 +5,8 @@
#include "httplib.h"
#include "http_request_host.h"
#include <cstring>
#include <regex>
#include "esphome/components/network/util.h"
#include "esphome/components/watchdog/watchdog.h"
@@ -16,8 +18,7 @@ namespace esphome::http_request {
static const char *const TAG = "http_request";
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url, const std::string &method,
const std::string &body,
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
@@ -27,10 +28,10 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
}
std::regex url_regex(R"(^(([^:\/?#]+):)?(//([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)", std::regex::extended);
std::smatch url_match_result;
std::cmatch url_match_result;
if (!std::regex_match(url, url_match_result, url_regex) || url_match_result.length() < 7) {
ESP_LOGE(TAG, "HTTP Request failed; Malformed URL: %s", url.c_str());
ESP_LOGE(TAG, "HTTP Request failed; Malformed URL: %s", url);
return nullptr;
}
auto host = url_match_result[4].str();
@@ -54,7 +55,7 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
}
httplib::Client client(scheme_host.c_str());
if (!client.is_valid()) {
ESP_LOGE(TAG, "HTTP Request failed; Invalid URL: %s", url.c_str());
ESP_LOGE(TAG, "HTTP Request failed; Invalid URL: %s", url);
return nullptr;
}
client.set_follow_location(this->follow_redirects_);
@@ -64,41 +65,41 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
#endif
httplib::Result result;
if (method == "GET") {
if (strcmp(method, "GET") == 0) {
result = client.Get(path, h_headers, [&](const char *data, size_t data_length) {
ESP_LOGV(TAG, "Got data length: %zu", data_length);
container->response_body_.insert(container->response_body_.end(), (const uint8_t *) data,
(const uint8_t *) data + data_length);
return true;
});
} else if (method == "HEAD") {
} else if (strcmp(method, "HEAD") == 0) {
result = client.Head(path, h_headers);
} else if (method == "PUT") {
} else if (strcmp(method, "PUT") == 0) {
result = client.Put(path, h_headers, body, "");
if (result) {
auto data = std::vector<uint8_t>(result->body.begin(), result->body.end());
container->response_body_.insert(container->response_body_.end(), data.begin(), data.end());
}
} else if (method == "PATCH") {
} else if (strcmp(method, "PATCH") == 0) {
result = client.Patch(path, h_headers, body, "");
if (result) {
auto data = std::vector<uint8_t>(result->body.begin(), result->body.end());
container->response_body_.insert(container->response_body_.end(), data.begin(), data.end());
}
} else if (method == "POST") {
} else if (strcmp(method, "POST") == 0) {
result = client.Post(path, h_headers, body, "");
if (result) {
auto data = std::vector<uint8_t>(result->body.begin(), result->body.end());
container->response_body_.insert(container->response_body_.end(), data.begin(), data.end());
}
} else {
ESP_LOGW(TAG, "HTTP Request failed - unsupported method %s; URL: %s", method.c_str(), url.c_str());
ESP_LOGW(TAG, "HTTP Request failed - unsupported method %s; URL: %s", method, url);
container->end();
return nullptr;
}
App.feed_wdt();
if (!result) {
ESP_LOGW(TAG, "HTTP Request failed; URL: %s, error code: %u", url.c_str(), (unsigned) result.error());
ESP_LOGW(TAG, "HTTP Request failed; URL: %s, error code: %u", url, (unsigned) result.error());
container->end();
this->status_momentary_error("failed", 1000);
return nullptr;
@@ -107,7 +108,7 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
auto response = *result;
container->status_code = response.status;
if (!is_success(response.status)) {
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), response.status);
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url, response.status);
this->status_momentary_error("failed", 1000);
// Still return the container, so it can be used to get the status code and error message
}
@@ -18,7 +18,7 @@ class HttpContainerHost : public HttpContainer {
class HttpRequestHost final : public HttpRequestComponent {
public:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) override;
void set_ca_path(const char *ca_path) { this->ca_path_ = ca_path; }
@@ -2,6 +2,8 @@
#ifdef USE_ESP32
#include <cstring>
#include "esphome/components/network/util.h"
#include "esphome/components/watchdog/watchdog.h"
@@ -48,8 +50,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
return ESP_OK;
}
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, const std::string &method,
const std::string &body,
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
@@ -59,15 +60,15 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
}
esp_http_client_method_t method_idf;
if (method == "GET") {
if (strcmp(method, "GET") == 0) {
method_idf = HTTP_METHOD_GET;
} else if (method == "POST") {
} else if (strcmp(method, "POST") == 0) {
method_idf = HTTP_METHOD_POST;
} else if (method == "PUT") {
} else if (strcmp(method, "PUT") == 0) {
method_idf = HTTP_METHOD_PUT;
} else if (method == "DELETE") {
} else if (strcmp(method, "DELETE") == 0) {
method_idf = HTTP_METHOD_DELETE;
} else if (method == "PATCH") {
} else if (strcmp(method, "PATCH") == 0) {
method_idf = HTTP_METHOD_PATCH;
} else {
this->status_momentary_error("failed", ERROR_DURATION_MS);
@@ -75,11 +76,11 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
return nullptr;
}
bool secure = url.find("https:") != std::string::npos;
bool secure = strstr(url, "https:") != nullptr;
esp_http_client_config_t config = {};
config.url = url.c_str();
config.url = url;
config.method = method_idf;
config.timeout_ms = this->timeout_;
config.disable_auto_redirect = !this->follow_redirects_;
@@ -218,7 +219,7 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
}
}
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code);
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url, container->status_code);
this->status_momentary_error("failed", ERROR_DURATION_MS);
return container;
}
@@ -30,6 +30,9 @@ class HttpContainerIDF : public HttpContainer {
class HttpRequestIDF final : public HttpRequestComponent {
public:
// User provided, not "= default": `new(p) HttpRequestIDF()` would zero-fill .bss that is already zero.
HttpRequestIDF() {}
void dump_config() override;
void set_buffer_size_rx(uint16_t buffer_size_rx) { this->buffer_size_rx_ = buffer_size_rx; }
@@ -38,7 +41,7 @@ class HttpRequestIDF final : public HttpRequestComponent {
void set_ca_certificate(const char *ca_certificate) { this->ca_certificate_ = ca_certificate; }
protected:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) override;
// if zero ESP-IDF will use DEFAULT_HTTP_BUF_SIZE
@@ -1,5 +1,7 @@
#include "http_request_update.h"
#include <cstring>
#include "esphome/core/application.h"
#include "esphome/core/version.h"
@@ -94,7 +96,7 @@ void HttpRequestUpdate::update_task(void *params) {
auto container = this_update->request_parent_->get(this_update->source_url_);
if (container == nullptr || container->status_code != HTTP_STATUS_OK) {
ESP_LOGE(TAG, "Failed to fetch manifest from %s", this_update->source_url_.c_str());
ESP_LOGE(TAG, "Failed to fetch manifest from %s", this_update->source_url_);
if (container != nullptr)
container->end();
result->error_str = LOG_STR("Failed to fetch manifest");
@@ -174,21 +176,26 @@ void HttpRequestUpdate::update_task(void *params) {
allocator.deallocate(data, content_length);
if (!valid) {
ESP_LOGE(TAG, "Failed to parse JSON from %s", this_update->source_url_.c_str());
ESP_LOGE(TAG, "Failed to parse JSON from %s", this_update->source_url_);
result->error_str = LOG_STR("Failed to parse manifest JSON");
goto defer; // NOLINT(cppcoreguidelines-avoid-goto)
}
// Merge source_url_ and firmware_url
if (!info->firmware_url.empty() && info->firmware_url.find("http") == std::string::npos) {
std::string path = info->firmware_url;
if (path[0] == '/') {
std::string domain = this_update->source_url_.substr(0, this_update->source_url_.find('/', 8));
info->firmware_url = domain + path;
const char *source = this_update->source_url_;
const size_t source_len = strlen(source);
size_t prefix_len;
if (info->firmware_url[0] == '/') {
// scheme and host, up to the first slash after "https://"
const char *host_end = source_len > 8 ? strchr(source + 8, '/') : nullptr;
prefix_len = host_end != nullptr ? host_end - source : source_len;
} else {
std::string domain = this_update->source_url_.substr(0, this_update->source_url_.rfind('/') + 1);
info->firmware_url = domain + path;
// directory of the manifest, up to and including its last slash
const char *dir_end = strrchr(source, '/');
prefix_len = dir_end != nullptr ? dir_end - source + 1 : 0;
}
info->firmware_url.insert(0, source, prefix_len);
}
#ifdef ESPHOME_PROJECT_VERSION
@@ -21,7 +21,7 @@ class HttpRequestUpdate final : public update::UpdateEntity, public PollingCompo
void perform(bool force) override;
void check() override { this->update(); }
void set_source_url(const std::string &source_url) { this->source_url_ = source_url; }
void set_source_url(const char *source_url) { this->source_url_ = source_url; }
void set_request_parent(HttpRequestComponent *request_parent) { this->request_parent_ = request_parent; }
void set_ota_parent(OtaHttpRequestComponent *ota_parent) { this->ota_parent_ = ota_parent; }
@@ -33,13 +33,15 @@ class HttpRequestUpdate final : public update::UpdateEntity, public PollingCompo
protected:
HttpRequestComponent *request_parent_;
OtaHttpRequestComponent *ota_parent_;
std::string source_url_;
static void update_task(void *params);
#ifdef USE_ESP32
TaskHandle_t update_task_handle_{nullptr};
#endif
uint8_t initial_check_remaining_{0};
private:
const char *source_url_{nullptr}; // literal from codegen
};
} // namespace esphome::http_request
+4 -2
View File
@@ -38,9 +38,11 @@ def _process_next_url(url: str) -> str:
return url
async def setup_improv_core(var: MockObj, config: ConfigType, component: str) -> None:
async def setup_improv_core(var: MockObj, config: ConfigType) -> None:
if next_url := config.get(CONF_NEXT_URL):
cg.add(var.set_next_url(_process_next_url(next_url)))
cg.add_define(f"USE_{component.upper()}_NEXT_URL")
# One define for all transports: next_url_ is per object, so a transport
# configured without next_url: calls add_next_url_ and appends nothing.
cg.add_define("USE_IMPROV_NEXT_URL")
cg.add_library("improv/Improv", "1.2.7")
@@ -8,7 +8,7 @@
namespace esphome::improv_base {
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
#ifdef USE_IMPROV_NEXT_URL
static const char *const TAG = "improv_base";
static constexpr const char DEVICE_NAME_PLACEHOLDER[] = "{{device_name}}";
+3 -3
View File
@@ -3,7 +3,7 @@
#include <cstddef>
#include "esphome/core/defines.h"
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
#ifdef USE_IMPROV_NEXT_URL
#include <improv.h>
#endif
@@ -11,12 +11,12 @@ namespace esphome::improv_base {
class ImprovBase {
public:
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
#ifdef USE_IMPROV_NEXT_URL
void set_next_url(const char *next_url) { this->next_url_ = next_url; }
#endif
protected:
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
#ifdef USE_IMPROV_NEXT_URL
/// Format next_url_ into buffer, replacing placeholders. Returns length written.
size_t get_formatted_next_url_(char *buffer, size_t buffer_size);
/// Append the formatted next_url to the RPC response, warning if it does not fit.
@@ -1,14 +1,41 @@
from esphome import automation
import esphome.codegen as cg
from esphome.components import binary_sensor, esp32_ble, improv_base, output
from esphome.components.esp32_ble import BTLoggers
from esphome.components import binary_sensor, improv_base, output
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_ON_START, CONF_ON_STATE, CONF_TRIGGER_ID
from esphome.const import (
CONF_ID,
CONF_ON_START,
CONF_ON_STATE,
CONF_TRIGGER_ID,
PLATFORM_ESP32,
)
from esphome.core import CORE
from esphome.types import ConfigType
AUTO_LOAD = ["esp32_ble_server", "improv_base"]
# The BLE GATT server component that hosts the Improv service, per target
# platform. improv_ble itself is platform neutral; supporting another chip
# means adding its BLE server component here and the matching backend in
# improv_ble_component.cpp. Doubles as the platform gate below, so an
# unsupported chip is rejected in validation rather than at link time.
BLE_SERVER_BACKENDS: dict[str, str] = {
PLATFORM_ESP32: "esp32_ble_server",
}
def AUTO_LOAD() -> list[str]:
auto_load = ["improv_base"]
if backend := BLE_SERVER_BACKENDS.get(CORE.target_platform):
auto_load.append(backend)
return auto_load
CODEOWNERS = ["@jesserockz"]
DEPENDENCIES = ["wifi", "esp32"]
DEPENDENCIES = ["wifi"]
# Legacy top-level YAML key that routes here; esphome/loader.py and
# esphome/config.py handle the warning and the key rename.
ALIASES = ["esp32_improv"]
ALIAS_REMOVAL_VERSION = "2027.4.0"
CONF_AUTHORIZED_DURATION = "authorized_duration"
CONF_AUTHORIZER = "authorizer"
@@ -29,29 +56,29 @@ improv_ns = cg.esphome_ns.namespace("improv")
Error = improv_ns.enum("Error")
State = improv_ns.enum("State")
esp32_improv_ns = cg.esphome_ns.namespace("esp32_improv")
ESP32ImprovComponent = esp32_improv_ns.class_("ESP32ImprovComponent", cg.Component)
ESP32ImprovProvisionedTrigger = esp32_improv_ns.class_(
"ESP32ImprovProvisionedTrigger", automation.Trigger.template()
improv_ble_ns = cg.esphome_ns.namespace("improv_ble")
ImprovBLEComponent = improv_ble_ns.class_("ImprovBLEComponent", cg.Component)
ImprovBLEProvisionedTrigger = improv_ble_ns.class_(
"ImprovBLEProvisionedTrigger", automation.Trigger.template()
)
ESP32ImprovProvisioningTrigger = esp32_improv_ns.class_(
"ESP32ImprovProvisioningTrigger", automation.Trigger.template()
ImprovBLEProvisioningTrigger = improv_ble_ns.class_(
"ImprovBLEProvisioningTrigger", automation.Trigger.template()
)
ESP32ImprovStartTrigger = esp32_improv_ns.class_(
"ESP32ImprovStartTrigger", automation.Trigger.template()
ImprovBLEStartTrigger = improv_ble_ns.class_(
"ImprovBLEStartTrigger", automation.Trigger.template()
)
ESP32ImprovStateTrigger = esp32_improv_ns.class_(
"ESP32ImprovStateTrigger", automation.Trigger.template()
ImprovBLEStateTrigger = improv_ble_ns.class_(
"ImprovBLEStateTrigger", automation.Trigger.template()
)
ESP32ImprovStoppedTrigger = esp32_improv_ns.class_(
"ESP32ImprovStoppedTrigger", automation.Trigger.template()
ImprovBLEStoppedTrigger = improv_ble_ns.class_(
"ImprovBLEStoppedTrigger", automation.Trigger.template()
)
CONFIG_SCHEMA = (
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ESP32ImprovComponent),
cv.GenerateID(): cv.declare_id(ImprovBLEComponent),
cv.Required(CONF_AUTHORIZER): cv.Any(
cv.none, cv.use_id(binary_sensor.BinarySensor)
),
@@ -68,55 +95,60 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_ON_PROVISIONED): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
ESP32ImprovProvisionedTrigger
ImprovBLEProvisionedTrigger
),
}
),
cv.Optional(CONF_ON_PROVISIONING): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
ESP32ImprovProvisioningTrigger
ImprovBLEProvisioningTrigger
),
}
),
cv.Optional(CONF_ON_START): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
ESP32ImprovStartTrigger
ImprovBLEStartTrigger
),
}
),
cv.Optional(CONF_ON_STATE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
ESP32ImprovStateTrigger
ImprovBLEStateTrigger
),
}
),
cv.Optional(CONF_ON_STOP): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
ESP32ImprovStoppedTrigger
ImprovBLEStoppedTrigger
),
}
),
}
)
.extend(improv_base.IMPROV_SCHEMA)
.extend(cv.COMPONENT_SCHEMA)
.extend(cv.COMPONENT_SCHEMA),
cv.only_on(list(BLE_SERVER_BACKENDS)),
)
async def to_code(config: ConfigType) -> None:
# ESP32 backend setup: the platform gate above means this is the only backend
# that can reach to_code. Make it conditional when a second one is added.
from esphome.components import esp32_ble
# Register the loggers this component needs
esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP)
esp32_ble.register_bt_logger(esp32_ble.BTLoggers.GATT, esp32_ble.BTLoggers.SMP)
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add_define("USE_IMPROV")
cg.add_define("USE_IMPROV_BLE")
await improv_base.setup_improv_core(var, config, "esp32_improv")
await improv_base.setup_improv_core(var, config)
cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION]))
cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION]))
@@ -155,4 +187,4 @@ async def to_code(config: ConfigType) -> None:
await automation.build_automation(trigger, [], conf)
use_state_callback = True
if use_state_callback:
cg.add_define("USE_ESP32_IMPROV_STATE_CALLBACK")
cg.add_define("USE_IMPROV_BLE_STATE_CALLBACK")
@@ -1,17 +1,17 @@
#pragma once
#ifdef USE_ESP32
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
#include "esp32_improv_component.h"
#ifdef USE_IMPROV_BLE_STATE_CALLBACK
#include "improv_ble_component.h"
#include "esphome/core/automation.h"
#include <improv.h>
namespace esphome::esp32_improv {
namespace esphome::improv_ble {
class ESP32ImprovProvisionedTrigger final : public Trigger<> {
class ImprovBLEProvisionedTrigger final : public Trigger<> {
public:
explicit ESP32ImprovProvisionedTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
explicit ImprovBLEProvisionedTrigger(ImprovBLEComponent *parent) : parent_(parent) {
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
if (state == improv::STATE_PROVISIONED && !this->parent_->is_failed()) {
this->trigger();
@@ -20,12 +20,12 @@ class ESP32ImprovProvisionedTrigger final : public Trigger<> {
}
protected:
ESP32ImprovComponent *parent_;
ImprovBLEComponent *parent_;
};
class ESP32ImprovProvisioningTrigger final : public Trigger<> {
class ImprovBLEProvisioningTrigger final : public Trigger<> {
public:
explicit ESP32ImprovProvisioningTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
explicit ImprovBLEProvisioningTrigger(ImprovBLEComponent *parent) : parent_(parent) {
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
if (state == improv::STATE_PROVISIONING && !this->parent_->is_failed()) {
this->trigger();
@@ -34,12 +34,12 @@ class ESP32ImprovProvisioningTrigger final : public Trigger<> {
}
protected:
ESP32ImprovComponent *parent_;
ImprovBLEComponent *parent_;
};
class ESP32ImprovStartTrigger final : public Trigger<> {
class ImprovBLEStartTrigger final : public Trigger<> {
public:
explicit ESP32ImprovStartTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
explicit ImprovBLEStartTrigger(ImprovBLEComponent *parent) : parent_(parent) {
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
if ((state == improv::STATE_AUTHORIZED || state == improv::STATE_AWAITING_AUTHORIZATION) &&
!this->parent_->is_failed()) {
@@ -49,12 +49,12 @@ class ESP32ImprovStartTrigger final : public Trigger<> {
}
protected:
ESP32ImprovComponent *parent_;
ImprovBLEComponent *parent_;
};
class ESP32ImprovStateTrigger final : public Trigger<improv::State, improv::Error> {
class ImprovBLEStateTrigger final : public Trigger<improv::State, improv::Error> {
public:
explicit ESP32ImprovStateTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
explicit ImprovBLEStateTrigger(ImprovBLEComponent *parent) : parent_(parent) {
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
if (!this->parent_->is_failed()) {
this->trigger(state, error);
@@ -63,12 +63,12 @@ class ESP32ImprovStateTrigger final : public Trigger<improv::State, improv::Erro
}
protected:
ESP32ImprovComponent *parent_;
ImprovBLEComponent *parent_;
};
class ESP32ImprovStoppedTrigger final : public Trigger<> {
class ImprovBLEStoppedTrigger final : public Trigger<> {
public:
explicit ESP32ImprovStoppedTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
explicit ImprovBLEStoppedTrigger(ImprovBLEComponent *parent) : parent_(parent) {
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
if (state == improv::STATE_STOPPED && !this->parent_->is_failed()) {
this->trigger();
@@ -77,10 +77,10 @@ class ESP32ImprovStoppedTrigger final : public Trigger<> {
}
protected:
ESP32ImprovComponent *parent_;
ImprovBLEComponent *parent_;
};
} // namespace esphome::esp32_improv
} // namespace esphome::improv_ble
#endif
#endif
@@ -1,10 +1,7 @@
#include "esp32_improv_component.h"
#include "improv_ble_component.h"
#include <array>
#include "esphome/components/bytebuffer/bytebuffer.h"
#include "esphome/components/esp32_ble/ble.h"
#include "esphome/components/esp32_ble_server/ble_2902.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
@@ -15,11 +12,15 @@
#ifdef USE_ESP32
namespace esphome::esp32_improv {
#include "esphome/components/bytebuffer/bytebuffer.h"
#include "esphome/components/esp32_ble/ble.h"
#include "esphome/components/esp32_ble_server/ble_2902.h"
namespace esphome::improv_ble {
using namespace bytebuffer;
static const char *const TAG = "esp32_improv.component";
static const char *const TAG = "improv_ble.component";
static constexpr size_t IMPROV_MAX_LOG_BYTES = 128;
static constexpr char ESPHOME_MY_LINK[] = "https://my.home-assistant.io/redirect/config_flow_start?domain=esphome";
// command + data length + trailing byte
@@ -38,9 +39,9 @@ static constexpr uint8_t IMPROV_SERVICE_DATA_SIZE = 8;
static constexpr uint8_t IMPROV_PROTOCOL_ID_1 = 0x77; // 'P' << 1 | 'R' >> 7
static constexpr uint8_t IMPROV_PROTOCOL_ID_2 = 0x46; // 'I' << 1 | 'M' >> 7
ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; }
ImprovBLEComponent::ImprovBLEComponent() { global_improv_component = this; }
void ESP32ImprovComponent::setup() {
void ImprovBLEComponent::setup() {
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr) {
this->authorizer_->add_on_state_callback([this](bool state) {
@@ -66,7 +67,7 @@ void ESP32ImprovComponent::setup() {
this->disable_loop();
}
void ESP32ImprovComponent::setup_characteristics() {
void ImprovBLEComponent::setup_characteristics() {
this->status_ = this->service_->create_characteristic(
improv::STATUS_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor *status_descriptor = new BLE2902();
@@ -104,11 +105,11 @@ void ESP32ImprovComponent::setup_characteristics() {
this->setup_complete_ = true;
}
void ESP32ImprovComponent::loop() {
void ImprovBLEComponent::loop() {
if (!global_ble_server->is_running()) {
if (this->state_ != improv::STATE_STOPPED) {
this->state_ = improv::STATE_STOPPED;
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
#ifdef USE_IMPROV_BLE_STATE_CALLBACK
this->state_callback_.call(this->state_, this->error_state_);
#endif
}
@@ -200,7 +201,7 @@ void ESP32ImprovComponent::loop() {
}
}
void ESP32ImprovComponent::set_status_indicator_state_(bool state) {
void ImprovBLEComponent::set_status_indicator_state_(bool state) {
#ifdef USE_OUTPUT
if (this->status_indicator_ == nullptr)
return;
@@ -216,7 +217,7 @@ void ESP32ImprovComponent::set_status_indicator_state_(bool state) {
}
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
const char *ESP32ImprovComponent::state_to_string_(improv::State state) {
const char *ImprovBLEComponent::state_to_string_(improv::State state) {
switch (state) {
case improv::STATE_STOPPED:
return "STOPPED";
@@ -234,7 +235,7 @@ const char *ESP32ImprovComponent::state_to_string_(improv::State state) {
}
#endif
bool ESP32ImprovComponent::check_identify_() {
bool ImprovBLEComponent::check_identify_() {
uint32_t now = millis();
bool identify = this->identify_start_ != 0 && now - this->identify_start_ <= this->identify_duration_;
@@ -246,7 +247,7 @@ bool ESP32ImprovComponent::check_identify_() {
return identify;
}
void ESP32ImprovComponent::set_state_(improv::State state, bool update_advertising) {
void ImprovBLEComponent::set_state_(improv::State state, bool update_advertising) {
// Skip if state hasn't changed
if (this->state_ == state) {
return;
@@ -274,12 +275,12 @@ void ESP32ImprovComponent::set_state_(improv::State state, bool update_advertisi
// Advertise the new state via service data
this->advertise_service_data_();
}
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
#ifdef USE_IMPROV_BLE_STATE_CALLBACK
this->state_callback_.call(this->state_, this->error_state_);
#endif
}
void ESP32ImprovComponent::set_error_(improv::Error error) {
void ImprovBLEComponent::set_error_(improv::Error error) {
if (error != improv::ERROR_NONE) {
ESP_LOGE(TAG, "Error: %d", error);
}
@@ -295,14 +296,14 @@ void ESP32ImprovComponent::set_error_(improv::Error error) {
}
}
void ESP32ImprovComponent::send_response_(std::span<const uint8_t> response) {
void ImprovBLEComponent::send_response_(std::span<const uint8_t> response) {
// The BLE characteristic owns its value, so one exact-size copy is required here
this->rpc_response_->set_value(std::vector<uint8_t>(response.begin(), response.end()));
if (this->state_ != improv::STATE_STOPPED)
this->rpc_response_->notify();
}
void ESP32ImprovComponent::start() {
void ImprovBLEComponent::start() {
if (this->should_start_ || this->state_ != improv::STATE_STOPPED)
return;
@@ -320,7 +321,7 @@ void ESP32ImprovComponent::start() {
this->enable_loop();
}
void ESP32ImprovComponent::stop() {
void ImprovBLEComponent::stop() {
this->should_start_ = false;
// Wait before stopping the service to ensure all BLE clients see the state change.
// This prevents clients from repeatedly reconnecting and wasting resources by allowing
@@ -335,10 +336,10 @@ void ESP32ImprovComponent::stop() {
});
}
float ESP32ImprovComponent::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; }
float ImprovBLEComponent::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; }
void ESP32ImprovComponent::dump_config() {
ESP_LOGCONFIG(TAG, "ESP32 Improv:");
void ImprovBLEComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Improv BLE:");
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_);
#endif
@@ -347,7 +348,7 @@ void ESP32ImprovComponent::dump_config() {
#endif
}
void ESP32ImprovComponent::process_incoming_data_() {
void ImprovBLEComponent::process_incoming_data_() {
if (this->incoming_data_.size() < 3)
return;
uint8_t length = this->incoming_data_[1];
@@ -422,7 +423,7 @@ void ESP32ImprovComponent::process_incoming_data_() {
}
}
void ESP32ImprovComponent::on_wifi_connect_timeout_() {
void ImprovBLEComponent::on_wifi_connect_timeout_() {
this->set_error_(improv::ERROR_UNABLE_TO_CONNECT);
this->set_state_(improv::STATE_AUTHORIZED);
#ifdef USE_BINARY_SENSOR
@@ -433,7 +434,7 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() {
wifi::global_wifi_component->clear_sta();
}
void ESP32ImprovComponent::check_wifi_connection_() {
void ImprovBLEComponent::check_wifi_connection_() {
if (!wifi::global_wifi_component->is_connected()) {
return;
}
@@ -447,7 +448,7 @@ void ESP32ImprovComponent::check_wifi_connection_() {
std::array<uint8_t, improv::RPC_RESPONSE_MAX_SIZE> buf;
improv::RpcResponseBuilder builder(buf, improv::WIFI_SETTINGS);
#ifdef USE_ESP32_IMPROV_NEXT_URL
#ifdef USE_IMPROV_NEXT_URL
// Add next_url if configured (should be first per Improv BLE spec)
this->add_next_url_(builder, MAX_NEXT_URL_LEN);
#endif
@@ -480,7 +481,7 @@ void ESP32ImprovComponent::check_wifi_connection_() {
this->stop();
}
void ESP32ImprovComponent::advertise_service_data_() {
void ImprovBLEComponent::advertise_service_data_() {
uint8_t service_data[IMPROV_SERVICE_DATA_SIZE] = {};
service_data[0] = IMPROV_PROTOCOL_ID_1; // PR
service_data[1] = IMPROV_PROTOCOL_ID_2; // IM
@@ -499,7 +500,7 @@ void ESP32ImprovComponent::advertise_service_data_() {
esp32_ble::global_ble->advertising_set_service_data_and_name(std::span<const uint8_t>(service_data), false);
}
void ESP32ImprovComponent::update_advertising_type_() {
void ImprovBLEComponent::update_advertising_type_() {
uint32_t now = App.get_loop_component_start_time();
// If we're advertising the device name and it's been more than NAME_ADVERTISING_DURATION, switch back to service data
@@ -524,21 +525,21 @@ void ESP32ImprovComponent::update_advertising_type_() {
}
}
void ESP32ImprovComponent::request_advertising_() {
void ImprovBLEComponent::request_advertising_() {
if (this->advertising_requested_)
return;
this->advertising_requested_ = true;
esp32_ble::global_ble->advertising_start();
}
void ESP32ImprovComponent::release_advertising_() {
void ImprovBLEComponent::release_advertising_() {
if (!this->advertising_requested_)
return;
this->advertising_requested_ = false;
esp32_ble::global_ble->advertising_stop();
}
improv::State ESP32ImprovComponent::get_initial_state_() const {
improv::State ImprovBLEComponent::get_initial_state_() const {
#ifdef USE_BINARY_SENSOR
// If we have an authorizer, start in awaiting authorization state
return this->authorizer_ == nullptr ? improv::STATE_AUTHORIZED : improv::STATE_AWAITING_AUTHORIZATION;
@@ -548,8 +549,8 @@ improv::State ESP32ImprovComponent::get_initial_state_() const {
#endif
}
ESP32ImprovComponent *global_improv_component = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
ImprovBLEComponent *global_improv_component = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace esphome::esp32_improv
} // namespace esphome::improv_ble
#endif
@@ -5,12 +5,10 @@
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include "esphome/components/improv_base/improv_base.h"
#include "esphome/components/wifi/wifi_component.h"
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
#ifdef USE_IMPROV_BLE_STATE_CALLBACK
#include "esphome/core/automation.h"
#endif
@@ -25,17 +23,23 @@
#include <span>
#include <vector>
// ESP-IDF is currently the only target platform with a BLE GATT server, so it is
// the only backend this component has. The Python side keeps the platform table
// (BLE_SERVER_BACKENDS in __init__.py); a second backend adds another arm here.
#ifdef USE_ESP32
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include <improv.h>
namespace esphome::esp32_improv {
namespace esphome::improv_ble {
using namespace esp32_ble_server;
class ESP32ImprovComponent final : public Component, public improv_base::ImprovBase {
class ImprovBLEComponent final : public Component, public improv_base::ImprovBase {
public:
ESP32ImprovComponent();
ImprovBLEComponent();
void dump_config() override;
void loop() override;
void setup() override;
@@ -47,7 +51,7 @@ class ESP32ImprovComponent final : public Component, public improv_base::ImprovB
bool is_active() const { return this->state_ != improv::STATE_STOPPED; }
bool should_start() const { return this->should_start_; }
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
#ifdef USE_IMPROV_BLE_STATE_CALLBACK
template<typename F> void add_on_state_callback(F &&callback) {
this->state_callback_.add(std::forward<F>(callback));
}
@@ -97,7 +101,7 @@ class ESP32ImprovComponent final : public Component, public improv_base::ImprovB
improv::State state_{improv::STATE_STOPPED};
improv::Error error_state_{improv::ERROR_NONE};
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
#ifdef USE_IMPROV_BLE_STATE_CALLBACK
CallbackManager<void(improv::State, improv::Error)> state_callback_{};
#endif
@@ -125,8 +129,8 @@ class ESP32ImprovComponent final : public Component, public improv_base::ImprovB
};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern ESP32ImprovComponent *global_improv_component;
extern ImprovBLEComponent *global_improv_component;
} // namespace esphome::esp32_improv
} // namespace esphome::improv_ble
#endif
+1 -1
View File
@@ -70,7 +70,7 @@ FINAL_VALIDATE_SCHEMA = validate_transport
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await improv_base.setup_improv_core(var, config, "improv_serial")
await improv_base.setup_improv_core(var, config)
cg.add_define("USE_IMPROV_SERIAL")
if (uart_id := config.get(CONF_UART_ID)) is not None:
cg.add(var.set_uart(await cg.get_variable(uart_id)))
@@ -208,7 +208,7 @@ void ImprovSerialComponent::add_webserver_urls_(improv::RpcResponseBuilder &buil
void ImprovSerialComponent::send_settings_response_(improv::Command command) {
std::array<uint8_t, improv::RPC_RESPONSE_MAX_SIZE> buf;
improv::RpcResponseBuilder builder(buf, command);
#ifdef USE_IMPROV_SERIAL_NEXT_URL
#ifdef USE_IMPROV_NEXT_URL
this->add_next_url_(builder, MAX_NEXT_URL_LEN);
#endif
#ifdef USE_WEBSERVER
@@ -55,7 +55,7 @@ static const uint8_t IMPROV_SERIAL_VERSION = 1;
#ifdef USE_WIFI
// Wi-Fi connect failure timers: a fresh provision reports at 30 s (stock behavior), while
// switching networks on an already-connected device (disconnect + reconnect) can legitimately
// take longer; 90 s matches esp32_improv's default wifi_timeout.
// take longer; 90 s matches improv_ble's default wifi_timeout.
static const uint32_t WIFI_CONNECT_TIMEOUT_MS = 30000;
static const uint32_t WIFI_SWITCH_TIMEOUT_MS = 90000;
#endif
@@ -13,6 +13,9 @@ namespace esphome::internal_temperature {
class InternalTemperatureSensor final : public sensor::Sensor, public PollingComponent {
public:
// User provided, not "= default": `new(p) InternalTemperatureSensor()` would zero-fill .bss that is already zero.
InternalTemperatureSensor() {}
#if defined(USE_ESP32) || (defined(USE_ZEPHYR) && defined(USE_NRF52))
void setup() override;
#endif // USE_ESP32 || (USE_ZEPHYR && USE_NRF52)
@@ -275,8 +275,4 @@ void Lc709203f::set_pack_size(uint16_t pack_size) {
// not cause an error or crash, so I am not doing any additional checking here.
}
void Lc709203f::set_thermistor_b_constant(uint16_t b_constant) { this->b_constant_ = b_constant; }
void Lc709203f::set_pack_voltage(LC709203FBatteryVoltage pack_voltage) { this->pack_voltage_ = pack_voltage; }
} // namespace esphome::lc709203f
+2 -2
View File
@@ -26,8 +26,8 @@ class Lc709203f final : public sensor::Sensor, public PollingComponent, public i
void dump_config() override;
void set_pack_size(uint16_t pack_size);
void set_thermistor_b_constant(uint16_t b_constant);
void set_pack_voltage(LC709203FBatteryVoltage pack_voltage);
void set_thermistor_b_constant(uint16_t b_constant) { this->b_constant_ = b_constant; }
void set_pack_voltage(LC709203FBatteryVoltage pack_voltage) { this->pack_voltage_ = pack_voltage; }
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_battery_remaining_sensor(sensor::Sensor *battery_remaining_sensor) {
battery_remaining_sensor_ = battery_remaining_sensor;
+2 -2
View File
@@ -109,14 +109,14 @@ async def to_code(config: ConfigType) -> None:
for x in range(14):
if gate_conf := config.get(f"gate_{x}"):
move_config = gate_conf[CONF_MOVE_THRESHOLD]
n = cg.new_Pvariable(move_config[CONF_ID], x)
n = cg.new_Pvariable(move_config[CONF_ID])
await number.register_number(
n, move_config, min_value=0, max_value=100, step=1
)
await cg.register_parented(n, config[CONF_LD2412_ID])
cg.add(LD2412_component.set_gate_move_threshold_number(x, n))
still_config = gate_conf[CONF_STILL_THRESHOLD]
n = cg.new_Pvariable(still_config[CONF_ID], x)
n = cg.new_Pvariable(still_config[CONF_ID])
await number.register_number(
n, still_config, min_value=0, max_value=100, step=1
)
@@ -2,8 +2,6 @@
namespace esphome::ld2412 {
GateThresholdNumber::GateThresholdNumber(uint8_t gate) : gate_(gate) {}
void GateThresholdNumber::control(float value) {
this->publish_state(value);
this->parent_->set_gate_threshold();
@@ -7,10 +7,10 @@ namespace esphome::ld2412 {
class GateThresholdNumber final : public number::Number, public Parented<LD2412Component> {
public:
GateThresholdNumber(uint8_t gate);
// Not "= default": that makes new(p) T() zero-fill the object at every codegen site before the ctor runs.
GateThresholdNumber() {}
protected:
uint8_t gate_;
void control(float value) override;
};
@@ -7,7 +7,8 @@ namespace esphome::ld2412 {
class LightThresholdNumber final : public number::Number, public Parented<LD2412Component> {
public:
LightThresholdNumber() = default;
// User provided, not "= default": `new(p) LightThresholdNumber()` would zero-fill .bss that is already zero.
LightThresholdNumber() {}
protected:
void control(float value) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2412 {
class BaudRateSelect final : public select::Select, public Parented<LD2412Component> {
public:
BaudRateSelect() = default;
// User provided, not "= default": `new(p) BaudRateSelect()` would zero-fill .bss that is already zero.
BaudRateSelect() {}
protected:
void control(size_t index) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2412 {
class DistanceResolutionSelect final : public select::Select, public Parented<LD2412Component> {
public:
DistanceResolutionSelect() = default;
// User provided, not "= default": `new(p) DistanceResolutionSelect()` would zero-fill .bss that is already zero.
DistanceResolutionSelect() {}
protected:
void control(size_t index) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2412 {
class LightOutControlSelect final : public select::Select, public Parented<LD2412Component> {
public:
LightOutControlSelect() = default;
// User provided, not "= default": `new(p) LightOutControlSelect()` would zero-fill .bss that is already zero.
LightOutControlSelect() {}
protected:
void control(size_t index) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2412 {
class BluetoothSwitch final : public switch_::Switch, public Parented<LD2412Component> {
public:
BluetoothSwitch() = default;
// User provided, not "= default": `new(p) BluetoothSwitch()` would zero-fill .bss that is already zero.
BluetoothSwitch() {}
protected:
void write_state(bool state) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2412 {
class EngineeringModeSwitch final : public switch_::Switch, public Parented<LD2412Component> {
public:
EngineeringModeSwitch() = default;
// User provided, not "= default": `new(p) EngineeringModeSwitch()` would zero-fill .bss that is already zero.
EngineeringModeSwitch() {}
protected:
void write_state(bool state) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2450 {
class FactoryResetButton : public button::Button, public Parented<LD2450Component> {
public:
FactoryResetButton() = default;
// User provided, not "= default": `new(p) FactoryResetButton()` would zero-fill .bss that is already zero.
FactoryResetButton() {}
protected:
void press_action() override;
@@ -7,7 +7,8 @@ namespace esphome::ld2450 {
class RestartButton : public button::Button, public Parented<LD2450Component> {
public:
RestartButton() = default;
// User provided, not "= default": `new(p) RestartButton()` would zero-fill .bss that is already zero.
RestartButton() {}
protected:
void press_action() override;
@@ -7,7 +7,8 @@ namespace esphome::ld2450 {
class PresenceTimeoutNumber : public number::Number, public Parented<LD2450Component> {
public:
PresenceTimeoutNumber() = default;
// User provided, not "= default": `new(p) PresenceTimeoutNumber()` would zero-fill .bss that is already zero.
PresenceTimeoutNumber() {}
protected:
void control(float value) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2450 {
class BaudRateSelect : public select::Select, public Parented<LD2450Component> {
public:
BaudRateSelect() = default;
// User provided, not "= default": `new(p) BaudRateSelect()` would zero-fill .bss that is already zero.
BaudRateSelect() {}
protected:
void control(size_t index) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2450 {
class ZoneTypeSelect : public select::Select, public Parented<LD2450Component> {
public:
ZoneTypeSelect() = default;
// User provided, not "= default": `new(p) ZoneTypeSelect()` would zero-fill .bss that is already zero.
ZoneTypeSelect() {}
protected:
void control(size_t index) override;
@@ -7,7 +7,8 @@ namespace esphome::ld2450 {
class BluetoothSwitch : public switch_::Switch, public Parented<LD2450Component> {
public:
BluetoothSwitch() = default;
// User provided, not "= default": `new(p) BluetoothSwitch()` would zero-fill .bss that is already zero.
BluetoothSwitch() {}
protected:
void write_state(bool state) override;
-2
View File
@@ -134,6 +134,4 @@ void MAX44009Sensor::write_(uint8_t reg, uint8_t value) {
}
}
void MAX44009Sensor::set_mode(MAX44009Mode mode) { this->mode_ = mode; }
} // namespace esphome::max44009
+1 -1
View File
@@ -16,7 +16,7 @@ class MAX44009Sensor final : public sensor::Sensor, public PollingComponent, pub
void setup() override;
void dump_config() override;
void update() override;
void set_mode(MAX44009Mode mode);
void set_mode(MAX44009Mode mode) { this->mode_ = mode; }
bool set_continuous_mode();
bool set_low_power_mode();
@@ -25,8 +25,6 @@ void ModbusSwitch::setup() {
}
void ModbusSwitch::dump_config() { LOG_SWITCH(TAG, "Modbus Controller Switch", this); }
void ModbusSwitch::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
bool ModbusSwitch::assumed_state() { return this->assumed_state_; }
void ModbusSwitch::parse_and_publish(std::span<const uint8_t> data) {
@@ -31,7 +31,7 @@ class ModbusSwitch final : public Component, public switch_::Switch, public Sens
void setup() override;
void write_state(bool state) override;
void dump_config() override;
void set_assumed_state(bool assumed_state);
void set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
void set_state(bool state) { this->state = state; }
void parse_and_publish(std::span<const uint8_t> data) override;
void set_parent(ModbusController *parent) { this->set_controller_(parent); }
@@ -25,7 +25,6 @@ void MQTTSubscribeSensor::setup() {
}
float MQTTSubscribeSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
void MQTTSubscribeSensor::set_qos(uint8_t qos) { this->qos_ = qos; }
void MQTTSubscribeSensor::dump_config() {
LOG_SENSOR("", "MQTT Subscribe", this);
ESP_LOGCONFIG(TAG, " Topic: %s", this->topic_.c_str());
@@ -18,7 +18,7 @@ class MQTTSubscribeSensor final : public sensor::Sensor, public Component {
void dump_config() override;
float get_setup_priority() const override;
void set_qos(uint8_t qos);
void set_qos(uint8_t qos) { this->qos_ = qos; }
protected:
mqtt::MQTTClientComponent *parent_;
@@ -15,7 +15,6 @@ void MQTTSubscribeTextSensor::setup() {
this->qos_);
}
float MQTTSubscribeTextSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
void MQTTSubscribeTextSensor::set_qos(uint8_t qos) { this->qos_ = qos; }
void MQTTSubscribeTextSensor::dump_config() {
LOG_TEXT_SENSOR("", "MQTT Subscribe Text Sensor", this);
ESP_LOGCONFIG(TAG, " Topic: %s", this->topic_.c_str());
@@ -17,7 +17,7 @@ class MQTTSubscribeTextSensor final : public text_sensor::TextSensor, public Com
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void set_qos(uint8_t qos);
void set_qos(uint8_t qos) { this->qos_ = qos; }
protected:
mqtt::MQTTClientComponent *parent_;
+1 -1
View File
@@ -28,7 +28,7 @@ class Number;
*/
class Number : public EntityBase {
public:
float state;
float state{};
void publish_state(float state);
@@ -227,8 +227,6 @@ void *OpenThreadSrpComponent::pool_alloc_(size_t size) {
return ptr;
}
void OpenThreadSrpComponent::set_mdns(esphome::mdns::MDNSComponent *mdns) { this->mdns_ = mdns; }
bool OpenThreadComponent::teardown() {
switch (this->teardown_stage_) {
case TeardownStage::TEARDOWN_STAGE_NOT_STARTED: {
+1 -1
View File
@@ -90,7 +90,7 @@ extern OpenThreadComponent *global_openthread_component; // NOLINT(cppcoreguide
class OpenThreadSrpComponent final : public Component {
public:
void set_mdns(esphome::mdns::MDNSComponent *mdns);
void set_mdns(esphome::mdns::MDNSComponent *mdns) { this->mdns_ = mdns; }
// This has to run after the mdns component or else no services are available to advertise
float get_setup_priority() const override { return this->mdns_->get_setup_priority() - 1.0f; }
void setup() override;
+7 -4
View File
@@ -55,6 +55,9 @@ class PCA9554Component final : public Component,
/// Helper class to expose a PCA9554 pin as an internal input GPIO pin.
class PCA9554GPIOPin final : public GPIOPin {
public:
// User provided, not "= default": `new(p) PCA9554GPIOPin()` would zero-fill .bss that is already zero.
PCA9554GPIOPin() {}
void setup() override;
void pin_mode(gpio::Flags flags) override;
bool digital_read() override;
@@ -69,10 +72,10 @@ class PCA9554GPIOPin final : public GPIOPin {
gpio::Flags get_flags() const override { return this->flags_; }
protected:
PCA9554Component *parent_;
uint8_t pin_;
bool inverted_;
gpio::Flags flags_;
PCA9554Component *parent_{nullptr};
uint8_t pin_{0};
bool inverted_{false};
gpio::Flags flags_{};
};
} // namespace esphome::pca9554
+7 -4
View File
@@ -51,6 +51,9 @@ class PCF8574Component final : public Component,
/// Helper class to expose a PCF8574 pin as an internal input GPIO pin.
class PCF8574GPIOPin final : public GPIOPin {
public:
// User provided, not "= default": `new(p) PCF8574GPIOPin()` would zero-fill .bss that is already zero.
PCF8574GPIOPin() {}
void setup() override;
void pin_mode(gpio::Flags flags) override;
bool digital_read() override;
@@ -65,10 +68,10 @@ class PCF8574GPIOPin final : public GPIOPin {
gpio::Flags get_flags() const override { return this->flags_; }
protected:
PCF8574Component *parent_;
uint8_t pin_;
bool inverted_;
gpio::Flags flags_;
PCF8574Component *parent_{nullptr};
uint8_t pin_{0};
bool inverted_{false};
gpio::Flags flags_{};
};
} // namespace esphome::pcf8574
+3
View File
@@ -9,6 +9,9 @@ namespace esphome::preferences {
class IntervalSyncer final : public PollingComponent {
public:
// User provided, not "= default": `new(p) IntervalSyncer()` would zero-fill .bss that is already zero.
IntervalSyncer() {}
// Remove before 2027.3.0
ESPDEPRECATED("Use set_update_interval() instead. Removed in 2027.3.0", "2026.9.0")
void set_write_interval(uint32_t write_interval) { this->set_update_interval(write_interval); }
@@ -7,6 +7,9 @@ namespace esphome::restart {
class RestartButton final : public button::Button, public Component {
public:
// User provided, not "= default": `new(p) RestartButton()` would zero-fill .bss that is already zero.
RestartButton() {}
void dump_config() override;
protected:
@@ -7,6 +7,9 @@ namespace esphome::restart {
class RestartSwitch final : public switch_::Switch, public Component {
public:
// User provided, not "= default": `new(p) RestartSwitch()` would zero-fill .bss that is already zero.
RestartSwitch() {}
void dump_config() override;
protected:
+3
View File
@@ -17,6 +17,9 @@ constexpr uint32_t RTC_KEY = 233825507UL;
/// SafeModeComponent provides a safe way to recover from repeated boot failures
class SafeModeComponent final : public Component {
public:
// User provided, not "= default": `new(p) SafeModeComponent()` would zero-fill .bss that is already zero.
SafeModeComponent() {}
bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time, uint32_t boot_is_good_after, bool in_flash);
/// Set to true if the next startup will enter safe mode
+4
View File
@@ -9,6 +9,10 @@ namespace esphome::scd4x {
template<typename... Ts>
class PerformForcedCalibrationAction final : public Action<Ts...>, public Parented<SCD4XComponent> {
public:
// User provided, not "= default": `new(p) PerformForcedCalibrationAction()` would zero-fill .bss that is already
// zero.
PerformForcedCalibrationAction() {}
void play(const Ts &...x) override {
if (this->value_.has_value()) {
this->parent_->perform_forced_calibration(this->value_.value(x...));
-2
View File
@@ -106,8 +106,6 @@ void SDS011Component::loop() {
}
}
void SDS011Component::set_rx_mode_only(bool rx_mode_only) { this->rx_mode_only_ = rx_mode_only; }
void SDS011Component::sds011_write_command_(const uint8_t *command_data) {
this->write_byte(SDS011_MSG_HEAD);
this->write_byte(SDS011_COMMAND_ID_REQUEST);
+1 -1
View File
@@ -12,7 +12,7 @@ class SDS011Component final : public Component, public uart::UARTDevice {
SDS011Component() = default;
/// Manually set the rx-only mode. Defaults to false.
void set_rx_mode_only(bool rx_mode_only);
void set_rx_mode_only(bool rx_mode_only) { this->rx_mode_only_ = rx_mode_only; }
void set_pm_2_5_sensor(sensor::Sensor *pm_2_5_sensor) { pm_2_5_sensor_ = pm_2_5_sensor; }
void set_pm_10_0_sensor(sensor::Sensor *pm_10_0_sensor) { pm_10_0_sensor_ = pm_10_0_sensor; }
-2
View File
@@ -152,8 +152,6 @@ void ST7789V::update() {
this->write_display_data();
}
void ST7789V::set_model_str(const char *model_str) { this->model_str_ = model_str; }
void ST7789V::write_display_data() {
uint16_t x1 = this->offset_width_;
uint16_t x2 = x1 + get_width_internal() - 1;
+1 -1
View File
@@ -110,7 +110,7 @@ class ST7789V final : public display::DisplayBuffer,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
spi::DATA_RATE_20MHZ> {
public:
void set_model_str(const char *model_str);
void set_model_str(const char *model_str) { this->model_str_ = model_str; }
void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; }
void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
void set_backlight_pin(GPIOPin *backlight_pin) { this->backlight_pin_ = backlight_pin; }
@@ -7,6 +7,8 @@ namespace esphome::status {
class StatusBinarySensor final : public binary_sensor::BinarySensor, public PollingComponent {
public:
// User provided, not "= default": `new(p) StatusBinarySensor()` would zero-fill .bss that is already zero.
StatusBinarySensor() {}
void update() override;
void setup() override;
@@ -8,6 +8,8 @@ namespace esphome::template_ {
class TemplateBinarySensor final : public Component, public binary_sensor::BinarySensor {
public:
// User provided, not "= default": `new(p) TemplateBinarySensor()` would zero-fill .bss that is already zero.
TemplateBinarySensor() {}
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
void setup() override;
@@ -6,6 +6,9 @@ namespace esphome::template_ {
class TemplateButton final : public button::Button {
public:
// User provided, not "= default": `new(p) TemplateButton()` would zero-fill .bss that is already zero.
TemplateButton() {}
// Implements the abstract `press_action` but the `on_press` trigger already handles the press.
void press_action() override{};
};
@@ -53,8 +53,6 @@ void TemplateCover::loop() {
if (changed)
this->publish_state();
}
void TemplateCover::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
void TemplateCover::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
float TemplateCover::get_setup_priority() const { return setup_priority::HARDWARE; }
Trigger<> *TemplateCover::get_open_trigger() { return &this->open_trigger_; }
Trigger<> *TemplateCover::get_close_trigger() { return &this->close_trigger_; }
@@ -117,10 +115,6 @@ CoverTraits TemplateCover::get_traits() {
}
Trigger<float> *TemplateCover::get_position_trigger() { return &this->position_trigger_; }
Trigger<float> *TemplateCover::get_tilt_trigger() { return &this->tilt_trigger_; }
void TemplateCover::set_has_stop(bool has_stop) { this->has_stop_ = has_stop; }
void TemplateCover::set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; }
void TemplateCover::set_has_position(bool has_position) { this->has_position_ = has_position; }
void TemplateCover::set_has_tilt(bool has_tilt) { this->has_tilt_ = has_tilt; }
void TemplateCover::stop_prev_trigger_() {
if (this->prev_command_trigger_ != nullptr) {
this->prev_command_trigger_->stop_action();
@@ -25,12 +25,12 @@ class TemplateCover final : public cover::Cover, public Component {
Trigger<> *get_toggle_trigger();
Trigger<float> *get_position_trigger();
Trigger<float> *get_tilt_trigger();
void set_optimistic(bool optimistic);
void set_assumed_state(bool assumed_state);
void set_has_stop(bool has_stop);
void set_has_position(bool has_position);
void set_has_tilt(bool has_tilt);
void set_has_toggle(bool has_toggle);
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
void set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
void set_has_stop(bool has_stop) { this->has_stop_ = has_stop; }
void set_has_position(bool has_position) { this->has_position_ = has_position; }
void set_has_tilt(bool has_tilt) { this->has_tilt_ = has_tilt; }
void set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; }
void set_restore_mode(TemplateCoverRestoreMode restore_mode) { restore_mode_ = restore_mode; }
void setup() override;
@@ -5,6 +5,10 @@
namespace esphome::template_ {
class TemplateEvent final : public Component, public event::Event {};
class TemplateEvent final : public Component, public event::Event {
public:
// User provided, not "= default": `new(p) TemplateEvent()` would zero-fill .bss that is already zero.
TemplateEvent() {}
};
} // namespace esphome::template_
@@ -47,7 +47,6 @@ void TemplateLock::open_latch() {
this->prev_trigger_ = &this->open_trigger_;
this->open_trigger_.trigger();
}
void TemplateLock::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
float TemplateLock::get_setup_priority() const { return setup_priority::HARDWARE; }
void TemplateLock::dump_config() {
LOG_LOCK("", "Template Lock", this);
@@ -18,7 +18,7 @@ class TemplateLock final : public lock::Lock, public Component {
Trigger<> *get_lock_trigger() { return &this->lock_trigger_; }
Trigger<> *get_unlock_trigger() { return &this->unlock_trigger_; }
Trigger<> *get_open_trigger() { return &this->open_trigger_; }
void set_optimistic(bool optimistic);
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
void loop() override;
float get_setup_priority() const override;

Some files were not shown because too many files have changed in this diff Show More