diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22bdeca429..ca6d1b0aac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,7 +296,7 @@ jobs: name: Run script/clang-tidy for ZEPHYR options: --environment nrf52-tidy --grep USE_ZEPHYR pio_cache_key: tidy-zephyr - ignore_errors: true + ignore_errors: false steps: - name: Check out code from GitHub diff --git a/CODEOWNERS b/CODEOWNERS index dade427a45..66ea80f8d6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -150,6 +150,7 @@ esphome/components/esp32_improv/* @jesserockz esphome/components/esp32_rmt/* @jesserockz esphome/components/esp32_rmt_led_strip/* @jesserockz esphome/components/esp8266/* @esphome/core +esphome/components/esp_ldo/* @clydebarrow esphome/components/ethernet_info/* @gtjadsonsantos esphome/components/event/* @nohat esphome/components/event_emitter/* @Rapsssito @@ -235,6 +236,7 @@ esphome/components/kamstrup_kmp/* @cfeenstra1024 esphome/components/key_collector/* @ssieb esphome/components/key_provider/* @ssieb esphome/components/kuntze/* @ssieb +esphome/components/lc709203f/* @ilikecake esphome/components/lcd_menu/* @numo68 esphome/components/ld2410/* @regevbr @sebcaps esphome/components/ld2420/* @descipher @@ -320,6 +322,7 @@ esphome/components/number/* @esphome/core esphome/components/one_wire/* @ssieb esphome/components/online_image/* @clydebarrow @guillempages esphome/components/opentherm/* @olegtarasov +esphome/components/openthread/* @mrene esphome/components/ota/* @esphome/core esphome/components/output/* @esphome/core esphome/components/packet_transport/* @clydebarrow diff --git a/Doxyfile b/Doxyfile index f807ba5c4e..03d432b924 100644 --- a/Doxyfile +++ b/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.0-dev +PROJECT_NUMBER = 2025.7.0-dev # 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 diff --git a/esphome/__main__.py b/esphome/__main__.py index adada75163..2dbdfeb1ff 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -134,6 +134,7 @@ def get_port_type(port): def run_miniterm(config, port, args): + from aioesphomeapi import LogParser import serial from esphome import platformio_api @@ -158,6 +159,7 @@ def run_miniterm(config, port, args): ser.dtr = False ser.rts = False + parser = LogParser() tries = 0 while tries < 5: try: @@ -174,8 +176,7 @@ def run_miniterm(config, port, args): .decode("utf8", "backslashreplace") ) time_str = datetime.now().time().strftime("[%H:%M:%S]") - message = time_str + line - safe_print(message) + safe_print(parser.parse_line(line, time_str)) backtrace_state = platformio_api.process_stacktrace( config, line, backtrace_state=backtrace_state diff --git a/esphome/components/absolute_humidity/absolute_humidity.cpp b/esphome/components/absolute_humidity/absolute_humidity.cpp index 877e6dbe22..c3cb159aed 100644 --- a/esphome/components/absolute_humidity/absolute_humidity.cpp +++ b/esphome/components/absolute_humidity/absolute_humidity.cpp @@ -40,9 +40,11 @@ void AbsoluteHumidityComponent::dump_config() { break; } - ESP_LOGCONFIG(TAG, "Sources"); - ESP_LOGCONFIG(TAG, " Temperature: '%s'", this->temperature_sensor_->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Relative Humidity: '%s'", this->humidity_sensor_->get_name().c_str()); + ESP_LOGCONFIG(TAG, + "Sources\n" + " Temperature: '%s'\n" + " Relative Humidity: '%s'", + this->temperature_sensor_->get_name().c_str(), this->humidity_sensor_->get_name().c_str()); } float AbsoluteHumidityComponent::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/ac_dimmer/ac_dimmer.cpp b/esphome/components/ac_dimmer/ac_dimmer.cpp index 4901719b32..ddaa910db3 100644 --- a/esphome/components/ac_dimmer/ac_dimmer.cpp +++ b/esphome/components/ac_dimmer/ac_dimmer.cpp @@ -214,8 +214,10 @@ void AcDimmer::dump_config() { ESP_LOGCONFIG(TAG, "AcDimmer:"); LOG_PIN(" Output Pin: ", this->gate_pin_); LOG_PIN(" Zero-Cross Pin: ", this->zero_cross_pin_); - ESP_LOGCONFIG(TAG, " Min Power: %.1f%%", this->store_.min_power / 10.0f); - ESP_LOGCONFIG(TAG, " Init with half cycle: %s", YESNO(this->init_with_half_cycle_)); + ESP_LOGCONFIG(TAG, + " Min Power: %.1f%%\n" + " Init with half cycle: %s", + this->store_.min_power / 10.0f, YESNO(this->init_with_half_cycle_)); if (method_ == DIM_METHOD_LEADING_PULSE) { ESP_LOGCONFIG(TAG, " Method: leading pulse"); } else if (method_ == DIM_METHOD_LEADING) { diff --git a/esphome/components/adc/adc_sensor_esp32.cpp b/esphome/components/adc/adc_sensor_esp32.cpp index efd3bafb83..d6cf6e893b 100644 --- a/esphome/components/adc/adc_sensor_esp32.cpp +++ b/esphome/components/adc/adc_sensor_esp32.cpp @@ -22,7 +22,7 @@ static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; void ADCSensor::setup() { - ESP_LOGCONFIG(TAG, "Running setup for '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str()); if (this->channel1_ != ADC1_CHANNEL_MAX) { adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); @@ -77,8 +77,10 @@ void ADCSensor::dump_config() { break; } } - ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); - ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); + ESP_LOGCONFIG(TAG, + " Samples: %i\n" + " Sampling mode: %s", + this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/adc/adc_sensor_esp8266.cpp b/esphome/components/adc/adc_sensor_esp8266.cpp index 14837562aa..67128fb1f3 100644 --- a/esphome/components/adc/adc_sensor_esp8266.cpp +++ b/esphome/components/adc/adc_sensor_esp8266.cpp @@ -17,7 +17,7 @@ namespace adc { static const char *const TAG = "adc.esp8266"; void ADCSensor::setup() { - ESP_LOGCONFIG(TAG, "Running setup for '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str()); #ifndef USE_ADC_SENSOR_VCC this->pin_->setup(); #endif @@ -30,8 +30,10 @@ void ADCSensor::dump_config() { #else LOG_PIN(" Pin: ", this->pin_); #endif // USE_ADC_SENSOR_VCC - ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); - ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); + ESP_LOGCONFIG(TAG, + " Samples: %i\n" + " Sampling mode: %s", + this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/adc/adc_sensor_libretiny.cpp b/esphome/components/adc/adc_sensor_libretiny.cpp index 5676857dc9..f7c7e669ec 100644 --- a/esphome/components/adc/adc_sensor_libretiny.cpp +++ b/esphome/components/adc/adc_sensor_libretiny.cpp @@ -9,7 +9,7 @@ namespace adc { static const char *const TAG = "adc.libretiny"; void ADCSensor::setup() { - ESP_LOGCONFIG(TAG, "Running setup for '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str()); #ifndef USE_ADC_SENSOR_VCC this->pin_->setup(); #endif // !USE_ADC_SENSOR_VCC @@ -22,8 +22,10 @@ void ADCSensor::dump_config() { #else // USE_ADC_SENSOR_VCC LOG_PIN(" Pin: ", this->pin_); #endif // USE_ADC_SENSOR_VCC - ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); - ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); + ESP_LOGCONFIG(TAG, + " Samples: %i\n" + " Sampling mode: %s", + this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/adc/adc_sensor_rp2040.cpp b/esphome/components/adc/adc_sensor_rp2040.cpp index 8c6afb8186..91d331270b 100644 --- a/esphome/components/adc/adc_sensor_rp2040.cpp +++ b/esphome/components/adc/adc_sensor_rp2040.cpp @@ -14,7 +14,7 @@ namespace adc { static const char *const TAG = "adc.rp2040"; void ADCSensor::setup() { - ESP_LOGCONFIG(TAG, "Running setup for '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str()); static bool initialized = false; if (!initialized) { adc_init(); @@ -33,8 +33,10 @@ void ADCSensor::dump_config() { LOG_PIN(" Pin: ", this->pin_); #endif // USE_ADC_SENSOR_VCC } - ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); - ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); + ESP_LOGCONFIG(TAG, + " Samples: %i\n" + " Sampling mode: %s", + this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_))); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/ade7880/ade7880.cpp b/esphome/components/ade7880/ade7880.cpp index 4a45b3b321..55f834bf86 100644 --- a/esphome/components/ade7880/ade7880.cpp +++ b/esphome/components/ade7880/ade7880.cpp @@ -177,11 +177,14 @@ void ADE7880::dump_config() { LOG_SENSOR(" ", "Power Factor", this->channel_a_->power_factor); LOG_SENSOR(" ", "Forward Active Energy", this->channel_a_->forward_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_a_->reverse_active_energy); - ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_a_->current_gain_calibration); - ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_a_->voltage_gain_calibration); - ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_a_->power_gain_calibration); - ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_a_->phase_angle_calibration); + ESP_LOGCONFIG(TAG, + " Calibration:\n" + " Current: %" PRId32 "\n" + " Voltage: %" PRId32 "\n" + " Power: %" PRId32 "\n" + " Phase Angle: %u", + this->channel_a_->current_gain_calibration, this->channel_a_->voltage_gain_calibration, + this->channel_a_->power_gain_calibration, this->channel_a_->phase_angle_calibration); } if (this->channel_b_ != nullptr) { @@ -193,11 +196,14 @@ void ADE7880::dump_config() { LOG_SENSOR(" ", "Power Factor", this->channel_b_->power_factor); LOG_SENSOR(" ", "Forward Active Energy", this->channel_b_->forward_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_b_->reverse_active_energy); - ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_b_->current_gain_calibration); - ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_b_->voltage_gain_calibration); - ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_b_->power_gain_calibration); - ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_b_->phase_angle_calibration); + ESP_LOGCONFIG(TAG, + " Calibration:\n" + " Current: %" PRId32 "\n" + " Voltage: %" PRId32 "\n" + " Power: %" PRId32 "\n" + " Phase Angle: %u", + this->channel_b_->current_gain_calibration, this->channel_b_->voltage_gain_calibration, + this->channel_b_->power_gain_calibration, this->channel_b_->phase_angle_calibration); } if (this->channel_c_ != nullptr) { @@ -209,18 +215,23 @@ void ADE7880::dump_config() { LOG_SENSOR(" ", "Power Factor", this->channel_c_->power_factor); LOG_SENSOR(" ", "Forward Active Energy", this->channel_c_->forward_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_c_->reverse_active_energy); - ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_c_->current_gain_calibration); - ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_c_->voltage_gain_calibration); - ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_c_->power_gain_calibration); - ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_c_->phase_angle_calibration); + ESP_LOGCONFIG(TAG, + " Calibration:\n" + " Current: %" PRId32 "\n" + " Voltage: %" PRId32 "\n" + " Power: %" PRId32 "\n" + " Phase Angle: %u", + this->channel_c_->current_gain_calibration, this->channel_c_->voltage_gain_calibration, + this->channel_c_->power_gain_calibration, this->channel_c_->phase_angle_calibration); } if (this->channel_n_ != nullptr) { ESP_LOGCONFIG(TAG, " Neutral:"); LOG_SENSOR(" ", "Current", this->channel_n_->current); - ESP_LOGCONFIG(TAG, " Calibration:"); - ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_n_->current_gain_calibration); + ESP_LOGCONFIG(TAG, + " Calibration:\n" + " Current: %" PRId32, + this->channel_n_->current_gain_calibration); } LOG_I2C_DEVICE(this); diff --git a/esphome/components/ade7953_base/ade7953_base.cpp b/esphome/components/ade7953_base/ade7953_base.cpp index 2511b4e04c..5f5fdd27ee 100644 --- a/esphome/components/ade7953_base/ade7953_base.cpp +++ b/esphome/components/ade7953_base/ade7953_base.cpp @@ -58,15 +58,18 @@ void ADE7953::dump_config() { LOG_SENSOR(" ", "Active Power B Sensor", this->active_power_b_sensor_); LOG_SENSOR(" ", "Rective Power A Sensor", this->reactive_power_a_sensor_); LOG_SENSOR(" ", "Reactive Power B Sensor", this->reactive_power_b_sensor_); - ESP_LOGCONFIG(TAG, " USE_ACC_ENERGY_REGS: %d", this->use_acc_energy_regs_); - ESP_LOGCONFIG(TAG, " PGA_V_8: 0x%X", pga_v_); - ESP_LOGCONFIG(TAG, " PGA_IA_8: 0x%X", pga_ia_); - ESP_LOGCONFIG(TAG, " PGA_IB_8: 0x%X", pga_ib_); - ESP_LOGCONFIG(TAG, " VGAIN_32: 0x%08jX", (uintmax_t) vgain_); - ESP_LOGCONFIG(TAG, " AIGAIN_32: 0x%08jX", (uintmax_t) aigain_); - ESP_LOGCONFIG(TAG, " BIGAIN_32: 0x%08jX", (uintmax_t) bigain_); - ESP_LOGCONFIG(TAG, " AWGAIN_32: 0x%08jX", (uintmax_t) awgain_); - ESP_LOGCONFIG(TAG, " BWGAIN_32: 0x%08jX", (uintmax_t) bwgain_); + ESP_LOGCONFIG(TAG, + " USE_ACC_ENERGY_REGS: %d\n" + " PGA_V_8: 0x%X\n" + " PGA_IA_8: 0x%X\n" + " PGA_IB_8: 0x%X\n" + " VGAIN_32: 0x%08jX\n" + " AIGAIN_32: 0x%08jX\n" + " BIGAIN_32: 0x%08jX\n" + " AWGAIN_32: 0x%08jX\n" + " BWGAIN_32: 0x%08jX", + this->use_acc_energy_regs_, pga_v_, pga_ia_, pga_ib_, (uintmax_t) vgain_, (uintmax_t) aigain_, + (uintmax_t) bigain_, (uintmax_t) awgain_, (uintmax_t) bwgain_); } #define ADE_PUBLISH_(name, val, factor) \ diff --git a/esphome/components/ade7953_i2c/ade7953_i2c.cpp b/esphome/components/ade7953_i2c/ade7953_i2c.cpp index ae381824db..59c2254d44 100644 --- a/esphome/components/ade7953_i2c/ade7953_i2c.cpp +++ b/esphome/components/ade7953_i2c/ade7953_i2c.cpp @@ -1,6 +1,6 @@ #include "ade7953_i2c.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ade7953_i2c { diff --git a/esphome/components/ade7953_spi/ade7953_spi.cpp b/esphome/components/ade7953_spi/ade7953_spi.cpp index 77a2a8adc7..6b16d933a2 100644 --- a/esphome/components/ade7953_spi/ade7953_spi.cpp +++ b/esphome/components/ade7953_spi/ade7953_spi.cpp @@ -1,6 +1,6 @@ #include "ade7953_spi.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ade7953_spi { diff --git a/esphome/components/ads1118/ads1118.cpp b/esphome/components/ads1118/ads1118.cpp index 976b599a6a..1daa8fdfd4 100644 --- a/esphome/components/ads1118/ads1118.cpp +++ b/esphome/components/ads1118/ads1118.cpp @@ -1,4 +1,5 @@ #include "ads1118.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/ags10/ags10.cpp b/esphome/components/ags10/ags10.cpp index 16228708ed..797a07afa5 100644 --- a/esphome/components/ags10/ags10.cpp +++ b/esphome/components/ags10/ags10.cpp @@ -1,4 +1,5 @@ #include "ags10.h" +#include "esphome/core/helpers.h" #include diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index de7fd04be9..7f17e1c0d6 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -13,9 +13,9 @@ // results making successive requests; the current implementation makes 3 attempts with a delay of 30ms each time. #include "aht10.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace aht10 { @@ -115,7 +115,7 @@ void AHT10Component::read_data_() { if (this->humidity_sensor_ == nullptr) { ESP_LOGV(TAG, "Invalid humidity (reading not required)"); } else { - ESP_LOGD(TAG, "Invalid humidity, retrying..."); + ESP_LOGD(TAG, "Invalid humidity, retrying"); if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) { this->status_set_warning(ESP_LOG_MSG_COMM_FAIL); } diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index 1bcb83bce7..e88050132a 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -235,6 +235,7 @@ async def register_alarm_control_panel(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_alarm_control_panel(var)) + CORE.register_platform_component("alarm_control_panel", var) await setup_alarm_control_panel_core_(var, config) diff --git a/esphome/components/am43/am43_base.h b/esphome/components/am43/am43_base.h index e817f161fe..35354af9ed 100644 --- a/esphome/components/am43/am43_base.h +++ b/esphome/components/am43/am43_base.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace am43 { diff --git a/esphome/components/am43/cover/am43_cover.cpp b/esphome/components/am43/cover/am43_cover.cpp index 93c77ea364..0d49439095 100644 --- a/esphome/components/am43/cover/am43_cover.cpp +++ b/esphome/components/am43/cover/am43_cover.cpp @@ -12,8 +12,10 @@ using namespace esphome::cover; void Am43Component::dump_config() { LOG_COVER("", "AM43 Cover", this); - ESP_LOGCONFIG(TAG, " Device Pin: %d", this->pin_); - ESP_LOGCONFIG(TAG, " Invert Position: %d", (int) this->invert_position_); + ESP_LOGCONFIG(TAG, + " Device Pin: %d\n" + " Invert Position: %d", + this->pin_, (int) this->invert_position_); } void Am43Component::setup() { diff --git a/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp b/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp index 8dcbb2ac4b..f83f2aff08 100644 --- a/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +++ b/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp @@ -34,8 +34,10 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) { void AnalogThresholdBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this); LOG_SENSOR(" ", "Sensor", this->sensor_); - ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_.value()); - ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_.value()); + ESP_LOGCONFIG(TAG, + " Upper threshold: %.11f\n" + " Lower threshold: %.11f", + this->upper_threshold_.value(), this->lower_threshold_.value()); } } // namespace analog_threshold diff --git a/esphome/components/apds9306/apds9306.cpp b/esphome/components/apds9306/apds9306.cpp index b785f61c57..9799f54d3d 100644 --- a/esphome/components/apds9306/apds9306.cpp +++ b/esphome/components/apds9306/apds9306.cpp @@ -108,9 +108,12 @@ void APDS9306::dump_config() { } } - ESP_LOGCONFIG(TAG, " Gain: %u", AMBIENT_LIGHT_GAIN_VALUES[this->gain_]); - ESP_LOGCONFIG(TAG, " Measurement rate: %u", MEASUREMENT_RATE_VALUES[this->measurement_rate_]); - ESP_LOGCONFIG(TAG, " Measurement Resolution/Bit width: %d", MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]); + ESP_LOGCONFIG(TAG, + " Gain: %u\n" + " Measurement rate: %u\n" + " Measurement Resolution/Bit width: %d", + AMBIENT_LIGHT_GAIN_VALUES[this->gain_], MEASUREMENT_RATE_VALUES[this->measurement_rate_], + MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 4b63c76fba..bd131ef8de 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -49,6 +49,7 @@ SERVICE_ARG_NATIVE_TYPES = { "string[]": cg.std_vector.template(cg.std_string), } CONF_ENCRYPTION = "encryption" +CONF_BATCH_DELAY = "batch_delay" def validate_encryption_key(value): @@ -109,6 +110,9 @@ CONFIG_SCHEMA = cv.All( ): 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.positive_time_period_milliseconds, cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( single=True ), @@ -129,6 +133,7 @@ async def to_code(config): cg.add(var.set_port(config[CONF_PORT])) cg.add(var.set_password(config[CONF_PASSWORD])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) + cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY])) for conf in config.get(CONF_ACTIONS, []): template_args = [] diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index ca615a6d98..93ba9248b4 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "esphome/components/network/util.h" #include "esphome/core/application.h" #include "esphome/core/entity_base.h" @@ -29,40 +31,8 @@ namespace api { static const char *const TAG = "api.connection"; static const int ESP32_CAMERA_STOP_STREAM = 5000; -// helper for allowing only unique entries in the queue -void DeferredMessageQueue::dmq_push_back_with_dedup_(void *source, send_message_t send_message) { - DeferredMessage item(source, send_message); - - auto iter = std::find_if(this->deferred_queue_.begin(), this->deferred_queue_.end(), - [&item](const DeferredMessage &test) -> bool { return test == item; }); - - if (iter != this->deferred_queue_.end()) { - (*iter) = item; - } else { - this->deferred_queue_.push_back(item); - } -} - -void DeferredMessageQueue::process_queue() { - while (!deferred_queue_.empty()) { - DeferredMessage &de = deferred_queue_.front(); - if ((this->api_connection_->*(de.send_message_))(de.source_)) { - // O(n) but memory efficiency is more important than speed here which is why std::vector was chosen - deferred_queue_.erase(deferred_queue_.begin()); - } else { - break; - } - } -} - -void DeferredMessageQueue::defer(void *source, send_message_t send_message) { - this->dmq_push_back_with_dedup_(source, send_message); -} - APIConnection::APIConnection(std::unique_ptr sock, APIServer *parent) - : parent_(parent), deferred_message_queue_(this), initial_state_iterator_(this), list_entities_iterator_(this) { - this->proto_write_buffer_.reserve(64); - + : parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) { #if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE) auto noise_ctx = parent->get_noise_ctx(); if (noise_ctx->has_psk()) { @@ -78,6 +48,9 @@ APIConnection::APIConnection(std::unique_ptr sock, APIServer *pa #error "No frame helper defined" #endif } + +uint32_t APIConnection::get_batch_delay_ms_() const { return this->parent_->get_batch_delay(); } + void APIConnection::start() { this->last_traffic_ = App.get_loop_component_start_time(); @@ -118,7 +91,7 @@ void APIConnection::loop() { // when network is disconnected force disconnect immediately // don't wait for timeout this->on_fatal_error(); - ESP_LOGW(TAG, "%s: Network unavailable, disconnecting", this->client_combined_info_.c_str()); + ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->client_combined_info_.c_str()); return; } if (this->next_close_) { @@ -166,8 +139,10 @@ void APIConnection::loop() { } } - if (!this->deferred_message_queue_.empty() && this->helper_->can_write_without_blocking()) { - this->deferred_message_queue_.process_queue(); + // Process deferred batch if scheduled + if (this->deferred_batch_.batch_scheduled && + App.get_loop_component_start_time() - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) { + this->process_batch_(); } if (!this->list_entities_iterator_.completed()) @@ -182,42 +157,30 @@ void APIConnection::loop() { // Disconnect if not responded within 2.5*keepalive if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) { on_fatal_error(); - ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_combined_info_.c_str()); + ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->client_combined_info_.c_str()); } } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) { - ESP_LOGVV(TAG, "Sending keepalive PING..."); - this->sent_ping_ = this->send_ping_request(PingRequest()); + ESP_LOGVV(TAG, "Sending keepalive PING"); + this->sent_ping_ = this->send_message(PingRequest()); if (!this->sent_ping_) { this->next_ping_retry_ = now + ping_retry_interval; this->ping_retries_++; + std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);", + this->client_combined_info_.c_str(), this->ping_retries_); if (this->ping_retries_ >= max_ping_retries) { on_fatal_error(); - ESP_LOGE(TAG, "%s: Sending keepalive failed %d time(s). Disconnecting...", this->client_combined_info_.c_str(), - this->ping_retries_); + ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str()); } else if (this->ping_retries_ >= 10) { - ESP_LOGW(TAG, "%s: Sending keepalive failed %d time(s), will retry in %d ms", - this->client_combined_info_.c_str(), this->ping_retries_, ping_retry_interval); + ESP_LOGW(TAG, "%s retrying in %u ms", warn_str.c_str(), ping_retry_interval); } else { - ESP_LOGD(TAG, "%s: Sending keepalive failed %d time(s), will retry in %d ms", - this->client_combined_info_.c_str(), this->ping_retries_, ping_retry_interval); + ESP_LOGD(TAG, "%s retrying in %u ms", warn_str.c_str(), ping_retry_interval); } } } #ifdef USE_ESP32_CAMERA if (this->image_reader_.available() && this->helper_->can_write_without_blocking()) { - // Message will use 8 more bytes than the minimum size, and typical - // MTU is 1500. Sometimes users will see as low as 1460 MTU. - // If its IPv6 the header is 40 bytes, and if its IPv4 - // the header is 20 bytes. So we have 1460 - 40 = 1420 bytes - // available for the payload. But we also need to add the size of - // the protobuf overhead, which is 8 bytes. - // - // To be safe we pick 1390 bytes as the maximum size - // to send in one go. This is the maximum size of a single packet - // that can be sent over the network. - // This is to avoid fragmentation of the packet. - uint32_t to_send = std::min((size_t) 1390, this->image_reader_.available()); + uint32_t to_send = std::min((size_t) MAX_PACKET_SIZE, this->image_reader_.available()); bool done = this->image_reader_.available() == to_send; uint32_t msg_size = 0; ProtoSize::add_fixed_field<4>(msg_size, 1, true); @@ -255,7 +218,7 @@ void APIConnection::loop() { resp.entity_id = it.entity_id; resp.attribute = it.attribute.value(); resp.once = it.once; - if (this->send_subscribe_home_assistant_state_response(resp)) { + if (this->send_message(resp)) { state_subs_at_++; } } @@ -270,54 +233,84 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) { // remote initiated disconnect_client // don't close yet, we still need to send the disconnect response // close will happen on next loop - ESP_LOGD(TAG, "%s requested disconnected", this->client_combined_info_.c_str()); + ESP_LOGD(TAG, "%s disconnected", this->client_combined_info_.c_str()); this->next_close_ = true; DisconnectResponse resp; return resp; } void APIConnection::on_disconnect_response(const DisconnectResponse &value) { - // pass + this->helper_->close(); + this->remove_ = true; +} + +// Encodes a message to the buffer and returns the total number of bytes used, +// including header and footer overhead. Returns 0 if the message doesn't fit. +uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn, + uint32_t remaining_size, bool is_single) { + // Calculate size + uint32_t size = 0; + msg.calculate_size(size); + + // Calculate total size with padding for buffer allocation + uint16_t total_size = + static_cast(size) + conn->helper_->frame_header_padding() + conn->helper_->frame_footer_size(); + + // Check if it fits + if (total_size > remaining_size) { + return 0; // Doesn't fit + } + + // Allocate exact buffer space needed (just the payload, not the overhead) + ProtoWriteBuffer buffer = + is_single ? conn->allocate_single_message_buffer(size) : conn->allocate_batch_message_buffer(size); + + // Encode directly into buffer + msg.encode(buffer); + return total_size; } #ifdef USE_BINARY_SENSOR -bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state) { - return this->send_state_with_value_(binary_sensor, &APIConnection::try_send_binary_sensor_state_, - &APIConnection::try_send_binary_sensor_state_, state); +bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor) { + return this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_state, + BinarySensorStateResponse::MESSAGE_TYPE); } void APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) { - this->send_info_(static_cast(binary_sensor), - reinterpret_cast(&APIConnection::try_send_binary_sensor_info_)); + this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_info, + ListEntitiesBinarySensorResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor) { - return this->try_send_binary_sensor_state_(binary_sensor, binary_sensor->state); + +uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *binary_sensor = static_cast(entity); + BinarySensorStateResponse resp; + resp.state = binary_sensor->state; + resp.missing_state = !binary_sensor->has_state(); + resp.key = binary_sensor->get_object_id_hash(); + return encode_message_to_buffer(resp, BinarySensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor, bool state) { - BinarySensorStateResponse msg; - msg.state = state; - msg.missing_state = !binary_sensor->has_state(); - msg.key = binary_sensor->get_object_id_hash(); - return this->send_binary_sensor_state_response(msg); -} -bool APIConnection::try_send_binary_sensor_info_(binary_sensor::BinarySensor *binary_sensor) { + +uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *binary_sensor = static_cast(entity); ListEntitiesBinarySensorResponse msg; msg.device_class = binary_sensor->get_device_class(); msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor); - return this->try_send_entity_info_(static_cast(binary_sensor), msg, - &APIConnection::send_list_entities_binary_sensor_response); + fill_entity_info_base(binary_sensor, msg); + return encode_message_to_buffer(msg, ListEntitiesBinarySensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } #endif #ifdef USE_COVER bool APIConnection::send_cover_state(cover::Cover *cover) { - return this->send_state_(static_cast(cover), - reinterpret_cast(&APIConnection::try_send_cover_state_)); + return this->schedule_message_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE); } void APIConnection::send_cover_info(cover::Cover *cover) { - this->send_info_(static_cast(cover), - reinterpret_cast(&APIConnection::try_send_cover_info_)); + this->schedule_message_(cover, &APIConnection::try_send_cover_info, ListEntitiesCoverResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_cover_state_(cover::Cover *cover) { +uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *cover = static_cast(entity); CoverStateResponse msg; auto traits = cover->get_traits(); msg.legacy_state = @@ -327,9 +320,11 @@ bool APIConnection::try_send_cover_state_(cover::Cover *cover) { msg.tilt = cover->tilt; msg.current_operation = static_cast(cover->current_operation); msg.key = cover->get_object_id_hash(); - return this->send_cover_state_response(msg); + return encode_message_to_buffer(msg, CoverStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_cover_info_(cover::Cover *cover) { +uint16_t APIConnection::try_send_cover_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *cover = static_cast(entity); ListEntitiesCoverResponse msg; auto traits = cover->get_traits(); msg.assumed_state = traits.get_is_assumed_state(); @@ -338,8 +333,8 @@ bool APIConnection::try_send_cover_info_(cover::Cover *cover) { msg.supports_stop = traits.get_supports_stop(); msg.device_class = cover->get_device_class(); msg.unique_id = get_default_unique_id("cover", cover); - return this->try_send_entity_info_(static_cast(cover), msg, - &APIConnection::send_list_entities_cover_response); + fill_entity_info_base(cover, msg); + return encode_message_to_buffer(msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::cover_command(const CoverCommandRequest &msg) { cover::Cover *cover = App.get_cover_by_key(msg.key); @@ -372,14 +367,14 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) { #ifdef USE_FAN bool APIConnection::send_fan_state(fan::Fan *fan) { - return this->send_state_(static_cast(fan), - reinterpret_cast(&APIConnection::try_send_fan_state_)); + return this->schedule_message_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE); } void APIConnection::send_fan_info(fan::Fan *fan) { - this->send_info_(static_cast(fan), - reinterpret_cast(&APIConnection::try_send_fan_info_)); + this->schedule_message_(fan, &APIConnection::try_send_fan_info, ListEntitiesFanResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_fan_state_(fan::Fan *fan) { +uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *fan = static_cast(entity); FanStateResponse msg; auto traits = fan->get_traits(); msg.state = fan->state; @@ -393,9 +388,11 @@ bool APIConnection::try_send_fan_state_(fan::Fan *fan) { if (traits.supports_preset_modes()) msg.preset_mode = fan->preset_mode; msg.key = fan->get_object_id_hash(); - return this->send_fan_state_response(msg); + return encode_message_to_buffer(msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_fan_info_(fan::Fan *fan) { +uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *fan = static_cast(entity); ListEntitiesFanResponse msg; auto traits = fan->get_traits(); msg.supports_oscillation = traits.supports_oscillation(); @@ -405,8 +402,8 @@ bool APIConnection::try_send_fan_info_(fan::Fan *fan) { for (auto const &preset : traits.supported_preset_modes()) msg.supported_preset_modes.push_back(preset); msg.unique_id = get_default_unique_id("fan", fan); - return this->try_send_entity_info_(static_cast(fan), msg, - &APIConnection::send_list_entities_fan_response); + fill_entity_info_base(fan, msg); + return encode_message_to_buffer(msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::fan_command(const FanCommandRequest &msg) { fan::Fan *fan = App.get_fan_by_key(msg.key); @@ -432,14 +429,14 @@ void APIConnection::fan_command(const FanCommandRequest &msg) { #ifdef USE_LIGHT bool APIConnection::send_light_state(light::LightState *light) { - return this->send_state_(static_cast(light), - reinterpret_cast(&APIConnection::try_send_light_state_)); + return this->schedule_message_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE); } void APIConnection::send_light_info(light::LightState *light) { - this->send_info_(static_cast(light), - reinterpret_cast(&APIConnection::try_send_light_info_)); + this->schedule_message_(light, &APIConnection::try_send_light_info, ListEntitiesLightResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_light_state_(light::LightState *light) { +uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *light = static_cast(entity); LightStateResponse resp; auto traits = light->get_traits(); auto values = light->remote_values; @@ -458,9 +455,11 @@ bool APIConnection::try_send_light_state_(light::LightState *light) { if (light->supports_effects()) resp.effect = light->get_effect_name(); resp.key = light->get_object_id_hash(); - return this->send_light_state_response(resp); + return encode_message_to_buffer(resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_light_info_(light::LightState *light) { +uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *light = static_cast(entity); ListEntitiesLightResponse msg; auto traits = light->get_traits(); for (auto mode : traits.get_supported_color_modes()) @@ -483,8 +482,8 @@ bool APIConnection::try_send_light_info_(light::LightState *light) { } } msg.unique_id = get_default_unique_id("light", light); - return this->try_send_entity_info_(static_cast(light), msg, - &APIConnection::send_list_entities_light_response); + fill_entity_info_base(light, msg); + return encode_message_to_buffer(msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::light_command(const LightCommandRequest &msg) { light::LightState *light = App.get_light_by_key(msg.key); @@ -524,26 +523,26 @@ void APIConnection::light_command(const LightCommandRequest &msg) { #endif #ifdef USE_SENSOR -bool APIConnection::send_sensor_state(sensor::Sensor *sensor, float state) { - return this->send_state_with_value_(sensor, &APIConnection::try_send_sensor_state_, - &APIConnection::try_send_sensor_state_, state); +bool APIConnection::send_sensor_state(sensor::Sensor *sensor) { + return this->schedule_message_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE); } void APIConnection::send_sensor_info(sensor::Sensor *sensor) { - this->send_info_(static_cast(sensor), - reinterpret_cast(&APIConnection::try_send_sensor_info_)); + this->schedule_message_(sensor, &APIConnection::try_send_sensor_info, ListEntitiesSensorResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_sensor_state_(sensor::Sensor *sensor) { - return this->try_send_sensor_state_(sensor, sensor->state); -} -bool APIConnection::try_send_sensor_state_(sensor::Sensor *sensor, float state) { - SensorStateResponse resp; - resp.state = state; - resp.missing_state = !sensor->has_state(); +uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *sensor = static_cast(entity); + SensorStateResponse resp; + resp.state = sensor->state; + resp.missing_state = !sensor->has_state(); resp.key = sensor->get_object_id_hash(); - return this->send_sensor_state_response(resp); + return encode_message_to_buffer(resp, SensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_sensor_info_(sensor::Sensor *sensor) { + +uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *sensor = static_cast(entity); ListEntitiesSensorResponse msg; msg.unit_of_measurement = sensor->get_unit_of_measurement(); msg.accuracy_decimals = sensor->get_accuracy_decimals(); @@ -553,37 +552,37 @@ bool APIConnection::try_send_sensor_info_(sensor::Sensor *sensor) { msg.unique_id = sensor->unique_id(); if (msg.unique_id.empty()) msg.unique_id = get_default_unique_id("sensor", sensor); - return this->try_send_entity_info_(static_cast(sensor), msg, - &APIConnection::send_list_entities_sensor_response); + fill_entity_info_base(sensor, msg); + return encode_message_to_buffer(msg, ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } #endif #ifdef USE_SWITCH -bool APIConnection::send_switch_state(switch_::Switch *a_switch, bool state) { - return this->send_state_with_value_(a_switch, &APIConnection::try_send_switch_state_, - &APIConnection::try_send_switch_state_, state); +bool APIConnection::send_switch_state(switch_::Switch *a_switch) { + return this->schedule_message_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE); } void APIConnection::send_switch_info(switch_::Switch *a_switch) { - this->send_info_(static_cast(a_switch), - reinterpret_cast(&APIConnection::try_send_switch_info_)); + this->schedule_message_(a_switch, &APIConnection::try_send_switch_info, ListEntitiesSwitchResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_switch_state_(switch_::Switch *a_switch) { - return this->try_send_switch_state_(a_switch, a_switch->state); -} -bool APIConnection::try_send_switch_state_(switch_::Switch *a_switch, bool state) { - SwitchStateResponse resp; - resp.state = state; +uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *a_switch = static_cast(entity); + SwitchStateResponse resp; + resp.state = a_switch->state; resp.key = a_switch->get_object_id_hash(); - return this->send_switch_state_response(resp); + return encode_message_to_buffer(resp, SwitchStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_switch_info_(switch_::Switch *a_switch) { + +uint16_t APIConnection::try_send_switch_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *a_switch = static_cast(entity); ListEntitiesSwitchResponse msg; msg.assumed_state = a_switch->assumed_state(); msg.device_class = a_switch->get_device_class(); msg.unique_id = get_default_unique_id("switch", a_switch); - return this->try_send_entity_info_(static_cast(a_switch), msg, - &APIConnection::send_list_entities_switch_response); + fill_entity_info_base(a_switch, msg); + return encode_message_to_buffer(msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::switch_command(const SwitchCommandRequest &msg) { switch_::Switch *a_switch = App.get_switch_by_key(msg.key); @@ -599,46 +598,44 @@ void APIConnection::switch_command(const SwitchCommandRequest &msg) { #endif #ifdef USE_TEXT_SENSOR -bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state) { - return this->send_state_with_value_(text_sensor, &APIConnection::try_send_text_sensor_state_, - &APIConnection::try_send_text_sensor_state_, std::move(state)); +bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor) { + return this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_state, + TextSensorStateResponse::MESSAGE_TYPE); } void APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) { - this->send_info_(static_cast(text_sensor), - reinterpret_cast(&APIConnection::try_send_text_sensor_info_)); + this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_info, + ListEntitiesTextSensorResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor) { - return this->try_send_text_sensor_state_(text_sensor, text_sensor->state); -} -bool APIConnection::try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor, std::string state) { - TextSensorStateResponse resp; - resp.state = std::move(state); - resp.missing_state = !text_sensor->has_state(); +uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *text_sensor = static_cast(entity); + TextSensorStateResponse resp; + resp.state = text_sensor->state; + resp.missing_state = !text_sensor->has_state(); resp.key = text_sensor->get_object_id_hash(); - return this->send_text_sensor_state_response(resp); + return encode_message_to_buffer(resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_text_sensor_info_(text_sensor::TextSensor *text_sensor) { +uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *text_sensor = static_cast(entity); ListEntitiesTextSensorResponse msg; msg.device_class = text_sensor->get_device_class(); msg.unique_id = text_sensor->unique_id(); if (msg.unique_id.empty()) msg.unique_id = get_default_unique_id("text_sensor", text_sensor); - return this->try_send_entity_info_(static_cast(text_sensor), msg, - &APIConnection::send_list_entities_text_sensor_response); + fill_entity_info_base(text_sensor, msg); + return encode_message_to_buffer(msg, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } #endif #ifdef USE_CLIMATE bool APIConnection::send_climate_state(climate::Climate *climate) { - return this->send_state_(static_cast(climate), - reinterpret_cast(&APIConnection::try_send_climate_state_)); + return this->schedule_message_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE); } -void APIConnection::send_climate_info(climate::Climate *climate) { - this->send_info_(static_cast(climate), - reinterpret_cast(&APIConnection::try_send_climate_info_)); -} -bool APIConnection::try_send_climate_state_(climate::Climate *climate) { +uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *climate = static_cast(entity); ClimateStateResponse resp; resp.key = climate->get_object_id_hash(); auto traits = climate->get_traits(); @@ -667,9 +664,14 @@ bool APIConnection::try_send_climate_state_(climate::Climate *climate) { resp.current_humidity = climate->current_humidity; if (traits.get_supports_target_humidity()) resp.target_humidity = climate->target_humidity; - return this->send_climate_state_response(resp); + return encode_message_to_buffer(resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_climate_info_(climate::Climate *climate) { +void APIConnection::send_climate_info(climate::Climate *climate) { + this->schedule_message_(climate, &APIConnection::try_send_climate_info, ListEntitiesClimateResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *climate = static_cast(entity); ListEntitiesClimateResponse msg; auto traits = climate->get_traits(); msg.supports_current_temperature = traits.get_supports_current_temperature(); @@ -697,8 +699,8 @@ bool APIConnection::try_send_climate_info_(climate::Climate *climate) { for (auto swing_mode : traits.get_supported_swing_modes()) msg.supported_swing_modes.push_back(static_cast(swing_mode)); msg.unique_id = get_default_unique_id("climate", climate); - return this->try_send_entity_info_(static_cast(climate), msg, - &APIConnection::send_list_entities_climate_response); + fill_entity_info_base(climate, msg); + return encode_message_to_buffer(msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::climate_command(const ClimateCommandRequest &msg) { climate::Climate *climate = App.get_climate_by_key(msg.key); @@ -731,26 +733,26 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) { #endif #ifdef USE_NUMBER -bool APIConnection::send_number_state(number::Number *number, float state) { - return this->send_state_with_value_(number, &APIConnection::try_send_number_state_, - &APIConnection::try_send_number_state_, state); +bool APIConnection::send_number_state(number::Number *number) { + return this->schedule_message_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE); } void APIConnection::send_number_info(number::Number *number) { - this->send_info_(static_cast(number), - reinterpret_cast(&APIConnection::try_send_number_info_)); + this->schedule_message_(number, &APIConnection::try_send_number_info, ListEntitiesNumberResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_number_state_(number::Number *number) { - return this->try_send_number_state_(number, number->state); -} -bool APIConnection::try_send_number_state_(number::Number *number, float state) { - NumberStateResponse resp; - resp.state = state; - resp.missing_state = !number->has_state(); +uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *number = static_cast(entity); + NumberStateResponse resp; + resp.state = number->state; + resp.missing_state = !number->has_state(); resp.key = number->get_object_id_hash(); - return this->send_number_state_response(resp); + return encode_message_to_buffer(resp, NumberStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_number_info_(number::Number *number) { + +uint16_t APIConnection::try_send_number_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *number = static_cast(entity); ListEntitiesNumberResponse msg; msg.unit_of_measurement = number->traits.get_unit_of_measurement(); msg.mode = static_cast(number->traits.get_mode()); @@ -759,8 +761,8 @@ bool APIConnection::try_send_number_info_(number::Number *number) { msg.max_value = number->traits.get_max_value(); msg.step = number->traits.get_step(); msg.unique_id = get_default_unique_id("number", number); - return this->try_send_entity_info_(static_cast(number), msg, - &APIConnection::send_list_entities_number_response); + fill_entity_info_base(number, msg); + return encode_message_to_buffer(msg, ListEntitiesNumberResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::number_command(const NumberCommandRequest &msg) { number::Number *number = App.get_number_by_key(msg.key); @@ -775,28 +777,29 @@ void APIConnection::number_command(const NumberCommandRequest &msg) { #ifdef USE_DATETIME_DATE bool APIConnection::send_date_state(datetime::DateEntity *date) { - return this->send_state_(static_cast(date), - reinterpret_cast(&APIConnection::try_send_date_state_)); + return this->schedule_message_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE); } -void APIConnection::send_date_info(datetime::DateEntity *date) { - this->send_info_(static_cast(date), - reinterpret_cast(&APIConnection::try_send_date_info_)); -} -bool APIConnection::try_send_date_state_(datetime::DateEntity *date) { +uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *date = static_cast(entity); DateStateResponse resp; resp.missing_state = !date->has_state(); resp.year = date->year; resp.month = date->month; resp.day = date->day; - resp.key = date->get_object_id_hash(); - return this->send_date_state_response(resp); + return encode_message_to_buffer(resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_date_info_(datetime::DateEntity *date) { +void APIConnection::send_date_info(datetime::DateEntity *date) { + this->schedule_message_(date, &APIConnection::try_send_date_info, ListEntitiesDateResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_date_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *date = static_cast(entity); ListEntitiesDateResponse msg; msg.unique_id = get_default_unique_id("date", date); - return this->try_send_entity_info_(static_cast(date), msg, - &APIConnection::send_list_entities_date_response); + fill_entity_info_base(date, msg); + return encode_message_to_buffer(msg, ListEntitiesDateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::date_command(const DateCommandRequest &msg) { datetime::DateEntity *date = App.get_date_by_key(msg.key); @@ -811,28 +814,29 @@ void APIConnection::date_command(const DateCommandRequest &msg) { #ifdef USE_DATETIME_TIME bool APIConnection::send_time_state(datetime::TimeEntity *time) { - return this->send_state_(static_cast(time), - reinterpret_cast(&APIConnection::try_send_time_state_)); + return this->schedule_message_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE); } -void APIConnection::send_time_info(datetime::TimeEntity *time) { - this->send_info_(static_cast(time), - reinterpret_cast(&APIConnection::try_send_time_info_)); -} -bool APIConnection::try_send_time_state_(datetime::TimeEntity *time) { +uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *time = static_cast(entity); TimeStateResponse resp; resp.missing_state = !time->has_state(); resp.hour = time->hour; resp.minute = time->minute; resp.second = time->second; - resp.key = time->get_object_id_hash(); - return this->send_time_state_response(resp); + return encode_message_to_buffer(resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_time_info_(datetime::TimeEntity *time) { +void APIConnection::send_time_info(datetime::TimeEntity *time) { + this->schedule_message_(time, &APIConnection::try_send_time_info, ListEntitiesTimeResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_time_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *time = static_cast(entity); ListEntitiesTimeResponse msg; msg.unique_id = get_default_unique_id("time", time); - return this->try_send_entity_info_(static_cast(time), msg, - &APIConnection::send_list_entities_time_response); + fill_entity_info_base(time, msg); + return encode_message_to_buffer(msg, ListEntitiesTimeResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::time_command(const TimeCommandRequest &msg) { datetime::TimeEntity *time = App.get_time_by_key(msg.key); @@ -847,29 +851,31 @@ void APIConnection::time_command(const TimeCommandRequest &msg) { #ifdef USE_DATETIME_DATETIME bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) { - return this->send_state_(static_cast(datetime), - reinterpret_cast(&APIConnection::try_send_datetime_state_)); + return this->schedule_message_(datetime, &APIConnection::try_send_datetime_state, + DateTimeStateResponse::MESSAGE_TYPE); } -void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) { - this->send_info_(static_cast(datetime), - reinterpret_cast(&APIConnection::try_send_datetime_info_)); -} -bool APIConnection::try_send_datetime_state_(datetime::DateTimeEntity *datetime) { +uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *datetime = static_cast(entity); DateTimeStateResponse resp; resp.missing_state = !datetime->has_state(); if (datetime->has_state()) { ESPTime state = datetime->state_as_esptime(); resp.epoch_seconds = state.timestamp; } - resp.key = datetime->get_object_id_hash(); - return this->send_date_time_state_response(resp); + return encode_message_to_buffer(resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_datetime_info_(datetime::DateTimeEntity *datetime) { +void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) { + this->schedule_message_(datetime, &APIConnection::try_send_datetime_info, ListEntitiesDateTimeResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_datetime_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *datetime = static_cast(entity); ListEntitiesDateTimeResponse msg; msg.unique_id = get_default_unique_id("datetime", datetime); - return this->try_send_entity_info_(static_cast(datetime), msg, - &APIConnection::send_list_entities_date_time_response); + fill_entity_info_base(datetime, msg); + return encode_message_to_buffer(msg, ListEntitiesDateTimeResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::datetime_command(const DateTimeCommandRequest &msg) { datetime::DateTimeEntity *datetime = App.get_datetime_by_key(msg.key); @@ -883,32 +889,34 @@ void APIConnection::datetime_command(const DateTimeCommandRequest &msg) { #endif #ifdef USE_TEXT -bool APIConnection::send_text_state(text::Text *text, std::string state) { - return this->send_state_with_value_(text, &APIConnection::try_send_text_state_, &APIConnection::try_send_text_state_, - std::move(state)); +bool APIConnection::send_text_state(text::Text *text) { + return this->schedule_message_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE); } void APIConnection::send_text_info(text::Text *text) { - this->send_info_(static_cast(text), - reinterpret_cast(&APIConnection::try_send_text_info_)); + this->schedule_message_(text, &APIConnection::try_send_text_info, ListEntitiesTextResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_text_state_(text::Text *text) { return this->try_send_text_state_(text, text->state); } -bool APIConnection::try_send_text_state_(text::Text *text, std::string state) { - TextStateResponse resp; - resp.state = std::move(state); - resp.missing_state = !text->has_state(); +uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *text = static_cast(entity); + TextStateResponse resp; + resp.state = text->state; + resp.missing_state = !text->has_state(); resp.key = text->get_object_id_hash(); - return this->send_text_state_response(resp); + return encode_message_to_buffer(resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_text_info_(text::Text *text) { + +uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *text = static_cast(entity); ListEntitiesTextResponse msg; msg.mode = static_cast(text->traits.get_mode()); msg.min_length = text->traits.get_min_length(); msg.max_length = text->traits.get_max_length(); msg.pattern = text->traits.get_pattern(); msg.unique_id = get_default_unique_id("text", text); - return this->try_send_entity_info_(static_cast(text), msg, - &APIConnection::send_list_entities_text_response); + fill_entity_info_base(text, msg); + return encode_message_to_buffer(msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::text_command(const TextCommandRequest &msg) { text::Text *text = App.get_text_by_key(msg.key); @@ -922,32 +930,32 @@ void APIConnection::text_command(const TextCommandRequest &msg) { #endif #ifdef USE_SELECT -bool APIConnection::send_select_state(select::Select *select, std::string state) { - return this->send_state_with_value_(select, &APIConnection::try_send_select_state_, - &APIConnection::try_send_select_state_, std::move(state)); +bool APIConnection::send_select_state(select::Select *select) { + return this->schedule_message_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE); } void APIConnection::send_select_info(select::Select *select) { - this->send_info_(static_cast(select), - reinterpret_cast(&APIConnection::try_send_select_info_)); + this->schedule_message_(select, &APIConnection::try_send_select_info, ListEntitiesSelectResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_select_state_(select::Select *select) { - return this->try_send_select_state_(select, select->state); -} -bool APIConnection::try_send_select_state_(select::Select *select, std::string state) { - SelectStateResponse resp; - resp.state = std::move(state); - resp.missing_state = !select->has_state(); +uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *select = static_cast(entity); + SelectStateResponse resp; + resp.state = select->state; + resp.missing_state = !select->has_state(); resp.key = select->get_object_id_hash(); - return this->send_select_state_response(resp); + return encode_message_to_buffer(resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_select_info_(select::Select *select) { + +uint16_t APIConnection::try_send_select_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *select = static_cast(entity); ListEntitiesSelectResponse msg; for (const auto &option : select->traits.get_options()) msg.options.push_back(option); msg.unique_id = get_default_unique_id("select", select); - return this->try_send_entity_info_(static_cast(select), msg, - &APIConnection::send_list_entities_select_response); + fill_entity_info_base(select, msg); + return encode_message_to_buffer(msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::select_command(const SelectCommandRequest &msg) { select::Select *select = App.get_select_by_key(msg.key); @@ -962,15 +970,16 @@ void APIConnection::select_command(const SelectCommandRequest &msg) { #ifdef USE_BUTTON void esphome::api::APIConnection::send_button_info(button::Button *button) { - this->send_info_(static_cast(button), - reinterpret_cast(&APIConnection::try_send_button_info_)); + this->schedule_message_(button, &APIConnection::try_send_button_info, ListEntitiesButtonResponse::MESSAGE_TYPE); } -bool esphome::api::APIConnection::try_send_button_info_(button::Button *button) { +uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *button = static_cast(entity); ListEntitiesButtonResponse msg; msg.device_class = button->get_device_class(); msg.unique_id = get_default_unique_id("button", button); - return this->try_send_entity_info_(static_cast(button), msg, - &APIConnection::send_list_entities_button_response); + fill_entity_info_base(button, msg); + return encode_message_to_buffer(msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg) { button::Button *button = App.get_button_by_key(msg.key); @@ -982,32 +991,32 @@ void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg #endif #ifdef USE_LOCK -bool APIConnection::send_lock_state(lock::Lock *a_lock, lock::LockState state) { - return this->send_state_with_value_(a_lock, &APIConnection::try_send_lock_state_, - &APIConnection::try_send_lock_state_, state); +bool APIConnection::send_lock_state(lock::Lock *a_lock) { + return this->schedule_message_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE); } void APIConnection::send_lock_info(lock::Lock *a_lock) { - this->send_info_(static_cast(a_lock), - reinterpret_cast(&APIConnection::try_send_lock_info_)); + this->schedule_message_(a_lock, &APIConnection::try_send_lock_info, ListEntitiesLockResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_lock_state_(lock::Lock *a_lock) { - return this->try_send_lock_state_(a_lock, a_lock->state); -} -bool APIConnection::try_send_lock_state_(lock::Lock *a_lock, lock::LockState state) { - LockStateResponse resp; - resp.state = static_cast(state); +uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *a_lock = static_cast(entity); + LockStateResponse resp; + resp.state = static_cast(a_lock->state); resp.key = a_lock->get_object_id_hash(); - return this->send_lock_state_response(resp); + return encode_message_to_buffer(resp, LockStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_lock_info_(lock::Lock *a_lock) { + +uint16_t APIConnection::try_send_lock_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *a_lock = static_cast(entity); ListEntitiesLockResponse msg; msg.assumed_state = a_lock->traits.get_assumed_state(); msg.supports_open = a_lock->traits.get_supports_open(); msg.requires_code = a_lock->traits.get_requires_code(); msg.unique_id = get_default_unique_id("lock", a_lock); - return this->try_send_entity_info_(static_cast(a_lock), msg, - &APIConnection::send_list_entities_lock_response); + fill_entity_info_base(a_lock, msg); + return encode_message_to_buffer(msg, ListEntitiesLockResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::lock_command(const LockCommandRequest &msg) { lock::Lock *a_lock = App.get_lock_by_key(msg.key); @@ -1030,22 +1039,23 @@ void APIConnection::lock_command(const LockCommandRequest &msg) { #ifdef USE_VALVE bool APIConnection::send_valve_state(valve::Valve *valve) { - return this->send_state_(static_cast(valve), - reinterpret_cast(&APIConnection::try_send_valve_state_)); + return this->schedule_message_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE); } -void APIConnection::send_valve_info(valve::Valve *valve) { - this->send_info_(static_cast(valve), - reinterpret_cast(&APIConnection::try_send_valve_info_)); -} -bool APIConnection::try_send_valve_state_(valve::Valve *valve) { +uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *valve = static_cast(entity); ValveStateResponse resp; resp.position = valve->position; resp.current_operation = static_cast(valve->current_operation); - resp.key = valve->get_object_id_hash(); - return this->send_valve_state_response(resp); + return encode_message_to_buffer(resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_valve_info_(valve::Valve *valve) { +void APIConnection::send_valve_info(valve::Valve *valve) { + this->schedule_message_(valve, &APIConnection::try_send_valve_info, ListEntitiesValveResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *valve = static_cast(entity); ListEntitiesValveResponse msg; auto traits = valve->get_traits(); msg.device_class = valve->get_device_class(); @@ -1053,8 +1063,8 @@ bool APIConnection::try_send_valve_info_(valve::Valve *valve) { msg.supports_position = traits.get_supports_position(); msg.supports_stop = traits.get_supports_stop(); msg.unique_id = get_default_unique_id("valve", valve); - return this->try_send_entity_info_(static_cast(valve), msg, - &APIConnection::send_list_entities_valve_response); + fill_entity_info_base(valve, msg); + return encode_message_to_buffer(msg, ListEntitiesValveResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::valve_command(const ValveCommandRequest &msg) { valve::Valve *valve = App.get_valve_by_key(msg.key); @@ -1072,14 +1082,12 @@ void APIConnection::valve_command(const ValveCommandRequest &msg) { #ifdef USE_MEDIA_PLAYER bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) { - return this->send_state_(static_cast(media_player), - reinterpret_cast(&APIConnection::try_send_media_player_state_)); + return this->schedule_message_(media_player, &APIConnection::try_send_media_player_state, + MediaPlayerStateResponse::MESSAGE_TYPE); } -void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) { - this->send_info_(static_cast(media_player), - reinterpret_cast(&APIConnection::try_send_media_player_info_)); -} -bool APIConnection::try_send_media_player_state_(media_player::MediaPlayer *media_player) { +uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *media_player = static_cast(entity); MediaPlayerStateResponse resp; media_player::MediaPlayerState report_state = media_player->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING ? media_player::MEDIA_PLAYER_STATE_PLAYING @@ -1087,11 +1095,16 @@ bool APIConnection::try_send_media_player_state_(media_player::MediaPlayer *medi resp.state = static_cast(report_state); resp.volume = media_player->volume; resp.muted = media_player->is_muted(); - resp.key = media_player->get_object_id_hash(); - return this->send_media_player_state_response(resp); + return encode_message_to_buffer(resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_media_player_info_(media_player::MediaPlayer *media_player) { +void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) { + this->schedule_message_(media_player, &APIConnection::try_send_media_player_info, + ListEntitiesMediaPlayerResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *media_player = static_cast(entity); ListEntitiesMediaPlayerResponse msg; auto traits = media_player->get_traits(); msg.supports_pause = traits.get_supports_pause(); @@ -1105,8 +1118,8 @@ bool APIConnection::try_send_media_player_info_(media_player::MediaPlayer *media msg.supported_formats.push_back(media_format); } msg.unique_id = get_default_unique_id("media_player", media_player); - return this->try_send_entity_info_(static_cast(media_player), msg, - &APIConnection::send_list_entities_media_player_response); + fill_entity_info_base(media_player, msg); + return encode_message_to_buffer(msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) { media_player::MediaPlayer *media_player = App.get_media_player_by_key(msg.key); @@ -1141,14 +1154,15 @@ void APIConnection::set_camera_state(std::shared_ptr this->image_reader_.set_image(std::move(image)); } void APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) { - this->send_info_(static_cast(camera), - reinterpret_cast(&APIConnection::try_send_camera_info_)); + this->schedule_message_(camera, &APIConnection::try_send_camera_info, ListEntitiesCameraResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_camera_info_(esp32_camera::ESP32Camera *camera) { +uint16_t APIConnection::try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *camera = static_cast(entity); ListEntitiesCameraResponse msg; msg.unique_id = get_default_unique_id("camera", camera); - return this->try_send_entity_info_(static_cast(camera), msg, - &APIConnection::send_list_entities_camera_response); + fill_entity_info_base(camera, msg); + return encode_message_to_buffer(msg, ListEntitiesCameraResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::camera_image(const CameraImageRequest &msg) { if (esp32_camera::global_esp32_camera == nullptr) @@ -1191,9 +1205,9 @@ bool APIConnection::send_bluetooth_le_advertisement(const BluetoothLEAdvertiseme manufacturer_data.legacy_data.assign(manufacturer_data.data.begin(), manufacturer_data.data.end()); manufacturer_data.data.clear(); } - return this->send_bluetooth_le_advertisement_response(resp); + return this->send_message(resp); } - return this->send_bluetooth_le_advertisement_response(msg); + return this->send_message(msg); } void APIConnection::bluetooth_device_request(const BluetoothDeviceRequest &msg) { bluetooth_proxy::global_bluetooth_proxy->bluetooth_device_request(msg); @@ -1337,28 +1351,32 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon #ifdef USE_ALARM_CONTROL_PANEL bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { - return this->send_state_(static_cast(a_alarm_control_panel), - reinterpret_cast(&APIConnection::try_send_alarm_control_panel_state_)); + return this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_state, + AlarmControlPanelStateResponse::MESSAGE_TYPE); } -void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { - this->send_info_(static_cast(a_alarm_control_panel), - reinterpret_cast(&APIConnection::try_send_alarm_control_panel_info_)); -} -bool APIConnection::try_send_alarm_control_panel_state_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { +uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, APIConnection *conn, + uint32_t remaining_size, bool is_single) { + auto *a_alarm_control_panel = static_cast(entity); AlarmControlPanelStateResponse resp; resp.state = static_cast(a_alarm_control_panel->get_state()); - resp.key = a_alarm_control_panel->get_object_id_hash(); - return this->send_alarm_control_panel_state_response(resp); + return encode_message_to_buffer(resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_alarm_control_panel_info_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { +void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { + this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_info, + ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, + uint32_t remaining_size, bool is_single) { + auto *a_alarm_control_panel = static_cast(entity); ListEntitiesAlarmControlPanelResponse msg; msg.supported_features = a_alarm_control_panel->get_supported_features(); msg.requires_code = a_alarm_control_panel->get_requires_code(); msg.requires_code_to_arm = a_alarm_control_panel->get_requires_code_to_arm(); msg.unique_id = get_default_unique_id("alarm_control_panel", a_alarm_control_panel); - return this->try_send_entity_info_(static_cast(a_alarm_control_panel), msg, - &APIConnection::send_list_entities_alarm_control_panel_response); + fill_entity_info_base(a_alarm_control_panel, msg); + return encode_message_to_buffer(msg, ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE, conn, remaining_size, + is_single); } void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) { alarm_control_panel::AlarmControlPanel *a_alarm_control_panel = App.get_alarm_control_panel_by_key(msg.key); @@ -1395,45 +1413,40 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe #endif #ifdef USE_EVENT -void APIConnection::send_event(event::Event *event, std::string event_type) { - this->send_state_with_value_(event, &APIConnection::try_send_event_, &APIConnection::try_send_event_, - std::move(event_type)); +void APIConnection::send_event(event::Event *event, const std::string &event_type) { + this->schedule_message_(event, MessageCreator(event_type, EventResponse::MESSAGE_TYPE), EventResponse::MESSAGE_TYPE); } void APIConnection::send_event_info(event::Event *event) { - this->send_info_(static_cast(event), - reinterpret_cast(&APIConnection::try_send_event_info_)); + this->schedule_message_(event, &APIConnection::try_send_event_info, ListEntitiesEventResponse::MESSAGE_TYPE); } -bool APIConnection::try_send_event_(event::Event *event) { - return this->try_send_event_(event, *(event->last_event_type)); -} -bool APIConnection::try_send_event_(event::Event *event, std::string event_type) { +uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn, + uint32_t remaining_size, bool is_single) { EventResponse resp; - resp.event_type = std::move(event_type); - + resp.event_type = event_type; resp.key = event->get_object_id_hash(); - return this->send_event_response(resp); + return encode_message_to_buffer(resp, EventResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_event_info_(event::Event *event) { + +uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *event = static_cast(entity); ListEntitiesEventResponse msg; msg.device_class = event->get_device_class(); for (const auto &event_type : event->get_event_types()) msg.event_types.push_back(event_type); msg.unique_id = get_default_unique_id("event", event); - return this->try_send_entity_info_(static_cast(event), msg, - &APIConnection::send_list_entities_event_response); + fill_entity_info_base(event, msg); + return encode_message_to_buffer(msg, ListEntitiesEventResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } #endif #ifdef USE_UPDATE bool APIConnection::send_update_state(update::UpdateEntity *update) { - return this->send_state_(static_cast(update), - reinterpret_cast(&APIConnection::try_send_update_state_)); + return this->schedule_message_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE); } -void APIConnection::send_update_info(update::UpdateEntity *update) { - this->send_info_(static_cast(update), - reinterpret_cast(&APIConnection::try_send_update_info_)); -} -bool APIConnection::try_send_update_state_(update::UpdateEntity *update) { +uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *update = static_cast(entity); UpdateStateResponse resp; resp.missing_state = !update->has_state(); if (update->has_state()) { @@ -1448,16 +1461,20 @@ bool APIConnection::try_send_update_state_(update::UpdateEntity *update) { resp.release_summary = update->update_info.summary; resp.release_url = update->update_info.release_url; } - resp.key = update->get_object_id_hash(); - return this->send_update_state_response(resp); + return encode_message_to_buffer(resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } -bool APIConnection::try_send_update_info_(update::UpdateEntity *update) { +void APIConnection::send_update_info(update::UpdateEntity *update) { + this->schedule_message_(update, &APIConnection::try_send_update_info, ListEntitiesUpdateResponse::MESSAGE_TYPE); +} +uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + auto *update = static_cast(entity); ListEntitiesUpdateResponse msg; msg.device_class = update->get_device_class(); msg.unique_id = get_default_unique_id("update", update); - return this->try_send_entity_info_(static_cast(update), msg, - &APIConnection::send_list_entities_update_response); + fill_entity_info_base(update, msg); + return encode_message_to_buffer(msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } void APIConnection::update_command(const UpdateCommandRequest &msg) { update::UpdateEntity *update = App.get_update_by_key(msg.key); @@ -1472,7 +1489,7 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) { update->check(); break; case enums::UPDATE_COMMAND_NONE: - ESP_LOGE(TAG, "UPDATE_COMMAND_NONE not handled. Check client is sending the correct command"); + ESP_LOGE(TAG, "UPDATE_COMMAND_NONE not handled; confirm command is correct"); break; default: ESP_LOGW(TAG, "Unknown update command: %" PRIu32, msg.command); @@ -1534,7 +1551,7 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { // bool invalid_password = 1; resp.invalid_password = !correct; if (correct) { - ESP_LOGD(TAG, "%s: Connected successfully", this->client_combined_info_.c_str()); + ESP_LOGD(TAG, "%s connected", this->client_combined_info_.c_str()); this->connection_state_ = ConnectionState::AUTHENTICATED; this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_); #ifdef USE_HOMEASSISTANT_TIME @@ -1605,7 +1622,7 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) { } } if (!found) { - ESP_LOGV(TAG, "Could not find matching service!"); + ESP_LOGV(TAG, "Could not find service"); } } #ifdef USE_API_NOISE @@ -1651,7 +1668,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { } return false; } -bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) { +bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) { if (!this->try_to_clear_buffer(message_type != 29)) { // SubscribeLogsResponse return false; } @@ -1674,17 +1691,350 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) } void APIConnection::on_unauthenticated_access() { this->on_fatal_error(); - ESP_LOGD(TAG, "%s: tried to access without authentication.", this->client_combined_info_.c_str()); + ESP_LOGD(TAG, "%s requested access without authentication", this->client_combined_info_.c_str()); } void APIConnection::on_no_setup_connection() { this->on_fatal_error(); - ESP_LOGD(TAG, "%s: tried to access without full connection.", this->client_combined_info_.c_str()); + ESP_LOGD(TAG, "%s requested access without full connection", this->client_combined_info_.c_str()); } void APIConnection::on_fatal_error() { this->helper_->close(); this->remove_ = true; } +void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) { + // Check if we already have a message of this type for this entity + // This provides deduplication per entity/message_type combination + // O(n) but optimized for RAM and not performance. + for (auto &item : items) { + if (item.entity == entity && item.message_type == message_type) { + // Update the existing item with the new creator + item.creator = std::move(creator); + return; + } + } + + // No existing item found, add new one + items.emplace_back(entity, std::move(creator), message_type); +} + +bool APIConnection::schedule_batch_() { + if (!this->deferred_batch_.batch_scheduled) { + this->deferred_batch_.batch_scheduled = true; + this->deferred_batch_.batch_start_time = App.get_loop_component_start_time(); + } + return true; +} + +ProtoWriteBuffer APIConnection::allocate_single_message_buffer(uint16_t size) { return this->create_buffer(size); } + +ProtoWriteBuffer APIConnection::allocate_batch_message_buffer(uint16_t size) { + ProtoWriteBuffer result = this->prepare_message_buffer(size, this->batch_first_message_); + this->batch_first_message_ = false; + return result; +} + +void APIConnection::process_batch_() { + if (this->deferred_batch_.empty()) { + this->deferred_batch_.batch_scheduled = false; + return; + } + + // Try to clear buffer first + if (!this->try_to_clear_buffer(true)) { + // Can't write now, we'll try again later + return; + } + + size_t num_items = this->deferred_batch_.items.size(); + + // Fast path for single message - allocate exact size needed + if (num_items == 1) { + const auto &item = this->deferred_batch_.items[0]; + + // Let the creator calculate size and encode if it fits + uint16_t payload_size = item.creator(item.entity, this, std::numeric_limits::max(), true); + + if (payload_size > 0 && + this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) { + this->deferred_batch_.clear(); + } else if (payload_size == 0) { + // Message too large + ESP_LOGW(TAG, "Message too large to send: type=%u", item.message_type); + this->deferred_batch_.clear(); + } + return; + } + + // Pre-allocate storage for packet info + std::vector packet_info; + packet_info.reserve(num_items); + + // Cache these values to avoid repeated virtual calls + const uint8_t header_padding = this->helper_->frame_header_padding(); + const uint8_t footer_size = this->helper_->frame_footer_size(); + + // Initialize buffer and tracking variables + this->parent_->get_shared_buffer_ref().clear(); + + // Pre-calculate exact buffer size needed based on message types + uint32_t total_estimated_size = 0; + for (const auto &item : this->deferred_batch_.items) { + total_estimated_size += get_estimated_message_size(item.message_type); + } + + // Calculate total overhead for all messages + uint32_t total_overhead = (header_padding + footer_size) * num_items; + + // Reserve based on estimated size (much more accurate than 24-byte worst-case) + this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead); + this->batch_first_message_ = true; + + size_t items_processed = 0; + uint32_t remaining_size = MAX_PACKET_SIZE; + + // Track where each message's header padding begins in the buffer + // For plaintext: this is where the 6-byte header padding starts + // For noise: this is where the 7-byte header padding starts + // The actual message data follows after the header padding + uint32_t current_offset = 0; + + // Process items and encode directly to buffer + for (const auto &item : this->deferred_batch_.items) { + // Try to encode message + // The creator will calculate overhead to determine if the message fits + uint16_t payload_size = item.creator(item.entity, this, remaining_size, false); + + if (payload_size == 0) { + // Message won't fit, stop processing + break; + } + + // Message was encoded successfully + // payload_size is header_padding + actual payload size + footer_size + uint16_t proto_payload_size = payload_size - header_padding - footer_size; + packet_info.emplace_back(item.message_type, current_offset, proto_payload_size); + + // Update tracking variables + remaining_size -= payload_size; + // Calculate where the next message's header padding will start + // Current buffer size + footer space (that prepare_message_buffer will add for this message) + current_offset = this->parent_->get_shared_buffer_ref().size() + footer_size; + items_processed++; + } + + if (items_processed == 0) { + this->deferred_batch_.clear(); + return; + } + + // Add footer space for the last message (for Noise protocol MAC) + if (footer_size > 0) { + auto &shared_buf = this->parent_->get_shared_buffer_ref(); + shared_buf.resize(shared_buf.size() + footer_size); + } + + // Send all collected packets + APIError err = + this->helper_->write_protobuf_packets(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, packet_info); + if (err != APIError::OK && err != APIError::WOULD_BLOCK) { + on_fatal_error(); + if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) { + ESP_LOGW(TAG, "%s: Connection reset during batch write", this->client_combined_info_.c_str()); + } else { + ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err), + errno); + } + } + + // Handle remaining items more efficiently + if (items_processed < this->deferred_batch_.items.size()) { + // Remove processed items from the beginning + this->deferred_batch_.items.erase(this->deferred_batch_.items.begin(), + this->deferred_batch_.items.begin() + items_processed); + + // Reschedule for remaining items + this->schedule_batch_(); + } else { + // All items processed + this->deferred_batch_.clear(); + } +} + +uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) const { + switch (message_type_) { + case 0: // Function pointer + return data_.ptr(entity, conn, remaining_size, is_single); + +#ifdef USE_EVENT + case EventResponse::MESSAGE_TYPE: { + auto *e = static_cast(entity); + return APIConnection::try_send_event_response(e, *data_.string_ptr, conn, remaining_size, is_single); + } +#endif + + default: + // Should not happen, return 0 to indicate no message + return 0; + } +} + +uint16_t APIConnection::try_send_list_info_done(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + ListEntitiesDoneResponse resp; + return encode_message_to_buffer(resp, ListEntitiesDoneResponse::MESSAGE_TYPE, conn, remaining_size, is_single); +} + +uint16_t APIConnection::try_send_disconnect_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single) { + DisconnectRequest req; + return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size, is_single); +} + +uint16_t APIConnection::get_estimated_message_size(uint16_t message_type) { + // Use generated ESTIMATED_SIZE constants from each message type + switch (message_type) { +#ifdef USE_BINARY_SENSOR + case BinarySensorStateResponse::MESSAGE_TYPE: + return BinarySensorStateResponse::ESTIMATED_SIZE; + case ListEntitiesBinarySensorResponse::MESSAGE_TYPE: + return ListEntitiesBinarySensorResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_SENSOR + case SensorStateResponse::MESSAGE_TYPE: + return SensorStateResponse::ESTIMATED_SIZE; + case ListEntitiesSensorResponse::MESSAGE_TYPE: + return ListEntitiesSensorResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_SWITCH + case SwitchStateResponse::MESSAGE_TYPE: + return SwitchStateResponse::ESTIMATED_SIZE; + case ListEntitiesSwitchResponse::MESSAGE_TYPE: + return ListEntitiesSwitchResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_TEXT_SENSOR + case TextSensorStateResponse::MESSAGE_TYPE: + return TextSensorStateResponse::ESTIMATED_SIZE; + case ListEntitiesTextSensorResponse::MESSAGE_TYPE: + return ListEntitiesTextSensorResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_NUMBER + case NumberStateResponse::MESSAGE_TYPE: + return NumberStateResponse::ESTIMATED_SIZE; + case ListEntitiesNumberResponse::MESSAGE_TYPE: + return ListEntitiesNumberResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_TEXT + case TextStateResponse::MESSAGE_TYPE: + return TextStateResponse::ESTIMATED_SIZE; + case ListEntitiesTextResponse::MESSAGE_TYPE: + return ListEntitiesTextResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_SELECT + case SelectStateResponse::MESSAGE_TYPE: + return SelectStateResponse::ESTIMATED_SIZE; + case ListEntitiesSelectResponse::MESSAGE_TYPE: + return ListEntitiesSelectResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_LOCK + case LockStateResponse::MESSAGE_TYPE: + return LockStateResponse::ESTIMATED_SIZE; + case ListEntitiesLockResponse::MESSAGE_TYPE: + return ListEntitiesLockResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_EVENT + case EventResponse::MESSAGE_TYPE: + return EventResponse::ESTIMATED_SIZE; + case ListEntitiesEventResponse::MESSAGE_TYPE: + return ListEntitiesEventResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_COVER + case CoverStateResponse::MESSAGE_TYPE: + return CoverStateResponse::ESTIMATED_SIZE; + case ListEntitiesCoverResponse::MESSAGE_TYPE: + return ListEntitiesCoverResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_FAN + case FanStateResponse::MESSAGE_TYPE: + return FanStateResponse::ESTIMATED_SIZE; + case ListEntitiesFanResponse::MESSAGE_TYPE: + return ListEntitiesFanResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_LIGHT + case LightStateResponse::MESSAGE_TYPE: + return LightStateResponse::ESTIMATED_SIZE; + case ListEntitiesLightResponse::MESSAGE_TYPE: + return ListEntitiesLightResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_CLIMATE + case ClimateStateResponse::MESSAGE_TYPE: + return ClimateStateResponse::ESTIMATED_SIZE; + case ListEntitiesClimateResponse::MESSAGE_TYPE: + return ListEntitiesClimateResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_ESP32_CAMERA + case ListEntitiesCameraResponse::MESSAGE_TYPE: + return ListEntitiesCameraResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_BUTTON + case ListEntitiesButtonResponse::MESSAGE_TYPE: + return ListEntitiesButtonResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_MEDIA_PLAYER + case MediaPlayerStateResponse::MESSAGE_TYPE: + return MediaPlayerStateResponse::ESTIMATED_SIZE; + case ListEntitiesMediaPlayerResponse::MESSAGE_TYPE: + return ListEntitiesMediaPlayerResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_ALARM_CONTROL_PANEL + case AlarmControlPanelStateResponse::MESSAGE_TYPE: + return AlarmControlPanelStateResponse::ESTIMATED_SIZE; + case ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE: + return ListEntitiesAlarmControlPanelResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_DATETIME_DATE + case DateStateResponse::MESSAGE_TYPE: + return DateStateResponse::ESTIMATED_SIZE; + case ListEntitiesDateResponse::MESSAGE_TYPE: + return ListEntitiesDateResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_DATETIME_TIME + case TimeStateResponse::MESSAGE_TYPE: + return TimeStateResponse::ESTIMATED_SIZE; + case ListEntitiesTimeResponse::MESSAGE_TYPE: + return ListEntitiesTimeResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_DATETIME_DATETIME + case DateTimeStateResponse::MESSAGE_TYPE: + return DateTimeStateResponse::ESTIMATED_SIZE; + case ListEntitiesDateTimeResponse::MESSAGE_TYPE: + return ListEntitiesDateTimeResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_VALVE + case ValveStateResponse::MESSAGE_TYPE: + return ValveStateResponse::ESTIMATED_SIZE; + case ListEntitiesValveResponse::MESSAGE_TYPE: + return ListEntitiesValveResponse::ESTIMATED_SIZE; +#endif +#ifdef USE_UPDATE + case UpdateStateResponse::MESSAGE_TYPE: + return UpdateStateResponse::ESTIMATED_SIZE; + case ListEntitiesUpdateResponse::MESSAGE_TYPE: + return ListEntitiesUpdateResponse::ESTIMATED_SIZE; +#endif + case ListEntitiesServicesResponse::MESSAGE_TYPE: + return ListEntitiesServicesResponse::ESTIMATED_SIZE; + case ListEntitiesDoneResponse::MESSAGE_TYPE: + return ListEntitiesDoneResponse::ESTIMATED_SIZE; + case DisconnectRequest::MESSAGE_TYPE: + return DisconnectRequest::ESTIMATED_SIZE; + default: + // Fallback for unknown message types + return 24; + } +} + } // namespace api } // namespace esphome #endif diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index f965a9e795..34c7dcd880 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -11,6 +11,7 @@ #include "esphome/core/entity_base.h" #include +#include namespace esphome { namespace api { @@ -18,49 +19,9 @@ namespace api { // Keepalive timeout in milliseconds static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000; -using send_message_t = bool (APIConnection::*)(void *); - -/* - This class holds a pointer to the source component that wants to publish a message, and a pointer to a function that - will lazily publish that message. The two pointers allow dedup in the deferred queue if multiple publishes for the - same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a std::vector) is - the DeferredMessage instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per entry. Even - 100 backed up messages (you'd have to have at least 100 sensors publishing because of dedup) would take up only 0.8 - kB. -*/ -class DeferredMessageQueue { - struct DeferredMessage { - friend class DeferredMessageQueue; - - protected: - void *source_; - send_message_t send_message_; - - public: - DeferredMessage(void *source, send_message_t send_message) : source_(source), send_message_(send_message) {} - bool operator==(const DeferredMessage &test) const { - return (source_ == test.source_ && send_message_ == test.send_message_); - } - } __attribute__((packed)); - - protected: - // vector is used very specifically for its zero memory overhead even though items are popped from the front (memory - // footprint is more important than speed here) - std::vector deferred_queue_; - APIConnection *api_connection_; - - // helper for allowing only unique entries in the queue - void dmq_push_back_with_dedup_(void *source, send_message_t send_message); - - public: - DeferredMessageQueue(APIConnection *api_connection) : api_connection_(api_connection) {} - void process_queue(); - void defer(void *source, send_message_t send_message); - bool empty() const { return deferred_queue_.empty(); } -}; - class APIConnection : public APIServerConnection { public: + friend class APIServer; APIConnection(std::unique_ptr socket, APIServer *parent); virtual ~APIConnection(); @@ -68,225 +29,105 @@ class APIConnection : public APIServerConnection { void loop(); bool send_list_info_done() { - ListEntitiesDoneResponse resp; - return this->send_list_entities_done_response(resp); + return this->schedule_message_(nullptr, &APIConnection::try_send_list_info_done, + ListEntitiesDoneResponse::MESSAGE_TYPE); } #ifdef USE_BINARY_SENSOR - bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state); + bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor); void send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor); - - protected: - bool try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor); - bool try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor, bool state); - bool try_send_binary_sensor_info_(binary_sensor::BinarySensor *binary_sensor); - - public: #endif #ifdef USE_COVER bool send_cover_state(cover::Cover *cover); void send_cover_info(cover::Cover *cover); void cover_command(const CoverCommandRequest &msg) override; - - protected: - bool try_send_cover_state_(cover::Cover *cover); - bool try_send_cover_info_(cover::Cover *cover); - - public: #endif #ifdef USE_FAN bool send_fan_state(fan::Fan *fan); void send_fan_info(fan::Fan *fan); void fan_command(const FanCommandRequest &msg) override; - - protected: - bool try_send_fan_state_(fan::Fan *fan); - bool try_send_fan_info_(fan::Fan *fan); - - public: #endif #ifdef USE_LIGHT bool send_light_state(light::LightState *light); void send_light_info(light::LightState *light); void light_command(const LightCommandRequest &msg) override; - - protected: - bool try_send_light_state_(light::LightState *light); - bool try_send_light_info_(light::LightState *light); - - public: #endif #ifdef USE_SENSOR - bool send_sensor_state(sensor::Sensor *sensor, float state); + bool send_sensor_state(sensor::Sensor *sensor); void send_sensor_info(sensor::Sensor *sensor); - - protected: - bool try_send_sensor_state_(sensor::Sensor *sensor); - bool try_send_sensor_state_(sensor::Sensor *sensor, float state); - bool try_send_sensor_info_(sensor::Sensor *sensor); - - public: #endif #ifdef USE_SWITCH - bool send_switch_state(switch_::Switch *a_switch, bool state); + bool send_switch_state(switch_::Switch *a_switch); void send_switch_info(switch_::Switch *a_switch); void switch_command(const SwitchCommandRequest &msg) override; - - protected: - bool try_send_switch_state_(switch_::Switch *a_switch); - bool try_send_switch_state_(switch_::Switch *a_switch, bool state); - bool try_send_switch_info_(switch_::Switch *a_switch); - - public: #endif #ifdef USE_TEXT_SENSOR - bool send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state); + bool send_text_sensor_state(text_sensor::TextSensor *text_sensor); void send_text_sensor_info(text_sensor::TextSensor *text_sensor); - - protected: - bool try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor); - bool try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor, std::string state); - bool try_send_text_sensor_info_(text_sensor::TextSensor *text_sensor); - - public: #endif #ifdef USE_ESP32_CAMERA void set_camera_state(std::shared_ptr image); void send_camera_info(esp32_camera::ESP32Camera *camera); void camera_image(const CameraImageRequest &msg) override; - - protected: - bool try_send_camera_info_(esp32_camera::ESP32Camera *camera); - - public: #endif #ifdef USE_CLIMATE bool send_climate_state(climate::Climate *climate); void send_climate_info(climate::Climate *climate); void climate_command(const ClimateCommandRequest &msg) override; - - protected: - bool try_send_climate_state_(climate::Climate *climate); - bool try_send_climate_info_(climate::Climate *climate); - - public: #endif #ifdef USE_NUMBER - bool send_number_state(number::Number *number, float state); + bool send_number_state(number::Number *number); void send_number_info(number::Number *number); void number_command(const NumberCommandRequest &msg) override; - - protected: - bool try_send_number_state_(number::Number *number); - bool try_send_number_state_(number::Number *number, float state); - bool try_send_number_info_(number::Number *number); - - public: #endif #ifdef USE_DATETIME_DATE bool send_date_state(datetime::DateEntity *date); void send_date_info(datetime::DateEntity *date); void date_command(const DateCommandRequest &msg) override; - - protected: - bool try_send_date_state_(datetime::DateEntity *date); - bool try_send_date_info_(datetime::DateEntity *date); - - public: #endif #ifdef USE_DATETIME_TIME bool send_time_state(datetime::TimeEntity *time); void send_time_info(datetime::TimeEntity *time); void time_command(const TimeCommandRequest &msg) override; - - protected: - bool try_send_time_state_(datetime::TimeEntity *time); - bool try_send_time_info_(datetime::TimeEntity *time); - - public: #endif #ifdef USE_DATETIME_DATETIME bool send_datetime_state(datetime::DateTimeEntity *datetime); void send_datetime_info(datetime::DateTimeEntity *datetime); void datetime_command(const DateTimeCommandRequest &msg) override; - - protected: - bool try_send_datetime_state_(datetime::DateTimeEntity *datetime); - bool try_send_datetime_info_(datetime::DateTimeEntity *datetime); - - public: #endif #ifdef USE_TEXT - bool send_text_state(text::Text *text, std::string state); + bool send_text_state(text::Text *text); void send_text_info(text::Text *text); void text_command(const TextCommandRequest &msg) override; - - protected: - bool try_send_text_state_(text::Text *text); - bool try_send_text_state_(text::Text *text, std::string state); - bool try_send_text_info_(text::Text *text); - - public: #endif #ifdef USE_SELECT - bool send_select_state(select::Select *select, std::string state); + bool send_select_state(select::Select *select); void send_select_info(select::Select *select); void select_command(const SelectCommandRequest &msg) override; - - protected: - bool try_send_select_state_(select::Select *select); - bool try_send_select_state_(select::Select *select, std::string state); - bool try_send_select_info_(select::Select *select); - - public: #endif #ifdef USE_BUTTON void send_button_info(button::Button *button); void button_command(const ButtonCommandRequest &msg) override; - - protected: - bool try_send_button_info_(button::Button *button); - - public: #endif #ifdef USE_LOCK - bool send_lock_state(lock::Lock *a_lock, lock::LockState state); + bool send_lock_state(lock::Lock *a_lock); void send_lock_info(lock::Lock *a_lock); void lock_command(const LockCommandRequest &msg) override; - - protected: - bool try_send_lock_state_(lock::Lock *a_lock); - bool try_send_lock_state_(lock::Lock *a_lock, lock::LockState state); - bool try_send_lock_info_(lock::Lock *a_lock); - - public: #endif #ifdef USE_VALVE bool send_valve_state(valve::Valve *valve); void send_valve_info(valve::Valve *valve); void valve_command(const ValveCommandRequest &msg) override; - - protected: - bool try_send_valve_state_(valve::Valve *valve); - bool try_send_valve_info_(valve::Valve *valve); - - public: #endif #ifdef USE_MEDIA_PLAYER bool send_media_player_state(media_player::MediaPlayer *media_player); void send_media_player_info(media_player::MediaPlayer *media_player); void media_player_command(const MediaPlayerCommandRequest &msg) override; - - protected: - bool try_send_media_player_state_(media_player::MediaPlayer *media_player); - bool try_send_media_player_info_(media_player::MediaPlayer *media_player); - - public: #endif bool try_send_log_message(int level, const char *tag, const char *line); void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { if (!this->service_call_subscription_) return; - this->send_homeassistant_service_response(call); + this->send_message(call); } #ifdef USE_BLUETOOTH_PROXY void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; @@ -308,7 +149,7 @@ class APIConnection : public APIServerConnection { #ifdef USE_HOMEASSISTANT_TIME void send_time_request() { GetTimeRequest req; - this->send_get_time_request(req); + this->send_message(req); } #endif @@ -328,36 +169,17 @@ class APIConnection : public APIServerConnection { bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); void send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override; - - protected: - bool try_send_alarm_control_panel_state_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); - bool try_send_alarm_control_panel_info_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel); - - public: #endif #ifdef USE_EVENT - void send_event(event::Event *event, std::string event_type); + void send_event(event::Event *event, const std::string &event_type); void send_event_info(event::Event *event); - - protected: - bool try_send_event_(event::Event *event); - bool try_send_event_(event::Event *event, std::string event_type); - bool try_send_event_info_(event::Event *event); - - public: #endif #ifdef USE_UPDATE bool send_update_state(update::UpdateEntity *update); void send_update_info(update::UpdateEntity *update); void update_command(const UpdateCommandRequest &msg) override; - - protected: - bool try_send_update_state_(update::UpdateEntity *update); - bool try_send_update_info_(update::UpdateEntity *update); - - public: #endif void on_disconnect_response(const DisconnectResponse &value) override; @@ -407,102 +229,67 @@ class APIConnection : public APIServerConnection { void on_no_setup_connection() override; ProtoWriteBuffer create_buffer(uint32_t reserve_size) override { // FIXME: ensure no recursive writes can happen - this->proto_write_buffer_.clear(); + // Get header padding size - used for both reserve and insert uint8_t header_padding = this->helper_->frame_header_padding(); + + // Get shared buffer from parent server + std::vector &shared_buf = this->parent_->get_shared_buffer_ref(); + shared_buf.clear(); // Reserve space for header padding + message + footer // - Header padding: space for protocol headers (7 bytes for Noise, 6 for Plaintext) // - Footer: space for MAC (16 bytes for Noise, 0 for Plaintext) - this->proto_write_buffer_.reserve(reserve_size + header_padding + this->helper_->frame_footer_size()); + shared_buf.reserve(reserve_size + header_padding + this->helper_->frame_footer_size()); // Insert header padding bytes so message encoding starts at the correct position - this->proto_write_buffer_.insert(this->proto_write_buffer_.begin(), header_padding, 0); - return {&this->proto_write_buffer_}; + shared_buf.insert(shared_buf.begin(), header_padding, 0); + return {&shared_buf}; } + + // Prepare buffer for next message in batch + ProtoWriteBuffer prepare_message_buffer(uint16_t message_size, bool is_first_message) { + // Get reference to shared buffer (it maintains state between batch messages) + std::vector &shared_buf = this->parent_->get_shared_buffer_ref(); + size_t current_size = shared_buf.size(); + + if (is_first_message) { + // For first message, initialize buffer with header padding + uint8_t header_padding = this->helper_->frame_header_padding(); + shared_buf.clear(); + shared_buf.reserve(message_size + header_padding); + shared_buf.resize(header_padding); + // Fill header padding with zeros + std::fill(shared_buf.begin(), shared_buf.end(), 0); + } else { + // For subsequent messages, add footer space for previous message and header for this message + uint8_t footer_size = this->helper_->frame_footer_size(); + uint8_t header_padding = this->helper_->frame_header_padding(); + + // Reserve additional space for everything + shared_buf.reserve(current_size + footer_size + header_padding + message_size); + + // Single resize to add both footer and header padding + size_t new_size = current_size + footer_size + header_padding; + shared_buf.resize(new_size); + + // Fill the newly added bytes with zeros (footer + header padding) + std::fill(shared_buf.begin() + current_size, shared_buf.end(), 0); + } + + return {&shared_buf}; + } + bool try_to_clear_buffer(bool log_out_of_space); - bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) override; + bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override; std::string get_client_combined_info() const { return this->client_combined_info_; } + // Buffer allocator methods for batch processing + ProtoWriteBuffer allocate_single_message_buffer(uint16_t size); + ProtoWriteBuffer allocate_batch_message_buffer(uint16_t size); + protected: - friend APIServer; - - /** - * Generic send entity state method to reduce code duplication. - * Only attempts to build and send the message if the transmit buffer is available. - * - * This is the base version for entities that use their current state. - * - * @param entity The entity to send state for - * @param try_send_func The function that tries to send the state - * @return True on success or message deferred, false if subscription check failed - */ - bool send_state_(esphome::EntityBase *entity, send_message_t try_send_func) { - if (!this->state_subscription_) - return false; - if (this->try_to_clear_buffer(true) && (this->*try_send_func)(entity)) { - return true; - } - this->deferred_message_queue_.defer(entity, try_send_func); - return true; - } - - /** - * Send entity state method that handles explicit state values. - * Only attempts to build and send the message if the transmit buffer is available. - * - * This method accepts a state parameter to be used instead of the entity's current state. - * It attempts to send the state with the provided value first, and if that fails due to buffer constraints, - * it defers the entity for later processing using the entity-only function. - * - * @tparam EntityT The entity type - * @tparam StateT Type of the state parameter - * @tparam Args Additional argument types (if any) - * @param entity The entity to send state for - * @param try_send_entity_func The function that tries to send the state with entity pointer only - * @param try_send_state_func The function that tries to send the state with entity and state parameters - * @param state The state value to send - * @param args Additional arguments to pass to the try_send_state_func - * @return True on success or message deferred, false if subscription check failed - */ - template - bool send_state_with_value_(EntityT *entity, bool (APIConnection::*try_send_entity_func)(EntityT *), - bool (APIConnection::*try_send_state_func)(EntityT *, StateT, Args...), StateT state, - Args... args) { - if (!this->state_subscription_) - return false; - if (this->try_to_clear_buffer(true) && (this->*try_send_state_func)(entity, state, args...)) { - return true; - } - this->deferred_message_queue_.defer(entity, reinterpret_cast(try_send_entity_func)); - return true; - } - - /** - * Generic send entity info method to reduce code duplication. - * Only attempts to build and send the message if the transmit buffer is available. - * - * @param entity The entity to send info for - * @param try_send_func The function that tries to send the info - */ - void send_info_(esphome::EntityBase *entity, send_message_t try_send_func) { - if (this->try_to_clear_buffer(true) && (this->*try_send_func)(entity)) { - return; - } - this->deferred_message_queue_.defer(entity, try_send_func); - } - - /** - * Generic function for generating entity info response messages. - * This is used to reduce duplication in the try_send_*_info functions. - * - * @param entity The entity to generate info for - * @param response The response object - * @param send_response_func Function pointer to send the response - * @return True if the message was sent successfully - */ - template - bool try_send_entity_info_(esphome::EntityBase *entity, ResponseT &response, - bool (APIServerConnectionBase::*send_response_func)(const ResponseT &)) { + // Helper function to fill common entity fields + template static void fill_entity_info_base(esphome::EntityBase *entity, ResponseT &response) { // Set common fields that are shared by all entity types response.key = entity->get_object_id_hash(); response.object_id = entity->get_object_id(); @@ -514,12 +301,137 @@ class APIConnection : public APIServerConnection { response.icon = entity->get_icon(); response.disabled_by_default = entity->is_disabled_by_default(); response.entity_category = static_cast(entity->get_entity_category()); - - // Send the response using the provided send method - return (this->*send_response_func)(response); } - bool send_(const void *buf, size_t len, bool force); + // Non-template helper to encode any ProtoMessage + static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn, + uint32_t remaining_size, bool is_single); + +#ifdef USE_BINARY_SENSOR + static uint16_t try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_binary_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_COVER + static uint16_t try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_cover_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_FAN + static uint16_t try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); + static uint16_t try_send_fan_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_LIGHT + static uint16_t try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_light_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_SENSOR + static uint16_t try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_SWITCH + static uint16_t try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_switch_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_TEXT_SENSOR + static uint16_t try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_text_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_CLIMATE + static uint16_t try_send_climate_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_climate_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_NUMBER + static uint16_t try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_number_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_DATETIME_DATE + static uint16_t try_send_date_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); + static uint16_t try_send_date_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_DATETIME_TIME + static uint16_t try_send_time_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); + static uint16_t try_send_time_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_DATETIME_DATETIME + static uint16_t try_send_datetime_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_datetime_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_TEXT + static uint16_t try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); + static uint16_t try_send_text_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_SELECT + static uint16_t try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_select_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_BUTTON + static uint16_t try_send_button_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_LOCK + static uint16_t try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); + static uint16_t try_send_lock_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_VALVE + static uint16_t try_send_valve_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_valve_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_MEDIA_PLAYER + static uint16_t try_send_media_player_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_media_player_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_ALARM_CONTROL_PANEL + static uint16_t try_send_alarm_control_panel_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_EVENT + static uint16_t try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn, + uint32_t remaining_size, bool is_single); + static uint16_t try_send_event_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); +#endif +#ifdef USE_UPDATE + static uint16_t try_send_update_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + static uint16_t try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif +#ifdef USE_ESP32_CAMERA + static uint16_t try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); +#endif + + // Method for ListEntitiesDone batching + static uint16_t try_send_list_info_done(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + + // Method for DisconnectRequest batching + static uint16_t try_send_disconnect_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, + bool is_single); + + // Helper function to get estimated message size for buffer pre-allocation + static uint16_t get_estimated_message_size(uint16_t message_type); enum class ConnectionState { WAITING_FOR_HELLO, @@ -529,9 +441,6 @@ class APIConnection : public APIServerConnection { bool remove_{false}; - // Buffer used to encode proto messages - // Re-use to prevent allocations - std::vector proto_write_buffer_; std::unique_ptr helper_; std::string client_info_; @@ -552,10 +461,160 @@ class APIConnection : public APIServerConnection { bool service_call_subscription_{false}; bool next_close_ = false; APIServer *parent_; - DeferredMessageQueue deferred_message_queue_; InitialStateIterator initial_state_iterator_; ListEntitiesIterator list_entities_iterator_; int state_subs_at_ = -1; + + // Function pointer type for message encoding + using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); + + // Optimized MessageCreator class using union dispatch + class MessageCreator { + public: + // Constructor for function pointer (message_type = 0) + MessageCreator(MessageCreatorPtr ptr) : message_type_(0) { data_.ptr = ptr; } + + // Constructor for string state capture + MessageCreator(const std::string &value, uint16_t msg_type) : message_type_(msg_type) { + data_.string_ptr = new std::string(value); + } + + // Destructor + ~MessageCreator() { + // Clean up string data for string-based message types + if (uses_string_data_()) { + delete data_.string_ptr; + } + } + + // Copy constructor + MessageCreator(const MessageCreator &other) : message_type_(other.message_type_) { + if (message_type_ == 0) { + data_.ptr = other.data_.ptr; + } else if (uses_string_data_()) { + data_.string_ptr = new std::string(*other.data_.string_ptr); + } else { + data_ = other.data_; // For POD types + } + } + + // Move constructor + MessageCreator(MessageCreator &&other) noexcept : data_(other.data_), message_type_(other.message_type_) { + other.message_type_ = 0; // Reset other to function pointer type + other.data_.ptr = nullptr; + } + + // Assignment operators (needed for batch deduplication) + MessageCreator &operator=(const MessageCreator &other) { + if (this != &other) { + // Clean up current string data if needed + if (uses_string_data_()) { + delete data_.string_ptr; + } + // Copy new data + message_type_ = other.message_type_; + if (other.message_type_ == 0) { + data_.ptr = other.data_.ptr; + } else if (other.uses_string_data_()) { + data_.string_ptr = new std::string(*other.data_.string_ptr); + } else { + data_ = other.data_; + } + } + return *this; + } + + MessageCreator &operator=(MessageCreator &&other) noexcept { + if (this != &other) { + // Clean up current string data if needed + if (uses_string_data_()) { + delete data_.string_ptr; + } + // Move data + message_type_ = other.message_type_; + data_ = other.data_; + // Reset other to safe state + other.message_type_ = 0; + other.data_.ptr = nullptr; + } + return *this; + } + + // Call operator + uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single) const; + + private: + // Helper to check if this message type uses heap-allocated strings + bool uses_string_data_() const { return message_type_ == EventResponse::MESSAGE_TYPE; } + union CreatorData { + MessageCreatorPtr ptr; // 8 bytes + std::string *string_ptr; // 8 bytes + } data_; // 8 bytes + uint16_t message_type_; // 2 bytes (0 = function ptr, >0 = state capture) + }; + + // Generic batching mechanism for both state updates and entity info + struct DeferredBatch { + struct BatchItem { + EntityBase *entity; // Entity pointer + MessageCreator creator; // Function that creates the message when needed + uint16_t message_type; // Message type for overhead calculation + + // Constructor for creating BatchItem + BatchItem(EntityBase *entity, MessageCreator creator, uint16_t message_type) + : entity(entity), creator(std::move(creator)), message_type(message_type) {} + }; + + std::vector items; + uint32_t batch_start_time{0}; + bool batch_scheduled{false}; + + DeferredBatch() { + // Pre-allocate capacity for typical batch sizes to avoid reallocation + items.reserve(8); + } + + // Add item to the batch + void add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type); + void clear() { + items.clear(); + batch_scheduled = false; + batch_start_time = 0; + } + bool empty() const { return items.empty(); } + }; + + DeferredBatch deferred_batch_; + uint32_t get_batch_delay_ms_() const; + // Message will use 8 more bytes than the minimum size, and typical + // MTU is 1500. Sometimes users will see as low as 1460 MTU. + // If its IPv6 the header is 40 bytes, and if its IPv4 + // the header is 20 bytes. So we have 1460 - 40 = 1420 bytes + // available for the payload. But we also need to add the size of + // the protobuf overhead, which is 8 bytes. + // + // To be safe we pick 1390 bytes as the maximum size + // to send in one go. This is the maximum size of a single packet + // that can be sent over the network. + // This is to avoid fragmentation of the packet. + static constexpr size_t MAX_PACKET_SIZE = 1390; // MTU + + bool schedule_batch_(); + void process_batch_(); + + // State for batch buffer allocation + bool batch_first_message_{false}; + + // Helper function to schedule a deferred message with known message type + bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) { + this->deferred_batch_.add_item(entity, std::move(creator), message_type); + return this->schedule_batch_(); + } + + // Overload for function pointers (for info messages and current state reads) + bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) { + return schedule_message_(entity, MessageCreator(function_ptr), message_type); + } }; } // namespace api diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index 19263f2f2c..e0eb94836d 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -1,9 +1,9 @@ #include "api_frame_helper.h" #ifdef USE_API -#include "esphome/core/log.h" +#include "esphome/core/application.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" -#include "esphome/core/application.h" +#include "esphome/core/log.h" #include "proto.h" #include "api_pb2_size.h" #include @@ -605,9 +605,21 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) { return APIError::OK; } APIError APINoiseFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) { - int err; - APIError aerr; - aerr = state_action_(); + std::vector *raw_buffer = buffer.get_buffer(); + uint16_t payload_len = static_cast(raw_buffer->size() - frame_header_padding_); + + // Resize to include MAC space (required for Noise encryption) + raw_buffer->resize(raw_buffer->size() + frame_footer_size_); + + // Use write_protobuf_packets with a single packet + std::vector packets; + packets.emplace_back(type, 0, payload_len); + + return write_protobuf_packets(buffer, packets); +} + +APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector &packets) { + APIError aerr = state_action_(); if (aerr != APIError::OK) { return aerr; } @@ -616,56 +628,66 @@ APIError APINoiseFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuf return APIError::WOULD_BLOCK; } - std::vector *raw_buffer = buffer.get_buffer(); - // Message data starts after padding - uint16_t payload_len = raw_buffer->size() - frame_header_padding_; - uint16_t padding = 0; - uint16_t msg_len = 4 + payload_len + padding; - - // We need to resize to include MAC space, but we already reserved it in create_buffer - raw_buffer->resize(raw_buffer->size() + frame_footer_size_); - - // Write the noise header in the padded area - // Buffer layout: - // [0] - 0x01 indicator byte - // [1-2] - Size of encrypted payload (filled after encryption) - // [3-4] - Message type (encrypted) - // [5-6] - Payload length (encrypted) - // [7...] - Actual payload data (encrypted) - uint8_t *buf_start = raw_buffer->data(); - buf_start[0] = 0x01; // indicator - // buf_start[1], buf_start[2] to be set later after encryption - const uint8_t msg_offset = 3; - buf_start[msg_offset + 0] = (uint8_t) (type >> 8); // type high byte - buf_start[msg_offset + 1] = (uint8_t) type; // type low byte - buf_start[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len high byte - buf_start[msg_offset + 3] = (uint8_t) payload_len; // data_len low byte - // payload data is already in the buffer starting at position 7 - - NoiseBuffer mbuf; - noise_buffer_init(mbuf); - // The capacity parameter should be msg_len + frame_footer_size_ (MAC length) to allow space for encryption - noise_buffer_set_inout(mbuf, buf_start + msg_offset, msg_len, msg_len + frame_footer_size_); - err = noise_cipherstate_encrypt(send_cipher_, &mbuf); - if (err != 0) { - state_ = State::FAILED; - HELPER_LOG("noise_cipherstate_encrypt failed: %s", noise_err_to_str(err).c_str()); - return APIError::CIPHERSTATE_ENCRYPT_FAILED; + if (packets.empty()) { + return APIError::OK; } - uint16_t total_len = 3 + mbuf.size; - buf_start[1] = (uint8_t) (mbuf.size >> 8); - buf_start[2] = (uint8_t) mbuf.size; + std::vector *raw_buffer = buffer.get_buffer(); + this->reusable_iovs_.clear(); + this->reusable_iovs_.reserve(packets.size()); - struct iovec iov; - // Point iov_base to the beginning of the buffer (no unused padding in Noise) - // We send the entire frame: indicator + size + encrypted(type + data_len + payload + MAC) - iov.iov_base = buf_start; - iov.iov_len = total_len; + // We need to encrypt each packet in place + for (const auto &packet : packets) { + uint16_t type = packet.message_type; + uint16_t offset = packet.offset; + uint16_t payload_len = packet.payload_size; + uint16_t msg_len = 4 + payload_len; // type(2) + data_len(2) + payload - // write raw to not have two packets sent if NAGLE disabled - return this->write_raw_(&iov, 1); + // The buffer already has padding at offset + uint8_t *buf_start = raw_buffer->data() + offset; + + // Write noise header + buf_start[0] = 0x01; // indicator + // buf_start[1], buf_start[2] to be set after encryption + + // Write message header (to be encrypted) + const uint8_t msg_offset = 3; + buf_start[msg_offset + 0] = (uint8_t) (type >> 8); // type high byte + buf_start[msg_offset + 1] = (uint8_t) type; // type low byte + buf_start[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len high byte + buf_start[msg_offset + 3] = (uint8_t) payload_len; // data_len low byte + // payload data is already in the buffer starting at offset + 7 + + // Make sure we have space for MAC + // The buffer should already have been sized appropriately + + // Encrypt the message in place + NoiseBuffer mbuf; + noise_buffer_init(mbuf); + noise_buffer_set_inout(mbuf, buf_start + msg_offset, msg_len, msg_len + frame_footer_size_); + + int err = noise_cipherstate_encrypt(send_cipher_, &mbuf); + if (err != 0) { + state_ = State::FAILED; + HELPER_LOG("noise_cipherstate_encrypt failed: %s", noise_err_to_str(err).c_str()); + return APIError::CIPHERSTATE_ENCRYPT_FAILED; + } + + // Fill in the encrypted size + buf_start[1] = (uint8_t) (mbuf.size >> 8); + buf_start[2] = (uint8_t) mbuf.size; + + // Add iovec for this encrypted packet + struct iovec iov; + iov.iov_base = buf_start; + iov.iov_len = 3 + mbuf.size; // indicator + size + encrypted data + this->reusable_iovs_.push_back(iov); + } + + // Send all encrypted packets in one writev call + return this->write_raw_(this->reusable_iovs_.data(), this->reusable_iovs_.size()); } + APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) { uint8_t header[3]; header[0] = 0x01; // indicator @@ -780,7 +802,7 @@ extern "C" { // declare how noise generates random bytes (here with a good HWRNG based on the RF system) void noise_rand_bytes(void *output, size_t len) { if (!esphome::random_bytes(reinterpret_cast(output), len)) { - ESP_LOGE(TAG, "Failed to acquire random bytes, rebooting!"); + ESP_LOGE(TAG, "Acquiring random bytes failed; rebooting"); arch_restart(); } } @@ -1004,65 +1026,86 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) { return APIError::OK; } APIError APIPlaintextFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) { + std::vector *raw_buffer = buffer.get_buffer(); + uint16_t payload_len = static_cast(raw_buffer->size() - frame_header_padding_); + + // Use write_protobuf_packets with a single packet + std::vector packets; + packets.emplace_back(type, 0, payload_len); + + return write_protobuf_packets(buffer, packets); +} + +APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, + const std::vector &packets) { if (state_ != State::DATA) { return APIError::BAD_STATE; } - std::vector *raw_buffer = buffer.get_buffer(); - // Message data starts after padding (frame_header_padding_ = 6) - uint16_t payload_len = static_cast(raw_buffer->size() - frame_header_padding_); - - // Calculate varint sizes for header components - uint8_t size_varint_len = api::ProtoSize::varint(static_cast(payload_len)); - uint8_t type_varint_len = api::ProtoSize::varint(static_cast(type)); - uint8_t total_header_len = 1 + size_varint_len + type_varint_len; - - if (total_header_len > frame_header_padding_) { - // Header is too large to fit in the padding - return APIError::BAD_ARG; + if (packets.empty()) { + return APIError::OK; } - // Calculate where to start writing the header - // The header starts at the latest possible position to minimize unused padding - // - // Example 1 (small values): total_header_len = 3, header_offset = 6 - 3 = 3 - // [0-2] - Unused padding - // [3] - 0x00 indicator byte - // [4] - Payload size varint (1 byte, for sizes 0-127) - // [5] - Message type varint (1 byte, for types 0-127) - // [6...] - Actual payload data - // - // Example 2 (medium values): total_header_len = 4, header_offset = 6 - 4 = 2 - // [0-1] - Unused padding - // [2] - 0x00 indicator byte - // [3-4] - Payload size varint (2 bytes, for sizes 128-16383) - // [5] - Message type varint (1 byte, for types 0-127) - // [6...] - Actual payload data - // - // Example 3 (large values): total_header_len = 6, header_offset = 6 - 6 = 0 - // [0] - 0x00 indicator byte - // [1-3] - Payload size varint (3 bytes, for sizes 16384-2097151) - // [4-5] - Message type varint (2 bytes, for types 128-32767) - // [6...] - Actual payload data - uint8_t *buf_start = raw_buffer->data(); - uint8_t header_offset = frame_header_padding_ - total_header_len; + std::vector *raw_buffer = buffer.get_buffer(); + this->reusable_iovs_.clear(); + this->reusable_iovs_.reserve(packets.size()); - // Write the plaintext header - buf_start[header_offset] = 0x00; // indicator + for (const auto &packet : packets) { + uint16_t type = packet.message_type; + uint16_t offset = packet.offset; + uint16_t payload_len = packet.payload_size; - // Encode size varint directly into buffer - ProtoVarInt(payload_len).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len); + // Calculate varint sizes for header layout + uint8_t size_varint_len = api::ProtoSize::varint(static_cast(payload_len)); + uint8_t type_varint_len = api::ProtoSize::varint(static_cast(type)); + uint8_t total_header_len = 1 + size_varint_len + type_varint_len; - // Encode type varint directly into buffer - ProtoVarInt(type).encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len); + // Calculate where to start writing the header + // The header starts at the latest possible position to minimize unused padding + // + // Example 1 (small values): total_header_len = 3, header_offset = 6 - 3 = 3 + // [0-2] - Unused padding + // [3] - 0x00 indicator byte + // [4] - Payload size varint (1 byte, for sizes 0-127) + // [5] - Message type varint (1 byte, for types 0-127) + // [6...] - Actual payload data + // + // Example 2 (medium values): total_header_len = 4, header_offset = 6 - 4 = 2 + // [0-1] - Unused padding + // [2] - 0x00 indicator byte + // [3-4] - Payload size varint (2 bytes, for sizes 128-16383) + // [5] - Message type varint (1 byte, for types 0-127) + // [6...] - Actual payload data + // + // Example 3 (large values): total_header_len = 6, header_offset = 6 - 6 = 0 + // [0] - 0x00 indicator byte + // [1-3] - Payload size varint (3 bytes, for sizes 16384-2097151) + // [4-5] - Message type varint (2 bytes, for types 128-32767) + // [6...] - Actual payload data + // + // The message starts at offset + frame_header_padding_ + // So we write the header starting at offset + frame_header_padding_ - total_header_len + uint8_t *buf_start = raw_buffer->data() + offset; + uint32_t header_offset = frame_header_padding_ - total_header_len; - struct iovec iov; - // Point iov_base to the beginning of our header (skip unused padding) - // This ensures we only send the actual header and payload, not the empty padding bytes - iov.iov_base = buf_start + header_offset; - iov.iov_len = total_header_len + payload_len; + // Write the plaintext header + buf_start[header_offset] = 0x00; // indicator - return write_raw_(&iov, 1); + // Encode size varint directly into buffer + ProtoVarInt(payload_len).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len); + + // Encode type varint directly into buffer + ProtoVarInt(type).encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len); + + // Add iovec for this packet (header + payload) + struct iovec iov; + iov.iov_base = buf_start + header_offset; + iov.iov_len = total_header_len + payload_len; + this->reusable_iovs_.push_back(iov); + } + + // Send all packets in one writev call + return write_raw_(this->reusable_iovs_.data(), this->reusable_iovs_.size()); } #endif // USE_API_PLAINTEXT diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 0799ae0f85..dc71a7ca17 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -27,6 +27,17 @@ struct ReadPacketBuffer { uint16_t data_len; }; +// Packed packet info structure to minimize memory usage +struct PacketInfo { + uint16_t message_type; // 2 bytes + uint16_t offset; // 2 bytes (sufficient for packet size ~1460 bytes) + uint16_t payload_size; // 2 bytes (up to 65535 bytes) + uint16_t padding; // 2 byte (for alignment) + + PacketInfo(uint16_t type, uint16_t off, uint16_t size) + : message_type(type), offset(off), payload_size(size), padding(0) {} +}; + enum class APIError : int { OK = 0, WOULD_BLOCK = 1001, @@ -87,6 +98,10 @@ class APIFrameHelper { // Give this helper a name for logging void set_log_info(std::string info) { info_ = std::move(info); } virtual APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) = 0; + // Write multiple protobuf packets in a single operation + // packets contains (message_type, offset, length) for each message in the buffer + // The buffer contains all messages with appropriate padding before each + virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector &packets) = 0; // Get the frame header padding required by this protocol virtual uint8_t frame_header_padding() = 0; // Get the frame footer size required by this protocol @@ -157,6 +172,9 @@ class APIFrameHelper { uint8_t frame_header_padding_{0}; uint8_t frame_footer_size_{0}; + // Reusable IOV array for write_protobuf_packets to avoid repeated allocations + std::vector reusable_iovs_; + // Receive buffer for reading frame data std::vector rx_buf_; uint16_t rx_buf_len_ = 0; @@ -182,6 +200,7 @@ class APINoiseFrameHelper : public APIFrameHelper { APIError loop() override; APIError read_packet(ReadPacketBuffer *buffer) override; APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override; + APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector &packets) override; // Get the frame header padding required by this protocol uint8_t frame_header_padding() override { return frame_header_padding_; } // Get the frame footer size required by this protocol @@ -226,6 +245,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper { APIError loop() override; APIError read_packet(ReadPacketBuffer *buffer) override; APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override; + APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector &packets) override; uint8_t frame_header_padding() override { return frame_header_padding_; } // Get the frame footer size required by this protocol uint8_t frame_footer_size() override { return frame_footer_size_; } diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 1869fc5ba1..8b3f7a7b2a 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -255,6 +255,11 @@ enum UpdateCommand : uint32_t { class HelloRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 1; + static constexpr uint16_t ESTIMATED_SIZE = 17; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "hello_request"; } +#endif std::string client_info{}; uint32_t api_version_major{0}; uint32_t api_version_minor{0}; @@ -270,6 +275,11 @@ class HelloRequest : public ProtoMessage { }; class HelloResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 2; + static constexpr uint16_t ESTIMATED_SIZE = 26; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "hello_response"; } +#endif uint32_t api_version_major{0}; uint32_t api_version_minor{0}; std::string server_info{}; @@ -286,6 +296,11 @@ class HelloResponse : public ProtoMessage { }; class ConnectRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 3; + static constexpr uint16_t ESTIMATED_SIZE = 9; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "connect_request"; } +#endif std::string password{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -298,6 +313,11 @@ class ConnectRequest : public ProtoMessage { }; class ConnectResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 4; + static constexpr uint16_t ESTIMATED_SIZE = 2; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "connect_response"; } +#endif bool invalid_password{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -310,6 +330,11 @@ class ConnectResponse : public ProtoMessage { }; class DisconnectRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 5; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "disconnect_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -320,6 +345,11 @@ class DisconnectRequest : public ProtoMessage { }; class DisconnectResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 6; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "disconnect_response"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -330,6 +360,11 @@ class DisconnectResponse : public ProtoMessage { }; class PingRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 7; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "ping_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -340,6 +375,11 @@ class PingRequest : public ProtoMessage { }; class PingResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 8; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "ping_response"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -350,6 +390,11 @@ class PingResponse : public ProtoMessage { }; class DeviceInfoRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 9; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "device_info_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -360,6 +405,11 @@ class DeviceInfoRequest : public ProtoMessage { }; class DeviceInfoResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 10; + static constexpr uint16_t ESTIMATED_SIZE = 129; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "device_info_response"; } +#endif bool uses_password{false}; std::string name{}; std::string mac_address{}; @@ -391,6 +441,11 @@ class DeviceInfoResponse : public ProtoMessage { }; class ListEntitiesRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 11; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -401,6 +456,11 @@ class ListEntitiesRequest : public ProtoMessage { }; class ListEntitiesDoneResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 19; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_done_response"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -411,6 +471,11 @@ class ListEntitiesDoneResponse : public ProtoMessage { }; class SubscribeStatesRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 20; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_states_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -421,6 +486,11 @@ class SubscribeStatesRequest : public ProtoMessage { }; class ListEntitiesBinarySensorResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 12; + static constexpr uint16_t ESTIMATED_SIZE = 56; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_binary_sensor_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -443,6 +513,11 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage { }; class BinarySensorStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 21; + static constexpr uint16_t ESTIMATED_SIZE = 9; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "binary_sensor_state_response"; } +#endif uint32_t key{0}; bool state{false}; bool missing_state{false}; @@ -458,6 +533,11 @@ class BinarySensorStateResponse : public ProtoMessage { }; class ListEntitiesCoverResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 13; + static constexpr uint16_t ESTIMATED_SIZE = 62; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_cover_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -483,6 +563,11 @@ class ListEntitiesCoverResponse : public ProtoMessage { }; class CoverStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 22; + static constexpr uint16_t ESTIMATED_SIZE = 19; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "cover_state_response"; } +#endif uint32_t key{0}; enums::LegacyCoverState legacy_state{}; float position{0.0f}; @@ -500,6 +585,11 @@ class CoverStateResponse : public ProtoMessage { }; class CoverCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 30; + static constexpr uint16_t ESTIMATED_SIZE = 25; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "cover_command_request"; } +#endif uint32_t key{0}; bool has_legacy_command{false}; enums::LegacyCoverCommand legacy_command{}; @@ -520,6 +610,11 @@ class CoverCommandRequest : public ProtoMessage { }; class ListEntitiesFanResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 14; + static constexpr uint16_t ESTIMATED_SIZE = 73; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_fan_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -545,6 +640,11 @@ class ListEntitiesFanResponse : public ProtoMessage { }; class FanStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 23; + static constexpr uint16_t ESTIMATED_SIZE = 26; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "fan_state_response"; } +#endif uint32_t key{0}; bool state{false}; bool oscillating{false}; @@ -565,6 +665,11 @@ class FanStateResponse : public ProtoMessage { }; class FanCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 31; + static constexpr uint16_t ESTIMATED_SIZE = 38; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "fan_command_request"; } +#endif uint32_t key{0}; bool has_state{false}; bool state{false}; @@ -591,6 +696,11 @@ class FanCommandRequest : public ProtoMessage { }; class ListEntitiesLightResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 15; + static constexpr uint16_t ESTIMATED_SIZE = 85; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_light_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -619,6 +729,11 @@ class ListEntitiesLightResponse : public ProtoMessage { }; class LightStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 24; + static constexpr uint16_t ESTIMATED_SIZE = 63; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "light_state_response"; } +#endif uint32_t key{0}; bool state{false}; float brightness{0.0f}; @@ -645,6 +760,11 @@ class LightStateResponse : public ProtoMessage { }; class LightCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 32; + static constexpr uint16_t ESTIMATED_SIZE = 107; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "light_command_request"; } +#endif uint32_t key{0}; bool has_state{false}; bool state{false}; @@ -685,6 +805,11 @@ class LightCommandRequest : public ProtoMessage { }; class ListEntitiesSensorResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 16; + static constexpr uint16_t ESTIMATED_SIZE = 73; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_sensor_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -711,6 +836,11 @@ class ListEntitiesSensorResponse : public ProtoMessage { }; class SensorStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 25; + static constexpr uint16_t ESTIMATED_SIZE = 12; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "sensor_state_response"; } +#endif uint32_t key{0}; float state{0.0f}; bool missing_state{false}; @@ -726,6 +856,11 @@ class SensorStateResponse : public ProtoMessage { }; class ListEntitiesSwitchResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 17; + static constexpr uint16_t ESTIMATED_SIZE = 56; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_switch_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -748,6 +883,11 @@ class ListEntitiesSwitchResponse : public ProtoMessage { }; class SwitchStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 26; + static constexpr uint16_t ESTIMATED_SIZE = 7; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "switch_state_response"; } +#endif uint32_t key{0}; bool state{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -762,6 +902,11 @@ class SwitchStateResponse : public ProtoMessage { }; class SwitchCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 33; + static constexpr uint16_t ESTIMATED_SIZE = 7; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "switch_command_request"; } +#endif uint32_t key{0}; bool state{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -776,6 +921,11 @@ class SwitchCommandRequest : public ProtoMessage { }; class ListEntitiesTextSensorResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 18; + static constexpr uint16_t ESTIMATED_SIZE = 54; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_text_sensor_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -797,6 +947,11 @@ class ListEntitiesTextSensorResponse : public ProtoMessage { }; class TextSensorStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 27; + static constexpr uint16_t ESTIMATED_SIZE = 16; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "text_sensor_state_response"; } +#endif uint32_t key{0}; std::string state{}; bool missing_state{false}; @@ -813,6 +968,11 @@ class TextSensorStateResponse : public ProtoMessage { }; class SubscribeLogsRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 28; + static constexpr uint16_t ESTIMATED_SIZE = 4; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_logs_request"; } +#endif enums::LogLevel level{}; bool dump_config{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -826,6 +986,11 @@ class SubscribeLogsRequest : public ProtoMessage { }; class SubscribeLogsResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 29; + static constexpr uint16_t ESTIMATED_SIZE = 13; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_logs_response"; } +#endif enums::LogLevel level{}; std::string message{}; bool send_failed{false}; @@ -841,6 +1006,11 @@ class SubscribeLogsResponse : public ProtoMessage { }; class NoiseEncryptionSetKeyRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 124; + static constexpr uint16_t ESTIMATED_SIZE = 9; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "noise_encryption_set_key_request"; } +#endif std::string key{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -853,6 +1023,11 @@ class NoiseEncryptionSetKeyRequest : public ProtoMessage { }; class NoiseEncryptionSetKeyResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 125; + static constexpr uint16_t ESTIMATED_SIZE = 2; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "noise_encryption_set_key_response"; } +#endif bool success{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -865,6 +1040,11 @@ class NoiseEncryptionSetKeyResponse : public ProtoMessage { }; class SubscribeHomeassistantServicesRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 34; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_homeassistant_services_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -888,6 +1068,11 @@ class HomeassistantServiceMap : public ProtoMessage { }; class HomeassistantServiceResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 35; + static constexpr uint16_t ESTIMATED_SIZE = 113; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "homeassistant_service_response"; } +#endif std::string service{}; std::vector data{}; std::vector data_template{}; @@ -905,6 +1090,11 @@ class HomeassistantServiceResponse : public ProtoMessage { }; class SubscribeHomeAssistantStatesRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 38; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_home_assistant_states_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -915,6 +1105,11 @@ class SubscribeHomeAssistantStatesRequest : public ProtoMessage { }; class SubscribeHomeAssistantStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 39; + static constexpr uint16_t ESTIMATED_SIZE = 20; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_home_assistant_state_response"; } +#endif std::string entity_id{}; std::string attribute{}; bool once{false}; @@ -930,6 +1125,11 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage { }; class HomeAssistantStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 40; + static constexpr uint16_t ESTIMATED_SIZE = 27; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "home_assistant_state_response"; } +#endif std::string entity_id{}; std::string state{}; std::string attribute{}; @@ -944,6 +1144,11 @@ class HomeAssistantStateResponse : public ProtoMessage { }; class GetTimeRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 36; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "get_time_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -954,6 +1159,11 @@ class GetTimeRequest : public ProtoMessage { }; class GetTimeResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 37; + static constexpr uint16_t ESTIMATED_SIZE = 5; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "get_time_response"; } +#endif uint32_t epoch_seconds{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -980,6 +1190,11 @@ class ListEntitiesServicesArgument : public ProtoMessage { }; class ListEntitiesServicesResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 41; + static constexpr uint16_t ESTIMATED_SIZE = 48; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_services_response"; } +#endif std::string name{}; uint32_t key{0}; std::vector args{}; @@ -1017,6 +1232,11 @@ class ExecuteServiceArgument : public ProtoMessage { }; class ExecuteServiceRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 42; + static constexpr uint16_t ESTIMATED_SIZE = 39; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "execute_service_request"; } +#endif uint32_t key{0}; std::vector args{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1031,6 +1251,11 @@ class ExecuteServiceRequest : public ProtoMessage { }; class ListEntitiesCameraResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 43; + static constexpr uint16_t ESTIMATED_SIZE = 45; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_camera_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1051,6 +1276,11 @@ class ListEntitiesCameraResponse : public ProtoMessage { }; class CameraImageResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 44; + static constexpr uint16_t ESTIMATED_SIZE = 16; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "camera_image_response"; } +#endif uint32_t key{0}; std::string data{}; bool done{false}; @@ -1067,6 +1297,11 @@ class CameraImageResponse : public ProtoMessage { }; class CameraImageRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 45; + static constexpr uint16_t ESTIMATED_SIZE = 4; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "camera_image_request"; } +#endif bool single{false}; bool stream{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -1080,6 +1315,11 @@ class CameraImageRequest : public ProtoMessage { }; class ListEntitiesClimateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 46; + static constexpr uint16_t ESTIMATED_SIZE = 151; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_climate_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1118,6 +1358,11 @@ class ListEntitiesClimateResponse : public ProtoMessage { }; class ClimateStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 47; + static constexpr uint16_t ESTIMATED_SIZE = 65; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "climate_state_response"; } +#endif uint32_t key{0}; enums::ClimateMode mode{}; float current_temperature{0.0f}; @@ -1146,6 +1391,11 @@ class ClimateStateResponse : public ProtoMessage { }; class ClimateCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 48; + static constexpr uint16_t ESTIMATED_SIZE = 83; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "climate_command_request"; } +#endif uint32_t key{0}; bool has_mode{false}; enums::ClimateMode mode{}; @@ -1182,6 +1432,11 @@ class ClimateCommandRequest : public ProtoMessage { }; class ListEntitiesNumberResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 49; + static constexpr uint16_t ESTIMATED_SIZE = 80; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_number_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1208,6 +1463,11 @@ class ListEntitiesNumberResponse : public ProtoMessage { }; class NumberStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 50; + static constexpr uint16_t ESTIMATED_SIZE = 12; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "number_state_response"; } +#endif uint32_t key{0}; float state{0.0f}; bool missing_state{false}; @@ -1223,6 +1483,11 @@ class NumberStateResponse : public ProtoMessage { }; class NumberCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 51; + static constexpr uint16_t ESTIMATED_SIZE = 10; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "number_command_request"; } +#endif uint32_t key{0}; float state{0.0f}; void encode(ProtoWriteBuffer buffer) const override; @@ -1236,6 +1501,11 @@ class NumberCommandRequest : public ProtoMessage { }; class ListEntitiesSelectResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 52; + static constexpr uint16_t ESTIMATED_SIZE = 63; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_select_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1257,6 +1527,11 @@ class ListEntitiesSelectResponse : public ProtoMessage { }; class SelectStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 53; + static constexpr uint16_t ESTIMATED_SIZE = 16; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "select_state_response"; } +#endif uint32_t key{0}; std::string state{}; bool missing_state{false}; @@ -1273,6 +1548,11 @@ class SelectStateResponse : public ProtoMessage { }; class SelectCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 54; + static constexpr uint16_t ESTIMATED_SIZE = 14; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "select_command_request"; } +#endif uint32_t key{0}; std::string state{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1287,6 +1567,11 @@ class SelectCommandRequest : public ProtoMessage { }; class ListEntitiesSirenResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 55; + static constexpr uint16_t ESTIMATED_SIZE = 67; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_siren_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1310,6 +1595,11 @@ class ListEntitiesSirenResponse : public ProtoMessage { }; class SirenStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 56; + static constexpr uint16_t ESTIMATED_SIZE = 7; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "siren_state_response"; } +#endif uint32_t key{0}; bool state{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -1324,6 +1614,11 @@ class SirenStateResponse : public ProtoMessage { }; class SirenCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 57; + static constexpr uint16_t ESTIMATED_SIZE = 33; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "siren_command_request"; } +#endif uint32_t key{0}; bool has_state{false}; bool state{false}; @@ -1346,6 +1641,11 @@ class SirenCommandRequest : public ProtoMessage { }; class ListEntitiesLockResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 58; + static constexpr uint16_t ESTIMATED_SIZE = 60; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_lock_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1370,6 +1670,11 @@ class ListEntitiesLockResponse : public ProtoMessage { }; class LockStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 59; + static constexpr uint16_t ESTIMATED_SIZE = 7; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "lock_state_response"; } +#endif uint32_t key{0}; enums::LockState state{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1384,6 +1689,11 @@ class LockStateResponse : public ProtoMessage { }; class LockCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 60; + static constexpr uint16_t ESTIMATED_SIZE = 18; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "lock_command_request"; } +#endif uint32_t key{0}; enums::LockCommand command{}; bool has_code{false}; @@ -1401,6 +1711,11 @@ class LockCommandRequest : public ProtoMessage { }; class ListEntitiesButtonResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 61; + static constexpr uint16_t ESTIMATED_SIZE = 54; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_button_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1422,6 +1737,11 @@ class ListEntitiesButtonResponse : public ProtoMessage { }; class ButtonCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 62; + static constexpr uint16_t ESTIMATED_SIZE = 5; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "button_command_request"; } +#endif uint32_t key{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1451,6 +1771,11 @@ class MediaPlayerSupportedFormat : public ProtoMessage { }; class ListEntitiesMediaPlayerResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 63; + static constexpr uint16_t ESTIMATED_SIZE = 81; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_media_player_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -1473,6 +1798,11 @@ class ListEntitiesMediaPlayerResponse : public ProtoMessage { }; class MediaPlayerStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 64; + static constexpr uint16_t ESTIMATED_SIZE = 14; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "media_player_state_response"; } +#endif uint32_t key{0}; enums::MediaPlayerState state{}; float volume{0.0f}; @@ -1489,6 +1819,11 @@ class MediaPlayerStateResponse : public ProtoMessage { }; class MediaPlayerCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 65; + static constexpr uint16_t ESTIMATED_SIZE = 31; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "media_player_command_request"; } +#endif uint32_t key{0}; bool has_command{false}; enums::MediaPlayerCommand command{}; @@ -1511,6 +1846,11 @@ class MediaPlayerCommandRequest : public ProtoMessage { }; class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 66; + static constexpr uint16_t ESTIMATED_SIZE = 4; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_bluetooth_le_advertisements_request"; } +#endif uint32_t flags{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1538,6 +1878,11 @@ class BluetoothServiceData : public ProtoMessage { }; class BluetoothLEAdvertisementResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 67; + static constexpr uint16_t ESTIMATED_SIZE = 107; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_le_advertisement_response"; } +#endif uint64_t address{0}; std::string name{}; int32_t rssi{0}; @@ -1573,6 +1918,11 @@ class BluetoothLERawAdvertisement : public ProtoMessage { }; class BluetoothLERawAdvertisementsResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 93; + static constexpr uint16_t ESTIMATED_SIZE = 34; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_le_raw_advertisements_response"; } +#endif std::vector advertisements{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1585,6 +1935,11 @@ class BluetoothLERawAdvertisementsResponse : public ProtoMessage { }; class BluetoothDeviceRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 68; + static constexpr uint16_t ESTIMATED_SIZE = 12; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_device_request"; } +#endif uint64_t address{0}; enums::BluetoothDeviceRequestType request_type{}; bool has_address_type{false}; @@ -1600,6 +1955,11 @@ class BluetoothDeviceRequest : public ProtoMessage { }; class BluetoothDeviceConnectionResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 69; + static constexpr uint16_t ESTIMATED_SIZE = 14; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_device_connection_response"; } +#endif uint64_t address{0}; bool connected{false}; uint32_t mtu{0}; @@ -1615,6 +1975,11 @@ class BluetoothDeviceConnectionResponse : public ProtoMessage { }; class BluetoothGATTGetServicesRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 70; + static constexpr uint16_t ESTIMATED_SIZE = 4; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_get_services_request"; } +#endif uint64_t address{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1671,6 +2036,11 @@ class BluetoothGATTService : public ProtoMessage { }; class BluetoothGATTGetServicesResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 71; + static constexpr uint16_t ESTIMATED_SIZE = 38; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_get_services_response"; } +#endif uint64_t address{0}; std::vector services{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1685,6 +2055,11 @@ class BluetoothGATTGetServicesResponse : public ProtoMessage { }; class BluetoothGATTGetServicesDoneResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 72; + static constexpr uint16_t ESTIMATED_SIZE = 4; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_get_services_done_response"; } +#endif uint64_t address{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1697,6 +2072,11 @@ class BluetoothGATTGetServicesDoneResponse : public ProtoMessage { }; class BluetoothGATTReadRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 73; + static constexpr uint16_t ESTIMATED_SIZE = 8; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_read_request"; } +#endif uint64_t address{0}; uint32_t handle{0}; void encode(ProtoWriteBuffer buffer) const override; @@ -1710,6 +2090,11 @@ class BluetoothGATTReadRequest : public ProtoMessage { }; class BluetoothGATTReadResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 74; + static constexpr uint16_t ESTIMATED_SIZE = 17; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_read_response"; } +#endif uint64_t address{0}; uint32_t handle{0}; std::string data{}; @@ -1725,6 +2110,11 @@ class BluetoothGATTReadResponse : public ProtoMessage { }; class BluetoothGATTWriteRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 75; + static constexpr uint16_t ESTIMATED_SIZE = 19; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_write_request"; } +#endif uint64_t address{0}; uint32_t handle{0}; bool response{false}; @@ -1741,6 +2131,11 @@ class BluetoothGATTWriteRequest : public ProtoMessage { }; class BluetoothGATTReadDescriptorRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 76; + static constexpr uint16_t ESTIMATED_SIZE = 8; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_read_descriptor_request"; } +#endif uint64_t address{0}; uint32_t handle{0}; void encode(ProtoWriteBuffer buffer) const override; @@ -1754,6 +2149,11 @@ class BluetoothGATTReadDescriptorRequest : public ProtoMessage { }; class BluetoothGATTWriteDescriptorRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 77; + static constexpr uint16_t ESTIMATED_SIZE = 17; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_write_descriptor_request"; } +#endif uint64_t address{0}; uint32_t handle{0}; std::string data{}; @@ -1769,6 +2169,11 @@ class BluetoothGATTWriteDescriptorRequest : public ProtoMessage { }; class BluetoothGATTNotifyRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 78; + static constexpr uint16_t ESTIMATED_SIZE = 10; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_notify_request"; } +#endif uint64_t address{0}; uint32_t handle{0}; bool enable{false}; @@ -1783,6 +2188,11 @@ class BluetoothGATTNotifyRequest : public ProtoMessage { }; class BluetoothGATTNotifyDataResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 79; + static constexpr uint16_t ESTIMATED_SIZE = 17; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_notify_data_response"; } +#endif uint64_t address{0}; uint32_t handle{0}; std::string data{}; @@ -1798,6 +2208,11 @@ class BluetoothGATTNotifyDataResponse : public ProtoMessage { }; class SubscribeBluetoothConnectionsFreeRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 80; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_bluetooth_connections_free_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1808,6 +2223,11 @@ class SubscribeBluetoothConnectionsFreeRequest : public ProtoMessage { }; class BluetoothConnectionsFreeResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 81; + static constexpr uint16_t ESTIMATED_SIZE = 16; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_connections_free_response"; } +#endif uint32_t free{0}; uint32_t limit{0}; std::vector allocated{}; @@ -1822,6 +2242,11 @@ class BluetoothConnectionsFreeResponse : public ProtoMessage { }; class BluetoothGATTErrorResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 82; + static constexpr uint16_t ESTIMATED_SIZE = 12; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_error_response"; } +#endif uint64_t address{0}; uint32_t handle{0}; int32_t error{0}; @@ -1836,6 +2261,11 @@ class BluetoothGATTErrorResponse : public ProtoMessage { }; class BluetoothGATTWriteResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 83; + static constexpr uint16_t ESTIMATED_SIZE = 8; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_write_response"; } +#endif uint64_t address{0}; uint32_t handle{0}; void encode(ProtoWriteBuffer buffer) const override; @@ -1849,6 +2279,11 @@ class BluetoothGATTWriteResponse : public ProtoMessage { }; class BluetoothGATTNotifyResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 84; + static constexpr uint16_t ESTIMATED_SIZE = 8; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_gatt_notify_response"; } +#endif uint64_t address{0}; uint32_t handle{0}; void encode(ProtoWriteBuffer buffer) const override; @@ -1862,6 +2297,11 @@ class BluetoothGATTNotifyResponse : public ProtoMessage { }; class BluetoothDevicePairingResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 85; + static constexpr uint16_t ESTIMATED_SIZE = 10; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_device_pairing_response"; } +#endif uint64_t address{0}; bool paired{false}; int32_t error{0}; @@ -1876,6 +2316,11 @@ class BluetoothDevicePairingResponse : public ProtoMessage { }; class BluetoothDeviceUnpairingResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 86; + static constexpr uint16_t ESTIMATED_SIZE = 10; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_device_unpairing_response"; } +#endif uint64_t address{0}; bool success{false}; int32_t error{0}; @@ -1890,6 +2335,11 @@ class BluetoothDeviceUnpairingResponse : public ProtoMessage { }; class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 87; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "unsubscribe_bluetooth_le_advertisements_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1900,6 +2350,11 @@ class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { }; class BluetoothDeviceClearCacheResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 88; + static constexpr uint16_t ESTIMATED_SIZE = 10; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_device_clear_cache_response"; } +#endif uint64_t address{0}; bool success{false}; int32_t error{0}; @@ -1914,6 +2369,11 @@ class BluetoothDeviceClearCacheResponse : public ProtoMessage { }; class BluetoothScannerStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 126; + static constexpr uint16_t ESTIMATED_SIZE = 4; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_scanner_state_response"; } +#endif enums::BluetoothScannerState state{}; enums::BluetoothScannerMode mode{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1927,6 +2387,11 @@ class BluetoothScannerStateResponse : public ProtoMessage { }; class BluetoothScannerSetModeRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 127; + static constexpr uint16_t ESTIMATED_SIZE = 2; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "bluetooth_scanner_set_mode_request"; } +#endif enums::BluetoothScannerMode mode{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1939,6 +2404,11 @@ class BluetoothScannerSetModeRequest : public ProtoMessage { }; class SubscribeVoiceAssistantRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 89; + static constexpr uint16_t ESTIMATED_SIZE = 6; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "subscribe_voice_assistant_request"; } +#endif bool subscribe{false}; uint32_t flags{0}; void encode(ProtoWriteBuffer buffer) const override; @@ -1967,6 +2437,11 @@ class VoiceAssistantAudioSettings : public ProtoMessage { }; class VoiceAssistantRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 90; + static constexpr uint16_t ESTIMATED_SIZE = 41; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_request"; } +#endif bool start{false}; std::string conversation_id{}; uint32_t flags{0}; @@ -1984,6 +2459,11 @@ class VoiceAssistantRequest : public ProtoMessage { }; class VoiceAssistantResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 91; + static constexpr uint16_t ESTIMATED_SIZE = 6; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_response"; } +#endif uint32_t port{0}; bool error{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -2010,6 +2490,11 @@ class VoiceAssistantEventData : public ProtoMessage { }; class VoiceAssistantEventResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 92; + static constexpr uint16_t ESTIMATED_SIZE = 36; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_event_response"; } +#endif enums::VoiceAssistantEvent event_type{}; std::vector data{}; void encode(ProtoWriteBuffer buffer) const override; @@ -2024,6 +2509,11 @@ class VoiceAssistantEventResponse : public ProtoMessage { }; class VoiceAssistantAudio : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 106; + static constexpr uint16_t ESTIMATED_SIZE = 11; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_audio"; } +#endif std::string data{}; bool end{false}; void encode(ProtoWriteBuffer buffer) const override; @@ -2038,6 +2528,11 @@ class VoiceAssistantAudio : public ProtoMessage { }; class VoiceAssistantTimerEventResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 115; + static constexpr uint16_t ESTIMATED_SIZE = 30; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_timer_event_response"; } +#endif enums::VoiceAssistantTimerEvent event_type{}; std::string timer_id{}; std::string name{}; @@ -2056,6 +2551,11 @@ class VoiceAssistantTimerEventResponse : public ProtoMessage { }; class VoiceAssistantAnnounceRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 119; + static constexpr uint16_t ESTIMATED_SIZE = 29; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_announce_request"; } +#endif std::string media_id{}; std::string text{}; std::string preannounce_media_id{}; @@ -2072,6 +2572,11 @@ class VoiceAssistantAnnounceRequest : public ProtoMessage { }; class VoiceAssistantAnnounceFinished : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 120; + static constexpr uint16_t ESTIMATED_SIZE = 2; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_announce_finished"; } +#endif bool success{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2098,6 +2603,11 @@ class VoiceAssistantWakeWord : public ProtoMessage { }; class VoiceAssistantConfigurationRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 121; + static constexpr uint16_t ESTIMATED_SIZE = 0; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_configuration_request"; } +#endif void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -2108,6 +2618,11 @@ class VoiceAssistantConfigurationRequest : public ProtoMessage { }; class VoiceAssistantConfigurationResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 122; + static constexpr uint16_t ESTIMATED_SIZE = 56; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_configuration_response"; } +#endif std::vector available_wake_words{}; std::vector active_wake_words{}; uint32_t max_active_wake_words{0}; @@ -2123,6 +2638,11 @@ class VoiceAssistantConfigurationResponse : public ProtoMessage { }; class VoiceAssistantSetConfiguration : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 123; + static constexpr uint16_t ESTIMATED_SIZE = 18; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "voice_assistant_set_configuration"; } +#endif std::vector active_wake_words{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2135,6 +2655,11 @@ class VoiceAssistantSetConfiguration : public ProtoMessage { }; class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 94; + static constexpr uint16_t ESTIMATED_SIZE = 53; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_alarm_control_panel_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2158,6 +2683,11 @@ class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { }; class AlarmControlPanelStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 95; + static constexpr uint16_t ESTIMATED_SIZE = 7; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "alarm_control_panel_state_response"; } +#endif uint32_t key{0}; enums::AlarmControlPanelState state{}; void encode(ProtoWriteBuffer buffer) const override; @@ -2172,6 +2702,11 @@ class AlarmControlPanelStateResponse : public ProtoMessage { }; class AlarmControlPanelCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 96; + static constexpr uint16_t ESTIMATED_SIZE = 16; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "alarm_control_panel_command_request"; } +#endif uint32_t key{0}; enums::AlarmControlPanelStateCommand command{}; std::string code{}; @@ -2188,6 +2723,11 @@ class AlarmControlPanelCommandRequest : public ProtoMessage { }; class ListEntitiesTextResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 97; + static constexpr uint16_t ESTIMATED_SIZE = 64; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_text_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2212,6 +2752,11 @@ class ListEntitiesTextResponse : public ProtoMessage { }; class TextStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 98; + static constexpr uint16_t ESTIMATED_SIZE = 16; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "text_state_response"; } +#endif uint32_t key{0}; std::string state{}; bool missing_state{false}; @@ -2228,6 +2773,11 @@ class TextStateResponse : public ProtoMessage { }; class TextCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 99; + static constexpr uint16_t ESTIMATED_SIZE = 14; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "text_command_request"; } +#endif uint32_t key{0}; std::string state{}; void encode(ProtoWriteBuffer buffer) const override; @@ -2242,6 +2792,11 @@ class TextCommandRequest : public ProtoMessage { }; class ListEntitiesDateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 100; + static constexpr uint16_t ESTIMATED_SIZE = 45; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_date_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2262,6 +2817,11 @@ class ListEntitiesDateResponse : public ProtoMessage { }; class DateStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 101; + static constexpr uint16_t ESTIMATED_SIZE = 19; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "date_state_response"; } +#endif uint32_t key{0}; bool missing_state{false}; uint32_t year{0}; @@ -2279,6 +2839,11 @@ class DateStateResponse : public ProtoMessage { }; class DateCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 102; + static constexpr uint16_t ESTIMATED_SIZE = 17; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "date_command_request"; } +#endif uint32_t key{0}; uint32_t year{0}; uint32_t month{0}; @@ -2295,6 +2860,11 @@ class DateCommandRequest : public ProtoMessage { }; class ListEntitiesTimeResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 103; + static constexpr uint16_t ESTIMATED_SIZE = 45; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_time_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2315,6 +2885,11 @@ class ListEntitiesTimeResponse : public ProtoMessage { }; class TimeStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 104; + static constexpr uint16_t ESTIMATED_SIZE = 19; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "time_state_response"; } +#endif uint32_t key{0}; bool missing_state{false}; uint32_t hour{0}; @@ -2332,6 +2907,11 @@ class TimeStateResponse : public ProtoMessage { }; class TimeCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 105; + static constexpr uint16_t ESTIMATED_SIZE = 17; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "time_command_request"; } +#endif uint32_t key{0}; uint32_t hour{0}; uint32_t minute{0}; @@ -2348,6 +2928,11 @@ class TimeCommandRequest : public ProtoMessage { }; class ListEntitiesEventResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 107; + static constexpr uint16_t ESTIMATED_SIZE = 72; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_event_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2370,6 +2955,11 @@ class ListEntitiesEventResponse : public ProtoMessage { }; class EventResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 108; + static constexpr uint16_t ESTIMATED_SIZE = 14; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "event_response"; } +#endif uint32_t key{0}; std::string event_type{}; void encode(ProtoWriteBuffer buffer) const override; @@ -2384,6 +2974,11 @@ class EventResponse : public ProtoMessage { }; class ListEntitiesValveResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 109; + static constexpr uint16_t ESTIMATED_SIZE = 60; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_valve_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2408,6 +3003,11 @@ class ListEntitiesValveResponse : public ProtoMessage { }; class ValveStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 110; + static constexpr uint16_t ESTIMATED_SIZE = 12; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "valve_state_response"; } +#endif uint32_t key{0}; float position{0.0f}; enums::ValveOperation current_operation{}; @@ -2423,6 +3023,11 @@ class ValveStateResponse : public ProtoMessage { }; class ValveCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 111; + static constexpr uint16_t ESTIMATED_SIZE = 14; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "valve_command_request"; } +#endif uint32_t key{0}; bool has_position{false}; float position{0.0f}; @@ -2439,6 +3044,11 @@ class ValveCommandRequest : public ProtoMessage { }; class ListEntitiesDateTimeResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 112; + static constexpr uint16_t ESTIMATED_SIZE = 45; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_date_time_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2459,6 +3069,11 @@ class ListEntitiesDateTimeResponse : public ProtoMessage { }; class DateTimeStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 113; + static constexpr uint16_t ESTIMATED_SIZE = 12; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "date_time_state_response"; } +#endif uint32_t key{0}; bool missing_state{false}; uint32_t epoch_seconds{0}; @@ -2474,6 +3089,11 @@ class DateTimeStateResponse : public ProtoMessage { }; class DateTimeCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 114; + static constexpr uint16_t ESTIMATED_SIZE = 10; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "date_time_command_request"; } +#endif uint32_t key{0}; uint32_t epoch_seconds{0}; void encode(ProtoWriteBuffer buffer) const override; @@ -2487,6 +3107,11 @@ class DateTimeCommandRequest : public ProtoMessage { }; class ListEntitiesUpdateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 116; + static constexpr uint16_t ESTIMATED_SIZE = 54; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "list_entities_update_response"; } +#endif std::string object_id{}; uint32_t key{0}; std::string name{}; @@ -2508,6 +3133,11 @@ class ListEntitiesUpdateResponse : public ProtoMessage { }; class UpdateStateResponse : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 117; + static constexpr uint16_t ESTIMATED_SIZE = 61; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "update_state_response"; } +#endif uint32_t key{0}; bool missing_state{false}; bool in_progress{false}; @@ -2531,6 +3161,11 @@ class UpdateStateResponse : public ProtoMessage { }; class UpdateCommandRequest : public ProtoMessage { public: + static constexpr uint16_t MESSAGE_TYPE = 118; + static constexpr uint16_t ESTIMATED_SIZE = 7; +#ifdef HAS_PROTO_MESSAGE_DUMP + static constexpr const char *message_name() { return "update_command_request"; } +#endif uint32_t key{0}; enums::UpdateCommand command{}; void encode(ProtoWriteBuffer buffer) const override; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 5a701aeafa..dacb23c12b 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -8,688 +8,12 @@ namespace api { static const char *const TAG = "api.service"; -bool APIServerConnectionBase::send_hello_response(const HelloResponse &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_hello_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 2); -} -bool APIServerConnectionBase::send_connect_response(const ConnectResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_connect_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 4); -} -bool APIServerConnectionBase::send_disconnect_request(const DisconnectRequest &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_disconnect_request: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 5); -} -bool APIServerConnectionBase::send_disconnect_response(const DisconnectResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_disconnect_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 6); -} -bool APIServerConnectionBase::send_ping_request(const PingRequest &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_ping_request: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 7); -} -bool APIServerConnectionBase::send_ping_response(const PingResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_ping_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 8); -} -bool APIServerConnectionBase::send_device_info_response(const DeviceInfoResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_device_info_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 10); -} -bool APIServerConnectionBase::send_list_entities_done_response(const ListEntitiesDoneResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_done_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 19); -} -#ifdef USE_BINARY_SENSOR -bool APIServerConnectionBase::send_list_entities_binary_sensor_response(const ListEntitiesBinarySensorResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_binary_sensor_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 12); -} -#endif -#ifdef USE_BINARY_SENSOR -bool APIServerConnectionBase::send_binary_sensor_state_response(const BinarySensorStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_binary_sensor_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 21); -} -#endif -#ifdef USE_COVER -bool APIServerConnectionBase::send_list_entities_cover_response(const ListEntitiesCoverResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_cover_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 13); -} -#endif -#ifdef USE_COVER -bool APIServerConnectionBase::send_cover_state_response(const CoverStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_cover_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 22); -} -#endif -#ifdef USE_COVER -#endif -#ifdef USE_FAN -bool APIServerConnectionBase::send_list_entities_fan_response(const ListEntitiesFanResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_fan_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 14); -} -#endif -#ifdef USE_FAN -bool APIServerConnectionBase::send_fan_state_response(const FanStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_fan_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 23); -} -#endif -#ifdef USE_FAN -#endif -#ifdef USE_LIGHT -bool APIServerConnectionBase::send_list_entities_light_response(const ListEntitiesLightResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_light_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 15); -} -#endif -#ifdef USE_LIGHT -bool APIServerConnectionBase::send_light_state_response(const LightStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_light_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 24); -} -#endif -#ifdef USE_LIGHT -#endif -#ifdef USE_SENSOR -bool APIServerConnectionBase::send_list_entities_sensor_response(const ListEntitiesSensorResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_sensor_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 16); -} -#endif -#ifdef USE_SENSOR -bool APIServerConnectionBase::send_sensor_state_response(const SensorStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_sensor_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 25); -} -#endif -#ifdef USE_SWITCH -bool APIServerConnectionBase::send_list_entities_switch_response(const ListEntitiesSwitchResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_switch_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 17); -} -#endif -#ifdef USE_SWITCH -bool APIServerConnectionBase::send_switch_state_response(const SwitchStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_switch_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 26); -} -#endif -#ifdef USE_SWITCH -#endif -#ifdef USE_TEXT_SENSOR -bool APIServerConnectionBase::send_list_entities_text_sensor_response(const ListEntitiesTextSensorResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_text_sensor_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 18); -} -#endif -#ifdef USE_TEXT_SENSOR -bool APIServerConnectionBase::send_text_sensor_state_response(const TextSensorStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_text_sensor_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 27); -} -#endif -bool APIServerConnectionBase::send_subscribe_logs_response(const SubscribeLogsResponse &msg) { - return this->send_message_(msg, 29); -} -#ifdef USE_API_NOISE -#endif -#ifdef USE_API_NOISE -bool APIServerConnectionBase::send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_noise_encryption_set_key_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 125); -} -#endif -bool APIServerConnectionBase::send_homeassistant_service_response(const HomeassistantServiceResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_homeassistant_service_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 35); -} -bool APIServerConnectionBase::send_subscribe_home_assistant_state_response( - const SubscribeHomeAssistantStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_subscribe_home_assistant_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 39); -} -bool APIServerConnectionBase::send_get_time_request(const GetTimeRequest &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_get_time_request: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 36); -} -bool APIServerConnectionBase::send_get_time_response(const GetTimeResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_get_time_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 37); -} -bool APIServerConnectionBase::send_list_entities_services_response(const ListEntitiesServicesResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_services_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 41); -} -#ifdef USE_ESP32_CAMERA -bool APIServerConnectionBase::send_list_entities_camera_response(const ListEntitiesCameraResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_camera_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 43); -} -#endif -#ifdef USE_ESP32_CAMERA -bool APIServerConnectionBase::send_camera_image_response(const CameraImageResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_camera_image_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 44); -} -#endif -#ifdef USE_ESP32_CAMERA -#endif -#ifdef USE_CLIMATE -bool APIServerConnectionBase::send_list_entities_climate_response(const ListEntitiesClimateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_climate_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 46); -} -#endif -#ifdef USE_CLIMATE -bool APIServerConnectionBase::send_climate_state_response(const ClimateStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_climate_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 47); -} -#endif -#ifdef USE_CLIMATE -#endif -#ifdef USE_NUMBER -bool APIServerConnectionBase::send_list_entities_number_response(const ListEntitiesNumberResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_number_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 49); -} -#endif -#ifdef USE_NUMBER -bool APIServerConnectionBase::send_number_state_response(const NumberStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_number_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 50); -} -#endif -#ifdef USE_NUMBER -#endif -#ifdef USE_SELECT -bool APIServerConnectionBase::send_list_entities_select_response(const ListEntitiesSelectResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_select_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 52); -} -#endif -#ifdef USE_SELECT -bool APIServerConnectionBase::send_select_state_response(const SelectStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_select_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 53); -} -#endif -#ifdef USE_SELECT -#endif -#ifdef USE_SIREN -bool APIServerConnectionBase::send_list_entities_siren_response(const ListEntitiesSirenResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_siren_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 55); -} -#endif -#ifdef USE_SIREN -bool APIServerConnectionBase::send_siren_state_response(const SirenStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_siren_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 56); -} -#endif -#ifdef USE_SIREN -#endif -#ifdef USE_LOCK -bool APIServerConnectionBase::send_list_entities_lock_response(const ListEntitiesLockResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_lock_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 58); +void APIServerConnectionBase::log_send_message_(const char *name, const std::string &dump) { + ESP_LOGVV(TAG, "send_message %s: %s", name, dump.c_str()); } #endif -#ifdef USE_LOCK -bool APIServerConnectionBase::send_lock_state_response(const LockStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_lock_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 59); -} -#endif -#ifdef USE_LOCK -#endif -#ifdef USE_BUTTON -bool APIServerConnectionBase::send_list_entities_button_response(const ListEntitiesButtonResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_button_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 61); -} -#endif -#ifdef USE_BUTTON -#endif -#ifdef USE_MEDIA_PLAYER -bool APIServerConnectionBase::send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_media_player_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 63); -} -#endif -#ifdef USE_MEDIA_PLAYER -bool APIServerConnectionBase::send_media_player_state_response(const MediaPlayerStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_media_player_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 64); -} -#endif -#ifdef USE_MEDIA_PLAYER -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_le_advertisement_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 67); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_le_raw_advertisements_response( - const BluetoothLERawAdvertisementsResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_le_raw_advertisements_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 93); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_device_connection_response(const BluetoothDeviceConnectionResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_device_connection_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 69); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_get_services_response(const BluetoothGATTGetServicesResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_get_services_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 71); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_get_services_done_response( - const BluetoothGATTGetServicesDoneResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_get_services_done_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 72); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_read_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 74); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_notify_data_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 79); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_connections_free_response(const BluetoothConnectionsFreeResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_connections_free_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 81); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_error_response(const BluetoothGATTErrorResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_error_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 82); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_write_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 83); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_gatt_notify_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 84); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_device_pairing_response(const BluetoothDevicePairingResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_device_pairing_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 85); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_device_unpairing_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 86); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_device_clear_cache_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 88); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -bool APIServerConnectionBase::send_bluetooth_scanner_state_response(const BluetoothScannerStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_bluetooth_scanner_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 126); -} -#endif -#ifdef USE_BLUETOOTH_PROXY -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_VOICE_ASSISTANT -bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantRequest &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_voice_assistant_request: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 90); -} -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_VOICE_ASSISTANT -bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAudio &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_voice_assistant_audio: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 106); -} -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_VOICE_ASSISTANT -bool APIServerConnectionBase::send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_voice_assistant_announce_finished: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 120); -} -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_VOICE_ASSISTANT -bool APIServerConnectionBase::send_voice_assistant_configuration_response( - const VoiceAssistantConfigurationResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_voice_assistant_configuration_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 122); -} -#endif -#ifdef USE_VOICE_ASSISTANT -#endif -#ifdef USE_ALARM_CONTROL_PANEL -bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( - const ListEntitiesAlarmControlPanelResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_alarm_control_panel_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 94); -} -#endif -#ifdef USE_ALARM_CONTROL_PANEL -bool APIServerConnectionBase::send_alarm_control_panel_state_response(const AlarmControlPanelStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_alarm_control_panel_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 95); -} -#endif -#ifdef USE_ALARM_CONTROL_PANEL -#endif -#ifdef USE_TEXT -bool APIServerConnectionBase::send_list_entities_text_response(const ListEntitiesTextResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_text_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 97); -} -#endif -#ifdef USE_TEXT -bool APIServerConnectionBase::send_text_state_response(const TextStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_text_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 98); -} -#endif -#ifdef USE_TEXT -#endif -#ifdef USE_DATETIME_DATE -bool APIServerConnectionBase::send_list_entities_date_response(const ListEntitiesDateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_date_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 100); -} -#endif -#ifdef USE_DATETIME_DATE -bool APIServerConnectionBase::send_date_state_response(const DateStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_date_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 101); -} -#endif -#ifdef USE_DATETIME_DATE -#endif -#ifdef USE_DATETIME_TIME -bool APIServerConnectionBase::send_list_entities_time_response(const ListEntitiesTimeResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_time_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 103); -} -#endif -#ifdef USE_DATETIME_TIME -bool APIServerConnectionBase::send_time_state_response(const TimeStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_time_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 104); -} -#endif -#ifdef USE_DATETIME_TIME -#endif -#ifdef USE_EVENT -bool APIServerConnectionBase::send_list_entities_event_response(const ListEntitiesEventResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_event_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 107); -} -#endif -#ifdef USE_EVENT -bool APIServerConnectionBase::send_event_response(const EventResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_event_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 108); -} -#endif -#ifdef USE_VALVE -bool APIServerConnectionBase::send_list_entities_valve_response(const ListEntitiesValveResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_valve_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 109); -} -#endif -#ifdef USE_VALVE -bool APIServerConnectionBase::send_valve_state_response(const ValveStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_valve_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 110); -} -#endif -#ifdef USE_VALVE -#endif -#ifdef USE_DATETIME_DATETIME -bool APIServerConnectionBase::send_list_entities_date_time_response(const ListEntitiesDateTimeResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_date_time_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 112); -} -#endif -#ifdef USE_DATETIME_DATETIME -bool APIServerConnectionBase::send_date_time_state_response(const DateTimeStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_date_time_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 113); -} -#endif -#ifdef USE_DATETIME_DATETIME -#endif -#ifdef USE_UPDATE -bool APIServerConnectionBase::send_list_entities_update_response(const ListEntitiesUpdateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_list_entities_update_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 116); -} -#endif -#ifdef USE_UPDATE -bool APIServerConnectionBase::send_update_state_response(const UpdateStateResponse &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "send_update_state_response: %s", msg.dump().c_str()); -#endif - return this->send_message_(msg, 117); -} -#endif -#ifdef USE_UPDATE -#endif + bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -1273,25 +597,25 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, void APIServerConnection::on_hello_request(const HelloRequest &msg) { HelloResponse ret = this->hello(msg); - if (!this->send_hello_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } void APIServerConnection::on_connect_request(const ConnectRequest &msg) { ConnectResponse ret = this->connect(msg); - if (!this->send_connect_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } void APIServerConnection::on_disconnect_request(const DisconnectRequest &msg) { DisconnectResponse ret = this->disconnect(msg); - if (!this->send_disconnect_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } void APIServerConnection::on_ping_request(const PingRequest &msg) { PingResponse ret = this->ping(msg); - if (!this->send_ping_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } @@ -1301,7 +625,7 @@ void APIServerConnection::on_device_info_request(const DeviceInfoRequest &msg) { return; } DeviceInfoResponse ret = this->device_info(msg); - if (!this->send_device_info_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } @@ -1367,7 +691,7 @@ void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) { return; } GetTimeResponse ret = this->get_time(msg); - if (!this->send_get_time_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } @@ -1393,7 +717,7 @@ void APIServerConnection::on_noise_encryption_set_key_request(const NoiseEncrypt return; } NoiseEncryptionSetKeyResponse ret = this->noise_encryption_set_key(msg); - if (!this->send_noise_encryption_set_key_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } @@ -1749,7 +1073,7 @@ void APIServerConnection::on_subscribe_bluetooth_connections_free_request( return; } BluetoothConnectionsFreeResponse ret = this->subscribe_bluetooth_connections_free(msg); - if (!this->send_bluetooth_connections_free_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } @@ -1805,7 +1129,7 @@ void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAs return; } VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg); - if (!this->send_voice_assistant_configuration_response(ret)) { + if (!this->send_message(ret)) { this->on_fatal_error(); } } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 8ee5c0fcf1..b2be314aaf 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -10,162 +10,94 @@ namespace api { class APIServerConnectionBase : public ProtoService { public: +#ifdef HAS_PROTO_MESSAGE_DUMP + protected: + void log_send_message_(const char *name, const std::string &dump); + + public: +#endif + + template bool send_message(const T &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + this->log_send_message_(T::message_name(), msg.dump()); +#endif + return this->send_message_(msg, T::MESSAGE_TYPE); + } + virtual void on_hello_request(const HelloRequest &value){}; - bool send_hello_response(const HelloResponse &msg); + virtual void on_connect_request(const ConnectRequest &value){}; - bool send_connect_response(const ConnectResponse &msg); - bool send_disconnect_request(const DisconnectRequest &msg); + virtual void on_disconnect_request(const DisconnectRequest &value){}; - bool send_disconnect_response(const DisconnectResponse &msg); virtual void on_disconnect_response(const DisconnectResponse &value){}; - bool send_ping_request(const PingRequest &msg); virtual void on_ping_request(const PingRequest &value){}; - bool send_ping_response(const PingResponse &msg); virtual void on_ping_response(const PingResponse &value){}; virtual void on_device_info_request(const DeviceInfoRequest &value){}; - bool send_device_info_response(const DeviceInfoResponse &msg); + virtual void on_list_entities_request(const ListEntitiesRequest &value){}; - bool send_list_entities_done_response(const ListEntitiesDoneResponse &msg); + virtual void on_subscribe_states_request(const SubscribeStatesRequest &value){}; -#ifdef USE_BINARY_SENSOR - bool send_list_entities_binary_sensor_response(const ListEntitiesBinarySensorResponse &msg); -#endif -#ifdef USE_BINARY_SENSOR - bool send_binary_sensor_state_response(const BinarySensorStateResponse &msg); -#endif -#ifdef USE_COVER - bool send_list_entities_cover_response(const ListEntitiesCoverResponse &msg); -#endif -#ifdef USE_COVER - bool send_cover_state_response(const CoverStateResponse &msg); -#endif + #ifdef USE_COVER virtual void on_cover_command_request(const CoverCommandRequest &value){}; #endif -#ifdef USE_FAN - bool send_list_entities_fan_response(const ListEntitiesFanResponse &msg); -#endif -#ifdef USE_FAN - bool send_fan_state_response(const FanStateResponse &msg); -#endif + #ifdef USE_FAN virtual void on_fan_command_request(const FanCommandRequest &value){}; #endif -#ifdef USE_LIGHT - bool send_list_entities_light_response(const ListEntitiesLightResponse &msg); -#endif -#ifdef USE_LIGHT - bool send_light_state_response(const LightStateResponse &msg); -#endif + #ifdef USE_LIGHT virtual void on_light_command_request(const LightCommandRequest &value){}; #endif -#ifdef USE_SENSOR - bool send_list_entities_sensor_response(const ListEntitiesSensorResponse &msg); -#endif -#ifdef USE_SENSOR - bool send_sensor_state_response(const SensorStateResponse &msg); -#endif -#ifdef USE_SWITCH - bool send_list_entities_switch_response(const ListEntitiesSwitchResponse &msg); -#endif -#ifdef USE_SWITCH - bool send_switch_state_response(const SwitchStateResponse &msg); -#endif + #ifdef USE_SWITCH virtual void on_switch_command_request(const SwitchCommandRequest &value){}; #endif -#ifdef USE_TEXT_SENSOR - bool send_list_entities_text_sensor_response(const ListEntitiesTextSensorResponse &msg); -#endif -#ifdef USE_TEXT_SENSOR - bool send_text_sensor_state_response(const TextSensorStateResponse &msg); -#endif + virtual void on_subscribe_logs_request(const SubscribeLogsRequest &value){}; - bool send_subscribe_logs_response(const SubscribeLogsResponse &msg); + #ifdef USE_API_NOISE virtual void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &value){}; #endif -#ifdef USE_API_NOISE - bool send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyResponse &msg); -#endif + virtual void on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &value){}; - bool send_homeassistant_service_response(const HomeassistantServiceResponse &msg); + virtual void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &value){}; - bool send_subscribe_home_assistant_state_response(const SubscribeHomeAssistantStateResponse &msg); + virtual void on_home_assistant_state_response(const HomeAssistantStateResponse &value){}; - bool send_get_time_request(const GetTimeRequest &msg); virtual void on_get_time_request(const GetTimeRequest &value){}; - bool send_get_time_response(const GetTimeResponse &msg); virtual void on_get_time_response(const GetTimeResponse &value){}; - bool send_list_entities_services_response(const ListEntitiesServicesResponse &msg); + virtual void on_execute_service_request(const ExecuteServiceRequest &value){}; -#ifdef USE_ESP32_CAMERA - bool send_list_entities_camera_response(const ListEntitiesCameraResponse &msg); -#endif -#ifdef USE_ESP32_CAMERA - bool send_camera_image_response(const CameraImageResponse &msg); -#endif + #ifdef USE_ESP32_CAMERA virtual void on_camera_image_request(const CameraImageRequest &value){}; #endif -#ifdef USE_CLIMATE - bool send_list_entities_climate_response(const ListEntitiesClimateResponse &msg); -#endif -#ifdef USE_CLIMATE - bool send_climate_state_response(const ClimateStateResponse &msg); -#endif + #ifdef USE_CLIMATE virtual void on_climate_command_request(const ClimateCommandRequest &value){}; #endif -#ifdef USE_NUMBER - bool send_list_entities_number_response(const ListEntitiesNumberResponse &msg); -#endif -#ifdef USE_NUMBER - bool send_number_state_response(const NumberStateResponse &msg); -#endif + #ifdef USE_NUMBER virtual void on_number_command_request(const NumberCommandRequest &value){}; #endif -#ifdef USE_SELECT - bool send_list_entities_select_response(const ListEntitiesSelectResponse &msg); -#endif -#ifdef USE_SELECT - bool send_select_state_response(const SelectStateResponse &msg); -#endif + #ifdef USE_SELECT virtual void on_select_command_request(const SelectCommandRequest &value){}; #endif -#ifdef USE_SIREN - bool send_list_entities_siren_response(const ListEntitiesSirenResponse &msg); -#endif -#ifdef USE_SIREN - bool send_siren_state_response(const SirenStateResponse &msg); -#endif + #ifdef USE_SIREN virtual void on_siren_command_request(const SirenCommandRequest &value){}; #endif -#ifdef USE_LOCK - bool send_list_entities_lock_response(const ListEntitiesLockResponse &msg); -#endif -#ifdef USE_LOCK - bool send_lock_state_response(const LockStateResponse &msg); -#endif + #ifdef USE_LOCK virtual void on_lock_command_request(const LockCommandRequest &value){}; #endif -#ifdef USE_BUTTON - bool send_list_entities_button_response(const ListEntitiesButtonResponse &msg); -#endif + #ifdef USE_BUTTON virtual void on_button_command_request(const ButtonCommandRequest &value){}; #endif -#ifdef USE_MEDIA_PLAYER - bool send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg); -#endif -#ifdef USE_MEDIA_PLAYER - bool send_media_player_state_response(const MediaPlayerStateResponse &msg); -#endif + #ifdef USE_MEDIA_PLAYER virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){}; #endif @@ -173,33 +105,19 @@ class APIServerConnectionBase : public ProtoService { virtual void on_subscribe_bluetooth_le_advertisements_request( const SubscribeBluetoothLEAdvertisementsRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_le_raw_advertisements_response(const BluetoothLERawAdvertisementsResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_device_request(const BluetoothDeviceRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_device_connection_response(const BluetoothDeviceConnectionResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_get_services_response(const BluetoothGATTGetServicesResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_get_services_done_response(const BluetoothGATTGetServicesDoneResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &value){}; #endif @@ -212,49 +130,23 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_connections_free_response(const BluetoothConnectionsFreeResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_error_response(const BluetoothGATTErrorResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_device_pairing_response(const BluetoothDevicePairingResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_unsubscribe_bluetooth_le_advertisements_request( const UnsubscribeBluetoothLEAdvertisementsRequest &value){}; #endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg); -#endif -#ifdef USE_BLUETOOTH_PROXY - bool send_bluetooth_scanner_state_response(const BluetoothScannerStateResponse &msg); -#endif + #ifdef USE_BLUETOOTH_PROXY virtual void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &value){}; #endif #ifdef USE_VOICE_ASSISTANT virtual void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &value){}; #endif -#ifdef USE_VOICE_ASSISTANT - bool send_voice_assistant_request(const VoiceAssistantRequest &msg); -#endif + #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_response(const VoiceAssistantResponse &value){}; #endif @@ -262,7 +154,6 @@ class APIServerConnectionBase : public ProtoService { virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){}; #endif #ifdef USE_VOICE_ASSISTANT - bool send_voice_assistant_audio(const VoiceAssistantAudio &msg); virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){}; #endif #ifdef USE_VOICE_ASSISTANT @@ -271,84 +162,39 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &value){}; #endif -#ifdef USE_VOICE_ASSISTANT - bool send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg); -#endif + #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &value){}; #endif -#ifdef USE_VOICE_ASSISTANT - bool send_voice_assistant_configuration_response(const VoiceAssistantConfigurationResponse &msg); -#endif + #ifdef USE_VOICE_ASSISTANT virtual void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){}; #endif -#ifdef USE_ALARM_CONTROL_PANEL - bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); -#endif -#ifdef USE_ALARM_CONTROL_PANEL - bool send_alarm_control_panel_state_response(const AlarmControlPanelStateResponse &msg); -#endif + #ifdef USE_ALARM_CONTROL_PANEL virtual void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &value){}; #endif -#ifdef USE_TEXT - bool send_list_entities_text_response(const ListEntitiesTextResponse &msg); -#endif -#ifdef USE_TEXT - bool send_text_state_response(const TextStateResponse &msg); -#endif + #ifdef USE_TEXT virtual void on_text_command_request(const TextCommandRequest &value){}; #endif -#ifdef USE_DATETIME_DATE - bool send_list_entities_date_response(const ListEntitiesDateResponse &msg); -#endif -#ifdef USE_DATETIME_DATE - bool send_date_state_response(const DateStateResponse &msg); -#endif + #ifdef USE_DATETIME_DATE virtual void on_date_command_request(const DateCommandRequest &value){}; #endif -#ifdef USE_DATETIME_TIME - bool send_list_entities_time_response(const ListEntitiesTimeResponse &msg); -#endif -#ifdef USE_DATETIME_TIME - bool send_time_state_response(const TimeStateResponse &msg); -#endif + #ifdef USE_DATETIME_TIME virtual void on_time_command_request(const TimeCommandRequest &value){}; #endif -#ifdef USE_EVENT - bool send_list_entities_event_response(const ListEntitiesEventResponse &msg); -#endif -#ifdef USE_EVENT - bool send_event_response(const EventResponse &msg); -#endif -#ifdef USE_VALVE - bool send_list_entities_valve_response(const ListEntitiesValveResponse &msg); -#endif -#ifdef USE_VALVE - bool send_valve_state_response(const ValveStateResponse &msg); -#endif + #ifdef USE_VALVE virtual void on_valve_command_request(const ValveCommandRequest &value){}; #endif -#ifdef USE_DATETIME_DATETIME - bool send_list_entities_date_time_response(const ListEntitiesDateTimeResponse &msg); -#endif -#ifdef USE_DATETIME_DATETIME - bool send_date_time_state_response(const DateTimeStateResponse &msg); -#endif + #ifdef USE_DATETIME_DATETIME virtual void on_date_time_command_request(const DateTimeCommandRequest &value){}; #endif -#ifdef USE_UPDATE - bool send_list_entities_update_response(const ListEntitiesUpdateResponse &msg); -#endif -#ifdef USE_UPDATE - bool send_update_state_response(const UpdateStateResponse &msg); -#endif + #ifdef USE_UPDATE virtual void on_update_command_request(const UpdateCommandRequest &value){}; #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 2d5c507b9d..6852afe937 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -24,7 +24,11 @@ static const char *const TAG = "api"; // APIServer APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -APIServer::APIServer() { global_api_server = this; } +APIServer::APIServer() { + global_api_server = this; + // Pre-allocate shared write buffer + shared_write_buffer_.reserve(64); +} void APIServer::setup() { ESP_LOGCONFIG(TAG, "Running setup"); @@ -88,6 +92,12 @@ void APIServer::setup() { #ifdef USE_LOGGER if (logger::global_logger != nullptr) { logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) { + if (this->shutting_down_) { + // Don't try to send logs during shutdown + // as it could result in a recursion and + // we would be filling a buffer we are trying to clear + return; + } for (auto &c : this->clients_) { if (!c->remove_) c->try_send_log_message(level, tag, message); @@ -112,8 +122,8 @@ void APIServer::setup() { } void APIServer::loop() { - // Accept new clients only if the socket has incoming connections - if (this->socket_->ready()) { + // Accept new clients only if the socket exists and has incoming connections + if (this->socket_ && this->socket_->ready()) { while (true) { struct sockaddr_storage source_addr; socklen_t addr_len = sizeof(source_addr); @@ -169,8 +179,10 @@ void APIServer::loop() { } void APIServer::dump_config() { - ESP_LOGCONFIG(TAG, "API Server:"); - ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->port_); + ESP_LOGCONFIG(TAG, + "API Server:\n" + " Address: %s:%u", + network::get_use_address().c_str(), this->port_); #ifdef USE_API_NOISE ESP_LOGCONFIG(TAG, " Using noise encryption: %s", YESNO(this->noise_ctx_->has_psk())); if (!this->noise_ctx_->has_psk()) { @@ -215,11 +227,11 @@ bool APIServer::check_password(const std::string &password) const { void APIServer::handle_disconnect(APIConnection *conn) {} #ifdef USE_BINARY_SENSOR -void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) { +void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) { if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_binary_sensor_state(obj, state); + c->send_binary_sensor_state(obj); } #endif @@ -255,7 +267,7 @@ void APIServer::on_sensor_update(sensor::Sensor *obj, float state) { if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_sensor_state(obj, state); + c->send_sensor_state(obj); } #endif @@ -264,7 +276,7 @@ void APIServer::on_switch_update(switch_::Switch *obj, bool state) { if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_switch_state(obj, state); + c->send_switch_state(obj); } #endif @@ -273,7 +285,7 @@ void APIServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::s if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_text_sensor_state(obj, state); + c->send_text_sensor_state(obj); } #endif @@ -291,7 +303,7 @@ void APIServer::on_number_update(number::Number *obj, float state) { if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_number_state(obj, state); + c->send_number_state(obj); } #endif @@ -327,7 +339,7 @@ void APIServer::on_text_update(text::Text *obj, const std::string &state) { if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_text_state(obj, state); + c->send_text_state(obj); } #endif @@ -336,7 +348,7 @@ void APIServer::on_select_update(select::Select *obj, const std::string &state, if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_select_state(obj, state); + c->send_select_state(obj); } #endif @@ -345,7 +357,7 @@ void APIServer::on_lock_update(lock::Lock *obj) { if (obj->is_internal()) return; for (auto &c : this->clients_) - c->send_lock_state(obj, obj->state); + c->send_lock_state(obj); } #endif @@ -396,6 +408,8 @@ void APIServer::set_port(uint16_t port) { this->port_ = port; } void APIServer::set_password(const std::string &password) { this->password_ = password; } +void APIServer::set_batch_delay(uint32_t batch_delay) { this->batch_delay_ = batch_delay; } + void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) { for (auto &client : this->clients_) { client->send_homeassistant_service_call(call); @@ -454,7 +468,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) { ESP_LOGW(TAG, "Disconnecting all clients to reset connections"); this->set_noise_psk(psk); for (auto &c : this->clients_) { - c->send_disconnect_request(DisconnectRequest()); + c->send_message(DisconnectRequest()); } }); } @@ -474,10 +488,36 @@ void APIServer::request_time() { bool APIServer::is_connected() const { return !this->clients_.empty(); } void APIServer::on_shutdown() { - for (auto &c : this->clients_) { - c->send_disconnect_request(DisconnectRequest()); + this->shutting_down_ = true; + + // Close the listening socket to prevent new connections + if (this->socket_) { + this->socket_->close(); + this->socket_ = nullptr; } - delay(10); + + // Change batch delay to 5ms for quick flushing during shutdown + this->batch_delay_ = 5; + + // Send disconnect requests to all connected clients + for (auto &c : this->clients_) { + if (!c->send_message(DisconnectRequest())) { + // If we can't send the disconnect request directly (tx_buffer full), + // schedule it in the batch so it will be sent with the 5ms timer + c->schedule_message_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE); + } + } +} + +bool APIServer::teardown() { + // If network is disconnected, no point trying to flush buffers + if (!network::is_connected()) { + return true; + } + this->loop(); + + // Return true only when all clients have been torn down + return this->clients_.empty(); } } // namespace api diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index a6645b96ce..971c192e4b 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -34,11 +34,17 @@ class APIServer : public Component, public Controller { void loop() override; void dump_config() override; void on_shutdown() override; + bool teardown() override; bool check_password(const std::string &password) const; bool uses_password() const; void set_port(uint16_t port); void set_password(const std::string &password); void set_reboot_timeout(uint32_t reboot_timeout); + void set_batch_delay(uint32_t batch_delay); + uint32_t get_batch_delay() const { return batch_delay_; } + + // Get reference to shared buffer for API connections + std::vector &get_shared_buffer_ref() { return shared_write_buffer_; } #ifdef USE_API_NOISE bool save_noise_psk(psk_t psk, bool make_active = true); @@ -48,7 +54,7 @@ class APIServer : public Component, public Controller { void handle_disconnect(APIConnection *conn); #ifdef USE_BINARY_SENSOR - void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override; + void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override; #endif #ifdef USE_COVER void on_cover_update(cover::Cover *obj) override; @@ -136,12 +142,15 @@ class APIServer : public Component, public Controller { } protected: + bool shutting_down_ = false; std::unique_ptr socket_ = nullptr; uint16_t port_{6053}; uint32_t reboot_timeout_{300000}; + uint32_t batch_delay_{100}; uint32_t last_connected_{0}; std::vector> clients_; std::string password_; + std::vector shared_write_buffer_; // Shared proto write buffer for all connections std::vector state_subs_; std::vector user_services_; Trigger *client_connected_trigger_ = new Trigger(); diff --git a/esphome/components/api/client.py b/esphome/components/api/client.py index c61b8d5ea3..20136ef7b8 100644 --- a/esphome/components/api/client.py +++ b/esphome/components/api/client.py @@ -5,7 +5,7 @@ from datetime import datetime import logging from typing import TYPE_CHECKING, Any -from aioesphomeapi import APIClient +from aioesphomeapi import APIClient, parse_log_message from aioesphomeapi.log_runner import async_run from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__ @@ -46,9 +46,10 @@ async def async_run_logs(config: dict[str, Any], address: str) -> None: time_ = datetime.now() message: bytes = msg.message text = message.decode("utf8", "backslashreplace") - if dashboard: - text = text.replace("\033", "\\033") - print(f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]{text}") + for parsed_msg in parse_log_message( + text, f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]" + ): + print(parsed_msg.replace("\033", "\\033") if dashboard else parsed_msg) stop = await async_run(cli, on_log, name=name) try: diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index e91756c3c9..32d13b69ae 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -3,8 +3,8 @@ #include "api_server.h" #ifdef USE_API #include "api_pb2.h" -#include "esphome/core/helpers.h" #include "esphome/core/automation.h" +#include "esphome/core/helpers.h" #include namespace esphome { diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index 574aa2525b..ceee3f00b8 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -73,7 +73,7 @@ bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done( ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {} bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) { auto resp = service->encode_list_service_response(); - return this->client_->send_list_entities_services_response(resp); + return this->client_->send_message(resp); } #ifdef USE_ESP32_CAMERA diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index 7af2e92534..25daf17ccc 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -1,5 +1,6 @@ #include "proto.h" #include +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index fae722f750..5265c4520d 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -1,8 +1,8 @@ #pragma once #include "esphome/core/component.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include @@ -360,11 +360,11 @@ class ProtoService { * @return A ProtoWriteBuffer object with the reserved size. */ virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0; - virtual bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) = 0; + virtual bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) = 0; virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0; // Optimized method that pre-allocates buffer based on message size - template bool send_message_(const C &msg, uint32_t message_type) { + bool send_message_(const ProtoMessage &msg, uint16_t message_type) { uint32_t msg_size = 0; msg.calculate_size(msg_size); diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 4b1d5ebc0d..4180435fcc 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -8,7 +8,7 @@ namespace api { #ifdef USE_BINARY_SENSOR bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { - return this->client_->send_binary_sensor_state(binary_sensor, binary_sensor->state); + return this->client_->send_binary_sensor_state(binary_sensor); } #endif #ifdef USE_COVER @@ -21,27 +21,21 @@ bool InitialStateIterator::on_fan(fan::Fan *fan) { return this->client_->send_fa bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); } #endif #ifdef USE_SENSOR -bool InitialStateIterator::on_sensor(sensor::Sensor *sensor) { - return this->client_->send_sensor_state(sensor, sensor->state); -} +bool InitialStateIterator::on_sensor(sensor::Sensor *sensor) { return this->client_->send_sensor_state(sensor); } #endif #ifdef USE_SWITCH -bool InitialStateIterator::on_switch(switch_::Switch *a_switch) { - return this->client_->send_switch_state(a_switch, a_switch->state); -} +bool InitialStateIterator::on_switch(switch_::Switch *a_switch) { return this->client_->send_switch_state(a_switch); } #endif #ifdef USE_TEXT_SENSOR bool InitialStateIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) { - return this->client_->send_text_sensor_state(text_sensor, text_sensor->state); + return this->client_->send_text_sensor_state(text_sensor); } #endif #ifdef USE_CLIMATE bool InitialStateIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_state(climate); } #endif #ifdef USE_NUMBER -bool InitialStateIterator::on_number(number::Number *number) { - return this->client_->send_number_state(number, number->state); -} +bool InitialStateIterator::on_number(number::Number *number) { return this->client_->send_number_state(number); } #endif #ifdef USE_DATETIME_DATE bool InitialStateIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_state(date); } @@ -55,15 +49,13 @@ bool InitialStateIterator::on_datetime(datetime::DateTimeEntity *datetime) { } #endif #ifdef USE_TEXT -bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text, text->state); } +bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text); } #endif #ifdef USE_SELECT -bool InitialStateIterator::on_select(select::Select *select) { - return this->client_->send_select_state(select, select->state); -} +bool InitialStateIterator::on_select(select::Select *select) { return this->client_->send_select_state(select); } #endif #ifdef USE_LOCK -bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); } +bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock); } #endif #ifdef USE_VALVE bool InitialStateIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_state(valve); } diff --git a/esphome/components/as3935/as3935.cpp b/esphome/components/as3935/as3935.cpp index adef45a395..5e6d62b284 100644 --- a/esphome/components/as3935/as3935.cpp +++ b/esphome/components/as3935/as3935.cpp @@ -282,7 +282,7 @@ void AS3935Component::display_oscillator(bool state, uint8_t osc) { // based on the resonance frequency of the antenna and so it should be trimmed // before the calibration is done. bool AS3935Component::calibrate_oscillator() { - ESP_LOGI(TAG, "Starting oscillators calibration..."); + ESP_LOGI(TAG, "Starting oscillators calibration"); this->write_register(CALIB_RCO, WIPE_ALL, DIRECT_COMMAND, 0); // Send command to calibrate the oscillators this->display_oscillator(true, 2); @@ -307,7 +307,7 @@ bool AS3935Component::calibrate_oscillator() { } void AS3935Component::tune_antenna() { - ESP_LOGI(TAG, "Starting antenna tuning..."); + ESP_LOGI(TAG, "Starting antenna tuning"); uint8_t div_ratio = this->read_div_ratio(); uint8_t tune_val = this->read_capacitance(); ESP_LOGI(TAG, "Division Ratio is set to: %d", div_ratio); diff --git a/esphome/components/as5600/as5600.cpp b/esphome/components/as5600/as5600.cpp index 5cfc7e1b9e..ff29ae5cd4 100644 --- a/esphome/components/as5600/as5600.cpp +++ b/esphome/components/as5600/as5600.cpp @@ -95,11 +95,13 @@ void AS5600Component::dump_config() { return; } - ESP_LOGCONFIG(TAG, " Watchdog: %d", this->watchdog_); - ESP_LOGCONFIG(TAG, " Fast Filter: %d", this->fast_filter_); - ESP_LOGCONFIG(TAG, " Slow Filter: %d", this->slow_filter_); - ESP_LOGCONFIG(TAG, " Hysteresis: %d", this->hysteresis_); - ESP_LOGCONFIG(TAG, " Start Position: %d", this->start_position_); + ESP_LOGCONFIG(TAG, + " Watchdog: %d\n" + " Fast Filter: %d\n" + " Slow Filter: %d\n" + " Hysteresis: %d\n" + " Start Position: %d", + this->watchdog_, this->fast_filter_, this->slow_filter_, this->hysteresis_, this->start_position_); if (this->end_mode_ == END_MODE_POSITION) { ESP_LOGCONFIG(TAG, " End Position: %d", this->end_position_); } else { diff --git a/esphome/components/as7341/as7341.cpp b/esphome/components/as7341/as7341.cpp index b01bcf2eed..1e335f43ad 100644 --- a/esphome/components/as7341/as7341.cpp +++ b/esphome/components/as7341/as7341.cpp @@ -41,9 +41,11 @@ void AS7341Component::dump_config() { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); } LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " Gain: %u", get_gain()); - ESP_LOGCONFIG(TAG, " ATIME: %u", get_atime()); - ESP_LOGCONFIG(TAG, " ASTEP: %u", get_astep()); + ESP_LOGCONFIG(TAG, + " Gain: %u\n" + " ATIME: %u\n" + " ASTEP: %u", + get_gain(), get_atime(), get_astep()); LOG_SENSOR(" ", "F1", this->f1_); LOG_SENSOR(" ", "F2", this->f2_); diff --git a/esphome/components/at581x/at581x.cpp b/esphome/components/at581x/at581x.cpp index 2171544be2..b4f817b737 100644 --- a/esphome/components/at581x/at581x.cpp +++ b/esphome/components/at581x/at581x.cpp @@ -75,15 +75,18 @@ void AT581XComponent::setup() { ESP_LOGCONFIG(TAG, "Running setup"); } void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); } #define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) bool AT581XComponent::i2c_write_config() { - ESP_LOGCONFIG(TAG, "Writing new config for AT581X..."); - ESP_LOGCONFIG(TAG, "Frequency: %dMHz", this->freq_); - ESP_LOGCONFIG(TAG, "Sensing distance: %d", this->delta_); - ESP_LOGCONFIG(TAG, "Power: %dµA", this->power_); - ESP_LOGCONFIG(TAG, "Gain: %d", this->gain_); - ESP_LOGCONFIG(TAG, "Trigger base time: %dms", this->trigger_base_time_ms_); - ESP_LOGCONFIG(TAG, "Trigger keep time: %dms", this->trigger_keep_time_ms_); - ESP_LOGCONFIG(TAG, "Protect time: %dms", this->protect_time_ms_); - ESP_LOGCONFIG(TAG, "Self check time: %dms", this->self_check_time_ms_); + ESP_LOGCONFIG(TAG, + "Writing new config for AT581X\n" + "Frequency: %dMHz\n" + "Sensing distance: %d\n" + "Power: %dµA\n" + "Gain: %d\n" + "Trigger base time: %dms\n" + "Trigger keep time: %dms\n" + "Protect time: %dms\n" + "Self check time: %dms", + this->freq_, this->delta_, this->power_, this->gain_, this->trigger_base_time_ms_, + this->trigger_keep_time_ms_, this->protect_time_ms_, this->self_check_time_ms_); // Set frequency point if (!this->i2c_write_reg(FREQ_ADDR, GAIN61_VALUE)) { diff --git a/esphome/components/atm90e32/atm90e32.cpp b/esphome/components/atm90e32/atm90e32.cpp index 545997eb14..f05d462845 100644 --- a/esphome/components/atm90e32/atm90e32.cpp +++ b/esphome/components/atm90e32/atm90e32.cpp @@ -686,7 +686,7 @@ void ATM90E32Component::restore_power_offset_calibrations_() { } void ATM90E32Component::clear_gain_calibrations() { - ESP_LOGI(TAG, "[CALIBRATION] Clearing stored gain calibrations and restoring config-defined values..."); + ESP_LOGI(TAG, "[CALIBRATION] Clearing stored gain calibrations and restoring config-defined values"); for (int phase = 0; phase < 3; phase++) { gain_phase_[phase].voltage_gain = this->phase_[phase].voltage_gain_; diff --git a/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp b/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp index d4e5d7b9c6..e6e049e332 100644 --- a/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +++ b/esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp @@ -60,8 +60,10 @@ void AXS15231Touchscreen::dump_config() { LOG_I2C_DEVICE(this); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " Width: %d", this->x_raw_max_); - ESP_LOGCONFIG(TAG, " Height: %d", this->y_raw_max_); + ESP_LOGCONFIG(TAG, + " Width: %d\n" + " Height: %d", + this->x_raw_max_, this->y_raw_max_); } } // namespace axs15231 diff --git a/esphome/components/bang_bang/bang_bang_climate.cpp b/esphome/components/bang_bang/bang_bang_climate.cpp index aed97b2890..bb85b49238 100644 --- a/esphome/components/bang_bang/bang_bang_climate.cpp +++ b/esphome/components/bang_bang/bang_bang_climate.cpp @@ -194,11 +194,14 @@ Trigger<> *BangBangClimate::get_heat_trigger() const { return this->heat_trigger 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, " Supports HEAT: %s", YESNO(this->supports_heat_)); - ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_)); - ESP_LOGCONFIG(TAG, " Supports AWAY mode: %s", YESNO(this->supports_away_)); - ESP_LOGCONFIG(TAG, " Default Target Temperature Low: %.2f°C", this->normal_config_.default_temperature_low); - ESP_LOGCONFIG(TAG, " Default Target Temperature High: %.2f°C", this->normal_config_.default_temperature_high); + ESP_LOGCONFIG(TAG, + " Supports HEAT: %s\n" + " Supports COOL: %s\n" + " Supports AWAY mode: %s\n" + " Default Target Temperature Low: %.2f°C\n" + " Default Target Temperature High: %.2f°C", + YESNO(this->supports_heat_), YESNO(this->supports_cool_), YESNO(this->supports_away_), + this->normal_config_.default_temperature_low, this->normal_config_.default_temperature_high); } BangBangClimateTargetTempConfig::BangBangClimateTargetTempConfig() = default; diff --git a/esphome/components/bedjet/bedjet_hub.cpp b/esphome/components/bedjet/bedjet_hub.cpp index fea7080de6..7ebed2e78d 100644 --- a/esphome/components/bedjet/bedjet_hub.cpp +++ b/esphome/components/bedjet/bedjet_hub.cpp @@ -484,9 +484,11 @@ void BedJetHub::loop() {} void BedJetHub::update() { this->dispatch_status_(); } void BedJetHub::dump_config() { - ESP_LOGCONFIG(TAG, "BedJet Hub '%s'", this->get_name().c_str()); - ESP_LOGCONFIG(TAG, " ble_client.app_id: %d", this->parent()->app_id); - ESP_LOGCONFIG(TAG, " ble_client.conn_id: %d", this->parent()->get_conn_id()); + ESP_LOGCONFIG(TAG, + "BedJet Hub '%s'\n" + " ble_client.app_id: %d\n" + " ble_client.conn_id: %d", + this->get_name().c_str(), this->parent()->app_id, this->parent()->get_conn_id()); LOG_UPDATE_INTERVAL(this) ESP_LOGCONFIG(TAG, " Child components (%d):", this->children_.size()); for (auto *child : this->children_) { @@ -527,7 +529,7 @@ void BedJetHub::dispatch_status_() { } if (this->timeout_ > 0 && diff > this->timeout_ && this->parent()->enabled) { - ESP_LOGW(TAG, "[%s] Timed out after %" PRId32 " sec. Retrying...", this->get_name().c_str(), this->timeout_); + ESP_LOGW(TAG, "[%s] Timed out after %" PRId32 " sec. Retrying", this->get_name().c_str(), this->timeout_); // set_enabled(false) will only close the connection if state != IDLE. this->parent()->set_state(espbt::ClientState::CONNECTING); this->parent()->set_enabled(false); diff --git a/esphome/components/beken_spi_led_strip/led_strip.cpp b/esphome/components/beken_spi_led_strip/led_strip.cpp index 39bf831226..d4585d7d36 100644 --- a/esphome/components/beken_spi_led_strip/led_strip.cpp +++ b/esphome/components/beken_spi_led_strip/led_strip.cpp @@ -256,7 +256,7 @@ void BekenSPILEDStripLightOutput::write_state(light::LightState *state) { this->last_refresh_ = now; this->mark_shown_(); - ESP_LOGVV(TAG, "Writing RGB values to bus..."); + ESP_LOGVV(TAG, "Writing RGB values to bus"); if (spi_data == nullptr) { ESP_LOGE(TAG, "SPI not initialized"); @@ -345,8 +345,10 @@ light::ESPColorView BekenSPILEDStripLightOutput::get_view_internal(int32_t index } void BekenSPILEDStripLightOutput::dump_config() { - ESP_LOGCONFIG(TAG, "Beken SPI LED Strip:"); - ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_); + ESP_LOGCONFIG(TAG, + "Beken SPI LED Strip:\n" + " Pin: %u", + this->pin_); const char *rgb_order; switch (this->rgb_order_) { case ORDER_RGB: @@ -371,9 +373,11 @@ void BekenSPILEDStripLightOutput::dump_config() { rgb_order = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order); - ESP_LOGCONFIG(TAG, " Max refresh rate: %" PRIu32, *this->max_refresh_rate_); - ESP_LOGCONFIG(TAG, " Number of LEDs: %u", this->num_leds_); + ESP_LOGCONFIG(TAG, + " RGB Order: %s\n" + " Max refresh rate: %" PRIu32 "\n" + " Number of LEDs: %u", + rgb_order, *this->max_refresh_rate_, this->num_leds_); } float BekenSPILEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; } diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 448323da5a..bc26c09622 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -1,7 +1,10 @@ +from logging import getLogger + from esphome import automation, core from esphome.automation import Condition, maybe_simple_id import esphome.codegen as cg from esphome.components import mqtt, web_server +from esphome.components.const import CONF_ON_STATE_CHANGE import esphome.config_validation as cv from esphome.const import ( CONF_DELAY, @@ -98,6 +101,7 @@ IS_PLATFORM_COMPONENT = True CONF_TIME_OFF = "time_off" CONF_TIME_ON = "time_on" +CONF_TRIGGER_ON_INITIAL_STATE = "trigger_on_initial_state" DEFAULT_DELAY = "1s" DEFAULT_TIME_OFF = "100ms" @@ -127,9 +131,17 @@ MultiClickTriggerEvent = binary_sensor_ns.struct("MultiClickTriggerEvent") StateTrigger = binary_sensor_ns.class_( "StateTrigger", automation.Trigger.template(bool) ) +StateChangeTrigger = binary_sensor_ns.class_( + "StateChangeTrigger", + automation.Trigger.template(cg.optional.template(bool), cg.optional.template(bool)), +) + BinarySensorPublishAction = binary_sensor_ns.class_( "BinarySensorPublishAction", automation.Action ) +BinarySensorInvalidateAction = binary_sensor_ns.class_( + "BinarySensorInvalidateAction", automation.Action +) # Condition BinarySensorCondition = binary_sensor_ns.class_("BinarySensorCondition", Condition) @@ -144,6 +156,8 @@ AutorepeatFilter = binary_sensor_ns.class_("AutorepeatFilter", Filter, cg.Compon LambdaFilter = binary_sensor_ns.class_("LambdaFilter", Filter) SettleFilter = binary_sensor_ns.class_("SettleFilter", Filter, cg.Component) +_LOGGER = getLogger(__name__) + FILTER_REGISTRY = Registry() validate_filters = cv.validate_registry("filter", FILTER_REGISTRY) @@ -386,6 +400,14 @@ def validate_click_timing(value): return value +def validate_publish_initial_state(value): + value = cv.boolean(value) + _LOGGER.warning( + "The 'publish_initial_state' option has been replaced by 'trigger_on_initial_state' and will be removed in a future release" + ) + return value + + _BINARY_SENSOR_SCHEMA = ( cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA) .extend(cv.MQTT_COMPONENT_SCHEMA) @@ -395,7 +417,12 @@ _BINARY_SENSOR_SCHEMA = ( cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( mqtt.MQTTBinarySensorComponent ), - cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean, + cv.Exclusive( + CONF_PUBLISH_INITIAL_STATE, CONF_TRIGGER_ON_INITIAL_STATE + ): validate_publish_initial_state, + cv.Exclusive( + CONF_TRIGGER_ON_INITIAL_STATE, CONF_TRIGGER_ON_INITIAL_STATE + ): cv.boolean, cv.Optional(CONF_DEVICE_CLASS): validate_device_class, cv.Optional(CONF_FILTERS): validate_filters, cv.Optional(CONF_ON_PRESS): automation.validate_automation( @@ -454,6 +481,11 @@ _BINARY_SENSOR_SCHEMA = ( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), } ), + cv.Optional(CONF_ON_STATE_CHANGE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateChangeTrigger), + } + ), } ) ) @@ -493,8 +525,10 @@ async def setup_binary_sensor_core_(var, config): if (device_class := config.get(CONF_DEVICE_CLASS)) is not None: cg.add(var.set_device_class(device_class)) - if publish_initial_state := config.get(CONF_PUBLISH_INITIAL_STATE): - cg.add(var.set_publish_initial_state(publish_initial_state)) + trigger = config.get(CONF_TRIGGER_ON_INITIAL_STATE, False) or config.get( + CONF_PUBLISH_INITIAL_STATE, False + ) + cg.add(var.set_trigger_on_initial_state(trigger)) if inverted := config.get(CONF_INVERTED): cg.add(var.set_inverted(inverted)) if filters_config := config.get(CONF_FILTERS): @@ -542,6 +576,17 @@ async def setup_binary_sensor_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [(bool, "x")], conf) + for conf in config.get(CONF_ON_STATE_CHANGE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation( + trigger, + [ + (cg.optional.template(bool), "x_previous"), + (cg.optional.template(bool), "x"), + ], + conf, + ) + if mqtt_id := config.get(CONF_MQTT_ID): mqtt_ = cg.new_Pvariable(mqtt_id, var) await mqtt.register_mqtt_component(mqtt_, config) @@ -554,6 +599,7 @@ async def register_binary_sensor(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_binary_sensor(var)) + CORE.register_platform_component("binary_sensor", var) await setup_binary_sensor_core_(var, config) @@ -590,3 +636,18 @@ async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args) async def to_code(config): cg.add_define("USE_BINARY_SENSOR") cg.add_global(binary_sensor_ns.using) + + +@automation.register_action( + "binary_sensor.invalidate_state", + BinarySensorInvalidateAction, + cv.maybe_simple_value( + { + cv.Required(CONF_ID): cv.use_id(BinarySensor), + }, + key=CONF_ID, + ), +) +async def binary_sensor_invalidate_state_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/binary_sensor/automation.cpp b/esphome/components/binary_sensor/automation.cpp index c2e76246aa..64a0d3db8d 100644 --- a/esphome/components/binary_sensor/automation.cpp +++ b/esphome/components/binary_sensor/automation.cpp @@ -68,8 +68,7 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) { *this->at_index_ = *this->at_index_ + 1; } void binary_sensor::MultiClickTrigger::schedule_cooldown_() { - ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %" PRIu32 " ms...", - this->invalid_cooldown_); + ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %" PRIu32 " ms", this->invalid_cooldown_); this->is_in_cooldown_ = true; this->set_timeout("cooldown", this->invalid_cooldown_, [this]() { ESP_LOGV(TAG, "Multi Click: Cooldown ended, matching is now enabled again."); diff --git a/esphome/components/binary_sensor/automation.h b/esphome/components/binary_sensor/automation.h index 12b07a05e3..b46436dc41 100644 --- a/esphome/components/binary_sensor/automation.h +++ b/esphome/components/binary_sensor/automation.h @@ -96,7 +96,7 @@ class MultiClickTrigger : public Trigger<>, public Component { : parent_(parent), timing_(std::move(timing)) {} void setup() override { - this->last_state_ = this->parent_->state; + this->last_state_ = this->parent_->get_state_default(false); auto f = std::bind(&MultiClickTrigger::on_state_, this, std::placeholders::_1); this->parent_->add_on_state_callback(f); } @@ -130,6 +130,14 @@ class StateTrigger : public Trigger { } }; +class StateChangeTrigger : public Trigger, optional > { + public: + explicit StateChangeTrigger(BinarySensor *parent) { + parent->add_full_state_callback( + [this](optional old_state, optional state) { this->trigger(old_state, state); }); + } +}; + template class BinarySensorCondition : public Condition { public: BinarySensorCondition(BinarySensor *parent, bool state) : parent_(parent), state_(state) {} @@ -154,5 +162,15 @@ template class BinarySensorPublishAction : public Action BinarySensor *sensor_; }; +template class BinarySensorInvalidateAction : public Action { + public: + explicit BinarySensorInvalidateAction(BinarySensor *sensor) : sensor_(sensor) {} + + void play(Ts... x) override { this->sensor_->invalidate_state(); } + + protected: + BinarySensor *sensor_; +}; + } // namespace binary_sensor } // namespace esphome diff --git a/esphome/components/binary_sensor/binary_sensor.cpp b/esphome/components/binary_sensor/binary_sensor.cpp index 20604a0b7e..02b83af552 100644 --- a/esphome/components/binary_sensor/binary_sensor.cpp +++ b/esphome/components/binary_sensor/binary_sensor.cpp @@ -7,42 +7,25 @@ namespace binary_sensor { static const char *const TAG = "binary_sensor"; -void BinarySensor::add_on_state_callback(std::function &&callback) { - this->state_callback_.add(std::move(callback)); -} - -void BinarySensor::publish_state(bool state) { - if (!this->publish_dedup_.next(state)) - return; +void BinarySensor::publish_state(bool new_state) { if (this->filter_list_ == nullptr) { - this->send_state_internal(state, false); + this->send_state_internal(new_state); } else { - this->filter_list_->input(state, false); + this->filter_list_->input(new_state); } } -void BinarySensor::publish_initial_state(bool state) { - if (!this->publish_dedup_.next(state)) - return; - if (this->filter_list_ == nullptr) { - this->send_state_internal(state, true); - } else { - this->filter_list_->input(state, true); +void BinarySensor::publish_initial_state(bool new_state) { + this->invalidate_state(); + this->publish_state(new_state); +} +void BinarySensor::send_state_internal(bool new_state) { + // copy the new state to the visible property for backwards compatibility, before any callbacks + this->state = new_state; + // Note that set_state_ de-dups and will only trigger callbacks if the state has actually changed + if (this->set_state_(new_state)) { + ESP_LOGD(TAG, "'%s': New state is %s", this->get_name().c_str(), ONOFF(new_state)); } } -void BinarySensor::send_state_internal(bool state, bool is_initial) { - if (is_initial) { - ESP_LOGD(TAG, "'%s': Sending initial state %s", this->get_name().c_str(), ONOFF(state)); - } else { - ESP_LOGD(TAG, "'%s': Sending state %s", this->get_name().c_str(), ONOFF(state)); - } - this->has_state_ = true; - this->state = state; - if (!is_initial || this->publish_initial_state_) { - this->state_callback_.call(state); - } -} - -BinarySensor::BinarySensor() : state(false) {} void BinarySensor::add_filter(Filter *filter) { filter->parent_ = this; @@ -60,7 +43,6 @@ void BinarySensor::add_filters(const std::vector &filters) { this->add_filter(filter); } } -bool BinarySensor::has_state() const { return this->has_state_; } bool BinarySensor::is_status_binary_sensor() const { return false; } } // namespace binary_sensor diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index 57cae9e2f5..d61be7a49b 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -1,6 +1,5 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" #include "esphome/components/binary_sensor/filter.h" @@ -34,52 +33,39 @@ namespace binary_sensor { * The sub classes should notify the front-end of new states via the publish_state() method which * handles inverted inputs for you. */ -class BinarySensor : public EntityBase, public EntityBase_DeviceClass { +class BinarySensor : public StatefulEntityBase, public EntityBase_DeviceClass { public: - explicit BinarySensor(); - - /** Add a callback to be notified of state changes. - * - * @param callback The void(bool) callback. - */ - void add_on_state_callback(std::function &&callback); + explicit BinarySensor(){}; /** Publish a new state to the front-end. * - * @param state The new state. + * @param new_state The new state. */ - void publish_state(bool state); + void publish_state(bool new_state); /** Publish the initial state, this will not make the callback manager send callbacks * and is meant only for the initial state on boot. * - * @param state The new state. + * @param new_state The new state. */ - void publish_initial_state(bool state); - - /// The current reported state of the binary sensor. - bool state{false}; + void publish_initial_state(bool new_state); void add_filter(Filter *filter); void add_filters(const std::vector &filters); - void set_publish_initial_state(bool publish_initial_state) { this->publish_initial_state_ = publish_initial_state; } - // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) - void send_state_internal(bool state, bool is_initial); + void send_state_internal(bool new_state); /// Return whether this binary sensor has outputted a state. - virtual bool has_state() const; - virtual bool is_status_binary_sensor() const; + // For backward compatibility, provide an accessible property + + bool state{}; + protected: - CallbackManager state_callback_{}; Filter *filter_list_{nullptr}; - bool has_state_{false}; - bool publish_initial_state_{false}; - Deduplicator publish_dedup_; }; class BinarySensorInitiallyOff : public BinarySensor { diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp index 8f94b108ac..41d0553b35 100644 --- a/esphome/components/binary_sensor/filter.cpp +++ b/esphome/components/binary_sensor/filter.cpp @@ -9,37 +9,36 @@ namespace binary_sensor { static const char *const TAG = "sensor.filter"; -void Filter::output(bool value, bool is_initial) { +void Filter::output(bool value) { + if (this->next_ == nullptr) { + this->parent_->send_state_internal(value); + } else { + this->next_->input(value); + } +} +void Filter::input(bool value) { if (!this->dedup_.next(value)) return; - - if (this->next_ == nullptr) { - this->parent_->send_state_internal(value, is_initial); - } else { - this->next_->input(value, is_initial); - } -} -void Filter::input(bool value, bool is_initial) { - auto b = this->new_value(value, is_initial); + auto b = this->new_value(value); if (b.has_value()) { - this->output(*b, is_initial); + this->output(*b); } } -optional DelayedOnOffFilter::new_value(bool value, bool is_initial) { +optional DelayedOnOffFilter::new_value(bool value) { if (value) { - this->set_timeout("ON_OFF", this->on_delay_.value(), [this, is_initial]() { this->output(true, is_initial); }); + this->set_timeout("ON_OFF", this->on_delay_.value(), [this]() { this->output(true); }); } else { - this->set_timeout("ON_OFF", this->off_delay_.value(), [this, is_initial]() { this->output(false, is_initial); }); + this->set_timeout("ON_OFF", this->off_delay_.value(), [this]() { this->output(false); }); } return {}; } float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; } -optional DelayedOnFilter::new_value(bool value, bool is_initial) { +optional DelayedOnFilter::new_value(bool value) { if (value) { - this->set_timeout("ON", this->delay_.value(), [this, is_initial]() { this->output(true, is_initial); }); + this->set_timeout("ON", this->delay_.value(), [this]() { this->output(true); }); return {}; } else { this->cancel_timeout("ON"); @@ -49,9 +48,9 @@ optional DelayedOnFilter::new_value(bool value, bool is_initial) { float DelayedOnFilter::get_setup_priority() const { return setup_priority::HARDWARE; } -optional DelayedOffFilter::new_value(bool value, bool is_initial) { +optional DelayedOffFilter::new_value(bool value) { if (!value) { - this->set_timeout("OFF", this->delay_.value(), [this, is_initial]() { this->output(false, is_initial); }); + this->set_timeout("OFF", this->delay_.value(), [this]() { this->output(false); }); return {}; } else { this->cancel_timeout("OFF"); @@ -61,11 +60,11 @@ optional DelayedOffFilter::new_value(bool value, bool is_initial) { float DelayedOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; } -optional InvertFilter::new_value(bool value, bool is_initial) { return !value; } +optional InvertFilter::new_value(bool value) { return !value; } AutorepeatFilter::AutorepeatFilter(std::vector timings) : timings_(std::move(timings)) {} -optional AutorepeatFilter::new_value(bool value, bool is_initial) { +optional AutorepeatFilter::new_value(bool value) { if (value) { // Ignore if already running if (this->active_timing_ != 0) @@ -101,7 +100,7 @@ void AutorepeatFilter::next_timing_() { void AutorepeatFilter::next_value_(bool val) { const AutorepeatFilterTiming &timing = this->timings_[this->active_timing_ - 2]; - this->output(val, false); // This is at least the second one so not initial + this->output(val); // This is at least the second one so not initial this->set_timeout("ON_OFF", val ? timing.time_on : timing.time_off, [this, val]() { this->next_value_(!val); }); } @@ -109,18 +108,18 @@ float AutorepeatFilter::get_setup_priority() const { return setup_priority::HARD LambdaFilter::LambdaFilter(std::function(bool)> f) : f_(std::move(f)) {} -optional LambdaFilter::new_value(bool value, bool is_initial) { return this->f_(value); } +optional LambdaFilter::new_value(bool value) { return this->f_(value); } -optional SettleFilter::new_value(bool value, bool is_initial) { +optional SettleFilter::new_value(bool value) { if (!this->steady_) { - this->set_timeout("SETTLE", this->delay_.value(), [this, value, is_initial]() { + this->set_timeout("SETTLE", this->delay_.value(), [this, value]() { this->steady_ = true; - this->output(value, is_initial); + this->output(value); }); return {}; } else { this->steady_ = false; - this->output(value, is_initial); + this->output(value); this->set_timeout("SETTLE", this->delay_.value(), [this]() { this->steady_ = true; }); return value; } diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index f7342db2fb..65838da49d 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -14,11 +14,11 @@ class BinarySensor; class Filter { public: - virtual optional new_value(bool value, bool is_initial) = 0; + virtual optional new_value(bool value) = 0; - void input(bool value, bool is_initial); + void input(bool value); - void output(bool value, bool is_initial); + void output(bool value); protected: friend BinarySensor; @@ -30,7 +30,7 @@ class Filter { class DelayedOnOffFilter : public Filter, public Component { public: - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; float get_setup_priority() const override; @@ -44,7 +44,7 @@ class DelayedOnOffFilter : public Filter, public Component { class DelayedOnFilter : public Filter, public Component { public: - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; float get_setup_priority() const override; @@ -56,7 +56,7 @@ class DelayedOnFilter : public Filter, public Component { class DelayedOffFilter : public Filter, public Component { public: - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; float get_setup_priority() const override; @@ -68,7 +68,7 @@ class DelayedOffFilter : public Filter, public Component { class InvertFilter : public Filter { public: - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; }; struct AutorepeatFilterTiming { @@ -86,7 +86,7 @@ class AutorepeatFilter : public Filter, public Component { public: explicit AutorepeatFilter(std::vector timings); - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; float get_setup_priority() const override; @@ -102,7 +102,7 @@ class LambdaFilter : public Filter { public: explicit LambdaFilter(std::function(bool)> f); - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; protected: std::function(bool)> f_; @@ -110,7 +110,7 @@ class LambdaFilter : public Filter { class SettleFilter : public Filter, public Component { public: - optional new_value(bool value, bool is_initial) override; + optional new_value(bool value) override; float get_setup_priority() const override; diff --git a/esphome/components/bl0906/bl0906.cpp b/esphome/components/bl0906/bl0906.cpp index bddb62ff64..e48715010c 100644 --- a/esphome/components/bl0906/bl0906.cpp +++ b/esphome/components/bl0906/bl0906.cpp @@ -100,7 +100,7 @@ void BL0906::handle_actions_() { for (int i = 0; i < this->action_queue_.size(); i++) { ptr_func = this->action_queue_[i]; if (ptr_func) { - ESP_LOGI(TAG, "HandleActionCallback[%d]...", i); + ESP_LOGI(TAG, "HandleActionCallback[%d]", i); (this->*ptr_func)(); } } diff --git a/esphome/components/bl0942/bl0942.cpp b/esphome/components/bl0942/bl0942.cpp index e6f96c1b19..86eff57147 100644 --- a/esphome/components/bl0942/bl0942.cpp +++ b/esphome/components/bl0942/bl0942.cpp @@ -196,14 +196,17 @@ void BL0942::received_package_(DataPacket *data) { } void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity) - ESP_LOGCONFIG(TAG, "BL0942:"); - ESP_LOGCONFIG(TAG, " Reset: %s", TRUEFALSE(this->reset_)); - ESP_LOGCONFIG(TAG, " Address: %d", this->address_); - ESP_LOGCONFIG(TAG, " Nominal line frequency: %d Hz", this->line_freq_); - ESP_LOGCONFIG(TAG, " Current reference: %f", this->current_reference_); - ESP_LOGCONFIG(TAG, " Energy reference: %f", this->energy_reference_); - ESP_LOGCONFIG(TAG, " Power reference: %f", this->power_reference_); - ESP_LOGCONFIG(TAG, " Voltage reference: %f", this->voltage_reference_); + ESP_LOGCONFIG(TAG, + "BL0942:\n" + " Reset: %s\n" + " Address: %d\n" + " Nominal line frequency: %d Hz\n" + " Current reference: %f\n" + " Energy reference: %f\n" + " Power reference: %f\n" + " Voltage reference: %f", + TRUEFALSE(this->reset_), this->address_, this->line_freq_, this->current_reference_, + this->energy_reference_, this->power_reference_, this->voltage_reference_); LOG_SENSOR("", "Voltage", this->voltage_sensor_); LOG_SENSOR("", "Current", this->current_sensor_); LOG_SENSOR("", "Power", this->power_sensor_); diff --git a/esphome/components/ble_client/__init__.py b/esphome/components/ble_client/__init__.py index 37f8ea32b3..a88172ca87 100644 --- a/esphome/components/ble_client/__init__.py +++ b/esphome/components/ble_client/__init__.py @@ -1,7 +1,8 @@ from esphome import automation from esphome.automation import maybe_simple_id import esphome.codegen as cg -from esphome.components import esp32_ble_client, esp32_ble_tracker +from esphome.components import esp32_ble, esp32_ble_client, esp32_ble_tracker +from esphome.components.esp32_ble import BTLoggers import esphome.config_validation as cv from esphome.const import ( CONF_CHARACTERISTIC_UUID, @@ -287,6 +288,9 @@ async def remove_bond_to_code(config, action_id, template_arg, args): async def to_code(config): + # Register the loggers this component needs + esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await esp32_ble_tracker.register_client(var, config) diff --git a/esphome/components/ble_client/output/ble_binary_output.cpp b/esphome/components/ble_client/output/ble_binary_output.cpp index 3f05bc4b84..ce67193be7 100644 --- a/esphome/components/ble_client/output/ble_binary_output.cpp +++ b/esphome/components/ble_client/output/ble_binary_output.cpp @@ -10,9 +10,12 @@ static const char *const TAG = "ble_binary_output"; void BLEBinaryOutput::dump_config() { ESP_LOGCONFIG(TAG, "BLE Binary Output:"); - ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent_->address_str().c_str()); - ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Characteristic UUID: %s", this->char_uuid_.to_string().c_str()); + ESP_LOGCONFIG(TAG, + " MAC address : %s\n" + " Service UUID : %s\n" + " Characteristic UUID: %s", + this->parent_->address_str().c_str(), this->service_uuid_.to_string().c_str(), + this->char_uuid_.to_string().c_str()); LOG_BINARY_OUTPUT(this); } diff --git a/esphome/components/ble_client/sensor/ble_sensor.cpp b/esphome/components/ble_client/sensor/ble_sensor.cpp index 43f61f5304..f91b07fee2 100644 --- a/esphome/components/ble_client/sensor/ble_sensor.cpp +++ b/esphome/components/ble_client/sensor/ble_sensor.cpp @@ -1,7 +1,7 @@ #include "ble_sensor.h" -#include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" #ifdef USE_ESP32 @@ -15,11 +15,14 @@ void BLESensor::loop() {} void BLESensor::dump_config() { LOG_SENSOR("", "BLE Sensor", this); - ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent()->address_str().c_str()); - ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Characteristic UUID: %s", this->char_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Descriptor UUID : %s", this->descr_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Notifications : %s", YESNO(this->notify_)); + ESP_LOGCONFIG(TAG, + " MAC address : %s\n" + " Service UUID : %s\n" + " Characteristic UUID: %s\n" + " Descriptor UUID : %s\n" + " Notifications : %s", + this->parent()->address_str().c_str(), this->service_uuid_.to_string().c_str(), + this->char_uuid_.to_string().c_str(), this->descr_uuid_.to_string().c_str(), YESNO(this->notify_)); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/ble_client/text_sensor/ble_text_sensor.cpp b/esphome/components/ble_client/text_sensor/ble_text_sensor.cpp index 33938ee7b7..5083e235c6 100644 --- a/esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +++ b/esphome/components/ble_client/text_sensor/ble_text_sensor.cpp @@ -18,11 +18,14 @@ void BLETextSensor::loop() {} void BLETextSensor::dump_config() { LOG_TEXT_SENSOR("", "BLE Text Sensor", this); - ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent()->address_str().c_str()); - ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Characteristic UUID: %s", this->char_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Descriptor UUID : %s", this->descr_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Notifications : %s", YESNO(this->notify_)); + ESP_LOGCONFIG(TAG, + " MAC address : %s\n" + " Service UUID : %s\n" + " Characteristic UUID: %s\n" + " Descriptor UUID : %s\n" + " Notifications : %s", + this->parent()->address_str().c_str(), this->service_uuid_.to_string().c_str(), + this->char_uuid_.to_string().c_str(), this->descr_uuid_.to_string().c_str(), YESNO(this->notify_)); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/bluetooth_proxy/__init__.py b/esphome/components/bluetooth_proxy/__init__.py index 04ac9116c7..5c144cadcc 100644 --- a/esphome/components/bluetooth_proxy/__init__.py +++ b/esphome/components/bluetooth_proxy/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg -from esphome.components import esp32_ble_client, esp32_ble_tracker +from esphome.components import esp32_ble, esp32_ble_client, esp32_ble_tracker from esphome.components.esp32 import add_idf_sdkconfig_option +from esphome.components.esp32_ble import BTLoggers import esphome.config_validation as cv from esphome.const import CONF_ACTIVE, CONF_ID @@ -77,6 +78,9 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): + # Register the loggers this component needs + esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.L2CAP, BTLoggers.SMP) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 3c5c2bd438..44d434802c 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -75,7 +75,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga resp.data.reserve(param->read.value_len); // Use bulk insert instead of individual push_backs resp.data.insert(resp.data.end(), param->read.value, param->read.value + param->read.value_len); - this->proxy_->get_api_connection()->send_bluetooth_gatt_read_response(resp); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_WRITE_CHAR_EVT: @@ -89,7 +89,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTWriteResponse resp; resp.address = this->address_; resp.handle = param->write.handle; - this->proxy_->get_api_connection()->send_bluetooth_gatt_write_response(resp); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: { @@ -103,7 +103,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTNotifyResponse resp; resp.address = this->address_; resp.handle = param->unreg_for_notify.handle; - this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_response(resp); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_REG_FOR_NOTIFY_EVT: { @@ -116,7 +116,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTNotifyResponse resp; resp.address = this->address_; resp.handle = param->reg_for_notify.handle; - this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_response(resp); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_NOTIFY_EVT: { @@ -128,7 +128,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga resp.data.reserve(param->notify.value_len); // Use bulk insert instead of individual push_backs resp.data.insert(resp.data.end(), param->notify.value, param->notify.value + param->notify.value_len); - this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_data_response(resp); + this->proxy_->get_api_connection()->send_message(resp); break; } default: diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index d8b2111cb0..7aeb818306 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -39,7 +39,7 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta resp.state = static_cast(state); resp.mode = this->parent_->get_scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE : api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE; - this->api_connection_->send_bluetooth_scanner_state_response(resp); + this->api_connection_->send_message(resp); } bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { @@ -103,7 +103,7 @@ void BluetoothProxy::flush_pending_advertisements() { api::BluetoothLERawAdvertisementsResponse resp; resp.advertisements.swap(batch_buffer); - this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp); + this->api_connection_->send_message(resp); } void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) { @@ -141,14 +141,16 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi manufacturer_data.data.assign(data.data.begin(), data.data.end()); } - this->api_connection_->send_bluetooth_le_advertisement(resp); + this->api_connection_->send_message(resp); } void BluetoothProxy::dump_config() { ESP_LOGCONFIG(TAG, "Bluetooth Proxy:"); - ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_)); - ESP_LOGCONFIG(TAG, " Connections: %d", this->connections_.size()); - ESP_LOGCONFIG(TAG, " Raw advertisements: %s", YESNO(this->raw_advertisements_)); + ESP_LOGCONFIG(TAG, + " Active: %s\n" + " Connections: %d\n" + " Raw advertisements: %s", + YESNO(this->active_), this->connections_.size(), YESNO(this->raw_advertisements_)); } int BluetoothProxy::get_bluetooth_connections_free() { @@ -300,7 +302,7 @@ void BluetoothProxy::loop() { service_resp.characteristics.push_back(std::move(characteristic_resp)); } resp.services.push_back(std::move(service_resp)); - this->api_connection_->send_bluetooth_gatt_get_services_response(resp); + this->api_connection_->send_message(resp); } } } @@ -453,7 +455,7 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest call.success = ret == ESP_OK; call.error = ret; - this->api_connection_->send_bluetooth_device_clear_cache_response(call); + this->api_connection_->send_message(call); break; } @@ -577,7 +579,7 @@ void BluetoothProxy::send_device_connection(uint64_t address, bool connected, ui call.connected = connected; call.mtu = mtu; call.error = error; - this->api_connection_->send_bluetooth_device_connection_response(call); + this->api_connection_->send_message(call); } void BluetoothProxy::send_connections_free() { if (this->api_connection_ == nullptr) @@ -590,7 +592,7 @@ void BluetoothProxy::send_connections_free() { call.allocated.push_back(connection->address_); } } - this->api_connection_->send_bluetooth_connections_free_response(call); + this->api_connection_->send_message(call); } void BluetoothProxy::send_gatt_services_done(uint64_t address) { @@ -598,7 +600,7 @@ void BluetoothProxy::send_gatt_services_done(uint64_t address) { return; api::BluetoothGATTGetServicesDoneResponse call; call.address = address; - this->api_connection_->send_bluetooth_gatt_get_services_done_response(call); + this->api_connection_->send_message(call); } void BluetoothProxy::send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) { @@ -608,7 +610,7 @@ void BluetoothProxy::send_gatt_error(uint64_t address, uint16_t handle, esp_err_ call.address = address; call.handle = handle; call.error = error; - this->api_connection_->send_bluetooth_gatt_error_response(call); + this->api_connection_->send_message(call); } void BluetoothProxy::send_device_pairing(uint64_t address, bool paired, esp_err_t error) { @@ -617,7 +619,7 @@ void BluetoothProxy::send_device_pairing(uint64_t address, bool paired, esp_err_ call.paired = paired; call.error = error; - this->api_connection_->send_bluetooth_device_pairing_response(call); + this->api_connection_->send_message(call); } void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_err_t error) { @@ -626,7 +628,7 @@ void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_e call.success = success; call.error = error; - this->api_connection_->send_bluetooth_device_unpairing_response(call); + this->api_connection_->send_message(call); } void BluetoothProxy::bluetooth_scanner_set_mode(bool active) { diff --git a/esphome/components/bme280_base/bme280_base.cpp b/esphome/components/bme280_base/bme280_base.cpp index c73b48589d..142a03fe1c 100644 --- a/esphome/components/bme280_base/bme280_base.cpp +++ b/esphome/components/bme280_base/bme280_base.cpp @@ -207,7 +207,7 @@ inline uint8_t oversampling_to_time(BME280Oversampling over_sampling) { return ( void BME280Component::update() { // Enable sensor - ESP_LOGV(TAG, "Sending conversion request..."); + ESP_LOGV(TAG, "Sending conversion request"); uint8_t meas_value = 0; meas_value |= (this->temperature_oversampling_ & 0b111) << 5; meas_value |= (this->pressure_oversampling_ & 0b111) << 2; diff --git a/esphome/components/bme680/sensor.py b/esphome/components/bme680/sensor.py index 5937ac6ad8..abdf6d3969 100644 --- a/esphome/components/bme680/sensor.py +++ b/esphome/components/bme680/sensor.py @@ -13,7 +13,7 @@ from esphome.const import ( CONF_PRESSURE, CONF_TEMPERATURE, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_PRESSURE, + DEVICE_CLASS_ATMOSPHERIC_PRESSURE, DEVICE_CLASS_TEMPERATURE, ICON_GAS_CYLINDER, STATE_CLASS_MEASUREMENT, @@ -71,7 +71,7 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_PRESSURE): sensor.sensor_schema( unit_of_measurement=UNIT_HECTOPASCAL, accuracy_decimals=1, - device_class=DEVICE_CLASS_PRESSURE, + device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE, state_class=STATE_CLASS_MEASUREMENT, ).extend( { diff --git a/esphome/components/bme680_bsec/bme680_bsec.cpp b/esphome/components/bme680_bsec/bme680_bsec.cpp index 92642173dc..562d39e7b5 100644 --- a/esphome/components/bme680_bsec/bme680_bsec.cpp +++ b/esphome/components/bme680_bsec/bme680_bsec.cpp @@ -1,6 +1,6 @@ #include "bme680_bsec.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include namespace esphome { @@ -159,11 +159,15 @@ void BME680BSECComponent::dump_config() { this->bme680_status_); } - ESP_LOGCONFIG(TAG, " Temperature Offset: %.2f", this->temperature_offset_); - ESP_LOGCONFIG(TAG, " IAQ Mode: %s", this->iaq_mode_ == IAQ_MODE_STATIC ? "Static" : "Mobile"); - ESP_LOGCONFIG(TAG, " Supply Voltage: %sV", this->supply_voltage_ == SUPPLY_VOLTAGE_3V3 ? "3.3" : "1.8"); - ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->sample_rate_)); - ESP_LOGCONFIG(TAG, " State Save Interval: %ims", this->state_save_interval_ms_); + ESP_LOGCONFIG(TAG, + " Temperature Offset: %.2f\n" + " IAQ Mode: %s\n" + " Supply Voltage: %sV\n" + " Sample Rate: %s\n" + " State Save Interval: %ims", + this->temperature_offset_, this->iaq_mode_ == IAQ_MODE_STATIC ? "Static" : "Mobile", + this->supply_voltage_ == SUPPLY_VOLTAGE_3V3 ? "3.3" : "1.8", + BME680_BSEC_SAMPLE_RATE_LOG(this->sample_rate_), this->state_save_interval_ms_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->temperature_sample_rate_)); diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 5107b0bfcd..8d3ae76e3f 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -15,6 +15,8 @@ from esphome.const import ( DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, ICON_GAS_CYLINDER, ICON_GAUGE, + ICON_THERMOMETER, + ICON_WATER_PERCENT, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_HECTOPASCAL, @@ -27,11 +29,11 @@ from . import CONF_BME680_BSEC_ID, SAMPLE_RATE_OPTIONS, BME680BSECComponent DEPENDENCIES = ["bme680_bsec"] -CONF_IAQ = "iaq" -CONF_CO2_EQUIVALENT = "co2_equivalent" CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent" -UNIT_IAQ = "IAQ" +CONF_CO2_EQUIVALENT = "co2_equivalent" +CONF_IAQ = "iaq" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" +UNIT_IAQ = "IAQ" TYPES = [ CONF_TEMPERATURE, @@ -49,6 +51,7 @@ CONFIG_SCHEMA = cv.Schema( cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, + icon=ICON_THERMOMETER, accuracy_decimals=1, device_class=DEVICE_CLASS_TEMPERATURE, state_class=STATE_CLASS_MEASUREMENT, @@ -65,6 +68,7 @@ CONFIG_SCHEMA = cv.Schema( ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( unit_of_measurement=UNIT_PERCENT, + icon=ICON_WATER_PERCENT, accuracy_decimals=1, device_class=DEVICE_CLASS_HUMIDITY, state_class=STATE_CLASS_MEASUREMENT, diff --git a/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp b/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp index 6b3663cdc8..a23711c4ca 100644 --- a/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +++ b/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp @@ -58,13 +58,13 @@ void BME68xBSEC2Component::setup() { } void BME68xBSEC2Component::dump_config() { - ESP_LOGCONFIG(TAG, "BME68X via BSEC2:"); - - ESP_LOGCONFIG(TAG, " BSEC2 version: %d.%d.%d.%d", this->version_.major, this->version_.minor, - this->version_.major_bugfix, this->version_.minor_bugfix); - - ESP_LOGCONFIG(TAG, " BSEC2 configuration blob:"); - ESP_LOGCONFIG(TAG, " Configured: %s", YESNO(this->bsec2_blob_configured_)); + ESP_LOGCONFIG(TAG, + "BME68X via BSEC2:\n" + " BSEC2 version: %d.%d.%d.%d\n" + " BSEC2 configuration blob:\n" + " Configured: %s", + this->version_.major, this->version_.minor, this->version_.major_bugfix, this->version_.minor_bugfix, + YESNO(this->bsec2_blob_configured_)); if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) { ESP_LOGCONFIG(TAG, " Size: %" PRIu32, this->bsec2_configuration_length_); } @@ -77,11 +77,14 @@ void BME68xBSEC2Component::dump_config() { if (this->algorithm_output_ != ALGORITHM_OUTPUT_IAQ) { ESP_LOGCONFIG(TAG, " Algorithm output: %s", BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(this->algorithm_output_)); } - ESP_LOGCONFIG(TAG, " Operating age: %s", BME68X_BSEC2_OPERATING_AGE_LOG(this->operating_age_)); - ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->sample_rate_)); - ESP_LOGCONFIG(TAG, " Voltage: %s", BME68X_BSEC2_VOLTAGE_LOG(this->voltage_)); - ESP_LOGCONFIG(TAG, " State save interval: %ims", this->state_save_interval_ms_); - ESP_LOGCONFIG(TAG, " Temperature offset: %.2f", this->temperature_offset_); + ESP_LOGCONFIG(TAG, + " Operating age: %s\n" + " Sample rate: %s\n" + " Voltage: %s\n" + " State save interval: %ims\n" + " Temperature offset: %.2f", + BME68X_BSEC2_OPERATING_AGE_LOG(this->operating_age_), BME68X_BSEC2_SAMPLE_RATE_LOG(this->sample_rate_), + BME68X_BSEC2_VOLTAGE_LOG(this->voltage_), this->state_save_interval_ms_, this->temperature_offset_); #ifdef USE_SENSOR LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); diff --git a/esphome/components/bme68x_bsec2/sensor.py b/esphome/components/bme68x_bsec2/sensor.py index 419f47b248..c7dca437d7 100644 --- a/esphome/components/bme68x_bsec2/sensor.py +++ b/esphome/components/bme68x_bsec2/sensor.py @@ -9,8 +9,10 @@ from esphome.const import ( CONF_SAMPLE_RATE, CONF_TEMPERATURE, DEVICE_CLASS_ATMOSPHERIC_PRESSURE, + DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, ICON_GAS_CYLINDER, ICON_GAUGE, ICON_THERMOMETER, @@ -32,7 +34,6 @@ CONF_CO2_EQUIVALENT = "co2_equivalent" CONF_IAQ = "iaq" CONF_IAQ_STATIC = "iaq_static" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" -ICON_TEST_TUBE = "mdi:test-tube" UNIT_IAQ = "IAQ" TYPES = [ @@ -61,7 +62,6 @@ CONFIG_SCHEMA = cv.Schema( ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( unit_of_measurement=UNIT_HECTOPASCAL, - icon=ICON_GAUGE, accuracy_decimals=1, device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE, state_class=STATE_CLASS_MEASUREMENT, @@ -102,14 +102,14 @@ CONFIG_SCHEMA = cv.Schema( ), cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema( unit_of_measurement=UNIT_PARTS_PER_MILLION, - icon=ICON_TEST_TUBE, accuracy_decimals=1, + device_class=DEVICE_CLASS_CARBON_DIOXIDE, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema( unit_of_measurement=UNIT_PARTS_PER_MILLION, - icon=ICON_TEST_TUBE, accuracy_decimals=1, + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, state_class=STATE_CLASS_MEASUREMENT, ), } diff --git a/esphome/components/bmi160/bmi160.cpp b/esphome/components/bmi160/bmi160.cpp index 67106cc20c..aca42f1b52 100644 --- a/esphome/components/bmi160/bmi160.cpp +++ b/esphome/components/bmi160/bmi160.cpp @@ -126,37 +126,37 @@ void BMI160Component::internal_setup_(int stage) { return; } - ESP_LOGV(TAG, " Bringing accelerometer out of sleep..."); + ESP_LOGV(TAG, " Bringing accelerometer out of sleep"); if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::ACCL_SET_PMU_MODE | (uint8_t) AcclPmuMode::NORMAL)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Waiting for accelerometer to wake up..."); + ESP_LOGV(TAG, " Waiting for accelerometer to wake up"); // need to wait (max delay in datasheet) because we can't send commands while another is in progress // min 5ms, 10ms this->set_timeout(10, [this]() { this->internal_setup_(1); }); break; case 1: - ESP_LOGV(TAG, " Bringing gyroscope out of sleep..."); + ESP_LOGV(TAG, " Bringing gyroscope out of sleep"); if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::GYRO_SET_PMU_MODE | (uint8_t) GyroPmuMode::NORMAL)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Waiting for gyroscope to wake up..."); + ESP_LOGV(TAG, " Waiting for gyroscope to wake up"); // wait between 51 & 81ms, doing 100 to be safe this->set_timeout(10, [this]() { this->internal_setup_(2); }); break; case 2: - ESP_LOGV(TAG, " Setting up Gyro Config..."); + ESP_LOGV(TAG, " Setting up Gyro Config"); uint8_t gyro_config = (uint8_t) GyroBandwidth::OSR4 | (uint8_t) GyroOuputDataRate::HZ_25; ESP_LOGV(TAG, " Output gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config)); if (!this->write_byte(BMI160_REGISTER_GYRO_CONFIG, gyro_config)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Setting up Gyro Range..."); + ESP_LOGV(TAG, " Setting up Gyro Range"); uint8_t gyro_range = (uint8_t) GyroRange::RANGE_2000_DPS; ESP_LOGV(TAG, " Output gyro_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_range)); if (!this->write_byte(BMI160_REGISTER_GYRO_RANGE, gyro_range)) { @@ -164,7 +164,7 @@ void BMI160Component::internal_setup_(int stage) { return; } - ESP_LOGV(TAG, " Setting up Accel Config..."); + ESP_LOGV(TAG, " Setting up Accel Config"); uint8_t accel_config = (uint8_t) AcclFilterMode::PERF | (uint8_t) AcclBandwidth::RES_AVG16 | (uint8_t) AccelOutputDataRate::HZ_25; ESP_LOGV(TAG, " Output accel_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_config)); @@ -172,7 +172,7 @@ void BMI160Component::internal_setup_(int stage) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Setting up Accel Range..."); + ESP_LOGV(TAG, " Setting up Accel Range"); uint8_t accel_range = (uint8_t) AccelRange::RANGE_16G; ESP_LOGV(TAG, " Output accel_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_range)); if (!this->write_byte(BMI160_REGISTER_ACCEL_RANGE, accel_range)) { @@ -219,7 +219,7 @@ void BMI160Component::update() { return; } - ESP_LOGV(TAG, " Updating BMI160..."); + ESP_LOGV(TAG, " Updating BMI160"); int16_t data[6]; if (this->read_le_int16_(BMI160_REGISTER_DATA_GYRO_X_LSB, data, 6) != i2c::ERROR_OK) { this->status_set_warning(); diff --git a/esphome/components/bmp085/bmp085.cpp b/esphome/components/bmp085/bmp085.cpp index 7f00a915f1..94dc61891b 100644 --- a/esphome/components/bmp085/bmp085.cpp +++ b/esphome/components/bmp085/bmp085.cpp @@ -129,7 +129,7 @@ void BMP085Component::read_pressure_() { this->status_clear_warning(); } bool BMP085Component::set_mode_(uint8_t mode) { - ESP_LOGV(TAG, "Setting mode to 0x%02X...", mode); + ESP_LOGV(TAG, "Setting mode to 0x%02X", mode); return this->write_byte(BMP085_REGISTER_CONTROL, mode); } float BMP085Component::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/bmp280_base/bmp280_base.cpp b/esphome/components/bmp280_base/bmp280_base.cpp index 665707e26c..94b8bd6540 100644 --- a/esphome/components/bmp280_base/bmp280_base.cpp +++ b/esphome/components/bmp280_base/bmp280_base.cpp @@ -155,7 +155,7 @@ inline uint8_t oversampling_to_time(BMP280Oversampling over_sampling) { return ( void BMP280Component::update() { // Enable sensor - ESP_LOGV(TAG, "Sending conversion request..."); + ESP_LOGV(TAG, "Sending conversion request"); uint8_t meas_value = 0; meas_value |= (this->temperature_oversampling_ & 0b111) << 5; meas_value |= (this->pressure_oversampling_ & 0b111) << 2; diff --git a/esphome/components/bmp3xx_base/bmp3xx_base.cpp b/esphome/components/bmp3xx_base/bmp3xx_base.cpp index d35c5fd331..979f354cb2 100644 --- a/esphome/components/bmp3xx_base/bmp3xx_base.cpp +++ b/esphome/components/bmp3xx_base/bmp3xx_base.cpp @@ -73,7 +73,7 @@ void BMP3XXComponent::setup() { ESP_LOGCONFIG(TAG, "Running setup"); // Call the Device base class "initialise" function if (!reset()) { - ESP_LOGE(TAG, "Failed to reset BMP3XX..."); + ESP_LOGE(TAG, "Failed to reset"); this->error_code_ = ERROR_SENSOR_RESET; this->mark_failed(); } @@ -148,8 +148,10 @@ void BMP3XXComponent::setup() { } void BMP3XXComponent::dump_config() { - ESP_LOGCONFIG(TAG, "BMP3XX:"); - ESP_LOGCONFIG(TAG, " Type: %s (0x%X)", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg); + ESP_LOGCONFIG(TAG, + "BMP3XX:\n" + " Type: %s (0x%X)", + LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg); switch (this->error_code_) { case NONE: break; @@ -157,16 +159,14 @@ void BMP3XXComponent::dump_config() { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); break; case ERROR_WRONG_CHIP_ID: - ESP_LOGE( - TAG, - "BMP3XX has wrong chip ID (reported id: 0x%X) - please check if you are really using a BMP 388 or BMP 390", - this->chip_id_.reg); + ESP_LOGE(TAG, "Wrong chip ID (reported id: 0x%X) - please check if you are really using a BMP 388 or BMP 390", + this->chip_id_.reg); break; case ERROR_SENSOR_RESET: - ESP_LOGE(TAG, "BMP3XX failed to reset"); + ESP_LOGE(TAG, "Failed to reset"); break; default: - ESP_LOGE(TAG, "BMP3XX error code %d", (int) this->error_code_); + ESP_LOGE(TAG, "Error code %d", (int) this->error_code_); break; } ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_filter_))); @@ -186,7 +186,7 @@ inline uint8_t oversampling_to_time(Oversampling over_sampling) { return (1 << u void BMP3XXComponent::update() { // Enable sensor - ESP_LOGV(TAG, "Sending conversion request..."); + ESP_LOGV(TAG, "Sending conversion request"); float meas_time = 1.0f; // Ref: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf 3.9.2 meas_time += 2.02f * oversampling_to_time(this->temperature_oversampling_) + 0.163f; @@ -296,7 +296,7 @@ bool BMP3XXComponent::get_pressure(float &pressure) { bool BMP3XXComponent::get_measurements(float &temperature, float &pressure) { // Check if a measurement is ready if (!data_ready()) { - ESP_LOGD(TAG, "BMP3XX Get measurement - data not ready skipping update"); + ESP_LOGD(TAG, "Get measurement - data not ready skipping update"); return false; } diff --git a/esphome/components/bmp581/bmp581.cpp b/esphome/components/bmp581/bmp581.cpp index 30d5b95a46..2204a6af2e 100644 --- a/esphome/components/bmp581/bmp581.cpp +++ b/esphome/components/bmp581/bmp581.cpp @@ -72,22 +72,22 @@ void BMP581Component::dump_config() { case NONE: break; case ERROR_COMMUNICATION_FAILED: - ESP_LOGE(TAG, " Communication with BMP581 failed!"); + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); break; case ERROR_WRONG_CHIP_ID: - ESP_LOGE(TAG, " BMP581 has wrong chip ID - please verify you are using a BMP 581"); + ESP_LOGE(TAG, "Unknown chip ID"); break; case ERROR_SENSOR_RESET: - ESP_LOGE(TAG, " BMP581 failed to reset"); + ESP_LOGE(TAG, "Reset failed"); break; case ERROR_SENSOR_STATUS: - ESP_LOGE(TAG, " BMP581 sensor status failed, there were NVM problems"); + ESP_LOGE(TAG, "Get status failed"); break; case ERROR_PRIME_IIR_FAILED: - ESP_LOGE(TAG, " BMP581's IIR Filter failed to prime with an initial measurement"); + ESP_LOGE(TAG, "IIR Filter failed to prime with initial measurement"); break; default: - ESP_LOGE(TAG, " BMP581 error code %d", (int) this->error_code_); + ESP_LOGE(TAG, "Error %d", (int) this->error_code_); break; } @@ -98,14 +98,20 @@ void BMP581Component::dump_config() { if (this->temperature_sensor_) { LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); - ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_temperature_level_))); - ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_))); + ESP_LOGCONFIG(TAG, + " IIR Filter: %s\n" + " Oversampling: %s", + LOG_STR_ARG(iir_filter_to_str(this->iir_temperature_level_)), + LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_))); } if (this->pressure_sensor_) { LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); - ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_pressure_level_))); - ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_))); + ESP_LOGCONFIG(TAG, + " IIR Filter: %s\n" + " Oversampling: %s", + LOG_STR_ARG(iir_filter_to_str(this->iir_pressure_level_)), + LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_))); } } @@ -130,7 +136,7 @@ void BMP581Component::setup() { // Power-On-Reboot bit is asserted if sensor successfully reset if (!this->reset_()) { - ESP_LOGE(TAG, "BMP581 failed to reset"); + ESP_LOGE(TAG, "Reset failed"); this->error_code_ = ERROR_SENSOR_RESET; this->mark_failed(); @@ -146,7 +152,7 @@ void BMP581Component::setup() { // read chip id from sensor if (!this->read_byte(BMP581_CHIP_ID, &chip_id)) { - ESP_LOGE(TAG, "Failed to read chip id"); + ESP_LOGE(TAG, "Read chip ID failed"); this->error_code_ = ERROR_COMMUNICATION_FAILED; this->mark_failed(); @@ -156,7 +162,7 @@ void BMP581Component::setup() { // verify id if (chip_id != BMP581_ASIC_ID) { - ESP_LOGE(TAG, "Unknown chip ID, is this a BMP581?"); + ESP_LOGE(TAG, "Unknown chip ID"); this->error_code_ = ERROR_WRONG_CHIP_ID; this->mark_failed(); @@ -179,7 +185,7 @@ void BMP581Component::setup() { // verify status_nvm_rdy bit (it is asserted if boot was successful) if (!(this->status_.bit.status_nvm_rdy)) { - ESP_LOGE(TAG, "NVM not ready after boot"); + ESP_LOGE(TAG, "NVM not ready"); this->error_code_ = ERROR_SENSOR_STATUS; this->mark_failed(); @@ -189,7 +195,7 @@ void BMP581Component::setup() { // verify status_nvm_err bit (it is asserted if an error is detected) if (this->status_.bit.status_nvm_err) { - ESP_LOGE(TAG, "NVM error detected on boot"); + ESP_LOGE(TAG, "NVM error detected"); this->error_code_ = ERROR_SENSOR_STATUS; this->mark_failed(); @@ -254,7 +260,7 @@ void BMP581Component::setup() { } if (!this->prime_iir_filter_()) { - ESP_LOGE(TAG, "Failed to prime the IIR filter with an intiial measurement"); + ESP_LOGE(TAG, "Failed to prime the IIR filter with an initial measurement"); this->error_code_ = ERROR_PRIME_IIR_FAILED; this->mark_failed(); @@ -286,10 +292,10 @@ void BMP581Component::update() { // 1) Request a measurement // ////////////////////////////// - ESP_LOGVV(TAG, "Requesting a measurement from sensor"); + ESP_LOGVV(TAG, "Requesting measurement"); if (!this->start_measurement_()) { - ESP_LOGW(TAG, "Failed to request forced measurement of sensor"); + ESP_LOGW(TAG, "Requesting forced measurement failed"); this->status_set_warning(); return; @@ -299,7 +305,7 @@ void BMP581Component::update() { // 2) Wait for measurement to finish (based on oversampling rates) // ////////////////////////////////////////////////////////////////////// - ESP_LOGVV(TAG, "Measurement is expected to take %d ms to complete", this->conversion_time_); + ESP_LOGVV(TAG, "Measurement should take %d ms", this->conversion_time_); this->set_timeout("measurement", this->conversion_time_, [this]() { float temperature = 0.0; @@ -311,14 +317,14 @@ void BMP581Component::update() { if (this->pressure_sensor_) { if (!this->read_temperature_and_pressure_(temperature, pressure)) { - ESP_LOGW(TAG, "Failed to read temperature and pressure measurements, skipping update"); + ESP_LOGW(TAG, "Failed to read temperature and pressure; skipping update"); this->status_set_warning(); return; } } else { if (!this->read_temperature_(temperature)) { - ESP_LOGW(TAG, "Failed to read temperature measurement, skipping update"); + ESP_LOGW(TAG, "Failed to read temperature; skipping update"); this->status_set_warning(); return; @@ -349,7 +355,7 @@ bool BMP581Component::check_data_readiness_() { // - returns data readiness state if (this->odr_config_.bit.pwr_mode == STANDBY_MODE) { - ESP_LOGD(TAG, "Data is not ready, sensor is in standby mode"); + ESP_LOGD(TAG, "Data not ready, sensor is in standby mode"); return false; } @@ -443,7 +449,7 @@ bool BMP581Component::read_temperature_(float &temperature) { // - the measured temperature (in degrees Celsius) if (!this->check_data_readiness_()) { - ESP_LOGW(TAG, "Data from sensor isn't ready, skipping this update"); + ESP_LOGW(TAG, "Data not ready, skipping this update"); this->status_set_warning(); return false; @@ -451,7 +457,7 @@ bool BMP581Component::read_temperature_(float &temperature) { uint8_t data[3]; if (!this->read_bytes(BMP581_MEASUREMENT_DATA, &data[0], 3)) { - ESP_LOGW(TAG, "Failed to read sensor's measurement data"); + ESP_LOGW(TAG, "Failed to read measurement"); this->status_set_warning(); return false; @@ -472,7 +478,7 @@ bool BMP581Component::read_temperature_and_pressure_(float &temperature, float & // - the measured pressure (in Pa) if (!this->check_data_readiness_()) { - ESP_LOGW(TAG, "Data from sensor isn't ready, skipping this update"); + ESP_LOGW(TAG, "Data not ready, skipping this update"); this->status_set_warning(); return false; @@ -480,7 +486,7 @@ bool BMP581Component::read_temperature_and_pressure_(float &temperature, float & uint8_t data[6]; if (!this->read_bytes(BMP581_MEASUREMENT_DATA, &data[0], 6)) { - ESP_LOGW(TAG, "Failed to read sensor's measurement data"); + ESP_LOGW(TAG, "Failed to read measurement"); this->status_set_warning(); return false; diff --git a/esphome/components/bp1658cj/bp1658cj.cpp b/esphome/components/bp1658cj/bp1658cj.cpp index 3a679bd79b..b502a738cd 100644 --- a/esphome/components/bp1658cj/bp1658cj.cpp +++ b/esphome/components/bp1658cj/bp1658cj.cpp @@ -26,8 +26,10 @@ void BP1658CJ::dump_config() { ESP_LOGCONFIG(TAG, "BP1658CJ:"); LOG_PIN(" Data Pin: ", this->data_pin_); LOG_PIN(" Clock Pin: ", this->clock_pin_); - ESP_LOGCONFIG(TAG, " Color Channels Max Power: %u", this->max_power_color_channels_); - ESP_LOGCONFIG(TAG, " White Channels Max Power: %u", this->max_power_white_channels_); + ESP_LOGCONFIG(TAG, + " Color Channels Max Power: %u\n" + " White Channels Max Power: %u", + this->max_power_color_channels_, this->max_power_white_channels_); } void BP1658CJ::loop() { diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index b68334dd98..892bf62f3a 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -108,6 +108,7 @@ async def register_button(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_button(var)) + CORE.register_platform_component("button", var) await setup_button_core_(var, config) diff --git a/esphome/components/cap1188/cap1188.cpp b/esphome/components/cap1188/cap1188.cpp index 2fdcca94c1..af167deb99 100644 --- a/esphome/components/cap1188/cap1188.cpp +++ b/esphome/components/cap1188/cap1188.cpp @@ -52,9 +52,11 @@ void CAP1188Component::dump_config() { ESP_LOGCONFIG(TAG, "CAP1188:"); LOG_I2C_DEVICE(this); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " Product ID: 0x%x", this->cap1188_product_id_); - ESP_LOGCONFIG(TAG, " Manufacture ID: 0x%x", this->cap1188_manufacture_id_); - ESP_LOGCONFIG(TAG, " Revision ID: 0x%x", this->cap1188_revision_); + ESP_LOGCONFIG(TAG, + " Product ID: 0x%x\n" + " Manufacture ID: 0x%x\n" + " Revision ID: 0x%x", + this->cap1188_product_id_, this->cap1188_manufacture_id_, this->cap1188_revision_); switch (this->error_code_) { case COMMUNICATION_FAILED: diff --git a/esphome/components/ccs811/ccs811.cpp b/esphome/components/ccs811/ccs811.cpp index 700e1b4df0..cecb92b3df 100644 --- a/esphome/components/ccs811/ccs811.cpp +++ b/esphome/components/ccs811/ccs811.cpp @@ -1,6 +1,7 @@ #include "ccs811.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ccs811 { diff --git a/esphome/components/chsc6x/chsc6x_touchscreen.cpp b/esphome/components/chsc6x/chsc6x_touchscreen.cpp index 7755b1d229..524fa1eb36 100644 --- a/esphome/components/chsc6x/chsc6x_touchscreen.cpp +++ b/esphome/components/chsc6x/chsc6x_touchscreen.cpp @@ -38,9 +38,11 @@ void CHSC6XTouchscreen::dump_config() { ESP_LOGCONFIG(TAG, "CHSC6X Touchscreen:"); LOG_I2C_DEVICE(this); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); - ESP_LOGCONFIG(TAG, " Touch timeout: %d", this->touch_timeout_); - ESP_LOGCONFIG(TAG, " x_raw_max_: %d", this->x_raw_max_); - ESP_LOGCONFIG(TAG, " y_raw_max_: %d", this->y_raw_max_); + ESP_LOGCONFIG(TAG, + " Touch timeout: %d\n" + " x_raw_max_: %d\n" + " y_raw_max_: %d", + this->touch_timeout_, this->x_raw_max_, this->y_raw_max_); } } // namespace chsc6x diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index 7007dc13af..52938a17d0 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -443,6 +443,7 @@ async def register_climate(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_climate(var)) + CORE.register_platform_component("climate", var) await setup_climate_core_(var, config) diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index bc8d932089..edebc0de69 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -569,17 +569,22 @@ bool Climate::set_custom_preset_(const std::string &preset) { void Climate::dump_traits_(const char *tag) { auto traits = this->get_traits(); ESP_LOGCONFIG(tag, "ClimateTraits:"); - ESP_LOGCONFIG(tag, " [x] Visual settings:"); - ESP_LOGCONFIG(tag, " - Min temperature: %.1f", traits.get_visual_min_temperature()); - ESP_LOGCONFIG(tag, " - Max temperature: %.1f", traits.get_visual_max_temperature()); - ESP_LOGCONFIG(tag, " - Temperature step:"); - ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step()); + ESP_LOGCONFIG(tag, + " [x] Visual settings:\n" + " - Min temperature: %.1f\n" + " - Max temperature: %.1f\n" + " - Temperature step:\n" + " Target: %.1f", + traits.get_visual_min_temperature(), traits.get_visual_max_temperature(), + traits.get_visual_target_temperature_step()); if (traits.get_supports_current_temperature()) { ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step()); } if (traits.get_supports_target_humidity() || traits.get_supports_current_humidity()) { - ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity()); - ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity()); + ESP_LOGCONFIG(tag, + " - Min humidity: %.0f\n" + " - Max humidity: %.0f", + traits.get_visual_min_humidity(), traits.get_visual_max_humidity()); } if (traits.get_supports_two_point_target_temperature()) { ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature"); diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h index d81702fb0c..b31a2eedf6 100644 --- a/esphome/components/climate/climate.h +++ b/esphome/components/climate/climate.h @@ -3,8 +3,8 @@ #include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" -#include "esphome/core/preferences.h" #include "esphome/core/log.h" +#include "esphome/core/preferences.h" #include "climate_mode.h" #include "climate_traits.h" diff --git a/esphome/components/climate_ir/climate_ir.cpp b/esphome/components/climate_ir/climate_ir.cpp index 8175383627..dc8117f6ae 100644 --- a/esphome/components/climate_ir/climate_ir.cpp +++ b/esphome/components/climate_ir/climate_ir.cpp @@ -75,10 +75,13 @@ void ClimateIR::control(const climate::ClimateCall &call) { } void ClimateIR::dump_config() { LOG_CLIMATE("", "IR Climate", this); - ESP_LOGCONFIG(TAG, " Min. Temperature: %.1f°C", this->minimum_temperature_); - ESP_LOGCONFIG(TAG, " Max. Temperature: %.1f°C", this->maximum_temperature_); - ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_)); - ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_)); + ESP_LOGCONFIG(TAG, + " Min. Temperature: %.1f°C\n" + " Max. Temperature: %.1f°C\n" + " Supports HEAT: %s\n" + " Supports COOL: %s", + this->minimum_temperature_, this->maximum_temperature_, YESNO(this->supports_heat_), + YESNO(this->supports_cool_)); } } // namespace climate_ir diff --git a/esphome/components/cm1106/cm1106.cpp b/esphome/components/cm1106/cm1106.cpp index aa19c0664e..109524c04a 100644 --- a/esphome/components/cm1106/cm1106.cpp +++ b/esphome/components/cm1106/cm1106.cpp @@ -38,7 +38,7 @@ void CM1106Component::update() { } if (response[0] != 0x16 || response[1] != 0x05 || response[2] != 0x01) { - ESP_LOGW(TAG, "Got wrong UART response from CM1106: %02X %02X %02X %02X...", response[0], response[1], response[2], + ESP_LOGW(TAG, "Got wrong UART response from CM1106: %02X %02X %02X %02X", response[0], response[1], response[2], response[3]); this->status_set_warning(); return; diff --git a/esphome/components/const/__init__.py b/esphome/components/const/__init__.py index 6af357f23b..66a5fe5d81 100644 --- a/esphome/components/const/__init__.py +++ b/esphome/components/const/__init__.py @@ -3,3 +3,5 @@ CODEOWNERS = ["@esphome/core"] CONF_DRAW_ROUNDING = "draw_rounding" +CONF_ON_STATE_CHANGE = "on_state_change" +CONF_REQUEST_HEADERS = "request_headers" diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index 13f117c3f0..9fe7593eab 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -189,6 +189,7 @@ async def register_cover(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_cover(var)) + CORE.register_platform_component("cover", var) await setup_cover_core_(var, config) diff --git a/esphome/components/cs5460a/cs5460a.cpp b/esphome/components/cs5460a/cs5460a.cpp index 4e045c17be..e3a5941d94 100644 --- a/esphome/components/cs5460a/cs5460a.cpp +++ b/esphome/components/cs5460a/cs5460a.cpp @@ -319,18 +319,23 @@ bool CS5460AComponent::check_status_() { void CS5460AComponent::dump_config() { uint32_t state = this->get_component_state(); - ESP_LOGCONFIG(TAG, "CS5460A:"); - ESP_LOGCONFIG(TAG, " Init status: %s", + ESP_LOGCONFIG(TAG, + "CS5460A:\n" + " Init status: %s", state == COMPONENT_STATE_LOOP ? "OK" : (state == COMPONENT_STATE_FAILED ? "failed" : "other")); LOG_PIN(" CS Pin: ", cs_); - ESP_LOGCONFIG(TAG, " Samples / cycle: %" PRIu32, samples_); - ESP_LOGCONFIG(TAG, " Phase offset: %i", phase_offset_); - ESP_LOGCONFIG(TAG, " PGA Gain: %s", pga_gain_ == CS5460A_PGA_GAIN_50X ? "50x" : "10x"); - ESP_LOGCONFIG(TAG, " Current gain: %.5f", current_gain_); - ESP_LOGCONFIG(TAG, " Voltage gain: %.5f", voltage_gain_); - ESP_LOGCONFIG(TAG, " Current HPF: %s", current_hpf_ ? "enabled" : "disabled"); - ESP_LOGCONFIG(TAG, " Voltage HPF: %s", voltage_hpf_ ? "enabled" : "disabled"); - ESP_LOGCONFIG(TAG, " Pulse energy: %.2f Wh", pulse_energy_wh_); + ESP_LOGCONFIG(TAG, + " Samples / cycle: %" PRIu32 "\n" + " Phase offset: %i\n" + " PGA Gain: %s\n" + " Current gain: %.5f\n" + " Voltage gain: %.5f\n" + " Current HPF: %s\n" + " Voltage HPF: %s\n" + " Pulse energy: %.2f Wh", + samples_, phase_offset_, pga_gain_ == CS5460A_PGA_GAIN_50X ? "50x" : "10x", current_gain_, + voltage_gain_, current_hpf_ ? "enabled" : "disabled", voltage_hpf_ ? "enabled" : "disabled", + pulse_energy_wh_); LOG_SENSOR(" ", "Voltage", voltage_sensor_); LOG_SENSOR(" ", "Current", current_sensor_); LOG_SENSOR(" ", "Power", power_sensor_); diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index b0876778a3..fe81ae91fe 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -223,11 +223,6 @@ void CSE7766Component::parse_data_() { #endif } -uint32_t CSE7766Component::get_24_bit_uint_(uint8_t start_index) { - return (uint32_t(this->raw_data_[start_index]) << 16) | (uint32_t(this->raw_data_[start_index + 1]) << 8) | - uint32_t(this->raw_data_[start_index + 2]); -} - void CSE7766Component::dump_config() { ESP_LOGCONFIG(TAG, "CSE7766:"); LOG_SENSOR(" ", "Voltage", this->voltage_sensor_); diff --git a/esphome/components/cse7766/cse7766.h b/esphome/components/cse7766/cse7766.h index 5d89b3b75b..8902eafe3c 100644 --- a/esphome/components/cse7766/cse7766.h +++ b/esphome/components/cse7766/cse7766.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" @@ -28,7 +29,10 @@ class CSE7766Component : public Component, public uart::UARTDevice { protected: bool check_byte_(); void parse_data_(); - uint32_t get_24_bit_uint_(uint8_t start_index); + uint32_t get_24_bit_uint_(uint8_t start_index) const { + return encode_uint24(this->raw_data_[start_index], this->raw_data_[start_index + 1], + this->raw_data_[start_index + 2]); + } uint8_t raw_data_[24]; uint8_t raw_data_index_{0}; diff --git a/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp b/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp index e76e40dba7..0c5099d4f0 100644 --- a/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +++ b/esphome/components/cst816/touchscreen/cst816_touchscreen.cpp @@ -1,4 +1,5 @@ #include "cst816_touchscreen.h" +#include "esphome/core/helpers.h" namespace esphome { namespace cst816 { @@ -74,8 +75,10 @@ void CST816Touchscreen::dump_config() { LOG_I2C_DEVICE(this); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " X Raw Min: %d, X Raw Max: %d", this->x_raw_min_, this->x_raw_max_); - ESP_LOGCONFIG(TAG, " Y Raw Min: %d, Y Raw Max: %d", this->y_raw_min_, this->y_raw_max_); + ESP_LOGCONFIG(TAG, + " X Raw Min: %d, X Raw Max: %d\n" + " Y Raw Min: %d, Y Raw Max: %d", + this->x_raw_min_, this->x_raw_max_, this->y_raw_min_, this->y_raw_max_); const char *name; switch (this->chip_id_) { case CST820_CHIP_ID: diff --git a/esphome/components/current_based/current_based_cover.cpp b/esphome/components/current_based/current_based_cover.cpp index 8bb27dbeca..895b5515cb 100644 --- a/esphome/components/current_based/current_based_cover.cpp +++ b/esphome/components/current_based/current_based_cover.cpp @@ -151,8 +151,10 @@ void CurrentBasedCover::dump_config() { if (this->max_duration_ != UINT32_MAX) { ESP_LOGCONFIG(TAG, "Maximum duration: %.1fs", this->max_duration_ / 1e3f); } - ESP_LOGCONFIG(TAG, "Start sensing delay: %.1fs", this->start_sensing_delay_ / 1e3f); - ESP_LOGCONFIG(TAG, "Malfunction detection: %s", YESNO(this->malfunction_detection_)); + ESP_LOGCONFIG(TAG, + "Start sensing delay: %.1fs\n" + "Malfunction detection: %s", + this->start_sensing_delay_ / 1e3f, YESNO(this->malfunction_detection_)); } float CurrentBasedCover::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/dac7678/dac7678_output.cpp b/esphome/components/dac7678/dac7678_output.cpp index 31d153beb9..5c10bbc1bc 100644 --- a/esphome/components/dac7678/dac7678_output.cpp +++ b/esphome/components/dac7678/dac7678_output.cpp @@ -1,7 +1,7 @@ #include "dac7678_output.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace dac7678 { @@ -22,7 +22,7 @@ static const uint8_t DAC7678_REG_INTERNAL_REF_1 = 0x90; void DAC7678Output::setup() { ESP_LOGCONFIG(TAG, "Running setup"); - ESP_LOGV(TAG, "Resetting device..."); + ESP_LOGV(TAG, "Resetting device"); // Reset device if (!this->write_byte_16(DAC7678_REG_SOFTWARE_RESET, 0x0000)) { diff --git a/esphome/components/daly_bms/daly_bms.cpp b/esphome/components/daly_bms/daly_bms.cpp index 1dd0520465..2d270cc56e 100644 --- a/esphome/components/daly_bms/daly_bms.cpp +++ b/esphome/components/daly_bms/daly_bms.cpp @@ -1,7 +1,8 @@ #include "daly_bms.h" #include -#include "esphome/core/log.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace daly_bms { diff --git a/esphome/components/datetime/__init__.py b/esphome/components/datetime/__init__.py index 630bf6962c..24fbf5a1ec 100644 --- a/esphome/components/datetime/__init__.py +++ b/esphome/components/datetime/__init__.py @@ -158,7 +158,9 @@ async def setup_datetime_core_(var, config): async def register_datetime(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) - cg.add(getattr(cg.App, f"register_{config[CONF_TYPE].lower()}")(var)) + entity_type = config[CONF_TYPE].lower() + cg.add(getattr(cg.App, f"register_{entity_type}")(var)) + CORE.register_platform_component(entity_type, var) await setup_datetime_core_(var, config) cg.add_define(f"USE_DATETIME_{config[CONF_TYPE]}") diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index c4de42c7e9..ade0968e08 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -2,9 +2,9 @@ #include #include "esphome/core/application.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/core/version.h" #include #include @@ -15,10 +15,6 @@ namespace debug { static const char *const TAG = "debug"; void DebugComponent::dump_config() { -#ifndef ESPHOME_LOG_HAS_DEBUG - return; // Can't log below if debug logging is disabled -#endif - ESP_LOGCONFIG(TAG, "Debug component:"); #ifdef USE_TEXT_SENSOR LOG_TEXT_SENSOR(" ", "Device info", this->device_info_); diff --git a/esphome/components/debug/debug_component.h b/esphome/components/debug/debug_component.h index 50d26ad2ea..efd0dafab0 100644 --- a/esphome/components/debug/debug_component.h +++ b/esphome/components/debug/debug_component.h @@ -2,8 +2,8 @@ #include "esphome/core/component.h" #include "esphome/core/defines.h" -#include "esphome/core/macros.h" #include "esphome/core/helpers.h" +#include "esphome/core/macros.h" #ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" diff --git a/esphome/components/debug/debug_esp32.cpp b/esphome/components/debug/debug_esp32.cpp index 999cb927b3..e48a4941b3 100644 --- a/esphome/components/debug/debug_esp32.cpp +++ b/esphome/components/debug/debug_esp32.cpp @@ -107,8 +107,10 @@ std::string DebugComponent::get_wakeup_cause_() { } void DebugComponent::log_partition_info_() { - ESP_LOGCONFIG(TAG, "Partition table:"); - ESP_LOGCONFIG(TAG, " %-12s %-4s %-8s %-10s %-10s", "Name", "Type", "Subtype", "Address", "Size"); + ESP_LOGCONFIG(TAG, + "Partition table:\n" + " %-12s %-4s %-8s %-10s %-10s", + "Name", "Type", "Subtype", "Address", "Size"); esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); while (it != NULL) { const esp_partition_t *partition = esp_partition_get(it); diff --git a/esphome/components/deep_sleep/deep_sleep_component.cpp b/esphome/components/deep_sleep/deep_sleep_component.cpp index b53dabc92f..84fc102b66 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.cpp +++ b/esphome/components/deep_sleep/deep_sleep_component.cpp @@ -6,6 +6,8 @@ namespace esphome { namespace deep_sleep { static const char *const TAG = "deep_sleep"; +// 5 seconds for deep sleep to ensure clean disconnect from Home Assistant +static const uint32_t TEARDOWN_TIMEOUT_DEEP_SLEEP_MS = 5000; bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -62,6 +64,10 @@ void DeepSleepComponent::begin_sleep(bool manual) { ESP_LOGI(TAG, "Sleeping for %" PRId64 "us", *this->sleep_duration_); } App.run_safe_shutdown_hooks(); + // It's critical to teardown components cleanly for deep sleep to ensure + // Home Assistant sees a clean disconnect instead of marking the device unavailable + App.teardown_components(TEARDOWN_TIMEOUT_DEEP_SLEEP_MS); + App.run_powerdown_hooks(); this->deep_sleep_(); } diff --git a/esphome/components/deep_sleep/deep_sleep_esp32.cpp b/esphome/components/deep_sleep/deep_sleep_esp32.cpp index 3c5d3382ce..7965ab738a 100644 --- a/esphome/components/deep_sleep/deep_sleep_esp32.cpp +++ b/esphome/components/deep_sleep/deep_sleep_esp32.cpp @@ -46,10 +46,12 @@ void DeepSleepComponent::dump_config_platform_() { LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_); } if (this->wakeup_cause_to_run_duration_.has_value()) { - ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms", - this->wakeup_cause_to_run_duration_->default_cause); - ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause); - ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause); + ESP_LOGCONFIG(TAG, + " Default Wakeup Run Duration: %" PRIu32 " ms\n" + " Touch Wakeup Run Duration: %" PRIu32 " ms\n" + " GPIO Wakeup Run Duration: %" PRIu32 " ms", + this->wakeup_cause_to_run_duration_->default_cause, this->wakeup_cause_to_run_duration_->touch_cause, + this->wakeup_cause_to_run_duration_->gpio_cause); } } diff --git a/esphome/components/dfrobot_sen0395/commands.cpp b/esphome/components/dfrobot_sen0395/commands.cpp index 2c60fb3449..42074c80cf 100644 --- a/esphome/components/dfrobot_sen0395/commands.cpp +++ b/esphome/components/dfrobot_sen0395/commands.cpp @@ -21,7 +21,7 @@ uint8_t Command::execute(DfrobotSen0395Component *parent) { if (this->retries_left_ > 0) { this->retries_left_ -= 1; this->cmd_sent_ = false; - ESP_LOGD(TAG, "Retrying..."); + ESP_LOGD(TAG, "Retrying"); return 0; } else { this->parent_->find_prompt_(); @@ -33,7 +33,7 @@ uint8_t Command::execute(DfrobotSen0395Component *parent) { if (this->retries_left_ > 0) { this->retries_left_ -= 1; this->cmd_sent_ = false; - ESP_LOGD(TAG, "Retrying..."); + ESP_LOGD(TAG, "Retrying"); return 0; } else { this->parent_->find_prompt_(); @@ -51,7 +51,7 @@ uint8_t Command::execute(DfrobotSen0395Component *parent) { if (this->retries_left_ > 0) { this->retries_left_ -= 1; this->cmd_sent_ = false; - ESP_LOGD(TAG, "Retrying..."); + ESP_LOGD(TAG, "Retrying"); } else { return 1; // Command done } diff --git a/esphome/components/dht/dht.cpp b/esphome/components/dht/dht.cpp index 27234ed4d1..7248ef624e 100644 --- a/esphome/components/dht/dht.cpp +++ b/esphome/components/dht/dht.cpp @@ -1,6 +1,6 @@ #include "dht.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace dht { diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 43da08f4ac..68c1184721 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -182,9 +182,11 @@ using display_writer_t = std::function; #define LOG_DISPLAY(prefix, type, obj) \ if ((obj) != nullptr) { \ - ESP_LOGCONFIG(TAG, prefix type); \ - ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \ - ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \ + ESP_LOGCONFIG(TAG, \ + prefix type "\n" \ + "%s Rotations: %d °\n" \ + "%s Dimensions: %dpx x %dpx", \ + prefix, (obj)->rotation_, prefix, (obj)->get_width(), (obj)->get_height()); \ } /// Turn the pixel OFF. diff --git a/esphome/components/dps310/dps310.cpp b/esphome/components/dps310/dps310.cpp index b1287b6f2d..a7fb7ecd5e 100644 --- a/esphome/components/dps310/dps310.cpp +++ b/esphome/components/dps310/dps310.cpp @@ -86,9 +86,11 @@ void DPS310Component::setup() { } void DPS310Component::dump_config() { - ESP_LOGCONFIG(TAG, "DPS310:"); - ESP_LOGCONFIG(TAG, " Product ID: %u", this->prod_rev_id_ & 0x0F); - ESP_LOGCONFIG(TAG, " Revision ID: %u", (this->prod_rev_id_ >> 4) & 0x0F); + ESP_LOGCONFIG(TAG, + "DPS310:\n" + " Product ID: %u\n" + " Revision ID: %u", + this->prod_rev_id_ & 0x0F, (this->prod_rev_id_ >> 4) & 0x0F); LOG_I2C_DEVICE(this); if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); diff --git a/esphome/components/dsmr/dsmr.cpp b/esphome/components/dsmr/dsmr.cpp index c0a2883d79..d99cf5e7a9 100644 --- a/esphome/components/dsmr/dsmr.cpp +++ b/esphome/components/dsmr/dsmr.cpp @@ -278,9 +278,11 @@ bool Dsmr::parse_telegram() { } void Dsmr::dump_config() { - ESP_LOGCONFIG(TAG, "DSMR:"); - ESP_LOGCONFIG(TAG, " Max telegram length: %d", this->max_telegram_len_); - ESP_LOGCONFIG(TAG, " Receive timeout: %.1fs", this->receive_timeout_ / 1e3f); + ESP_LOGCONFIG(TAG, + "DSMR:\n" + " Max telegram length: %d\n" + " Receive timeout: %.1fs", + this->max_telegram_len_, this->receive_timeout_ / 1e3f); if (this->request_pin_ != nullptr) { LOG_PIN(" Request Pin: ", this->request_pin_); } diff --git a/esphome/components/duty_cycle/duty_cycle_sensor.cpp b/esphome/components/duty_cycle/duty_cycle_sensor.cpp index 6c24fc7a8b..8939de0ee9 100644 --- a/esphome/components/duty_cycle/duty_cycle_sensor.cpp +++ b/esphome/components/duty_cycle/duty_cycle_sensor.cpp @@ -1,6 +1,6 @@ #include "duty_cycle_sensor.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace duty_cycle { diff --git a/esphome/components/duty_time/duty_time_sensor.cpp b/esphome/components/duty_time/duty_time_sensor.cpp index d4369c89c0..c7319f7c33 100644 --- a/esphome/components/duty_time/duty_time_sensor.cpp +++ b/esphome/components/duty_time/duty_time_sensor.cpp @@ -94,9 +94,11 @@ void DutyTimeSensor::publish_and_save_(const uint32_t sec, const uint32_t ms) { } void DutyTimeSensor::dump_config() { - ESP_LOGCONFIG(TAG, "Duty Time:"); - ESP_LOGCONFIG(TAG, " Update Interval: %" PRId32 "ms", this->get_update_interval()); - ESP_LOGCONFIG(TAG, " Restore: %s", ONOFF(this->restore_)); + ESP_LOGCONFIG(TAG, + "Duty Time:\n" + " Update Interval: %" PRId32 "ms\n" + " Restore: %s", + this->get_update_interval(), ONOFF(this->restore_)); LOG_SENSOR(" ", "Duty Time Sensor:", this); LOG_SENSOR(" ", "Last Duty Time Sensor:", this->last_duty_time_sensor_); } diff --git a/esphome/components/ee895/ee895.cpp b/esphome/components/ee895/ee895.cpp index 4ce29bcfab..bdaa3f3200 100644 --- a/esphome/components/ee895/ee895.cpp +++ b/esphome/components/ee895/ee895.cpp @@ -1,6 +1,6 @@ #include "ee895.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ee895 { diff --git a/esphome/components/emc2101/emc2101.cpp b/esphome/components/emc2101/emc2101.cpp index 6918c6d391..75d324c2bb 100644 --- a/esphome/components/emc2101/emc2101.cpp +++ b/esphome/components/emc2101/emc2101.cpp @@ -100,8 +100,10 @@ void Emc2101Component::dump_config() { if (this->dac_mode_) { ESP_LOGCONFIG(TAG, " DAC Conversion Rate: %X", this->dac_conversion_rate_); } else { - ESP_LOGCONFIG(TAG, " PWM Resolution: %02X", this->pwm_resolution_); - ESP_LOGCONFIG(TAG, " PWM Divider: %02X", this->pwm_divider_); + ESP_LOGCONFIG(TAG, + " PWM Resolution: %02X\n" + " PWM Divider: %02X", + this->pwm_resolution_, this->pwm_divider_); } ESP_LOGCONFIG(TAG, " Inverted: %s", YESNO(this->inverted_)); } diff --git a/esphome/components/es7210/es7210.cpp b/esphome/components/es7210/es7210.cpp index f494bf32f0..bcbaf3d270 100644 --- a/esphome/components/es7210/es7210.cpp +++ b/esphome/components/es7210/es7210.cpp @@ -25,9 +25,11 @@ static const size_t MCLK_DIV_FRE = 256; } void ES7210::dump_config() { - ESP_LOGCONFIG(TAG, "ES7210 audio ADC:"); - ESP_LOGCONFIG(TAG, " Bits Per Sample: %" PRIu8, this->bits_per_sample_); - ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_rate_); + ESP_LOGCONFIG(TAG, + "ES7210 audio ADC:\n" + " Bits Per Sample: %" PRIu8 "\n" + " Sample Rate: %" PRIu32, + this->bits_per_sample_, this->sample_rate_); if (this->is_failed()) { ESP_LOGE(TAG, " Failed to initialize"); diff --git a/esphome/components/es8311/es8311.cpp b/esphome/components/es8311/es8311.cpp index 47bd82adb1..0e59ac12d5 100644 --- a/esphome/components/es8311/es8311.cpp +++ b/esphome/components/es8311/es8311.cpp @@ -52,11 +52,13 @@ void ES8311::setup() { } void ES8311::dump_config() { - ESP_LOGCONFIG(TAG, "ES8311 Audio Codec:"); - ESP_LOGCONFIG(TAG, " Use MCLK: %s", YESNO(this->use_mclk_)); - ESP_LOGCONFIG(TAG, " Use Microphone: %s", YESNO(this->use_mic_)); - ESP_LOGCONFIG(TAG, " DAC Bits per Sample: %" PRIu8, this->resolution_out_); - ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_frequency_); + ESP_LOGCONFIG(TAG, + "ES8311 Audio Codec:\n" + " Use MCLK: %s\n" + " Use Microphone: %s\n" + " DAC Bits per Sample: %" PRIu8 "\n" + " Sample Rate: %" PRIu32, + YESNO(this->use_mclk_), YESNO(this->use_mic_), this->resolution_out_, this->sample_frequency_); if (this->is_failed()) { ESP_LOGCONFIG(TAG, " Failed to initialize!"); diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index b211015865..b5d4c83f5e 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -71,12 +71,28 @@ from .const import ( # noqa from .gpio import esp32_pin_to_code # noqa _LOGGER = logging.getLogger(__name__) -CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["preferences"] +CODEOWNERS = ["@esphome/core"] IS_TARGET_PLATFORM = True -CONF_RELEASE = "release" +CONF_ASSERTION_LEVEL = "assertion_level" +CONF_COMPILER_OPTIMIZATION = "compiler_optimization" CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES = "enable_idf_experimental_features" +CONF_ENABLE_LWIP_ASSERT = "enable_lwip_assert" +CONF_RELEASE = "release" + +ASSERTION_LEVELS = { + "DISABLE": "CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE", + "ENABLE": "CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE", + "SILENT": "CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT", +} + +COMPILER_OPTIMIZATIONS = { + "DEBUG": "CONFIG_COMPILER_OPTIMIZATION_DEBUG", + "NONE": "CONFIG_COMPILER_OPTIMIZATION_NONE", + "PERF": "CONFIG_COMPILER_OPTIMIZATION_PERF", + "SIZE": "CONFIG_COMPILER_OPTIMIZATION_SIZE", +} def get_cpu_frequencies(*frequencies): @@ -451,8 +467,8 @@ def _parse_platform_version(value): if ver.major >= 50: # a pioarduino version if "-" in value: # maybe a release candidate?...definitely not our default, just use it as-is... - return f"https://github.com/pioarduino/platform-espressif32.git#{value}" - return f"https://github.com/pioarduino/platform-espressif32.git#{ver.major}.{ver.minor:02d}.{ver.patch:02d}" + return f"https://github.com/pioarduino/platform-espressif32/releases/download/{value}/platform-espressif32.zip" + return f"https://github.com/pioarduino/platform-espressif32/releases/download/{ver.major}.{ver.minor:02d}.{ver.patch:02d}/platform-espressif32.zip" # if platform version is a valid version constraint, prefix the default package cv.platformio_version_constraint(value) return f"platformio/espressif32@{value}" @@ -542,6 +558,10 @@ ARDUINO_FRAMEWORK_SCHEMA = cv.All( ) CONF_SDKCONFIG_OPTIONS = "sdkconfig_options" +CONF_ENABLE_LWIP_DHCP_SERVER = "enable_lwip_dhcp_server" +CONF_ENABLE_LWIP_MDNS_QUERIES = "enable_lwip_mdns_queries" +CONF_ENABLE_LWIP_BRIDGE_INTERFACE = "enable_lwip_bridge_interface" + ESP_IDF_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { @@ -554,11 +574,30 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All( }, cv.Optional(CONF_ADVANCED, default={}): cv.Schema( { + cv.Optional(CONF_ASSERTION_LEVEL): cv.one_of( + *ASSERTION_LEVELS, upper=True + ), + cv.Optional(CONF_COMPILER_OPTIMIZATION, default="SIZE"): cv.one_of( + *COMPILER_OPTIMIZATIONS, upper=True + ), + cv.Optional(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): cv.boolean, + cv.Optional(CONF_ENABLE_LWIP_ASSERT, default=True): cv.boolean, cv.Optional( CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False ): cv.boolean, cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC): cv.boolean, - cv.Optional(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): cv.boolean, + # DHCP server is needed for WiFi AP mode. When WiFi component is used, + # it will handle disabling DHCP server when AP is not configured. + # Default to false (disabled) when WiFi is not used. + cv.OnlyWithout( + CONF_ENABLE_LWIP_DHCP_SERVER, "wifi", default=False + ): cv.boolean, + cv.Optional( + CONF_ENABLE_LWIP_MDNS_QUERIES, default=False + ): cv.boolean, + cv.Optional( + CONF_ENABLE_LWIP_BRIDGE_INTERFACE, default=False + ): cv.boolean, } ), cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list( @@ -641,7 +680,7 @@ async def to_code(config): conf = config[CONF_FRAMEWORK] cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) - if CONF_ADVANCED in conf and conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: + if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") add_extra_script( @@ -672,8 +711,6 @@ async def to_code(config): add_idf_sdkconfig_option( "CONFIG_PARTITION_TABLE_CUSTOM_FILENAME", "partitions.csv" ) - add_idf_sdkconfig_option("CONFIG_COMPILER_OPTIMIZATION_DEFAULT", False) - add_idf_sdkconfig_option("CONFIG_COMPILER_OPTIMIZATION_SIZE", True) # Increase freertos tick speed from 100Hz to 1kHz so that delay() resolution is 1ms add_idf_sdkconfig_option("CONFIG_FREERTOS_HZ", 1000) @@ -687,16 +724,41 @@ async def to_code(config): # Set default CPU frequency add_idf_sdkconfig_option(f"CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_{freq}", True) + # Apply LWIP optimization settings + advanced = conf[CONF_ADVANCED] + # DHCP server: only disable if explicitly set to false + # WiFi component handles its own optimization when AP mode is not used + if ( + CONF_ENABLE_LWIP_DHCP_SERVER in advanced + and not advanced[CONF_ENABLE_LWIP_DHCP_SERVER] + ): + add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False) + if not advanced.get(CONF_ENABLE_LWIP_MDNS_QUERIES, False): + add_idf_sdkconfig_option("CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES", False) + if not advanced.get(CONF_ENABLE_LWIP_BRIDGE_INTERFACE, False): + add_idf_sdkconfig_option("CONFIG_LWIP_BRIDGEIF_MAX_PORTS", 0) + cg.add_platformio_option("board_build.partitions", "partitions.csv") if CONF_PARTITIONS in config: add_extra_build_file( "partitions.csv", CORE.relative_config_path(config[CONF_PARTITIONS]) ) - for name, value in conf[CONF_SDKCONFIG_OPTIONS].items(): - add_idf_sdkconfig_option(name, RawSdkconfigValue(value)) + if assertion_level := advanced.get(CONF_ASSERTION_LEVEL): + for key, flag in ASSERTION_LEVELS.items(): + add_idf_sdkconfig_option(flag, assertion_level == key) - if conf[CONF_ADVANCED].get(CONF_IGNORE_EFUSE_MAC_CRC): + add_idf_sdkconfig_option("CONFIG_COMPILER_OPTIMIZATION_DEFAULT", False) + compiler_optimization = advanced.get(CONF_COMPILER_OPTIMIZATION) + for key, flag in COMPILER_OPTIMIZATIONS.items(): + add_idf_sdkconfig_option(flag, compiler_optimization == key) + + add_idf_sdkconfig_option( + "CONFIG_LWIP_ESP_LWIP_ASSERT", + conf[CONF_ADVANCED][CONF_ENABLE_LWIP_ASSERT], + ) + + if advanced.get(CONF_IGNORE_EFUSE_MAC_CRC): add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) if (framework_ver.major, framework_ver.minor) >= (4, 4): add_idf_sdkconfig_option( @@ -706,7 +768,7 @@ async def to_code(config): add_idf_sdkconfig_option( "CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE", False ) - if conf[CONF_ADVANCED].get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): + if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): _LOGGER.warning( "Using experimental features in ESP-IDF may result in unexpected failures." ) @@ -719,6 +781,9 @@ async def to_code(config): ), ) + for name, value in conf[CONF_SDKCONFIG_OPTIONS].items(): + add_idf_sdkconfig_option(name, RawSdkconfigValue(value)) + for component in conf[CONF_COMPONENTS]: source = component[CONF_SOURCE] if source[CONF_TYPE] == TYPE_GIT: diff --git a/esphome/components/esp32/preferences.cpp b/esphome/components/esp32/preferences.cpp index f90b8a4603..e53cdd90d3 100644 --- a/esphome/components/esp32/preferences.cpp +++ b/esphome/components/esp32/preferences.cpp @@ -1,8 +1,8 @@ #ifdef USE_ESP32 -#include "esphome/core/preferences.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "esphome/core/preferences.h" #include #include #include @@ -84,7 +84,7 @@ class ESP32Preferences : public ESPPreferences { if (err == 0) return; - ESP_LOGW(TAG, "nvs_open failed: %s - erasing NVS...", esp_err_to_name(err)); + ESP_LOGW(TAG, "nvs_open failed: %s - erasing NVS", esp_err_to_name(err)); nvs_flash_deinit(); nvs_flash_erase(); nvs_flash_init(); @@ -111,7 +111,7 @@ class ESP32Preferences : public ESPPreferences { if (s_pending_save.empty()) return true; - ESP_LOGD(TAG, "Saving %d preferences to flash...", s_pending_save.size()); + ESP_LOGV(TAG, "Saving %d items...", s_pending_save.size()); // goal try write all pending saves even if one fails int cached = 0, written = 0, failed = 0; esp_err_t last_err = ESP_OK; @@ -139,10 +139,10 @@ class ESP32Preferences : public ESPPreferences { } s_pending_save.erase(s_pending_save.begin() + i); } - ESP_LOGD(TAG, "Saving %d preferences to flash: %d cached, %d written, %d failed", cached + written + failed, cached, - written, failed); + ESP_LOGD(TAG, "Writing %d items: %d cached, %d written, %d failed", cached + written + failed, cached, written, + failed); if (failed > 0) { - ESP_LOGE(TAG, "Error saving %d preferences to flash. Last error=%s for key=%s", failed, esp_err_to_name(last_err), + ESP_LOGE(TAG, "Writing %d items failed. Last error=%s for key=%s", failed, esp_err_to_name(last_err), last_key.c_str()); } @@ -173,7 +173,7 @@ class ESP32Preferences : public ESPPreferences { } bool reset() override { - ESP_LOGD(TAG, "Cleaning up preferences in flash..."); + ESP_LOGD(TAG, "Erasing storage"); s_pending_save.clear(); nvs_flash_deinit(); diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 37b4900a03..93bb643596 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -1,3 +1,4 @@ +from enum import Enum import re from esphome import automation @@ -12,9 +13,110 @@ import esphome.final_validate as fv DEPENDENCIES = ["esp32"] CODEOWNERS = ["@jesserockz", "@Rapsssito"] + +class BTLoggers(Enum): + """Bluetooth logger categories available in ESP-IDF. + + Each logger controls debug output for a specific Bluetooth subsystem. + The value is the ESP-IDF sdkconfig option name for controlling the log level. + """ + + # Core Stack Layers + HCI = "CONFIG_BT_LOG_HCI_TRACE_LEVEL" + """Host Controller Interface - Low-level interface between host and controller""" + + BTM = "CONFIG_BT_LOG_BTM_TRACE_LEVEL" + """Bluetooth Manager - Core device control, connections, and security""" + + L2CAP = "CONFIG_BT_LOG_L2CAP_TRACE_LEVEL" + """Logical Link Control and Adaptation Protocol - Connection multiplexing""" + + RFCOMM = "CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL" + """Serial port emulation over Bluetooth (Classic only)""" + + SDP = "CONFIG_BT_LOG_SDP_TRACE_LEVEL" + """Service Discovery Protocol - Service discovery (Classic only)""" + + GAP = "CONFIG_BT_LOG_GAP_TRACE_LEVEL" + """Generic Access Profile - Device discovery and connections""" + + # Network Protocols + BNEP = "CONFIG_BT_LOG_BNEP_TRACE_LEVEL" + """Bluetooth Network Encapsulation Protocol - IP over Bluetooth""" + + PAN = "CONFIG_BT_LOG_PAN_TRACE_LEVEL" + """Personal Area Networking - Ethernet over Bluetooth""" + + # Audio/Video Profiles (Classic Bluetooth) + A2D = "CONFIG_BT_LOG_A2D_TRACE_LEVEL" + """Advanced Audio Distribution - A2DP audio streaming""" + + AVDT = "CONFIG_BT_LOG_AVDT_TRACE_LEVEL" + """Audio/Video Distribution Transport - A2DP transport protocol""" + + AVCT = "CONFIG_BT_LOG_AVCT_TRACE_LEVEL" + """Audio/Video Control Transport - AVRCP transport protocol""" + + AVRC = "CONFIG_BT_LOG_AVRC_TRACE_LEVEL" + """Audio/Video Remote Control - Media playback control""" + + # Security + SMP = "CONFIG_BT_LOG_SMP_TRACE_LEVEL" + """Security Manager Protocol - BLE pairing and encryption""" + + # Application Layer + BTIF = "CONFIG_BT_LOG_BTIF_TRACE_LEVEL" + """Bluetooth Interface - Application interface layer""" + + BTC = "CONFIG_BT_LOG_BTC_TRACE_LEVEL" + """Bluetooth Common - Task handling and coordination""" + + # BLE Specific + BLE_SCAN = "CONFIG_BT_LOG_BLE_SCAN_TRACE_LEVEL" + """BLE scanning operations""" + + GATT = "CONFIG_BT_LOG_GATT_TRACE_LEVEL" + """Generic Attribute Profile - BLE data exchange protocol""" + + # Other Profiles + MCA = "CONFIG_BT_LOG_MCA_TRACE_LEVEL" + """Multi-Channel Adaptation - Health device profile""" + + HID = "CONFIG_BT_LOG_HID_TRACE_LEVEL" + """Human Interface Device - Keyboards, mice, controllers""" + + APPL = "CONFIG_BT_LOG_APPL_TRACE_LEVEL" + """Application layer logging""" + + OSI = "CONFIG_BT_LOG_OSI_TRACE_LEVEL" + """OS abstraction layer - Threading, memory, timers""" + + BLUFI = "CONFIG_BT_LOG_BLUFI_TRACE_LEVEL" + """ESP32 WiFi provisioning over Bluetooth""" + + +# Set to track which loggers are needed by components +_required_loggers: set[BTLoggers] = set() + + +def register_bt_logger(*loggers: BTLoggers) -> None: + """Register Bluetooth logger categories that a component needs. + + Args: + *loggers: One or more BTLoggers enum members + """ + for logger in loggers: + if not isinstance(logger, BTLoggers): + raise TypeError( + f"Logger must be a BTLoggers enum member, got {type(logger)}" + ) + _required_loggers.add(logger) + + CONF_BLE_ID = "ble_id" CONF_IO_CAPABILITY = "io_capability" CONF_ADVERTISING_CYCLE_TIME = "advertising_cycle_time" +CONF_DISABLE_BT_LOGS = "disable_bt_logs" NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2] @@ -62,6 +164,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional( CONF_ADVERTISING_CYCLE_TIME, default="10s" ): cv.positive_time_period_milliseconds, + cv.SplitDefault(CONF_DISABLE_BT_LOGS, esp32_idf=True): cv.All( + cv.only_with_esp_idf, cv.boolean + ), } ).extend(cv.COMPONENT_SCHEMA) @@ -140,6 +245,16 @@ async def to_code(config): add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) + # Register the core BLE loggers that are always needed + register_bt_logger(BTLoggers.GAP, BTLoggers.BTM, BTLoggers.HCI) + + # Apply logger settings if log disabling is enabled + if config.get(CONF_DISABLE_BT_LOGS, False): + # Disable all Bluetooth loggers that are not required + for logger in BTLoggers: + if logger not in _required_loggers: + add_idf_sdkconfig_option(f"{logger.value}_NONE", True) + cg.add_define("USE_ESP32_BLE") diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 9d9a264154..824c2b9dbc 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -270,14 +270,14 @@ void ESP32BLE::loop() { case BLE_COMPONENT_STATE_DISABLED: return; case BLE_COMPONENT_STATE_DISABLE: { - ESP_LOGD(TAG, "Disabling BLE..."); + ESP_LOGD(TAG, "Disabling"); for (auto *ble_event_handler : this->ble_status_event_handlers_) { ble_event_handler->ble_before_disabled_event_handler(); } if (!ble_dismantle_()) { - ESP_LOGE(TAG, "BLE could not be dismantled"); + ESP_LOGE(TAG, "Could not be dismantled"); this->mark_failed(); return; } @@ -285,11 +285,11 @@ void ESP32BLE::loop() { return; } case BLE_COMPONENT_STATE_ENABLE: { - ESP_LOGD(TAG, "Enabling BLE..."); + ESP_LOGD(TAG, "Enabling"); this->state_ = BLE_COMPONENT_STATE_OFF; if (!ble_setup_()) { - ESP_LOGE(TAG, "BLE could not be set up"); + ESP_LOGE(TAG, "Could not be set up"); this->mark_failed(); return; } @@ -408,10 +408,12 @@ void ESP32BLE::dump_config() { io_capability_s = "invalid"; break; } - ESP_LOGCONFIG(TAG, "ESP32 BLE:"); - ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2], - mac_address[3], mac_address[4], mac_address[5]); - ESP_LOGCONFIG(TAG, " IO Capability: %s", io_capability_s); + ESP_LOGCONFIG(TAG, + "ESP32 BLE:\n" + " MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n" + " IO Capability: %s", + mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5], + io_capability_s); } else { ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled"); } diff --git a/esphome/components/esp32_ble/ble_uuid.h b/esphome/components/esp32_ble/ble_uuid.h index d90db3a599..06f84d4da7 100644 --- a/esphome/components/esp32_ble/ble_uuid.h +++ b/esphome/components/esp32_ble/ble_uuid.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #ifdef USE_ESP32 diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index 2a1757524f..4e61fb287c 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -45,8 +45,10 @@ void BLEClientBase::loop() { float BLEClientBase::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; } void BLEClientBase::dump_config() { - ESP_LOGCONFIG(TAG, " Address: %s", this->address_str().c_str()); - ESP_LOGCONFIG(TAG, " Auto-Connect: %s", TRUEFALSE(this->auto_connect_)); + ESP_LOGCONFIG(TAG, + " Address: %s\n" + " Auto-Connect: %s", + this->address_str().c_str(), TRUEFALSE(this->auto_connect_)); std::string state_name; switch (this->state()) { case espbt::ClientState::INIT: diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index 0fcb5c9822..773445a1a7 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -4,7 +4,7 @@ from esphome import automation import esphome.codegen as cg from esphome.components import esp32_ble from esphome.components.esp32 import add_idf_sdkconfig_option -from esphome.components.esp32_ble import bt_uuid +from esphome.components.esp32_ble import BTLoggers, bt_uuid import esphome.config_validation as cv from esphome.config_validation import UNDEFINED from esphome.const import ( @@ -525,6 +525,9 @@ async def to_code_characteristic(service_var, char_conf): async def to_code(config): + # Register the loggers this component needs + esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/esp32_ble_server/ble_characteristic.cpp b/esphome/components/esp32_ble_server/ble_characteristic.cpp index 15739d60bb..373d57436e 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_server/ble_characteristic.cpp @@ -2,6 +2,7 @@ #include "ble_server.h" #include "ble_service.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #ifdef USE_ESP32 diff --git a/esphome/components/esp32_ble_server/ble_server.h b/esphome/components/esp32_ble_server/ble_server.h index 43599438f3..531b52d6b9 100644 --- a/esphome/components/esp32_ble_server/ble_server.h +++ b/esphome/components/esp32_ble_server/ble_server.h @@ -43,7 +43,6 @@ class BLEServer : public Component, float get_setup_priority() const override; bool can_proceed() override; - void teardown(); bool is_running(); void set_manufacturer_data(const std::vector &data) { diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index b7eddeb0dd..61eed1c029 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -9,6 +9,7 @@ import esphome.codegen as cg from esphome.components import esp32_ble from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32_ble import ( + BTLoggers, bt_uuid, bt_uuid16_format, bt_uuid32_format, @@ -259,6 +260,9 @@ ESP_BLE_DEVICE_SCHEMA = cv.Schema( async def to_code(config): + # Register the loggers this component needs + esp32_ble.register_bt_logger(BTLoggers.BLE_SCAN) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 1a6071c9fe..6d60f1638c 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -172,7 +172,7 @@ void ESP32BLETracker::loop() { (this->scan_set_param_failed_ && this->scanner_state_ == ScannerState::RUNNING)) { this->stop_scan_(); if (this->scan_start_fail_count_ == std::numeric_limits::max()) { - ESP_LOGE(TAG, "ESP-IDF BLE scan could not restart after %d attempts, rebooting to restore BLE stack...", + ESP_LOGE(TAG, "Scan could not restart after %d attempts, rebooting to restore stack (IDF)", std::numeric_limits::max()); App.reboot(); } @@ -219,10 +219,10 @@ void ESP32BLETracker::loop() { for (auto *client : this->clients_) { if (client->state() == ClientState::DISCOVERED) { if (this->scanner_state_ == ScannerState::RUNNING) { - ESP_LOGD(TAG, "Stopping scan to make connection..."); + ESP_LOGD(TAG, "Stopping scan to make connection"); this->stop_scan_(); } else if (this->scanner_state_ == ScannerState::IDLE) { - ESP_LOGD(TAG, "Promoting client to connect..."); + ESP_LOGD(TAG, "Promoting client to connect"); // We only want to promote one client at a time. // once the scanner is fully stopped. #ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE @@ -306,7 +306,7 @@ void ESP32BLETracker::start_scan_(bool first) { // Start timeout before scan is started. Otherwise scan never starts if any error. this->set_timeout("scan", this->scan_duration_ * 2000, []() { - ESP_LOGE(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); + ESP_LOGE(TAG, "Scan never terminated, rebooting to restore stack (IDF)"); App.reboot(); }); @@ -731,11 +731,14 @@ uint64_t ESPBTDevice::address_uint64() const { return esp32_ble::ble_addr_to_uin void ESP32BLETracker::dump_config() { ESP_LOGCONFIG(TAG, "BLE Tracker:"); - ESP_LOGCONFIG(TAG, " Scan Duration: %" PRIu32 " s", this->scan_duration_); - ESP_LOGCONFIG(TAG, " Scan Interval: %.1f ms", this->scan_interval_ * 0.625f); - ESP_LOGCONFIG(TAG, " Scan Window: %.1f ms", this->scan_window_ * 0.625f); - ESP_LOGCONFIG(TAG, " Scan Type: %s", this->scan_active_ ? "ACTIVE" : "PASSIVE"); - ESP_LOGCONFIG(TAG, " Continuous Scanning: %s", YESNO(this->scan_continuous_)); + ESP_LOGCONFIG(TAG, + " Scan Duration: %" PRIu32 " s\n" + " Scan Interval: %.1f ms\n" + " Scan Window: %.1f ms\n" + " Scan Type: %s\n" + " Continuous Scanning: %s", + this->scan_duration_, this->scan_interval_ * 0.625f, this->scan_window_ * 0.625f, + this->scan_active_ ? "ACTIVE" : "PASSIVE", YESNO(this->scan_continuous_)); switch (this->scanner_state_) { case ScannerState::IDLE: ESP_LOGCONFIG(TAG, " Scanner State: IDLE"); diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp index cfcf7869d4..a7551571dd 100644 --- a/esphome/components/esp32_camera/esp32_camera.cpp +++ b/esphome/components/esp32_camera/esp32_camera.cpp @@ -46,17 +46,20 @@ void ESP32Camera::setup() { void ESP32Camera::dump_config() { auto conf = this->config_; - ESP_LOGCONFIG(TAG, "ESP32 Camera:"); - ESP_LOGCONFIG(TAG, " Name: %s", this->name_.c_str()); - ESP_LOGCONFIG(TAG, " Internal: %s", YESNO(this->internal_)); - ESP_LOGCONFIG(TAG, " Data Pins: D0:%d D1:%d D2:%d D3:%d D4:%d D5:%d D6:%d D7:%d", conf.pin_d0, conf.pin_d1, - conf.pin_d2, conf.pin_d3, conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7); - ESP_LOGCONFIG(TAG, " VSYNC Pin: %d", conf.pin_vsync); - ESP_LOGCONFIG(TAG, " HREF Pin: %d", conf.pin_href); - ESP_LOGCONFIG(TAG, " Pixel Clock Pin: %d", conf.pin_pclk); - ESP_LOGCONFIG(TAG, " External Clock: Pin:%d Frequency:%u", conf.pin_xclk, conf.xclk_freq_hz); - ESP_LOGCONFIG(TAG, " I2C Pins: SDA:%d SCL:%d", conf.pin_sccb_sda, conf.pin_sccb_scl); - ESP_LOGCONFIG(TAG, " Reset Pin: %d", conf.pin_reset); + ESP_LOGCONFIG(TAG, + "ESP32 Camera:\n" + " Name: %s\n" + " Internal: %s\n" + " Data Pins: D0:%d D1:%d D2:%d D3:%d D4:%d D5:%d D6:%d D7:%d\n" + " VSYNC Pin: %d\n" + " HREF Pin: %d\n" + " Pixel Clock Pin: %d\n" + " External Clock: Pin:%d Frequency:%u\n" + " I2C Pins: SDA:%d SCL:%d\n" + " Reset Pin: %d", + this->name_.c_str(), YESNO(this->internal_), conf.pin_d0, conf.pin_d1, conf.pin_d2, conf.pin_d3, + conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7, conf.pin_vsync, conf.pin_href, conf.pin_pclk, + conf.pin_xclk, conf.xclk_freq_hz, conf.pin_sccb_sda, conf.pin_sccb_scl, conf.pin_reset); switch (this->config_.frame_size) { case FRAMESIZE_QQVGA: ESP_LOGCONFIG(TAG, " Resolution: 160x120 (QQVGA)"); @@ -123,24 +126,29 @@ void ESP32Camera::dump_config() { sensor_t *s = esp_camera_sensor_get(); auto st = s->status; - ESP_LOGCONFIG(TAG, " JPEG Quality: %u", st.quality); - ESP_LOGCONFIG(TAG, " Framebuffer Count: %u", conf.fb_count); - ESP_LOGCONFIG(TAG, " Contrast: %d", st.contrast); - ESP_LOGCONFIG(TAG, " Brightness: %d", st.brightness); - ESP_LOGCONFIG(TAG, " Saturation: %d", st.saturation); - ESP_LOGCONFIG(TAG, " Vertical Flip: %s", ONOFF(st.vflip)); - ESP_LOGCONFIG(TAG, " Horizontal Mirror: %s", ONOFF(st.hmirror)); - ESP_LOGCONFIG(TAG, " Special Effect: %u", st.special_effect); - ESP_LOGCONFIG(TAG, " White Balance Mode: %u", st.wb_mode); + ESP_LOGCONFIG(TAG, + " JPEG Quality: %u\n" + " Framebuffer Count: %u\n" + " Contrast: %d\n" + " Brightness: %d\n" + " Saturation: %d\n" + " Vertical Flip: %s\n" + " Horizontal Mirror: %s\n" + " Special Effect: %u\n" + " White Balance Mode: %u", + st.quality, conf.fb_count, st.contrast, st.brightness, st.saturation, ONOFF(st.vflip), + ONOFF(st.hmirror), st.special_effect, st.wb_mode); // ESP_LOGCONFIG(TAG, " Auto White Balance: %u", st.awb); // ESP_LOGCONFIG(TAG, " Auto White Balance Gain: %u", st.awb_gain); - ESP_LOGCONFIG(TAG, " Auto Exposure Control: %u", st.aec); - ESP_LOGCONFIG(TAG, " Auto Exposure Control 2: %u", st.aec2); - ESP_LOGCONFIG(TAG, " Auto Exposure Level: %d", st.ae_level); - ESP_LOGCONFIG(TAG, " Auto Exposure Value: %u", st.aec_value); - ESP_LOGCONFIG(TAG, " AGC: %u", st.agc); - ESP_LOGCONFIG(TAG, " AGC Gain: %u", st.agc_gain); - ESP_LOGCONFIG(TAG, " Gain Ceiling: %u", st.gainceiling); + ESP_LOGCONFIG(TAG, + " Auto Exposure Control: %u\n" + " Auto Exposure Control 2: %u\n" + " Auto Exposure Level: %d\n" + " Auto Exposure Value: %u\n" + " AGC: %u\n" + " AGC Gain: %u\n" + " Gain Ceiling: %u", + st.aec, st.aec2, st.ae_level, st.aec_value, st.agc, st.agc_gain, st.gainceiling); // ESP_LOGCONFIG(TAG, " BPC: %u", st.bpc); // ESP_LOGCONFIG(TAG, " WPC: %u", st.wpc); // ESP_LOGCONFIG(TAG, " RAW_GMA: %u", st.raw_gma); diff --git a/esphome/components/esp32_camera_web_server/camera_web_server.cpp b/esphome/components/esp32_camera_web_server/camera_web_server.cpp index 7ca0c56d23..0a83128908 100644 --- a/esphome/components/esp32_camera_web_server/camera_web_server.cpp +++ b/esphome/components/esp32_camera_web_server/camera_web_server.cpp @@ -85,8 +85,10 @@ void CameraWebServer::on_shutdown() { } void CameraWebServer::dump_config() { - ESP_LOGCONFIG(TAG, "ESP32 Camera Web Server:"); - ESP_LOGCONFIG(TAG, " Port: %d", this->port_); + ESP_LOGCONFIG(TAG, + "ESP32 Camera Web Server:\n" + " Port: %d", + this->port_); if (this->mode_ == STREAM) { ESP_LOGCONFIG(TAG, " Mode: stream"); } else { diff --git a/esphome/components/esp32_dac/esp32_dac.cpp b/esphome/components/esp32_dac/esp32_dac.cpp index 46e3553559..01bf0e04c3 100644 --- a/esphome/components/esp32_dac/esp32_dac.cpp +++ b/esphome/components/esp32_dac/esp32_dac.cpp @@ -1,6 +1,6 @@ #include "esp32_dac.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ESP32 diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index ca39c1cd36..fa33bd947a 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -1,6 +1,7 @@ from esphome import automation import esphome.codegen as cg -from esphome.components import binary_sensor, output +from esphome.components import binary_sensor, esp32_ble, output +from esphome.components.esp32_ble import BTLoggers import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID @@ -94,6 +95,9 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): + # Register the loggers this component needs + esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP) + var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index d74714838f..9d84d38968 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -324,10 +324,10 @@ void ESP32ImprovComponent::process_incoming_data_() { this->incoming_data_.clear(); } } else if (this->incoming_data_.size() - 2 > length) { - ESP_LOGV(TAG, "Too much data received or data malformed; resetting buffer..."); + ESP_LOGV(TAG, "Too much data received or data malformed; resetting buffer"); this->incoming_data_.clear(); } else { - ESP_LOGV(TAG, "Waiting for split data packets..."); + ESP_LOGV(TAG, "Waiting for split data packets"); } } diff --git a/esphome/components/esp32_rmt_led_strip/led_strip.cpp b/esphome/components/esp32_rmt_led_strip/led_strip.cpp index 9b15e1898e..88ddf24d49 100644 --- a/esphome/components/esp32_rmt_led_strip/led_strip.cpp +++ b/esphome/components/esp32_rmt_led_strip/led_strip.cpp @@ -143,7 +143,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) { this->last_refresh_ = now; this->mark_shown_(); - ESP_LOGVV(TAG, "Writing RGB values to bus..."); + ESP_LOGVV(TAG, "Writing RGB values to bus"); #if ESP_IDF_VERSION_MAJOR >= 5 esp_err_t error = rmt_tx_wait_all_done(this->channel_, 1000); @@ -247,8 +247,10 @@ light::ESPColorView ESP32RMTLEDStripLightOutput::get_view_internal(int32_t index } void ESP32RMTLEDStripLightOutput::dump_config() { - ESP_LOGCONFIG(TAG, "ESP32 RMT LED Strip:"); - ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_); + ESP_LOGCONFIG(TAG, + "ESP32 RMT LED Strip:\n" + " Pin: %u", + this->pin_); #if ESP_IDF_VERSION_MAJOR >= 5 ESP_LOGCONFIG(TAG, " RMT Symbols: %" PRIu32, this->rmt_symbols_); #else @@ -278,9 +280,11 @@ void ESP32RMTLEDStripLightOutput::dump_config() { rgb_order = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order); - ESP_LOGCONFIG(TAG, " Max refresh rate: %" PRIu32, *this->max_refresh_rate_); - ESP_LOGCONFIG(TAG, " Number of LEDs: %u", this->num_leds_); + ESP_LOGCONFIG(TAG, + " RGB Order: %s\n" + " Max refresh rate: %" PRIu32 "\n" + " Number of LEDs: %u", + rgb_order, *this->max_refresh_rate_, this->num_leds_); } float ESP32RMTLEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; } diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index ae92d99b12..596770b96d 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -131,7 +131,9 @@ CONFIG_SCHEMA = cv.All( esp32_idf=192, esp32_s2_idf=192, esp32_s3_idf=192, + esp32_p4_idf=192, esp32_c3_idf=96, + esp32_c5_idf=96, esp32_c6_idf=96, esp32_h2_idf=96, ): cv.All(only_with_new_rmt_driver, cv.int_range(min=2)), @@ -140,7 +142,9 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_IS_RGBW, default=False): cv.boolean, cv.Optional(CONF_IS_WRGB, default=False): cv.boolean, cv.Optional(CONF_USE_DMA): cv.All( - esp32.only_on_variant(supported=[esp32.const.VARIANT_ESP32S3]), + esp32.only_on_variant( + supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] + ), cv.only_with_esp_idf, cv.boolean, ), diff --git a/esphome/components/esp32_touch/esp32_touch.cpp b/esphome/components/esp32_touch/esp32_touch.cpp index b6fd2dda96..366aa10697 100644 --- a/esphome/components/esp32_touch/esp32_touch.cpp +++ b/esphome/components/esp32_touch/esp32_touch.cpp @@ -75,9 +75,11 @@ void ESP32TouchComponent::setup() { } void ESP32TouchComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Config for ESP32 Touch Hub:"); - ESP_LOGCONFIG(TAG, " Meas cycle: %.2fms", this->meas_cycle_ / (8000000.0f / 1000.0f)); - ESP_LOGCONFIG(TAG, " Sleep cycle: %.2fms", this->sleep_cycle_ / (150000.0f / 1000.0f)); + ESP_LOGCONFIG(TAG, + "Config for ESP32 Touch Hub:\n" + " Meas cycle: %.2fms\n" + " Sleep cycle: %.2fms", + this->meas_cycle_ / (8000000.0f / 1000.0f), this->sleep_cycle_ / (150000.0f / 1000.0f)); const char *lv_s; switch (this->low_voltage_reference_) { @@ -171,10 +173,12 @@ void ESP32TouchComponent::dump_config() { filter_mode_s = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " Filter mode: %s", filter_mode_s); - ESP_LOGCONFIG(TAG, " Debounce count: %" PRIu32, this->debounce_count_); - ESP_LOGCONFIG(TAG, " Noise threshold coefficient: %" PRIu32, this->noise_threshold_); - ESP_LOGCONFIG(TAG, " Jitter filter step size: %" PRIu32, this->jitter_step_); + ESP_LOGCONFIG(TAG, + " Filter mode: %s\n" + " Debounce count: %" PRIu32 "\n" + " Noise threshold coefficient: %" PRIu32 "\n" + " Jitter filter step size: %" PRIu32, + filter_mode_s, this->debounce_count_, this->noise_threshold_, this->jitter_step_); const char *smooth_level_s; switch (this->smooth_level_) { case TOUCH_PAD_SMOOTH_OFF: diff --git a/esphome/components/esp8266/gpio.cpp b/esphome/components/esp8266/gpio.cpp index 9f23e8e67e..4a997a790c 100644 --- a/esphome/components/esp8266/gpio.cpp +++ b/esphome/components/esp8266/gpio.cpp @@ -40,6 +40,7 @@ struct ISRPinArg { volatile uint32_t *mode_set_reg; volatile uint32_t *mode_clr_reg; volatile uint32_t *func_reg; + volatile uint32_t *control_reg; uint32_t mask; }; @@ -54,6 +55,7 @@ ISRInternalGPIOPin ESP8266GPIOPin::to_isr() const { arg->mode_set_reg = &GPES; arg->mode_clr_reg = &GPEC; arg->func_reg = &GPF(this->pin_); + arg->control_reg = &GPC(this->pin_); arg->mask = 1 << this->pin_; } else { arg->in_reg = &GP16I; @@ -62,6 +64,7 @@ ISRInternalGPIOPin ESP8266GPIOPin::to_isr() const { arg->mode_set_reg = &GP16E; arg->mode_clr_reg = nullptr; arg->func_reg = &GPF16; + arg->control_reg = nullptr; arg->mask = 1; } return ISRInternalGPIOPin((void *) arg); @@ -143,11 +146,17 @@ void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) { if (arg->pin < 16) { if (flags & gpio::FLAG_OUTPUT) { *arg->mode_set_reg = arg->mask; - } else { + if (flags & gpio::FLAG_OPEN_DRAIN) { + *arg->control_reg |= 1 << GPCD; + } else { + *arg->control_reg &= ~(1 << GPCD); + } + } else if (flags & gpio::FLAG_INPUT) { *arg->mode_clr_reg = arg->mask; } if (flags & gpio::FLAG_PULLUP) { *arg->func_reg |= 1 << GPFPU; + *arg->control_reg |= 1 << GPCD; } else { *arg->func_reg &= ~(1 << GPFPU); } diff --git a/esphome/components/esp8266/preferences.cpp b/esphome/components/esp8266/preferences.cpp index 8ee5a8225a..efd226e8f8 100644 --- a/esphome/components/esp8266/preferences.cpp +++ b/esphome/components/esp8266/preferences.cpp @@ -169,7 +169,7 @@ class ESP8266Preferences : public ESPPreferences { void setup() { s_flash_storage = new uint32_t[ESP8266_FLASH_STORAGE_SIZE]; // NOLINT - ESP_LOGVV(TAG, "Loading preferences from flash..."); + ESP_LOGVV(TAG, "Loading preferences from flash"); { InterruptLock lock; @@ -235,7 +235,7 @@ class ESP8266Preferences : public ESPPreferences { if (s_prevent_write) return false; - ESP_LOGD(TAG, "Saving preferences to flash..."); + ESP_LOGD(TAG, "Saving"); SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK; { InterruptLock lock; @@ -245,11 +245,11 @@ class ESP8266Preferences : public ESPPreferences { } } if (erase_res != SPI_FLASH_RESULT_OK) { - ESP_LOGE(TAG, "Erase ESP8266 flash failed!"); + ESP_LOGE(TAG, "Erasing failed"); return false; } if (write_res != SPI_FLASH_RESULT_OK) { - ESP_LOGE(TAG, "Write ESP8266 flash failed!"); + ESP_LOGE(TAG, "Writing failed"); return false; } @@ -258,14 +258,14 @@ class ESP8266Preferences : public ESPPreferences { } bool reset() override { - ESP_LOGD(TAG, "Cleaning up preferences in flash..."); + ESP_LOGD(TAG, "Erasing storage"); SpiFlashOpResult erase_res; { InterruptLock lock; erase_res = spi_flash_erase_sector(get_esp8266_flash_sector()); } if (erase_res != SPI_FLASH_RESULT_OK) { - ESP_LOGE(TAG, "Erase ESP8266 flash failed!"); + ESP_LOGE(TAG, "Erasing failed"); return false; } diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.cpp b/esphome/components/esp8266_pwm/esp8266_pwm.cpp index fcf66ee1a5..03fa3c683e 100644 --- a/esphome/components/esp8266_pwm/esp8266_pwm.cpp +++ b/esphome/components/esp8266_pwm/esp8266_pwm.cpp @@ -1,10 +1,10 @@ #ifdef USE_ESP8266 #include "esp8266_pwm.h" -#include "esphome/core/macros.h" #include "esphome/core/defines.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include "esphome/core/macros.h" #include diff --git a/esphome/components/esp_ldo/__init__.py b/esphome/components/esp_ldo/__init__.py new file mode 100644 index 0000000000..ce24028083 --- /dev/null +++ b/esphome/components/esp_ldo/__init__.py @@ -0,0 +1,91 @@ +from esphome.automation import Action, register_action +import esphome.codegen as cg +from esphome.components.esp32 import VARIANT_ESP32P4, only_on_variant +import esphome.config_validation as cv +from esphome.const import CONF_CHANNEL, CONF_ID, CONF_VOLTAGE +from esphome.final_validate import full_config + +CODEOWNERS = ["@clydebarrow"] + +DOMAIN = "esp_ldo" + +esp_ldo_ns = cg.esphome_ns.namespace("esp_ldo") +EspLdo = esp_ldo_ns.class_("EspLdo", cg.Component) +AdjustAction = esp_ldo_ns.class_("AdjustAction", Action) + +CHANNELS = (3, 4) +CONF_ADJUSTABLE = "adjustable" + +adjusted_ids = set() + +CONFIG_SCHEMA = cv.All( + cv.ensure_list( + { + cv.GenerateID(): cv.declare_id(EspLdo), + cv.Required(CONF_VOLTAGE): cv.All( + cv.voltage, cv.float_range(min=0.5, max=2.7) + ), + cv.Required(CONF_CHANNEL): cv.one_of(*CHANNELS, int=True), + cv.Optional(CONF_ADJUSTABLE, default=False): cv.boolean, + } + ), + cv.only_with_esp_idf, + only_on_variant(supported=[VARIANT_ESP32P4]), +) + + +async def to_code(configs): + for config in configs: + var = cg.new_Pvariable(config[CONF_ID], config[CONF_CHANNEL]) + await cg.register_component(var, config) + cg.add(var.set_voltage(config[CONF_VOLTAGE])) + cg.add(var.set_adjustable(config[CONF_ADJUSTABLE])) + + +def final_validate(configs): + for channel in CHANNELS: + used = [config for config in configs if config[CONF_CHANNEL] == channel] + if len(used) > 1: + raise cv.Invalid( + f"Multiple LDOs configured for channel {channel}. Each channel must be unique.", + path=[CONF_CHANNEL, channel], + ) + + global_config = full_config.get() + for w in adjusted_ids: + path = global_config.get_path_for_id(w) + ldo_conf = global_config.get_config_for_path(path[:-1]) + if not ldo_conf[CONF_ADJUSTABLE]: + raise cv.Invalid( + "A non adjustable LDO may not be adjusted.", + path, + ) + + +FINAL_VALIDATE_SCHEMA = final_validate + + +def adjusted_ldo_id(value): + value = cv.use_id(EspLdo)(value) + adjusted_ids.add(value) + return value + + +@register_action( + "esp_ldo.voltage.adjust", + AdjustAction, + cv.Schema( + { + cv.GenerateID(CONF_ID): adjusted_ldo_id, + cv.Required(CONF_VOLTAGE): cv.templatable( + cv.All(cv.voltage, cv.float_range(min=0.5, max=2.7)) + ), + } + ), +) +async def ldo_voltage_adjust_to_code(config, action_id, template_arg, args): + parent = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, parent) + template_ = await cg.templatable(config[CONF_VOLTAGE], args, cg.float_) + cg.add(var.set_voltage(template_)) + return var diff --git a/esphome/components/esp_ldo/esp_ldo.cpp b/esphome/components/esp_ldo/esp_ldo.cpp new file mode 100644 index 0000000000..eb04670d7e --- /dev/null +++ b/esphome/components/esp_ldo/esp_ldo.cpp @@ -0,0 +1,43 @@ +#ifdef USE_ESP32_VARIANT_ESP32P4 +#include "esp_ldo.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace esp_ldo { + +static const char *const TAG = "esp_ldo"; +void EspLdo::setup() { + esp_ldo_channel_config_t config{}; + config.chan_id = this->channel_; + config.voltage_mv = (int) (this->voltage_ * 1000.0f); + config.flags.adjustable = this->adjustable_; + auto err = esp_ldo_acquire_channel(&config, &this->handle_); + if (err != ESP_OK) { + auto msg = str_sprintf("Failed to acquire LDO channel %d with voltage %fV", this->channel_, this->voltage_); + this->mark_failed(msg.c_str()); + } else { + ESP_LOGD(TAG, "Acquired LDO channel %d with voltage %fV", this->channel_, this->voltage_); + } +} +void EspLdo::dump_config() { + ESP_LOGCONFIG(TAG, "ESP LDO Channel %d:", this->channel_); + ESP_LOGCONFIG(TAG, " Voltage: %fV", this->voltage_); + ESP_LOGCONFIG(TAG, " Adjustable: %s", YESNO(this->adjustable_)); +} + +void EspLdo::adjust_voltage(float voltage) { + if (!std::isfinite(voltage) || voltage < 0.5f || voltage > 2.7f) { + ESP_LOGE(TAG, "Invalid voltage %fV for LDO channel %d", voltage, this->channel_); + return; + } + auto erro = esp_ldo_channel_adjust_voltage(this->handle_, (int) (voltage * 1000.0f)); + if (erro != ESP_OK) { + ESP_LOGE(TAG, "Failed to adjust LDO channel %d to voltage %fV: %s", this->channel_, voltage, esp_err_to_name(erro)); + } +} + +} // namespace esp_ldo +} // namespace esphome + +#endif // USE_ESP32_VARIANT_ESP32P4 diff --git a/esphome/components/esp_ldo/esp_ldo.h b/esphome/components/esp_ldo/esp_ldo.h new file mode 100644 index 0000000000..fb5abf7a3a --- /dev/null +++ b/esphome/components/esp_ldo/esp_ldo.h @@ -0,0 +1,43 @@ +#pragma once +#ifdef USE_ESP32_VARIANT_ESP32P4 +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esp_ldo_regulator.h" + +namespace esphome { +namespace esp_ldo { + +class EspLdo : public Component { + public: + EspLdo(int channel) : channel_(channel) {} + + void setup() override; + void dump_config() override; + + void set_adjustable(bool adjustable) { this->adjustable_ = adjustable; } + void set_voltage(float voltage) { this->voltage_ = voltage; } + void adjust_voltage(float voltage); + + protected: + int channel_; + float voltage_{2.7}; + bool adjustable_{false}; + esp_ldo_channel_handle_t handle_{}; +}; + +template class AdjustAction : public Action { + public: + explicit AdjustAction(EspLdo *ldo) : ldo_(ldo) {} + + TEMPLATABLE_VALUE(float, voltage) + + void play(Ts... x) override { this->ldo_->adjust_voltage(this->voltage_.value(x...)); } + + protected: + EspLdo *ldo_; +}; + +} // namespace esp_ldo +} // namespace esphome + +#endif // USE_ESP32_VARIANT_ESP32P4 diff --git a/esphome/components/esphome/ota/ota_esphome.cpp b/esphome/components/esphome/ota/ota_esphome.cpp index 6f128e548b..227cb676ff 100644 --- a/esphome/components/esphome/ota/ota_esphome.cpp +++ b/esphome/components/esphome/ota/ota_esphome.cpp @@ -70,9 +70,11 @@ void ESPHomeOTAComponent::setup() { } void ESPHomeOTAComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Over-The-Air updates:"); - ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->port_); - ESP_LOGCONFIG(TAG, " Version: %d", USE_OTA_VERSION); + ESP_LOGCONFIG(TAG, + "Over-The-Air updates:\n" + " Address: %s:%u\n" + " Version: %d", + network::get_use_address().c_str(), this->port_, USE_OTA_VERSION); #ifdef USE_OTA_PASSWORD if (!this->password_.empty()) { ESP_LOGCONFIG(TAG, " Password configured"); @@ -119,7 +121,7 @@ void ESPHomeOTAComponent::handle_() { return; } - ESP_LOGD(TAG, "Starting update from %s...", this->client_->getpeername().c_str()); + ESP_LOGD(TAG, "Starting update from %s", this->client_->getpeername().c_str()); this->status_set_warning(); #ifdef USE_OTA_STATE_CALLBACK this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index c76c5523b2..fe96973924 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -245,33 +245,33 @@ void EthernetComponent::loop() { switch (this->state_) { case EthernetComponentState::STOPPED: if (this->started_) { - ESP_LOGI(TAG, "Starting ethernet connection"); + ESP_LOGI(TAG, "Starting connection"); this->state_ = EthernetComponentState::CONNECTING; this->start_connect_(); } break; case EthernetComponentState::CONNECTING: if (!this->started_) { - ESP_LOGI(TAG, "Stopped ethernet connection"); + ESP_LOGI(TAG, "Stopped connection"); this->state_ = EthernetComponentState::STOPPED; } else if (this->connected_) { // connection established - ESP_LOGI(TAG, "Connected via Ethernet!"); + ESP_LOGI(TAG, "Connected"); this->state_ = EthernetComponentState::CONNECTED; this->dump_connect_params_(); this->status_clear_warning(); } else if (now - this->connect_begin_ > 15000) { - ESP_LOGW(TAG, "Connecting via ethernet failed! Re-connecting..."); + ESP_LOGW(TAG, "Connecting failed; reconnecting"); this->start_connect_(); } break; case EthernetComponentState::CONNECTED: if (!this->started_) { - ESP_LOGI(TAG, "Stopped ethernet connection"); + ESP_LOGI(TAG, "Stopped connection"); this->state_ = EthernetComponentState::STOPPED; } else if (!this->connected_) { - ESP_LOGW(TAG, "Connection via Ethernet lost! Re-connecting..."); + ESP_LOGW(TAG, "Connection lost; reconnecting"); this->state_ = EthernetComponentState::CONNECTING; this->start_connect_(); } @@ -326,10 +326,12 @@ void EthernetComponent::dump_config() { ESP_LOGCONFIG(TAG, "Ethernet:"); this->dump_connect_params_(); #ifdef USE_ETHERNET_SPI - ESP_LOGCONFIG(TAG, " CLK Pin: %u", this->clk_pin_); - ESP_LOGCONFIG(TAG, " MISO Pin: %u", this->miso_pin_); - ESP_LOGCONFIG(TAG, " MOSI Pin: %u", this->mosi_pin_); - ESP_LOGCONFIG(TAG, " CS Pin: %u", this->cs_pin_); + ESP_LOGCONFIG(TAG, + " CLK Pin: %u\n" + " MISO Pin: %u\n" + " MOSI Pin: %u\n" + " CS Pin: %u", + this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_); #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT if (this->polling_interval_ != 0) { ESP_LOGCONFIG(TAG, " Polling Interval: %lu ms", this->polling_interval_); @@ -338,15 +340,19 @@ void EthernetComponent::dump_config() { { ESP_LOGCONFIG(TAG, " IRQ Pin: %d", this->interrupt_pin_); } - ESP_LOGCONFIG(TAG, " Reset Pin: %d", this->reset_pin_); - ESP_LOGCONFIG(TAG, " Clock Speed: %d MHz", this->clock_speed_ / 1000000); + ESP_LOGCONFIG(TAG, + " Reset Pin: %d\n" + " Clock Speed: %d MHz", + this->reset_pin_, this->clock_speed_ / 1000000); #else if (this->power_pin_ != -1) { ESP_LOGCONFIG(TAG, " Power Pin: %u", this->power_pin_); } - ESP_LOGCONFIG(TAG, " MDC Pin: %u", this->mdc_pin_); - ESP_LOGCONFIG(TAG, " MDIO Pin: %u", this->mdio_pin_); - ESP_LOGCONFIG(TAG, " PHY addr: %u", this->phy_addr_); + ESP_LOGCONFIG(TAG, + " MDC Pin: %u\n" + " MDIO Pin: %u\n" + " PHY addr: %u", + this->mdc_pin_, this->mdio_pin_, this->phy_addr_); #endif ESP_LOGCONFIG(TAG, " Type: %s", eth_type); } @@ -512,16 +518,19 @@ bool EthernetComponent::is_connected() { return this->state_ == EthernetComponen void EthernetComponent::dump_connect_params_() { esp_netif_ip_info_t ip; esp_netif_get_ip_info(this->eth_netif_, &ip); - ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(&ip.ip).str().c_str()); - ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str()); - ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(&ip.netmask).str().c_str()); - ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(&ip.gw).str().c_str()); - const ip_addr_t *dns_ip1 = dns_getserver(0); const ip_addr_t *dns_ip2 = dns_getserver(1); - ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1).str().c_str()); - ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2).str().c_str()); + ESP_LOGCONFIG(TAG, + " IP Address: %s\n" + " Hostname: '%s'\n" + " Subnet: %s\n" + " Gateway: %s\n" + " DNS1: %s\n" + " DNS2: %s", + network::IPAddress(&ip.ip).str().c_str(), App.get_name().c_str(), + network::IPAddress(&ip.netmask).str().c_str(), network::IPAddress(&ip.gw).str().c_str(), + network::IPAddress(dns_ip1).str().c_str(), network::IPAddress(dns_ip2).str().c_str()); #if USE_NETWORK_IPV6 struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; @@ -533,9 +542,12 @@ void EthernetComponent::dump_connect_params_() { } #endif /* USE_NETWORK_IPV6 */ - ESP_LOGCONFIG(TAG, " MAC Address: %s", this->get_eth_mac_address_pretty().c_str()); - ESP_LOGCONFIG(TAG, " Is Full Duplex: %s", YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL)); - ESP_LOGCONFIG(TAG, " Link Speed: %u", this->get_link_speed() == ETH_SPEED_100M ? 100 : 10); + ESP_LOGCONFIG(TAG, + " MAC Address: %s\n" + " Is Full Duplex: %s\n" + " Link Speed: %u", + this->get_eth_mac_address_pretty().c_str(), YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL), + this->get_link_speed() == ETH_SPEED_100M ? 100 : 10); } #ifdef USE_ETHERNET_SPI diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index fb178431d5..7a205d89f0 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -56,7 +56,7 @@ class EthernetComponent : public Component { void dump_config() override; float get_setup_priority() const override; bool can_proceed() override; - void on_shutdown() override { powerdown(); } + void on_powerdown() override { powerdown(); } bool is_connected(); #ifdef USE_ETHERNET_SPI diff --git a/esphome/components/event/__init__.py b/esphome/components/event/__init__.py index 0e5fb43690..e7ab489a25 100644 --- a/esphome/components/event/__init__.py +++ b/esphome/components/event/__init__.py @@ -113,6 +113,7 @@ async def register_event(var, config, *, event_types: list[str]): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_event(var)) + CORE.register_platform_component("event", var) await setup_event_core_(var, config, event_types=event_types) diff --git a/esphome/components/exposure_notifications/exposure_notifications.cpp b/esphome/components/exposure_notifications/exposure_notifications.cpp index 3083cf429c..307bee26f8 100644 --- a/esphome/components/exposure_notifications/exposure_notifications.cpp +++ b/esphome/components/exposure_notifications/exposure_notifications.cpp @@ -1,6 +1,6 @@ #include "exposure_notifications.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ESP32 diff --git a/esphome/components/factory_reset/button/factory_reset_button.cpp b/esphome/components/factory_reset/button/factory_reset_button.cpp index a6e7b41e82..585975c043 100644 --- a/esphome/components/factory_reset/button/factory_reset_button.cpp +++ b/esphome/components/factory_reset/button/factory_reset_button.cpp @@ -10,7 +10,7 @@ static const char *const TAG = "factory_reset.button"; void FactoryResetButton::dump_config() { LOG_BUTTON("", "Factory Reset Button", this); } void FactoryResetButton::press_action() { - ESP_LOGI(TAG, "Resetting..."); + ESP_LOGI(TAG, "Resetting"); // Let MQTT settle a bit delay(100); // NOLINT global_preferences->reset(); diff --git a/esphome/components/factory_reset/switch/factory_reset_switch.cpp b/esphome/components/factory_reset/switch/factory_reset_switch.cpp index 116d696aa7..1282c73f4e 100644 --- a/esphome/components/factory_reset/switch/factory_reset_switch.cpp +++ b/esphome/components/factory_reset/switch/factory_reset_switch.cpp @@ -14,7 +14,7 @@ void FactoryResetSwitch::write_state(bool state) { this->publish_state(false); if (state) { - ESP_LOGI(TAG, "Resetting..."); + ESP_LOGI(TAG, "Resetting"); // Let MQTT settle a bit delay(100); // NOLINT global_preferences->reset(); diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 960809ff70..c6ff938cd6 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -296,6 +296,7 @@ async def register_fan(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_fan(var)) + CORE.register_platform_component("fan", var) await setup_fan_core_(var, config) diff --git a/esphome/components/fan/fan.cpp b/esphome/components/fan/fan.cpp index 1d560d2fc6..87bf4939a0 100644 --- a/esphome/components/fan/fan.cpp +++ b/esphome/components/fan/fan.cpp @@ -189,8 +189,10 @@ void Fan::dump_traits_(const char *tag, const char *prefix) { auto traits = this->get_traits(); if (traits.supports_speed()) { - ESP_LOGCONFIG(tag, "%s Speed: YES", prefix); - ESP_LOGCONFIG(tag, "%s Speed count: %d", prefix, traits.supported_speed_count()); + ESP_LOGCONFIG(tag, + "%s Speed: YES\n" + "%s Speed count: %d", + prefix, prefix, traits.supported_speed_count()); } if (traits.supports_oscillation()) { ESP_LOGCONFIG(tag, "%s Oscillation: YES", prefix); diff --git a/esphome/components/fastled_base/fastled_light.cpp b/esphome/components/fastled_base/fastled_light.cpp index 5d5b65cb7e..bca7de811a 100644 --- a/esphome/components/fastled_base/fastled_light.cpp +++ b/esphome/components/fastled_base/fastled_light.cpp @@ -18,9 +18,11 @@ void FastLEDLightOutput::setup() { } } void FastLEDLightOutput::dump_config() { - ESP_LOGCONFIG(TAG, "FastLED light:"); - ESP_LOGCONFIG(TAG, " Num LEDs: %u", this->num_leds_); - ESP_LOGCONFIG(TAG, " Max refresh rate: %u", *this->max_refresh_rate_); + ESP_LOGCONFIG(TAG, + "FastLED light:\n" + " Num LEDs: %u\n" + " Max refresh rate: %u", + this->num_leds_, *this->max_refresh_rate_); } void FastLEDLightOutput::write_state(light::LightState *state) { // protect from refreshing too often @@ -33,7 +35,7 @@ void FastLEDLightOutput::write_state(light::LightState *state) { this->last_refresh_ = now; this->mark_shown_(); - ESP_LOGVV(TAG, "Writing RGB values to bus..."); + ESP_LOGVV(TAG, "Writing RGB values to bus"); this->controller_->showLeds(this->state_parent_->current_values.get_brightness() * 255); } diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index 57b12ef228..e28548428c 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -534,11 +534,13 @@ void FingerprintGrowComponent::sensor_sleep_() { } void FingerprintGrowComponent::dump_config() { - ESP_LOGCONFIG(TAG, "GROW_FINGERPRINT_READER:"); - ESP_LOGCONFIG(TAG, " System Identifier Code: 0x%.4X", this->system_identifier_code_); - ESP_LOGCONFIG(TAG, " Touch Sensing Pin: %s", - this->has_sensing_pin_ ? this->sensing_pin_->dump_summary().c_str() : "None"); - ESP_LOGCONFIG(TAG, " Sensor Power Pin: %s", + ESP_LOGCONFIG(TAG, + "GROW_FINGERPRINT_READER:\n" + " System Identifier Code: 0x%.4X\n" + " Touch Sensing Pin: %s\n" + " Sensor Power Pin: %s", + this->system_identifier_code_, + this->has_sensing_pin_ ? this->sensing_pin_->dump_summary().c_str() : "None", this->has_power_pin_ ? this->sensor_power_pin_->dump_summary().c_str() : "None"); if (this->idle_period_to_sleep_ms_ < UINT32_MAX) { ESP_LOGCONFIG(TAG, " Idle Period to Sleep: %" PRIu32 " ms", this->idle_period_to_sleep_ms_); diff --git a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp index 3e12d06647..9873a88fde 100644 --- a/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp +++ b/esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp @@ -1,5 +1,6 @@ #include "ft5x06_touchscreen.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { @@ -81,9 +82,11 @@ void FT5x06Touchscreen::update_touches() { } void FT5x06Touchscreen::dump_config() { - ESP_LOGCONFIG(TAG, "FT5x06 Touchscreen:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); - ESP_LOGCONFIG(TAG, " Vendor ID: 0x%X", (int) this->vendor_id_); + ESP_LOGCONFIG(TAG, + "FT5x06 Touchscreen:\n" + " Address: 0x%02X\n" + " Vendor ID: 0x%X", + this->address_, (int) this->vendor_id_); } bool FT5x06Touchscreen::err_check_(i2c::ErrorCode err, const char *msg) { diff --git a/esphome/components/ft63x6/ft63x6.cpp b/esphome/components/ft63x6/ft63x6.cpp index cd5a646d2e..ba5b2094a5 100644 --- a/esphome/components/ft63x6/ft63x6.cpp +++ b/esphome/components/ft63x6/ft63x6.cpp @@ -71,8 +71,10 @@ void FT63X6Touchscreen::dump_config() { LOG_I2C_DEVICE(this); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " X Calibration: [%d, %d]", this->x_raw_min_, this->x_raw_max_); - ESP_LOGCONFIG(TAG, " Y Calibration: [%d, %d]", this->y_raw_min_, this->y_raw_max_); + ESP_LOGCONFIG(TAG, + " X Calibration: [%d, %d]\n" + " Y Calibration: [%d, %d]", + this->x_raw_min_, this->x_raw_max_, this->y_raw_min_, this->y_raw_max_); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/gcja5/gcja5.cpp b/esphome/components/gcja5/gcja5.cpp index 29b0b910a7..a7342bc828 100644 --- a/esphome/components/gcja5/gcja5.cpp +++ b/esphome/components/gcja5/gcja5.cpp @@ -76,16 +76,6 @@ bool GCJA5Component::calculate_checksum_() { return (crc == this->rx_message_[30]); } -uint32_t GCJA5Component::get_32_bit_uint_(uint8_t start_index) { - return (((uint32_t) this->rx_message_[start_index + 3]) << 24) | - (((uint32_t) this->rx_message_[start_index + 2]) << 16) | - (((uint32_t) this->rx_message_[start_index + 1]) << 8) | ((uint32_t) this->rx_message_[start_index]); -} - -uint16_t GCJA5Component::get_16_bit_uint_(uint8_t start_index) { - return (((uint32_t) this->rx_message_[start_index + 1]) << 8) | ((uint32_t) this->rx_message_[start_index]); -} - void GCJA5Component::parse_data_() { ESP_LOGVV(TAG, "GCJA5 Data: "); for (uint8_t i = 0; i < 32; i++) { diff --git a/esphome/components/gcja5/gcja5.h b/esphome/components/gcja5/gcja5.h index 844da33a54..ea1fb78bf0 100644 --- a/esphome/components/gcja5/gcja5.h +++ b/esphome/components/gcja5/gcja5.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" @@ -28,8 +29,13 @@ class GCJA5Component : public Component, public uart::UARTDevice { void parse_data_(); bool calculate_checksum_(); - uint32_t get_32_bit_uint_(uint8_t start_index); - uint16_t get_16_bit_uint_(uint8_t start_index); + uint16_t get_16_bit_uint_(uint8_t start_index) const { + return encode_uint16(this->rx_message_[start_index + 1], this->rx_message_[start_index]); + } + uint32_t get_32_bit_uint_(uint8_t start_index) const { + return encode_uint32(this->rx_message_[start_index + 3], this->rx_message_[start_index + 2], + this->rx_message_[start_index + 1], this->rx_message_[start_index]); + } uint32_t last_transmission_{0}; std::vector rx_message_; diff --git a/esphome/components/globals/globals_component.h b/esphome/components/globals/globals_component.h index 78808436af..4c6a12aa72 100644 --- a/esphome/components/globals/globals_component.h +++ b/esphome/components/globals/globals_component.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/core/automation.h" +#include "esphome/core/component.h" #include "esphome/core/helpers.h" #include @@ -39,7 +39,7 @@ template class RestoringGlobalsComponent : public Component { void setup() override { this->rtc_ = global_preferences->make_preference(1944399030U ^ this->name_hash_); this->rtc_.load(&this->value_); - memcpy(&this->prev_value_, &this->value_, sizeof(T)); + memcpy(&this->last_checked_value_, &this->value_, sizeof(T)); } float get_setup_priority() const override { return setup_priority::HARDWARE; } @@ -52,15 +52,15 @@ template class RestoringGlobalsComponent : public Component { protected: void store_value_() { - int diff = memcmp(&this->value_, &this->prev_value_, sizeof(T)); + int diff = memcmp(&this->value_, &this->last_checked_value_, sizeof(T)); if (diff != 0) { this->rtc_.save(&this->value_); - memcpy(&this->prev_value_, &this->value_, sizeof(T)); + memcpy(&this->last_checked_value_, &this->value_, sizeof(T)); } } T value_{}; - T prev_value_{}; + T last_checked_value_{}; uint32_t name_hash_{}; ESPPreferenceObject rtc_; }; @@ -85,7 +85,7 @@ template class RestoringGlobalStringComponent : public C if (hasdata) { this->value_.assign(temp + 1, temp[0]); } - this->prev_value_.assign(this->value_); + this->last_checked_value_.assign(this->value_); } float get_setup_priority() const override { return setup_priority::HARDWARE; } @@ -98,13 +98,12 @@ template class RestoringGlobalStringComponent : public C protected: void store_value_() { - int diff = this->value_.compare(this->prev_value_); + int diff = this->value_.compare(this->last_checked_value_); if (diff != 0) { // Make it into a length prefixed thing unsigned char temp[SZ]; // If string is bigger than the allocation, do not save it. - // We don't need to waste ram setting prev_value either. int size = this->value_.size(); // Less than, not less than or equal, SZ includes the length byte. if (size < SZ) { @@ -112,13 +111,17 @@ template class RestoringGlobalStringComponent : public C // SZ should be pre checked at the schema level, it can't go past the char range. temp[0] = ((unsigned char) size); this->rtc_.save(&temp); - this->prev_value_.assign(this->value_); } + // Always update last_checked_value_ to match current value, even for oversized strings. + // This prevents redundant size checks on every loop iteration when a string remains oversized. + // Without this, the diff != 0 check would pass repeatedly for the same oversized string, + // wasting CPU cycles on size comparisons. + this->last_checked_value_.assign(this->value_); } } T value_{}; - T prev_value_{}; + T last_checked_value_{}; uint32_t name_hash_{}; ESPPreferenceObject rtc_; }; diff --git a/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp b/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp index 95b7653e51..c8b0f13d3a 100644 --- a/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp +++ b/esphome/components/gp2y1010au0f/gp2y1010au0f.cpp @@ -13,8 +13,10 @@ static const float MAX_VOLTAGE = 4.0f; void GP2Y1010AU0FSensor::dump_config() { LOG_SENSOR("", "Sharp GP2Y1010AU0F PM2.5 Sensor", this); - ESP_LOGCONFIG(TAG, " Sampling duration: %" PRId32 " ms", this->sample_duration_); - ESP_LOGCONFIG(TAG, " ADC voltage multiplier: %.3f", this->voltage_multiplier_); + ESP_LOGCONFIG(TAG, + " Sampling duration: %" PRId32 " ms\n" + " ADC voltage multiplier: %.3f", + this->sample_duration_, this->voltage_multiplier_); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/gp8403/gp8403.cpp b/esphome/components/gp8403/gp8403.cpp index 7a08a18a8f..5107e96dee 100644 --- a/esphome/components/gp8403/gp8403.cpp +++ b/esphome/components/gp8403/gp8403.cpp @@ -12,8 +12,10 @@ static const uint8_t RANGE_REGISTER = 0x01; void GP8403::setup() { this->write_register(RANGE_REGISTER, (uint8_t *) (&this->voltage_), 1); } void GP8403::dump_config() { - ESP_LOGCONFIG(TAG, "GP8403:"); - ESP_LOGCONFIG(TAG, " Voltage: %dV", this->voltage_ == GP8403_VOLTAGE_5V ? 5 : 10); + ESP_LOGCONFIG(TAG, + "GP8403:\n" + " Voltage: %dV", + this->voltage_ == GP8403_VOLTAGE_5V ? 5 : 10); LOG_I2C_DEVICE(this); } diff --git a/esphome/components/gp8403/output/gp8403_output.cpp b/esphome/components/gp8403/output/gp8403_output.cpp index ff73bb4627..edb6972184 100644 --- a/esphome/components/gp8403/output/gp8403_output.cpp +++ b/esphome/components/gp8403/output/gp8403_output.cpp @@ -10,8 +10,10 @@ static const char *const TAG = "gp8403.output"; static const uint8_t OUTPUT_REGISTER = 0x02; void GP8403Output::dump_config() { - ESP_LOGCONFIG(TAG, "GP8403 Output:"); - ESP_LOGCONFIG(TAG, " Channel: %u", this->channel_); + ESP_LOGCONFIG(TAG, + "GP8403 Output:\n" + " Channel: %u", + this->channel_); } void GP8403Output::write_state(float state) { diff --git a/esphome/components/gpio/one_wire/gpio_one_wire.cpp b/esphome/components/gpio/one_wire/gpio_one_wire.cpp index 7022c5fc31..ee80fde6fa 100644 --- a/esphome/components/gpio/one_wire/gpio_one_wire.cpp +++ b/esphome/components/gpio/one_wire/gpio_one_wire.cpp @@ -1,6 +1,6 @@ #include "gpio_one_wire.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace gpio { diff --git a/esphome/components/graphical_display_menu/graphical_display_menu.cpp b/esphome/components/graphical_display_menu/graphical_display_menu.cpp index 4a4e519009..1a29536b46 100644 --- a/esphome/components/graphical_display_menu/graphical_display_menu.cpp +++ b/esphome/components/graphical_display_menu/graphical_display_menu.cpp @@ -36,14 +36,18 @@ void GraphicalDisplayMenu::setup() { } void GraphicalDisplayMenu::dump_config() { - ESP_LOGCONFIG(TAG, "Graphical Display Menu"); - ESP_LOGCONFIG(TAG, "Has Display: %s", YESNO(this->display_ != nullptr)); - ESP_LOGCONFIG(TAG, "Popup Mode: %s", YESNO(this->display_ != nullptr)); - ESP_LOGCONFIG(TAG, "Advanced Drawing Mode: %s", YESNO(this->display_ == nullptr)); - ESP_LOGCONFIG(TAG, "Has Font: %s", YESNO(this->font_ != nullptr)); - ESP_LOGCONFIG(TAG, "Mode: %s", this->mode_ == display_menu_base::MENU_MODE_ROTARY ? "Rotary" : "Joystick"); - ESP_LOGCONFIG(TAG, "Active: %s", YESNO(this->active_)); - ESP_LOGCONFIG(TAG, "Menu items:"); + ESP_LOGCONFIG(TAG, + "Graphical Display Menu\n" + "Has Display: %s\n" + "Popup Mode: %s\n" + "Advanced Drawing Mode: %s\n" + "Has Font: %s\n" + "Mode: %s\n" + "Active: %s\n" + "Menu items:", + YESNO(this->display_ != nullptr), YESNO(this->display_ != nullptr), YESNO(this->display_ == nullptr), + YESNO(this->font_ != nullptr), + this->mode_ == display_menu_base::MENU_MODE_ROTARY ? "Rotary" : "Joystick", YESNO(this->active_)); for (size_t i = 0; i < this->displayed_item_->items_size(); i++) { auto *item = this->displayed_item_->get_item(i); ESP_LOGCONFIG(TAG, " %i: %s (Type: %s, Immediate Edit: %s)", i, item->get_text().c_str(), diff --git a/esphome/components/grove_tb6612fng/grove_tb6612fng.h b/esphome/components/grove_tb6612fng/grove_tb6612fng.h index 2743ef4ed7..68281117e7 100644 --- a/esphome/components/grove_tb6612fng/grove_tb6612fng.h +++ b/esphome/components/grove_tb6612fng/grove_tb6612fng.h @@ -1,9 +1,9 @@ #pragma once #include "esphome/components/i2c/i2c.h" +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" -#include "esphome/core/automation.h" //#include "esphome/core/helpers.h" /* diff --git a/esphome/components/growatt_solar/growatt_solar.cpp b/esphome/components/growatt_solar/growatt_solar.cpp index 60fd1379e8..686c1c232e 100644 --- a/esphome/components/growatt_solar/growatt_solar.cpp +++ b/esphome/components/growatt_solar/growatt_solar.cpp @@ -1,6 +1,7 @@ #include "growatt_solar.h" -#include "esphome/core/log.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace growatt_solar { @@ -134,8 +135,10 @@ void GrowattSolar::on_modbus_data(const std::vector &data) { } void GrowattSolar::dump_config() { - ESP_LOGCONFIG(TAG, "GROWATT Solar:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "GROWATT Solar:\n" + " Address: 0x%02X", + this->address_); } } // namespace growatt_solar diff --git a/esphome/components/haier/haier_base.cpp b/esphome/components/haier/haier_base.cpp index f8c0a7587e..a784accdf4 100644 --- a/esphome/components/haier/haier_base.cpp +++ b/esphome/components/haier/haier_base.cpp @@ -242,7 +242,7 @@ haier_protocol::HandlerError HaierClimateBase::timeout_default_handler_(haier_pr } void HaierClimateBase::setup() { - ESP_LOGI(TAG, "Haier initialization..."); + ESP_LOGCONFIG(TAG, "Running setup"); // Set timestamp here to give AC time to boot this->last_request_timestamp_ = std::chrono::steady_clock::now(); this->set_phase(ProtocolPhases::SENDING_INIT_1); @@ -286,7 +286,7 @@ void HaierClimateBase::loop() { if (this->action_request_.has_value() && this->prepare_pending_action()) { this->set_phase(ProtocolPhases::SENDING_ACTION_COMMAND); } else if (this->next_hvac_settings_.valid || this->force_send_control_) { - ESP_LOGV(TAG, "Control packet is pending..."); + ESP_LOGV(TAG, "Control packet is pending"); this->set_phase(ProtocolPhases::SENDING_CONTROL); if (this->next_hvac_settings_.valid) { this->current_hvac_settings_ = this->next_hvac_settings_; diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 9b59dd0c10..fd2d6a5800 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -339,13 +339,20 @@ void HonClimate::set_handlers() { void HonClimate::dump_config() { HaierClimateBase::dump_config(); - ESP_LOGCONFIG(TAG, " Protocol version: hOn"); - ESP_LOGCONFIG(TAG, " Control method: %d", (uint8_t) this->control_method_); + ESP_LOGCONFIG(TAG, + " Protocol version: hOn\n" + " Control method: %d", + (uint8_t) this->control_method_); if (this->hvac_hardware_info_.has_value()) { - ESP_LOGCONFIG(TAG, " Device protocol version: %s", this->hvac_hardware_info_.value().protocol_version_.c_str()); - ESP_LOGCONFIG(TAG, " Device software version: %s", this->hvac_hardware_info_.value().software_version_.c_str()); - ESP_LOGCONFIG(TAG, " Device hardware version: %s", this->hvac_hardware_info_.value().hardware_version_.c_str()); - ESP_LOGCONFIG(TAG, " Device name: %s", this->hvac_hardware_info_.value().device_name_.c_str()); + ESP_LOGCONFIG(TAG, + " Device protocol version: %s\n" + " Device software version: %s\n" + " Device hardware version: %s\n" + " Device name: %s", + this->hvac_hardware_info_.value().protocol_version_.c_str(), + this->hvac_hardware_info_.value().software_version_.c_str(), + this->hvac_hardware_info_.value().hardware_version_.c_str(), + this->hvac_hardware_info_.value().device_name_.c_str()); ESP_LOGCONFIG(TAG, " Device features:%s%s%s%s%s", (this->hvac_hardware_info_.value().functions_[0] ? " interactive" : ""), (this->hvac_hardware_info_.value().functions_[1] ? " controller-device" : ""), diff --git a/esphome/components/havells_solar/havells_solar.cpp b/esphome/components/havells_solar/havells_solar.cpp index f029df10ad..20dddf39ed 100644 --- a/esphome/components/havells_solar/havells_solar.cpp +++ b/esphome/components/havells_solar/havells_solar.cpp @@ -1,5 +1,6 @@ #include "havells_solar.h" #include "havells_solar_registers.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { @@ -123,8 +124,10 @@ void HavellsSolar::on_modbus_data(const std::vector &data) { void HavellsSolar::update() { this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT); } void HavellsSolar::dump_config() { - ESP_LOGCONFIG(TAG, "HAVELLS Solar:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "HAVELLS Solar:\n" + " Address: 0x%02X", + this->address_); for (uint8_t i = 0; i < 3; i++) { auto phase = this->phases_[i]; if (!phase.setup) diff --git a/esphome/components/he60r/he60r.cpp b/esphome/components/he60r/he60r.cpp index 83e895543d..ca17930272 100644 --- a/esphome/components/he60r/he60r.cpp +++ b/esphome/components/he60r/he60r.cpp @@ -40,8 +40,10 @@ CoverTraits HE60rCover::get_traits() { void HE60rCover::dump_config() { LOG_COVER("", "HE60R Cover", this); this->check_uart_settings(1200, 1, uart::UART_CONFIG_PARITY_EVEN, 8); - ESP_LOGCONFIG(TAG, " Open Duration: %.1fs", this->open_duration_ / 1e3f); - ESP_LOGCONFIG(TAG, " Close Duration: %.1fs", this->close_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, + " Open Duration: %.1fs\n" + " Close Duration: %.1fs", + this->open_duration_ / 1e3f, this->close_duration_ / 1e3f); auto restore = this->restore_state_(); if (restore.has_value()) ESP_LOGCONFIG(TAG, " Saved position %d%%", (int) (restore->position * 100.f)); diff --git a/esphome/components/hlw8012/hlw8012.cpp b/esphome/components/hlw8012/hlw8012.cpp index 1044a528a0..ea1d081790 100644 --- a/esphome/components/hlw8012/hlw8012.cpp +++ b/esphome/components/hlw8012/hlw8012.cpp @@ -38,9 +38,11 @@ void HLW8012Component::dump_config() { LOG_PIN(" SEL Pin: ", this->sel_pin_) LOG_PIN(" CF Pin: ", this->cf_pin_) LOG_PIN(" CF1 Pin: ", this->cf1_pin_) - ESP_LOGCONFIG(TAG, " Change measurement mode every %" PRIu32, this->change_mode_every_); - ESP_LOGCONFIG(TAG, " Current resistor: %.1f mΩ", this->current_resistor_ * 1000.0f); - ESP_LOGCONFIG(TAG, " Voltage Divider: %.1f", this->voltage_divider_); + ESP_LOGCONFIG(TAG, + " Change measurement mode every %" PRIu32 "\n" + " Current resistor: %.1f mΩ\n" + " Voltage Divider: %.1f", + this->change_mode_every_, this->current_resistor_ * 1000.0f, this->voltage_divider_); LOG_UPDATE_INTERVAL(this) LOG_SENSOR(" ", "Voltage", this->voltage_sensor_) LOG_SENSOR(" ", "Current", this->current_sensor_) diff --git a/esphome/components/homeassistant/time/homeassistant_time.cpp b/esphome/components/homeassistant/time/homeassistant_time.cpp index 9f5239404a..0a91a2f63d 100644 --- a/esphome/components/homeassistant/time/homeassistant_time.cpp +++ b/esphome/components/homeassistant/time/homeassistant_time.cpp @@ -7,8 +7,10 @@ namespace homeassistant { static const char *const TAG = "homeassistant.time"; void HomeassistantTime::dump_config() { - ESP_LOGCONFIG(TAG, "Home Assistant Time:"); - ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str()); + ESP_LOGCONFIG(TAG, + "Home Assistant Time:\n" + " Timezone: '%s'", + this->timezone_.c_str()); } float HomeassistantTime::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/honeywellabp/honeywellabp.cpp b/esphome/components/honeywellabp/honeywellabp.cpp index 124bd6bb95..9252e613dd 100644 --- a/esphome/components/honeywellabp/honeywellabp.cpp +++ b/esphome/components/honeywellabp/honeywellabp.cpp @@ -85,8 +85,10 @@ float HONEYWELLABPSensor::get_setup_priority() const { return setup_priority::LA void HONEYWELLABPSensor::dump_config() { // LOG_SENSOR("", "HONEYWELLABP", this); LOG_PIN(" CS Pin: ", this->cs_); - ESP_LOGCONFIG(TAG, " Min Pressure Range: %0.1f", honeywellabp_min_pressure_); - ESP_LOGCONFIG(TAG, " Max Pressure Range: %0.1f", honeywellabp_max_pressure_); + ESP_LOGCONFIG(TAG, + " Min Pressure Range: %0.1f\n" + " Max Pressure Range: %0.1f", + honeywellabp_min_pressure_, honeywellabp_max_pressure_); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp b/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp index 598f69d226..11f5dbc314 100644 --- a/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp +++ b/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp @@ -1,6 +1,6 @@ #include "honeywellabp2.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace honeywellabp2_i2c { @@ -84,8 +84,10 @@ void HONEYWELLABP2Sensor::update() { } void HONEYWELLABP2Sensor::dump_config() { - ESP_LOGCONFIG(TAG, " Min Pressure Range: %0.1f", this->min_pressure_); - ESP_LOGCONFIG(TAG, " Max Pressure Range: %0.1f", this->max_pressure_); + ESP_LOGCONFIG(TAG, + " Min Pressure Range: %0.1f\n" + " Max Pressure Range: %0.1f", + this->min_pressure_, this->max_pressure_); if (this->transfer_function_ == ABP2_TRANS_FUNC_A) { ESP_LOGCONFIG(TAG, " Transfer function A"); } else { diff --git a/esphome/components/hte501/hte501.cpp b/esphome/components/hte501/hte501.cpp index e40d53b52d..0f97c67f9e 100644 --- a/esphome/components/hte501/hte501.cpp +++ b/esphome/components/hte501/hte501.cpp @@ -1,4 +1,5 @@ #include "hte501.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 878f362f28..ac13334118 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -1,6 +1,7 @@ from esphome import automation import esphome.codegen as cg from esphome.components import esp32 +from esphome.components.const import CONF_REQUEST_HEADERS import esphome.config_validation as cv from esphome.const import ( CONF_ESP8266_DISABLE_SSL_SUPPORT, @@ -51,7 +52,6 @@ CONF_CA_CERTIFICATE_PATH = "ca_certificate_path" CONF_MAX_RESPONSE_BUFFER_SIZE = "max_response_buffer_size" CONF_ON_RESPONSE = "on_response" CONF_HEADERS = "headers" -CONF_REQUEST_HEADERS = "request_headers" CONF_COLLECT_HEADERS = "collect_headers" CONF_BODY = "body" CONF_JSON = "json" diff --git a/esphome/components/http_request/http_request.cpp b/esphome/components/http_request/http_request.cpp index ca9fd2c2dc..806354baf1 100644 --- a/esphome/components/http_request/http_request.cpp +++ b/esphome/components/http_request/http_request.cpp @@ -10,11 +10,13 @@ namespace http_request { static const char *const TAG = "http_request"; void HttpRequestComponent::dump_config() { - ESP_LOGCONFIG(TAG, "HTTP Request:"); - ESP_LOGCONFIG(TAG, " Timeout: %ums", this->timeout_); - ESP_LOGCONFIG(TAG, " User-Agent: %s", this->useragent_); - ESP_LOGCONFIG(TAG, " Follow redirects: %s", YESNO(this->follow_redirects_)); - ESP_LOGCONFIG(TAG, " Redirect limit: %d", this->redirect_limit_); + ESP_LOGCONFIG(TAG, + "HTTP Request:\n" + " Timeout: %ums\n" + " User-Agent: %s\n" + " Follow redirects: %s\n" + " Redirect limit: %d", + this->timeout_, this->useragent_, YESNO(this->follow_redirects_), this->redirect_limit_); if (this->watchdog_timeout_ > 0) { ESP_LOGCONFIG(TAG, " Watchdog Timeout: %" PRIu32 "ms", this->watchdog_timeout_); } diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index 0923062822..6a779ba03a 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -26,8 +26,10 @@ struct UserData { void HttpRequestIDF::dump_config() { HttpRequestComponent::dump_config(); - ESP_LOGCONFIG(TAG, " Buffer Size RX: %u", this->buffer_size_rx_); - ESP_LOGCONFIG(TAG, " Buffer Size TX: %u", this->buffer_size_tx_); + ESP_LOGCONFIG(TAG, + " Buffer Size RX: %u\n" + " Buffer Size TX: %u", + this->buffer_size_rx_, this->buffer_size_tx_); } esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) { diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index cec30d72ec..4c8d49dad5 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -48,7 +48,7 @@ void OtaHttpRequestComponent::flash() { return; } - ESP_LOGI(TAG, "Starting update..."); + ESP_LOGI(TAG, "Starting update"); #ifdef USE_OTA_STATE_CALLBACK this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); #endif diff --git a/esphome/components/hx711/hx711.cpp b/esphome/components/hx711/hx711.cpp index d9b82fd7cd..0fc8b29604 100644 --- a/esphome/components/hx711/hx711.cpp +++ b/esphome/components/hx711/hx711.cpp @@ -1,6 +1,6 @@ #include "hx711.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace hx711 { diff --git a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp index 86cf19eb24..2d8381b60c 100644 --- a/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +++ b/esphome/components/hydreon_rgxx/hydreon_rgxx.cpp @@ -18,8 +18,10 @@ void HydreonRGxxComponent::dump_config() { ESP_LOGE(TAG, "Connection with hydreon_rgxx failed!"); } if (model_ == RG9) { - ESP_LOGCONFIG(TAG, " Model: RG9"); - ESP_LOGCONFIG(TAG, " Disable Led: %s", TRUEFALSE(this->disable_led_)); + ESP_LOGCONFIG(TAG, + " Model: RG9\n" + " Disable Led: %s", + TRUEFALSE(this->disable_led_)); } else { ESP_LOGCONFIG(TAG, " Model: RG15"); if (this->resolution_ == FORCE_HIGH) { diff --git a/esphome/components/i2c/i2c_bus_arduino.cpp b/esphome/components/i2c/i2c_bus_arduino.cpp index 9a5f1233b1..dca77e878d 100644 --- a/esphome/components/i2c/i2c_bus_arduino.cpp +++ b/esphome/components/i2c/i2c_bus_arduino.cpp @@ -1,9 +1,9 @@ #ifdef USE_ARDUINO #include "i2c_bus_arduino.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include #include @@ -40,7 +40,7 @@ void ArduinoI2CBus::setup() { this->initialized_ = true; if (this->scan_) { - ESP_LOGV(TAG, "Scanning i2c bus for active devices..."); + ESP_LOGV(TAG, "Scanning bus for active devices"); this->i2c_scan_(); } } @@ -70,9 +70,11 @@ void ArduinoI2CBus::set_pins_and_clock_() { void ArduinoI2CBus::dump_config() { ESP_LOGCONFIG(TAG, "I2C Bus:"); - ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_); - ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_); - ESP_LOGCONFIG(TAG, " Frequency: %u Hz", this->frequency_); + ESP_LOGCONFIG(TAG, + " SDA Pin: GPIO%u\n" + " SCL Pin: GPIO%u\n" + " Frequency: %u Hz", + this->sda_pin_, this->scl_pin_, this->frequency_); if (timeout_ > 0) { #if defined(USE_ESP32) ESP_LOGCONFIG(TAG, " Timeout: %u ms", this->timeout_ / 1000); diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index c99870191e..e4643405ce 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -75,15 +75,17 @@ void IDFI2CBus::setup() { } initialized_ = true; if (this->scan_) { - ESP_LOGV(TAG, "Scanning i2c bus for active devices..."); + ESP_LOGV(TAG, "Scanning bus for active devices"); this->i2c_scan_(); } } void IDFI2CBus::dump_config() { ESP_LOGCONFIG(TAG, "I2C Bus:"); - ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_); - ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_); - ESP_LOGCONFIG(TAG, " Frequency: %" PRIu32 " Hz", this->frequency_); + ESP_LOGCONFIG(TAG, + " SDA Pin: GPIO%u\n" + " SCL Pin: GPIO%u\n" + " Frequency: %" PRIu32 " Hz", + this->sda_pin_, this->scl_pin_, this->frequency_); if (timeout_ > 0) { ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 "us", this->timeout_); } diff --git a/esphome/components/i2s_audio/i2s_audio.h b/esphome/components/i2s_audio/i2s_audio.h index e839bcd891..cfccf7e01f 100644 --- a/esphome/components/i2s_audio/i2s_audio.h +++ b/esphome/components/i2s_audio/i2s_audio.h @@ -3,8 +3,8 @@ #ifdef USE_ESP32 #include "esphome/core/component.h" -#include "esphome/core/helpers.h" #include "esphome/core/defines.h" +#include "esphome/core/helpers.h" #ifdef USE_I2S_LEGACY #include #else diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index db6c3ae228..57e184d7f8 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -244,8 +244,10 @@ void I2SAudioMediaPlayer::dump_config() { } } else { #endif - ESP_LOGCONFIG(TAG, " External DAC channels: %d", this->external_dac_channels_); - ESP_LOGCONFIG(TAG, " I2S DOUT Pin: %d", this->dout_pin_); + ESP_LOGCONFIG(TAG, + " External DAC channels: %d\n" + " I2S DOUT Pin: %d", + this->external_dac_channels_, this->dout_pin_); LOG_PIN(" Mute Pin: ", this->mute_pin_); #if SOC_I2S_SUPPORTS_DAC } diff --git a/esphome/components/iaqcore/iaqcore.cpp b/esphome/components/iaqcore/iaqcore.cpp index 27ae776287..2a84eabf75 100644 --- a/esphome/components/iaqcore/iaqcore.cpp +++ b/esphome/components/iaqcore/iaqcore.cpp @@ -1,7 +1,7 @@ #include "iaqcore.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace iaqcore { diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index f056f0a128..41fd89cc58 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -89,8 +89,10 @@ void ILI9XXXDisplay::setup_pins_() { void ILI9XXXDisplay::dump_config() { LOG_DISPLAY("", "ili9xxx", this); - ESP_LOGCONFIG(TAG, " Width Offset: %u", this->offset_x_); - ESP_LOGCONFIG(TAG, " Height Offset: %u", this->offset_y_); + ESP_LOGCONFIG(TAG, + " Width Offset: %u\n" + " Height Offset: %u", + this->offset_x_, this->offset_y_); switch (this->buffer_color_mode_) { case BITS_8_INDEXED: ESP_LOGCONFIG(TAG, " Color mode: 8bit Indexed"); @@ -111,11 +113,14 @@ void ILI9XXXDisplay::dump_config() { LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Busy Pin: ", this->busy_pin_); - ESP_LOGCONFIG(TAG, " Color order: %s", this->color_order_ == display::COLOR_ORDER_BGR ? "BGR" : "RGB"); - ESP_LOGCONFIG(TAG, " Swap_xy: %s", YESNO(this->swap_xy_)); - ESP_LOGCONFIG(TAG, " Mirror_x: %s", YESNO(this->mirror_x_)); - ESP_LOGCONFIG(TAG, " Mirror_y: %s", YESNO(this->mirror_y_)); - ESP_LOGCONFIG(TAG, " Invert colors: %s", YESNO(this->pre_invertcolors_)); + ESP_LOGCONFIG(TAG, + " Color order: %s\n" + " Swap_xy: %s\n" + " Mirror_x: %s\n" + " Mirror_y: %s\n" + " Invert colors: %s", + this->color_order_ == display::COLOR_ORDER_BGR ? "BGR" : "RGB", YESNO(this->swap_xy_), + YESNO(this->mirror_x_), YESNO(this->mirror_y_), YESNO(this->pre_invertcolors_)); if (this->is_failed()) { ESP_LOGCONFIG(TAG, " => Failed to init Memory: YES!"); diff --git a/esphome/components/ili9xxx/ili9xxx_display.h b/esphome/components/ili9xxx/ili9xxx_display.h index 0babcedc48..629bbb41cb 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -89,7 +89,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer, void dump_config() override; void setup() override; - void on_shutdown() override { this->command(ILI9XXX_SLPIN); } + void on_powerdown() override { this->command(ILI9XXX_SLPIN); } display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, diff --git a/esphome/components/image/image.cpp b/esphome/components/image/image.cpp index 82e46e3460..7b65c4d0cb 100644 --- a/esphome/components/image/image.cpp +++ b/esphome/components/image/image.cpp @@ -1,6 +1,7 @@ #include "image.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" namespace esphome { namespace image { diff --git a/esphome/components/ina226/ina226.cpp b/esphome/components/ina226/ina226.cpp index f25e11e2e1..52e7127708 100644 --- a/esphome/components/ina226/ina226.cpp +++ b/esphome/components/ina226/ina226.cpp @@ -93,9 +93,12 @@ void INA226Component::dump_config() { } LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " ADC Conversion Time Bus Voltage: %d", INA226_ADC_TIMES[this->adc_time_voltage_ & 0b111]); - ESP_LOGCONFIG(TAG, " ADC Conversion Time Shunt Voltage: %d", INA226_ADC_TIMES[this->adc_time_current_ & 0b111]); - ESP_LOGCONFIG(TAG, " ADC Averaging Samples: %d", INA226_ADC_AVG_SAMPLES[this->adc_avg_samples_ & 0b111]); + ESP_LOGCONFIG(TAG, + " ADC Conversion Time Bus Voltage: %d\n" + " ADC Conversion Time Shunt Voltage: %d\n" + " ADC Averaging Samples: %d", + INA226_ADC_TIMES[this->adc_time_voltage_ & 0b111], INA226_ADC_TIMES[this->adc_time_current_ & 0b111], + INA226_ADC_AVG_SAMPLES[this->adc_avg_samples_ & 0b111]); LOG_SENSOR(" ", "Bus Voltage", this->bus_voltage_sensor_); LOG_SENSOR(" ", "Shunt Voltage", this->shunt_voltage_sensor_); diff --git a/esphome/components/ina2xx_base/ina2xx_base.cpp b/esphome/components/ina2xx_base/ina2xx_base.cpp index 82fd1e4d4d..2112a28b02 100644 --- a/esphome/components/ina2xx_base/ina2xx_base.cpp +++ b/esphome/components/ina2xx_base/ina2xx_base.cpp @@ -1,7 +1,7 @@ #include "ina2xx_base.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include #include @@ -206,12 +206,16 @@ void INA2XX::dump_config() { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); } LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " Shunt resistance = %f Ohm", this->shunt_resistance_ohm_); - ESP_LOGCONFIG(TAG, " Max current = %f A", this->max_current_a_); - ESP_LOGCONFIG(TAG, " Shunt temp coeff = %d ppm/°C", this->shunt_tempco_ppm_c_); - ESP_LOGCONFIG(TAG, " ADCRANGE = %d (%s)", (uint8_t) this->adc_range_, this->adc_range_ ? "±40.96 mV" : "±163.84 mV"); - ESP_LOGCONFIG(TAG, " CURRENT_LSB = %f", this->current_lsb_); - ESP_LOGCONFIG(TAG, " SHUNT_CAL = %d", this->shunt_cal_); + ESP_LOGCONFIG(TAG, + " Shunt resistance = %f Ohm\n" + " Max current = %f A\n" + " Shunt temp coeff = %d ppm/°C\n" + " ADCRANGE = %d (%s)\n" + " CURRENT_LSB = %f\n" + " SHUNT_CAL = %d", + this->shunt_resistance_ohm_, this->max_current_a_, this->shunt_tempco_ppm_c_, + (uint8_t) this->adc_range_, this->adc_range_ ? "±40.96 mV" : "±163.84 mV", this->current_lsb_, + this->shunt_cal_); ESP_LOGCONFIG(TAG, " ADC Samples = %d; ADC times: Bus = %d μs, Shunt = %d μs, Temp = %d μs", ADC_SAMPLES[0b111 & (uint8_t) this->adc_avg_samples_], diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index 492cdf9340..a7d31c0131 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -117,7 +117,6 @@ CONFIG_SCHEMA = cv.All( .extend(cv.polling_component_schema("5s")) .extend(i2c.i2c_device_schema(0x48)), cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), - cv.only_with_arduino, ) diff --git a/esphome/components/inkplate6/inkplate.cpp b/esphome/components/inkplate6/inkplate.cpp index 8c853b75c2..247aa35ead 100644 --- a/esphome/components/inkplate6/inkplate.cpp +++ b/esphome/components/inkplate6/inkplate.cpp @@ -3,9 +3,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#ifdef USE_ESP32_FRAMEWORK_ARDUINO - -#include +#include namespace esphome { namespace inkplate6 { @@ -186,9 +184,11 @@ void HOT Inkplate6::draw_absolute_pixel_internal(int x, int y, Color color) { void Inkplate6::dump_config() { LOG_DISPLAY("", "Inkplate", this); - ESP_LOGCONFIG(TAG, " Greyscale: %s", YESNO(this->greyscale_)); - ESP_LOGCONFIG(TAG, " Partial Updating: %s", YESNO(this->partial_updating_)); - ESP_LOGCONFIG(TAG, " Full Update Every: %d", this->full_update_every_); + ESP_LOGCONFIG(TAG, + " Greyscale: %s\n" + " Partial Updating: %s\n" + " Full Update Every: %d", + YESNO(this->greyscale_), YESNO(this->partial_updating_), this->full_update_every_); // Log pins LOG_PIN(" CKV Pin: ", this->ckv_pin_); LOG_PIN(" CL Pin: ", this->cl_pin_); @@ -721,5 +721,3 @@ void Inkplate6::pins_as_outputs_() { } // namespace inkplate6 } // namespace esphome - -#endif // USE_ESP32_FRAMEWORK_ARDUINO diff --git a/esphome/components/inkplate6/inkplate.h b/esphome/components/inkplate6/inkplate.h index 1680b84b7f..d8918bdf2a 100644 --- a/esphome/components/inkplate6/inkplate.h +++ b/esphome/components/inkplate6/inkplate.h @@ -5,8 +5,6 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" -#ifdef USE_ESP32_FRAMEWORK_ARDUINO - namespace esphome { namespace inkplate6 { @@ -254,5 +252,3 @@ class Inkplate6 : public display::DisplayBuffer, public i2c::I2CDevice { } // namespace inkplate6 } // namespace esphome - -#endif // USE_ESP32_FRAMEWORK_ARDUINO diff --git a/esphome/components/integration/integration_sensor.cpp b/esphome/components/integration/integration_sensor.cpp index 2ac7caca21..c09778e79e 100644 --- a/esphome/components/integration/integration_sensor.cpp +++ b/esphome/components/integration/integration_sensor.cpp @@ -1,7 +1,7 @@ #include "integration_sensor.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" namespace esphome { namespace integration { diff --git a/esphome/components/key_collector/key_collector.cpp b/esphome/components/key_collector/key_collector.cpp index ffb4b47fa2..9cfc74f50e 100644 --- a/esphome/components/key_collector/key_collector.cpp +++ b/esphome/components/key_collector/key_collector.cpp @@ -32,8 +32,10 @@ void KeyCollector::dump_config() { if (!this->start_keys_.empty()) ESP_LOGCONFIG(TAG, " start keys '%s'", this->start_keys_.c_str()); if (!this->end_keys_.empty()) { - ESP_LOGCONFIG(TAG, " end keys '%s'", this->end_keys_.c_str()); - ESP_LOGCONFIG(TAG, " end key is required: %s", ONOFF(this->end_key_required_)); + ESP_LOGCONFIG(TAG, + " end keys '%s'\n" + " end key is required: %s", + this->end_keys_.c_str(), ONOFF(this->end_key_required_)); } if (!this->allowed_keys_.empty()) ESP_LOGCONFIG(TAG, " allowed keys '%s'", this->allowed_keys_.c_str()); diff --git a/esphome/components/kmeteriso/kmeteriso.cpp b/esphome/components/kmeteriso/kmeteriso.cpp index 4856ee0e8f..b3fbc31fe6 100644 --- a/esphome/components/kmeteriso/kmeteriso.cpp +++ b/esphome/components/kmeteriso/kmeteriso.cpp @@ -1,5 +1,6 @@ #include "kmeteriso.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/kuntze/kuntze.cpp b/esphome/components/kuntze/kuntze.cpp index 8ab7af8cd9..42545d9d54 100644 --- a/esphome/components/kuntze/kuntze.cpp +++ b/esphome/components/kuntze/kuntze.cpp @@ -77,8 +77,10 @@ void Kuntze::loop() { void Kuntze::update() { this->state_ = 1; } void Kuntze::dump_config() { - ESP_LOGCONFIG(TAG, "Kuntze:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "Kuntze:\n" + " Address: 0x%02X", + this->address_); LOG_SENSOR("", "pH", this->ph_sensor_); LOG_SENSOR("", "temperature", this->temperature_sensor_); LOG_SENSOR("", "DIS1", this->dis1_sensor_); diff --git a/esphome/components/lc709203f/__init__.py b/esphome/components/lc709203f/__init__.py new file mode 100644 index 0000000000..3be68d174f --- /dev/null +++ b/esphome/components/lc709203f/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@ilikecake"] diff --git a/esphome/components/lc709203f/lc709203f.cpp b/esphome/components/lc709203f/lc709203f.cpp new file mode 100644 index 0000000000..d95a2c1d5e --- /dev/null +++ b/esphome/components/lc709203f/lc709203f.cpp @@ -0,0 +1,299 @@ +#include "esphome/core/log.h" +#include "lc709203f.h" + +namespace esphome { +namespace lc709203f { + +static const char *const TAG = "lc709203f.sensor"; + +// Device I2C address. This address is fixed. +static const uint8_t LC709203F_I2C_ADDR_DEFAULT = 0x0B; + +// Device registers +static const uint8_t LC709203F_BEFORE_RSOC = 0x04; +static const uint8_t LC709203F_THERMISTOR_B = 0x06; +static const uint8_t LC709203F_INITIAL_RSOC = 0x07; +static const uint8_t LC709203F_CELL_TEMPERATURE = 0x08; +static const uint8_t LC709203F_CELL_VOLTAGE = 0x09; +static const uint8_t LC709203F_CURRENT_DIRECTION = 0x0A; +static const uint8_t LC709203F_APA = 0x0B; +static const uint8_t LC709203F_APT = 0x0C; +static const uint8_t LC709203F_RSOC = 0x0D; +static const uint8_t LC709203F_ITE = 0x0F; +static const uint8_t LC709203F_IC_VERSION = 0x11; +static const uint8_t LC709203F_CHANGE_OF_THE_PARAMETER = 0x12; +static const uint8_t LC709203F_ALARM_LOW_RSOC = 0x13; +static const uint8_t LC709203F_ALARM_LOW_CELL_VOLTAGE = 0x14; +static const uint8_t LC709203F_IC_POWER_MODE = 0x15; +static const uint8_t LC709203F_STATUS_BIT = 0x16; +static const uint8_t LC709203F_NUMBER_OF_THE_PARAMETER = 0x1A; + +static const uint8_t LC709203F_POWER_MODE_ON = 0x0001; +static const uint8_t LC709203F_POWER_MODE_SLEEP = 0x0002; + +// The number of times to retry an I2C transaction before giving up. In my experience, +// 10 is a good number here that will take care of most bus issues that require retry. +static const uint8_t LC709203F_I2C_RETRY_COUNT = 10; + +void Lc709203f::setup() { + // Note: The setup implements a small state machine. This is because we want to have + // delays before and after sending the RSOC command. The full init process should be: + // INIT->RSOC->TEMP_SETUP->NORMAL + // The setup() function will only perform the first part of the initialization process. + // Assuming no errors, the whole process should occur during the setup() function and + // the first two calls to update(). After that, the part should remain in normal mode + // until a device reset. + // + // This device can be picky about I2C communication and can error out occasionally. The + // get/set register functions impelment retry logic to retry the I2C transactions. The + // initialization code checks the return code from those functions. If they don't return + // NO_ERROR (0x00), that part of the initialization aborts and will be retried on the next + // call to update(). + ESP_LOGCONFIG(TAG, "Running setup"); + + // Set power mode to on. Note that, unlike some other similar devices, in sleep mode the IC + // does not record power usage. If there is significant power consumption during sleep mode, + // the pack RSOC will likely no longer be correct. Because of that, I do not implement + // sleep mode on this device. + + // Initialize device registers. If any of these fail, retry during the update() function. + if (this->set_register_(LC709203F_IC_POWER_MODE, LC709203F_POWER_MODE_ON) != i2c::NO_ERROR) { + return; + } + + if (this->set_register_(LC709203F_APA, this->apa_) != i2c::NO_ERROR) { + return; + } + + if (this->set_register_(LC709203F_CHANGE_OF_THE_PARAMETER, this->pack_voltage_) != i2c::NO_ERROR) { + return; + } + + this->state_ = STATE_RSOC; + // Note: Initialization continues in the update() function. +} + +void Lc709203f::update() { + uint16_t buffer; + + if (this->state_ == STATE_NORMAL) { + // Note: If we fail to read from the data registers, we do not report any sensor reading. + if (this->voltage_sensor_ != nullptr) { + if (this->get_register_(LC709203F_CELL_VOLTAGE, &buffer) == i2c::NO_ERROR) { + // Raw units are mV + this->voltage_sensor_->publish_state(static_cast(buffer) / 1000.0f); + this->status_clear_warning(); + } + } + if (this->battery_remaining_sensor_ != nullptr) { + if (this->get_register_(LC709203F_ITE, &buffer) == i2c::NO_ERROR) { + // Raw units are .1% + this->battery_remaining_sensor_->publish_state(static_cast(buffer) / 10.0f); + this->status_clear_warning(); + } + } + if (this->temperature_sensor_ != nullptr) { + // I can't test this with a real thermistor because I don't have a device with + // an attached thermistor. I have turned on the sensor and made sure that it + // sets up the registers properly. + if (this->get_register_(LC709203F_CELL_TEMPERATURE, &buffer) == i2c::NO_ERROR) { + // Raw units are .1 K + this->temperature_sensor_->publish_state((static_cast(buffer) / 10.0f) - 273.15f); + this->status_clear_warning(); + } + } + } else if (this->state_ == STATE_INIT) { + // Retry initializing the device registers. We should only get here if the init sequence + // failed during the setup() function. This would likely occur because of a repeated failures + // on the I2C bus. If any of these fail, retry the next time the update() function is called. + if (this->set_register_(LC709203F_IC_POWER_MODE, LC709203F_POWER_MODE_ON) != i2c::NO_ERROR) { + return; + } + + if (this->set_register_(LC709203F_APA, this->apa_) != i2c::NO_ERROR) { + return; + } + + if (this->set_register_(LC709203F_CHANGE_OF_THE_PARAMETER, this->pack_voltage_) != i2c::NO_ERROR) { + return; + } + + this->state_ = STATE_RSOC; + + } else if (this->state_ == STATE_RSOC) { + // We implement a delay here to send the initial RSOC command. + // This should run once on the first update() after initialization. + if (this->set_register_(LC709203F_INITIAL_RSOC, 0xAA55) == i2c::NO_ERROR) { + this->state_ = STATE_TEMP_SETUP; + } + } else if (this->state_ == STATE_TEMP_SETUP) { + // This should run once on the second update() after initialization. + if (this->temperature_sensor_ != nullptr) { + // This assumes that a thermistor is attached to the device as shown in the datahseet. + if (this->set_register_(LC709203F_STATUS_BIT, 0x0001) == i2c::NO_ERROR) { + if (this->set_register_(LC709203F_THERMISTOR_B, this->b_constant_) == i2c::NO_ERROR) { + this->state_ = STATE_NORMAL; + } + } + } else if (this->set_register_(LC709203F_STATUS_BIT, 0x0000) == i2c::NO_ERROR) { + // The device expects to get updates to the temperature in this mode. + // I am not doing that now. The temperature register defaults to 25C. + // In theory, we could have another temperature sensor and have ESPHome + // send updated temperature to the device occasionally, but I have no idea + // how to make that happen. + this->state_ = STATE_NORMAL; + } + } +} + +void Lc709203f::dump_config() { + ESP_LOGCONFIG(TAG, "LC709203F:"); + LOG_I2C_DEVICE(this); + + LOG_UPDATE_INTERVAL(this); + ESP_LOGCONFIG(TAG, + " Pack Size: %d mAH\n" + " Pack APA: 0x%02X", + this->pack_size_, this->apa_); + + // This is only true if the pack_voltage_ is either 0x0000 or 0x0001. The config validator + // should have already verified this. + ESP_LOGCONFIG(TAG, " Pack Rated Voltage: 3.%sV", this->pack_voltage_ == 0x0000 ? "8" : "7"); + + LOG_SENSOR(" ", "Voltage", this->voltage_sensor_); + LOG_SENSOR(" ", "Battery Remaining", this->battery_remaining_sensor_); + + if (this->temperature_sensor_ != nullptr) { + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); + ESP_LOGCONFIG(TAG, " B_Constant: %d", this->b_constant_); + } else { + ESP_LOGCONFIG(TAG, " No Temperature Sensor"); + } +} + +uint8_t Lc709203f::get_register_(uint8_t register_to_read, uint16_t *register_value) { + i2c::ErrorCode return_code; + uint8_t read_buffer[6]; + + read_buffer[0] = (this->address_) << 1; + read_buffer[1] = register_to_read; + read_buffer[2] = ((this->address_) << 1) | 0x01; + + for (uint8_t i = 0; i <= LC709203F_I2C_RETRY_COUNT; i++) { + // Note: the read_register() function does not send a stop between the write and + // the read portions of the I2C transation when you set the last variable to 'false' + // as we do below. Some of the other I2C read functions such as the generic read() + // function will send a stop between the read and the write portion of the I2C + // transaction. This is bad in this case and will result in reading nothing but 0xFFFF + // from the registers. + return_code = this->read_register(register_to_read, &read_buffer[3], 3, false); + if (return_code != i2c::NO_ERROR) { + // Error on the i2c bus + this->status_set_warning( + str_sprintf("Error code %d when reading from register 0x%02X", return_code, register_to_read).c_str()); + } else if (this->crc8_(read_buffer, 5) != read_buffer[5]) { + // I2C indicated OK, but the CRC of the data does not matcth. + this->status_set_warning(str_sprintf("CRC error reading from register 0x%02X", register_to_read).c_str()); + } else { + *register_value = ((uint16_t) read_buffer[4] << 8) | (uint16_t) read_buffer[3]; + return i2c::NO_ERROR; + } + } + + // If we get here, we tried LC709203F_I2C_RETRY_COUNT times to read the register and + // failed each time. Set the register value to 0 and return the I2C error code or 0xFF + // to indicate a CRC failure. It will be up to the higher level code what to do when + // this happens. + *register_value = 0x0000; + if (return_code != i2c::NO_ERROR) { + return return_code; + } else { + return 0xFF; + } +} + +uint8_t Lc709203f::set_register_(uint8_t register_to_set, uint16_t value_to_set) { + i2c::ErrorCode return_code; + uint8_t write_buffer[5]; + + // Note: We don't actually send byte[0] of the buffer. We include it because it is + // part of the CRC calculation. + write_buffer[0] = (this->address_) << 1; + write_buffer[1] = register_to_set; + write_buffer[2] = value_to_set & 0xFF; // Low byte + write_buffer[3] = (value_to_set >> 8) & 0xFF; // High byte + write_buffer[4] = this->crc8_(write_buffer, 4); + + for (uint8_t i = 0; i <= LC709203F_I2C_RETRY_COUNT; i++) { + // Note: we don't write the first byte of the write buffer to the device. + // This is done automatically by the write() function. + return_code = this->write(&write_buffer[1], 4, true); + if (return_code == i2c::NO_ERROR) { + return return_code; + } else { + this->status_set_warning( + str_sprintf("Error code %d when writing to register 0x%02X", return_code, register_to_set).c_str()); + } + } + + // If we get here, we tried to send the data LC709203F_I2C_RETRY_COUNT times and failed. + // We return the I2C error code, it is up to the higher level code what to do about it. + return return_code; +} + +uint8_t Lc709203f::crc8_(uint8_t *byte_buffer, uint8_t length_of_crc) { + uint8_t crc = 0x00; + const uint8_t polynomial(0x07); + + for (uint8_t j = length_of_crc; j; --j) { + crc ^= *byte_buffer++; + + for (uint8_t i = 8; i; --i) { + crc = (crc & 0x80) ? (crc << 1) ^ polynomial : (crc << 1); + } + } + return crc; +} + +void Lc709203f::set_pack_size(uint16_t pack_size) { + static const uint16_t PACK_SIZE_ARRAY[6] = {100, 200, 500, 1000, 2000, 3000}; + static const uint16_t APA_ARRAY[6] = {0x08, 0x0B, 0x10, 0x19, 0x2D, 0x36}; + float slope; + float intercept; + + this->pack_size_ = pack_size; // Pack size in mAH + + // The size is used to calculate the 'Adjustment Pack Application' number. + // Here we assume a type 01 or type 03 battery and do a linear curve fit to find the APA. + for (uint8_t i = 0; i < 6; i++) { + if (PACK_SIZE_ARRAY[i] == pack_size) { + // If the pack size is exactly one of the values in the array. + this->apa_ = APA_ARRAY[i]; + return; + } else if ((i > 0) && (PACK_SIZE_ARRAY[i] > pack_size) && (PACK_SIZE_ARRAY[i - 1] < pack_size)) { + // If the pack size is between the current array element and the previous. Do a linear + // Curve fit to determine the APA value. + + // Type casting is required here to avoid interger division + slope = static_cast(APA_ARRAY[i] - APA_ARRAY[i - 1]) / + static_cast(PACK_SIZE_ARRAY[i] - PACK_SIZE_ARRAY[i - 1]); + + // Type casting might not be needed here. + intercept = static_cast(APA_ARRAY[i]) - slope * static_cast(PACK_SIZE_ARRAY[i]); + + this->apa_ = static_cast(slope * pack_size + intercept); + return; + } + } + // We should never get here. If we do, it means we never set the pack APA. This should + // not be possible because of the config validation. However, if it does happen, the + // consequence is that the RSOC values will likley not be as accurate. However, it should + // 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 lc709203f +} // namespace esphome diff --git a/esphome/components/lc709203f/lc709203f.h b/esphome/components/lc709203f/lc709203f.h new file mode 100644 index 0000000000..3b5b04775f --- /dev/null +++ b/esphome/components/lc709203f/lc709203f.h @@ -0,0 +1,55 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace lc709203f { + +enum LC709203FState { + STATE_INIT, + STATE_RSOC, + STATE_TEMP_SETUP, + STATE_NORMAL, +}; + +/// Enum listing allowable voltage settings for the LC709203F. +enum LC709203FBatteryVoltage { + LC709203F_BATTERY_VOLTAGE_3_8 = 0x0000, + LC709203F_BATTERY_VOLTAGE_3_7 = 0x0001, +}; + +class Lc709203f : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + void update() override; + 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_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; + } + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } + + private: + uint8_t get_register_(uint8_t register_to_read, uint16_t *register_value); + uint8_t set_register_(uint8_t register_to_set, uint16_t value_to_set); + uint8_t crc8_(uint8_t *byte_buffer, uint8_t length_of_crc); + + protected: + sensor::Sensor *voltage_sensor_{nullptr}; + sensor::Sensor *battery_remaining_sensor_{nullptr}; + sensor::Sensor *temperature_sensor_{nullptr}; + uint16_t pack_size_; + uint16_t apa_; + uint16_t b_constant_; + LC709203FState state_ = STATE_INIT; + uint16_t pack_voltage_; +}; + +} // namespace lc709203f +} // namespace esphome diff --git a/esphome/components/lc709203f/sensor.py b/esphome/components/lc709203f/sensor.py new file mode 100644 index 0000000000..eb08a522e5 --- /dev/null +++ b/esphome/components/lc709203f/sensor.py @@ -0,0 +1,93 @@ +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_BATTERY_LEVEL, + CONF_BATTERY_VOLTAGE, + CONF_ID, + CONF_SIZE, + CONF_TEMPERATURE, + CONF_VOLTAGE, + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_VOLTAGE, + ENTITY_CATEGORY_DIAGNOSTIC, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_PERCENT, + UNIT_VOLT, +) + +DEPENDENCIES = ["i2c"] + +lc709203f_ns = cg.esphome_ns.namespace("lc709203f") + +CONF_B_CONSTANT = "b_constant" + +LC709203FBatteryVoltage = lc709203f_ns.enum("LC709203FBatteryVoltage") +BATTERY_VOLTAGE_OPTIONS = { + "3.7": LC709203FBatteryVoltage.LC709203F_BATTERY_VOLTAGE_3_7, + "3.8": LC709203FBatteryVoltage.LC709203F_BATTERY_VOLTAGE_3_8, +} + +lc709203f = lc709203f_ns.class_("Lc709203f", cg.PollingComponent, i2c.I2CDevice) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(lc709203f), + cv.Optional(CONF_SIZE, default="500"): cv.int_range(100, 3000), + cv.Optional(CONF_VOLTAGE, default="3.7"): cv.enum( + BATTERY_VOLTAGE_OPTIONS, upper=True + ), + cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_BATTERY, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=2, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ).extend( + { + cv.Required(CONF_B_CONSTANT): cv.int_range(0, 0xFFFF), + } + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x0B)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + cg.add(var.set_pack_size(config.get(CONF_SIZE))) + cg.add(var.set_pack_voltage(BATTERY_VOLTAGE_OPTIONS[config[CONF_VOLTAGE]])) + + if voltage_config := config.get(CONF_BATTERY_VOLTAGE): + sens = await sensor.new_sensor(voltage_config) + cg.add(var.set_voltage_sensor(sens)) + + if level_config := config.get(CONF_BATTERY_LEVEL): + sens = await sensor.new_sensor(level_config) + cg.add(var.set_battery_remaining_sensor(sens)) + + if temp_config := config.get(CONF_TEMPERATURE): + sens = await sensor.new_sensor(temp_config) + cg.add(var.set_temperature_sensor(sens)) + cg.add(var.set_thermistor_b_constant(temp_config[CONF_B_CONSTANT])) diff --git a/esphome/components/lcd_base/lcd_display.cpp b/esphome/components/lcd_base/lcd_display.cpp index 65d7aa508f..d3434cce10 100644 --- a/esphome/components/lcd_base/lcd_display.cpp +++ b/esphome/components/lcd_base/lcd_display.cpp @@ -1,7 +1,7 @@ #include "lcd_display.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace lcd_base { diff --git a/esphome/components/lcd_gpio/gpio_lcd_display.cpp b/esphome/components/lcd_gpio/gpio_lcd_display.cpp index 1b1b07c464..afa74643fb 100644 --- a/esphome/components/lcd_gpio/gpio_lcd_display.cpp +++ b/esphome/components/lcd_gpio/gpio_lcd_display.cpp @@ -24,8 +24,10 @@ void GPIOLCDDisplay::setup() { LCDDisplay::setup(); } void GPIOLCDDisplay::dump_config() { - ESP_LOGCONFIG(TAG, "GPIO LCD Display:"); - ESP_LOGCONFIG(TAG, " Columns: %u, Rows: %u", this->columns_, this->rows_); + ESP_LOGCONFIG(TAG, + "GPIO LCD Display:\n" + " Columns: %u, Rows: %u", + this->columns_, this->rows_); LOG_PIN(" RS Pin: ", this->rs_pin_); LOG_PIN(" RW Pin: ", this->rw_pin_); LOG_PIN(" Enable Pin: ", this->enable_pin_); diff --git a/esphome/components/lcd_menu/lcd_menu.cpp b/esphome/components/lcd_menu/lcd_menu.cpp index 74ada5e584..c664b394bf 100644 --- a/esphome/components/lcd_menu/lcd_menu.cpp +++ b/esphome/components/lcd_menu/lcd_menu.cpp @@ -19,10 +19,12 @@ void LCDCharacterMenuComponent::setup() { float LCDCharacterMenuComponent::get_setup_priority() const { return setup_priority::PROCESSOR - 1.0f; } void LCDCharacterMenuComponent::dump_config() { - ESP_LOGCONFIG(TAG, "LCD Menu"); - ESP_LOGCONFIG(TAG, " Columns: %u, Rows: %u", this->columns_, this->rows_); - ESP_LOGCONFIG(TAG, " Mark characters: %02x, %02x, %02x, %02x", this->mark_selected_, this->mark_editing_, - this->mark_submenu_, this->mark_back_); + ESP_LOGCONFIG(TAG, + "LCD Menu\n" + " Columns: %u, Rows: %u\n" + " Mark characters: %02x, %02x, %02x, %02x", + this->columns_, this->rows_, this->mark_selected_, this->mark_editing_, this->mark_submenu_, + this->mark_back_); if (this->is_failed()) { ESP_LOGE(TAG, "The connected display failed, the menu is disabled!"); } diff --git a/esphome/components/lcd_pcf8574/pcf8574_display.cpp b/esphome/components/lcd_pcf8574/pcf8574_display.cpp index 90ba3ba876..0f06548b13 100644 --- a/esphome/components/lcd_pcf8574/pcf8574_display.cpp +++ b/esphome/components/lcd_pcf8574/pcf8574_display.cpp @@ -21,8 +21,10 @@ void PCF8574LCDDisplay::setup() { LCDDisplay::setup(); } void PCF8574LCDDisplay::dump_config() { - ESP_LOGCONFIG(TAG, "PCF8574 LCD Display:"); - ESP_LOGCONFIG(TAG, " Columns: %u, Rows: %u", this->columns_, this->rows_); + ESP_LOGCONFIG(TAG, + "PCF8574 LCD Display:\n" + " Columns: %u, Rows: %u", + this->columns_, this->rows_); LOG_I2C_DEVICE(this); LOG_UPDATE_INTERVAL(this); if (this->is_failed()) { diff --git a/esphome/components/ld2410/ld2410.cpp b/esphome/components/ld2410/ld2410.cpp index 20411be078..d7007ae0bd 100644 --- a/esphome/components/ld2410/ld2410.cpp +++ b/esphome/components/ld2410/ld2410.cpp @@ -72,9 +72,11 @@ void LD2410Component::dump_config() { } #endif this->read_all_info(); - ESP_LOGCONFIG(TAG, " Throttle_ : %ums", this->throttle_); - ESP_LOGCONFIG(TAG, " MAC Address : %s", const_cast(this->mac_.c_str())); - ESP_LOGCONFIG(TAG, " Firmware Version : %s", const_cast(this->version_.c_str())); + ESP_LOGCONFIG(TAG, + " Throttle_ : %ums\n" + " MAC Address : %s\n" + " Firmware Version : %s", + this->throttle_, const_cast(this->mac_.c_str()), const_cast(this->version_.c_str())); } void LD2410Component::setup() { diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index f94a5d7781..5b3206bf12 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -65,9 +65,11 @@ static const char *const TAG = "ld2420"; float LD2420Component::get_setup_priority() const { return setup_priority::BUS; } void LD2420Component::dump_config() { - ESP_LOGCONFIG(TAG, "LD2420:"); - ESP_LOGCONFIG(TAG, " Firmware Version : %7s", this->ld2420_firmware_ver_); - ESP_LOGCONFIG(TAG, "LD2420 Number:"); + ESP_LOGCONFIG(TAG, + "LD2420:\n" + " Firmware Version : %7s\n" + "LD2420 Number:", + this->ld2420_firmware_ver_); #ifdef USE_NUMBER LOG_NUMBER(TAG, " Gate Timeout:", this->gate_timeout_number_); LOG_NUMBER(TAG, " Gate Max Distance:", this->max_gate_distance_number_); @@ -158,7 +160,7 @@ void LD2420Component::apply_config_action() { ESP_LOGCONFIG(TAG, "No configuration change detected"); return; } - ESP_LOGCONFIG(TAG, "Reconfiguring LD2420..."); + ESP_LOGCONFIG(TAG, "Reconfiguring LD2420"); if (this->set_config_mode(true) == LD2420_ERROR_TIMEOUT) { ESP_LOGE(TAG, "LD2420 module has failed to respond, check baud rate and serial connections."); this->mark_failed(); @@ -180,7 +182,7 @@ void LD2420Component::apply_config_action() { } void LD2420Component::factory_reset_action() { - ESP_LOGCONFIG(TAG, "Setting factory defaults..."); + ESP_LOGCONFIG(TAG, "Setting factory defaults"); if (this->set_config_mode(true) == LD2420_ERROR_TIMEOUT) { ESP_LOGE(TAG, "LD2420 module has failed to respond, check baud rate and serial connections."); this->mark_failed(); @@ -209,7 +211,7 @@ void LD2420Component::factory_reset_action() { } void LD2420Component::restart_module_action() { - ESP_LOGCONFIG(TAG, "Restarting LD2420 module..."); + ESP_LOGCONFIG(TAG, "Restarting LD2420 module"); this->send_module_restart(); this->set_timeout(250, [this]() { this->set_config_mode(true); diff --git a/esphome/components/ld2450/ld2450.cpp b/esphome/components/ld2450/ld2450.cpp index 59aeb5ccb4..519e4d89a3 100644 --- a/esphome/components/ld2450/ld2450.cpp +++ b/esphome/components/ld2450/ld2450.cpp @@ -188,9 +188,11 @@ void LD2450Component::dump_config() { #ifdef USE_NUMBER LOG_NUMBER(" ", "PresenceTimeoutNumber", this->presence_timeout_number_); #endif - ESP_LOGCONFIG(TAG, " Throttle : %ums", this->throttle_); - ESP_LOGCONFIG(TAG, " MAC Address : %s", const_cast(this->mac_.c_str())); - ESP_LOGCONFIG(TAG, " Firmware version : %s", const_cast(this->version_.c_str())); + ESP_LOGCONFIG(TAG, + " Throttle : %ums\n" + " MAC Address : %s\n" + " Firmware version : %s", + this->throttle_, const_cast(this->mac_.c_str()), const_cast(this->version_.c_str())); } void LD2450Component::loop() { diff --git a/esphome/components/ld2450/sensor.py b/esphome/components/ld2450/sensor.py index 21580c5801..071ce8aa32 100644 --- a/esphome/components/ld2450/sensor.py +++ b/esphome/components/ld2450/sensor.py @@ -6,6 +6,8 @@ from esphome.const import ( CONF_DISTANCE, CONF_RESOLUTION, CONF_SPEED, + CONF_X, + CONF_Y, DEVICE_CLASS_DISTANCE, DEVICE_CLASS_SPEED, UNIT_DEGREES, @@ -19,8 +21,6 @@ DEPENDENCIES = ["ld2450"] CONF_MOVING_TARGET_COUNT = "moving_target_count" CONF_STILL_TARGET_COUNT = "still_target_count" CONF_TARGET_COUNT = "target_count" -CONF_X = "x" -CONF_Y = "y" ICON_ACCOUNT_GROUP = "mdi:account-group" ICON_ACCOUNT_SWITCH = "mdi:account-switch" diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 567fa5ac07..aefe0e63d8 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -139,7 +139,7 @@ void LEDCOutput::write_state(float state) { } void LEDCOutput::setup() { - ESP_LOGV(TAG, "Entering setup..."); + ESP_LOGCONFIG(TAG, "Running setup"); #ifdef USE_ARDUINO this->update_frequency(this->frequency_); this->turn_off(); @@ -181,10 +181,12 @@ void LEDCOutput::setup() { void LEDCOutput::dump_config() { ESP_LOGCONFIG(TAG, "Output:"); LOG_PIN(" Pin ", this->pin_); - ESP_LOGCONFIG(TAG, " Channel: %u", this->channel_); - ESP_LOGCONFIG(TAG, " PWM Frequency: %.1f Hz", this->frequency_); - ESP_LOGCONFIG(TAG, " Phase angle: %.1f°", this->phase_angle_); - ESP_LOGCONFIG(TAG, " Bit depth: %u", this->bit_depth_); + ESP_LOGCONFIG(TAG, + " Channel: %u\n" + " PWM Frequency: %.1f Hz\n" + " Phase angle: %.1f°\n" + " Bit depth: %u", + this->channel_, this->frequency_, this->phase_angle_, this->bit_depth_); ESP_LOGV(TAG, " Max frequency for bit depth: %f", ledc_max_frequency_for_bit_depth(this->bit_depth_)); ESP_LOGV(TAG, " Min frequency for bit depth: %f", ledc_min_frequency_for_bit_depth(this->bit_depth_, (this->frequency_ < 100))); @@ -207,14 +209,14 @@ void LEDCOutput::update_frequency(float frequency) { this->bit_depth_ = bit_depth_opt.value_or(8); this->frequency_ = frequency; #ifdef USE_ARDUINO - ESP_LOGV(TAG, "Using Arduino API - Trying to define channel, frequency and bit depth..."); + ESP_LOGV(TAG, "Using Arduino API - Trying to define channel, frequency and bit depth"); u_int32_t configured_frequency = 0; // Configure LEDC channel, frequency and bit depth with fallback int attempt_count_max = SETUP_ATTEMPT_COUNT_MAX; while (attempt_count_max > 0 && configured_frequency == 0) { - ESP_LOGV(TAG, "Initializing channel %u with frequency %.1f and bit depth of %u...", this->channel_, - this->frequency_, this->bit_depth_); + ESP_LOGV(TAG, "Initializing channel %u with frequency %.1f and bit depth of %u", this->channel_, this->frequency_, + this->bit_depth_); configured_frequency = ledcSetup(this->channel_, frequency, this->bit_depth_); if (configured_frequency != 0) { this->initialized_ = true; diff --git a/esphome/components/libretiny/preferences.cpp b/esphome/components/libretiny/preferences.cpp index a090f42aa7..ce4ed915c0 100644 --- a/esphome/components/libretiny/preferences.cpp +++ b/esphome/components/libretiny/preferences.cpp @@ -1,8 +1,8 @@ #ifdef USE_LIBRETINY -#include "esphome/core/preferences.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "esphome/core/preferences.h" #include #include #include @@ -101,7 +101,7 @@ class LibreTinyPreferences : public ESPPreferences { if (s_pending_save.empty()) return true; - ESP_LOGD(TAG, "Saving %d preferences to flash...", s_pending_save.size()); + ESP_LOGV(TAG, "Saving %d items...", s_pending_save.size()); // goal try write all pending saves even if one fails int cached = 0, written = 0, failed = 0; fdb_err_t last_err = FDB_NO_ERR; @@ -129,11 +129,10 @@ class LibreTinyPreferences : public ESPPreferences { } s_pending_save.erase(s_pending_save.begin() + i); } - ESP_LOGD(TAG, "Saving %d preferences to flash: %d cached, %d written, %d failed", cached + written + failed, cached, - written, failed); + ESP_LOGD(TAG, "Writing %d items: %d cached, %d written, %d failed", cached + written + failed, cached, written, + failed); if (failed > 0) { - ESP_LOGE(TAG, "Error saving %d preferences to flash. Last error=%d for key=%s", failed, last_err, - last_key.c_str()); + ESP_LOGE(TAG, "Writing %d items failed. Last error=%d for key=%s", failed, last_err, last_key.c_str()); } return failed == 0; @@ -158,7 +157,7 @@ class LibreTinyPreferences : public ESPPreferences { } bool reset() override { - ESP_LOGD(TAG, "Cleaning up preferences in flash..."); + ESP_LOGD(TAG, "Erasing storage"); s_pending_save.clear(); fdb_kv_set_default(&db); diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 237ab45f38..a013029fc2 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -37,7 +37,7 @@ from esphome.const import ( CONF_WEB_SERVER, CONF_WHITE, ) -from esphome.core import coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority from esphome.cpp_generator import MockObjClass from esphome.cpp_helpers import setup_entity @@ -270,6 +270,7 @@ async def setup_light_core_(light_var, output_var, config): async def register_light(output_var, config): light_var = cg.new_Pvariable(config[CONF_ID], output_var) cg.add(cg.App.register_light(light_var)) + CORE.register_platform_component("light", light_var) await cg.register_component(light_var, config) await setup_light_core_(light_var, output_var, config) diff --git a/esphome/components/light/esp_hsv_color.h b/esphome/components/light/esp_hsv_color.h index 39f5e55707..cdde91c71c 100644 --- a/esphome/components/light/esp_hsv_color.h +++ b/esphome/components/light/esp_hsv_color.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/helpers.h" #include "esphome/core/color.h" +#include "esphome/core/helpers.h" namespace esphome { namespace light { diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index 0f8de7fac5..0aae6aed15 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -91,12 +91,16 @@ void LightState::setup() { void LightState::dump_config() { ESP_LOGCONFIG(TAG, "Light '%s'", this->get_name().c_str()); if (this->get_traits().supports_color_capability(ColorCapability::BRIGHTNESS)) { - ESP_LOGCONFIG(TAG, " Default Transition Length: %.1fs", this->default_transition_length_ / 1e3f); - ESP_LOGCONFIG(TAG, " Gamma Correct: %.2f", this->gamma_correct_); + ESP_LOGCONFIG(TAG, + " Default Transition Length: %.1fs\n" + " Gamma Correct: %.2f", + this->default_transition_length_ / 1e3f, this->gamma_correct_); } if (this->get_traits().supports_color_capability(ColorCapability::COLOR_TEMPERATURE)) { - ESP_LOGCONFIG(TAG, " Min Mireds: %.1f", this->get_traits().get_min_mireds()); - ESP_LOGCONFIG(TAG, " Max Mireds: %.1f", this->get_traits().get_max_mireds()); + ESP_LOGCONFIG(TAG, + " Min Mireds: %.1f\n" + " Max Mireds: %.1f", + this->get_traits().get_min_mireds(), this->get_traits().get_max_mireds()); } } void LightState::loop() { diff --git a/esphome/components/light/light_transformer.h b/esphome/components/light/light_transformer.h index 35b045d5b4..fb9b709187 100644 --- a/esphome/components/light/light_transformer.h +++ b/esphome/components/light/light_transformer.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "light_color_values.h" namespace esphome { diff --git a/esphome/components/lightwaverf/LwTx.cpp b/esphome/components/lightwaverf/LwTx.cpp index 2f46b04b2d..f5ef6ddb2c 100644 --- a/esphome/components/lightwaverf/LwTx.cpp +++ b/esphome/components/lightwaverf/LwTx.cpp @@ -8,8 +8,8 @@ #include "LwTx.h" #include #include -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace lightwaverf { diff --git a/esphome/components/lock/__init__.py b/esphome/components/lock/__init__.py index a96290dca6..0fb67e3948 100644 --- a/esphome/components/lock/__init__.py +++ b/esphome/components/lock/__init__.py @@ -115,6 +115,7 @@ async def register_lock(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_lock(var)) + CORE.register_platform_component("lock", var) await _setup_lock_core(var, config) diff --git a/esphome/components/lock/lock.h b/esphome/components/lock/lock.h index 7a98187a4f..2173c84903 100644 --- a/esphome/components/lock/lock.h +++ b/esphome/components/lock/lock.h @@ -2,9 +2,9 @@ #include "esphome/core/component.h" #include "esphome/core/entity_base.h" -#include "esphome/core/preferences.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "esphome/core/preferences.h" #include namespace esphome { diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 014f7e3dec..59a3398ce8 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -221,12 +221,16 @@ float Logger::get_setup_priority() const { return setup_priority::BUS + 500.0f; static const char *const LOG_LEVELS[] = {"NONE", "ERROR", "WARN", "INFO", "CONFIG", "DEBUG", "VERBOSE", "VERY_VERBOSE"}; void Logger::dump_config() { - ESP_LOGCONFIG(TAG, "Logger:"); - ESP_LOGCONFIG(TAG, " Max Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]); - ESP_LOGCONFIG(TAG, " Initial Level: %s", LOG_LEVELS[this->current_level_]); + ESP_LOGCONFIG(TAG, + "Logger:\n" + " Max Level: %s\n" + " Initial Level: %s", + LOG_LEVELS[ESPHOME_LOG_LEVEL], LOG_LEVELS[this->current_level_]); #ifndef USE_HOST - ESP_LOGCONFIG(TAG, " Log Baud Rate: %" PRIu32, this->baud_rate_); - ESP_LOGCONFIG(TAG, " Hardware UART: %s", get_uart_selection_()); + ESP_LOGCONFIG(TAG, + " Log Baud Rate: %" PRIu32 "\n" + " Hardware UART: %s", + this->baud_rate_, get_uart_selection_()); #endif #ifdef USE_ESPHOME_TASK_LOG_BUFFER if (this->log_buffer_) { diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index 5c53c4d40c..6030d9e8f2 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -212,9 +212,9 @@ class Logger : public Component { } // Format string to explicit buffer with varargs - inline void printf_to_buffer_(const char *format, char *buffer, int *buffer_at, int buffer_size, ...) { + inline void printf_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, ...) { va_list arg; - va_start(arg, buffer_size); + va_start(arg, format); this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, arg); va_end(arg); } @@ -312,13 +312,13 @@ class Logger : public Component { #if defined(USE_ESP32) || defined(USE_LIBRETINY) if (thread_name != nullptr) { // Non-main task with thread name - this->printf_to_buffer_("%s[%s][%s:%03u]%s[%s]%s: ", buffer, buffer_at, buffer_size, color, letter, tag, line, + this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]%s[%s]%s: ", color, letter, tag, line, ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), thread_name, color); return; } #endif // Main task or non ESP32/LibreTiny platform - this->printf_to_buffer_("%s[%s][%s:%03u]: ", buffer, buffer_at, buffer_size, color, letter, tag, line); + this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]: ", color, letter, tag, line); } inline void HOT format_body_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index 6e31fcdc42..cc7e686d13 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -187,10 +187,13 @@ void LTR390Component::setup() { void LTR390Component::dump_config() { LOG_I2C_DEVICE(this); - ESP_LOGCONFIG(TAG, " ALS Gain: X%.0f", GAINVALUES[this->gain_als_]); - ESP_LOGCONFIG(TAG, " ALS Resolution: %u-bit", RESOLUTION_BITS[this->res_als_]); - ESP_LOGCONFIG(TAG, " UV Gain: X%.0f", GAINVALUES[this->gain_uv_]); - ESP_LOGCONFIG(TAG, " UV Resolution: %u-bit", RESOLUTION_BITS[this->res_uv_]); + ESP_LOGCONFIG(TAG, + " ALS Gain: X%.0f\n" + " ALS Resolution: %u-bit\n" + " UV Gain: X%.0f\n" + " UV Resolution: %u-bit", + GAINVALUES[this->gain_als_], RESOLUTION_BITS[this->res_als_], GAINVALUES[this->gain_uv_], + RESOLUTION_BITS[this->res_uv_]); } void LTR390Component::update() { diff --git a/esphome/components/ltr501/ltr501.cpp b/esphome/components/ltr501/ltr501.cpp index 9fbc3f3b13..12f227ab91 100644 --- a/esphome/components/ltr501/ltr501.cpp +++ b/esphome/components/ltr501/ltr501.cpp @@ -1,7 +1,7 @@ #include "ltr501.h" #include "esphome/core/application.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" using esphome::i2c::ErrorCode; @@ -94,16 +94,21 @@ void LTRAlsPs501Component::dump_config() { }; LOG_I2C_DEVICE(this); - ESP_LOGCONFIG(TAG, " Device type: %s", get_device_type(this->ltr_type_)); - ESP_LOGCONFIG(TAG, " Automatic mode: %s", ONOFF(this->automatic_mode_enabled_)); - ESP_LOGCONFIG(TAG, " Gain: %.0fx", get_gain_coeff(this->gain_)); - ESP_LOGCONFIG(TAG, " Integration time: %d ms", get_itime_ms(this->integration_time_)); - ESP_LOGCONFIG(TAG, " Measurement repeat rate: %d ms", get_meas_time_ms(this->repeat_rate_)); - ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); - ESP_LOGCONFIG(TAG, " Proximity gain: %.0fx", get_ps_gain_coeff(this->ps_gain_)); - ESP_LOGCONFIG(TAG, " Proximity cooldown time: %d s", this->ps_cooldown_time_s_); - ESP_LOGCONFIG(TAG, " Proximity high threshold: %d", this->ps_threshold_high_); - ESP_LOGCONFIG(TAG, " Proximity low threshold: %d", this->ps_threshold_low_); + ESP_LOGCONFIG(TAG, + " Device type: %s\n" + " Automatic mode: %s\n" + " Gain: %.0fx\n" + " Integration time: %d ms\n" + " Measurement repeat rate: %d ms\n" + " Glass attenuation factor: %f\n" + " Proximity gain: %.0fx\n" + " Proximity cooldown time: %d s\n" + " Proximity high threshold: %d\n" + " Proximity low threshold: %d", + get_device_type(this->ltr_type_), ONOFF(this->automatic_mode_enabled_), get_gain_coeff(this->gain_), + get_itime_ms(this->integration_time_), get_meas_time_ms(this->repeat_rate_), + this->glass_attenuation_factor_, get_ps_gain_coeff(this->ps_gain_), this->ps_cooldown_time_s_, + this->ps_threshold_high_, this->ps_threshold_low_); LOG_UPDATE_INTERVAL(this); @@ -306,7 +311,7 @@ void LTRAlsPs501Component::configure_als_() { uint8_t tries = MAX_TRIES; do { - ESP_LOGV(TAG, "Waiting for ALS device to become active..."); + ESP_LOGV(TAG, "Waiting for ALS device to become active"); delay(2); als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); } while (!als_ctrl.als_mode_active && tries--); // while active mode is not set - keep waiting diff --git a/esphome/components/ltr_als_ps/ltr_als_ps.cpp b/esphome/components/ltr_als_ps/ltr_als_ps.cpp index 402fd1318b..9b635a12b1 100644 --- a/esphome/components/ltr_als_ps/ltr_als_ps.cpp +++ b/esphome/components/ltr_als_ps/ltr_als_ps.cpp @@ -1,7 +1,7 @@ #include "ltr_als_ps.h" #include "esphome/core/application.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" using esphome::i2c::ErrorCode; @@ -85,21 +85,28 @@ void LTRAlsPsComponent::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Device type: %s", get_device_type(this->ltr_type_)); if (this->is_als_()) { - ESP_LOGCONFIG(TAG, " Automatic mode: %s", ONOFF(this->automatic_mode_enabled_)); - ESP_LOGCONFIG(TAG, " Gain: %.0fx", get_gain_coeff(this->gain_)); - ESP_LOGCONFIG(TAG, " Integration time: %d ms", get_itime_ms(this->integration_time_)); - ESP_LOGCONFIG(TAG, " Measurement repeat rate: %d ms", get_meas_time_ms(this->repeat_rate_)); - ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); + ESP_LOGCONFIG(TAG, + " Automatic mode: %s\n" + " Gain: %.0fx\n" + " Integration time: %d ms\n" + " Measurement repeat rate: %d ms\n" + " Glass attenuation factor: %f", + ONOFF(this->automatic_mode_enabled_), get_gain_coeff(this->gain_), + get_itime_ms(this->integration_time_), get_meas_time_ms(this->repeat_rate_), + this->glass_attenuation_factor_); LOG_SENSOR(" ", "ALS calculated lux", this->ambient_light_sensor_); LOG_SENSOR(" ", "CH1 Infrared counts", this->infrared_counts_sensor_); LOG_SENSOR(" ", "CH0 Visible+IR counts", this->full_spectrum_counts_sensor_); LOG_SENSOR(" ", "Actual gain", this->actual_gain_sensor_); } if (this->is_ps_()) { - ESP_LOGCONFIG(TAG, " Proximity gain: %.0fx", get_ps_gain_coeff(this->ps_gain_)); - ESP_LOGCONFIG(TAG, " Proximity cooldown time: %d s", this->ps_cooldown_time_s_); - ESP_LOGCONFIG(TAG, " Proximity high threshold: %d", this->ps_threshold_high_); - ESP_LOGCONFIG(TAG, " Proximity low threshold: %d", this->ps_threshold_low_); + ESP_LOGCONFIG(TAG, + " Proximity gain: %.0fx\n" + " Proximity cooldown time: %d s\n" + " Proximity high threshold: %d\n" + " Proximity low threshold: %d", + get_ps_gain_coeff(this->ps_gain_), this->ps_cooldown_time_s_, this->ps_threshold_high_, + this->ps_threshold_low_); LOG_SENSOR(" ", "Proximity counts", this->proximity_counts_sensor_); } LOG_UPDATE_INTERVAL(this); @@ -298,7 +305,7 @@ void LTRAlsPsComponent::configure_als_() { uint8_t tries = MAX_TRIES; do { - ESP_LOGV(TAG, "Waiting for device to become active..."); + ESP_LOGV(TAG, "Waiting for device to become active"); delay(2); als_ctrl.raw = this->reg((uint8_t) CommandRegisters::ALS_CONTR).get(); } while (!als_ctrl.active_mode && tries--); // while active mode is not set - keep waiting diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index f49356604b..cc0f833ced 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -21,7 +21,7 @@ from .defines import ( literal, static_cast, ) -from .lv_validation import lv_bool, lv_color, lv_image, opacity +from .lv_validation import lv_bool, lv_color, lv_image, lv_milliseconds, opacity from .lvcode import ( LVGL_COMP_ARG, UPDATE_EVENT, @@ -129,14 +129,14 @@ async def lvgl_is_paused(config, condition_id, template_arg, args): LVGL_SCHEMA.extend( { cv.Required(CONF_TIMEOUT): cv.templatable( - cv.positive_time_period_milliseconds + lv_milliseconds, ) } ), ) async def lvgl_is_idle(config, condition_id, template_arg, args): lvgl = config[CONF_LVGL_ID] - timeout = await cg.templatable(config[CONF_TIMEOUT], [], cg.uint32) + timeout = await lv_milliseconds.process(config[CONF_TIMEOUT]) async with LambdaContext(LVGL_COMP_ARG, return_type=cg.bool_) as context: lv_add(ReturnStatement(lvgl_comp.is_idle(timeout))) var = cg.new_Pvariable( diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 7783fb2321..baa9a19c51 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -519,8 +519,6 @@ CONF_UPDATE_ON_RELEASE = "update_on_release" CONF_VISIBLE_ROW_COUNT = "visible_row_count" CONF_WIDGET = "widget" CONF_WIDGETS = "widgets" -CONF_X = "x" -CONF_Y = "y" CONF_ZOOM = "zoom" # Keypad keys diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index d58fb24584..dd877df0f0 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -1,7 +1,7 @@ #include "esphome/core/defines.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "lvgl_hal.h" #include "lvgl_esphome.h" @@ -85,11 +85,14 @@ static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { lv_event_code_t lv_api_event; // NOLINT lv_event_code_t lv_update_event; // NOLINT void LvglComponent::dump_config() { - ESP_LOGCONFIG(TAG, "LVGL:"); - ESP_LOGCONFIG(TAG, " Display width/height: %d x %d", this->disp_drv_.hor_res, this->disp_drv_.ver_res); - ESP_LOGCONFIG(TAG, " Buffer size: %zu%%", 100 / this->buffer_frac_); - ESP_LOGCONFIG(TAG, " Rotation: %d", this->rotation); - ESP_LOGCONFIG(TAG, " Draw rounding: %d", (int) this->draw_rounding); + ESP_LOGCONFIG(TAG, + "LVGL:\n" + " Display width/height: %d x %d\n" + " Buffer size: %zu%%\n" + " Rotation: %d\n" + " Draw rounding: %d", + this->disp_drv_.hor_res, this->disp_drv_.ver_res, 100 / this->buffer_frac_, this->rotation, + (int) this->draw_rounding); } void LvglComponent::set_paused(bool paused, bool show_snow) { this->paused_ = paused; diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 2bae560041..fdc8750d1d 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -13,13 +13,15 @@ from esphome.const import ( CONF_TIME, CONF_TRIGGER_ID, CONF_TYPE, + CONF_X, + CONF_Y, ) from esphome.core import TimePeriod from esphome.core.config import StartupTrigger from esphome.schema_extractors import SCHEMA_EXTRACT from . import defines as df, lv_validation as lvalid -from .defines import CONF_TIME_FORMAT, CONF_X, CONF_Y, LV_GRAD_DIR +from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR from .helpers import add_lv_use, requires_component, validate_printf from .lv_validation import lv_color, lv_font, lv_gradient, lv_image, opacity from .lvcode import LvglComponent, lv_event_t_ptr @@ -354,8 +356,8 @@ ALIGN_TO_SCHEMA = { { cv.Required(CONF_ID): cv.use_id(lv_obj_t), cv.Required(df.CONF_ALIGN): df.ALIGN_ALIGNMENTS.one_of, - cv.Optional(df.CONF_X, default=0): lvalid.pixels_or_percent, - cv.Optional(df.CONF_Y, default=0): lvalid.pixels_or_percent, + cv.Optional(CONF_X, default=0): lvalid.pixels_or_percent, + cv.Optional(CONF_Y, default=0): lvalid.pixels_or_percent, } ) } diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index 283c9a5e56..2f8b454ec4 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -1,12 +1,17 @@ from esphome import automation import esphome.codegen as cg -from esphome.const import CONF_ID, CONF_ON_BOOT, CONF_ON_VALUE, CONF_TRIGGER_ID +from esphome.const import ( + CONF_ID, + CONF_ON_BOOT, + CONF_ON_VALUE, + CONF_TRIGGER_ID, + CONF_X, + CONF_Y, +) from .defines import ( CONF_ALIGN, CONF_ALIGN_TO, - CONF_X, - CONF_Y, DIRECTIONS, LV_EVENT_MAP, LV_EVENT_TRIGGERS, diff --git a/esphome/components/lvgl/widgets/canvas.py b/esphome/components/lvgl/widgets/canvas.py index 60812093d5..4fd81b6e4a 100644 --- a/esphome/components/lvgl/widgets/canvas.py +++ b/esphome/components/lvgl/widgets/canvas.py @@ -1,6 +1,14 @@ from esphome import automation, codegen as cg, config_validation as cv from esphome.components.display_menu_base import CONF_LABEL -from esphome.const import CONF_COLOR, CONF_HEIGHT, CONF_ID, CONF_TEXT, CONF_WIDTH +from esphome.const import ( + CONF_COLOR, + CONF_HEIGHT, + CONF_ID, + CONF_TEXT, + CONF_WIDTH, + CONF_X, + CONF_Y, +) from esphome.cpp_generator import Literal, MockObj from ..automation import action_to_code @@ -13,8 +21,6 @@ from ..defines import ( CONF_POINTS, CONF_SRC, CONF_START_ANGLE, - CONF_X, - CONF_Y, literal, ) from ..lv_validation import ( diff --git a/esphome/components/lvgl/widgets/line.py b/esphome/components/lvgl/widgets/line.py index 94fdfe2346..bd90edbefc 100644 --- a/esphome/components/lvgl/widgets/line.py +++ b/esphome/components/lvgl/widgets/line.py @@ -1,8 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome.const import CONF_X, CONF_Y from esphome.core import Lambda -from ..defines import CONF_MAIN, CONF_X, CONF_Y, call_lambda +from ..defines import CONF_MAIN, call_lambda from ..lvcode import lv_add from ..schemas import point_schema from ..types import LvCompound, LvType diff --git a/esphome/components/m5stack_8angle/m5stack_8angle.cpp b/esphome/components/m5stack_8angle/m5stack_8angle.cpp index f08bb1214c..416b903816 100644 --- a/esphome/components/m5stack_8angle/m5stack_8angle.cpp +++ b/esphome/components/m5stack_8angle/m5stack_8angle.cpp @@ -13,14 +13,14 @@ void M5Stack8AngleComponent::setup() { err = this->read(nullptr, 0); if (err != i2c::NO_ERROR) { - ESP_LOGE(TAG, "I2C error %02X...", err); + ESP_LOGE(TAG, "I2C error %02X", err); this->mark_failed(); return; }; err = this->read_register(M5STACK_8ANGLE_REGISTER_FW_VERSION, &this->fw_version_, 1); if (err != i2c::NO_ERROR) { - ESP_LOGE(TAG, "I2C error %02X...", err); + ESP_LOGE(TAG, "I2C error %02X", err); this->mark_failed(); return; }; diff --git a/esphome/components/matrix_keypad/matrix_keypad.cpp b/esphome/components/matrix_keypad/matrix_keypad.cpp index 6cb4fc4f3c..43a20c49d1 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.cpp +++ b/esphome/components/matrix_keypad/matrix_keypad.cpp @@ -97,8 +97,8 @@ void MatrixKeypad::loop() { } void MatrixKeypad::dump_config() { - ESP_LOGCONFIG(TAG, "Matrix Keypad:"); - ESP_LOGCONFIG(TAG, " Rows:"); + ESP_LOGCONFIG(TAG, "Matrix Keypad:\n" + " Rows:"); for (auto &pin : this->rows_) { LOG_PIN(" Pin: ", pin); } diff --git a/esphome/components/max31855/max31855.cpp b/esphome/components/max31855/max31855.cpp index e4ca94c5a5..26fba428cc 100644 --- a/esphome/components/max31855/max31855.cpp +++ b/esphome/components/max31855/max31855.cpp @@ -1,5 +1,6 @@ #include "max31855.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/max31856/max31856.cpp b/esphome/components/max31856/max31856.cpp index 2eb4a7538e..c30e2e1a31 100644 --- a/esphome/components/max31856/max31856.cpp +++ b/esphome/components/max31856/max31856.cpp @@ -95,28 +95,28 @@ bool MAX31856Sensor::has_fault_() { this->status_set_warning(); if ((faults & MAX31856_FAULT_CJRANGE) == MAX31856_FAULT_CJRANGE) { - ESP_LOGW(TAG, "Cold Junction Out-of-Range: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Cold Junction Out-of-Range: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_TCRANGE) == MAX31856_FAULT_TCRANGE) { - ESP_LOGW(TAG, "Thermocouple Out-of-Range: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Thermocouple Out-of-Range: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_CJHIGH) == MAX31856_FAULT_CJHIGH) { - ESP_LOGW(TAG, "Cold-Junction High Fault: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Cold-Junction High Fault: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_CJLOW) == MAX31856_FAULT_CJLOW) { - ESP_LOGW(TAG, "Cold-Junction Low Fault: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Cold-Junction Low Fault: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_TCHIGH) == MAX31856_FAULT_TCHIGH) { - ESP_LOGW(TAG, "Thermocouple Temperature High Fault: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Thermocouple Temperature High Fault: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_TCLOW) == MAX31856_FAULT_TCLOW) { - ESP_LOGW(TAG, "Thermocouple Temperature Low Fault: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Thermocouple Temperature Low Fault: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_OVUV) == MAX31856_FAULT_OVUV) { - ESP_LOGW(TAG, "Overvoltage or Undervoltage Input Fault: '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Overvoltage or Undervoltage Input Fault: '%s'", this->name_.c_str()); } if ((faults & MAX31856_FAULT_OPEN) == MAX31856_FAULT_OPEN) { - ESP_LOGW(TAG, "Thermocouple Open-Circuit Fault (possibly not connected): '%s'...", this->name_.c_str()); + ESP_LOGW(TAG, "Thermocouple Open-Circuit Fault (possibly not connected): '%s'", this->name_.c_str()); } return true; diff --git a/esphome/components/max31865/max31865.cpp b/esphome/components/max31865/max31865.cpp index ac41130a8e..4c9a4ae540 100644 --- a/esphome/components/max31865/max31865.cpp +++ b/esphome/components/max31865/max31865.cpp @@ -83,9 +83,11 @@ void MAX31865Sensor::dump_config() { LOG_SENSOR("", "MAX31865", this); LOG_PIN(" CS Pin: ", this->cs_); LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " Reference Resistance: %.2fΩ", reference_resistance_); - ESP_LOGCONFIG(TAG, " RTD: %u-wire %.2fΩ", rtd_wires_, rtd_nominal_resistance_); - ESP_LOGCONFIG(TAG, " Mains Filter: %s", + ESP_LOGCONFIG(TAG, + " Reference Resistance: %.2fΩ\n" + " RTD: %u-wire %.2fΩ\n" + " Mains Filter: %s", + reference_resistance_, rtd_wires_, rtd_nominal_resistance_, (filter_ == FILTER_60HZ ? "60 Hz" : (filter_ == FILTER_50HZ ? "50 Hz" : "Unknown!"))); } diff --git a/esphome/components/max6956/max6956.cpp b/esphome/components/max6956/max6956.cpp index 3da4dcc43d..5a1da9dc6f 100644 --- a/esphome/components/max6956/max6956.cpp +++ b/esphome/components/max6956/max6956.cpp @@ -146,8 +146,10 @@ void MAX6956::dump_config() { ESP_LOGCONFIG(TAG, "MAX6956"); if (brightness_mode_ == MAX6956CURRENTMODE::GLOBAL) { - ESP_LOGCONFIG(TAG, "current mode: global"); - ESP_LOGCONFIG(TAG, "global brightness: %u", global_brightness_); + ESP_LOGCONFIG(TAG, + "current mode: global\n" + "global brightness: %u", + global_brightness_); } else { ESP_LOGCONFIG(TAG, "current mode: segment"); } diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index 64be13d621..3f78b35bbb 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -1,7 +1,7 @@ #include "max7219.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace max7219 { @@ -133,9 +133,11 @@ void MAX7219Component::setup() { this->send_to_all_(MAX7219_REGISTER_SHUTDOWN, 1); } void MAX7219Component::dump_config() { - ESP_LOGCONFIG(TAG, "MAX7219:"); - ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_); - ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_); + ESP_LOGCONFIG(TAG, + "MAX7219:\n" + " Number of Chips: %u\n" + " Intensity: %u", + this->num_chips_, this->intensity_); LOG_PIN(" CS Pin: ", this->cs_); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/max7219digit/max7219digit.cpp b/esphome/components/max7219digit/max7219digit.cpp index a6c06b5213..1721dc80ce 100644 --- a/esphome/components/max7219digit/max7219digit.cpp +++ b/esphome/components/max7219digit/max7219digit.cpp @@ -1,8 +1,8 @@ #include "max7219digit.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" -#include "esphome/core/hal.h" #include "esphome/core/application.h" +#include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "max7219font.h" #include @@ -50,15 +50,18 @@ void MAX7219Component::setup() { } void MAX7219Component::dump_config() { - ESP_LOGCONFIG(TAG, "MAX7219DIGIT:"); - ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_); - ESP_LOGCONFIG(TAG, " Number of Chips Lines: %u", this->num_chip_lines_); - ESP_LOGCONFIG(TAG, " Chips Lines Style : %u", this->chip_lines_style_); - ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_); - ESP_LOGCONFIG(TAG, " Scroll Mode: %u", this->scroll_mode_); - ESP_LOGCONFIG(TAG, " Scroll Speed: %u", this->scroll_speed_); - ESP_LOGCONFIG(TAG, " Scroll Dwell: %u", this->scroll_dwell_); - ESP_LOGCONFIG(TAG, " Scroll Delay: %u", this->scroll_delay_); + ESP_LOGCONFIG(TAG, + "MAX7219DIGIT:\n" + " Number of Chips: %u\n" + " Number of Chips Lines: %u\n" + " Chips Lines Style : %u\n" + " Intensity: %u\n" + " Scroll Mode: %u\n" + " Scroll Speed: %u\n" + " Scroll Dwell: %u\n" + " Scroll Delay: %u", + this->num_chips_, this->num_chip_lines_, this->chip_lines_style_, this->intensity_, this->scroll_mode_, + this->scroll_speed_, this->scroll_dwell_, this->scroll_delay_); LOG_PIN(" CS Pin: ", this->cs_); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/max9611/max9611.cpp b/esphome/components/max9611/max9611.cpp index ca081b9f16..e61a30ab99 100644 --- a/esphome/components/max9611/max9611.cpp +++ b/esphome/components/max9611/max9611.cpp @@ -42,18 +42,20 @@ void MAX9611Component::setup() { const uint8_t fast_mode_dat[] = {CONTROL_REGISTER_1_ADRR, MAX9611Multiplexer::MAX9611_MULTIPLEXER_FAST_MODE}; if (this->write(reinterpret_cast(&setup_dat), sizeof(setup_dat)) != ErrorCode::ERROR_OK) { - ESP_LOGE(TAG, "Failed to setup Max9611 during GAIN SET"); + ESP_LOGE(TAG, "GAIN SET failed"); return; } delay(SETUP_DELAY); if (this->write(reinterpret_cast(&fast_mode_dat), sizeof(fast_mode_dat)) != ErrorCode::ERROR_OK) { - ESP_LOGE(TAG, "Failed to setup Max9611 during FAST MODE SET"); + ESP_LOGE(TAG, "FAST MODE SET failed"); return; } } void MAX9611Component::dump_config() { - ESP_LOGCONFIG(TAG, "Dump Config max9611..."); - ESP_LOGCONFIG(TAG, " CSA Gain Register: %x", gain_); + ESP_LOGCONFIG(TAG, + "MAX9611:\n" + " CSA Gain Register: %x", + gain_); LOG_I2C_DEVICE(this); } void MAX9611Component::update() { @@ -63,7 +65,7 @@ void MAX9611Component::update() { // Just read the entire register map in a bulk read, faster than individually querying register. const ErrorCode read_result = this->read(register_map_, sizeof(register_map_)); if (write_result != ErrorCode::ERROR_OK || read_result != ErrorCode::ERROR_OK) { - ESP_LOGW(TAG, "MAX9611 Update FAILED!"); + ESP_LOGW(TAG, "Update failed"); return; } uint16_t csa_register = ((register_map_[CSA_DATA_BYTE_MSB_ADRR] << 8) | (register_map_[CSA_DATA_BYTE_LSB_ADRR])) >> 4; diff --git a/esphome/components/mcp23016/__init__.py b/esphome/components/mcp23016/__init__.py index e15c643349..3333e46c97 100644 --- a/esphome/components/mcp23016/__init__.py +++ b/esphome/components/mcp23016/__init__.py @@ -50,7 +50,7 @@ MCP23016_PIN_SCHEMA = pins.gpio_base_schema( cv.int_range(min=0, max=15), modes=[CONF_INPUT, CONF_OUTPUT], mode_validator=validate_mode, - invertable=True, + invertible=True, ).extend( { cv.Required(CONF_MCP23016): cv.use_id(MCP23016), diff --git a/esphome/components/mcp23xxx_base/__init__.py b/esphome/components/mcp23xxx_base/__init__.py index c0e44d72de..8cf0ebcd44 100644 --- a/esphome/components/mcp23xxx_base/__init__.py +++ b/esphome/components/mcp23xxx_base/__init__.py @@ -60,7 +60,7 @@ MCP23XXX_PIN_SCHEMA = pins.gpio_base_schema( cv.int_range(min=0, max=15), modes=[CONF_INPUT, CONF_OUTPUT, CONF_PULLUP], mode_validator=validate_mode, - invertable=True, + invertible=True, ).extend( { cv.Required(CONF_MCP23XXX): cv.use_id(MCP23XXXBase), diff --git a/esphome/components/mcp3008/sensor/mcp3008_sensor.cpp b/esphome/components/mcp3008/sensor/mcp3008_sensor.cpp index df2a8735f8..81eb0a812f 100644 --- a/esphome/components/mcp3008/sensor/mcp3008_sensor.cpp +++ b/esphome/components/mcp3008/sensor/mcp3008_sensor.cpp @@ -10,9 +10,11 @@ static const char *const TAG = "mcp3008.sensor"; float MCP3008Sensor::get_setup_priority() const { return setup_priority::DATA; } void MCP3008Sensor::dump_config() { - ESP_LOGCONFIG(TAG, "MCP3008Sensor:"); - ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_); - ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_); + ESP_LOGCONFIG(TAG, + "MCP3008Sensor:\n" + " Pin: %u\n" + " Reference Voltage: %.2fV", + this->pin_, this->reference_voltage_); } float MCP3008Sensor::sample() { diff --git a/esphome/components/mcp4461/mcp4461.cpp b/esphome/components/mcp4461/mcp4461.cpp index 88e7475a76..39127a6c04 100644 --- a/esphome/components/mcp4461/mcp4461.cpp +++ b/esphome/components/mcp4461/mcp4461.cpp @@ -1,7 +1,7 @@ #include "mcp4461.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" namespace esphome { namespace mcp4461 { diff --git a/esphome/components/mdns/mdns_component.cpp b/esphome/components/mdns/mdns_component.cpp index ffc668e218..06ca99b402 100644 --- a/esphome/components/mdns/mdns_component.cpp +++ b/esphome/components/mdns/mdns_component.cpp @@ -59,6 +59,8 @@ void MDNSComponent::compile_records_() { service.txt_records.push_back({"network", "wifi"}); #elif defined(USE_ETHERNET) service.txt_records.push_back({"network", "ethernet"}); +#elif defined(USE_OPENTHREAD) + service.txt_records.push_back({"network", "thread"}); #endif #ifdef USE_API_NOISE @@ -117,8 +119,10 @@ void MDNSComponent::compile_records_() { } void MDNSComponent::dump_config() { - ESP_LOGCONFIG(TAG, "mDNS:"); - ESP_LOGCONFIG(TAG, " Hostname: %s", this->hostname_.c_str()); + ESP_LOGCONFIG(TAG, + "mDNS:\n" + " Hostname: %s", + this->hostname_.c_str()); ESP_LOGV(TAG, " Services:"); for (const auto &service : this->services_) { ESP_LOGV(TAG, " - %s, %s, %d", service.service_type.c_str(), service.proto.c_str(), @@ -130,6 +134,8 @@ void MDNSComponent::dump_config() { } } +std::vector MDNSComponent::get_services() { return this->services_; } + } // namespace mdns } // namespace esphome #endif diff --git a/esphome/components/mdns/mdns_component.h b/esphome/components/mdns/mdns_component.h index 9eb2ba11d0..93a16f40d2 100644 --- a/esphome/components/mdns/mdns_component.h +++ b/esphome/components/mdns/mdns_component.h @@ -33,10 +33,12 @@ class MDNSComponent : public Component { #if (defined(USE_ESP8266) || defined(USE_RP2040)) && defined(USE_ARDUINO) void loop() override; #endif - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; } void add_extra_service(MDNSService service) { services_extra_.push_back(std::move(service)); } + std::vector get_services(); + void on_shutdown() override; protected: diff --git a/esphome/components/media_player/__init__.py b/esphome/components/media_player/__init__.py index 2f5fe0c03e..ef76419de3 100644 --- a/esphome/components/media_player/__init__.py +++ b/esphome/components/media_player/__init__.py @@ -103,6 +103,7 @@ async def register_media_player(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_media_player(var)) + CORE.register_platform_component("media_player", var) await setup_media_player_core_(var, config) diff --git a/esphome/components/micro_wake_word/streaming_model.cpp b/esphome/components/micro_wake_word/streaming_model.cpp index 38b88557e6..31341bba0d 100644 --- a/esphome/components/micro_wake_word/streaming_model.cpp +++ b/esphome/components/micro_wake_word/streaming_model.cpp @@ -11,15 +11,19 @@ namespace esphome { namespace micro_wake_word { void WakeWordModel::log_model_config() { - ESP_LOGCONFIG(TAG, " - Wake Word: %s", this->wake_word_.c_str()); - ESP_LOGCONFIG(TAG, " Probability cutoff: %.2f", this->probability_cutoff_ / 255.0f); - ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_); + ESP_LOGCONFIG(TAG, + " - Wake Word: %s\n" + " Probability cutoff: %.2f\n" + " Sliding window size: %d", + this->wake_word_.c_str(), this->probability_cutoff_ / 255.0f, this->sliding_window_size_); } void VADModel::log_model_config() { - ESP_LOGCONFIG(TAG, " - VAD Model"); - ESP_LOGCONFIG(TAG, " Probability cutoff: %.2f", this->probability_cutoff_ / 255.0f); - ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_); + ESP_LOGCONFIG(TAG, + " - VAD Model\n" + " Probability cutoff: %.2f\n" + " Sliding window size: %d", + this->probability_cutoff_ / 255.0f, this->sliding_window_size_); } bool StreamingModel::load_model_() { diff --git a/esphome/components/micronova/micronova.h b/esphome/components/micronova/micronova.h index aebef277e5..fc68d941cf 100644 --- a/esphome/components/micronova/micronova.h +++ b/esphome/components/micronova/micronova.h @@ -1,10 +1,10 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/components/uart/uart.h" -#include "esphome/core/log.h" +#include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include diff --git a/esphome/components/mics_4514/mics_4514.cpp b/esphome/components/mics_4514/mics_4514.cpp index 5fab97d57a..3a2cf22914 100644 --- a/esphome/components/mics_4514/mics_4514.cpp +++ b/esphome/components/mics_4514/mics_4514.cpp @@ -16,7 +16,7 @@ void MICS4514Component::setup() { uint8_t power_mode; this->read_register(POWER_MODE_REGISTER, &power_mode, 1); if (power_mode == 0x00) { - ESP_LOGCONFIG(TAG, "Waking up MICS 4514, sensors will have data after 3 minutes..."); + ESP_LOGCONFIG(TAG, "Waking up MICS 4514, sensors will have data after 3 minutes"); power_mode = 0x01; this->write_register(POWER_MODE_REGISTER, &power_mode, 1); delay(100); // NOLINT diff --git a/esphome/components/midea/air_conditioner.cpp b/esphome/components/midea/air_conditioner.cpp index 247aea0488..170a2f6a40 100644 --- a/esphome/components/midea/air_conditioner.cpp +++ b/esphome/components/midea/air_conditioner.cpp @@ -1,7 +1,7 @@ #ifdef USE_ARDUINO -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "air_conditioner.h" #include "ac_adapter.h" #include @@ -103,10 +103,12 @@ ClimateTraits AirConditioner::traits() { } void AirConditioner::dump_config() { - ESP_LOGCONFIG(Constants::TAG, "MideaDongle:"); - ESP_LOGCONFIG(Constants::TAG, " [x] Period: %dms", this->base_.getPeriod()); - ESP_LOGCONFIG(Constants::TAG, " [x] Response timeout: %dms", this->base_.getTimeout()); - ESP_LOGCONFIG(Constants::TAG, " [x] Request attempts: %d", this->base_.getNumAttempts()); + ESP_LOGCONFIG(Constants::TAG, + "MideaDongle:\n" + " [x] Period: %dms\n" + " [x] Response timeout: %dms\n" + " [x] Request attempts: %d", + this->base_.getPeriod(), this->base_.getTimeout(), this->base_.getNumAttempts()); #ifdef USE_REMOTE_TRANSMITTER ESP_LOGCONFIG(Constants::TAG, " [x] Using RemoteTransmitter"); #endif diff --git a/esphome/components/midea_ir/midea_ir.cpp b/esphome/components/midea_ir/midea_ir.cpp index aa5e2b46f5..c269b2f7d9 100644 --- a/esphome/components/midea_ir/midea_ir.cpp +++ b/esphome/components/midea_ir/midea_ir.cpp @@ -1,7 +1,7 @@ #include "midea_ir.h" #include "midea_data.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/components/coolix/coolix.h" namespace esphome { diff --git a/esphome/components/mipi_spi/mipi_spi.cpp b/esphome/components/mipi_spi/mipi_spi.cpp index 043346411e..962575477d 100644 --- a/esphome/components/mipi_spi/mipi_spi.cpp +++ b/esphome/components/mipi_spi/mipi_spi.cpp @@ -447,21 +447,28 @@ void MipiSpi::write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) { } void MipiSpi::dump_config() { - ESP_LOGCONFIG(TAG, "MIPI_SPI Display"); - ESP_LOGCONFIG(TAG, " Model: %s", this->model_); - ESP_LOGCONFIG(TAG, " Width: %u", this->width_); - ESP_LOGCONFIG(TAG, " Height: %u", this->height_); + ESP_LOGCONFIG(TAG, + "MIPI_SPI Display\n" + " Model: %s\n" + " Width: %u\n" + " Height: %u", + this->model_, this->width_, this->height_); if (this->offset_width_ != 0) ESP_LOGCONFIG(TAG, " Offset width: %u", this->offset_width_); if (this->offset_height_ != 0) ESP_LOGCONFIG(TAG, " Offset height: %u", this->offset_height_); - ESP_LOGCONFIG(TAG, " Swap X/Y: %s", YESNO(this->madctl_ & MADCTL_MV)); - ESP_LOGCONFIG(TAG, " Mirror X: %s", YESNO(this->madctl_ & (MADCTL_MX | MADCTL_XFLIP))); - ESP_LOGCONFIG(TAG, " Mirror Y: %s", YESNO(this->madctl_ & (MADCTL_MY | MADCTL_YFLIP))); - ESP_LOGCONFIG(TAG, " Color depth: %d bits", this->color_depth_ == display::COLOR_BITNESS_565 ? 16 : 8); - ESP_LOGCONFIG(TAG, " Invert colors: %s", YESNO(this->invert_colors_)); - ESP_LOGCONFIG(TAG, " Color order: %s", this->madctl_ & MADCTL_BGR ? "BGR" : "RGB"); - ESP_LOGCONFIG(TAG, " Pixel mode: %s", this->pixel_mode_ == PIXEL_MODE_18 ? "18bit" : "16bit"); + ESP_LOGCONFIG(TAG, + " Swap X/Y: %s\n" + " Mirror X: %s\n" + " Mirror Y: %s\n" + " Color depth: %d bits\n" + " Invert colors: %s\n" + " Color order: %s\n" + " Pixel mode: %s", + YESNO(this->madctl_ & MADCTL_MV), YESNO(this->madctl_ & (MADCTL_MX | MADCTL_XFLIP)), + YESNO(this->madctl_ & (MADCTL_MY | MADCTL_YFLIP)), + this->color_depth_ == display::COLOR_BITNESS_565 ? 16 : 8, YESNO(this->invert_colors_), + this->madctl_ & MADCTL_BGR ? "BGR" : "RGB", this->pixel_mode_ == PIXEL_MODE_18 ? "18bit" : "16bit"); if (this->brightness_.has_value()) ESP_LOGCONFIG(TAG, " Brightness: %u", this->brightness_.value()); if (this->spi_16_) @@ -472,9 +479,11 @@ void MipiSpi::dump_config() { LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" DC Pin: ", this->dc_pin_); - ESP_LOGCONFIG(TAG, " SPI Mode: %d", this->mode_); - ESP_LOGCONFIG(TAG, " SPI Data rate: %dMHz", static_cast(this->data_rate_ / 1000000)); - ESP_LOGCONFIG(TAG, " SPI Bus width: %d", this->bus_width_); + ESP_LOGCONFIG(TAG, + " SPI Mode: %d\n" + " SPI Data rate: %dMHz\n" + " SPI Bus width: %d", + this->mode_, static_cast(this->data_rate_ / 1000000), this->bus_width_); } } // namespace mipi_spi diff --git a/esphome/components/mixer/speaker/mixer_speaker.cpp b/esphome/components/mixer/speaker/mixer_speaker.cpp index 8e480dd49b..fc0517c7be 100644 --- a/esphome/components/mixer/speaker/mixer_speaker.cpp +++ b/esphome/components/mixer/speaker/mixer_speaker.cpp @@ -43,8 +43,10 @@ enum MixerEventGroupBits : uint32_t { }; void SourceSpeaker::dump_config() { - ESP_LOGCONFIG(TAG, "Mixer Source Speaker"); - ESP_LOGCONFIG(TAG, " Buffer Duration: %" PRIu32 " ms", this->buffer_duration_ms_); + ESP_LOGCONFIG(TAG, + "Mixer Source Speaker\n" + " Buffer Duration: %" PRIu32 " ms", + this->buffer_duration_ms_); if (this->timeout_ms_.has_value()) { ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 " ms", this->timeout_ms_.value()); } else { @@ -291,8 +293,10 @@ void SourceSpeaker::duck_samples(int16_t *input_buffer, uint32_t input_samples_t } void MixerSpeaker::dump_config() { - ESP_LOGCONFIG(TAG, "Speaker Mixer:"); - ESP_LOGCONFIG(TAG, " Number of output channels: %u", this->output_channels_); + ESP_LOGCONFIG(TAG, + "Speaker Mixer:\n" + " Number of output channels: %u", + this->output_channels_); } void MixerSpeaker::setup() { diff --git a/esphome/components/mlx90614/mlx90614.cpp b/esphome/components/mlx90614/mlx90614.cpp index 97888b59bd..afc565d38b 100644 --- a/esphome/components/mlx90614/mlx90614.cpp +++ b/esphome/components/mlx90614/mlx90614.cpp @@ -1,6 +1,7 @@ #include "mlx90614.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index cd5fc55689..c2efa93fae 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -1,7 +1,7 @@ #include "modbus.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace modbus { @@ -165,8 +165,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { void Modbus::dump_config() { ESP_LOGCONFIG(TAG, "Modbus:"); LOG_PIN(" Flow Control Pin: ", this->flow_control_pin_); - ESP_LOGCONFIG(TAG, " Send Wait Time: %d ms", this->send_wait_time_); - ESP_LOGCONFIG(TAG, " CRC Disabled: %s", YESNO(this->disable_crc_)); + ESP_LOGCONFIG(TAG, + " Send Wait Time: %d ms\n" + " CRC Disabled: %s", + this->send_wait_time_, YESNO(this->disable_crc_)); } float Modbus::get_setup_priority() const { // After UART bus diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 3f487abc94..48ff868087 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -346,10 +346,12 @@ size_t ModbusController::create_register_ranges_() { } void ModbusController::dump_config() { - ESP_LOGCONFIG(TAG, "ModbusController:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); - ESP_LOGCONFIG(TAG, " Max Command Retries: %d", this->max_cmd_retries_); - ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_); + ESP_LOGCONFIG(TAG, + "ModbusController:\n" + " Address: 0x%02X\n" + " Max Command Retries: %d\n" + " Offline Skip Updates: %d", + this->address_, this->max_cmd_retries_, this->offline_skip_updates_); #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE ESP_LOGCONFIG(TAG, "sensormap"); for (auto &it : this->sensorset_) { diff --git a/esphome/components/modbus_controller/output/modbus_output.cpp b/esphome/components/modbus_controller/output/modbus_output.cpp index f0f6e64f10..45e786a704 100644 --- a/esphome/components/modbus_controller/output/modbus_output.cpp +++ b/esphome/components/modbus_controller/output/modbus_output.cpp @@ -52,9 +52,11 @@ void ModbusFloatOutput::write_state(float value) { void ModbusFloatOutput::dump_config() { ESP_LOGCONFIG(TAG, "Modbus Float Output:"); LOG_FLOAT_OUTPUT(this); - ESP_LOGCONFIG(TAG, " Device start address: 0x%X", this->start_address); - ESP_LOGCONFIG(TAG, " Register count: %d", this->register_count); - ESP_LOGCONFIG(TAG, " Value type: %d", static_cast(this->sensor_value_type)); + ESP_LOGCONFIG(TAG, + " Device start address: 0x%X\n" + " Register count: %d\n" + " Value type: %d", + this->start_address, this->register_count, static_cast(this->sensor_value_type)); } // ModbusBinaryOutput @@ -102,9 +104,11 @@ void ModbusBinaryOutput::write_state(bool state) { void ModbusBinaryOutput::dump_config() { ESP_LOGCONFIG(TAG, "Modbus Binary Output:"); LOG_BINARY_OUTPUT(this); - ESP_LOGCONFIG(TAG, " Device start address: 0x%X", this->start_address); - ESP_LOGCONFIG(TAG, " Register count: %d", this->register_count); - ESP_LOGCONFIG(TAG, " Value type: %d", static_cast(this->sensor_value_type)); + ESP_LOGCONFIG(TAG, + " Device start address: 0x%X\n" + " Register count: %d\n" + " Value type: %d", + this->start_address, this->register_count, static_cast(this->sensor_value_type)); } } // namespace modbus_controller diff --git a/esphome/components/mpl3115a2/mpl3115a2.cpp b/esphome/components/mpl3115a2/mpl3115a2.cpp index d415b77294..9b65fb04e4 100644 --- a/esphome/components/mpl3115a2/mpl3115a2.cpp +++ b/esphome/components/mpl3115a2/mpl3115a2.cpp @@ -1,5 +1,6 @@ #include "mpl3115a2.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/mpu6050/mpu6050.cpp b/esphome/components/mpu6050/mpu6050.cpp index 127d84e816..84f0fb4bae 100644 --- a/esphome/components/mpu6050/mpu6050.cpp +++ b/esphome/components/mpu6050/mpu6050.cpp @@ -29,7 +29,7 @@ void MPU6050Component::setup() { return; } - ESP_LOGV(TAG, " Setting up Power Management..."); + ESP_LOGV(TAG, " Setting up Power Management"); // Setup power management uint8_t power_management; if (!this->read_byte(MPU6050_REGISTER_POWER_MANAGEMENT_1, &power_management)) { @@ -50,7 +50,7 @@ void MPU6050Component::setup() { return; } - ESP_LOGV(TAG, " Setting up Gyro Config..."); + ESP_LOGV(TAG, " Setting up Gyro Config"); // Set scale - 2000DPS uint8_t gyro_config; if (!this->read_byte(MPU6050_REGISTER_GYRO_CONFIG, &gyro_config)) { @@ -66,7 +66,7 @@ void MPU6050Component::setup() { return; } - ESP_LOGV(TAG, " Setting up Accel Config..."); + ESP_LOGV(TAG, " Setting up Accel Config"); // Set range - 2G uint8_t accel_config; if (!this->read_byte(MPU6050_REGISTER_ACCEL_CONFIG, &accel_config)) { @@ -99,7 +99,7 @@ void MPU6050Component::dump_config() { } void MPU6050Component::update() { - ESP_LOGV(TAG, " Updating MPU6050..."); + ESP_LOGV(TAG, "Updating"); uint16_t raw_data[7]; if (!this->read_bytes_16(MPU6050_REGISTER_ACCEL_XOUT_H, raw_data, 7)) { this->status_set_warning(); diff --git a/esphome/components/mpu6886/mpu6886.cpp b/esphome/components/mpu6886/mpu6886.cpp index 8f3adeed8d..cbd8b601bd 100644 --- a/esphome/components/mpu6886/mpu6886.cpp +++ b/esphome/components/mpu6886/mpu6886.cpp @@ -33,7 +33,7 @@ void MPU6886Component::setup() { return; } - ESP_LOGV(TAG, " Setting up Power Management..."); + ESP_LOGV(TAG, " Setting up Power Management"); // Setup power management uint8_t power_management; if (!this->read_byte(MPU6886_REGISTER_POWER_MANAGEMENT_1, &power_management)) { @@ -54,7 +54,7 @@ void MPU6886Component::setup() { return; } - ESP_LOGV(TAG, " Setting up Gyroscope Config..."); + ESP_LOGV(TAG, " Setting up Gyroscope Config"); // Set scale - 2000DPS uint8_t gyro_config; if (!this->read_byte(MPU6886_REGISTER_GYRO_CONFIG, &gyro_config)) { @@ -70,7 +70,7 @@ void MPU6886Component::setup() { return; } - ESP_LOGV(TAG, " Setting up Accelerometer Config..."); + ESP_LOGV(TAG, " Setting up Accelerometer Config"); // Set range - 2G uint8_t accel_config; if (!this->read_byte(MPU6886_REGISTER_ACCEL_CONFIG, &accel_config)) { @@ -104,7 +104,7 @@ void MPU6886Component::dump_config() { } void MPU6886Component::update() { - ESP_LOGV(TAG, " Updating MPU6886..."); + ESP_LOGV(TAG, " Updating"); uint16_t raw_data[7]; if (!this->read_bytes_16(MPU6886_REGISTER_ACCEL_XOUT_H, raw_data, 7)) { this->status_set_warning(); diff --git a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp index 4cc4773bd3..0a38598679 100644 --- a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp +++ b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp @@ -45,9 +45,13 @@ void MQTTAlarmControlPanelComponent::setup() { void MQTTAlarmControlPanelComponent::dump_config() { ESP_LOGCONFIG(TAG, "MQTT alarm_control_panel '%s':", this->alarm_control_panel_->get_name().c_str()); LOG_MQTT_COMPONENT(true, true) - ESP_LOGCONFIG(TAG, " Supported Features: %" PRIu32, this->alarm_control_panel_->get_supported_features()); - ESP_LOGCONFIG(TAG, " Requires Code to Disarm: %s", YESNO(this->alarm_control_panel_->get_requires_code())); - ESP_LOGCONFIG(TAG, " Requires Code To Arm: %s", YESNO(this->alarm_control_panel_->get_requires_code_to_arm())); + ESP_LOGCONFIG(TAG, + " Supported Features: %" PRIu32 "\n" + " Requires Code to Disarm: %s\n" + " Requires Code To Arm: %s", + this->alarm_control_panel_->get_supported_features(), + YESNO(this->alarm_control_panel_->get_requires_code()), + YESNO(this->alarm_control_panel_->get_requires_code_to_arm())); } void MQTTAlarmControlPanelComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { diff --git a/esphome/components/mqtt/mqtt_backend_esp32.cpp b/esphome/components/mqtt/mqtt_backend_esp32.cpp index 2cccb957eb..64dc27d84b 100644 --- a/esphome/components/mqtt/mqtt_backend_esp32.cpp +++ b/esphome/components/mqtt/mqtt_backend_esp32.cpp @@ -4,8 +4,8 @@ #ifdef USE_ESP32 #include -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace mqtt { diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index f95096106f..ceb56bdfbe 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -149,18 +149,23 @@ void MQTTClientComponent::send_device_info_() { } void MQTTClientComponent::dump_config() { - ESP_LOGCONFIG(TAG, "MQTT:"); - ESP_LOGCONFIG(TAG, " Server Address: %s:%u (%s)", this->credentials_.address.c_str(), this->credentials_.port, - this->ip_.str().c_str()); - ESP_LOGCONFIG(TAG, " Username: " LOG_SECRET("'%s'"), this->credentials_.username.c_str()); - ESP_LOGCONFIG(TAG, " Client ID: " LOG_SECRET("'%s'"), this->credentials_.client_id.c_str()); - ESP_LOGCONFIG(TAG, " Clean Session: %s", YESNO(this->credentials_.clean_session)); + ESP_LOGCONFIG(TAG, + "MQTT:\n" + " Server Address: %s:%u (%s)\n" + " Username: " LOG_SECRET("'%s'") "\n" + " Client ID: " LOG_SECRET("'%s'") "\n" + " Clean Session: %s", + this->credentials_.address.c_str(), this->credentials_.port, this->ip_.str().c_str(), + this->credentials_.username.c_str(), this->credentials_.client_id.c_str(), + YESNO(this->credentials_.clean_session)); if (this->is_discovery_ip_enabled()) { ESP_LOGCONFIG(TAG, " Discovery IP enabled"); } if (!this->discovery_info_.prefix.empty()) { - ESP_LOGCONFIG(TAG, " Discovery prefix: '%s'", this->discovery_info_.prefix.c_str()); - ESP_LOGCONFIG(TAG, " Discovery retain: %s", YESNO(this->discovery_info_.retain)); + ESP_LOGCONFIG(TAG, + " Discovery prefix: '%s'\n" + " Discovery retain: %s", + this->discovery_info_.prefix.c_str(), YESNO(this->discovery_info_.retain)); } ESP_LOGCONFIG(TAG, " Topic Prefix: '%s'", this->topic_prefix_.c_str()); if (!this->log_message_.topic.empty()) { @@ -201,13 +206,13 @@ void MQTTClientComponent::start_dnslookup_() { } case ERR_INPROGRESS: { // wait for callback - ESP_LOGD(TAG, "Resolving MQTT broker IP address..."); + ESP_LOGD(TAG, "Resolving broker IP address"); break; } default: case ERR_ARG: { // error - ESP_LOGW(TAG, "Error resolving MQTT broker IP address: %d", err); + ESP_LOGW(TAG, "Error resolving broker IP address: %d", err); break; } } @@ -221,7 +226,7 @@ void MQTTClientComponent::check_dnslookup_() { } if (this->dns_resolve_error_) { - ESP_LOGW(TAG, "Couldn't resolve IP address for '%s'!", this->credentials_.address.c_str()); + ESP_LOGW(TAG, "Couldn't resolve IP address for '%s'", this->credentials_.address.c_str()); this->state_ = MQTT_CLIENT_DISCONNECTED; return; } @@ -251,7 +256,7 @@ void MQTTClientComponent::start_connect_() { if (!network::is_connected()) return; - ESP_LOGI(TAG, "Connecting to MQTT..."); + ESP_LOGI(TAG, "Connecting"); // Force disconnect first this->mqtt_backend_.disconnect(); @@ -292,7 +297,7 @@ void MQTTClientComponent::check_connected() { this->state_ = MQTT_CLIENT_CONNECTED; this->sent_birth_message_ = false; this->status_clear_warning(); - ESP_LOGI(TAG, "MQTT Connected!"); + ESP_LOGI(TAG, "Connected"); // MQTT Client needs some time to be fully set up. delay(100); // NOLINT @@ -341,7 +346,7 @@ void MQTTClientComponent::loop() { if (!network::is_connected()) { reason_s = LOG_STR("WiFi disconnected"); } - ESP_LOGW(TAG, "MQTT Disconnected: %s.", LOG_STR_ARG(reason_s)); + ESP_LOGW(TAG, "Disconnected: %s", LOG_STR_ARG(reason_s)); this->disconnect_reason_.reset(); } @@ -364,7 +369,7 @@ void MQTTClientComponent::loop() { case MQTT_CLIENT_CONNECTED: if (!this->mqtt_backend_.connected()) { this->state_ = MQTT_CLIENT_DISCONNECTED; - ESP_LOGW(TAG, "Lost MQTT Client connection!"); + ESP_LOGW(TAG, "Lost client connection"); this->start_dnslookup_(); } else { if (!this->birth_message_.topic.empty() && !this->sent_birth_message_) { @@ -378,7 +383,7 @@ void MQTTClientComponent::loop() { } if (millis() - this->last_connected_ > this->reboot_timeout_ && this->reboot_timeout_ != 0) { - ESP_LOGE(TAG, "Can't connect to MQTT... Restarting..."); + ESP_LOGE(TAG, "Can't connect; restarting"); App.reboot(); } } @@ -396,7 +401,7 @@ bool MQTTClientComponent::subscribe_(const char *topic, uint8_t qos) { ESP_LOGV(TAG, "subscribe(topic='%s')", topic); } else { delay(5); - ESP_LOGV(TAG, "Subscribe failed for topic='%s'. Will retry later.", topic); + ESP_LOGV(TAG, "Subscribe failed for topic='%s'. Will retry", topic); this->status_momentary_warning("subscribe", 1000); } return ret != 0; @@ -499,7 +504,7 @@ bool MQTTClientComponent::publish(const MQTTMessage &message) { ESP_LOGV(TAG, "Publish(topic='%s' payload='%s' retain=%d qos=%d)", message.topic.c_str(), message.payload.c_str(), message.retain, message.qos); } else { - ESP_LOGV(TAG, "Publish failed for topic='%s' (len=%u). will retry later..", message.topic.c_str(), + ESP_LOGV(TAG, "Publish failed for topic='%s' (len=%u). Will retry", message.topic.c_str(), message.payload.length()); this->status_momentary_warning("publish", 1000); } @@ -515,7 +520,7 @@ bool MQTTClientComponent::publish_json(const std::string &topic, const json::jso void MQTTClientComponent::enable() { if (this->state_ != MQTT_CLIENT_DISABLED) return; - ESP_LOGD(TAG, "Enabling MQTT..."); + ESP_LOGD(TAG, "Enabling"); this->state_ = MQTT_CLIENT_DISCONNECTED; this->last_connected_ = millis(); this->start_dnslookup_(); @@ -524,7 +529,7 @@ void MQTTClientComponent::enable() { void MQTTClientComponent::disable() { if (this->state_ == MQTT_CLIENT_DISABLED) return; - ESP_LOGD(TAG, "Disabling MQTT..."); + ESP_LOGD(TAG, "Disabling"); this->state_ = MQTT_CLIENT_DISABLED; this->on_shutdown(); } @@ -721,9 +726,11 @@ void MQTTMessageTrigger::setup() { this->qos_); } void MQTTMessageTrigger::dump_config() { - ESP_LOGCONFIG(TAG, "MQTT Message Trigger:"); - ESP_LOGCONFIG(TAG, " Topic: '%s'", this->topic_.c_str()); - ESP_LOGCONFIG(TAG, " QoS: %u", this->qos_); + ESP_LOGCONFIG(TAG, + "MQTT Message Trigger:\n" + " Topic: '%s'\n" + " QoS: %u", + this->topic_.c_str(), this->qos_); } float MQTTMessageTrigger::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index 3b9d367a7b..456ae25e65 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -64,11 +64,11 @@ bool MQTTComponent::send_discovery_() { const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info(); if (discovery_info.clean) { - ESP_LOGV(TAG, "'%s': Cleaning discovery...", this->friendly_name().c_str()); + ESP_LOGV(TAG, "'%s': Cleaning discovery", this->friendly_name().c_str()); return global_mqtt_client->publish(this->get_discovery_topic_(discovery_info), "", 0, this->qos_, true); } - ESP_LOGV(TAG, "'%s': Sending discovery...", this->friendly_name().c_str()); + ESP_LOGV(TAG, "'%s': Sending discovery", this->friendly_name().c_str()); return global_mqtt_client->publish_json( this->get_discovery_topic_(discovery_info), diff --git a/esphome/components/mqtt/mqtt_cover.cpp b/esphome/components/mqtt/mqtt_cover.cpp index 0718a24828..8d09d836f3 100644 --- a/esphome/components/mqtt/mqtt_cover.cpp +++ b/esphome/components/mqtt/mqtt_cover.cpp @@ -54,12 +54,16 @@ void MQTTCoverComponent::dump_config() { bool has_command_topic = traits.get_supports_position() || !traits.get_supports_tilt(); LOG_MQTT_COMPONENT(true, has_command_topic) if (traits.get_supports_position()) { - ESP_LOGCONFIG(TAG, " Position State Topic: '%s'", this->get_position_state_topic().c_str()); - ESP_LOGCONFIG(TAG, " Position Command Topic: '%s'", this->get_position_command_topic().c_str()); + ESP_LOGCONFIG(TAG, + " Position State Topic: '%s'\n" + " Position Command Topic: '%s'", + this->get_position_state_topic().c_str(), this->get_position_command_topic().c_str()); } if (traits.get_supports_tilt()) { - ESP_LOGCONFIG(TAG, " Tilt State Topic: '%s'", this->get_tilt_state_topic().c_str()); - ESP_LOGCONFIG(TAG, " Tilt Command Topic: '%s'", this->get_tilt_command_topic().c_str()); + ESP_LOGCONFIG(TAG, + " Tilt State Topic: '%s'\n" + " Tilt Command Topic: '%s'", + this->get_tilt_state_topic().c_str(), this->get_tilt_command_topic().c_str()); } } void MQTTCoverComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { diff --git a/esphome/components/mqtt/mqtt_fan.cpp b/esphome/components/mqtt/mqtt_fan.cpp index 9e5ea54bee..35713bdab6 100644 --- a/esphome/components/mqtt/mqtt_fan.cpp +++ b/esphome/components/mqtt/mqtt_fan.cpp @@ -121,16 +121,22 @@ void MQTTFanComponent::dump_config() { ESP_LOGCONFIG(TAG, "MQTT Fan '%s': ", this->state_->get_name().c_str()); LOG_MQTT_COMPONENT(true, true); if (this->state_->get_traits().supports_direction()) { - ESP_LOGCONFIG(TAG, " Direction State Topic: '%s'", this->get_direction_state_topic().c_str()); - ESP_LOGCONFIG(TAG, " Direction Command Topic: '%s'", this->get_direction_command_topic().c_str()); + ESP_LOGCONFIG(TAG, + " Direction State Topic: '%s'\n" + " Direction Command Topic: '%s'", + this->get_direction_state_topic().c_str(), this->get_direction_command_topic().c_str()); } if (this->state_->get_traits().supports_oscillation()) { - ESP_LOGCONFIG(TAG, " Oscillation State Topic: '%s'", this->get_oscillation_state_topic().c_str()); - ESP_LOGCONFIG(TAG, " Oscillation Command Topic: '%s'", this->get_oscillation_command_topic().c_str()); + ESP_LOGCONFIG(TAG, + " Oscillation State Topic: '%s'\n" + " Oscillation Command Topic: '%s'", + this->get_oscillation_state_topic().c_str(), this->get_oscillation_command_topic().c_str()); } if (this->state_->get_traits().supports_speed()) { - ESP_LOGCONFIG(TAG, " Speed Level State Topic: '%s'", this->get_speed_level_state_topic().c_str()); - ESP_LOGCONFIG(TAG, " Speed Level Command Topic: '%s'", this->get_speed_level_command_topic().c_str()); + ESP_LOGCONFIG(TAG, + " Speed Level State Topic: '%s'\n" + " Speed Level Command Topic: '%s'", + this->get_speed_level_state_topic().c_str(), this->get_speed_level_command_topic().c_str()); } } diff --git a/esphome/components/mqtt/mqtt_valve.cpp b/esphome/components/mqtt/mqtt_valve.cpp index 07eeca08d6..85e06fe79c 100644 --- a/esphome/components/mqtt/mqtt_valve.cpp +++ b/esphome/components/mqtt/mqtt_valve.cpp @@ -42,8 +42,10 @@ void MQTTValveComponent::dump_config() { bool has_command_topic = traits.get_supports_position(); LOG_MQTT_COMPONENT(true, has_command_topic) if (traits.get_supports_position()) { - ESP_LOGCONFIG(TAG, " Position State Topic: '%s'", this->get_position_state_topic().c_str()); - ESP_LOGCONFIG(TAG, " Position Command Topic: '%s'", this->get_position_command_topic().c_str()); + ESP_LOGCONFIG(TAG, + " Position State Topic: '%s'\n" + " Position Command Topic: '%s'", + this->get_position_state_topic().c_str(), this->get_position_command_topic().c_str()); } } void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { diff --git a/esphome/components/msa3xx/msa3xx.cpp b/esphome/components/msa3xx/msa3xx.cpp index 75aa139e88..17f0a9c418 100644 --- a/esphome/components/msa3xx/msa3xx.cpp +++ b/esphome/components/msa3xx/msa3xx.cpp @@ -1,7 +1,7 @@ #include "msa3xx.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace msa3xx { @@ -161,13 +161,17 @@ void MSA3xxComponent::dump_config() { if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); } - ESP_LOGCONFIG(TAG, " Model: %s", model_to_string(this->model_)); - ESP_LOGCONFIG(TAG, " Power Mode: %s", power_mode_to_string(this->power_mode_)); - ESP_LOGCONFIG(TAG, " Bandwidth: %s", bandwidth_to_string(this->bandwidth_)); - ESP_LOGCONFIG(TAG, " Range: %s", range_to_string(this->range_)); - ESP_LOGCONFIG(TAG, " Resolution: %s", res_to_string(this->resolution_)); - ESP_LOGCONFIG(TAG, " Offsets: {%.3f m/s², %.3f m/s², %.3f m/s²}", this->offset_x_, this->offset_y_, this->offset_z_); - ESP_LOGCONFIG(TAG, " Transform: {mirror_x=%s, mirror_y=%s, mirror_z=%s, swap_xy=%s}", YESNO(this->swap_.x_polarity), + ESP_LOGCONFIG(TAG, + " Model: %s\n" + " Power Mode: %s\n" + " Bandwidth: %s\n" + " Range: %s\n" + " Resolution: %s\n" + " Offsets: {%.3f m/s², %.3f m/s², %.3f m/s²}\n" + " Transform: {mirror_x=%s, mirror_y=%s, mirror_z=%s, swap_xy=%s}", + model_to_string(this->model_), power_mode_to_string(this->power_mode_), + bandwidth_to_string(this->bandwidth_), range_to_string(this->range_), res_to_string(this->resolution_), + this->offset_x_, this->offset_y_, this->offset_z_, YESNO(this->swap_.x_polarity), YESNO(this->swap_.y_polarity), YESNO(this->swap_.z_polarity), YESNO(this->swap_.x_y_swap)); LOG_UPDATE_INTERVAL(this); @@ -248,10 +252,10 @@ void MSA3xxComponent::loop() { } void MSA3xxComponent::update() { - ESP_LOGV(TAG, "Updating MSA3xx..."); + ESP_LOGV(TAG, "Updating"); if (!this->is_ready()) { - ESP_LOGV(TAG, "Component MSA3xx not ready for update"); + ESP_LOGV(TAG, "Not ready for update"); return; } ESP_LOGV(TAG, "Acceleration: {x = %+1.3f m/s², y = %+1.3f m/s², z = %+1.3f m/s²}; ", this->data_.x, this->data_.y, diff --git a/esphome/components/my9231/my9231.cpp b/esphome/components/my9231/my9231.cpp index 5edaa83c38..691c945254 100644 --- a/esphome/components/my9231/my9231.cpp +++ b/esphome/components/my9231/my9231.cpp @@ -1,6 +1,6 @@ #include "my9231.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace my9231 { @@ -63,9 +63,11 @@ void MY9231OutputComponent::dump_config() { ESP_LOGCONFIG(TAG, "MY9231:"); LOG_PIN(" DI Pin: ", this->pin_di_); LOG_PIN(" DCKI Pin: ", this->pin_dcki_); - ESP_LOGCONFIG(TAG, " Total number of channels: %u", this->num_channels_); - ESP_LOGCONFIG(TAG, " Number of chips: %u", this->num_chips_); - ESP_LOGCONFIG(TAG, " Bit depth: %u", this->bit_depth_); + ESP_LOGCONFIG(TAG, + " Total number of channels: %u\n" + " Number of chips: %u\n" + " Bit depth: %u", + this->num_channels_, this->num_chips_, this->bit_depth_); } void MY9231OutputComponent::loop() { if (!this->update_) diff --git a/esphome/components/nau7802/nau7802.cpp b/esphome/components/nau7802/nau7802.cpp index fa4c4b64a1..edcd114852 100644 --- a/esphome/components/nau7802/nau7802.cpp +++ b/esphome/components/nau7802/nau7802.cpp @@ -131,8 +131,10 @@ void NAU7802Sensor::dump_config() { return; } // Note these may differ from the values on the device if calbration has been run - ESP_LOGCONFIG(TAG, " Offset Calibration: %s", to_string(this->offset_calibration_).c_str()); - ESP_LOGCONFIG(TAG, " Gain Calibration: %f", this->gain_calibration_); + ESP_LOGCONFIG(TAG, + " Offset Calibration: %s\n" + " Gain Calibration: %f", + to_string(this->offset_calibration_).c_str(), this->gain_calibration_); std::string voltage = "unknown"; switch (this->ldo_) { diff --git a/esphome/components/neopixelbus/neopixelbus_light.h b/esphome/components/neopixelbus/neopixelbus_light.h index 5233886075..d94a923614 100644 --- a/esphome/components/neopixelbus/neopixelbus_light.h +++ b/esphome/components/neopixelbus/neopixelbus_light.h @@ -2,10 +2,10 @@ #ifdef USE_ARDUINO -#include "esphome/core/macros.h" +#include "esphome/core/color.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" -#include "esphome/core/color.h" +#include "esphome/core/macros.h" #include "esphome/components/light/light_output.h" #include "esphome/components/light/addressable_light.h" diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index 1598daf6f9..d76da573b5 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -5,8 +5,8 @@ #include #include #include -#include "esphome/core/macros.h" #include "esphome/core/helpers.h" +#include "esphome/core/macros.h" #if defined(USE_ESP_IDF) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0) #include diff --git a/esphome/components/network/util.cpp b/esphome/components/network/util.cpp index ed519f738a..a8e792a2d7 100644 --- a/esphome/components/network/util.cpp +++ b/esphome/components/network/util.cpp @@ -9,6 +9,10 @@ #include "esphome/components/ethernet/ethernet_component.h" #endif +#ifdef USE_OPENTHREAD +#include "esphome/components/openthread/openthread.h" +#endif + namespace esphome { namespace network { @@ -23,6 +27,11 @@ bool is_connected() { return wifi::global_wifi_component->is_connected(); #endif +#ifdef USE_OPENTHREAD + if (openthread::global_openthread_component != nullptr) + return openthread::global_openthread_component->is_connected(); +#endif + #ifdef USE_HOST return true; // Assume its connected #endif @@ -45,6 +54,10 @@ network::IPAddresses get_ip_addresses() { #ifdef USE_WIFI if (wifi::global_wifi_component != nullptr) return wifi::global_wifi_component->get_ip_addresses(); +#endif +#ifdef USE_OPENTHREAD + if (openthread::global_openthread_component != nullptr) + return openthread::global_openthread_component->get_ip_addresses(); #endif return {}; } diff --git a/esphome/components/nextion/base_component.py b/esphome/components/nextion/base_component.py index 0058d957dc..98dea4b513 100644 --- a/esphome/components/nextion/base_component.py +++ b/esphome/components/nextion/base_component.py @@ -14,6 +14,8 @@ CONF_COMPONENT_NAME = "component_name" CONF_EXIT_REPARSE_ON_START = "exit_reparse_on_start" CONF_FONT_ID = "font_id" CONF_FOREGROUND_PRESSED_COLOR = "foreground_pressed_color" +CONF_MAX_COMMANDS_PER_LOOP = "max_commands_per_loop" +CONF_MAX_QUEUE_SIZE = "max_queue_size" CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow" CONF_ON_PAGE = "on_page" CONF_ON_SETUP = "on_setup" diff --git a/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp b/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp index 499cd901c0..ab1e20859c 100644 --- a/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +++ b/esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp @@ -16,7 +16,7 @@ void NextionBinarySensor::process_bool(const std::string &variable_name, bool st if (this->variable_name_ == variable_name) { this->publish_state(state); - ESP_LOGD(TAG, "Processed binarysensor \"%s\" state %s", variable_name.c_str(), state ? "ON" : "OFF"); + ESP_LOGD(TAG, "Binary sensor: %s=%s", variable_name.c_str(), ONOFF(state)); } } @@ -61,8 +61,7 @@ void NextionBinarySensor::set_state(bool state, bool publish, bool send_to_nexti this->update_component_settings(); - ESP_LOGN(TAG, "Wrote state for sensor \"%s\" state %s", this->variable_name_.c_str(), - ONOFF(this->variable_name_.c_str())); + ESP_LOGN(TAG, "Write: %s=%s", this->variable_name_.c_str(), ONOFF(this->state)); } } // namespace nextion diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py index 2e7c1c2825..7f63ca147b 100644 --- a/esphome/components/nextion/display.py +++ b/esphome/components/nextion/display.py @@ -16,10 +16,12 @@ from .base_component import ( CONF_AUTO_WAKE_ON_TOUCH, CONF_COMMAND_SPACING, CONF_EXIT_REPARSE_ON_START, + CONF_MAX_COMMANDS_PER_LOOP, + CONF_MAX_QUEUE_SIZE, CONF_ON_BUFFER_OVERFLOW, + CONF_ON_PAGE, CONF_ON_SETUP, CONF_ON_SLEEP, - CONF_ON_PAGE, CONF_ON_WAKE, CONF_SKIP_CONNECTION_HANDSHAKE, CONF_START_UP_PAGE, @@ -49,8 +51,27 @@ CONFIG_SCHEMA = ( display.BASIC_DISPLAY_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(Nextion), - cv.Optional(CONF_TFT_URL): cv.url, + cv.Optional(CONF_AUTO_WAKE_ON_TOUCH, default=True): cv.boolean, cv.Optional(CONF_BRIGHTNESS): cv.percentage, + cv.Optional(CONF_COMMAND_SPACING): cv.All( + cv.positive_time_period_milliseconds, + cv.Range(max=TimePeriod(milliseconds=255)), + ), + cv.Optional(CONF_EXIT_REPARSE_ON_START, default=False): cv.boolean, + cv.Optional(CONF_MAX_COMMANDS_PER_LOOP): cv.uint16_t, + cv.Optional(CONF_MAX_QUEUE_SIZE): cv.positive_int, + cv.Optional(CONF_ON_BUFFER_OVERFLOW): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + BufferOverflowTrigger + ), + } + ), + cv.Optional(CONF_ON_PAGE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PageTrigger), + } + ), cv.Optional(CONF_ON_SETUP): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SetupTrigger), @@ -61,38 +82,21 @@ CONFIG_SCHEMA = ( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SleepTrigger), } ), - cv.Optional(CONF_ON_WAKE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(WakeTrigger), - } - ), - cv.Optional(CONF_ON_PAGE): automation.validate_automation( - { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PageTrigger), - } - ), cv.Optional(CONF_ON_TOUCH): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TouchTrigger), } ), - cv.Optional(CONF_ON_BUFFER_OVERFLOW): automation.validate_automation( + cv.Optional(CONF_ON_WAKE): automation.validate_automation( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( - BufferOverflowTrigger - ), + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(WakeTrigger), } ), + cv.Optional(CONF_SKIP_CONNECTION_HANDSHAKE, default=False): cv.boolean, + cv.Optional(CONF_START_UP_PAGE): cv.uint8_t, + cv.Optional(CONF_TFT_URL): cv.url, cv.Optional(CONF_TOUCH_SLEEP_TIMEOUT): cv.int_range(min=3, max=65535), cv.Optional(CONF_WAKE_UP_PAGE): cv.uint8_t, - cv.Optional(CONF_START_UP_PAGE): cv.uint8_t, - cv.Optional(CONF_AUTO_WAKE_ON_TOUCH, default=True): cv.boolean, - cv.Optional(CONF_EXIT_REPARSE_ON_START, default=False): cv.boolean, - cv.Optional(CONF_SKIP_CONNECTION_HANDSHAKE, default=False): cv.boolean, - cv.Optional(CONF_COMMAND_SPACING): cv.All( - cv.positive_time_period_milliseconds, - cv.Range(max=TimePeriod(milliseconds=255)), - ), } ) .extend(cv.polling_component_schema("5s")) @@ -125,6 +129,10 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await uart.register_uart_device(var, config) + if max_queue_size := config.get(CONF_MAX_QUEUE_SIZE): + cg.add_define("USE_NEXTION_MAX_QUEUE_SIZE") + cg.add(var.set_max_queue_size(max_queue_size)) + if command_spacing := config.get(CONF_COMMAND_SPACING): cg.add_define("USE_NEXTION_COMMAND_SPACING") cg.add(var.set_command_spacing(command_spacing.total_milliseconds)) @@ -167,6 +175,10 @@ async def to_code(config): cg.add(var.set_skip_connection_handshake(config[CONF_SKIP_CONNECTION_HANDSHAKE])) + if max_commands_per_loop := config.get(CONF_MAX_COMMANDS_PER_LOOP): + cg.add_define("USE_NEXTION_MAX_COMMANDS_PER_LOOP") + cg.add(var.set_max_commands_per_loop(max_commands_per_loop)) + await display.register_display(var, config) for conf in config.get(CONF_ON_SETUP, []): diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 38e37300af..3de32bfde9 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -37,7 +37,7 @@ bool Nextion::send_command_(const std::string &command) { } #endif // USE_NEXTION_COMMAND_SPACING - ESP_LOGN(TAG, "send_command %s", command.c_str()); + ESP_LOGN(TAG, "cmd: %s", command.c_str()); this->write_str(command.c_str()); const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF}; @@ -57,7 +57,7 @@ bool Nextion::check_connect_() { // Check if the handshake should be skipped for the Nextion connection if (this->skip_connection_handshake_) { // Log the connection status without handshake - ESP_LOGW(TAG, "Nextion display set as connected without performing handshake"); + ESP_LOGW(TAG, "Connected (no handshake)"); // Set the connection status to true this->is_connected_ = true; // Return true indicating the connection is set @@ -88,27 +88,27 @@ bool Nextion::check_connect_() { this->recv_ret_string_(response, 0, false); if (!response.empty() && response[0] == 0x1A) { // Swallow invalid variable name responses that may be caused by the above commands - ESP_LOGD(TAG, "0x1A error ignored during setup"); + ESP_LOGD(TAG, "0x1A error ignored (setup)"); return false; } if (response.empty() || response.find("comok") == std::string::npos) { #ifdef NEXTION_PROTOCOL_LOG - ESP_LOGN(TAG, "Bad connect request %s", response.c_str()); + ESP_LOGN(TAG, "Bad connect: %s", response.c_str()); for (size_t i = 0; i < response.length(); i++) { - ESP_LOGN(TAG, "response %s %d %d %c", response.c_str(), i, response[i], response[i]); + ESP_LOGN(TAG, "resp: %s %d %d %c", response.c_str(), i, response[i], response[i]); } #endif - ESP_LOGW(TAG, "Nextion is not connected! "); + ESP_LOGW(TAG, "Not connected"); comok_sent_ = 0; return false; } this->ignore_is_setup_ = true; - ESP_LOGI(TAG, "Nextion is connected"); + ESP_LOGI(TAG, "Connected"); this->is_connected_ = true; - ESP_LOGN(TAG, "connect request %s", response.c_str()); + ESP_LOGN(TAG, "connect: %s", response.c_str()); size_t start; size_t end = 0; @@ -120,14 +120,14 @@ bool Nextion::check_connect_() { this->is_detected_ = (connect_info.size() == 7); if (this->is_detected_) { - ESP_LOGN(TAG, "Received connect_info %zu", connect_info.size()); + ESP_LOGN(TAG, "Connect info: %zu", connect_info.size()); this->device_model_ = connect_info[2]; this->firmware_version_ = connect_info[3]; this->serial_number_ = connect_info[5]; this->flash_size_ = connect_info[6]; } else { - ESP_LOGE(TAG, "Nextion returned bad connect value \"%s\"", response.c_str()); + ESP_LOGE(TAG, "Bad connect value: '%s'", response.c_str()); } this->ignore_is_setup_ = false; @@ -148,31 +148,43 @@ void Nextion::reset_(bool reset_nextion) { void Nextion::dump_config() { ESP_LOGCONFIG(TAG, "Nextion:"); if (this->skip_connection_handshake_) { - ESP_LOGCONFIG(TAG, " Skip handshake: %s", YESNO(this->skip_connection_handshake_)); + ESP_LOGCONFIG(TAG, " Skip handshake: %s", YESNO(this->skip_connection_handshake_)); } else { - ESP_LOGCONFIG(TAG, " Device Model: %s", this->device_model_.c_str()); - ESP_LOGCONFIG(TAG, " Firmware Version: %s", this->firmware_version_.c_str()); - ESP_LOGCONFIG(TAG, " Serial Number: %s", this->serial_number_.c_str()); - ESP_LOGCONFIG(TAG, " Flash Size: %s", this->flash_size_.c_str()); + ESP_LOGCONFIG(TAG, + " Device Model: %s\n" + " FW Version: %s\n" + " Serial Number: %s\n" + " Flash Size: %s", + this->device_model_.c_str(), this->firmware_version_.c_str(), this->serial_number_.c_str(), + this->flash_size_.c_str()); } - ESP_LOGCONFIG(TAG, " Wake On Touch: %s", YESNO(this->auto_wake_on_touch_)); - ESP_LOGCONFIG(TAG, " Exit reparse: %s", YESNO(this->exit_reparse_on_start_)); + ESP_LOGCONFIG(TAG, + " Wake On Touch: %s\n" + " Exit reparse: %s", + YESNO(this->auto_wake_on_touch_), YESNO(this->exit_reparse_on_start_)); +#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP + ESP_LOGCONFIG(TAG, " Max commands per loop: %u", this->max_commands_per_loop_); +#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP if (this->touch_sleep_timeout_ != 0) { - ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu32, this->touch_sleep_timeout_); + ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu32, this->touch_sleep_timeout_); } if (this->wake_up_page_ != -1) { - ESP_LOGCONFIG(TAG, " Wake Up Page: %" PRId16, this->wake_up_page_); + ESP_LOGCONFIG(TAG, " Wake Up Page: %d", this->wake_up_page_); } if (this->start_up_page_ != -1) { - ESP_LOGCONFIG(TAG, " Start Up Page: %" PRId16, this->start_up_page_); + ESP_LOGCONFIG(TAG, " Start Up Page: %d", this->start_up_page_); } #ifdef USE_NEXTION_COMMAND_SPACING - ESP_LOGCONFIG(TAG, " Command spacing: %" PRIu8 "ms", this->command_pacer_.get_spacing()); + ESP_LOGCONFIG(TAG, " Cmd spacing: %u ms", this->command_pacer_.get_spacing()); #endif // USE_NEXTION_COMMAND_SPACING + +#ifdef USE_NEXTION_MAX_QUEUE_SIZE + ESP_LOGCONFIG(TAG, " Max queue size: %zu", this->max_queue_size_); +#endif } float Nextion::get_setup_priority() const { return setup_priority::DATA; } @@ -248,7 +260,7 @@ bool Nextion::send_command_printf(const char *format, ...) { int ret = vsnprintf(buffer, sizeof(buffer), format, arg); va_end(arg); if (ret <= 0) { - ESP_LOGW(TAG, "Building command for format '%s' failed!", format); + ESP_LOGW(TAG, "Bad cmd format: '%s'", format); return false; } @@ -269,9 +281,9 @@ void Nextion::print_queue_members_() { break; if (i == nullptr) { - ESP_LOGN(TAG, "Nextion queue is null"); + ESP_LOGN(TAG, "Queue null"); } else { - ESP_LOGN(TAG, "Nextion queue type: %d:%s , name: %s", i->component->get_queue_type(), + ESP_LOGN(TAG, "Queue type: %d:%s, name: %s", i->component->get_queue_type(), i->component->get_queue_type_string().c_str(), i->component->get_variable_name().c_str()); } } @@ -312,7 +324,7 @@ void Nextion::loop() { this->started_ms_ = millis(); if (this->started_ms_ + this->startup_override_ms_ < millis()) { - ESP_LOGD(TAG, "Manually set nextion report ready"); + ESP_LOGD(TAG, "Manual ready set"); this->nextion_reports_is_setup_ = true; } } @@ -321,20 +333,20 @@ void Nextion::loop() { bool Nextion::remove_from_q_(bool report_empty) { if (this->nextion_queue_.empty()) { if (report_empty) { - ESP_LOGE(TAG, "Nextion queue is empty!"); + ESP_LOGE(TAG, "Queue empty"); } return false; } NextionQueue *nb = this->nextion_queue_.front(); if (!nb || !nb->component) { - ESP_LOGE(TAG, "Invalid queue entry!"); + ESP_LOGE(TAG, "Invalid queue"); this->nextion_queue_.pop_front(); return false; } NextionComponentBase *component = nb->component; - ESP_LOGN(TAG, "Removing %s from the queue", component->get_variable_name().c_str()); + ESP_LOGN(TAG, "Removed: %s", component->get_variable_name().c_str()); if (component->get_queue_type() == NextionQueueType::NO_RESULT) { if (component->get_variable_name() == "sleep_wake") { @@ -361,6 +373,10 @@ void Nextion::process_nextion_commands_() { return; } +#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP + size_t commands_processed = 0; +#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP + #ifdef USE_NEXTION_COMMAND_SPACING if (!this->command_pacer_.can_send()) { return; // Will try again in next loop iteration @@ -370,16 +386,22 @@ void Nextion::process_nextion_commands_() { size_t to_process_length = 0; std::string to_process; - ESP_LOGN(TAG, "this->command_data_ %s length %d", this->command_data_.c_str(), this->command_data_.length()); + ESP_LOGN(TAG, "command_data_ %s len %d", this->command_data_.c_str(), this->command_data_.length()); #ifdef NEXTION_PROTOCOL_LOG this->print_queue_members_(); #endif while ((to_process_length = this->command_data_.find(COMMAND_DELIMITER)) != std::string::npos) { - ESP_LOGN(TAG, "print_queue_members_ size %zu", this->nextion_queue_.size()); +#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP + if (++commands_processed > this->max_commands_per_loop_) { + ESP_LOGW(TAG, "Command processing limit exceeded"); + break; + } +#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP + ESP_LOGN(TAG, "queue size: %zu", this->nextion_queue_.size()); while (to_process_length + COMMAND_DELIMITER.length() < this->command_data_.length() && static_cast(this->command_data_[to_process_length + COMMAND_DELIMITER.length()]) == 0xFF) { ++to_process_length; - ESP_LOGN(TAG, "Add extra 0xFF to process"); + ESP_LOGN(TAG, "Add 0xFF"); } this->nextion_event_ = this->command_data_[0]; @@ -389,19 +411,19 @@ void Nextion::process_nextion_commands_() { switch (this->nextion_event_) { case 0x00: // instruction sent by user has failed - ESP_LOGW(TAG, "Nextion reported invalid instruction!"); + ESP_LOGW(TAG, "Invalid instruction"); this->remove_from_q_(); break; case 0x01: // instruction sent by user was successful - ESP_LOGVV(TAG, "instruction sent by user was successful"); + ESP_LOGVV(TAG, "Cmd OK"); ESP_LOGN(TAG, "this->nextion_queue_.empty() %s", this->nextion_queue_.empty() ? "True" : "False"); this->remove_from_q_(); if (!this->is_setup_) { if (this->nextion_queue_.empty()) { - ESP_LOGD(TAG, "Nextion is setup"); + ESP_LOGD(TAG, "Setup complete"); this->is_setup_ = true; this->setup_callback_.call(); } @@ -411,96 +433,91 @@ void Nextion::process_nextion_commands_() { #endif break; case 0x02: // invalid Component ID or name was used - ESP_LOGW(TAG, "Nextion reported component ID or name invalid!"); + ESP_LOGW(TAG, "Invalid component ID/name"); this->remove_from_q_(); break; case 0x03: // invalid Page ID or name was used - ESP_LOGW(TAG, "Nextion reported page ID invalid!"); + ESP_LOGW(TAG, "Invalid page ID"); this->remove_from_q_(); break; case 0x04: // invalid Picture ID was used - ESP_LOGW(TAG, "Nextion reported picture ID invalid!"); + ESP_LOGW(TAG, "Invalid picture ID"); this->remove_from_q_(); break; case 0x05: // invalid Font ID was used - ESP_LOGW(TAG, "Nextion reported font ID invalid!"); + ESP_LOGW(TAG, "Invalid font ID"); this->remove_from_q_(); break; case 0x06: // File operation fails - ESP_LOGW(TAG, "Nextion File operation fail!"); + ESP_LOGW(TAG, "File operation failed"); break; case 0x09: // Instructions with CRC validation fails their CRC check - ESP_LOGW(TAG, "Nextion Instructions with CRC validation fails their CRC check!"); + ESP_LOGW(TAG, "CRC validation failed"); break; case 0x11: // invalid Baud rate was used - ESP_LOGW(TAG, "Nextion reported baud rate invalid!"); + ESP_LOGW(TAG, "Invalid baud rate"); break; case 0x12: // invalid Waveform ID or Channel # was used if (this->waveform_queue_.empty()) { - ESP_LOGW(TAG, - "Nextion reported invalid Waveform ID or Channel # was used but no waveform sensor in queue found!"); + ESP_LOGW(TAG, "Waveform ID/ch used but no sensor queued"); } else { auto &nb = this->waveform_queue_.front(); NextionComponentBase *component = nb->component; - ESP_LOGW(TAG, "Nextion reported invalid Waveform ID %d or Channel # %d was used!", - component->get_component_id(), component->get_wave_channel_id()); + ESP_LOGW(TAG, "Invalid waveform ID %d/ch %d", component->get_component_id(), + component->get_wave_channel_id()); - ESP_LOGN(TAG, "Removing waveform from queue with component id %d and waveform id %d", - component->get_component_id(), component->get_wave_channel_id()); + ESP_LOGN(TAG, "Remove waveform ID %d/ch %d", component->get_component_id(), component->get_wave_channel_id()); delete nb; // NOLINT(cppcoreguidelines-owning-memory) this->waveform_queue_.pop_front(); } break; case 0x1A: // variable name invalid - ESP_LOGW(TAG, "Nextion reported variable name invalid!"); + ESP_LOGW(TAG, "Invalid variable name"); this->remove_from_q_(); break; case 0x1B: // variable operation invalid - ESP_LOGW(TAG, "Nextion reported variable operation invalid!"); + ESP_LOGW(TAG, "Invalid variable operation"); this->remove_from_q_(); break; case 0x1C: // failed to assign - ESP_LOGW(TAG, "Nextion reported failed to assign variable!"); + ESP_LOGW(TAG, "Variable assign failed"); this->remove_from_q_(); break; case 0x1D: // operate EEPROM failed - ESP_LOGW(TAG, "Nextion reported operating EEPROM failed!"); + ESP_LOGW(TAG, "EEPROM operation failed"); break; case 0x1E: // parameter quantity invalid - ESP_LOGW(TAG, "Nextion reported parameter quantity invalid!"); + ESP_LOGW(TAG, "Invalid parameter count"); this->remove_from_q_(); break; case 0x1F: // IO operation failed - ESP_LOGW(TAG, "Nextion reported component I/O operation invalid!"); + ESP_LOGW(TAG, "Invalid component I/O"); break; case 0x20: // undefined escape characters - ESP_LOGW(TAG, "Nextion reported undefined escape characters!"); + ESP_LOGW(TAG, "Undefined escape chars"); this->remove_from_q_(); break; case 0x23: // too long variable name - ESP_LOGW(TAG, "Nextion reported too long variable name!"); + ESP_LOGW(TAG, "Variable name too long"); this->remove_from_q_(); break; case 0x24: // Serial Buffer overflow occurs // Buffer will continue to receive the current instruction, all previous instructions are lost. - ESP_LOGE(TAG, "Nextion reported Serial Buffer overflow!"); + ESP_LOGE(TAG, "Serial buffer overflow"); this->buffer_overflow_callback_.call(); break; case 0x65: { // touch event return data if (to_process_length != 3) { - ESP_LOGW(TAG, "Touch event data is expecting 3, received %zu", to_process_length); + ESP_LOGW(TAG, "Incorrect touch len: %zu (need 3)", to_process_length); break; } uint8_t page_id = to_process[0]; uint8_t component_id = to_process[1]; uint8_t touch_event = to_process[2]; // 0 -> release, 1 -> press - ESP_LOGD(TAG, "Got touch event:"); - ESP_LOGD(TAG, " page_id: %u", page_id); - ESP_LOGD(TAG, " component_id: %u", component_id); - ESP_LOGD(TAG, " event type: %s", touch_event ? "PRESS" : "RELEASE"); + ESP_LOGD(TAG, "Touch %s: page %u comp %u", touch_event ? "PRESS" : "RELEASE", page_id, component_id); for (auto *touch : this->touch_) { touch->process_touch(page_id, component_id, touch_event != 0); } @@ -510,12 +527,12 @@ void Nextion::process_nextion_commands_() { case 0x66: { // Nextion initiated new page event return data. // Also is used for sendme command which we never explicitly initiate if (to_process_length != 1) { - ESP_LOGW(TAG, "New page event data is expecting 1, received %zu", to_process_length); + ESP_LOGW(TAG, "Page event: expect 1, got %zu", to_process_length); break; } uint8_t page_id = to_process[0]; - ESP_LOGD(TAG, "Got new page: %u", page_id); + ESP_LOGD(TAG, "New page: %u", page_id); this->page_callback_.call(page_id); break; } @@ -525,7 +542,7 @@ void Nextion::process_nextion_commands_() { case 0x68: { // touch coordinate data (sleep) if (to_process_length != 5) { - ESP_LOGW(TAG, "Touch coordinate data is expecting 5, received %zu", to_process_length); + ESP_LOGW(TAG, "Touch coordinate: expect 5, got %zu", to_process_length); ESP_LOGW(TAG, "%s", to_process.c_str()); break; } @@ -533,10 +550,7 @@ void Nextion::process_nextion_commands_() { uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1]; uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3]; uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press - ESP_LOGD(TAG, "Got touch event:"); - ESP_LOGD(TAG, " x: %u", x); - ESP_LOGD(TAG, " y: %u", y); - ESP_LOGD(TAG, " type: %s", touch_event ? "PRESS" : "RELEASE"); + ESP_LOGD(TAG, "Touch %s at %u,%u", touch_event ? "PRESS" : "RELEASE", x, y); break; } @@ -547,25 +561,23 @@ void Nextion::process_nextion_commands_() { case 0x70: // string variable data return { if (this->nextion_queue_.empty()) { - ESP_LOGW(TAG, "ERROR: Received string return but the queue is empty"); + ESP_LOGW(TAG, "String return but queue is empty"); break; } NextionQueue *nb = this->nextion_queue_.front(); if (!nb || !nb->component) { - ESP_LOGE(TAG, "Invalid queue entry!"); + ESP_LOGE(TAG, "Invalid queue entry"); this->nextion_queue_.pop_front(); return; } NextionComponentBase *component = nb->component; if (component->get_queue_type() != NextionQueueType::TEXT_SENSOR) { - ESP_LOGE(TAG, "ERROR: Received string return but next in queue \"%s\" is not a text sensor", - component->get_variable_name().c_str()); + ESP_LOGE(TAG, "String return but '%s' not text sensor", component->get_variable_name().c_str()); } else { - ESP_LOGN(TAG, "Received get_string response: \"%s\" for component id: %s, type: %s", to_process.c_str(), - component->get_variable_name().c_str(), component->get_queue_type_string().c_str()); - component->set_state_from_string(to_process, true, false); + ESP_LOGN(TAG, "String resp: '%s' id: %s type: %s", to_process.c_str(), component->get_variable_name().c_str(), + component->get_queue_type_string().c_str()); } delete nb; // NOLINT(cppcoreguidelines-owning-memory) @@ -581,12 +593,12 @@ void Nextion::process_nextion_commands_() { case 0x71: // numeric variable data return { if (this->nextion_queue_.empty()) { - ESP_LOGE(TAG, "ERROR: Received numeric return but the queue is empty"); + ESP_LOGE(TAG, "Numeric return but queue empty"); break; } if (to_process_length == 0) { - ESP_LOGE(TAG, "ERROR: Received numeric return but no data!"); + ESP_LOGE(TAG, "Numeric return but no data"); break; } @@ -598,7 +610,7 @@ void Nextion::process_nextion_commands_() { NextionQueue *nb = this->nextion_queue_.front(); if (!nb || !nb->component) { - ESP_LOGE(TAG, "Invalid queue entry!"); + ESP_LOGE(TAG, "Invalid queue"); this->nextion_queue_.pop_front(); return; } @@ -607,12 +619,11 @@ void Nextion::process_nextion_commands_() { if (component->get_queue_type() != NextionQueueType::SENSOR && component->get_queue_type() != NextionQueueType::BINARY_SENSOR && component->get_queue_type() != NextionQueueType::SWITCH) { - ESP_LOGE(TAG, "ERROR: Received numeric return but next in queue \"%s\" is not a valid sensor type %d", - component->get_variable_name().c_str(), component->get_queue_type()); + ESP_LOGE(TAG, "Numeric return but '%s' invalid type %d", component->get_variable_name().c_str(), + component->get_queue_type()); } else { - ESP_LOGN(TAG, "Received numeric return for variable %s, queue type %d:%s, value %d", - component->get_variable_name().c_str(), component->get_queue_type(), - component->get_queue_type_string().c_str(), value); + ESP_LOGN(TAG, "Numeric: %s type %d:%s val %d", component->get_variable_name().c_str(), + component->get_queue_type(), component->get_queue_type_string().c_str(), value); component->set_state_from_int(value, true, false); } @@ -623,14 +634,14 @@ void Nextion::process_nextion_commands_() { } case 0x86: { // device automatically enters into sleep mode - ESP_LOGVV(TAG, "Received Nextion entering sleep automatically"); + ESP_LOGVV(TAG, "Auto sleep"); this->is_sleeping_ = true; this->sleep_callback_.call(); break; } case 0x87: // device automatically wakes up { - ESP_LOGVV(TAG, "Received Nextion leaves sleep automatically"); + ESP_LOGVV(TAG, "Auto wake"); this->is_sleeping_ = false; this->wake_callback_.call(); this->all_components_send_state_(false); @@ -638,7 +649,7 @@ void Nextion::process_nextion_commands_() { } case 0x88: // system successful start up { - ESP_LOGD(TAG, "system successful start up %zu", to_process_length); + ESP_LOGD(TAG, "System start: %zu", to_process_length); this->nextion_reports_is_setup_ = true; break; } @@ -657,17 +668,15 @@ void Nextion::process_nextion_commands_() { // Get variable name auto index = to_process.find('\0'); if (index == std::string::npos || (to_process_length - index - 1) < 1) { - ESP_LOGE(TAG, "Bad switch component data received for 0x90 event!"); - ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index); + ESP_LOGE(TAG, "Bad switch data (0x90)"); + ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index); break; } variable_name = to_process.substr(0, index); ++index; - ESP_LOGN(TAG, "Got Switch:"); - ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str()); - ESP_LOGN(TAG, " value: %d", to_process[0] != 0); + ESP_LOGN(TAG, "Switch %s: %s", ONOFF(to_process[index] != 0), variable_name.c_str()); for (auto *switchtype : this->switchtype_) { switchtype->process_bool(variable_name, to_process[index] != 0); @@ -685,8 +694,8 @@ void Nextion::process_nextion_commands_() { auto index = to_process.find('\0'); if (index == std::string::npos || (to_process_length - index - 1) != 4) { - ESP_LOGE(TAG, "Bad sensor component data received for 0x91 event!"); - ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index); + ESP_LOGE(TAG, "Bad sensor data (0x91)"); + ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index); break; } @@ -698,9 +707,7 @@ void Nextion::process_nextion_commands_() { value += to_process[i + index + 1] << (8 * i); } - ESP_LOGN(TAG, "Got sensor:"); - ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str()); - ESP_LOGN(TAG, " value: %d", value); + ESP_LOGN(TAG, "Sensor: %s=%d", variable_name.c_str(), value); for (auto *sensor : this->sensortype_) { sensor->process_sensor(variable_name, value); @@ -722,8 +729,8 @@ void Nextion::process_nextion_commands_() { // Get variable name auto index = to_process.find('\0'); if (index == std::string::npos || (to_process_length - index - 1) < 1) { - ESP_LOGE(TAG, "Bad text sensor component data received for 0x92 event!"); - ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index); + ESP_LOGE(TAG, "Bad text data (0x92)"); + ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index); break; } @@ -732,9 +739,7 @@ void Nextion::process_nextion_commands_() { text_value = to_process.substr(index); - ESP_LOGN(TAG, "Got Text Sensor:"); - ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str()); - ESP_LOGN(TAG, " value: %s", text_value.c_str()); + ESP_LOGN(TAG, "Text sensor: %s='%s'", variable_name.c_str(), text_value.c_str()); // NextionTextSensorResponseQueue *nq = new NextionTextSensorResponseQueue; // nq->variable_name = variable_name; @@ -757,17 +762,15 @@ void Nextion::process_nextion_commands_() { // Get variable name auto index = to_process.find('\0'); if (index == std::string::npos || (to_process_length - index - 1) < 1) { - ESP_LOGE(TAG, "Bad binary sensor component data received for 0x92 event!"); - ESP_LOGN(TAG, "to_process %s %zu %d", to_process.c_str(), to_process_length, index); + ESP_LOGE(TAG, "Bad binary data (0x92)"); + ESP_LOGN(TAG, "proc: %s %zu %d", to_process.c_str(), to_process_length, index); break; } variable_name = to_process.substr(0, index); ++index; - ESP_LOGN(TAG, "Got Binary Sensor:"); - ESP_LOGN(TAG, " variable_name: %s", variable_name.c_str()); - ESP_LOGN(TAG, " value: %d", to_process[index] != 0); + ESP_LOGN(TAG, "Binary sensor: %s=%s", variable_name.c_str(), ONOFF(to_process[index] != 0)); for (auto *binarysensortype : this->binarysensortype_) { binarysensortype->process_bool(&variable_name[0], to_process[index] != 0); @@ -775,14 +778,14 @@ void Nextion::process_nextion_commands_() { break; } case 0xFD: { // data transparent transmit finished - ESP_LOGVV(TAG, "Nextion reported data transmit finished!"); + ESP_LOGVV(TAG, "Data transmit done"); this->check_pending_waveform_(); break; } case 0xFE: { // data transparent transmit ready - ESP_LOGVV(TAG, "Nextion reported ready for transmit!"); + ESP_LOGVV(TAG, "Ready for transmit"); if (this->waveform_queue_.empty()) { - ESP_LOGE(TAG, "No waveforms in queue to send data!"); + ESP_LOGE(TAG, "No waveforms queued"); break; } @@ -793,8 +796,8 @@ void Nextion::process_nextion_commands_() { this->write_array(component->get_wave_buffer().data(), static_cast(buffer_to_send)); - ESP_LOGN(TAG, "Nextion sending waveform data for component id %d and waveform id %d, size %zu", - component->get_component_id(), component->get_wave_channel_id(), buffer_to_send); + ESP_LOGN(TAG, "Send waveform: component id %d, waveform id %d, size %zu", component->get_component_id(), + component->get_wave_channel_id(), buffer_to_send); component->clear_wave_buffer(buffer_to_send); delete nb; // NOLINT(cppcoreguidelines-owning-memory) @@ -802,14 +805,12 @@ void Nextion::process_nextion_commands_() { break; } default: - ESP_LOGW(TAG, "Received unknown event from nextion: 0x%02X", this->nextion_event_); + ESP_LOGW(TAG, "Unknown event: 0x%02X", this->nextion_event_); break; } // ESP_LOGN(TAG, "nextion_event_ deleting from 0 to %d", to_process_length + COMMAND_DELIMITER.length() + 1); this->command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1); - // App.feed_wdt(); Remove before master merge - this->process_serial_(); } uint32_t ms = millis(); @@ -819,15 +820,15 @@ void Nextion::process_nextion_commands_() { NextionComponentBase *component = this->nextion_queue_[i]->component; if (this->nextion_queue_[i]->queue_time + this->max_q_age_ms_ < ms) { if (this->nextion_queue_[i]->queue_time == 0) { - ESP_LOGD(TAG, "Removing old queue type \"%s\" name \"%s\" queue_time 0", - component->get_queue_type_string().c_str(), component->get_variable_name().c_str()); + ESP_LOGD(TAG, "Remove old queue '%s':'%s' (t=0)", component->get_queue_type_string().c_str(), + component->get_variable_name().c_str()); } if (component->get_variable_name() == "sleep_wake") { this->is_sleeping_ = false; } - ESP_LOGD(TAG, "Removing old queue type \"%s\" name \"%s\"", component->get_queue_type_string().c_str(), + ESP_LOGD(TAG, "Remove old queue '%s':'%s'", component->get_queue_type_string().c_str(), component->get_variable_name().c_str()); if (component->get_queue_type() == NextionQueueType::NO_RESULT) { @@ -847,20 +848,17 @@ void Nextion::process_nextion_commands_() { } } } - ESP_LOGN(TAG, "Loop End"); + ESP_LOGN(TAG, "Loop end"); // App.feed_wdt(); Remove before master merge this->process_serial_(); -} // namespace nextion +} // Nextion::process_nextion_commands_() void Nextion::set_nextion_sensor_state(int queue_type, const std::string &name, float state) { this->set_nextion_sensor_state(static_cast(queue_type), name, state); } void Nextion::set_nextion_sensor_state(NextionQueueType queue_type, const std::string &name, float state) { - ESP_LOGN(TAG, "Received state:"); - ESP_LOGN(TAG, " variable: %s", name.c_str()); - ESP_LOGN(TAG, " state: %lf", state); - ESP_LOGN(TAG, " queue type: %d", queue_type); + ESP_LOGN(TAG, "State: %s=%lf (type %d)", name.c_str(), state, queue_type); switch (queue_type) { case NextionQueueType::SENSOR: { @@ -891,15 +889,13 @@ void Nextion::set_nextion_sensor_state(NextionQueueType queue_type, const std::s break; } default: { - ESP_LOGW(TAG, "set_nextion_sensor_state does not support a queue type %d", queue_type); + ESP_LOGW(TAG, "set_sensor_state: bad type %d", queue_type); } } } void Nextion::set_nextion_text_state(const std::string &name, const std::string &state) { - ESP_LOGD(TAG, "Received state:"); - ESP_LOGD(TAG, " variable: %s", name.c_str()); - ESP_LOGD(TAG, " state: %s", state.c_str()); + ESP_LOGD(TAG, "State: %s='%s'", name.c_str(), state.c_str()); for (auto *sensor : this->textsensortype_) { if (name == sensor->get_variable_name()) { @@ -910,7 +906,7 @@ void Nextion::set_nextion_text_state(const std::string &name, const std::string } void Nextion::all_components_send_state_(bool force_update) { - ESP_LOGD(TAG, "all_components_send_state_ "); + ESP_LOGD(TAG, "Send states"); for (auto *binarysensortype : this->binarysensortype_) { if (force_update || binarysensortype->get_needs_to_send_update()) binarysensortype->send_state_to_nextion(); @@ -998,13 +994,30 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool } /** - * @brief + * @brief Add a command to the Nextion queue that expects no response. * - * @param variable_name Name for the queue + * This is typically used for write-only operations such as variable assignments or component updates + * where no return value or acknowledgment is expected from the display. + * + * If the `max_queue_size` limit is configured and reached, the command will be skipped. + * + * @param variable_name Name of the variable or component associated with the command. */ void Nextion::add_no_result_to_queue_(const std::string &variable_name) { - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - nextion::NextionQueue *nextion_queue = new nextion::NextionQueue; +#ifdef USE_NEXTION_MAX_QUEUE_SIZE + if (this->max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) { + ESP_LOGW(TAG, "Queue full (%zu), drop: %s", this->nextion_queue_.size(), variable_name.c_str()); + return; + } +#endif + + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + nextion::NextionQueue *nextion_queue = allocator.allocate(1); + if (nextion_queue == nullptr) { + ESP_LOGW(TAG, "Queue alloc failed"); + return; + } + new (nextion_queue) nextion::NextionQueue(); // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) nextion_queue->component = new nextion::NextionComponentBase; @@ -1014,7 +1027,7 @@ void Nextion::add_no_result_to_queue_(const std::string &variable_name) { this->nextion_queue_.push_back(nextion_queue); - ESP_LOGN(TAG, "Add to queue type: NORESULT component %s", nextion_queue->component->get_variable_name().c_str()); + ESP_LOGN(TAG, "Queue NORESULT: %s", nextion_queue->component->get_variable_name().c_str()); } /** @@ -1043,7 +1056,7 @@ bool Nextion::add_no_result_to_queue_with_ignore_sleep_printf_(const std::string int ret = vsnprintf(buffer, sizeof(buffer), format, arg); va_end(arg); if (ret <= 0) { - ESP_LOGW(TAG, "Building command for format '%s' failed!", format); + ESP_LOGW(TAG, "Bad cmd format: '%s'", format); return false; } @@ -1068,7 +1081,7 @@ bool Nextion::add_no_result_to_queue_with_printf_(const std::string &variable_na int ret = vsnprintf(buffer, sizeof(buffer), format, arg); va_end(arg); if (ret <= 0) { - ESP_LOGW(TAG, "Building command for format '%s' failed!", format); + ESP_LOGW(TAG, "Bad cmd format: '%s'", format); return false; } @@ -1133,18 +1146,39 @@ void Nextion::add_no_result_to_queue_with_set_internal_(const std::string &varia state_value.c_str()); } +/** + * @brief Queue a GET command for a component that expects a response from the Nextion display. + * + * This method is used for querying values such as sensor states, text content, or switch status. + * The component will be added to the Nextion queue only if the display is already set up, + * the queue has not reached the configured maximum size (if set), and the command is sent successfully. + * + * @param component Pointer to the Nextion component that will handle the response. + */ void Nextion::add_to_get_queue(NextionComponentBase *component) { if ((!this->is_setup() && !this->ignore_is_setup_)) return; - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - nextion::NextionQueue *nextion_queue = new nextion::NextionQueue; +#ifdef USE_NEXTION_MAX_QUEUE_SIZE + if (this->max_queue_size_ > 0 && this->nextion_queue_.size() >= this->max_queue_size_) { + ESP_LOGW(TAG, "Queue full (%zu), drop GET: %s", this->nextion_queue_.size(), + component->get_variable_name().c_str()); + return; + } +#endif + + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + nextion::NextionQueue *nextion_queue = allocator.allocate(1); + if (nextion_queue == nullptr) { + ESP_LOGW(TAG, "Queue alloc failed"); + return; + } + new (nextion_queue) nextion::NextionQueue(); nextion_queue->component = component; nextion_queue->queue_time = millis(); - ESP_LOGN(TAG, "Add to queue type: %s component %s", component->get_queue_type_string().c_str(), - component->get_variable_name().c_str()); + ESP_LOGN(TAG, "Queue %s: %s", component->get_queue_type_string().c_str(), component->get_variable_name().c_str()); std::string command = "get " + component->get_variable_name_to_send(); @@ -1165,8 +1199,13 @@ void Nextion::add_addt_command_to_queue(NextionComponentBase *component) { if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping()) return; - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - nextion::NextionQueue *nextion_queue = new nextion::NextionQueue; + ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + nextion::NextionQueue *nextion_queue = allocator.allocate(1); + if (nextion_queue == nullptr) { + ESP_LOGW(TAG, "Queue alloc failed"); + return; + } + new (nextion_queue) nextion::NextionQueue(); nextion_queue->component = component; nextion_queue->queue_time = millis(); @@ -1195,8 +1234,8 @@ void Nextion::check_pending_waveform_() { void Nextion::set_writer(const nextion_writer_t &writer) { this->writer_ = writer; } -ESPDEPRECATED("set_wait_for_ack(bool) is deprecated and has no effect", "v1.20") -void Nextion::set_wait_for_ack(bool wait_for_ack) { ESP_LOGE(TAG, "This command is deprecated"); } +ESPDEPRECATED("set_wait_for_ack(bool) deprecated, no effect", "v1.20") +void Nextion::set_wait_for_ack(bool wait_for_ack) { ESP_LOGE(TAG, "Deprecated"); } bool Nextion::is_updating() { return this->is_updating_; } diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 4bc5305923..036fbe6c6d 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -75,6 +75,36 @@ class NextionCommandPacer { class Nextion : public NextionBase, public PollingComponent, public uart::UARTDevice { public: +#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP + /** + * @brief Set the maximum number of commands to process in each loop iteration + * @param value Maximum number of commands (default: 20) + * + * Limiting the number of commands per loop helps prevent stack overflows + * when a large number of commands are queued at once, especially during boot. + */ + inline void set_max_commands_per_loop(uint16_t value) { this->max_commands_per_loop_ = value; } + + /** + * @brief Get the current maximum number of commands allowed per loop iteration + * @return Configured command limit per loop + */ + inline uint16_t get_max_commands_per_loop() const { return this->max_commands_per_loop_; } +#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP +#ifdef USE_NEXTION_MAX_QUEUE_SIZE + /** + * @brief Set the maximum allowed queue size + * @param size Max number of entries allowed in nextion_queue_ + */ + inline void set_max_queue_size(size_t size) { this->max_queue_size_ = size; } + + /** + * @brief Get the maximum allowed queue size + * @return Current limit (0 = unlimited) + */ + inline size_t get_max_queue_size() const { return this->max_queue_size_; } +#endif // USE_NEXTION_MAX_QUEUE_SIZE + #ifdef USE_NEXTION_COMMAND_SPACING /** * @brief Set the command spacing for the display @@ -1273,6 +1303,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe bool is_connected() { return this->is_connected_; } protected: +#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP + uint16_t max_commands_per_loop_{1000}; +#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP +#ifdef USE_NEXTION_MAX_QUEUE_SIZE + size_t max_queue_size_{0}; +#endif // USE_NEXTION_MAX_QUEUE_SIZE #ifdef USE_NEXTION_COMMAND_SPACING NextionCommandPacer command_pacer_{0}; #endif // USE_NEXTION_COMMAND_SPACING diff --git a/esphome/components/nextion/nextion_commands.cpp b/esphome/components/nextion/nextion_commands.cpp index e3172c8c1b..0226e0a13c 100644 --- a/esphome/components/nextion/nextion_commands.cpp +++ b/esphome/components/nextion/nextion_commands.cpp @@ -17,7 +17,7 @@ void Nextion::set_wake_up_page(uint8_t wake_up_page) { void Nextion::set_touch_sleep_timeout(uint32_t touch_sleep_timeout) { if (touch_sleep_timeout < 3) { - ESP_LOGD(TAG, "Sleep timeout out of bounds, range 3-65535"); + ESP_LOGD(TAG, "Sleep timeout out of bounds (3-65535)"); return; } @@ -37,7 +37,7 @@ void Nextion::sleep(bool sleep) { // Protocol reparse mode bool Nextion::set_protocol_reparse_mode(bool active_mode) { - ESP_LOGV(TAG, "Set Nextion protocol reparse mode: %s", YESNO(active_mode)); + ESP_LOGV(TAG, "Reparse mode: %s", YESNO(active_mode)); this->ignore_is_setup_ = true; // if not in reparse mode setup will fail, so it should be ignored bool all_commands_sent = true; if (active_mode) { // Sets active protocol reparse mode @@ -184,7 +184,7 @@ void Nextion::goto_page(uint8_t page) { this->add_no_result_to_queue_with_printf void Nextion::set_backlight_brightness(float brightness) { if (brightness < 0 || brightness > 1.0) { - ESP_LOGD(TAG, "Brightness out of bounds, percentage range 0-1.0"); + ESP_LOGD(TAG, "Brightness out of bounds (0-1.0)"); return; } this->add_no_result_to_queue_with_printf_("backlight_brightness", "dim=%d", static_cast(brightness * 100)); diff --git a/esphome/components/nextion/nextion_upload_arduino.cpp b/esphome/components/nextion/nextion_upload_arduino.cpp index 1187c77c8e..fcd665917c 100644 --- a/esphome/components/nextion/nextion_upload_arduino.cpp +++ b/esphome/components/nextion/nextion_upload_arduino.cpp @@ -31,7 +31,7 @@ inline uint32_t Nextion::get_free_heap_() { int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { uint32_t range_size = this->tft_size_ - range_start; - ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGV(TAG, "Heap: %" PRIu32, this->get_free_heap_()); uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1; ESP_LOGD(TAG, "Range start: %" PRIu32, range_start); if (range_size <= 0 or range_end <= range_start) { @@ -43,11 +43,11 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { char range_header[32]; sprintf(range_header, "bytes=%" PRIu32 "-%" PRIu32, range_start, range_end); - ESP_LOGV(TAG, "Requesting range: %s", range_header); + ESP_LOGV(TAG, "Range: %s", range_header); http_client.addHeader("Range", range_header); int code = http_client.GET(); if (code != HTTP_CODE_OK and code != HTTP_CODE_PARTIAL_CONTENT) { - ESP_LOGW(TAG, "HTTP Request failed; Error: %s", HTTPClient::errorToString(code).c_str()); + ESP_LOGW(TAG, "HTTP failed: %s", HTTPClient::errorToString(code).c_str()); return -1; } @@ -55,7 +55,7 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); uint8_t *buffer = allocator.allocate(4096); if (!buffer) { - ESP_LOGE(TAG, "Failed to allocate upload buffer"); + ESP_LOGE(TAG, "Buffer alloc failed"); return -1; } @@ -64,7 +64,7 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { App.feed_wdt(); const uint16_t buffer_size = this->content_length_ < 4096 ? this->content_length_ : 4096; // Limits buffer to the remaining data - ESP_LOGV(TAG, "Fetching %" PRIu16 " bytes from HTTP", buffer_size); + ESP_LOGV(TAG, "Fetch %" PRIu16 " bytes", buffer_size); uint16_t read_len = 0; int partial_read_len = 0; const uint32_t start_time = millis(); @@ -81,14 +81,13 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { } if (read_len != buffer_size) { // Did not receive the full package within the timeout period - ESP_LOGE(TAG, "Failed to read full package, received only %" PRIu16 " of %" PRIu16 " bytes", read_len, - buffer_size); + ESP_LOGE(TAG, "Read failed: %" PRIu16 "/%" PRIu16 " bytes", read_len, buffer_size); // Deallocate buffer allocator.deallocate(buffer, 4096); buffer = nullptr; return -1; } - ESP_LOGV(TAG, "%d bytes fetched, writing it to UART", read_len); + ESP_LOGV(TAG, "Fetched %d bytes", read_len); if (read_len > 0) { recv_string.clear(); this->write_array(buffer, buffer_size); @@ -97,25 +96,23 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { this->content_length_ -= read_len; const float upload_percentage = 100.0f * (this->tft_size_ - this->content_length_) / this->tft_size_; #if defined(USE_ESP32) && defined(USE_PSRAM) - ESP_LOGD( - TAG, - "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " (DRAM) + %" PRIu32 " (PSRAM) bytes", - upload_percentage, this->content_length_, static_cast(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)), - static_cast(heap_caps_get_free_size(MALLOC_CAP_SPIRAM))); + ESP_LOGD(TAG, "Upload: %0.2f%% (%" PRIu32 " left, heap: %" PRIu32 "+%" PRIu32 ")", upload_percentage, + this->content_length_, static_cast(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)), + static_cast(heap_caps_get_free_size(MALLOC_CAP_SPIRAM))); #else - ESP_LOGD(TAG, "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " bytes", upload_percentage, - this->content_length_, this->get_free_heap_()); + ESP_LOGD(TAG, "Upload: %0.2f%% (%" PRIu32 " left, heap: %" PRIu32 ")", upload_percentage, this->content_length_, + this->get_free_heap_()); #endif upload_first_chunk_sent_ = true; if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request - ESP_LOGD(TAG, "recv_string [%s]", + ESP_LOGD(TAG, "Recv: [%s]", format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); uint32_t result = 0; for (int j = 0; j < 4; ++j) { result += static_cast(recv_string[j + 1]) << (8 * j); } if (result > 0) { - ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result); + ESP_LOGI(TAG, "New range: %" PRIu32, result); this->content_length_ = this->tft_size_ - result; range_start = result; } else { @@ -126,7 +123,7 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { buffer = nullptr; return range_end + 1; } else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok" - ESP_LOGE(TAG, "Invalid response from Nextion: [%s]", + ESP_LOGE(TAG, "Invalid response: [%s]", format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); // Deallocate buffer allocator.deallocate(buffer, 4096); @@ -136,10 +133,10 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { recv_string.clear(); } else if (read_len == 0) { - ESP_LOGV(TAG, "End of HTTP response reached"); + ESP_LOGV(TAG, "HTTP end"); break; // Exit the loop if there is no more data to read } else { - ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %d", read_len); + ESP_LOGE(TAG, "HTTP read failed: %d", read_len); break; // Exit the loop on error } } @@ -151,26 +148,26 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) { } bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { - ESP_LOGD(TAG, "Nextion TFT upload requested"); + ESP_LOGD(TAG, "TFT upload requested"); ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); if (this->is_updating_) { - ESP_LOGW(TAG, "Currently uploading"); + ESP_LOGW(TAG, "Upload in progress"); return false; } if (!network::is_connected()) { - ESP_LOGE(TAG, "Network is not connected"); + ESP_LOGE(TAG, "No network"); return false; } this->is_updating_ = true; if (exit_reparse) { - ESP_LOGD(TAG, "Exiting Nextion reparse mode"); + ESP_LOGD(TAG, "Exit reparse mode"); if (!this->set_protocol_reparse_mode(false)) { - ESP_LOGW(TAG, "Failed to request Nextion to exit reparse mode"); + ESP_LOGW(TAG, "Exit reparse failed"); return false; } } @@ -185,8 +182,8 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate); // Define the configuration for the HTTP client - ESP_LOGV(TAG, "Initializing HTTP client"); - ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGV(TAG, "Init HTTP client"); + ESP_LOGV(TAG, "Heap: %" PRIu32, this->get_free_heap_()); HTTPClient http_client; http_client.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along @@ -215,7 +212,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { http_client.addHeader("Range", "bytes=0-255"); const char *header_names[] = {"Content-Range"}; http_client.collectHeaders(header_names, 1); - ESP_LOGD(TAG, "Requesting URL: %s", this->tft_url_.c_str()); + ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); http_client.setReuse(true); // try up to 5 times. DNS sometimes needs a second try or so int tries = 1; @@ -224,7 +221,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { App.feed_wdt(); while (code != 200 && code != 206 && tries <= 5) { - ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s, retrying (%d/5)", this->tft_url_.c_str(), + ESP_LOGW(TAG, "HTTP fail: URL: %s; Error: %s, retry %d/5", this->tft_url_.c_str(), HTTPClient::errorToString(code).c_str(), tries); delay(250); // NOLINT @@ -241,27 +238,27 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { content_range_string.remove(0, 12); this->tft_size_ = content_range_string.toInt(); - ESP_LOGD(TAG, "TFT file size: %zu bytes", this->tft_size_); + ESP_LOGD(TAG, "TFT size: %zu bytes", this->tft_size_); if (this->tft_size_ < 4096) { - ESP_LOGE(TAG, "File size check failed."); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGE(TAG, "Size check failed"); + ESP_LOGD(TAG, "Close HTTP"); http_client.end(); ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } else { - ESP_LOGV(TAG, "File size check passed. Proceeding..."); + ESP_LOGV(TAG, "Size check OK"); } this->content_length_ = this->tft_size_; - ESP_LOGD(TAG, "Uploading Nextion"); + ESP_LOGD(TAG, "Uploading"); // The Nextion will ignore the upload command if it is sleeping - ESP_LOGV(TAG, "Wake-up Nextion"); + ESP_LOGV(TAG, "Wake-up"); this->ignore_is_setup_ = true; this->send_command_("sleep=0"); this->send_command_("dim=100"); delay(250); // NOLINT - ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGV(TAG, "Heap: %" PRIu32, this->get_free_heap_()); App.feed_wdt(); char command[128]; @@ -271,16 +268,16 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { sprintf(command, "whmi-wris %d,%d,1", this->content_length_, baud_rate); // Clear serial receive buffer - ESP_LOGV(TAG, "Clear serial receive buffer"); + ESP_LOGV(TAG, "Clear RX buffer"); this->reset_(false); delay(250); // NOLINT - ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGV(TAG, "Heap: %" PRIu32, this->get_free_heap_()); - ESP_LOGV(TAG, "Send upload instruction: %s", command); + ESP_LOGV(TAG, "Upload cmd: %s", command); this->send_command_(command); if (baud_rate != this->original_baud_rate_) { - ESP_LOGD(TAG, "Changing baud rate from %" PRIu32 " to %" PRIu32 " bps", this->original_baud_rate_, baud_rate); + ESP_LOGD(TAG, "Baud: %" PRIu32 "->%" PRIu32, this->original_baud_rate_, baud_rate); this->parent_->set_baud_rate(baud_rate); this->parent_->load_settings(); } @@ -288,74 +285,74 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { App.feed_wdt(); std::string response; - ESP_LOGV(TAG, "Waiting for upgrade response"); + ESP_LOGV(TAG, "Wait upload resp"); this->recv_ret_string_(response, 5000, true); // This can take some time to return // The Nextion display will, if it's ready to accept data, send a 0x05 byte. - ESP_LOGD(TAG, "Upgrade response is [%s] - %zu byte(s)", + ESP_LOGD(TAG, "Upload resp: [%s] %zu B", format_hex_pretty(reinterpret_cast(response.data()), response.size()).c_str(), response.length()); - ESP_LOGV(TAG, "Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGV(TAG, "Heap: %" PRIu32, this->get_free_heap_()); if (response.find(0x05) != std::string::npos) { - ESP_LOGV(TAG, "Preparation for TFT upload done"); + ESP_LOGV(TAG, "Upload prep done"); } else { - ESP_LOGE(TAG, "Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str()); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGE(TAG, "Prep failed %d '%s'", response[0], response.c_str()); + ESP_LOGD(TAG, "Close HTTP"); http_client.end(); ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } - ESP_LOGD(TAG, "Uploading TFT to Nextion:"); - ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str()); - ESP_LOGD(TAG, " File size: %d bytes", this->content_length_); - ESP_LOGD(TAG, " Free heap: %" PRIu32, this->get_free_heap_()); + ESP_LOGD(TAG, "Upload TFT:"); + ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str()); + ESP_LOGD(TAG, " Size: %d bytes", this->content_length_); + ESP_LOGD(TAG, " Heap: %" PRIu32, this->get_free_heap_()); // Proceed with the content download as before - ESP_LOGV(TAG, "Starting transfer by chunks loop"); + ESP_LOGV(TAG, "Start chunk transfer"); uint32_t position = 0; while (this->content_length_ > 0) { int upload_result = upload_by_chunks_(http_client, position); if (upload_result < 0) { - ESP_LOGE(TAG, "Error uploading TFT to Nextion!"); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGE(TAG, "Upload error"); + ESP_LOGD(TAG, "Close HTTP"); http_client.end(); ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } App.feed_wdt(); - ESP_LOGV(TAG, "Free heap: %" PRIu32 ", Bytes left: %" PRIu32, this->get_free_heap_(), this->content_length_); + ESP_LOGV(TAG, "Heap: %" PRIu32 " left: %" PRIu32, this->get_free_heap_(), this->content_length_); } - ESP_LOGD(TAG, "Successfully uploaded TFT to Nextion!"); + ESP_LOGD(TAG, "Upload complete"); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGV(TAG, "Close HTTP"); http_client.end(); ESP_LOGV(TAG, "Connection closed"); return upload_end_(true); } bool Nextion::upload_end_(bool successful) { - ESP_LOGD(TAG, "Nextion TFT upload finished: %s", YESNO(successful)); + ESP_LOGD(TAG, "TFT upload done: %s", YESNO(successful)); this->is_updating_ = false; this->ignore_is_setup_ = false; uint32_t baud_rate = this->parent_->get_baud_rate(); if (baud_rate != this->original_baud_rate_) { - ESP_LOGD(TAG, "Changing baud rate back from %" PRIu32 " to %" PRIu32 " bps", baud_rate, this->original_baud_rate_); + ESP_LOGD(TAG, "Baud back: %" PRIu32 "->%" PRIu32, baud_rate, this->original_baud_rate_); this->parent_->set_baud_rate(this->original_baud_rate_); this->parent_->load_settings(); } if (successful) { - ESP_LOGD(TAG, "Restarting ESPHome"); + ESP_LOGD(TAG, "Restart"); delay(1500); // NOLINT - arch_restart(); + App.safe_reboot(); } else { - ESP_LOGE(TAG, "Nextion TFT upload failed"); + ESP_LOGE(TAG, "TFT upload failed"); } return successful; } diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp index 7541a57d56..8f54fbd8ac 100644 --- a/esphome/components/nextion/nextion_upload_idf.cpp +++ b/esphome/components/nextion/nextion_upload_idf.cpp @@ -21,7 +21,7 @@ static const char *const TAG = "nextion.upload.idf"; int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start) { uint32_t range_size = this->tft_size_ - range_start; - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1; ESP_LOGD(TAG, "Range start: %" PRIu32, range_start); if (range_size <= 0 or range_end <= range_start) { @@ -33,20 +33,20 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r char range_header[32]; sprintf(range_header, "bytes=%" PRIu32 "-%" PRIu32, range_start, range_end); - ESP_LOGV(TAG, "Requesting range: %s", range_header); + ESP_LOGV(TAG, "Range: %s", range_header); esp_http_client_set_header(http_client, "Range", range_header); - ESP_LOGV(TAG, "Opening HTTP connetion"); + ESP_LOGV(TAG, "Open HTTP"); esp_err_t err = esp_http_client_open(http_client, 0); if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "HTTP open failed: %s", esp_err_to_name(err)); return -1; } - ESP_LOGV(TAG, "Fetch content length"); + ESP_LOGV(TAG, "Fetch length"); const int chunk_size = esp_http_client_fetch_headers(http_client); - ESP_LOGV(TAG, "content_length = %d", chunk_size); + ESP_LOGV(TAG, "Length: %d", chunk_size); if (chunk_size <= 0) { - ESP_LOGE(TAG, "Failed to get chunk's content length: %d", chunk_size); + ESP_LOGE(TAG, "Get length failed: %d", chunk_size); return -1; } @@ -54,7 +54,7 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); uint8_t *buffer = allocator.allocate(4096); if (!buffer) { - ESP_LOGE(TAG, "Failed to allocate upload buffer"); + ESP_LOGE(TAG, "Buffer alloc failed"); return -1; } @@ -63,7 +63,7 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r App.feed_wdt(); const uint16_t buffer_size = this->content_length_ < 4096 ? this->content_length_ : 4096; // Limits buffer to the remaining data - ESP_LOGV(TAG, "Fetching %" PRIu16 " bytes from HTTP", buffer_size); + ESP_LOGV(TAG, "Fetch %" PRIu16 " bytes", buffer_size); uint16_t read_len = 0; int partial_read_len = 0; uint8_t retries = 0; @@ -84,14 +84,13 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r } if (read_len != buffer_size) { // Did not receive the full package within the timeout period - ESP_LOGE(TAG, "Failed to read full package, received only %" PRIu16 " of %" PRIu16 " bytes", read_len, - buffer_size); + ESP_LOGE(TAG, "Read failed: %" PRIu16 "/%" PRIu16 " bytes", read_len, buffer_size); // Deallocate buffer allocator.deallocate(buffer, 4096); buffer = nullptr; return -1; } - ESP_LOGV(TAG, "%d bytes fetched, writing it to UART", read_len); + ESP_LOGV(TAG, "Fetched %d bytes", read_len); if (read_len > 0) { recv_string.clear(); this->write_array(buffer, buffer_size); @@ -100,25 +99,23 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r this->content_length_ -= read_len; const float upload_percentage = 100.0f * (this->tft_size_ - this->content_length_) / this->tft_size_; #ifdef USE_PSRAM - ESP_LOGD( - TAG, - "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " (DRAM) + %" PRIu32 " (PSRAM) bytes", - upload_percentage, this->content_length_, static_cast(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)), - static_cast(heap_caps_get_free_size(MALLOC_CAP_SPIRAM))); + ESP_LOGD(TAG, "Upload: %0.2f%% (%" PRIu32 " left, heap: %" PRIu32 "+%" PRIu32 ")", upload_percentage, + this->content_length_, static_cast(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)), + static_cast(heap_caps_get_free_size(MALLOC_CAP_SPIRAM))); #else - ESP_LOGD(TAG, "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " bytes", upload_percentage, - this->content_length_, static_cast(esp_get_free_heap_size())); + ESP_LOGD(TAG, "Upload: %0.2f%% (%" PRIu32 " left, heap: %" PRIu32 ")", upload_percentage, this->content_length_, + static_cast(esp_get_free_heap_size())); #endif upload_first_chunk_sent_ = true; if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request - ESP_LOGD(TAG, "recv_string [%s]", + ESP_LOGD(TAG, "Recv: [%s]", format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); uint32_t result = 0; for (int j = 0; j < 4; ++j) { result += static_cast(recv_string[j + 1]) << (8 * j); } if (result > 0) { - ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result); + ESP_LOGI(TAG, "New range: %" PRIu32, result); this->content_length_ = this->tft_size_ - result; range_start = result; } else { @@ -129,7 +126,7 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r buffer = nullptr; return range_end + 1; } else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok" - ESP_LOGE(TAG, "Invalid response from Nextion: [%s]", + ESP_LOGE(TAG, "Invalid response: [%s]", format_hex_pretty(reinterpret_cast(recv_string.data()), recv_string.size()).c_str()); // Deallocate buffer allocator.deallocate(buffer, 4096); @@ -139,10 +136,10 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r recv_string.clear(); } else if (read_len == 0) { - ESP_LOGV(TAG, "End of HTTP response reached"); + ESP_LOGV(TAG, "HTTP end"); break; // Exit the loop if there is no more data to read } else { - ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %" PRIu16, read_len); + ESP_LOGE(TAG, "HTTP read failed: %" PRIu16, read_len); break; // Exit the loop on error } } @@ -154,26 +151,26 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r } bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { - ESP_LOGD(TAG, "Nextion TFT upload requested"); + ESP_LOGD(TAG, "TFT upload requested"); ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse)); ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str()); if (this->is_updating_) { - ESP_LOGW(TAG, "Currently uploading"); + ESP_LOGW(TAG, "Upload in progress"); return false; } if (!network::is_connected()) { - ESP_LOGE(TAG, "Network is not connected"); + ESP_LOGE(TAG, "No network"); return false; } this->is_updating_ = true; if (exit_reparse) { - ESP_LOGD(TAG, "Exiting Nextion reparse mode"); + ESP_LOGD(TAG, "Exit reparse mode"); if (!this->set_protocol_reparse_mode(false)) { - ESP_LOGW(TAG, "Failed to request Nextion to exit reparse mode"); + ESP_LOGW(TAG, "Exit reparse failed"); return false; } } @@ -188,8 +185,8 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate); // Define the configuration for the HTTP client - ESP_LOGV(TAG, "Initializing HTTP client"); - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Init HTTP client"); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); esp_http_client_config_t config = { .url = this->tft_url_.c_str(), .cert_pem = nullptr, @@ -201,30 +198,30 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { // Initialize the HTTP client with the configuration esp_http_client_handle_t http_client = esp_http_client_init(&config); if (!http_client) { - ESP_LOGE(TAG, "Failed to initialize HTTP client."); + ESP_LOGE(TAG, "HTTP init failed"); return this->upload_end_(false); } esp_err_t err = esp_http_client_set_header(http_client, "Connection", "keep-alive"); if (err != ESP_OK) { - ESP_LOGE(TAG, "HTTP set header failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "Set header failed: %s", esp_err_to_name(err)); esp_http_client_cleanup(http_client); return this->upload_end_(false); } // Perform the HTTP request - ESP_LOGV(TAG, "Check if the client could connect"); - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Check connection"); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); err = esp_http_client_perform(http_client); if (err != ESP_OK) { - ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "HTTP failed: %s", esp_err_to_name(err)); esp_http_client_cleanup(http_client); return this->upload_end_(false); } // Check the HTTP Status Code - ESP_LOGV(TAG, "Check the HTTP Status Code"); - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Check status"); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); int status_code = esp_http_client_get_status_code(http_client); if (status_code != 200 && status_code != 206) { return this->upload_end_(false); @@ -232,28 +229,28 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { this->tft_size_ = esp_http_client_get_content_length(http_client); - ESP_LOGD(TAG, "TFT file size: %zu bytes", this->tft_size_); + ESP_LOGD(TAG, "TFT size: %zu bytes", this->tft_size_); if (this->tft_size_ < 4096 || this->tft_size_ > 134217728) { - ESP_LOGE(TAG, "File size check failed."); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGE(TAG, "Size check failed"); + ESP_LOGD(TAG, "Close HTTP"); esp_http_client_close(http_client); esp_http_client_cleanup(http_client); ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } else { - ESP_LOGV(TAG, "File size check passed. Proceeding..."); + ESP_LOGV(TAG, "Size check OK"); } this->content_length_ = this->tft_size_; - ESP_LOGD(TAG, "Uploading Nextion"); + ESP_LOGD(TAG, "Uploading"); // The Nextion will ignore the upload command if it is sleeping - ESP_LOGV(TAG, "Wake-up Nextion"); + ESP_LOGV(TAG, "Wake-up"); this->ignore_is_setup_ = true; this->send_command_("sleep=0"); this->send_command_("dim=100"); vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); App.feed_wdt(); char command[128]; @@ -263,75 +260,75 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { sprintf(command, "whmi-wris %" PRIu32 ",%" PRIu32 ",1", this->content_length_, baud_rate); // Clear serial receive buffer - ESP_LOGV(TAG, "Clear serial receive buffer"); + ESP_LOGV(TAG, "Clear RX buffer"); this->reset_(false); vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); - ESP_LOGV(TAG, "Send upload instruction: %s", command); + ESP_LOGV(TAG, "Upload cmd: %s", command); this->send_command_(command); if (baud_rate != this->original_baud_rate_) { - ESP_LOGD(TAG, "Changing baud rate from %" PRIu32 " to %" PRIu32 " bps", this->original_baud_rate_, baud_rate); + ESP_LOGD(TAG, "Baud: %" PRIu32 "->%" PRIu32, this->original_baud_rate_, baud_rate); this->parent_->set_baud_rate(baud_rate); this->parent_->load_settings(); } std::string response; - ESP_LOGV(TAG, "Waiting for upgrade response"); + ESP_LOGV(TAG, "Wait upload resp"); this->recv_ret_string_(response, 5000, true); // This can take some time to return // The Nextion display will, if it's ready to accept data, send a 0x05 byte. - ESP_LOGD(TAG, "Upgrade response is [%s] - %zu byte(s)", + ESP_LOGD(TAG, "Upload resp: [%s] %zu B", format_hex_pretty(reinterpret_cast(response.data()), response.size()).c_str(), response.length()); - ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size()); if (response.find(0x05) != std::string::npos) { - ESP_LOGV(TAG, "Preparation for TFT upload done"); + ESP_LOGV(TAG, "Upload prep done"); } else { - ESP_LOGE(TAG, "Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str()); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGE(TAG, "Upload prep failed %d '%s'", response[0], response.c_str()); + ESP_LOGD(TAG, "Close HTTP"); esp_http_client_close(http_client); esp_http_client_cleanup(http_client); ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } - ESP_LOGV(TAG, "Change the method to GET before starting the download"); + ESP_LOGV(TAG, "Set method to GET"); esp_err_t set_method_result = esp_http_client_set_method(http_client, HTTP_METHOD_GET); if (set_method_result != ESP_OK) { - ESP_LOGE(TAG, "Failed to set HTTP method to GET: %s", esp_err_to_name(set_method_result)); + ESP_LOGE(TAG, "Set GET failed: %s", esp_err_to_name(set_method_result)); return this->upload_end_(false); } - ESP_LOGD(TAG, "Uploading TFT to Nextion:"); - ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str()); - ESP_LOGD(TAG, " File size: %" PRIu32 " bytes", this->content_length_); - ESP_LOGD(TAG, " Free heap: %" PRIu32, esp_get_free_heap_size()); + ESP_LOGD(TAG, "Uploading TFT:"); + ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str()); + ESP_LOGD(TAG, " Size: %" PRIu32 " bytes", this->content_length_); + ESP_LOGD(TAG, " Heap: %" PRIu32, esp_get_free_heap_size()); // Proceed with the content download as before - ESP_LOGV(TAG, "Starting transfer by chunks loop"); + ESP_LOGV(TAG, "Start chunk transfer"); uint32_t position = 0; while (this->content_length_ > 0) { int upload_result = upload_by_chunks_(http_client, position); if (upload_result < 0) { - ESP_LOGE(TAG, "Error uploading TFT to Nextion!"); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGE(TAG, "TFT upload error"); + ESP_LOGD(TAG, "Close HTTP"); esp_http_client_close(http_client); esp_http_client_cleanup(http_client); ESP_LOGV(TAG, "Connection closed"); return this->upload_end_(false); } App.feed_wdt(); - ESP_LOGV(TAG, "Free heap: %" PRIu32 ", Bytes left: %" PRIu32, esp_get_free_heap_size(), this->content_length_); + ESP_LOGV(TAG, "Heap: %" PRIu32 " left: %" PRIu32, esp_get_free_heap_size(), this->content_length_); } - ESP_LOGD(TAG, "Successfully uploaded TFT to Nextion!"); + ESP_LOGD(TAG, "TFT upload complete"); - ESP_LOGD(TAG, "Close HTTP connection"); + ESP_LOGD(TAG, "Close HTTP"); esp_http_client_close(http_client); esp_http_client_cleanup(http_client); ESP_LOGV(TAG, "Connection closed"); @@ -339,23 +336,23 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) { } bool Nextion::upload_end_(bool successful) { - ESP_LOGD(TAG, "Nextion TFT upload finished: %s", YESNO(successful)); + ESP_LOGD(TAG, "TFT upload done: %s", YESNO(successful)); this->is_updating_ = false; this->ignore_is_setup_ = false; uint32_t baud_rate = this->parent_->get_baud_rate(); if (baud_rate != this->original_baud_rate_) { - ESP_LOGD(TAG, "Changing baud rate back from %" PRIu32 " to %" PRIu32 " bps", baud_rate, this->original_baud_rate_); + ESP_LOGD(TAG, "Baud back: %" PRIu32 "->%" PRIu32, baud_rate, this->original_baud_rate_); this->parent_->set_baud_rate(this->original_baud_rate_); this->parent_->load_settings(); } if (successful) { - ESP_LOGD(TAG, "Restarting ESPHome"); + ESP_LOGD(TAG, "Restart"); delay(1500); // NOLINT - arch_restart(); + App.safe_reboot(); } else { - ESP_LOGE(TAG, "Nextion TFT upload failed"); + ESP_LOGE(TAG, "TFT upload failed"); } return successful; } diff --git a/esphome/components/nextion/sensor/nextion_sensor.cpp b/esphome/components/nextion/sensor/nextion_sensor.cpp index 6cc641fcf3..9be49e3476 100644 --- a/esphome/components/nextion/sensor/nextion_sensor.cpp +++ b/esphome/components/nextion/sensor/nextion_sensor.cpp @@ -13,7 +13,7 @@ void NextionSensor::process_sensor(const std::string &variable_name, int state) if (this->wave_chan_id_ == UINT8_MAX && this->variable_name_ == variable_name) { this->publish_state(state); - ESP_LOGD(TAG, "Processed sensor \"%s\" state %d", variable_name.c_str(), state); + ESP_LOGD(TAG, "Sensor: %s=%d", variable_name.c_str(), state); } } @@ -93,7 +93,7 @@ void NextionSensor::set_state(float state, bool publish, bool send_to_nextion) { } this->update_component_settings(); - ESP_LOGN(TAG, "Wrote state for sensor \"%s\" state %lf", this->variable_name_.c_str(), published_state); + ESP_LOGN(TAG, "Write: %s=%lf", this->variable_name_.c_str(), published_state); } void NextionSensor::wave_update_() { @@ -105,8 +105,8 @@ void NextionSensor::wave_update_() { size_t buffer_to_send = this->wave_buffer_.size() < 255 ? this->wave_buffer_.size() : 255; // ADDT command can only send 255 - ESP_LOGN(TAG, "wave_update send %zu of %zu value(s) to wave nextion component id %d and wave channel id %d", - buffer_to_send, this->wave_buffer_.size(), this->component_id_, this->wave_chan_id_); + ESP_LOGN(TAG, "Wave update: %zu/%zu vals to comp %d ch %d", buffer_to_send, this->wave_buffer_.size(), + this->component_id_, this->wave_chan_id_); #endif this->nextion_->add_addt_command_to_queue(this); diff --git a/esphome/components/nextion/switch/nextion_switch.cpp b/esphome/components/nextion/switch/nextion_switch.cpp index 63c1882b48..fe71182496 100644 --- a/esphome/components/nextion/switch/nextion_switch.cpp +++ b/esphome/components/nextion/switch/nextion_switch.cpp @@ -13,7 +13,7 @@ void NextionSwitch::process_bool(const std::string &variable_name, bool on) { if (this->variable_name_ == variable_name) { this->publish_state(on); - ESP_LOGD(TAG, "Processed switch \"%s\" state %s", variable_name.c_str(), state ? "ON" : "OFF"); + ESP_LOGD(TAG, "Switch: %s=%s", variable_name.c_str(), ONOFF(on)); } } @@ -43,7 +43,7 @@ void NextionSwitch::set_state(bool state, bool publish, bool send_to_nextion) { this->update_component_settings(); - ESP_LOGN(TAG, "Updated switch \"%s\" state %s", this->variable_name_.c_str(), ONOFF(state)); + ESP_LOGN(TAG, "Write: %s=%s", this->variable_name_.c_str(), ONOFF(state)); } void NextionSwitch::write_state(bool state) { this->set_state(state); } diff --git a/esphome/components/nextion/text_sensor/nextion_textsensor.cpp b/esphome/components/nextion/text_sensor/nextion_textsensor.cpp index a3fc9390f5..a1d45f55e0 100644 --- a/esphome/components/nextion/text_sensor/nextion_textsensor.cpp +++ b/esphome/components/nextion/text_sensor/nextion_textsensor.cpp @@ -11,7 +11,7 @@ void NextionTextSensor::process_text(const std::string &variable_name, const std return; if (this->variable_name_ == variable_name) { this->publish_state(text_value); - ESP_LOGD(TAG, "Processed text_sensor \"%s\" state \"%s\"", variable_name.c_str(), text_value.c_str()); + ESP_LOGD(TAG, "Text sensor: %s='%s'", variable_name.c_str(), text_value.c_str()); } } @@ -42,7 +42,7 @@ void NextionTextSensor::set_state(const std::string &state, bool publish, bool s this->update_component_settings(); - ESP_LOGN(TAG, "Wrote state for text_sensor \"%s\" state \"%s\"", this->variable_name_.c_str(), state.c_str()); + ESP_LOGN(TAG, "Write: %s='%s'", this->variable_name_.c_str(), state.c_str()); } } // namespace nextion diff --git a/esphome/components/nfc/nci_message.h b/esphome/components/nfc/nci_message.h index c6b8537402..0c5c871f74 100644 --- a/esphome/components/nfc/nci_message.h +++ b/esphome/components/nfc/nci_message.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include diff --git a/esphome/components/nfc/ndef_record.h b/esphome/components/nfc/ndef_record.h index 20542bf24b..76d8b6a50a 100644 --- a/esphome/components/nfc/ndef_record.h +++ b/esphome/components/nfc/ndef_record.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include diff --git a/esphome/components/nfc/ndef_record_text.h b/esphome/components/nfc/ndef_record_text.h index aa8f13bb4b..e6c15704f0 100644 --- a/esphome/components/nfc/ndef_record_text.h +++ b/esphome/components/nfc/ndef_record_text.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "ndef_record.h" #include diff --git a/esphome/components/nfc/ndef_record_uri.h b/esphome/components/nfc/ndef_record_uri.h index fc8f2d9a73..1eadda1b4f 100644 --- a/esphome/components/nfc/ndef_record_uri.h +++ b/esphome/components/nfc/ndef_record_uri.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "ndef_record.h" #include diff --git a/esphome/components/nfc/nfc.h b/esphome/components/nfc/nfc.h index 23bfdd8ef0..2e5c5cd9c5 100644 --- a/esphome/components/nfc/nfc.h +++ b/esphome/components/nfc/nfc.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "ndef_record.h" #include "ndef_message.h" #include "nfc_tag.h" diff --git a/esphome/components/nfc/nfc_tag.h b/esphome/components/nfc/nfc_tag.h index 58875a744d..55600c3bd9 100644 --- a/esphome/components/nfc/nfc_tag.h +++ b/esphome/components/nfc/nfc_tag.h @@ -3,8 +3,8 @@ #include #include -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "ndef_message.h" namespace esphome { diff --git a/esphome/components/noblex/noblex.cpp b/esphome/components/noblex/noblex.cpp index 3521745bdc..53f807809e 100644 --- a/esphome/components/noblex/noblex.cpp +++ b/esphome/components/noblex/noblex.cpp @@ -1,6 +1,6 @@ #include "noblex.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace noblex { diff --git a/esphome/components/npi19/npi19.cpp b/esphome/components/npi19/npi19.cpp index 3da5a9dbf8..17ca0ef23e 100644 --- a/esphome/components/npi19/npi19.cpp +++ b/esphome/components/npi19/npi19.cpp @@ -1,7 +1,7 @@ #include "npi19.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace npi19 { diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index fd9e948ea3..2567d9ffe1 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -277,6 +277,7 @@ async def register_number( if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_number(var)) + CORE.register_platform_component("number", var) await setup_number_core_( var, config, min_value=min_value, max_value=max_value, step=step ) diff --git a/esphome/components/online_image/__init__.py b/esphome/components/online_image/__init__.py index 7ef80ff92f..9380cf1b1b 100644 --- a/esphome/components/online_image/__init__.py +++ b/esphome/components/online_image/__init__.py @@ -2,6 +2,7 @@ import logging from esphome import automation import esphome.codegen as cg +from esphome.components.const import CONF_REQUEST_HEADERS from esphome.components.http_request import CONF_HTTP_REQUEST_ID, HttpRequestComponent from esphome.components.image import ( CONF_INVERT_ALPHA, @@ -24,6 +25,7 @@ from esphome.const import ( CONF_TYPE, CONF_URL, ) +from esphome.core import Lambda AUTO_LOAD = ["image"] DEPENDENCIES = ["display", "http_request"] @@ -124,6 +126,9 @@ ONLINE_IMAGE_SCHEMA = ( cv.GenerateID(CONF_HTTP_REQUEST_ID): cv.use_id(HttpRequestComponent), # Online Image specific options cv.Required(CONF_URL): cv.url, + cv.Optional(CONF_REQUEST_HEADERS): cv.All( + cv.Schema({cv.string: cv.templatable(cv.string)}) + ), cv.Required(CONF_FORMAT): cv.one_of(*IMAGE_FORMATS, upper=True), cv.Optional(CONF_PLACEHOLDER): cv.use_id(Image_), cv.Optional(CONF_BUFFER_SIZE, default=65536): cv.int_range(256, 65536), @@ -207,6 +212,13 @@ async def to_code(config): await cg.register_component(var, config) await cg.register_parented(var, config[CONF_HTTP_REQUEST_ID]) + for key, value in config.get(CONF_REQUEST_HEADERS, {}).items(): + if isinstance(value, Lambda): + template_ = await cg.templatable(value, [], cg.std_string) + cg.add(var.add_request_header(key, template_)) + else: + cg.add(var.add_request_header(key, value)) + if placeholder_id := config.get(CONF_PLACEHOLDER): placeholder = await cg.get_variable(placeholder_id) cg.add(var.set_placeholder(placeholder)) diff --git a/esphome/components/online_image/online_image.cpp b/esphome/components/online_image/online_image.cpp index 5c0ffc1cb2..8030bd0095 100644 --- a/esphome/components/online_image/online_image.cpp +++ b/esphome/components/online_image/online_image.cpp @@ -56,7 +56,7 @@ void OnlineImage::draw(int x, int y, display::Display *display, Color color_on, void OnlineImage::release() { if (this->buffer_) { - ESP_LOGV(TAG, "Deallocating old buffer..."); + ESP_LOGV(TAG, "Deallocating old buffer"); this->allocator_.deallocate(this->buffer_, this->get_buffer_size_()); this->data_start_ = nullptr; this->buffer_ = nullptr; @@ -143,6 +143,10 @@ void OnlineImage::update() { headers.push_back(accept_header); + for (auto &header : this->request_headers_) { + headers.push_back(http_request::Header{header.first, header.second.value()}); + } + this->downloader_ = this->parent_->get(this->url_, headers, {ETAG_HEADER_NAME, LAST_MODIFIED_HEADER_NAME}); if (this->downloader_ == nullptr) { diff --git a/esphome/components/online_image/online_image.h b/esphome/components/online_image/online_image.h index 920aee2796..6ed9c7956f 100644 --- a/esphome/components/online_image/online_image.h +++ b/esphome/components/online_image/online_image.h @@ -67,6 +67,11 @@ class OnlineImage : public PollingComponent, this->last_modified_ = ""; } + /** Add the request header */ + template void add_request_header(const std::string &header, V value) { + this->request_headers_.push_back(std::pair >(header, value)); + } + /** * @brief Set the image that needs to be shown as long as the downloaded image * is not available. @@ -153,6 +158,8 @@ class OnlineImage : public PollingComponent, std::string url_{""}; + std::vector > > request_headers_; + /** width requested on configuration, or 0 if non specified. */ const int fixed_width_; /** height requested on configuration, or 0 if non specified. */ diff --git a/esphome/components/opentherm/hub.cpp b/esphome/components/opentherm/hub.cpp index 97adf71752..0a4ef98507 100644 --- a/esphome/components/opentherm/hub.cpp +++ b/esphome/components/opentherm/hub.cpp @@ -399,13 +399,17 @@ void OpenthermHub::dump_config() { ESP_LOGCONFIG(TAG, "OpenTherm:"); LOG_PIN(" In: ", this->in_pin_); LOG_PIN(" Out: ", this->out_pin_); - ESP_LOGCONFIG(TAG, " Sync mode: %s", YESNO(this->sync_mode_)); - ESP_LOGCONFIG(TAG, " Sensors: %s", SHOW(OPENTHERM_SENSOR_LIST(ID, ))); - ESP_LOGCONFIG(TAG, " Binary sensors: %s", SHOW(OPENTHERM_BINARY_SENSOR_LIST(ID, ))); - ESP_LOGCONFIG(TAG, " Switches: %s", SHOW(OPENTHERM_SWITCH_LIST(ID, ))); - ESP_LOGCONFIG(TAG, " Input sensors: %s", SHOW(OPENTHERM_INPUT_SENSOR_LIST(ID, ))); - ESP_LOGCONFIG(TAG, " Outputs: %s", SHOW(OPENTHERM_OUTPUT_LIST(ID, ))); - ESP_LOGCONFIG(TAG, " Numbers: %s", SHOW(OPENTHERM_NUMBER_LIST(ID, ))); + ESP_LOGCONFIG(TAG, + " Sync mode: %s\n" + " Sensors: %s\n" + " Binary sensors: %s\n" + " Switches: %s\n" + " Input sensors: %s\n" + " Outputs: %s\n" + " Numbers: %s", + YESNO(this->sync_mode_), SHOW(OPENTHERM_SENSOR_LIST(ID, )), SHOW(OPENTHERM_BINARY_SENSOR_LIST(ID, )), + SHOW(OPENTHERM_SWITCH_LIST(ID, )), SHOW(OPENTHERM_INPUT_SENSOR_LIST(ID, )), + SHOW(OPENTHERM_OUTPUT_LIST(ID, )), SHOW(OPENTHERM_NUMBER_LIST(ID, ))); ESP_LOGCONFIG(TAG, " Initial requests:"); for (auto type : initial_messages) { ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str(type)); diff --git a/esphome/components/opentherm/number/number.cpp b/esphome/components/opentherm/number/number.cpp index d02b99ee9c..90ab5d6490 100644 --- a/esphome/components/opentherm/number/number.cpp +++ b/esphome/components/opentherm/number/number.cpp @@ -31,9 +31,11 @@ void OpenthermNumber::setup() { void OpenthermNumber::dump_config() { LOG_NUMBER("", "OpenTherm Number", this); - ESP_LOGCONFIG(TAG, " Restore value: %d", this->restore_value_); - ESP_LOGCONFIG(TAG, " Initial value: %.2f", this->initial_value_); - ESP_LOGCONFIG(TAG, " Current value: %.2f", this->state); + ESP_LOGCONFIG(TAG, + " Restore value: %d\n" + " Initial value: %.2f\n" + " Current value: %.2f", + this->restore_value_, this->initial_value_, this->state); } } // namespace opentherm diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index 4280832d09..a5822cdfe1 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -9,8 +9,8 @@ #include #include "esphome/core/hal.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #if defined(ESP32) || defined(USE_ESP_IDF) #include "driver/timer.h" diff --git a/esphome/components/openthread/__init__.py b/esphome/components/openthread/__init__.py new file mode 100644 index 0000000000..5b1ea491e3 --- /dev/null +++ b/esphome/components/openthread/__init__.py @@ -0,0 +1,146 @@ +import esphome.codegen as cg +from esphome.components.esp32 import ( + VARIANT_ESP32C6, + VARIANT_ESP32H2, + add_idf_sdkconfig_option, + only_on_variant, +) +from esphome.components.mdns import MDNSComponent +import esphome.config_validation as cv +from esphome.const import CONF_CHANNEL, CONF_ENABLE_IPV6, CONF_ID +import esphome.final_validate as fv + +from .const import ( + CONF_EXT_PAN_ID, + CONF_FORCE_DATASET, + CONF_MDNS_ID, + CONF_MESH_LOCAL_PREFIX, + CONF_NETWORK_KEY, + CONF_NETWORK_NAME, + CONF_PAN_ID, + CONF_PSKC, + CONF_SRP_ID, + CONF_TLV, +) +from .tlv import parse_tlv + +CODEOWNERS = ["@mrene"] + +AUTO_LOAD = ["network"] + +# Wi-fi / Bluetooth / Thread coexistence isn't implemented at this time +# TODO: Doesn't conflict with wifi if you're using another ESP as an RCP (radio coprocessor), but this isn't implemented yet +CONFLICTS_WITH = ["wifi"] +DEPENDENCIES = ["esp32"] + + +def set_sdkconfig_options(config): + # and expose options for using SPI/UART RCPs + add_idf_sdkconfig_option("CONFIG_IEEE802154_ENABLED", True) + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_RADIO_NATIVE", True) + + # There is a conflict if the logger's uart also uses the default UART, which is seen as a watchdog failure on "ot_cli" + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_CLI", False) + + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_ENABLED", True) + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PANID", config[CONF_PAN_ID]) + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_CHANNEL", config[CONF_CHANNEL]) + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{config[CONF_NETWORK_KEY]:X}" + ) + + if network_name := config.get(CONF_NETWORK_NAME): + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_NAME", network_name) + + if (ext_pan_id := config.get(CONF_EXT_PAN_ID)) is not None: + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}" + ) + if (mesh_local_prefix := config.get(CONF_MESH_LOCAL_PREFIX)) is not None: + add_idf_sdkconfig_option( + "CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix:X}" + ) + if (pskc := config.get(CONF_PSKC)) is not None: + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}") + + if CONF_FORCE_DATASET in config: + if config[CONF_FORCE_DATASET]: + cg.add_define("CONFIG_OPENTHREAD_FORCE_DATASET") + + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_DNS64_CLIENT", True) + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_SRP_CLIENT", True) + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_SRP_CLIENT_MAX_SERVICES", 5) + + # TODO: Add suport for sleepy end devices + add_idf_sdkconfig_option("CONFIG_OPENTHREAD_FTD", True) # Full Thread Device + + +openthread_ns = cg.esphome_ns.namespace("openthread") +OpenThreadComponent = openthread_ns.class_("OpenThreadComponent", cg.Component) +OpenThreadSrpComponent = openthread_ns.class_("OpenThreadSrpComponent", cg.Component) + + +def _convert_tlv(config): + if tlv := config.get(CONF_TLV): + config = config.copy() + parsed_tlv = parse_tlv(tlv) + validated = _CONNECTION_SCHEMA(parsed_tlv) + config.update(validated) + del config[CONF_TLV] + return config + + +_CONNECTION_SCHEMA = cv.Schema( + { + cv.Inclusive(CONF_PAN_ID, "manual"): cv.hex_int, + cv.Inclusive(CONF_CHANNEL, "manual"): cv.int_, + cv.Inclusive(CONF_NETWORK_KEY, "manual"): cv.hex_int, + cv.Optional(CONF_EXT_PAN_ID): cv.hex_int, + cv.Optional(CONF_NETWORK_NAME): cv.string_strict, + cv.Optional(CONF_PSKC): cv.hex_int, + cv.Optional(CONF_MESH_LOCAL_PREFIX): cv.hex_int, + } +) + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(OpenThreadComponent), + cv.GenerateID(CONF_SRP_ID): cv.declare_id(OpenThreadSrpComponent), + cv.GenerateID(CONF_MDNS_ID): cv.use_id(MDNSComponent), + cv.Optional(CONF_FORCE_DATASET): cv.boolean, + cv.Optional(CONF_TLV): cv.string_strict, + } + ).extend(_CONNECTION_SCHEMA), + cv.has_exactly_one_key(CONF_PAN_ID, CONF_TLV), + _convert_tlv, + cv.only_with_esp_idf, + only_on_variant(supported=[VARIANT_ESP32C6, VARIANT_ESP32H2]), +) + + +def _final_validate(_): + full_config = fv.full_config.get() + network_config = full_config.get("network", {}) + if not network_config.get(CONF_ENABLE_IPV6, False): + raise cv.Invalid( + "OpenThread requires IPv6 to be enabled in the network component. " + "Please set `enable_ipv6: true` in the `network` configuration." + ) + + +FINAL_VALIDATE_SCHEMA = _final_validate + + +async def to_code(config): + cg.add_define("USE_OPENTHREAD") + + ot = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(ot, config) + + srp = cg.new_Pvariable(config[CONF_SRP_ID]) + mdns_component = await cg.get_variable(config[CONF_MDNS_ID]) + cg.add(srp.set_mdns(mdns_component)) + await cg.register_component(srp, config) + + set_sdkconfig_options(config) diff --git a/esphome/components/openthread/const.py b/esphome/components/openthread/const.py new file mode 100644 index 0000000000..7837e69eea --- /dev/null +++ b/esphome/components/openthread/const.py @@ -0,0 +1,10 @@ +CONF_EXT_PAN_ID = "ext_pan_id" +CONF_FORCE_DATASET = "force_dataset" +CONF_MDNS_ID = "mdns_id" +CONF_MESH_LOCAL_PREFIX = "mesh_local_prefix" +CONF_NETWORK_NAME = "network_name" +CONF_NETWORK_KEY = "network_key" +CONF_PAN_ID = "pan_id" +CONF_PSKC = "pskc" +CONF_SRP_ID = "srp_id" +CONF_TLV = "tlv" diff --git a/esphome/components/openthread/openthread.cpp b/esphome/components/openthread/openthread.cpp new file mode 100644 index 0000000000..f40a56952a --- /dev/null +++ b/esphome/components/openthread/openthread.cpp @@ -0,0 +1,206 @@ +#include "esphome/core/defines.h" +#ifdef USE_OPENTHREAD +#include "openthread.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +static const char *const TAG = "openthread"; + +namespace esphome { +namespace openthread { + +OpenThreadComponent *global_openthread_component = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +OpenThreadComponent::OpenThreadComponent() { global_openthread_component = this; } + +OpenThreadComponent::~OpenThreadComponent() { + auto lock = InstanceLock::try_acquire(100); + if (!lock) { + ESP_LOGW(TAG, "Failed to acquire OpenThread lock in destructor, leaking memory"); + return; + } + otInstance *instance = lock->get_instance(); + otSrpClientClearHostAndServices(instance); + otSrpClientBuffersFreeAllServices(instance); + global_openthread_component = nullptr; +} + +bool OpenThreadComponent::is_connected() { + auto lock = InstanceLock::try_acquire(100); + if (!lock) { + ESP_LOGW(TAG, "Failed to acquire OpenThread lock in is_connected"); + return false; + } + + otInstance *instance = lock->get_instance(); + if (instance == nullptr) { + return false; + } + + otDeviceRole role = otThreadGetDeviceRole(instance); + + // TODO: If we're a leader, check that there is at least 1 known peer + return role >= OT_DEVICE_ROLE_CHILD; +} + +// Gets the off-mesh routable address +std::optional OpenThreadComponent::get_omr_address() { + InstanceLock lock = InstanceLock::acquire(); + return this->get_omr_address_(lock); +} + +std::optional OpenThreadComponent::get_omr_address_(InstanceLock &lock) { + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otInstance *instance = nullptr; + + instance = lock.get_instance(); + + otBorderRouterConfig config; + if (otNetDataGetNextOnMeshPrefix(instance, &iterator, &config) != OT_ERROR_NONE) { + return std::nullopt; + } + + const otIp6Prefix *omr_prefix = &config.mPrefix; + const otNetifAddress *unicast_addresses = otIp6GetUnicastAddresses(instance); + for (const otNetifAddress *addr = unicast_addresses; addr; addr = addr->mNext) { + const otIp6Address *local_ip = &addr->mAddress; + if (otIp6PrefixMatch(&omr_prefix->mPrefix, local_ip)) { + return *local_ip; + } + } + return {}; +} + +void srp_callback(otError err, const otSrpClientHostInfo *host_info, const otSrpClientService *services, + const otSrpClientService *removed_services, void *context) { + if (err != 0) { + ESP_LOGW(TAG, "SRP client reported an error: %s", otThreadErrorToString(err)); + for (const otSrpClientHostInfo *host = host_info; host; host = nullptr) { + ESP_LOGW(TAG, " Host: %s", host->mName); + } + for (const otSrpClientService *service = services; service; service = service->mNext) { + ESP_LOGW(TAG, " Service: %s", service->mName); + } + } +} + +void srp_start_callback(const otSockAddr *server_socket_address, void *context) { + ESP_LOGI(TAG, "SRP client has started"); +} + +void OpenThreadSrpComponent::setup() { + otError error; + InstanceLock lock = InstanceLock::acquire(); + otInstance *instance = lock.get_instance(); + + otSrpClientSetCallback(instance, srp_callback, nullptr); + + // set the host name + uint16_t size; + char *existing_host_name = otSrpClientBuffersGetHostNameString(instance, &size); + const std::string &host_name = App.get_name(); + uint16_t host_name_len = host_name.size(); + if (host_name_len > size) { + ESP_LOGW(TAG, "Hostname is too long, choose a shorter project name"); + return; + } + memset(existing_host_name, 0, size); + memcpy(existing_host_name, host_name.c_str(), host_name_len); + + error = otSrpClientSetHostName(instance, existing_host_name); + if (error != 0) { + ESP_LOGW(TAG, "Could not set host name"); + return; + } + + error = otSrpClientEnableAutoHostAddress(instance); + if (error != 0) { + ESP_LOGW(TAG, "Could not enable auto host address"); + return; + } + + // Copy the mdns services to our local instance so that the c_str pointers remain valid for the lifetime of this + // component + this->mdns_services_ = this->mdns_->get_services(); + ESP_LOGW(TAG, "Setting up SRP services. count = %d\n", this->mdns_services_.size()); + for (const auto &service : this->mdns_services_) { + otSrpClientBuffersServiceEntry *entry = otSrpClientBuffersAllocateService(instance); + if (!entry) { + ESP_LOGW(TAG, "Failed to allocate service entry"); + continue; + } + + // Set service name + char *string = otSrpClientBuffersGetServiceEntryServiceNameString(entry, &size); + std::string full_service = service.service_type + "." + service.proto; + if (full_service.size() > size) { + ESP_LOGW(TAG, "Service name too long: %s", full_service.c_str()); + continue; + } + memcpy(string, full_service.c_str(), full_service.size() + 1); + + // Set instance name (using host_name) + string = otSrpClientBuffersGetServiceEntryInstanceNameString(entry, &size); + if (host_name_len > size) { + ESP_LOGW(TAG, "Instance name too long: %s", host_name.c_str()); + continue; + } + memset(string, 0, size); + memcpy(string, host_name.c_str(), host_name_len); + + // Set port + entry->mService.mPort = const_cast &>(service.port).value(); + + otDnsTxtEntry *txt_entries = + reinterpret_cast(this->pool_alloc_(sizeof(otDnsTxtEntry) * service.txt_records.size())); + // Set TXT records + entry->mService.mNumTxtEntries = service.txt_records.size(); + for (size_t i = 0; i < service.txt_records.size(); i++) { + const auto &txt = service.txt_records[i]; + auto value = const_cast &>(txt.value).value(); + txt_entries[i].mKey = strdup(txt.key.c_str()); + txt_entries[i].mValue = reinterpret_cast(strdup(value.c_str())); + txt_entries[i].mValueLength = value.size(); + } + entry->mService.mTxtEntries = txt_entries; + entry->mService.mNumTxtEntries = service.txt_records.size(); + + // Add service + error = otSrpClientAddService(instance, &entry->mService); + if (error != OT_ERROR_NONE) { + ESP_LOGW(TAG, "Failed to add service: %s", otThreadErrorToString(error)); + } + ESP_LOGW(TAG, "Added service: %s", full_service.c_str()); + } + + otSrpClientEnableAutoStartMode(instance, srp_start_callback, nullptr); + ESP_LOGW(TAG, "Finished SRP setup"); +} + +void *OpenThreadSrpComponent::pool_alloc_(size_t size) { + uint8_t *ptr = new uint8_t[size]; + this->memory_pool_.emplace_back(std::unique_ptr(ptr)); + return ptr; +} + +void OpenThreadSrpComponent::set_mdns(esphome::mdns::MDNSComponent *mdns) { this->mdns_ = mdns; } + +} // namespace openthread +} // namespace esphome + +#endif diff --git a/esphome/components/openthread/openthread.h b/esphome/components/openthread/openthread.h new file mode 100644 index 0000000000..77fd58851a --- /dev/null +++ b/esphome/components/openthread/openthread.h @@ -0,0 +1,68 @@ +#pragma once +#include "esphome/core/defines.h" +#ifdef USE_OPENTHREAD + +#include "esphome/components/mdns/mdns_component.h" +#include "esphome/components/network/ip_address.h" +#include "esphome/core/component.h" + +#include + +#include +#include + +namespace esphome { +namespace openthread { + +class InstanceLock; + +class OpenThreadComponent : public Component { + public: + OpenThreadComponent(); + ~OpenThreadComponent(); + void setup() override; + float get_setup_priority() const override { return setup_priority::WIFI; } + + bool is_connected(); + network::IPAddresses get_ip_addresses(); + std::optional get_omr_address(); + void ot_main(); + + protected: + std::optional get_omr_address_(InstanceLock &lock); +}; + +extern OpenThreadComponent *global_openthread_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + +class OpenThreadSrpComponent : public Component { + public: + void set_mdns(esphome::mdns::MDNSComponent *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.0; } + void setup() override; + + protected: + esphome::mdns::MDNSComponent *mdns_{nullptr}; + std::vector mdns_services_; + std::vector> memory_pool_; + void *pool_alloc_(size_t size); +}; + +class InstanceLock { + public: + static std::optional try_acquire(int delay); + static InstanceLock acquire(); + ~InstanceLock(); + + // Returns the global openthread instance guarded by this lock + otInstance *get_instance(); + + private: + // Use a private constructor in order to force thehandling + // of acquisition failure + InstanceLock() {} +}; + +} // namespace openthread +} // namespace esphome +#endif diff --git a/esphome/components/openthread/openthread_esp.cpp b/esphome/components/openthread/openthread_esp.cpp new file mode 100644 index 0000000000..c5c817382f --- /dev/null +++ b/esphome/components/openthread/openthread_esp.cpp @@ -0,0 +1,164 @@ +#include "esphome/core/defines.h" +#if defined(USE_OPENTHREAD) && defined(USE_ESP_IDF) +#include +#include "openthread.h" + +#include "esp_log.h" +#include "esp_openthread.h" +#include "esp_openthread_lock.h" + +#include "esp_task_wdt.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +#include "esp_err.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_netif_types.h" +#include "esp_openthread_cli.h" +#include "esp_openthread_netif_glue.h" +#include "esp_vfs_eventfd.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "nvs_flash.h" + +static const char *const TAG = "openthread"; + +namespace esphome { +namespace openthread { + +void OpenThreadComponent::setup() { + ESP_LOGCONFIG(TAG, "Running setup"); + // Used eventfds: + // * netif + // * ot task queue + // * radio driver + esp_vfs_eventfd_config_t eventfd_config = { + .max_fds = 3, + }; + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); + + xTaskCreate( + [](void *arg) { + static_cast(arg)->ot_main(); + vTaskDelete(nullptr); + }, + "ot_main", 10240, this, 5, nullptr); +} + +static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config) { + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD(); + esp_netif_t *netif = esp_netif_new(&cfg); + assert(netif != nullptr); + ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init(config))); + + return netif; +} + +void OpenThreadComponent::ot_main() { + esp_openthread_platform_config_t config = { + .radio_config = + { + .radio_mode = RADIO_MODE_NATIVE, + .radio_uart_config = {}, + }, + .host_config = + { + // There is a conflict between esphome's logger which also + // claims the usb serial jtag device. + // .host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, + // .host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), + }, + .port_config = + { + .storage_partition_name = "nvs", + .netif_queue_size = 10, + .task_queue_size = 10, + }, + }; + + // Initialize the OpenThread stack + // otLoggingSetLevel(OT_LOG_LEVEL_DEBG); + ESP_ERROR_CHECK(esp_openthread_init(&config)); + +#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE + ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance())); +#endif + +#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC + // The OpenThread log level directly matches ESP log level + (void) otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL); +#endif + // Initialize the OpenThread cli +#if CONFIG_OPENTHREAD_CLI + esp_openthread_cli_init(); +#endif + + esp_netif_t *openthread_netif; + // Initialize the esp_netif bindings + openthread_netif = init_openthread_netif(&config); + esp_netif_set_default_netif(openthread_netif); + +#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION + esp_cli_custom_command_init(); +#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION + + // Run the main loop +#if CONFIG_OPENTHREAD_CLI + esp_openthread_cli_create_task(); +#endif + ESP_LOGI(TAG, "Activating dataset..."); + otOperationalDatasetTlvs dataset; + +#ifdef CONFIG_OPENTHREAD_FORCE_DATASET + ESP_ERROR_CHECK(esp_openthread_auto_start(NULL)); +#else + otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); + ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); +#endif + esp_openthread_launch_mainloop(); + + // Clean up + esp_openthread_netif_glue_deinit(); + esp_netif_destroy(openthread_netif); + + esp_vfs_eventfd_unregister(); +} + +network::IPAddresses OpenThreadComponent::get_ip_addresses() { + network::IPAddresses addresses; + struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; + uint8_t count = 0; + esp_netif_t *netif = esp_netif_get_default_netif(); + count = esp_netif_get_all_ip6(netif, if_ip6s); + assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES); + for (int i = 0; i < count; i++) { + addresses[i + 1] = network::IPAddress(&if_ip6s[i]); + } + return addresses; +} + +std::optional InstanceLock::try_acquire(int delay) { + if (esp_openthread_lock_acquire(delay)) { + return InstanceLock(); + } + return {}; +} + +InstanceLock InstanceLock::acquire() { + while (!esp_openthread_lock_acquire(100)) { + esp_task_wdt_reset(); + } + return InstanceLock(); +} + +otInstance *InstanceLock::get_instance() { return esp_openthread_get_instance(); } + +InstanceLock::~InstanceLock() { esp_openthread_lock_release(); } + +} // namespace openthread +} // namespace esphome +#endif diff --git a/esphome/components/openthread/tlv.py b/esphome/components/openthread/tlv.py new file mode 100644 index 0000000000..45c8c47227 --- /dev/null +++ b/esphome/components/openthread/tlv.py @@ -0,0 +1,58 @@ +# Sourced from https://gist.github.com/agners/0338576e0003318b63ec1ea75adc90f9 +import binascii + +from esphome.const import CONF_CHANNEL + +from . import ( + CONF_EXT_PAN_ID, + CONF_MESH_LOCAL_PREFIX, + CONF_NETWORK_KEY, + CONF_NETWORK_NAME, + CONF_PAN_ID, + CONF_PSKC, +) + +TLV_TYPES = { + 0: CONF_CHANNEL, + 1: CONF_PAN_ID, + 2: CONF_EXT_PAN_ID, + 3: CONF_NETWORK_NAME, + 4: CONF_PSKC, + 5: CONF_NETWORK_KEY, + 7: CONF_MESH_LOCAL_PREFIX, +} + + +def parse_tlv(tlv) -> dict: + data = binascii.a2b_hex(tlv) + output = {} + pos = 0 + while pos < len(data): + tag = data[pos] + pos += 1 + _len = data[pos] + pos += 1 + val = data[pos : pos + _len] + pos += _len + if tag in TLV_TYPES: + if tag == 3: + output[TLV_TYPES[tag]] = val.decode("utf-8") + else: + output[TLV_TYPES[tag]] = int.from_bytes(val) + return output + + +def main(): + import sys + + args = sys.argv[1:] + parsed = parse_tlv(args[0]) + # print the parsed TLV data + for key, value in parsed.items(): + if isinstance(value, bytes): + value = value.hex() + print(f"{key}: {value}") + + +if __name__ == "__main__": + main() diff --git a/esphome/components/openthread_info/__init__.py b/esphome/components/openthread_info/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/openthread_info/openthread_info_text_sensor.cpp b/esphome/components/openthread_info/openthread_info_text_sensor.cpp new file mode 100644 index 0000000000..10724f3e2f --- /dev/null +++ b/esphome/components/openthread_info/openthread_info_text_sensor.cpp @@ -0,0 +1,24 @@ + +#include "openthread_info_text_sensor.h" +#ifdef USE_OPENTHREAD +#include "esphome/core/log.h" + +namespace esphome { +namespace openthread_info { + +static const char *const TAG = "openthread_info"; + +void IPAddressOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "IPAddress", this); } +void RoleOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Role", this); } +void ChannelOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Channel", this); } +void Rloc16OpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Rloc16", this); } +void ExtAddrOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "ExtAddr", this); } +void Eui64OpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Eui64", this); } +void NetworkNameOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Network Name", this); } +void NetworkKeyOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Network Key", this); } +void PanIdOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "PAN ID", this); } +void ExtPanIdOpenThreadInfo::dump_config() { LOG_TEXT_SENSOR("", "Extended PAN ID", this); } + +} // namespace openthread_info +} // namespace esphome +#endif diff --git a/esphome/components/openthread_info/openthread_info_text_sensor.h b/esphome/components/openthread_info/openthread_info_text_sensor.h new file mode 100644 index 0000000000..bbcd2d4655 --- /dev/null +++ b/esphome/components/openthread_info/openthread_info_text_sensor.h @@ -0,0 +1,218 @@ +#pragma once + +#include "esphome/components/openthread/openthread.h" +#include "esphome/components/text_sensor/text_sensor.h" +#include "esphome/core/component.h" +#ifdef USE_OPENTHREAD + +namespace esphome { +namespace openthread_info { + +using esphome::openthread::InstanceLock; + +class OpenThreadInstancePollingComponent : public PollingComponent { + public: + void update() override { + auto lock = InstanceLock::try_acquire(10); + if (!lock) { + return; + } + + this->update_instance(lock->get_instance()); + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + + protected: + virtual void update_instance(otInstance *instance) = 0; +}; + +class IPAddressOpenThreadInfo : public PollingComponent, public text_sensor::TextSensor { + public: + void update() override { + std::optional address = openthread::global_openthread_component->get_omr_address(); + if (!address) { + return; + } + + char address_as_string[40]; + otIp6AddressToString(&*address, address_as_string, 40); + std::string ip = address_as_string; + + if (this->last_ip_ != ip) { + this->last_ip_ = ip; + this->publish_state(this->last_ip_); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + std::string last_ip_; +}; + +class RoleOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { + public: + void update_instance(otInstance *instance) override { + otDeviceRole role = otThreadGetDeviceRole(instance); + + if (this->last_role_ != role) { + this->last_role_ = role; + this->publish_state(otThreadDeviceRoleToString(this->last_role_)); + } + } + void dump_config() override; + + protected: + otDeviceRole last_role_; +}; + +class Rloc16OpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { + public: + void update_instance(otInstance *instance) override { + uint16_t rloc16 = otThreadGetRloc16(instance); + if (this->last_rloc16_ != rloc16) { + this->last_rloc16_ = rloc16; + char buf[5]; + snprintf(buf, sizeof(buf), "%04x", rloc16); + this->publish_state(buf); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + uint16_t last_rloc16_; +}; + +class ExtAddrOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { + public: + void update_instance(otInstance *instance) override { + const auto *extaddr = otLinkGetExtendedAddress(instance); + if (!std::equal(this->last_extaddr_.begin(), this->last_extaddr_.end(), extaddr->m8)) { + std::copy(extaddr->m8, extaddr->m8 + 8, this->last_extaddr_.begin()); + this->publish_state(format_hex(extaddr->m8, 8)); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + std::array last_extaddr_{}; +}; + +class Eui64OpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { + public: + void update_instance(otInstance *instance) override { + otExtAddress addr; + otLinkGetFactoryAssignedIeeeEui64(instance, &addr); + + if (!std::equal(this->last_eui64_.begin(), this->last_eui64_.end(), addr.m8)) { + std::copy(addr.m8, addr.m8 + 8, this->last_eui64_.begin()); + this->publish_state(format_hex(this->last_eui64_.begin(), 8)); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + std::array last_eui64_{}; +}; + +class ChannelOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { + public: + void update_instance(otInstance *instance) override { + uint8_t channel = otLinkGetChannel(instance); + if (this->last_channel_ != channel) { + this->last_channel_ = channel; + this->publish_state(std::to_string(this->last_channel_)); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + uint8_t last_channel_; +}; + +class DatasetOpenThreadInfo : public OpenThreadInstancePollingComponent { + public: + void update_instance(otInstance *instance) override { + otOperationalDataset dataset; + if (otDatasetGetActive(instance, &dataset) != OT_ERROR_NONE) { + return; + } + + this->update_dataset(&dataset); + } + + protected: + virtual void update_dataset(otOperationalDataset *dataset) = 0; +}; + +class NetworkNameOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { + public: + void update_dataset(otOperationalDataset *dataset) override { + if (this->last_network_name_ != dataset->mNetworkName.m8) { + this->last_network_name_ = dataset->mNetworkName.m8; + this->publish_state(this->last_network_name_); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + std::string last_network_name_; +}; + +class NetworkKeyOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { + public: + void update_dataset(otOperationalDataset *dataset) override { + if (!std::equal(this->last_key_.begin(), this->last_key_.end(), dataset->mNetworkKey.m8)) { + std::copy(dataset->mNetworkKey.m8, dataset->mNetworkKey.m8 + 16, this->last_key_.begin()); + this->publish_state(format_hex(dataset->mNetworkKey.m8, 16)); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + std::array last_key_{}; +}; + +class PanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { + public: + void update_dataset(otOperationalDataset *dataset) override { + uint16_t panid = dataset->mPanId; + if (this->last_panid_ != panid) { + this->last_panid_ = panid; + char buf[5]; + snprintf(buf, sizeof(buf), "%04x", panid); + this->publish_state(buf); + } + } + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + uint16_t last_panid_; +}; + +class ExtPanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { + public: + void update_dataset(otOperationalDataset *dataset) override { + if (!std::equal(this->last_extpanid_.begin(), this->last_extpanid_.end(), dataset->mExtendedPanId.m8)) { + std::copy(dataset->mExtendedPanId.m8, dataset->mExtendedPanId.m8 + 8, this->last_extpanid_.begin()); + this->publish_state(format_hex(this->last_extpanid_.begin(), 8)); + } + } + + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void dump_config() override; + + protected: + std::array last_extpanid_{}; +}; + +} // namespace openthread_info +} // namespace esphome +#endif diff --git a/esphome/components/openthread_info/text_sensor.py b/esphome/components/openthread_info/text_sensor.py new file mode 100644 index 0000000000..ddec8f264c --- /dev/null +++ b/esphome/components/openthread_info/text_sensor.py @@ -0,0 +1,105 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +from esphome.components.openthread.const import ( + CONF_EXT_PAN_ID, + CONF_NETWORK_KEY, + CONF_NETWORK_NAME, + CONF_PAN_ID, +) +import esphome.config_validation as cv +from esphome.const import CONF_CHANNEL, CONF_IP_ADDRESS, ENTITY_CATEGORY_DIAGNOSTIC + +CONF_ROLE = "role" +CONF_RLOC16 = "rloc16" +CONF_EUI64 = "eui64" +CONF_EXT_ADDR = "ext_addr" + + +DEPENDENCIES = ["openthread"] + +openthread_info_ns = cg.esphome_ns.namespace("openthread_info") +IPAddressOpenThreadInfo = openthread_info_ns.class_( + "IPAddressOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +RoleOpenThreadInfo = openthread_info_ns.class_( + "RoleOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +Rloc16OpenThreadInfo = openthread_info_ns.class_( + "Rloc16OpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +ExtAddrOpenThreadInfo = openthread_info_ns.class_( + "ExtAddrOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +Eui64OpenThreadInfo = openthread_info_ns.class_( + "Eui64OpenThreadInfo", text_sensor.TextSensor, cg.Component +) +ChannelOpenThreadInfo = openthread_info_ns.class_( + "ChannelOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +NetworkNameOpenThreadInfo = openthread_info_ns.class_( + "NetworkNameOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +NetworkKeyOpenThreadInfo = openthread_info_ns.class_( + "NetworkKeyOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +PanIdOpenThreadInfo = openthread_info_ns.class_( + "PanIdOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) +ExtPanIdOpenThreadInfo = openthread_info_ns.class_( + "ExtPanIdOpenThreadInfo", text_sensor.TextSensor, cg.PollingComponent +) + + +CONFIG_SCHEMA = cv.Schema( + { + cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema( + IPAddressOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ), + cv.Optional(CONF_ROLE): text_sensor.text_sensor_schema( + RoleOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_RLOC16): text_sensor.text_sensor_schema( + Rloc16OpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_EXT_ADDR): text_sensor.text_sensor_schema( + ExtAddrOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_EUI64): text_sensor.text_sensor_schema( + Eui64OpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1h")), + cv.Optional(CONF_CHANNEL): text_sensor.text_sensor_schema( + ChannelOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_NETWORK_NAME): text_sensor.text_sensor_schema( + NetworkNameOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_NETWORK_KEY): text_sensor.text_sensor_schema( + NetworkKeyOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_PAN_ID): text_sensor.text_sensor_schema( # noqa: F821 + PanIdOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + cv.Optional(CONF_EXT_PAN_ID): text_sensor.text_sensor_schema( + ExtPanIdOpenThreadInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC + ).extend(cv.polling_component_schema("1s")), + } +) + + +async def setup_conf(config: dict, key: str): + if conf := config.get(key): + var = await text_sensor.new_text_sensor(conf) + await cg.register_component(var, conf) + + +async def to_code(config): + await setup_conf(config, CONF_IP_ADDRESS) + await setup_conf(config, CONF_ROLE) + await setup_conf(config, CONF_RLOC16) + await setup_conf(config, CONF_EXT_ADDR) + await setup_conf(config, CONF_EUI64) + await setup_conf(config, CONF_CHANNEL) + await setup_conf(config, CONF_NETWORK_NAME) + await setup_conf(config, CONF_NETWORK_KEY) + await setup_conf(config, CONF_PAN_ID) + await setup_conf(config, CONF_EXT_PAN_ID) diff --git a/esphome/components/output/float_output.cpp b/esphome/components/output/float_output.cpp index e7dba1d81d..3b83c85716 100644 --- a/esphome/components/output/float_output.cpp +++ b/esphome/components/output/float_output.cpp @@ -1,6 +1,6 @@ #include "float_output.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace output { diff --git a/esphome/components/packet_transport/packet_transport.cpp b/esphome/components/packet_transport/packet_transport.cpp index be2f77e379..5c721002b0 100644 --- a/esphome/components/packet_transport/packet_transport.cpp +++ b/esphome/components/packet_transport/packet_transport.cpp @@ -474,10 +474,12 @@ void PacketTransport::process_(const std::vector &data) { } void PacketTransport::dump_config() { - ESP_LOGCONFIG(TAG, "Packet Transport:"); - ESP_LOGCONFIG(TAG, " Platform: %s", this->platform_name_); - ESP_LOGCONFIG(TAG, " Encrypted: %s", YESNO(this->is_encrypted_())); - ESP_LOGCONFIG(TAG, " Ping-pong: %s", YESNO(this->ping_pong_enable_)); + ESP_LOGCONFIG(TAG, + "Packet Transport:\n" + " Platform: %s\n" + " Encrypted: %s\n" + " Ping-pong: %s", + this->platform_name_, YESNO(this->is_encrypted_()), YESNO(this->ping_pong_enable_)); #ifdef USE_SENSOR for (auto sensor : this->sensors_) ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id); diff --git a/esphome/components/pca9554/pca9554.cpp b/esphome/components/pca9554/pca9554.cpp index fe4375c171..6b3f2d20af 100644 --- a/esphome/components/pca9554/pca9554.cpp +++ b/esphome/components/pca9554/pca9554.cpp @@ -45,8 +45,10 @@ void PCA9554Component::loop() { } void PCA9554Component::dump_config() { - ESP_LOGCONFIG(TAG, "PCA9554:"); - ESP_LOGCONFIG(TAG, " I/O Pins: %d", this->pin_count_); + ESP_LOGCONFIG(TAG, + "PCA9554:\n" + " I/O Pins: %d", + this->pin_count_); LOG_I2C_DEVICE(this) if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); diff --git a/esphome/components/pca9685/pca9685_output.cpp b/esphome/components/pca9685/pca9685_output.cpp index 504adc43ff..2fe22fd1cc 100644 --- a/esphome/components/pca9685/pca9685_output.cpp +++ b/esphome/components/pca9685/pca9685_output.cpp @@ -1,7 +1,7 @@ #include "pca9685_output.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace pca9685 { @@ -28,7 +28,7 @@ static const uint8_t PCA9685_MODE1_SLEEP = 0b00010000; void PCA9685Output::setup() { ESP_LOGCONFIG(TAG, "Running setup"); - ESP_LOGV(TAG, " Resetting devices..."); + ESP_LOGV(TAG, " Resetting devices"); if (!this->write_bytes(PCA9685_REGISTER_SOFTWARE_RESET, nullptr, 0)) { this->mark_failed(); return; @@ -83,13 +83,17 @@ void PCA9685Output::setup() { } void PCA9685Output::dump_config() { - ESP_LOGCONFIG(TAG, "PCA9685:"); - ESP_LOGCONFIG(TAG, " Mode: 0x%02X", this->mode_); + ESP_LOGCONFIG(TAG, + "PCA9685:\n" + " Mode: 0x%02X", + this->mode_); if (this->extclk_) { ESP_LOGCONFIG(TAG, " EXTCLK: enabled"); } else { - ESP_LOGCONFIG(TAG, " EXTCLK: disabled"); - ESP_LOGCONFIG(TAG, " Frequency: %.0f Hz", this->frequency_); + ESP_LOGCONFIG(TAG, + " EXTCLK: disabled\n" + " Frequency: %.0f Hz", + this->frequency_); } if (this->is_failed()) { ESP_LOGE(TAG, "Setting up PCA9685 failed!"); diff --git a/esphome/components/pcd8544/pcd_8544.cpp b/esphome/components/pcd8544/pcd_8544.cpp index 5651d60b15..f5b018b127 100644 --- a/esphome/components/pcd8544/pcd_8544.cpp +++ b/esphome/components/pcd8544/pcd_8544.cpp @@ -1,7 +1,7 @@ #include "pcd_8544.h" -#include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace pcd8544 { diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py index 64bef86443..ff7c314bcd 100644 --- a/esphome/components/pcf8574/__init__.py +++ b/esphome/components/pcf8574/__init__.py @@ -53,7 +53,7 @@ PCF8574_PIN_SCHEMA = pins.gpio_base_schema( cv.int_range(min=0, max=17), modes=[CONF_INPUT, CONF_OUTPUT], mode_validator=validate_mode, - invertable=True, + invertible=True, ).extend( { cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component), diff --git a/esphome/components/pid/pid_climate.cpp b/esphome/components/pid/pid_climate.cpp index 93b6999a00..8b3be36dcc 100644 --- a/esphome/components/pid/pid_climate.cpp +++ b/esphome/components/pid/pid_climate.cpp @@ -73,15 +73,18 @@ climate::ClimateTraits PIDClimate::traits() { } void PIDClimate::dump_config() { LOG_CLIMATE("", "PID Climate", this); - ESP_LOGCONFIG(TAG, " Control Parameters:"); - ESP_LOGCONFIG(TAG, " kp: %.5f, ki: %.5f, kd: %.5f, output samples: %d", controller_.kp_, controller_.ki_, - controller_.kd_, controller_.output_samples_); + ESP_LOGCONFIG(TAG, + " Control Parameters:\n" + " kp: %.5f, ki: %.5f, kd: %.5f, output samples: %d", + controller_.kp_, controller_.ki_, controller_.kd_, controller_.output_samples_); if (controller_.threshold_low_ == 0 && controller_.threshold_high_ == 0) { ESP_LOGCONFIG(TAG, " Deadband disabled."); } else { - ESP_LOGCONFIG(TAG, " Deadband Parameters:"); - ESP_LOGCONFIG(TAG, " threshold: %0.5f to %0.5f, multipliers(kp: %.5f, ki: %.5f, kd: %.5f), output samples: %d", + ESP_LOGCONFIG(TAG, + " Deadband Parameters:\n" + " threshold: %0.5f to %0.5f, multipliers(kp: %.5f, ki: %.5f, kd: %.5f), " + "output samples: %d", controller_.threshold_low_, controller_.threshold_high_, controller_.kp_multiplier_, controller_.ki_multiplier_, controller_.kd_multiplier_, controller_.deadband_output_samples_); } diff --git a/esphome/components/pid/pid_climate.h b/esphome/components/pid/pid_climate.h index b5275e9775..1a09ffdd20 100644 --- a/esphome/components/pid/pid_climate.h +++ b/esphome/components/pid/pid_climate.h @@ -1,8 +1,8 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" -#include "esphome/core/automation.h" #include "esphome/components/climate/climate.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/output/float_output.h" diff --git a/esphome/components/pid/sensor/pid_climate_sensor.cpp b/esphome/components/pid/sensor/pid_climate_sensor.cpp index 2a76c775d3..41ca027d8d 100644 --- a/esphome/components/pid/sensor/pid_climate_sensor.cpp +++ b/esphome/components/pid/sensor/pid_climate_sensor.cpp @@ -1,6 +1,6 @@ #include "pid_climate_sensor.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace pid { diff --git a/esphome/components/pipsolar/output/pipsolar_output.cpp b/esphome/components/pipsolar/output/pipsolar_output.cpp index b843f1f3e6..00ec73b56a 100644 --- a/esphome/components/pipsolar/output/pipsolar_output.cpp +++ b/esphome/components/pipsolar/output/pipsolar_output.cpp @@ -1,6 +1,6 @@ #include "pipsolar_output.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace pipsolar { diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index 03c699e7d4..40405114a4 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -1,6 +1,6 @@ #include "pipsolar.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace pipsolar { @@ -861,8 +861,8 @@ void Pipsolar::switch_command(const std::string &command) { queue_command_(command.c_str(), command.length()); } void Pipsolar::dump_config() { - ESP_LOGCONFIG(TAG, "Pipsolar:"); - ESP_LOGCONFIG(TAG, "used commands:"); + ESP_LOGCONFIG(TAG, "Pipsolar:\n" + "used commands:"); for (auto &used_polling_command : this->used_polling_commands_) { if (used_polling_command.length != 0) { ESP_LOGCONFIG(TAG, "%s", used_polling_command.command); diff --git a/esphome/components/pm1006/pm1006.cpp b/esphome/components/pm1006/pm1006.cpp index f28c647721..c466c4bb25 100644 --- a/esphome/components/pm1006/pm1006.cpp +++ b/esphome/components/pm1006/pm1006.cpp @@ -95,9 +95,5 @@ void PM1006Component::parse_data_() { } } -uint16_t PM1006Component::get_16_bit_uint_(uint8_t start_index) const { - return encode_uint16(this->data_[start_index], this->data_[start_index + 1]); -} - } // namespace pm1006 } // namespace esphome diff --git a/esphome/components/pm1006/pm1006.h b/esphome/components/pm1006/pm1006.h index 238ac67006..98637dad71 100644 --- a/esphome/components/pm1006/pm1006.h +++ b/esphome/components/pm1006/pm1006.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" @@ -22,8 +23,10 @@ class PM1006Component : public PollingComponent, public uart::UARTDevice { protected: optional check_byte_() const; void parse_data_(); - uint16_t get_16_bit_uint_(uint8_t start_index) const; uint8_t pm1006_checksum_(const uint8_t *command_data, uint8_t length) const; + uint16_t get_16_bit_uint_(uint8_t start_index) const { + return encode_uint16(this->data_[start_index], this->data_[start_index + 1]); + } sensor::Sensor *pm_2_5_sensor_{nullptr}; diff --git a/esphome/components/pm2005/pm2005.cpp b/esphome/components/pm2005/pm2005.cpp index 4b00cd6f2e..57c616c4c6 100644 --- a/esphome/components/pm2005/pm2005.cpp +++ b/esphome/components/pm2005/pm2005.cpp @@ -103,8 +103,10 @@ void PM2005Component::update() { } void PM2005Component::dump_config() { - ESP_LOGCONFIG(TAG, "PM2005:"); - ESP_LOGCONFIG(TAG, " Type: PM2%u05", this->sensor_type_ == PM2105); + ESP_LOGCONFIG(TAG, + "PM2005:\n" + " Type: PM2%u05", + this->sensor_type_ == PM2105); LOG_I2C_DEVICE(this); if (this->is_failed()) { diff --git a/esphome/components/pmsa003i/pmsa003i.cpp b/esphome/components/pmsa003i/pmsa003i.cpp index 3a5473d759..4702c0cf5f 100644 --- a/esphome/components/pmsa003i/pmsa003i.cpp +++ b/esphome/components/pmsa003i/pmsa003i.cpp @@ -1,6 +1,6 @@ #include "pmsa003i.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include namespace esphome { diff --git a/esphome/components/pmsx003/pmsx003.cpp b/esphome/components/pmsx003/pmsx003.cpp index 0abed8a5a4..eb10d19c91 100644 --- a/esphome/components/pmsx003/pmsx003.cpp +++ b/esphome/components/pmsx003/pmsx003.cpp @@ -314,9 +314,5 @@ void PMSX003Component::parse_data_() { this->status_clear_warning(); } -uint16_t PMSX003Component::get_16_bit_uint_(uint8_t start_index) { - return (uint16_t(this->data_[start_index]) << 8) | uint16_t(this->data_[start_index + 1]); -} - } // namespace pmsx003 } // namespace esphome diff --git a/esphome/components/pmsx003/pmsx003.h b/esphome/components/pmsx003/pmsx003.h index 85bb1ff9f3..e422d4165b 100644 --- a/esphome/components/pmsx003/pmsx003.h +++ b/esphome/components/pmsx003/pmsx003.h @@ -1,8 +1,9 @@ #pragma once +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" -#include "esphome/core/component.h" namespace esphome { namespace pmsx003 { @@ -77,7 +78,9 @@ class PMSX003Component : public uart::UARTDevice, public Component { void parse_data_(); bool check_payload_length_(uint16_t payload_length); void send_command_(PMSX0003Command cmd, uint16_t data); - uint16_t get_16_bit_uint_(uint8_t start_index); + uint16_t get_16_bit_uint_(uint8_t start_index) const { + return encode_uint16(this->data_[start_index], this->data_[start_index + 1]); + } uint8_t data_[64]; uint8_t data_index_{0}; diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index facbd0a857..da5598bf10 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -19,7 +19,7 @@ void PN532::setup() { // Get version data if (!this->write_command_({PN532_COMMAND_VERSION_DATA})) { - ESP_LOGW(TAG, "Error sending version command, trying again..."); + ESP_LOGW(TAG, "Error sending version command, trying again"); if (!this->write_command_({PN532_COMMAND_VERSION_DATA})) { ESP_LOGE(TAG, "Error sending version command"); this->mark_failed(); @@ -208,21 +208,21 @@ void PN532::loop() { } } } else if (next_task_ == CLEAN) { - ESP_LOGD(TAG, " Tag cleaning..."); + ESP_LOGD(TAG, " Tag cleaning"); if (!this->clean_tag_(nfcid)) { ESP_LOGE(TAG, " Tag was not fully cleaned successfully"); } ESP_LOGD(TAG, " Tag cleaned!"); } else if (next_task_ == FORMAT) { - ESP_LOGD(TAG, " Tag formatting..."); + ESP_LOGD(TAG, " Tag formatting"); if (!this->format_tag_(nfcid)) { ESP_LOGE(TAG, "Error formatting tag as NDEF"); } ESP_LOGD(TAG, " Tag formatted!"); } else if (next_task_ == WRITE) { if (this->next_task_message_to_write_ != nullptr) { - ESP_LOGD(TAG, " Tag writing..."); - ESP_LOGD(TAG, " Tag formatting..."); + ESP_LOGD(TAG, " Tag writing"); + ESP_LOGD(TAG, " Tag formatting"); if (!this->format_tag_(nfcid)) { ESP_LOGE(TAG, " Tag could not be formatted for writing"); } else { @@ -281,7 +281,7 @@ bool PN532::write_command_(const std::vector &data) { } bool PN532::read_ack_() { - ESP_LOGV(TAG, "Reading ACK..."); + ESP_LOGV(TAG, "Reading ACK"); std::vector data; if (!this->read_data(data, 6)) { diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index 8194d86477..c8e9a40008 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -38,7 +38,7 @@ class PN532 : public PollingComponent { float get_setup_priority() const override; void loop() override; - void on_shutdown() override { powerdown(); } + void on_powerdown() override { powerdown(); } void register_tag(PN532BinarySensor *tag) { this->binary_sensors_.push_back(tag); } void register_ontag_trigger(nfc::NfcOnTagTrigger *trig) { this->triggers_ontag_.push_back(trig); } diff --git a/esphome/components/pn532_spi/pn532_spi.cpp b/esphome/components/pn532_spi/pn532_spi.cpp index d55d8161d8..2e66d4ed83 100644 --- a/esphome/components/pn532_spi/pn532_spi.cpp +++ b/esphome/components/pn532_spi/pn532_spi.cpp @@ -51,7 +51,7 @@ bool PN532Spi::read_data(std::vector &data, uint8_t len) { delay(2); this->write_byte(0x03); - ESP_LOGV(TAG, "Reading data..."); + ESP_LOGV(TAG, "Reading data"); data.resize(len); this->read_array(data.data(), len); diff --git a/esphome/components/pn7150/pn7150.cpp b/esphome/components/pn7150/pn7150.cpp index be4d6c1bb7..971ddd23cb 100644 --- a/esphome/components/pn7150/pn7150.cpp +++ b/esphome/components/pn7150/pn7150.cpp @@ -830,7 +830,7 @@ void PN7150::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi switch (this->next_task_) { case EP_CLEAN: - ESP_LOGD(TAG, " Tag cleaning..."); + ESP_LOGD(TAG, " Tag cleaning"); if (this->clean_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) { ESP_LOGE(TAG, " Tag cleaning incomplete"); } @@ -838,7 +838,7 @@ void PN7150::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi break; case EP_FORMAT: - ESP_LOGD(TAG, " Tag formatting..."); + ESP_LOGD(TAG, " Tag formatting"); if (this->format_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) { ESP_LOGE(TAG, "Error formatting tag as NDEF"); } @@ -847,8 +847,8 @@ void PN7150::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi case EP_WRITE: if (this->next_task_message_to_write_ != nullptr) { - ESP_LOGD(TAG, " Tag writing..."); - ESP_LOGD(TAG, " Tag formatting..."); + ESP_LOGD(TAG, " Tag writing"); + ESP_LOGD(TAG, " Tag formatting"); if (this->format_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) { ESP_LOGE(TAG, " Tag could not be formatted for writing"); } else { diff --git a/esphome/components/pn7160/pn7160.cpp b/esphome/components/pn7160/pn7160.cpp index a7d3b38fb7..2a1de20657 100644 --- a/esphome/components/pn7160/pn7160.cpp +++ b/esphome/components/pn7160/pn7160.cpp @@ -854,7 +854,7 @@ void PN7160::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi switch (this->next_task_) { case EP_CLEAN: - ESP_LOGD(TAG, " Tag cleaning..."); + ESP_LOGD(TAG, " Tag cleaning"); if (this->clean_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) { ESP_LOGE(TAG, " Tag cleaning incomplete"); } @@ -862,7 +862,7 @@ void PN7160::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi break; case EP_FORMAT: - ESP_LOGD(TAG, " Tag formatting..."); + ESP_LOGD(TAG, " Tag formatting"); if (this->format_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) { ESP_LOGE(TAG, "Error formatting tag as NDEF"); } @@ -871,8 +871,8 @@ void PN7160::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi case EP_WRITE: if (this->next_task_message_to_write_ != nullptr) { - ESP_LOGD(TAG, " Tag writing..."); - ESP_LOGD(TAG, " Tag formatting..."); + ESP_LOGD(TAG, " Tag writing"); + ESP_LOGD(TAG, " Tag formatting"); if (this->format_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) { ESP_LOGE(TAG, " Tag could not be formatted for writing"); } else { diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp index 3c449aadd5..6fbadc73ae 100644 --- a/esphome/components/power_supply/power_supply.cpp +++ b/esphome/components/power_supply/power_supply.cpp @@ -17,8 +17,10 @@ void PowerSupply::setup() { void PowerSupply::dump_config() { ESP_LOGCONFIG(TAG, "Power Supply:"); LOG_PIN(" Pin: ", this->pin_); - ESP_LOGCONFIG(TAG, " Time to enable: %" PRIu32 " ms", this->enable_time_); - ESP_LOGCONFIG(TAG, " Keep on time: %.1f s", this->keep_on_time_ / 1000.0f); + ESP_LOGCONFIG(TAG, + " Time to enable: %" PRIu32 " ms\n" + " Keep on time: %.1f s", + this->enable_time_, this->keep_on_time_ / 1000.0f); if (this->enable_on_boot_) ESP_LOGCONFIG(TAG, " Enabled at startup: True"); } @@ -50,7 +52,7 @@ void PowerSupply::unrequest_high_power() { }); } } -void PowerSupply::on_shutdown() { +void PowerSupply::on_powerdown() { this->active_requests_ = 0; this->pin_->digital_write(false); } diff --git a/esphome/components/power_supply/power_supply.h b/esphome/components/power_supply/power_supply.h index 0b06105ae9..3959f6f299 100644 --- a/esphome/components/power_supply/power_supply.h +++ b/esphome/components/power_supply/power_supply.h @@ -32,7 +32,7 @@ class PowerSupply : public Component { /// Hardware setup priority (+1). float get_setup_priority() const override; - void on_shutdown() override; + void on_powerdown() override; protected: GPIOPin *pin_; diff --git a/esphome/components/psram/__init__.py b/esphome/components/psram/__init__.py index c00cbb2ba2..9299cdcd0e 100644 --- a/esphome/components/psram/__init__.py +++ b/esphome/components/psram/__init__.py @@ -7,9 +7,12 @@ from esphome.components.esp32 import ( VARIANT_ESP32, add_idf_sdkconfig_option, get_esp32_variant, - only_on_variant, ) -from esphome.components.esp32.const import VARIANT_ESP32S2, VARIANT_ESP32S3 +from esphome.components.esp32.const import ( + VARIANT_ESP32P4, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) import esphome.config_validation as cv from esphome.const import ( CONF_ADVANCED, @@ -35,24 +38,31 @@ PsramComponent = psram_ns.class_("PsramComponent", cg.Component) TYPE_QUAD = "quad" TYPE_OCTAL = "octal" +TYPE_HEX = "hex" + +SDK_MODES = {TYPE_QUAD: "QUAD", TYPE_OCTAL: "OCT", TYPE_HEX: "HEX"} CONF_ENABLE_ECC = "enable_ecc" SPIRAM_MODES = { - TYPE_QUAD: "CONFIG_SPIRAM_MODE_QUAD", - TYPE_OCTAL: "CONFIG_SPIRAM_MODE_OCT", + VARIANT_ESP32: (TYPE_QUAD,), + VARIANT_ESP32S2: (TYPE_QUAD,), + VARIANT_ESP32S3: (TYPE_QUAD, TYPE_OCTAL), + VARIANT_ESP32P4: (TYPE_HEX,), } + SPIRAM_SPEEDS = { - 40e6: "CONFIG_SPIRAM_SPEED_40M", - 80e6: "CONFIG_SPIRAM_SPEED_80M", - 120e6: "CONFIG_SPIRAM_SPEED_120M", + VARIANT_ESP32: (40, 80, 120), + VARIANT_ESP32S2: (40, 80, 120), + VARIANT_ESP32S3: (40, 80, 120), + VARIANT_ESP32P4: (20, 100, 200), } def validate_psram_mode(config): esp32_config = fv.full_config.get()[PLATFORM_ESP32] - if config[CONF_SPEED] == 120e6: + if config[CONF_SPEED] == "120MHZ": if esp32_config[CONF_CPU_FREQUENCY] != "240MHZ": raise cv.Invalid( "PSRAM 120MHz requires 240MHz CPU frequency (set in esp32 component)" @@ -79,23 +89,23 @@ def validate_psram_mode(config): return config -CONFIG_SCHEMA = cv.All( - cv.Schema( +def get_config_schema(config): + variant = get_esp32_variant() + speeds = [f"{s}MHZ" for s in SPIRAM_SPEEDS.get(variant, [])] + if not speeds: + return cv.Invalid("PSRAM is not supported on this chip") + modes = SPIRAM_MODES[variant] + return cv.Schema( { cv.GenerateID(): cv.declare_id(PsramComponent), - cv.Optional(CONF_MODE, default=TYPE_QUAD): cv.enum( - SPIRAM_MODES, lower=True - ), + cv.Optional(CONF_MODE, default=modes[0]): cv.one_of(*modes, lower=True), cv.Optional(CONF_ENABLE_ECC, default=False): cv.boolean, - cv.Optional(CONF_SPEED, default=40e6): cv.All( - cv.frequency, cv.one_of(*SPIRAM_SPEEDS) - ), + cv.Optional(CONF_SPEED, default=speeds[0]): cv.one_of(*speeds, upper=True), } - ), - only_on_variant( - supported=[VARIANT_ESP32, VARIANT_ESP32S3, VARIANT_ESP32S2], - ), -) + )(config) + + +CONFIG_SCHEMA = get_config_schema FINAL_VALIDATE_SCHEMA = validate_psram_mode @@ -110,15 +120,23 @@ async def to_code(config): add_idf_sdkconfig_option( f"CONFIG_{get_esp32_variant().upper()}_SPIRAM_SUPPORT", True ) + add_idf_sdkconfig_option("CONFIG_SOC_SPIRAM_SUPPORTED", True) add_idf_sdkconfig_option("CONFIG_SPIRAM", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_USE", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_USE_CAPS_ALLOC", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_IGNORE_NOTFOUND", True) - add_idf_sdkconfig_option(f"{SPIRAM_MODES[config[CONF_MODE]]}", True) - add_idf_sdkconfig_option(f"{SPIRAM_SPEEDS[config[CONF_SPEED]]}", True) - if config[CONF_MODE] == TYPE_OCTAL and config[CONF_SPEED] == 120e6: + add_idf_sdkconfig_option( + f"CONFIG_SPIRAM_MODE_{SDK_MODES[config[CONF_MODE]]}", True + ) + + # Remove MHz suffix, convert to int + speed = int(config[CONF_SPEED][:-3]) + add_idf_sdkconfig_option(f"CONFIG_SPIRAM_SPEED_{speed}M", True) + add_idf_sdkconfig_option("CONFIG_SPIRAM_SPEED", speed) + if config[CONF_MODE] == TYPE_OCTAL and speed == 120: add_idf_sdkconfig_option("CONFIG_ESPTOOLPY_FLASHFREQ_120M", True) + add_idf_sdkconfig_option("CONFIG_BOOTLOADER_FLASH_DC_AWARE", True) if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(5, 4, 0): add_idf_sdkconfig_option( "CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR", True diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.cpp b/esphome/components/pulse_counter/pulse_counter_sensor.cpp index 5ad3f1fc33..bfca0c6a4e 100644 --- a/esphome/components/pulse_counter/pulse_counter_sensor.cpp +++ b/esphome/components/pulse_counter/pulse_counter_sensor.cpp @@ -171,9 +171,12 @@ void PulseCounterSensor::set_total_pulses(uint32_t pulses) { void PulseCounterSensor::dump_config() { LOG_SENSOR("", "Pulse Counter", this); LOG_PIN(" Pin: ", this->pin_); - ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode]); - ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode]); - ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %" PRIu32 " µs", this->storage_.filter_us); + ESP_LOGCONFIG(TAG, + " Rising Edge: %s\n" + " Falling Edge: %s\n" + " Filtering pulses shorter than %" PRIu32 " µs", + EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode], + EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode], this->storage_.filter_us); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp index 1856a023cc..74f63a9640 100644 --- a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +++ b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp @@ -8,11 +8,14 @@ namespace pvvx_mithermometer { static const char *const TAG = "display.pvvx_mithermometer"; void PVVXDisplay::dump_config() { - ESP_LOGCONFIG(TAG, "PVVX MiThermometer display:"); - ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent_->address_str().c_str()); - ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Characteristic UUID : %s", this->char_uuid_.to_string().c_str()); - ESP_LOGCONFIG(TAG, " Auto clear : %s", YESNO(this->auto_clear_enabled_)); + ESP_LOGCONFIG(TAG, + "PVVX MiThermometer display:\n" + " MAC address : %s\n" + " Service UUID : %s\n" + " Characteristic UUID : %s\n" + " Auto clear : %s", + this->parent_->address_str().c_str(), this->service_uuid_.to_string().c_str(), + this->char_uuid_.to_string().c_str(), YESNO(this->auto_clear_enabled_)); #ifdef USE_TIME ESP_LOGCONFIG(TAG, " Set time on connection: %s", YESNO(this->time_ != nullptr)); #endif diff --git a/esphome/components/pylontech/pylontech.cpp b/esphome/components/pylontech/pylontech.cpp index cf133742dc..ef3de069ca 100644 --- a/esphome/components/pylontech/pylontech.cpp +++ b/esphome/components/pylontech/pylontech.cpp @@ -1,6 +1,6 @@ #include "pylontech.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace pylontech { diff --git a/esphome/components/pylontech/sensor/pylontech_sensor.cpp b/esphome/components/pylontech/sensor/pylontech_sensor.cpp index 5b5db0731e..11437369ed 100644 --- a/esphome/components/pylontech/sensor/pylontech_sensor.cpp +++ b/esphome/components/pylontech/sensor/pylontech_sensor.cpp @@ -10,8 +10,10 @@ static const char *const TAG = "pylontech.sensor"; PylontechSensor::PylontechSensor(int8_t bat_num) { this->bat_num_ = bat_num; } void PylontechSensor::dump_config() { - ESP_LOGCONFIG(TAG, "Pylontech Sensor:"); - ESP_LOGCONFIG(TAG, " Battery %d", this->bat_num_); + ESP_LOGCONFIG(TAG, + "Pylontech Sensor:\n" + " Battery %d", + this->bat_num_); LOG_SENSOR(" ", "Voltage", this->voltage_sensor_); LOG_SENSOR(" ", "Current", this->current_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); diff --git a/esphome/components/pylontech/text_sensor/pylontech_text_sensor.cpp b/esphome/components/pylontech/text_sensor/pylontech_text_sensor.cpp index 9e894bc570..55e02f3e33 100644 --- a/esphome/components/pylontech/text_sensor/pylontech_text_sensor.cpp +++ b/esphome/components/pylontech/text_sensor/pylontech_text_sensor.cpp @@ -10,8 +10,10 @@ static const char *const TAG = "pylontech.textsensor"; PylontechTextSensor::PylontechTextSensor(int8_t bat_num) { this->bat_num_ = bat_num; } void PylontechTextSensor::dump_config() { - ESP_LOGCONFIG(TAG, "Pylontech Text Sensor:"); - ESP_LOGCONFIG(TAG, " Battery %d", this->bat_num_); + ESP_LOGCONFIG(TAG, + "Pylontech Text Sensor:\n" + " Battery %d", + this->bat_num_); LOG_TEXT_SENSOR(" ", "Base state", this->base_state_text_sensor_); LOG_TEXT_SENSOR(" ", "Voltage state", this->voltage_state_text_sensor_); LOG_TEXT_SENSOR(" ", "Current state", this->current_state_text_sensor_); diff --git a/esphome/components/pzemac/pzemac.cpp b/esphome/components/pzemac/pzemac.cpp index c3738d1852..0dbe0e761d 100644 --- a/esphome/components/pzemac/pzemac.cpp +++ b/esphome/components/pzemac/pzemac.cpp @@ -64,8 +64,10 @@ void PZEMAC::on_modbus_data(const std::vector &data) { void PZEMAC::update() { this->send(PZEM_CMD_READ_IN_REGISTERS, 0, PZEM_REGISTER_COUNT); } void PZEMAC::dump_config() { - ESP_LOGCONFIG(TAG, "PZEMAC:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "PZEMAC:\n" + " Address: 0x%02X", + this->address_); LOG_SENSOR("", "Voltage", this->voltage_sensor_); LOG_SENSOR("", "Current", this->current_sensor_); LOG_SENSOR("", "Power", this->power_sensor_); diff --git a/esphome/components/pzemdc/pzemdc.cpp b/esphome/components/pzemdc/pzemdc.cpp index 28e4210ff7..428bcc1fcf 100644 --- a/esphome/components/pzemdc/pzemdc.cpp +++ b/esphome/components/pzemdc/pzemdc.cpp @@ -54,8 +54,10 @@ void PZEMDC::on_modbus_data(const std::vector &data) { void PZEMDC::update() { this->send(PZEM_CMD_READ_IN_REGISTERS, 0, 8); } void PZEMDC::dump_config() { - ESP_LOGCONFIG(TAG, "PZEMDC:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "PZEMDC:\n" + " Address: 0x%02X", + this->address_); LOG_SENSOR("", "Voltage", this->voltage_sensor_); LOG_SENSOR("", "Current", this->current_sensor_); LOG_SENSOR("", "Power", this->power_sensor_); diff --git a/esphome/components/qmp6988/qmp6988.h b/esphome/components/qmp6988/qmp6988.h index f0c11adf43..61b46a4189 100644 --- a/esphome/components/qmp6988/qmp6988.h +++ b/esphome/components/qmp6988/qmp6988.h @@ -1,9 +1,9 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" diff --git a/esphome/components/qr_code/qr_code.cpp b/esphome/components/qr_code/qr_code.cpp index b60e60a4b0..c2db741e17 100644 --- a/esphome/components/qr_code/qr_code.cpp +++ b/esphome/components/qr_code/qr_code.cpp @@ -9,8 +9,10 @@ namespace qr_code { static const char *const TAG = "qr_code"; void QrCode::dump_config() { - ESP_LOGCONFIG(TAG, "QR code:"); - ESP_LOGCONFIG(TAG, " Value: '%s'", this->value_.c_str()); + ESP_LOGCONFIG(TAG, + "QR code:\n" + " Value: '%s'", + this->value_.c_str()); } void QrCode::set_value(const std::string &value) { @@ -24,7 +26,7 @@ void QrCode::set_ecc(qrcodegen_Ecc ecc) { } void QrCode::generate_qr_code() { - ESP_LOGV(TAG, "Generating QR code..."); + ESP_LOGV(TAG, "Generating QR code"); uint8_t tempbuffer[qrcodegen_BUFFER_LEN_MAX]; if (!qrcodegen_encodeText(this->value_.c_str(), tempbuffer, this->qr_, this->ecc_, qrcodegen_VERSION_MIN, diff --git a/esphome/components/qwiic_pir/qwiic_pir.cpp b/esphome/components/qwiic_pir/qwiic_pir.cpp index df9da561a2..6a5196f831 100644 --- a/esphome/components/qwiic_pir/qwiic_pir.cpp +++ b/esphome/components/qwiic_pir/qwiic_pir.cpp @@ -11,31 +11,24 @@ void QwiicPIRComponent::setup() { // Verify I2C communcation by reading and verifying the chip ID uint8_t chip_id; - if (!this->read_byte(QWIIC_PIR_CHIP_ID, &chip_id)) { - ESP_LOGE(TAG, "Failed to read the chip's ID"); - + ESP_LOGE(TAG, "Failed to read chip ID"); this->error_code_ = ERROR_COMMUNICATION_FAILED; this->mark_failed(); - return; } if (chip_id != QWIIC_PIR_DEVICE_ID) { - ESP_LOGE(TAG, "Unknown chip ID, is this a Qwiic PIR?"); - + ESP_LOGE(TAG, "Unknown chip ID"); this->error_code_ = ERROR_WRONG_CHIP_ID; this->mark_failed(); - return; } if (!this->write_byte_16(QWIIC_PIR_DEBOUNCE_TIME, this->debounce_time_)) { - ESP_LOGE(TAG, "Failed to configure debounce time."); - + ESP_LOGE(TAG, "Failed to configure debounce time"); this->error_code_ = ERROR_COMMUNICATION_FAILED; this->mark_failed(); - return; } @@ -43,11 +36,9 @@ void QwiicPIRComponent::setup() { // Publish the starting raw state of the PIR sensor // If NATIVE mode, the binary_sensor state would be unknown until a motion event if (!this->read_byte(QWIIC_PIR_EVENT_STATUS, &this->event_register_.reg)) { - ESP_LOGE(TAG, "Failed to read initial sensor state."); - + ESP_LOGE(TAG, "Failed to read initial state"); this->error_code_ = ERROR_COMMUNICATION_FAILED; this->mark_failed(); - return; } @@ -59,7 +50,6 @@ void QwiicPIRComponent::loop() { // Read Event Register if (!this->read_byte(QWIIC_PIR_EVENT_STATUS, &this->event_register_.reg)) { ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL); - return; } @@ -98,39 +88,47 @@ void QwiicPIRComponent::loop() { } void QwiicPIRComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Qwiic PIR:"); + static const char *const RAW = "RAW"; + static const char *const NATIVE = "NATIVE"; + static const char *const HYBRID = "HYBRID"; - if (this->debounce_mode_ == RAW_DEBOUNCE_MODE) { - ESP_LOGCONFIG(TAG, " Debounce Mode: RAW"); - } else if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) { - ESP_LOGCONFIG(TAG, " Debounce Mode: NATIVE"); - ESP_LOGCONFIG(TAG, " Debounce Time: %ums", this->debounce_time_); + const char *debounce_mode_str = RAW; + if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) { + debounce_mode_str = NATIVE; } else if (this->debounce_mode_ == HYBRID_DEBOUNCE_MODE) { - ESP_LOGCONFIG(TAG, " Debounce Mode: HYBRID"); + debounce_mode_str = HYBRID; + } + + ESP_LOGCONFIG(TAG, + "Qwiic PIR:\n" + " Debounce Mode: %s", + debounce_mode_str); + if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) { + ESP_LOGCONFIG(TAG, " Debounce Time: %ums", this->debounce_time_); } switch (this->error_code_) { case NONE: break; case ERROR_COMMUNICATION_FAILED: - ESP_LOGE(TAG, " Communication with Qwiic PIR failed!"); + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); break; case ERROR_WRONG_CHIP_ID: - ESP_LOGE(TAG, " Qwiic PIR has wrong chip ID - please verify you are using a Qwiic PIR"); + ESP_LOGE(TAG, "Unknown chip ID"); break; default: - ESP_LOGE(TAG, " Qwiic PIR error code %d", (int) this->error_code_); + ESP_LOGE(TAG, "Error %d", (int) this->error_code_); break; } LOG_I2C_DEVICE(this); - LOG_BINARY_SENSOR(" ", "Qwiic PIR Binary Sensor", this); + LOG_BINARY_SENSOR(" ", "Binary Sensor", this); } void QwiicPIRComponent::clear_events_() { // Clear event status register if (!this->write_byte(QWIIC_PIR_EVENT_STATUS, 0x00)) - ESP_LOGW(TAG, "Failed to clear events on sensor"); + ESP_LOGW(TAG, "Failed to clear events"); } } // namespace qwiic_pir diff --git a/esphome/components/rc522/rc522.cpp b/esphome/components/rc522/rc522.cpp index e2146dd14e..018b714190 100644 --- a/esphome/components/rc522/rc522.cpp +++ b/esphome/components/rc522/rc522.cpp @@ -46,7 +46,7 @@ void RC522::setup() { reset_pin_->pin_mode(gpio::FLAG_INPUT); if (!reset_pin_->digital_read()) { // The MFRC522 chip is in power down mode. - ESP_LOGV(TAG, "Power down mode detected. Hard resetting..."); + ESP_LOGV(TAG, "Power down mode detected. Hard resetting"); reset_pin_->pin_mode(gpio::FLAG_OUTPUT); // Now set the resetPowerDownPin as digital output. reset_pin_->digital_write(false); // Make sure we have a clean LOW state. delayMicroseconds(2); // 8.8.1 Reset timing requirements says about 100ns. Let us be generous: 2μsl @@ -101,7 +101,7 @@ void RC522::dump_config() { case NONE: break; case RESET_FAILED: - ESP_LOGE(TAG, "Reset command failed!"); + ESP_LOGE(TAG, "Reset command failed"); break; } @@ -292,7 +292,7 @@ void RC522::pcd_reset_() { return; if (reset_count_ == RESET_COUNT) { - ESP_LOGI(TAG, "Soft reset..."); + ESP_LOGI(TAG, "Soft reset"); // Issue the SoftReset command. pcd_write_register(COMMAND_REG, PCD_SOFT_RESET); } @@ -300,14 +300,14 @@ void RC522::pcd_reset_() { // Expect the PowerDown bit in CommandReg to be cleared (max 3x50ms) if ((pcd_read_register(COMMAND_REG) & (1 << 4)) == 0) { reset_count_ = 0; - ESP_LOGI(TAG, "Device online."); + ESP_LOGI(TAG, "Device online"); // Wait for initialize reset_timeout_ = millis(); return; } if (--reset_count_ == 0) { - ESP_LOGE(TAG, "Unable to reset RC522."); + ESP_LOGE(TAG, "Unable to reset"); this->error_code_ = RESET_FAILED; mark_failed(); } diff --git a/esphome/components/rdm6300/rdm6300.cpp b/esphome/components/rdm6300/rdm6300.cpp index bfdd880079..f9b6126c4b 100644 --- a/esphome/components/rdm6300/rdm6300.cpp +++ b/esphome/components/rdm6300/rdm6300.cpp @@ -1,4 +1,5 @@ #include "rdm6300.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 8c21cb210c..6994eebd91 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -1,6 +1,6 @@ from esphome import pins import esphome.codegen as cg -from esphome.components import esp32_rmt, remote_base +from esphome.components import esp32, esp32_rmt, remote_base import esphome.config_validation as cv from esphome.const import ( CONF_BUFFER_SIZE, @@ -128,7 +128,9 @@ CONFIG_SCHEMA = remote_base.validate_triggers( esp32_idf=192, esp32_s2_idf=192, esp32_s3_idf=192, + esp32_p4_idf=192, esp32_c3_idf=96, + esp32_c5_idf=96, esp32_c6_idf=96, esp32_h2_idf=96, ): cv.All(cv.only_with_esp_idf, cv.int_range(min=2)), @@ -139,7 +141,13 @@ CONFIG_SCHEMA = remote_base.validate_triggers( CONF_RECEIVE_SYMBOLS, esp32_idf=192, ): cv.All(cv.only_with_esp_idf, cv.int_range(min=2)), - cv.Optional(CONF_USE_DMA): cv.All(cv.only_with_esp_idf, cv.boolean), + cv.Optional(CONF_USE_DMA): cv.All( + esp32.only_on_variant( + supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] + ), + cv.only_with_esp_idf, + cv.boolean, + ), } ).extend(cv.COMPONENT_SCHEMA) ) diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index 18bf01c8e8..b78928d857 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -161,23 +161,33 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, "Remote Receiver:"); LOG_PIN(" Pin: ", this->pin_); #if ESP_IDF_VERSION_MAJOR >= 5 - ESP_LOGCONFIG(TAG, " Clock resolution: %" PRIu32 " hz", this->clock_resolution_); - ESP_LOGCONFIG(TAG, " RMT symbols: %" PRIu32, this->rmt_symbols_); - ESP_LOGCONFIG(TAG, " Filter symbols: %" PRIu32, this->filter_symbols_); - ESP_LOGCONFIG(TAG, " Receive symbols: %" PRIu32, this->receive_symbols_); + ESP_LOGCONFIG(TAG, + " Clock resolution: %" PRIu32 " hz\n" + " RMT symbols: %" PRIu32 "\n" + " Filter symbols: %" PRIu32 "\n" + " Receive symbols: %" PRIu32 "\n" + " Tolerance: %" PRIu32 "%s\n" + " Filter out pulses shorter than: %" PRIu32 " us\n" + " Signal is done after %" PRIu32 " us of no changes", + this->clock_resolution_, this->rmt_symbols_, this->filter_symbols_, this->receive_symbols_, + this->tolerance_, (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", + this->filter_us_, this->idle_us_); #else if (this->pin_->digital_read()) { ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " "invert the signal using 'inverted: True' in the pin schema!"); } - ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); - ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_); - ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); + ESP_LOGCONFIG(TAG, + " Channel: %d\n" + " RMT memory blocks: %d\n" + " Clock divider: %u\n" + " Tolerance: %" PRIu32 "%s\n" + " Filter out pulses shorter than: %" PRIu32 " us\n" + " Signal is done after %" PRIu32 " us of no changes", + this->channel_, this->mem_block_num_, this->clock_divider_, this->tolerance_, + (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", this->filter_us_, + this->idle_us_); #endif - ESP_LOGCONFIG(TAG, " Tolerance: %" PRIu32 "%s", this->tolerance_, - (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%"); - ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_); - ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_); if (this->is_failed()) { ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_), this->error_string_.c_str()); diff --git a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp index 4c743a6eed..a0fd56bcf4 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp @@ -1,7 +1,7 @@ #include "remote_receiver.h" #include "esphome/core/hal.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ESP8266 @@ -63,11 +63,14 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " "invert the signal using 'inverted: True' in the pin schema!"); } - ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_); - ESP_LOGCONFIG(TAG, " Tolerance: %u%s", this->tolerance_, - (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%"); - ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); - ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); + ESP_LOGCONFIG(TAG, + " Buffer Size: %u\n" + " Tolerance: %u%s\n" + " Filter out pulses shorter than: %u us\n" + " Signal is done after %u us of no changes", + this->buffer_size_, this->tolerance_, + (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", this->filter_us_, + this->idle_us_); } void RemoteReceiverComponent::loop() { diff --git a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp index fe84799cae..7a6054737e 100644 --- a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp +++ b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp @@ -1,7 +1,7 @@ #include "remote_receiver.h" #include "esphome/core/hal.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_LIBRETINY @@ -63,11 +63,14 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " "invert the signal using 'inverted: True' in the pin schema!"); } - ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_); - ESP_LOGCONFIG(TAG, " Tolerance: %u%s", this->tolerance_, - (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%"); - ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); - ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); + ESP_LOGCONFIG(TAG, + " Buffer Size: %u\n" + " Tolerance: %u%s\n" + " Filter out pulses shorter than: %u us\n" + " Signal is done after %u us of no changes", + this->buffer_size_, this->tolerance_, + (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%", this->filter_us_, + this->idle_us_); } void RemoteReceiverComponent::loop() { diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py index e7a94c175e..4db24760d8 100644 --- a/esphome/components/remote_transmitter/__init__.py +++ b/esphome/components/remote_transmitter/__init__.py @@ -1,6 +1,6 @@ from esphome import automation, pins import esphome.codegen as cg -from esphome.components import esp32_rmt, remote_base +from esphome.components import esp32, esp32_rmt, remote_base import esphome.config_validation as cv from esphome.const import ( CONF_CARRIER_DUTY_PERCENT, @@ -45,13 +45,21 @@ CONFIG_SCHEMA = cv.Schema( cv.only_on_esp32, cv.only_with_arduino, cv.int_range(min=1, max=255) ), cv.Optional(CONF_EOT_LEVEL): cv.All(cv.only_with_esp_idf, cv.boolean), - cv.Optional(CONF_USE_DMA): cv.All(cv.only_with_esp_idf, cv.boolean), + cv.Optional(CONF_USE_DMA): cv.All( + esp32.only_on_variant( + supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4] + ), + cv.only_with_esp_idf, + cv.boolean, + ), cv.SplitDefault( CONF_RMT_SYMBOLS, esp32_idf=64, esp32_s2_idf=64, esp32_s3_idf=48, + esp32_p4_idf=48, esp32_c3_idf=48, + esp32_c5_idf=48, esp32_c6_idf=48, esp32_h2_idf=48, ): cv.All(cv.only_with_esp_idf, cv.int_range(min=2)), diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp index a5512c2a55..d51c45c607 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp @@ -19,12 +19,16 @@ void RemoteTransmitterComponent::setup() { void RemoteTransmitterComponent::dump_config() { ESP_LOGCONFIG(TAG, "Remote Transmitter:"); #if ESP_IDF_VERSION_MAJOR >= 5 - ESP_LOGCONFIG(TAG, " Clock resolution: %" PRIu32 " hz", this->clock_resolution_); - ESP_LOGCONFIG(TAG, " RMT symbols: %" PRIu32, this->rmt_symbols_); + ESP_LOGCONFIG(TAG, + " Clock resolution: %" PRIu32 " hz\n" + " RMT symbols: %" PRIu32, + this->clock_resolution_, this->rmt_symbols_); #else - ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); - ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_); - ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); + ESP_LOGCONFIG(TAG, + " Channel: %d\n" + " RMT memory blocks: %d\n" + " Clock divider: %u", + this->channel_, this->mem_block_num_, this->clock_divider_); #endif LOG_PIN(" Pin: ", this->pin_); diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp index 09cc16e975..73a1a7754f 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp @@ -15,8 +15,10 @@ void RemoteTransmitterComponent::setup() { } void RemoteTransmitterComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Remote Transmitter..."); - ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_); + ESP_LOGCONFIG(TAG, + "Remote Transmitter:\n" + " Carrier Duty: %u%%", + this->carrier_duty_percent_); LOG_PIN(" Pin: ", this->pin_); } @@ -72,7 +74,7 @@ void RemoteTransmitterComponent::space_(uint32_t usec) { } void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { - ESP_LOGD(TAG, "Sending remote code..."); + ESP_LOGD(TAG, "Sending remote code"); uint32_t on_time, off_time; this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time); this->target_time_ = 0; diff --git a/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp b/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp index 20d8736c00..42bf5bd95b 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp @@ -15,8 +15,10 @@ void RemoteTransmitterComponent::setup() { } void RemoteTransmitterComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Remote Transmitter..."); - ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_); + ESP_LOGCONFIG(TAG, + "Remote Transmitter:\n" + " Carrier Duty: %u%%", + this->carrier_duty_percent_); LOG_PIN(" Pin: ", this->pin_); } @@ -74,7 +76,7 @@ void RemoteTransmitterComponent::space_(uint32_t usec) { } void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { - ESP_LOGD(TAG, "Sending remote code..."); + ESP_LOGD(TAG, "Sending remote code"); uint32_t on_time, off_time; this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time); this->target_time_ = 0; diff --git a/esphome/components/resistance/resistance_sensor.cpp b/esphome/components/resistance/resistance_sensor.cpp index e13959fd37..6e57214449 100644 --- a/esphome/components/resistance/resistance_sensor.cpp +++ b/esphome/components/resistance/resistance_sensor.cpp @@ -8,9 +8,12 @@ static const char *const TAG = "resistance"; void ResistanceSensor::dump_config() { LOG_SENSOR("", "Resistance Sensor", this); - ESP_LOGCONFIG(TAG, " Configuration: %s", this->configuration_ == UPSTREAM ? "UPSTREAM" : "DOWNSTREAM"); - ESP_LOGCONFIG(TAG, " Resistor: %.2fΩ", this->resistor_); - ESP_LOGCONFIG(TAG, " Reference Voltage: %.1fV", this->reference_voltage_); + ESP_LOGCONFIG(TAG, + " Configuration: %s\n" + " Resistor: %.2fΩ\n" + " Reference Voltage: %.1fV", + this->configuration_ == UPSTREAM ? "UPSTREAM" : "DOWNSTREAM", this->resistor_, + this->reference_voltage_); } void ResistanceSensor::process_(float value) { if (std::isnan(value)) { diff --git a/esphome/components/restart/button/restart_button.cpp b/esphome/components/restart/button/restart_button.cpp index d8ff061355..accb1a8356 100644 --- a/esphome/components/restart/button/restart_button.cpp +++ b/esphome/components/restart/button/restart_button.cpp @@ -9,7 +9,7 @@ namespace restart { static const char *const TAG = "restart.button"; void RestartButton::press_action() { - ESP_LOGI(TAG, "Restarting device..."); + ESP_LOGI(TAG, "Restarting device"); // Let MQTT settle a bit delay(100); // NOLINT App.safe_reboot(); diff --git a/esphome/components/restart/switch/restart_switch.cpp b/esphome/components/restart/switch/restart_switch.cpp index 3076fde99e..422e85f4cd 100644 --- a/esphome/components/restart/switch/restart_switch.cpp +++ b/esphome/components/restart/switch/restart_switch.cpp @@ -13,7 +13,7 @@ void RestartSwitch::write_state(bool state) { this->publish_state(false); if (state) { - ESP_LOGI(TAG, "Restarting device..."); + ESP_LOGI(TAG, "Restarting device"); // Let MQTT settle a bit delay(100); // NOLINT App.safe_reboot(); diff --git a/esphome/components/rotary_encoder/rotary_encoder.cpp b/esphome/components/rotary_encoder/rotary_encoder.cpp index 9a9c3a6338..79bc123597 100644 --- a/esphome/components/rotary_encoder/rotary_encoder.cpp +++ b/esphome/components/rotary_encoder/rotary_encoder.cpp @@ -1,6 +1,6 @@ #include "rotary_encoder.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace rotary_encoder { diff --git a/esphome/components/rp2040/gpio.cpp b/esphome/components/rp2040/gpio.cpp index e32b93b5c2..3927815e46 100644 --- a/esphome/components/rp2040/gpio.cpp +++ b/esphome/components/rp2040/gpio.cpp @@ -8,7 +8,7 @@ namespace rp2040 { static const char *const TAG = "rp2040"; -static int IRAM_ATTR flags_to_mode(gpio::Flags flags, uint8_t pin) { +static int flags_to_mode(gpio::Flags flags, uint8_t pin) { if (flags == gpio::FLAG_INPUT) { // NOLINT(bugprone-branch-clone) return INPUT; } else if (flags == gpio::FLAG_OUTPUT) { @@ -25,14 +25,16 @@ static int IRAM_ATTR flags_to_mode(gpio::Flags flags, uint8_t pin) { } struct ISRPinArg { + uint32_t mask; uint8_t pin; bool inverted; }; ISRInternalGPIOPin RP2040GPIOPin::to_isr() const { auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory) - arg->pin = pin_; - arg->inverted = inverted_; + arg->pin = this->pin_; + arg->inverted = this->inverted_; + arg->mask = 1 << this->pin_; return ISRInternalGPIOPin((void *) arg); } @@ -81,21 +83,36 @@ void RP2040GPIOPin::detach_interrupt() const { detachInterrupt(pin_); } using namespace rp2040; bool IRAM_ATTR ISRInternalGPIOPin::digital_read() { - auto *arg = reinterpret_cast(arg_); - return bool(digitalRead(arg->pin)) != arg->inverted; // NOLINT + auto *arg = reinterpret_cast(this->arg_); + return bool(sio_hw->gpio_in & arg->mask) != arg->inverted; } + void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) { - auto *arg = reinterpret_cast(arg_); - digitalWrite(arg->pin, value != arg->inverted ? 1 : 0); // NOLINT + auto *arg = reinterpret_cast(this->arg_); + if (value != arg->inverted) { + sio_hw->gpio_set = arg->mask; + } else { + sio_hw->gpio_clr = arg->mask; + } } + void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { // TODO: implement // auto *arg = reinterpret_cast(arg_); // GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin); } + void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) { - auto *arg = reinterpret_cast(arg_); - pinMode(arg->pin, flags_to_mode(flags, arg->pin)); // NOLINT + auto *arg = reinterpret_cast(this->arg_); + if (flags & gpio::FLAG_OUTPUT) { + sio_hw->gpio_oe_set = arg->mask; + } else if (flags & gpio::FLAG_INPUT) { + sio_hw->gpio_oe_clr = arg->mask; + hw_write_masked(&padsbank0_hw->io[arg->pin], + (bool_to_bit(flags & gpio::FLAG_PULLUP) << PADS_BANK0_GPIO0_PUE_LSB) | + (bool_to_bit(flags & gpio::FLAG_PULLDOWN) << PADS_BANK0_GPIO0_PDE_LSB), + PADS_BANK0_GPIO0_PUE_BITS | PADS_BANK0_GPIO0_PDE_BITS); + } } } // namespace esphome diff --git a/esphome/components/rp2040/preferences.cpp b/esphome/components/rp2040/preferences.cpp index e7aa9ab28d..cbf2b00641 100644 --- a/esphome/components/rp2040/preferences.cpp +++ b/esphome/components/rp2040/preferences.cpp @@ -87,7 +87,7 @@ class RP2040Preferences : public ESPPreferences { RP2040Preferences() : eeprom_sector_(&_EEPROM_start) {} void setup() { s_flash_storage = new uint8_t[RP2040_FLASH_STORAGE_SIZE]; // NOLINT - ESP_LOGVV(TAG, "Loading preferences from flash..."); + ESP_LOGVV(TAG, "Loading preferences from flash"); memcpy(s_flash_storage, this->eeprom_sector_, RP2040_FLASH_STORAGE_SIZE); } @@ -114,7 +114,7 @@ class RP2040Preferences : public ESPPreferences { if (s_prevent_write) return false; - ESP_LOGD(TAG, "Saving preferences to flash..."); + ESP_LOGD(TAG, "Saving"); { InterruptLock lock; @@ -129,7 +129,7 @@ class RP2040Preferences : public ESPPreferences { } bool reset() override { - ESP_LOGD(TAG, "Cleaning up preferences in flash..."); + ESP_LOGD(TAG, "Erasing storage"); { InterruptLock lock; ::rp2040.idleOtherCore(); diff --git a/esphome/components/rp2040_pio_led_strip/led_strip.cpp b/esphome/components/rp2040_pio_led_strip/led_strip.cpp index b675277914..a6ff037d88 100644 --- a/esphome/components/rp2040_pio_led_strip/led_strip.cpp +++ b/esphome/components/rp2040_pio_led_strip/led_strip.cpp @@ -138,7 +138,7 @@ void RP2040PIOLEDStripLightOutput::setup() { } void RP2040PIOLEDStripLightOutput::write_state(light::LightState *state) { - ESP_LOGVV(TAG, "Writing state..."); + ESP_LOGVV(TAG, "Writing state"); if (this->is_failed()) { ESP_LOGW(TAG, "Light is in failed state, not writing state."); @@ -199,12 +199,15 @@ light::ESPColorView RP2040PIOLEDStripLightOutput::get_view_internal(int32_t inde } void RP2040PIOLEDStripLightOutput::dump_config() { - ESP_LOGCONFIG(TAG, "RP2040 PIO LED Strip Light Output:"); - ESP_LOGCONFIG(TAG, " Pin: GPIO%d", this->pin_); - ESP_LOGCONFIG(TAG, " Number of LEDs: %d", this->num_leds_); - ESP_LOGCONFIG(TAG, " RGBW: %s", YESNO(this->is_rgbw_)); - ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order_to_string(this->rgb_order_)); - ESP_LOGCONFIG(TAG, " Max Refresh Rate: %f Hz", this->max_refresh_rate_); + ESP_LOGCONFIG(TAG, + "RP2040 PIO LED Strip Light Output:\n" + " Pin: GPIO%d\n" + " Number of LEDs: %d\n" + " RGBW: %s\n" + " RGB Order: %s\n" + " Max Refresh Rate: %f Hz", + this->pin_, this->num_leds_, YESNO(this->is_rgbw_), rgb_order_to_string(this->rgb_order_), + this->max_refresh_rate_); } float RP2040PIOLEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; } diff --git a/esphome/components/rp2040_pio_led_strip/light.py b/esphome/components/rp2040_pio_led_strip/light.py index 4b6a80e78b..9107db9b7f 100644 --- a/esphome/components/rp2040_pio_led_strip/light.py +++ b/esphome/components/rp2040_pio_led_strip/light.py @@ -173,7 +173,7 @@ RGB_ORDERS = { CHIPSET_TIMINGS = { "WS2812": LEDStripTimings(20, 40, 46, 34), "WS2812B": LEDStripTimings(23, 49, 46, 26), - "SK6812": LEDStripTimings(17, 52, 34, 34), + "SK6812": LEDStripTimings(20, 54, 38, 38), "SM16703": LEDStripTimings(17, 52, 52, 17), } diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index 6b7071609f..e24816fd83 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -27,8 +27,10 @@ inline double deg2rad(double degrees) { } void Rtttl::dump_config() { - ESP_LOGCONFIG(TAG, "Rtttl:"); - ESP_LOGCONFIG(TAG, " Gain: %f", this->gain_); + ESP_LOGCONFIG(TAG, + "Rtttl:\n" + " Gain: %f", + this->gain_); } void Rtttl::play(std::string rtttl) { diff --git a/esphome/components/safe_mode/safe_mode.cpp b/esphome/components/safe_mode/safe_mode.cpp index 245d217501..89c9242357 100644 --- a/esphome/components/safe_mode/safe_mode.cpp +++ b/esphome/components/safe_mode/safe_mode.cpp @@ -16,10 +16,12 @@ static const char *const TAG = "safe_mode"; void SafeModeComponent::dump_config() { ESP_LOGCONFIG(TAG, "Safe Mode:"); - ESP_LOGCONFIG(TAG, " Boot considered successful after %" PRIu32 " seconds", - this->safe_mode_boot_is_good_after_ / 1000); // because milliseconds - ESP_LOGCONFIG(TAG, " Invoke after %u boot attempts", this->safe_mode_num_attempts_); - ESP_LOGCONFIG(TAG, " Remain for %" PRIu32 " seconds", + ESP_LOGCONFIG(TAG, + " Boot considered successful after %" PRIu32 " seconds\n" + " Invoke after %u boot attempts\n" + " Remain for %" PRIu32 " seconds", + this->safe_mode_boot_is_good_after_ / 1000, // because milliseconds + this->safe_mode_num_attempts_, this->safe_mode_enable_time_ / 1000); // because milliseconds if (this->safe_mode_rtc_value_ > 1 && this->safe_mode_rtc_value_ != SafeModeComponent::ENTER_SAFE_MODE_MAGIC) { diff --git a/esphome/components/scd30/scd30.cpp b/esphome/components/scd30/scd30.cpp index a7283eb680..8561732d8b 100644 --- a/esphome/components/scd30/scd30.cpp +++ b/esphome/components/scd30/scd30.cpp @@ -140,10 +140,13 @@ void SCD30Component::dump_config() { } else { ESP_LOGCONFIG(TAG, " Altitude compensation: %dm", this->altitude_compensation_); } - ESP_LOGCONFIG(TAG, " Automatic self calibration: %s", ONOFF(this->enable_asc_)); - ESP_LOGCONFIG(TAG, " Ambient pressure compensation: %dmBar", this->ambient_pressure_compensation_); - ESP_LOGCONFIG(TAG, " Temperature offset: %.2f °C", this->temperature_offset_); - ESP_LOGCONFIG(TAG, " Update interval: %ds", this->update_interval_); + ESP_LOGCONFIG(TAG, + " Automatic self calibration: %s\n" + " Ambient pressure compensation: %dmBar\n" + " Temperature offset: %.2f °C\n" + " Update interval: %ds", + ONOFF(this->enable_asc_), this->ambient_pressure_compensation_, this->temperature_offset_, + this->update_interval_); LOG_SENSOR(" ", "CO2", this->co2_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); diff --git a/esphome/components/scd4x/scd4x.cpp b/esphome/components/scd4x/scd4x.cpp index 8cd81f802f..f617ffe276 100644 --- a/esphome/components/scd4x/scd4x.cpp +++ b/esphome/components/scd4x/scd4x.cpp @@ -115,11 +115,15 @@ void SCD4XComponent::dump_config() { this->ambient_pressure_source_->get_name().c_str()); } else { if (this->ambient_pressure_compensation_) { - ESP_LOGCONFIG(TAG, " Altitude compensation disabled"); - ESP_LOGCONFIG(TAG, " Ambient pressure compensation: %dmBar", this->ambient_pressure_); + ESP_LOGCONFIG(TAG, + " Altitude compensation disabled\n" + " Ambient pressure compensation: %dmBar", + this->ambient_pressure_); } else { - ESP_LOGCONFIG(TAG, " Ambient pressure compensation disabled"); - ESP_LOGCONFIG(TAG, " Altitude compensation: %dm", this->altitude_compensation_); + ESP_LOGCONFIG(TAG, + " Ambient pressure compensation disabled\n" + " Altitude compensation: %dm", + this->altitude_compensation_); } } switch (this->measurement_mode_) { diff --git a/esphome/components/sdl/display.py b/esphome/components/sdl/display.py index 66709cc834..ae8b0fd43a 100644 --- a/esphome/components/sdl/display.py +++ b/esphome/components/sdl/display.py @@ -8,16 +8,28 @@ from esphome.const import ( CONF_HEIGHT, CONF_ID, CONF_LAMBDA, + CONF_POSITION, CONF_WIDTH, + CONF_X, + CONF_Y, PLATFORM_HOST, ) sdl_ns = cg.esphome_ns.namespace("sdl") Sdl = sdl_ns.class_("Sdl", display.Display, cg.Component) +sdl_window_flags = cg.global_ns.enum("SDL_WindowFlags") CONF_SDL_OPTIONS = "sdl_options" CONF_SDL_ID = "sdl_id" +CONF_WINDOW_OPTIONS = "window_options" +WINDOW_OPTIONS = ( + "borderless", + "always_on_top", + "fullscreen", + "skip_taskbar", + "resizable", +) def get_sdl_options(value): @@ -29,6 +41,10 @@ def get_sdl_options(value): raise cv.Invalid("Unable to run sdl2-config - have you installed sdl2?") from e +def get_window_options(): + return {cv.Optional(option, default=False): cv.boolean for option in WINDOW_OPTIONS} + + CONFIG_SCHEMA = cv.All( display.FULL_DISPLAY_SCHEMA.extend( cv.Schema( @@ -44,6 +60,17 @@ CONFIG_SCHEMA = cv.All( } ), ), + cv.Optional(CONF_WINDOW_OPTIONS): cv.Schema( + { + cv.Optional(CONF_POSITION): cv.Schema( + { + cv.Required(CONF_X): cv.int_, + cv.Required(CONF_Y): cv.int_, + } + ), + **get_window_options(), + } + ), } ) ), @@ -65,6 +92,19 @@ async def to_code(config): (width, height) = dimensions cg.add(var.set_dimensions(width, height)) + if window_options := config.get(CONF_WINDOW_OPTIONS): + create_flags = 0 + for option in WINDOW_OPTIONS: + value = window_options.get(option, False) + if value: + create_flags = create_flags | getattr( + sdl_window_flags, "SDL_WINDOW_" + option.upper() + ) + cg.add(var.set_window_options(create_flags)) + + if position := window_options.get(CONF_POSITION): + cg.add(var.set_position(position[CONF_X], position[CONF_Y])) + if lamb := config.get(CONF_LAMBDA): lambda_ = await cg.process_lambda( lamb, [(display.DisplayRef, "it")], return_type=cg.void diff --git a/esphome/components/sdl/sdl_esphome.cpp b/esphome/components/sdl/sdl_esphome.cpp index 42dfe687e9..e55bff58fe 100644 --- a/esphome/components/sdl/sdl_esphome.cpp +++ b/esphome/components/sdl/sdl_esphome.cpp @@ -8,8 +8,8 @@ namespace sdl { void Sdl::setup() { ESP_LOGD(TAG, "Starting setup"); SDL_Init(SDL_INIT_VIDEO); - this->window_ = SDL_CreateWindow(App.get_name().c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - this->width_, this->height_, SDL_WINDOW_RESIZABLE); + this->window_ = SDL_CreateWindow(App.get_name().c_str(), this->pos_x_, this->pos_y_, this->width_, this->height_, + this->window_options_); this->renderer_ = SDL_CreateRenderer(this->window_, -1, SDL_RENDERER_SOFTWARE); SDL_RenderSetLogicalSize(this->renderer_, this->width_, this->height_); this->texture_ = diff --git a/esphome/components/sdl/sdl_esphome.h b/esphome/components/sdl/sdl_esphome.h index 39ea3ed417..bf5fde1428 100644 --- a/esphome/components/sdl/sdl_esphome.h +++ b/esphome/components/sdl/sdl_esphome.h @@ -28,6 +28,11 @@ class Sdl : public display::Display { this->width_ = width; this->height_ = height; } + void set_window_options(uint32_t window_options) { this->window_options_ = window_options; } + void set_position(uint16_t pos_x, uint16_t pos_y) { + this->pos_x_ = pos_x; + this->pos_y_ = pos_y; + } int get_width() override { return this->width_; } int get_height() override { return this->height_; } float get_setup_priority() const override { return setup_priority::HARDWARE; } @@ -49,6 +54,9 @@ class Sdl : public display::Display { void redraw_(SDL_Rect &rect); int width_{}; int height_{}; + uint32_t window_options_{0}; + int pos_x_{SDL_WINDOWPOS_UNDEFINED}; + int pos_y_{SDL_WINDOWPOS_UNDEFINED}; SDL_Renderer *renderer_{}; SDL_Window *window_{}; SDL_Texture *texture_{}; diff --git a/esphome/components/sdm_meter/sdm_meter.cpp b/esphome/components/sdm_meter/sdm_meter.cpp index 18e06e2b04..12a3277269 100644 --- a/esphome/components/sdm_meter/sdm_meter.cpp +++ b/esphome/components/sdm_meter/sdm_meter.cpp @@ -1,5 +1,6 @@ #include "sdm_meter.h" #include "sdm_meter_registers.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { @@ -84,8 +85,10 @@ void SDMMeter::on_modbus_data(const std::vector &data) { void SDMMeter::update() { this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT); } void SDMMeter::dump_config() { - ESP_LOGCONFIG(TAG, "SDM Meter:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "SDM Meter:\n" + " Address: 0x%02X", + this->address_); for (uint8_t i = 0; i < 3; i++) { auto phase = this->phases_[i]; if (!phase.setup) diff --git a/esphome/components/sdp3x/sdp3x.cpp b/esphome/components/sdp3x/sdp3x.cpp index 7a957e55ac..58aefe09d7 100644 --- a/esphome/components/sdp3x/sdp3x.cpp +++ b/esphome/components/sdp3x/sdp3x.cpp @@ -1,7 +1,7 @@ #include "sdp3x.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace sdp3x { @@ -17,31 +17,31 @@ static const uint16_t SDP3X_STOP_MEAS = 0x3FF9; void SDP3XComponent::update() { this->read_pressure_(); } void SDP3XComponent::setup() { - ESP_LOGD(TAG, "Setting up SDP3X..."); + ESP_LOGCONFIG(TAG, "Running setup"); if (!this->write_command(SDP3X_STOP_MEAS)) { - ESP_LOGW(TAG, "Stop SDP3X failed!"); // This sometimes fails for no good reason + ESP_LOGW(TAG, "Stop failed"); // This sometimes fails for no good reason } if (!this->write_command(SDP3X_SOFT_RESET)) { - ESP_LOGW(TAG, "Soft Reset SDP3X failed!"); // This sometimes fails for no good reason + ESP_LOGW(TAG, "Soft Reset failed"); // This sometimes fails for no good reason } this->set_timeout(20, [this] { if (!this->write_command(SDP3X_READ_ID1)) { - ESP_LOGE(TAG, "Read ID1 SDP3X failed!"); + ESP_LOGE(TAG, "Read ID1 failed"); this->mark_failed(); return; } if (!this->write_command(SDP3X_READ_ID2)) { - ESP_LOGE(TAG, "Read ID2 SDP3X failed!"); + ESP_LOGE(TAG, "Read ID2 failed"); this->mark_failed(); return; } uint16_t data[6]; if (!this->read_data(data, 6)) { - ESP_LOGE(TAG, "Read ID SDP3X failed!"); + ESP_LOGE(TAG, "Read ID failed"); this->mark_failed(); return; } @@ -79,18 +79,18 @@ void SDP3XComponent::setup() { } if (!this->write_command(measurement_mode_ == DP_AVG ? SDP3X_START_DP_AVG : SDP3X_START_MASS_FLOW_AVG)) { - ESP_LOGE(TAG, "Start Measurements SDP3X failed!"); + ESP_LOGE(TAG, "Start Measurements failed"); this->mark_failed(); return; } - ESP_LOGCONFIG(TAG, "SDP3X started!"); + ESP_LOGCONFIG(TAG, "started"); }); } void SDP3XComponent::dump_config() { LOG_SENSOR(" ", "SDP3X", this); LOG_I2C_DEVICE(this); if (this->is_failed()) { - ESP_LOGE(TAG, " Connection with SDP3X failed!"); + ESP_LOGE(TAG, " Connection with failed"); } LOG_UPDATE_INTERVAL(this); } @@ -98,7 +98,7 @@ void SDP3XComponent::dump_config() { void SDP3XComponent::read_pressure_() { uint16_t data[3]; if (!this->read_data(data, 3)) { - ESP_LOGW(TAG, "Couldn't read SDP3X data!"); + ESP_LOGW(TAG, "Couldn't read data"); this->status_set_warning(); return; } diff --git a/esphome/components/sds011/sds011.cpp b/esphome/components/sds011/sds011.cpp index a34059d85d..4e12c0e322 100644 --- a/esphome/components/sds011/sds011.cpp +++ b/esphome/components/sds011/sds011.cpp @@ -67,9 +67,11 @@ void SDS011Component::set_working_state(bool working_state) { } void SDS011Component::dump_config() { - ESP_LOGCONFIG(TAG, "SDS011:"); - ESP_LOGCONFIG(TAG, " Update Interval: %u min", this->update_interval_min_); - ESP_LOGCONFIG(TAG, " RX-only mode: %s", ONOFF(this->rx_mode_only_)); + ESP_LOGCONFIG(TAG, + "SDS011:\n" + " Update Interval: %u min\n" + " RX-only mode: %s", + this->update_interval_min_, ONOFF(this->rx_mode_only_)); LOG_SENSOR(" ", "PM2.5", this->pm_2_5_sensor_); LOG_SENSOR(" ", "PM10.0", this->pm_10_0_sensor_); this->check_uart_settings(9600); @@ -180,9 +182,6 @@ void SDS011Component::parse_data_() { } } -uint16_t SDS011Component::get_16_bit_uint_(uint8_t start_index) const { - return (uint16_t(this->data_[start_index + 1]) << 8) | uint16_t(this->data_[start_index]); -} void SDS011Component::set_update_interval_min(uint8_t update_interval_min) { this->update_interval_min_ = update_interval_min; } diff --git a/esphome/components/sds011/sds011.h b/esphome/components/sds011/sds011.h index 19e0cd3efe..1f404601b1 100644 --- a/esphome/components/sds011/sds011.h +++ b/esphome/components/sds011/sds011.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" @@ -32,7 +33,9 @@ class SDS011Component : public Component, public uart::UARTDevice { uint8_t sds011_checksum_(const uint8_t *command_data, uint8_t length) const; optional check_byte_() const; void parse_data_(); - uint16_t get_16_bit_uint_(uint8_t start_index) const; + uint16_t get_16_bit_uint_(uint8_t start_index) const { + return encode_uint16(this->data_[start_index + 1], this->data_[start_index]); + } sensor::Sensor *pm_2_5_sensor_{nullptr}; sensor::Sensor *pm_10_0_sensor_{nullptr}; diff --git a/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp index 05d0c6eb21..8683d6cad7 100644 --- a/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp +++ b/esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp @@ -1,5 +1,6 @@ #include "seeed_mr24hpc1.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -533,7 +534,7 @@ void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) { this->custom_mode_number_->publish_state(0); } if (this->custom_mode_end_text_sensor_ != nullptr) { - this->custom_mode_end_text_sensor_->publish_state("Setup in progress..."); + this->custom_mode_end_text_sensor_->publish_state("Setup in progress"); } } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x81) { ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]); diff --git a/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp b/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp index 75f3f092a6..c815c98419 100644 --- a/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +++ b/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp @@ -1,4 +1,5 @@ #include "seeed_mr60bha2.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include diff --git a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp index 6bbef085a5..e40cd9c0c7 100644 --- a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +++ b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp @@ -1,4 +1,5 @@ #include "seeed_mr60fda2.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -335,7 +336,7 @@ void MR60FDA2Component::set_install_height(uint8_t index) { void MR60FDA2Component::set_height_threshold(uint8_t index) { uint8_t send_data[13] = {0x01, 0x00, 0x00, 0x00, 0x04, 0x0E, 0x08, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00}; - float_to_bytes(INSTALL_HEIGHT[index], &send_data[8]); + float_to_bytes(HEIGHT_THRESHOLD[index], &send_data[8]); send_data[12] = calculate_checksum(send_data + 8, 4); this->write_array(send_data, 13); ESP_LOGV(TAG, "SEND HEIGHT THRESHOLD: %s", format_hex_pretty(send_data, 13).c_str()); diff --git a/esphome/components/selec_meter/selec_meter.cpp b/esphome/components/selec_meter/selec_meter.cpp index 8bcf91f3c0..ae41327896 100644 --- a/esphome/components/selec_meter/selec_meter.cpp +++ b/esphome/components/selec_meter/selec_meter.cpp @@ -1,5 +1,6 @@ #include "selec_meter.h" #include "selec_meter_registers.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { @@ -83,8 +84,10 @@ void SelecMeter::on_modbus_data(const std::vector &data) { void SelecMeter::update() { this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT); } void SelecMeter::dump_config() { - ESP_LOGCONFIG(TAG, "SELEC Meter:"); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, + "SELEC Meter:\n" + " Address: 0x%02X", + this->address_); LOG_SENSOR(" ", "Total Active Energy", this->total_active_energy_sensor_); LOG_SENSOR(" ", "Import Active Energy", this->import_active_energy_sensor_); LOG_SENSOR(" ", "Export Active Energy", this->export_active_energy_sensor_); diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index ecbba8677b..e14a9351a0 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -111,6 +111,7 @@ async def register_select(var, config, *, options: list[str]): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_select(var)) + CORE.register_platform_component("select", var) await setup_select_core_(var, config, options=options) diff --git a/esphome/components/sen5x/sen5x.cpp b/esphome/components/sen5x/sen5x.cpp index d7e1f5f62e..c7fd997b0c 100644 --- a/esphome/components/sen5x/sen5x.cpp +++ b/esphome/components/sen5x/sen5x.cpp @@ -264,9 +264,12 @@ void SEN5XComponent::dump_config() { break; } } - ESP_LOGCONFIG(TAG, " Productname: %s", this->product_name_.c_str()); - ESP_LOGCONFIG(TAG, " Firmware version: %d", this->firmware_version_); - ESP_LOGCONFIG(TAG, " Serial number %02d.%02d.%02d", serial_number_[0], serial_number_[1], serial_number_[2]); + ESP_LOGCONFIG(TAG, + " Productname: %s\n" + " Firmware version: %d\n" + " Serial number %02d.%02d.%02d", + this->product_name_.c_str(), this->firmware_version_, serial_number_[0], serial_number_[1], + serial_number_[2]); if (this->auto_cleaning_interval_.has_value()) { ESP_LOGCONFIG(TAG, " Auto cleaning interval %" PRId32 " seconds", auto_cleaning_interval_.value()); } diff --git a/esphome/components/sensirion_common/i2c_sensirion.cpp b/esphome/components/sensirion_common/i2c_sensirion.cpp index d8ab817a73..f71b3c14cb 100644 --- a/esphome/components/sensirion_common/i2c_sensirion.cpp +++ b/esphome/components/sensirion_common/i2c_sensirion.cpp @@ -1,6 +1,7 @@ #include "i2c_sensirion.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include namespace esphome { diff --git a/esphome/components/sensirion_common/i2c_sensirion.h b/esphome/components/sensirion_common/i2c_sensirion.h index 24b706cf36..aba93d6cc3 100644 --- a/esphome/components/sensirion_common/i2c_sensirion.h +++ b/esphome/components/sensirion_common/i2c_sensirion.h @@ -1,5 +1,6 @@ #pragma once #include "esphome/components/i2c/i2c.h" +#include "esphome/core/helpers.h" #include diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index c6b3469ebe..1ad3cfabee 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -167,7 +167,6 @@ DEVICE_CLASSES = [ ] _LOGGER = logging.getLogger(__name__) - sensor_ns = cg.esphome_ns.namespace("sensor") StateClasses = sensor_ns.enum("StateClass") STATE_CLASSES = { @@ -840,6 +839,7 @@ async def register_sensor(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_sensor(var)) + CORE.register_platform_component("sensor", var) await setup_sensor_core_(var, config) diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 3cfaebb708..94fec8208b 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -3,9 +3,9 @@ #include #include #include +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" -#include "esphome/core/automation.h" namespace esphome { namespace sensor { diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index 98356c943d..ab9ff1565c 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -1,9 +1,9 @@ #pragma once -#include "esphome/core/log.h" #include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/components/sensor/filter.h" #include @@ -13,13 +13,17 @@ namespace sensor { #define LOG_SENSOR(prefix, type, obj) \ if ((obj) != nullptr) { \ - ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ + ESP_LOGCONFIG(TAG, \ + "%s%s '%s'\n" \ + "%s State Class: '%s'\n" \ + "%s Unit of Measurement: '%s'\n" \ + "%s Accuracy Decimals: %d", \ + prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str(), prefix, \ + state_class_to_string((obj)->get_state_class()).c_str(), prefix, \ + (obj)->get_unit_of_measurement().c_str(), prefix, (obj)->get_accuracy_decimals()); \ if (!(obj)->get_device_class().empty()) { \ ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ } \ - ESP_LOGCONFIG(TAG, "%s State Class: '%s'", prefix, state_class_to_string((obj)->get_state_class()).c_str()); \ - ESP_LOGCONFIG(TAG, "%s Unit of Measurement: '%s'", prefix, (obj)->get_unit_of_measurement().c_str()); \ - ESP_LOGCONFIG(TAG, "%s Accuracy Decimals: %d", prefix, (obj)->get_accuracy_decimals()); \ if (!(obj)->get_icon().empty()) { \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ } \ diff --git a/esphome/components/servo/servo.cpp b/esphome/components/servo/servo.cpp index 18e8c8087e..b8546d345c 100644 --- a/esphome/components/servo/servo.cpp +++ b/esphome/components/servo/servo.cpp @@ -11,12 +11,15 @@ static const char *const TAG = "servo"; uint32_t global_servo_id = 1911044085ULL; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) void Servo::dump_config() { - ESP_LOGCONFIG(TAG, "Servo:"); - ESP_LOGCONFIG(TAG, " Idle Level: %.1f%%", this->idle_level_ * 100.0f); - ESP_LOGCONFIG(TAG, " Min Level: %.1f%%", this->min_level_ * 100.0f); - ESP_LOGCONFIG(TAG, " Max Level: %.1f%%", this->max_level_ * 100.0f); - ESP_LOGCONFIG(TAG, " auto detach time: %" PRIu32 " ms", this->auto_detach_time_); - ESP_LOGCONFIG(TAG, " run duration: %" PRIu32 " ms", this->transition_length_); + ESP_LOGCONFIG(TAG, + "Servo:\n" + " Idle Level: %.1f%%\n" + " Min Level: %.1f%%\n" + " Max Level: %.1f%%\n" + " Auto-detach time: %" PRIu32 " ms\n" + " Run duration: %" PRIu32 " ms", + this->idle_level_ * 100.0f, this->min_level_ * 100.0f, this->max_level_ * 100.0f, + this->auto_detach_time_, this->transition_length_); } void Servo::setup() { @@ -41,7 +44,7 @@ void Servo::loop() { if (millis() - this->start_millis_ > this->auto_detach_time_) { this->detach(); this->start_millis_ = 0; - ESP_LOGD(TAG, "Servo detached on auto_detach_time"); + ESP_LOGD(TAG, "Detached on auto_detach_time"); } } if (this->target_value_ != this->current_value_ && this->state_ == STATE_ATTACHED) { @@ -63,7 +66,7 @@ void Servo::loop() { if (this->target_value_ == this->current_value_ && this->state_ == STATE_ATTACHED) { this->state_ = STATE_TARGET_REACHED; this->start_millis_ = millis(); // set current stamp for potential auto_detach_time_ check - ESP_LOGD(TAG, "Servo reached target"); + ESP_LOGD(TAG, "Reached target"); } } @@ -78,7 +81,7 @@ void Servo::write(float value) { this->source_value_ = this->current_value_; this->state_ = STATE_ATTACHED; this->start_millis_ = millis(); - ESP_LOGD(TAG, "Servo new target: %f", value); + ESP_LOGD(TAG, "New target: %f", value); } void Servo::internal_write(float value) { diff --git a/esphome/components/servo/servo.h b/esphome/components/servo/servo.h index 13a7472ae5..92d18bf601 100644 --- a/esphome/components/servo/servo.h +++ b/esphome/components/servo/servo.h @@ -1,7 +1,7 @@ #pragma once -#include "esphome/core/component.h" #include "esphome/core/automation.h" +#include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" #include "esphome/components/output/float_output.h" diff --git a/esphome/components/sgp30/sgp30.cpp b/esphome/components/sgp30/sgp30.cpp index 21f98602eb..0c7f25b699 100644 --- a/esphome/components/sgp30/sgp30.cpp +++ b/esphome/components/sgp30/sgp30.cpp @@ -250,9 +250,11 @@ void SGP30Component::dump_config() { } else { ESP_LOGCONFIG(TAG, " Serial number: %" PRIu64, this->serial_number_); if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) { - ESP_LOGCONFIG(TAG, " Baseline:"); - ESP_LOGCONFIG(TAG, " eCO2 Baseline: 0x%04X", this->eco2_baseline_); - ESP_LOGCONFIG(TAG, " TVOC Baseline: 0x%04X", this->tvoc_baseline_); + ESP_LOGCONFIG(TAG, + " Baseline:\n" + " eCO2 Baseline: 0x%04X\n" + " TVOC Baseline: 0x%04X", + this->eco2_baseline_, this->tvoc_baseline_); } else { ESP_LOGCONFIG(TAG, " Baseline: No baseline configured"); } diff --git a/esphome/components/sgp4x/sgp4x.cpp b/esphome/components/sgp4x/sgp4x.cpp index 1571a8c1e3..bd84ae97f3 100644 --- a/esphome/components/sgp4x/sgp4x.cpp +++ b/esphome/components/sgp4x/sgp4x.cpp @@ -14,29 +14,29 @@ void SGP4xComponent::setup() { // Serial Number identification uint16_t raw_serial_number[3]; if (!this->get_register(SGP4X_CMD_GET_SERIAL_ID, raw_serial_number, 3, 1)) { - ESP_LOGE(TAG, "Failed to read serial number"); + ESP_LOGE(TAG, "Get serial number failed"); this->error_code_ = SERIAL_NUMBER_IDENTIFICATION_FAILED; this->mark_failed(); return; } this->serial_number_ = (uint64_t(raw_serial_number[0]) << 24) | (uint64_t(raw_serial_number[1]) << 16) | (uint64_t(raw_serial_number[2])); - ESP_LOGD(TAG, "Serial Number: %" PRIu64, this->serial_number_); + ESP_LOGD(TAG, "Serial number: %" PRIu64, this->serial_number_); // Featureset identification for future use - uint16_t raw_featureset; - if (!this->get_register(SGP4X_CMD_GET_FEATURESET, raw_featureset, 1)) { - ESP_LOGD(TAG, "raw_featureset write_command_ failed"); + uint16_t featureset; + if (!this->get_register(SGP4X_CMD_GET_FEATURESET, featureset, 1)) { + ESP_LOGD(TAG, "Get feature set failed"); this->mark_failed(); return; } - this->featureset_ = raw_featureset; - if ((this->featureset_ & 0x1FF) == SGP40_FEATURESET) { - sgp_type_ = SGP40; - self_test_time_ = SPG40_SELFTEST_TIME; - measure_time_ = SGP40_MEASURE_TIME; + featureset &= 0x1FF; + if (featureset == SGP40_FEATURESET) { + this->sgp_type_ = SGP40; + this->self_test_time_ = SPG40_SELFTEST_TIME; + this->measure_time_ = SGP40_MEASURE_TIME; if (this->nox_sensor_) { - ESP_LOGE(TAG, "Measuring NOx requires a SGP41 sensor but a SGP40 sensor is detected"); + ESP_LOGE(TAG, "SGP41 required for NOx"); // disable the sensor this->nox_sensor_->set_disabled_by_default(true); // make sure it's not visible in HA @@ -45,20 +45,17 @@ void SGP4xComponent::setup() { // remove pointer to sensor this->nox_sensor_ = nullptr; } + } else if (featureset == SGP41_FEATURESET) { + this->sgp_type_ = SGP41; + this->self_test_time_ = SPG41_SELFTEST_TIME; + this->measure_time_ = SGP41_MEASURE_TIME; } else { - if ((this->featureset_ & 0x1FF) == SGP41_FEATURESET) { - sgp_type_ = SGP41; - self_test_time_ = SPG41_SELFTEST_TIME; - measure_time_ = SGP41_MEASURE_TIME; - } else { - ESP_LOGD(TAG, "Product feature set failed 0x%0X , expecting 0x%0X", uint16_t(this->featureset_ & 0x1FF), - SGP40_FEATURESET); - this->mark_failed(); - return; - } + ESP_LOGD(TAG, "Unknown feature set 0x%0X", featureset); + this->mark_failed(); + return; } - ESP_LOGD(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF)); + ESP_LOGD(TAG, "Version 0x%0X", featureset); if (this->store_baseline_) { // Hash with compilation time and serial number @@ -70,7 +67,7 @@ void SGP4xComponent::setup() { if (this->pref_.load(&this->voc_baselines_storage_)) { this->voc_state0_ = this->voc_baselines_storage_.state0; this->voc_state1_ = this->voc_baselines_storage_.state1; - ESP_LOGI(TAG, "Loaded VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, + ESP_LOGV(TAG, "Loaded VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, this->voc_baselines_storage_.state0, voc_baselines_storage_.state1); } @@ -78,7 +75,7 @@ void SGP4xComponent::setup() { this->seconds_since_last_store_ = 0; if (this->voc_baselines_storage_.state0 > 0 && this->voc_baselines_storage_.state1 > 0) { - ESP_LOGI(TAG, "Setting VOC baseline from save state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, + ESP_LOGV(TAG, "Setting VOC baseline from save state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, this->voc_baselines_storage_.state0, voc_baselines_storage_.state1); voc_algorithm_.set_states(this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1); } @@ -110,39 +107,29 @@ void SGP4xComponent::setup() { limit the amount of communication done over wifi for power consumption or to keep the number of records reported from being overwhelming. */ - ESP_LOGD(TAG, "Component requires sampling of 1Hz, setting up background sampler"); + ESP_LOGV(TAG, "Component requires sampling of 1Hz, setting up background sampler"); this->set_interval(1000, [this]() { this->take_sample(); }); } void SGP4xComponent::self_test_() { - ESP_LOGD(TAG, "Self-test started"); + ESP_LOGD(TAG, "Starting self-test"); if (!this->write_command(SGP4X_CMD_SELF_TEST)) { this->error_code_ = COMMUNICATION_FAILED; - ESP_LOGD(TAG, "Self-test communication failed"); + ESP_LOGD(TAG, ESP_LOG_MSG_COMM_FAIL); this->mark_failed(); } - this->set_timeout(self_test_time_, [this]() { - uint16_t reply; - if (!this->read_data(reply)) { + this->set_timeout(this->self_test_time_, [this]() { + uint16_t reply = 0; + if (!this->read_data(reply) || (reply != 0xD400)) { this->error_code_ = SELF_TEST_FAILED; - ESP_LOGD(TAG, "Self-test read_data_ failed"); + ESP_LOGW(TAG, "Self-test failed (0x%X)", reply); this->mark_failed(); return; } - if (reply == 0xD400) { - this->self_test_complete_ = true; - ESP_LOGD(TAG, "Self-test completed"); - return; - } else { - this->error_code_ = SELF_TEST_FAILED; - ESP_LOGD(TAG, "Self-test failed 0x%X", reply); - return; - } - - ESP_LOGD(TAG, "Self-test failed 0x%X", reply); - this->mark_failed(); + this->self_test_complete_ = true; + ESP_LOGD(TAG, "Self-test complete"); }); } @@ -150,7 +137,7 @@ void SGP4xComponent::update_gas_indices_() { this->voc_index_ = this->voc_algorithm_.process(this->voc_sraw_); if (this->nox_sensor_ != nullptr) this->nox_index_ = this->nox_algorithm_.process(this->nox_sraw_); - ESP_LOGV(TAG, "VOC = %" PRId32 ", NOx = %" PRId32, this->voc_index_, this->nox_index_); + ESP_LOGV(TAG, "VOC: %" PRId32 ", NOx: %" PRId32, this->voc_index_, this->nox_index_); // Store baselines after defined interval or if the difference between current and stored baseline becomes too // much if (this->store_baseline_ && this->seconds_since_last_store_ > SHORTEST_BASELINE_STORE_INTERVAL) { @@ -162,18 +149,18 @@ void SGP4xComponent::update_gas_indices_() { this->voc_baselines_storage_.state1 = this->voc_state1_; if (this->pref_.save(&this->voc_baselines_storage_)) { - ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 " ,state1: 0x%04" PRIX32, + ESP_LOGV(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32, this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1); } else { - ESP_LOGW(TAG, "Could not store VOC baselines"); + ESP_LOGW(TAG, "Storing VOC baselines failed"); } } } if (this->samples_read_ < this->samples_to_stabilize_) { this->samples_read_++; - ESP_LOGD(TAG, "Sensor has not collected enough samples yet. (%d/%d) VOC index is: %" PRIu32, this->samples_read_, - this->samples_to_stabilize_, this->voc_index_); + ESP_LOGD(TAG, "Stabilizing (%d/%d); VOC index: %" PRIu32, this->samples_read_, this->samples_to_stabilize_, + this->voc_index_); } } @@ -182,7 +169,7 @@ void SGP4xComponent::measure_raw_() { static uint32_t nox_conditioning_start = millis(); if (!this->self_test_complete_) { - ESP_LOGD(TAG, "Self-test not yet complete"); + ESP_LOGW(TAG, "Self-test incomplete"); return; } if (this->humidity_sensor_ != nullptr) { @@ -270,7 +257,7 @@ void SGP4xComponent::update() { void SGP4xComponent::dump_config() { ESP_LOGCONFIG(TAG, "SGP4x:"); LOG_I2C_DEVICE(this); - ESP_LOGCONFIG(TAG, " store_baseline: %d", this->store_baseline_); + ESP_LOGCONFIG(TAG, " Store baseline: %s", YESNO(this->store_baseline_)); if (this->is_failed()) { switch (this->error_code_) { @@ -278,29 +265,30 @@ void SGP4xComponent::dump_config() { ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL); break; case SERIAL_NUMBER_IDENTIFICATION_FAILED: - ESP_LOGW(TAG, "Get Serial number failed"); + ESP_LOGW(TAG, "Get serial number failed"); break; case SELF_TEST_FAILED: - ESP_LOGW(TAG, "Self test failed"); + ESP_LOGW(TAG, "Self-test failed"); break; - default: - ESP_LOGW(TAG, "Unknown setup error"); + ESP_LOGW(TAG, "Unknown error"); break; } } else { - ESP_LOGCONFIG(TAG, " Type: %s", sgp_type_ == SGP41 ? "SGP41" : "SPG40"); - ESP_LOGCONFIG(TAG, " Serial number: %" PRIu64, this->serial_number_); - ESP_LOGCONFIG(TAG, " Minimum Samples: %f", GasIndexAlgorithm_INITIAL_BLACKOUT); + ESP_LOGCONFIG(TAG, + " Type: %s\n" + " Serial number: %" PRIu64 "\n" + " Minimum Samples: %f", + sgp_type_ == SGP41 ? "SGP41" : "SPG40", this->serial_number_, GasIndexAlgorithm_INITIAL_BLACKOUT); } LOG_UPDATE_INTERVAL(this); + ESP_LOGCONFIG(TAG, " Compensation:"); if (this->humidity_sensor_ != nullptr || this->temperature_sensor_ != nullptr) { - ESP_LOGCONFIG(TAG, " Compensation:"); LOG_SENSOR(" ", "Temperature Source:", this->temperature_sensor_); LOG_SENSOR(" ", "Humidity Source:", this->humidity_sensor_); } else { - ESP_LOGCONFIG(TAG, " Compensation: No source configured"); + ESP_LOGCONFIG(TAG, " No source configured"); } LOG_SENSOR(" ", "VOC", this->voc_sensor_); LOG_SENSOR(" ", "NOx", this->nox_sensor_); diff --git a/esphome/components/sgp4x/sgp4x.h b/esphome/components/sgp4x/sgp4x.h index 959ff12c27..45ee66af68 100644 --- a/esphome/components/sgp4x/sgp4x.h +++ b/esphome/components/sgp4x/sgp4x.h @@ -115,7 +115,6 @@ class SGP4xComponent : public PollingComponent, public sensor::Sensor, public se SgpType sgp_type_{SGP40}; uint64_t serial_number_; - uint16_t featureset_; bool self_test_complete_; uint16_t self_test_time_; diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index d4229b2384..6b4ab13c48 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -101,7 +101,7 @@ void ShellyDimmer::setup() { this->pin_nrst_->setup(); this->pin_boot0_->setup(); - ESP_LOGI(TAG, "Initializing Shelly Dimmer..."); + ESP_LOGI(TAG, "Initializing"); this->handle_firmware(); @@ -119,17 +119,21 @@ void ShellyDimmer::dump_config() { LOG_PIN(" NRST Pin: ", this->pin_nrst_); LOG_PIN(" BOOT0 Pin: ", this->pin_boot0_); - ESP_LOGCONFIG(TAG, " Leading Edge: %s", YESNO(this->leading_edge_)); - ESP_LOGCONFIG(TAG, " Warmup Brightness: %d", this->warmup_brightness_); + ESP_LOGCONFIG(TAG, + " Leading Edge: %s\n" + " Warmup Brightness: %d\n" + " Minimum Brightness: %d\n" + " Maximum Brightness: %d", + YESNO(this->leading_edge_), this->warmup_brightness_, this->min_brightness_, this->max_brightness_); // ESP_LOGCONFIG(TAG, " Warmup Time: %d", this->warmup_time_); // ESP_LOGCONFIG(TAG, " Fade Rate: %d", this->fade_rate_); - ESP_LOGCONFIG(TAG, " Minimum Brightness: %d", this->min_brightness_); - ESP_LOGCONFIG(TAG, " Maximum Brightness: %d", this->max_brightness_); LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " STM32 current firmware version: %d.%d ", this->version_major_, this->version_minor_); - ESP_LOGCONFIG(TAG, " STM32 required firmware version: %d.%d", USE_SHD_FIRMWARE_MAJOR_VERSION, + ESP_LOGCONFIG(TAG, + " STM32 current firmware version: %d.%d \n" + " STM32 required firmware version: %d.%d", + this->version_major_, this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION); if (this->version_major_ != USE_SHD_FIRMWARE_MAJOR_VERSION || diff --git a/esphome/components/shtcx/shtcx.cpp b/esphome/components/shtcx/shtcx.cpp index 770bcf6c6d..5420119bd6 100644 --- a/esphome/components/shtcx/shtcx.cpp +++ b/esphome/components/shtcx/shtcx.cpp @@ -20,7 +20,7 @@ inline const char *to_string(SHTCXType type) { case SHTCX_TYPE_SHTC1: return "SHTC1"; default: - return "[Unknown model]"; + return "UNKNOWN"; } } @@ -29,15 +29,9 @@ void SHTCXComponent::setup() { this->wake_up(); this->soft_reset(); - if (!this->write_command(SHTCX_COMMAND_READ_ID_REGISTER)) { - ESP_LOGE(TAG, "Error requesting Device ID"); - this->mark_failed(); - return; - } - uint16_t device_id_register; - if (!this->read_data(&device_id_register, 1)) { - ESP_LOGE(TAG, "Error reading Device ID"); + if (!this->write_command(SHTCX_COMMAND_READ_ID_REGISTER) || !this->read_data(&device_id_register, 1)) { + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); this->mark_failed(); return; } @@ -53,8 +47,8 @@ void SHTCXComponent::setup() { } else { this->type_ = SHTCX_TYPE_UNKNOWN; } - ESP_LOGCONFIG(TAG, " Device identified: %s (%04x)", to_string(this->type_), device_id_register); } + void SHTCXComponent::dump_config() { ESP_LOGCONFIG(TAG, "SHTCx:"); ESP_LOGCONFIG(TAG, " Model: %s (%04x)", to_string(this->type_), this->sensor_id_); @@ -67,17 +61,19 @@ void SHTCXComponent::dump_config() { LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); } + float SHTCXComponent::get_setup_priority() const { return setup_priority::DATA; } + void SHTCXComponent::update() { if (this->status_has_warning()) { - ESP_LOGW(TAG, "Retrying to reconnect the sensor."); + ESP_LOGW(TAG, "Retrying communication"); this->soft_reset(); } if (this->type_ != SHTCX_TYPE_SHTC1) { this->wake_up(); } if (!this->write_command(SHTCX_COMMAND_POLLING_H)) { - ESP_LOGE(TAG, "sensor polling failed"); + ESP_LOGE(TAG, "Polling failed"); if (this->temperature_sensor_ != nullptr) this->temperature_sensor_->publish_state(NAN); if (this->humidity_sensor_ != nullptr) @@ -91,13 +87,13 @@ void SHTCXComponent::update() { float humidity = NAN; uint16_t raw_data[2]; if (!this->read_data(raw_data, 2)) { - ESP_LOGE(TAG, "sensor read failed"); + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); this->status_set_warning(); } else { temperature = 175.0f * float(raw_data[0]) / 65536.0f - 45.0f; humidity = 100.0f * float(raw_data[1]) / 65536.0f; - ESP_LOGD(TAG, "Got temperature=%.2f°C humidity=%.2f%%", temperature, humidity); + ESP_LOGD(TAG, "Temperature=%.2f°C Humidity=%.2f%%", temperature, humidity); } if (this->temperature_sensor_ != nullptr) this->temperature_sensor_->publish_state(temperature); @@ -114,6 +110,7 @@ void SHTCXComponent::soft_reset() { this->write_command(SHTCX_COMMAND_SOFT_RESET); delayMicroseconds(200); } + void SHTCXComponent::sleep() { this->write_command(SHTCX_COMMAND_SLEEP); } void SHTCXComponent::wake_up() { diff --git a/esphome/components/shutdown/button/shutdown_button.cpp b/esphome/components/shutdown/button/shutdown_button.cpp index be88a10d49..b40af7517b 100644 --- a/esphome/components/shutdown/button/shutdown_button.cpp +++ b/esphome/components/shutdown/button/shutdown_button.cpp @@ -17,7 +17,7 @@ static const char *const TAG = "shutdown.button"; void ShutdownButton::dump_config() { LOG_BUTTON("", "Shutdown Button", this); } void ShutdownButton::press_action() { - ESP_LOGI(TAG, "Shutting down..."); + ESP_LOGI(TAG, "Shutting down"); // Let MQTT settle a bit delay(100); // NOLINT App.run_safe_shutdown_hooks(); diff --git a/esphome/components/shutdown/switch/shutdown_switch.cpp b/esphome/components/shutdown/switch/shutdown_switch.cpp index a5f9a92982..b685ab14ab 100644 --- a/esphome/components/shutdown/switch/shutdown_switch.cpp +++ b/esphome/components/shutdown/switch/shutdown_switch.cpp @@ -21,7 +21,7 @@ void ShutdownSwitch::write_state(bool state) { this->publish_state(false); if (state) { - ESP_LOGI(TAG, "Shutting down..."); + ESP_LOGI(TAG, "Shutting down"); delay(100); // NOLINT App.run_safe_shutdown_hooks(); diff --git a/esphome/components/sim800l/sim800l.cpp b/esphome/components/sim800l/sim800l.cpp index 38775b0062..d97b0ae364 100644 --- a/esphome/components/sim800l/sim800l.cpp +++ b/esphome/components/sim800l/sim800l.cpp @@ -28,7 +28,7 @@ void Sim800LComponent::update() { this->state_ = STATE_DIALING1; } else if (this->registered_ && this->connect_pending_) { this->connect_pending_ = false; - ESP_LOGI(TAG, "Connecting..."); + ESP_LOGI(TAG, "Connecting"); this->send_cmd_("ATA"); this->state_ = STATE_ATA_SENT; } else if (this->registered_ && this->send_ussd_pending_) { @@ -36,7 +36,7 @@ void Sim800LComponent::update() { this->state_ = STATE_SEND_USSD1; } else if (this->registered_ && this->disconnect_pending_) { this->disconnect_pending_ = false; - ESP_LOGI(TAG, "Disconnecting..."); + ESP_LOGI(TAG, "Disconnecting"); this->send_cmd_("ATH"); } else if (this->registered_ && this->call_state_ != 6) { send_cmd_("AT+CLCC"); diff --git a/esphome/components/slow_pwm/slow_pwm_output.cpp b/esphome/components/slow_pwm/slow_pwm_output.cpp index 643294303c..48ded94b3a 100644 --- a/esphome/components/slow_pwm/slow_pwm_output.cpp +++ b/esphome/components/slow_pwm/slow_pwm_output.cpp @@ -63,8 +63,10 @@ void SlowPWMOutput::dump_config() { if (this->turn_off_trigger_) { ESP_LOGCONFIG(TAG, " Turn off automation configured"); } - ESP_LOGCONFIG(TAG, " Period: %d ms", this->period_); - ESP_LOGCONFIG(TAG, " Restart cycle on state change: %s", YESNO(this->restart_cycle_on_state_change_)); + ESP_LOGCONFIG(TAG, + " Period: %d ms\n" + " Restart cycle on state change: %s", + this->period_, YESNO(this->restart_cycle_on_state_change_)); LOG_FLOAT_OUTPUT(this); } diff --git a/esphome/components/sm2235/sm2235.cpp b/esphome/components/sm2235/sm2235.cpp index 3edd1e24a7..e9f84773e2 100644 --- a/esphome/components/sm2235/sm2235.cpp +++ b/esphome/components/sm2235/sm2235.cpp @@ -19,8 +19,10 @@ void SM2235::dump_config() { ESP_LOGCONFIG(TAG, "sm2235:"); LOG_PIN(" Data Pin: ", this->data_pin_); LOG_PIN(" Clock Pin: ", this->clock_pin_); - ESP_LOGCONFIG(TAG, " Color Channels Max Power: %u", this->max_power_color_channels_); - ESP_LOGCONFIG(TAG, " White Channels Max Power: %u", this->max_power_white_channels_); + ESP_LOGCONFIG(TAG, + " Color Channels Max Power: %u\n" + " White Channels Max Power: %u", + this->max_power_color_channels_, this->max_power_white_channels_); } } // namespace sm2235 diff --git a/esphome/components/sm2335/sm2335.cpp b/esphome/components/sm2335/sm2335.cpp index a891b14ea0..99b722a639 100644 --- a/esphome/components/sm2335/sm2335.cpp +++ b/esphome/components/sm2335/sm2335.cpp @@ -19,8 +19,10 @@ void SM2335::dump_config() { ESP_LOGCONFIG(TAG, "sm2335:"); LOG_PIN(" Data Pin: ", this->data_pin_); LOG_PIN(" Clock Pin: ", this->clock_pin_); - ESP_LOGCONFIG(TAG, " Color Channels Max Power: %u", this->max_power_color_channels_); - ESP_LOGCONFIG(TAG, " White Channels Max Power: %u", this->max_power_white_channels_); + ESP_LOGCONFIG(TAG, + " Color Channels Max Power: %u\n" + " White Channels Max Power: %u", + this->max_power_color_channels_, this->max_power_white_channels_); } } // namespace sm2335 diff --git a/esphome/components/sml/sml.cpp b/esphome/components/sml/sml.cpp index 7ae9044c72..c1ffdc0e68 100644 --- a/esphome/components/sml/sml.cpp +++ b/esphome/components/sml/sml.cpp @@ -1,6 +1,6 @@ #include "sml.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "sml_parser.h" namespace esphome { diff --git a/esphome/components/sn74hc595/__init__.py b/esphome/components/sn74hc595/__init__.py index db18b00cd1..26e5c03802 100644 --- a/esphome/components/sn74hc595/__init__.py +++ b/esphome/components/sn74hc595/__init__.py @@ -95,7 +95,7 @@ SN74HC595_PIN_SCHEMA = pins.gpio_base_schema( cv.int_range(min=0, max=2047), modes=[CONF_OUTPUT], mode_validator=_validate_output_mode, - invertable=True, + invertible=True, ).extend( { cv.Required(CONF_SN74HC595): cv.use_id(SN74HC595Component), diff --git a/esphome/components/sonoff_d1/sonoff_d1.cpp b/esphome/components/sonoff_d1/sonoff_d1.cpp index e70ec7b70d..e3d55681c5 100644 --- a/esphome/components/sonoff_d1/sonoff_d1.cpp +++ b/esphome/components/sonoff_d1/sonoff_d1.cpp @@ -286,10 +286,13 @@ void SonoffD1Output::write_state(light::LightState *state) { } void SonoffD1Output::dump_config() { - ESP_LOGCONFIG(TAG, "Sonoff D1 Dimmer: '%s'", this->light_state_ ? this->light_state_->get_name().c_str() : ""); - ESP_LOGCONFIG(TAG, " Use RM433 Remote: %s", ONOFF(this->use_rm433_remote_)); - ESP_LOGCONFIG(TAG, " Minimal brightness: %d", this->min_value_); - ESP_LOGCONFIG(TAG, " Maximal brightness: %d", this->max_value_); + ESP_LOGCONFIG(TAG, + "Sonoff D1 Dimmer: '%s'\n" + " Use RM433 Remote: %s\n" + " Minimal brightness: %d\n" + " Maximal brightness: %d", + this->light_state_ ? this->light_state_->get_name().c_str() : "", ONOFF(this->use_rm433_remote_), + this->min_value_, this->max_value_); } void SonoffD1Output::loop() { diff --git a/esphome/components/sonoff_d1/sonoff_d1.h b/esphome/components/sonoff_d1/sonoff_d1.h index 4df0f5afb2..19ff83f378 100644 --- a/esphome/components/sonoff_d1/sonoff_d1.h +++ b/esphome/components/sonoff_d1/sonoff_d1.h @@ -31,9 +31,9 @@ ----- */ -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/components/uart/uart.h" #include "esphome/components/light/light_output.h" #include "esphome/components/light/light_state.h" diff --git a/esphome/components/sound_level/sound_level.cpp b/esphome/components/sound_level/sound_level.cpp index f8447ce436..decf630aba 100644 --- a/esphome/components/sound_level/sound_level.cpp +++ b/esphome/components/sound_level/sound_level.cpp @@ -19,8 +19,10 @@ static const uint32_t RING_BUFFER_DURATION_MS = 120; static const double MAX_SAMPLE_SQUARED_DENOMINATOR = INT16_MIN * INT16_MIN; void SoundLevelComponent::dump_config() { - ESP_LOGCONFIG(TAG, "Sound Level Component:"); - ESP_LOGCONFIG(TAG, " Measurement Duration: %" PRIu32 " ms", measurement_duration_ms_); + ESP_LOGCONFIG(TAG, + "Sound Level Component:\n" + " Measurement Duration: %" PRIu32 " ms", + measurement_duration_ms_); LOG_SENSOR(" ", "Peak:", this->peak_sensor_); LOG_SENSOR(" ", "RMS:", this->rms_sensor_); diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 5b28b3546b..ffb5e11f79 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -2,12 +2,14 @@ import re from esphome import pins import esphome.codegen as cg +from esphome.components.esp32 import only_on_variant from esphome.components.esp32.const import ( KEY_ESP32, VARIANT_ESP32C2, VARIANT_ESP32C3, VARIANT_ESP32C6, VARIANT_ESP32H2, + VARIANT_ESP32P4, VARIANT_ESP32S2, VARIANT_ESP32S3, ) @@ -287,7 +289,15 @@ def spi_mode_schema(mode): if mode == TYPE_SINGLE: return SPI_SINGLE_SCHEMA pin_count = 4 if mode == TYPE_QUAD else 8 + onlys = [cv.only_on([PLATFORM_ESP32]), cv.only_with_esp_idf] + if pin_count == 8: + onlys.append( + only_on_variant( + supported=[VARIANT_ESP32S3, VARIANT_ESP32S2, VARIANT_ESP32P4] + ) + ) return cv.All( + *onlys, cv.Schema( { cv.GenerateID(): cv.declare_id(TYPE_CLASS[mode]), @@ -308,8 +318,6 @@ def spi_mode_schema(mode): ), } ), - cv.only_on([PLATFORM_ESP32]), - cv.only_with_esp_idf, ) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index 18f7852757..76d9d8ae86 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -18,7 +18,7 @@ GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-a SPIDelegate *SPIComponent::register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate, GPIOPin *cs_pin) { if (this->devices_.count(device) != 0) { - ESP_LOGE(TAG, "SPI device already registered"); + ESP_LOGE(TAG, "Device already registered"); return this->devices_[device]; } SPIDelegate *delegate = this->spi_bus_->get_delegate(data_rate, bit_order, mode, cs_pin); // NOLINT @@ -28,7 +28,7 @@ SPIDelegate *SPIComponent::register_device(SPIClient *device, SPIMode mode, SPIB void SPIComponent::unregister_device(SPIClient *device) { if (this->devices_.count(device) == 0) { - esph_log_e(TAG, "SPI device not registered"); + esph_log_e(TAG, "Device not registered"); return; } delete this->devices_[device]; // NOLINT @@ -36,14 +36,14 @@ void SPIComponent::unregister_device(SPIClient *device) { } void SPIComponent::setup() { - ESP_LOGD(TAG, "Setting up SPI bus..."); + ESP_LOGCONFIG(TAG, "Running setup"); if (this->sdo_pin_ == nullptr) this->sdo_pin_ = NullPin::NULL_PIN; if (this->sdi_pin_ == nullptr) this->sdi_pin_ = NullPin::NULL_PIN; if (this->clk_pin_ == nullptr) { - ESP_LOGE(TAG, "No clock pin for SPI"); + ESP_LOGE(TAG, "No clock pin"); this->mark_failed(); return; } diff --git a/esphome/components/spi_device/spi_device.cpp b/esphome/components/spi_device/spi_device.cpp index 1f579cb802..872b3054e6 100644 --- a/esphome/components/spi_device/spi_device.cpp +++ b/esphome/components/spi_device/spi_device.cpp @@ -9,9 +9,8 @@ namespace spi_device { static const char *const TAG = "spi_device"; void SPIDeviceComponent::setup() { - ESP_LOGD(TAG, "Setting up SPIDevice..."); + ESP_LOGCONFIG(TAG, "Running setup"); this->spi_setup(); - ESP_LOGCONFIG(TAG, "SPIDevice started!"); } void SPIDeviceComponent::dump_config() { diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 50ea3eff51..e191498857 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -1712,15 +1712,18 @@ void Sprinkler::dump_config() { if (this->valve_overlap_) { ESP_LOGCONFIG(TAG, " Valve Overlap: %" PRIu32 " seconds", this->switching_delay_.value_or(0)); } else { - ESP_LOGCONFIG(TAG, " Valve Open Delay: %" PRIu32 " seconds", this->switching_delay_.value_or(0)); - ESP_LOGCONFIG(TAG, " Pump Switch Off During Valve Open Delay: %s", - YESNO(this->pump_switch_off_during_valve_open_delay_)); + ESP_LOGCONFIG(TAG, + " Valve Open Delay: %" PRIu32 " seconds\n" + " Pump Switch Off During Valve Open Delay: %s", + this->switching_delay_.value_or(0), YESNO(this->pump_switch_off_during_valve_open_delay_)); } } for (size_t valve_number = 0; valve_number < this->number_of_valves(); valve_number++) { - ESP_LOGCONFIG(TAG, " Valve %zu:", valve_number); - ESP_LOGCONFIG(TAG, " Name: %s", this->valve_name(valve_number)); - ESP_LOGCONFIG(TAG, " Run Duration: %" PRIu32 " seconds", this->valve_run_duration(valve_number)); + ESP_LOGCONFIG(TAG, + " Valve %zu:\n" + " Name: %s\n" + " Run Duration: %" PRIu32 " seconds", + valve_number, this->valve_name(valve_number), this->valve_run_duration(valve_number)); if (this->valve_[valve_number].valve_switch.pulse_duration()) { ESP_LOGCONFIG(TAG, " Pulse Duration: %" PRIu32 " milliseconds", this->valve_[valve_number].valve_switch.pulse_duration()); diff --git a/esphome/components/sps30/sps30.cpp b/esphome/components/sps30/sps30.cpp index 5a0335998f..c0df539867 100644 --- a/esphome/components/sps30/sps30.cpp +++ b/esphome/components/sps30/sps30.cpp @@ -96,9 +96,10 @@ void SPS30Component::dump_config() { } } LOG_UPDATE_INTERVAL(this); - ESP_LOGCONFIG(TAG, " Serial Number: '%s'", this->serial_number_); - ESP_LOGCONFIG(TAG, " Firmware version v%0d.%0d", (raw_firmware_version_ >> 8), - uint16_t(raw_firmware_version_ & 0xFF)); + ESP_LOGCONFIG(TAG, + " Serial Number: '%s'\n" + " Firmware version v%0d.%0d", + this->serial_number_, (raw_firmware_version_ >> 8), uint16_t(raw_firmware_version_ & 0xFF)); LOG_SENSOR(" ", "PM1.0 Weight Concentration", this->pm_1_0_sensor_); LOG_SENSOR(" ", "PM2.5 Weight Concentration", this->pm_2_5_sensor_); LOG_SENSOR(" ", "PM4 Weight Concentration", this->pm_4_0_sensor_); @@ -113,18 +114,18 @@ void SPS30Component::dump_config() { void SPS30Component::update() { /// Check if warning flag active (sensor reconnected?) if (this->status_has_warning()) { - ESP_LOGD(TAG, "Trying to reconnect the sensor..."); + ESP_LOGD(TAG, "Trying to reconnect"); if (this->write_command(SPS30_CMD_SOFT_RESET)) { - ESP_LOGD(TAG, "Sensor has soft-reset successfully. Waiting for reconnection in 500ms..."); + ESP_LOGD(TAG, "Soft-reset successful. Waiting for reconnection in 500 ms"); this->set_timeout(500, [this]() { this->start_continuous_measurement_(); /// Sensor restarted and reading attempt made next cycle this->status_clear_warning(); this->skipped_data_read_cycles_ = 0; - ESP_LOGD(TAG, "Sensor reconnected successfully. Resuming continuous measurement!"); + ESP_LOGD(TAG, "Reconnect successful. Resuming continuous measurement"); }); } else { - ESP_LOGD(TAG, "Sensor soft-reset failed. Is the sensor offline?"); + ESP_LOGD(TAG, "Soft-reset failed"); } return; } @@ -136,19 +137,19 @@ void SPS30Component::update() { uint16_t raw_read_status; if (!this->read_data(&raw_read_status, 1) || raw_read_status == 0x00) { - ESP_LOGD(TAG, "Sensor measurement not ready yet."); + ESP_LOGD(TAG, "Not ready yet"); this->skipped_data_read_cycles_++; /// The following logic is required to address the cases when a sensor is quickly replaced before it's marked /// as failed so that new sensor is eventually forced to be reinitialized for continuous measurement. if (this->skipped_data_read_cycles_ > MAX_SKIPPED_DATA_CYCLES_BEFORE_ERROR) { - ESP_LOGD(TAG, "Sensor exceeded max allowed attempts. Sensor communication will be reinitialized."); + ESP_LOGD(TAG, "Exceeded max allowed attempts; communication will be reinitialized"); this->status_set_warning(); } return; } if (!this->write_command(SPS30_CMD_READ_MEASUREMENT)) { - ESP_LOGW(TAG, "Error reading measurement status!"); + ESP_LOGW(TAG, "Error reading status"); this->status_set_warning(); return; } @@ -156,7 +157,7 @@ void SPS30Component::update() { this->set_timeout(50, [this]() { uint16_t raw_data[20]; if (!this->read_data(raw_data, 20)) { - ESP_LOGW(TAG, "Error reading measurement data!"); + ESP_LOGW(TAG, "Error reading data"); this->status_set_warning(); return; } diff --git a/esphome/components/ssd1306_base/ssd1306_base.cpp b/esphome/components/ssd1306_base/ssd1306_base.cpp index 90b805a79f..0547a77184 100644 --- a/esphome/components/ssd1306_base/ssd1306_base.cpp +++ b/esphome/components/ssd1306_base/ssd1306_base.cpp @@ -1,6 +1,6 @@ #include "ssd1306_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ssd1306_base { diff --git a/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp b/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp index 4013ae7209..f9a2609948 100644 --- a/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp +++ b/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp @@ -24,12 +24,15 @@ void I2CSSD1306::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " External VCC: %s", YESNO(this->external_vcc_)); - ESP_LOGCONFIG(TAG, " Flip X: %s", YESNO(this->flip_x_)); - ESP_LOGCONFIG(TAG, " Flip Y: %s", YESNO(this->flip_y_)); - ESP_LOGCONFIG(TAG, " Offset X: %d", this->offset_x_); - ESP_LOGCONFIG(TAG, " Offset Y: %d", this->offset_y_); - ESP_LOGCONFIG(TAG, " Inverted Color: %s", YESNO(this->invert_)); + ESP_LOGCONFIG(TAG, + " External VCC: %s\n" + " Flip X: %s\n" + " Flip Y: %s\n" + " Offset X: %d\n" + " Offset Y: %d\n" + " Inverted Color: %s", + YESNO(this->external_vcc_), YESNO(this->flip_x_), YESNO(this->flip_y_), this->offset_x_, + this->offset_y_, YESNO(this->invert_)); LOG_UPDATE_INTERVAL(this); if (this->error_code_ == COMMUNICATION_FAILED) { diff --git a/esphome/components/ssd1306_spi/ssd1306_spi.cpp b/esphome/components/ssd1306_spi/ssd1306_spi.cpp index 28425da587..249e6593ae 100644 --- a/esphome/components/ssd1306_spi/ssd1306_spi.cpp +++ b/esphome/components/ssd1306_spi/ssd1306_spi.cpp @@ -21,12 +21,15 @@ void SPISSD1306::dump_config() { LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " External VCC: %s", YESNO(this->external_vcc_)); - ESP_LOGCONFIG(TAG, " Flip X: %s", YESNO(this->flip_x_)); - ESP_LOGCONFIG(TAG, " Flip Y: %s", YESNO(this->flip_y_)); - ESP_LOGCONFIG(TAG, " Offset X: %d", this->offset_x_); - ESP_LOGCONFIG(TAG, " Offset Y: %d", this->offset_y_); - ESP_LOGCONFIG(TAG, " Inverted Color: %s", YESNO(this->invert_)); + ESP_LOGCONFIG(TAG, + " External VCC: %s\n" + " Flip X: %s\n" + " Flip Y: %s\n" + " Offset X: %d\n" + " Offset Y: %d\n" + " Inverted Color: %s", + YESNO(this->external_vcc_), YESNO(this->flip_x_), YESNO(this->flip_y_), this->offset_x_, + this->offset_y_, YESNO(this->invert_)); LOG_UPDATE_INTERVAL(this); } void SPISSD1306::command(uint8_t value) { diff --git a/esphome/components/ssd1322_base/ssd1322_base.cpp b/esphome/components/ssd1322_base/ssd1322_base.cpp index 520248a66e..eb8d87998f 100644 --- a/esphome/components/ssd1322_base/ssd1322_base.cpp +++ b/esphome/components/ssd1322_base/ssd1322_base.cpp @@ -1,6 +1,6 @@ #include "ssd1322_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ssd1322_base { diff --git a/esphome/components/ssd1325_base/ssd1325_base.cpp b/esphome/components/ssd1325_base/ssd1325_base.cpp index 711f9e5197..e7d2386ac7 100644 --- a/esphome/components/ssd1325_base/ssd1325_base.cpp +++ b/esphome/components/ssd1325_base/ssd1325_base.cpp @@ -1,6 +1,6 @@ #include "ssd1325_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ssd1325_base { diff --git a/esphome/components/ssd1327_base/ssd1327_base.cpp b/esphome/components/ssd1327_base/ssd1327_base.cpp index 4223a013a4..6b83ec5f9d 100644 --- a/esphome/components/ssd1327_base/ssd1327_base.cpp +++ b/esphome/components/ssd1327_base/ssd1327_base.cpp @@ -1,6 +1,6 @@ #include "ssd1327_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ssd1327_base { diff --git a/esphome/components/ssd1331_base/ssd1331_base.cpp b/esphome/components/ssd1331_base/ssd1331_base.cpp index 14f94dee4f..8ee12387e4 100644 --- a/esphome/components/ssd1331_base/ssd1331_base.cpp +++ b/esphome/components/ssd1331_base/ssd1331_base.cpp @@ -1,6 +1,6 @@ #include "ssd1331_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ssd1331_base { diff --git a/esphome/components/ssd1351_base/ssd1351_base.cpp b/esphome/components/ssd1351_base/ssd1351_base.cpp index 38ea05a0b8..09530e8a27 100644 --- a/esphome/components/ssd1351_base/ssd1351_base.cpp +++ b/esphome/components/ssd1351_base/ssd1351_base.cpp @@ -1,6 +1,6 @@ #include "ssd1351_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ssd1351_base { diff --git a/esphome/components/st7567_base/st7567_base.cpp b/esphome/components/st7567_base/st7567_base.cpp index b22a7d7fd5..0afd2a70ba 100644 --- a/esphome/components/st7567_base/st7567_base.cpp +++ b/esphome/components/st7567_base/st7567_base.cpp @@ -1,6 +1,6 @@ #include "st7567_base.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace st7567_base { @@ -13,7 +13,7 @@ void ST7567::setup() { } void ST7567::display_init_() { - ESP_LOGD(TAG, "Initializing ST7567 display..."); + ESP_LOGD(TAG, "Initializing display"); this->display_init_registers_(); this->clear(); this->write_display_data(); @@ -42,7 +42,7 @@ void ST7567::display_init_registers_() { } void ST7567::display_sw_refresh_() { - ESP_LOGD(TAG, "Performing refresh sequence..."); + ESP_LOGD(TAG, "Performing refresh sequence"); this->command(ST7567_SW_REFRESH); this->display_init_registers_(); } diff --git a/esphome/components/st7567_i2c/st7567_i2c.cpp b/esphome/components/st7567_i2c/st7567_i2c.cpp index 9180409cc0..0640d3be8d 100644 --- a/esphome/components/st7567_i2c/st7567_i2c.cpp +++ b/esphome/components/st7567_i2c/st7567_i2c.cpp @@ -24,9 +24,11 @@ void I2CST7567::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); LOG_PIN(" Reset Pin: ", this->reset_pin_); - ESP_LOGCONFIG(TAG, " Mirror X: %s", YESNO(this->mirror_x_)); - ESP_LOGCONFIG(TAG, " Mirror Y: %s", YESNO(this->mirror_y_)); - ESP_LOGCONFIG(TAG, " Invert Colors: %s", YESNO(this->invert_colors_)); + ESP_LOGCONFIG(TAG, + " Mirror X: %s\n" + " Mirror Y: %s\n" + " Invert Colors: %s", + YESNO(this->mirror_x_), YESNO(this->mirror_y_), YESNO(this->invert_colors_)); LOG_UPDATE_INTERVAL(this); if (this->error_code_ == COMMUNICATION_FAILED) { diff --git a/esphome/components/st7701s/st7701s.cpp b/esphome/components/st7701s/st7701s.cpp index 403bff789d..6261f33b77 100644 --- a/esphome/components/st7701s/st7701s.cpp +++ b/esphome/components/st7701s/st7701s.cpp @@ -181,8 +181,10 @@ void ST7701S::write_init_sequence_() { void ST7701S::dump_config() { ESP_LOGCONFIG("", "ST7701S RGB LCD"); - ESP_LOGCONFIG(TAG, " Height: %u", this->height_); - ESP_LOGCONFIG(TAG, " Width: %u", this->width_); + ESP_LOGCONFIG(TAG, + " Height: %u\n" + " Width: %u", + this->height_, this->width_); LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" DE Pin: ", this->de_pin_); diff --git a/esphome/components/st7735/st7735.cpp b/esphome/components/st7735/st7735.cpp index f37770a767..9c9c0a3df5 100644 --- a/esphome/components/st7735/st7735.cpp +++ b/esphome/components/st7735/st7735.cpp @@ -1,7 +1,7 @@ #include "st7735.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace st7735 { diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index 72460d8c89..1f3cd50d6c 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -122,12 +122,15 @@ void ST7789V::setup() { void ST7789V::dump_config() { LOG_DISPLAY("", "SPI ST7789V", this); - ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_); - ESP_LOGCONFIG(TAG, " Height: %u", this->height_); - ESP_LOGCONFIG(TAG, " Width: %u", this->width_); - ESP_LOGCONFIG(TAG, " Height Offset: %u", this->offset_height_); - ESP_LOGCONFIG(TAG, " Width Offset: %u", this->offset_width_); - ESP_LOGCONFIG(TAG, " 8-bit color mode: %s", YESNO(this->eightbitcolor_)); + ESP_LOGCONFIG(TAG, + " Model: %s\n" + " Height: %u\n" + " Width: %u\n" + " Height Offset: %u\n" + " Width Offset: %u\n" + " 8-bit color mode: %s", + this->model_str_, this->height_, this->width_, this->offset_height_, this->offset_width_, + YESNO(this->eightbitcolor_)); LOG_PIN(" CS Pin: ", this->cs_); LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_); diff --git a/esphome/components/st7920/st7920.cpp b/esphome/components/st7920/st7920.cpp index 0623125bfb..54ac6d2efd 100644 --- a/esphome/components/st7920/st7920.cpp +++ b/esphome/components/st7920/st7920.cpp @@ -95,8 +95,10 @@ void ST7920::fill(Color color) { memset(this->buffer_, color.is_on() ? 0xFF : 0x void ST7920::dump_config() { LOG_DISPLAY("", "ST7920", this); LOG_PIN(" CS Pin: ", this->cs_); - ESP_LOGCONFIG(TAG, " Height: %d", this->height_); - ESP_LOGCONFIG(TAG, " Width: %d", this->width_); + ESP_LOGCONFIG(TAG, + " Height: %d\n" + " Width: %d", + this->height_, this->width_); } float ST7920::get_setup_priority() const { return setup_priority::PROCESSOR; } @@ -129,7 +131,7 @@ void HOT ST7920::draw_absolute_pixel_internal(int x, int y, Color color) { } void ST7920::display_init_() { - ESP_LOGD(TAG, "Initializing display..."); + ESP_LOGD(TAG, "Initializing display"); this->command_(LCD_BASIC); // 8bit mode this->command_(LCD_BASIC); // 8bit mode this->command_(LCD_CLS); // clear screen diff --git a/esphome/components/statsd/statsd.cpp b/esphome/components/statsd/statsd.cpp index b7fad19332..05f71c7b24 100644 --- a/esphome/components/statsd/statsd.cpp +++ b/esphome/components/statsd/statsd.cpp @@ -38,17 +38,21 @@ StatsdComponent::~StatsdComponent() { } void StatsdComponent::dump_config() { - ESP_LOGCONFIG(TAG, "statsD:"); - ESP_LOGCONFIG(TAG, " host: %s", this->host_); - ESP_LOGCONFIG(TAG, " port: %d", this->port_); + ESP_LOGCONFIG(TAG, + "statsD:\n" + " host: %s\n" + " port: %d", + this->host_, this->port_); if (this->prefix_) { ESP_LOGCONFIG(TAG, " prefix: %s", this->prefix_); } ESP_LOGCONFIG(TAG, " metrics:"); for (sensors_t s : this->sensors_) { - ESP_LOGCONFIG(TAG, " - name: %s", s.name); - ESP_LOGCONFIG(TAG, " type: %d", s.type); + ESP_LOGCONFIG(TAG, + " - name: %s\n" + " type: %d", + s.name, s.type); } } diff --git a/esphome/components/stepper/stepper.h b/esphome/components/stepper/stepper.h index ba2b3182d7..1cf4830b1f 100644 --- a/esphome/components/stepper/stepper.h +++ b/esphome/components/stepper/stepper.h @@ -7,9 +7,11 @@ namespace esphome { namespace stepper { #define LOG_STEPPER(this) \ - ESP_LOGCONFIG(TAG, " Acceleration: %.0f steps/s^2", this->acceleration_); \ - ESP_LOGCONFIG(TAG, " Deceleration: %.0f steps/s^2", this->deceleration_); \ - ESP_LOGCONFIG(TAG, " Max Speed: %.0f steps/s", this->max_speed_); + ESP_LOGCONFIG(TAG, \ + " Acceleration: %.0f steps/s^2\n" \ + " Deceleration: %.0f steps/s^2\n" \ + " Max Speed: %.0f steps/s", \ + this->acceleration_, this->deceleration_, this->max_speed_); class Stepper { public: diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py index e7445051e0..0211c648fc 100644 --- a/esphome/components/switch/__init__.py +++ b/esphome/components/switch/__init__.py @@ -159,6 +159,7 @@ async def register_switch(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_switch(var)) + CORE.register_platform_component("switch", var) await setup_switch_core_(var, config) diff --git a/esphome/components/switch/switch.cpp b/esphome/components/switch/switch.cpp index 96611b0b87..c204895755 100644 --- a/esphome/components/switch/switch.cpp +++ b/esphome/components/switch/switch.cpp @@ -65,7 +65,24 @@ bool Switch::is_inverted() const { return this->inverted_; } void log_switch(const char *tag, const char *prefix, const char *type, Switch *obj) { if (obj != nullptr) { - ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str()); + // Prepare restore mode string + const LogString *onoff = LOG_STR(""), *inverted = onoff, *restore; + if (obj->restore_mode & RESTORE_MODE_DISABLED_MASK) { + restore = LOG_STR("disabled"); + } else { + onoff = obj->restore_mode & RESTORE_MODE_ON_MASK ? LOG_STR("ON") : LOG_STR("OFF"); + inverted = obj->restore_mode & RESTORE_MODE_INVERTED_MASK ? LOG_STR("inverted ") : LOG_STR(""); + restore = obj->restore_mode & RESTORE_MODE_PERSISTENT_MASK ? LOG_STR("restore defaults to") : LOG_STR("always"); + } + + // Build the base message with mandatory fields + ESP_LOGCONFIG(tag, + "%s%s '%s'\n" + "%s Restore Mode: %s%s %s", + prefix, type, obj->get_name().c_str(), prefix, LOG_STR_ARG(inverted), LOG_STR_ARG(restore), + LOG_STR_ARG(onoff)); + + // Add optional fields separately if (!obj->get_icon().empty()) { ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); } @@ -78,17 +95,6 @@ void log_switch(const char *tag, const char *prefix, const char *type, Switch *o if (!obj->get_device_class().empty()) { ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str()); } - const LogString *onoff = LOG_STR(""), *inverted = onoff, *restore; - if (obj->restore_mode & RESTORE_MODE_DISABLED_MASK) { - restore = LOG_STR("disabled"); - } else { - onoff = obj->restore_mode & RESTORE_MODE_ON_MASK ? LOG_STR("ON") : LOG_STR("OFF"); - inverted = obj->restore_mode & RESTORE_MODE_INVERTED_MASK ? LOG_STR("inverted ") : LOG_STR(""); - restore = obj->restore_mode & RESTORE_MODE_PERSISTENT_MASK ? LOG_STR("restore defaults to") : LOG_STR("always"); - } - - ESP_LOGCONFIG(tag, "%s Restore Mode: %s%s %s", prefix, LOG_STR_ARG(inverted), LOG_STR_ARG(restore), - LOG_STR_ARG(onoff)); } } diff --git a/esphome/components/switch/switch.h b/esphome/components/switch/switch.h index b5395a2c83..e8018ed36f 100644 --- a/esphome/components/switch/switch.h +++ b/esphome/components/switch/switch.h @@ -2,8 +2,8 @@ #include "esphome/core/component.h" #include "esphome/core/entity_base.h" -#include "esphome/core/preferences.h" #include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" namespace esphome { namespace switch_ { diff --git a/esphome/components/sx1509/sx1509.cpp b/esphome/components/sx1509/sx1509.cpp index 865bf6f25b..d323c9a92c 100644 --- a/esphome/components/sx1509/sx1509.cpp +++ b/esphome/components/sx1509/sx1509.cpp @@ -10,7 +10,7 @@ static const char *const TAG = "sx1509"; void SX1509Component::setup() { ESP_LOGCONFIG(TAG, "Running setup"); - ESP_LOGV(TAG, " Resetting devices..."); + ESP_LOGV(TAG, " Resetting devices"); if (!this->write_byte(REG_RESET, 0x12)) { this->mark_failed(); return; diff --git a/esphome/components/t6615/t6615.cpp b/esphome/components/t6615/t6615.cpp index 1c78833500..c2ac88ee2e 100644 --- a/esphome/components/t6615/t6615.cpp +++ b/esphome/components/t6615/t6615.cpp @@ -1,4 +1,5 @@ #include "t6615.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/tca9555/__init__.py b/esphome/components/tca9555/__init__.py index db0451d4e6..f42e0fe398 100644 --- a/esphome/components/tca9555/__init__.py +++ b/esphome/components/tca9555/__init__.py @@ -53,7 +53,7 @@ TCA9555_PIN_SCHEMA = pins.gpio_base_schema( cv.int_range(min=0, max=15), modes=[CONF_INPUT, CONF_OUTPUT], mode_validator=validate_mode, - invertable=True, + invertible=True, ).extend( { cv.Required(CONF_TCA9555): cv.use_id(TCA9555Component), diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index 0aed2c8f46..9926ebc553 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -1,8 +1,8 @@ #include "tcs34725.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" -#include #include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include namespace esphome { namespace tcs34725 { diff --git a/esphome/components/tee501/tee501.cpp b/esphome/components/tee501/tee501.cpp index 329aee7c52..45241627f9 100644 --- a/esphome/components/tee501/tee501.cpp +++ b/esphome/components/tee501/tee501.cpp @@ -1,4 +1,5 @@ #include "tee501.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/tem3200/tem3200.cpp b/esphome/components/tem3200/tem3200.cpp index 05bf580e11..c0655d02b8 100644 --- a/esphome/components/tem3200/tem3200.cpp +++ b/esphome/components/tem3200/tem3200.cpp @@ -1,7 +1,7 @@ #include "tem3200.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace tem3200 { @@ -43,7 +43,6 @@ void TEM3200Component::setup() { this->status_set_warning(); break; } - ESP_LOGCONFIG(TAG, " Success..."); } void TEM3200Component::dump_config() { diff --git a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp index 4b81ab1c35..c550d60630 100644 --- a/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +++ b/esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp @@ -29,8 +29,10 @@ void TemplateAlarmControlPanel::add_sensor(binary_sensor::BinarySensor *sensor, void TemplateAlarmControlPanel::dump_config() { ESP_LOGCONFIG(TAG, "TemplateAlarmControlPanel:"); - ESP_LOGCONFIG(TAG, " Current State: %s", LOG_STR_ARG(alarm_control_panel_state_to_string(this->current_state_))); - ESP_LOGCONFIG(TAG, " Number of Codes: %u", this->codes_.size()); + ESP_LOGCONFIG(TAG, + " Current State: %s\n" + " Number of Codes: %u", + LOG_STR_ARG(alarm_control_panel_state_to_string(this->current_state_)), this->codes_.size()); if (!this->codes_.empty()) ESP_LOGCONFIG(TAG, " Requires Code To Arm: %s", YESNO(this->requires_code_to_arm_)); ESP_LOGCONFIG(TAG, " Arming Away Time: %" PRIu32 "s", (this->arming_away_time_ / 1000)); @@ -38,19 +40,25 @@ void TemplateAlarmControlPanel::dump_config() { ESP_LOGCONFIG(TAG, " Arming Home Time: %" PRIu32 "s", (this->arming_home_time_ / 1000)); if (this->arming_night_time_ != 0) ESP_LOGCONFIG(TAG, " Arming Night Time: %" PRIu32 "s", (this->arming_night_time_ / 1000)); - ESP_LOGCONFIG(TAG, " Pending Time: %" PRIu32 "s", (this->pending_time_ / 1000)); - ESP_LOGCONFIG(TAG, " Trigger Time: %" PRIu32 "s", (this->trigger_time_ / 1000)); - ESP_LOGCONFIG(TAG, " Supported Features: %" PRIu32, this->get_supported_features()); + ESP_LOGCONFIG(TAG, + " Pending Time: %" PRIu32 "s\n" + " Trigger Time: %" PRIu32 "s\n" + " Supported Features: %" PRIu32, + (this->pending_time_ / 1000), (this->trigger_time_ / 1000), this->get_supported_features()); #ifdef USE_BINARY_SENSOR for (auto sensor_info : this->sensor_map_) { ESP_LOGCONFIG(TAG, " Binary Sensor:"); - ESP_LOGCONFIG(TAG, " Name: %s", sensor_info.first->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Armed home bypass: %s", - TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME)); - ESP_LOGCONFIG(TAG, " Armed night bypass: %s", - TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT)); - ESP_LOGCONFIG(TAG, " Auto bypass: %s", TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_AUTO)); - ESP_LOGCONFIG(TAG, " Chime mode: %s", TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_CHIME)); + ESP_LOGCONFIG(TAG, + " Name: %s\n" + " Armed home bypass: %s\n" + " Armed night bypass: %s\n" + " Auto bypass: %s\n" + " Chime mode: %s", + sensor_info.first->get_name().c_str(), + TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_HOME), + TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_ARMED_NIGHT), + TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_AUTO), + TRUEFALSE(sensor_info.second.flags & BINARY_SENSOR_MODE_CHIME)); const char *sensor_type; switch (sensor_info.second.type) { case ALARM_SENSOR_TYPE_INSTANT: diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.cpp b/esphome/components/template/binary_sensor/template_binary_sensor.cpp index 5ce8894a8a..d1fb618695 100644 --- a/esphome/components/template/binary_sensor/template_binary_sensor.cpp +++ b/esphome/components/template/binary_sensor/template_binary_sensor.cpp @@ -6,16 +6,8 @@ namespace template_ { static const char *const TAG = "template.binary_sensor"; -void TemplateBinarySensor::setup() { - if (!this->publish_initial_state_) - return; +void TemplateBinarySensor::setup() { this->loop(); } - if (this->f_ != nullptr) { - this->publish_initial_state(this->f_().value_or(false)); - } else { - this->publish_initial_state(false); - } -} void TemplateBinarySensor::loop() { if (this->f_ == nullptr) return; diff --git a/esphome/components/template/select/template_select.cpp b/esphome/components/template/select/template_select.cpp index 599226f4ba..0160fab04b 100644 --- a/esphome/components/template/select/template_select.cpp +++ b/esphome/components/template/select/template_select.cpp @@ -66,9 +66,11 @@ void TemplateSelect::dump_config() { LOG_UPDATE_INTERVAL(this); if (this->f_.has_value()) return; - ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); - ESP_LOGCONFIG(TAG, " Initial Option: %s", this->initial_option_.c_str()); - ESP_LOGCONFIG(TAG, " Restore Value: %s", YESNO(this->restore_value_)); + ESP_LOGCONFIG(TAG, + " Optimistic: %s\n" + " Initial Option: %s\n" + " Restore Value: %s", + YESNO(this->optimistic_), this->initial_option_.c_str(), YESNO(this->restore_value_)); } } // namespace template_ diff --git a/esphome/components/template/valve/template_valve.cpp b/esphome/components/template/valve/template_valve.cpp index 99bf5e6d8a..8421f5e06f 100644 --- a/esphome/components/template/valve/template_valve.cpp +++ b/esphome/components/template/valve/template_valve.cpp @@ -66,8 +66,10 @@ Trigger<> *TemplateValve::get_toggle_trigger() const { return this->toggle_trigg void TemplateValve::dump_config() { LOG_VALVE("", "Template Valve", this); - ESP_LOGCONFIG(TAG, " Has position: %s", YESNO(this->has_position_)); - ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_)); + ESP_LOGCONFIG(TAG, + " Has position: %s\n" + " Optimistic: %s", + YESNO(this->has_position_), YESNO(this->optimistic_)); } void TemplateValve::control(const ValveCall &call) { diff --git a/esphome/components/text/__init__.py b/esphome/components/text/__init__.py index a864a0ba4f..40b3a90d6b 100644 --- a/esphome/components/text/__init__.py +++ b/esphome/components/text/__init__.py @@ -126,6 +126,7 @@ async def register_text( if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_text(var)) + CORE.register_platform_component("text", var) await setup_text_core_( var, config, min_length=min_length, max_length=max_length, pattern=pattern ) diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index 888b65745f..c7ac17c35a 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -215,6 +215,7 @@ async def register_text_sensor(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_text_sensor(var)) + CORE.register_platform_component("text_sensor", var) await setup_text_sensor_core_(var, config) diff --git a/esphome/components/thermostat/thermostat_climate.cpp b/esphome/components/thermostat/thermostat_climate.cpp index f7b3410df9..fe6ed8b159 100644 --- a/esphome/components/thermostat/thermostat_climate.cpp +++ b/esphome/components/thermostat/thermostat_climate.cpp @@ -537,7 +537,7 @@ void ThermostatClimate::switch_to_supplemental_action_(climate::ClimateAction ac default: return; } - ESP_LOGVV(TAG, "Updating supplemental action..."); + ESP_LOGVV(TAG, "Updating supplemental action"); this->supplemental_action_ = action; this->trigger_supplemental_action_(); } @@ -1300,37 +1300,48 @@ void ThermostatClimate::dump_config() { } ESP_LOGCONFIG(TAG, " Start-up Delay Enabled: %s", YESNO(this->use_startup_delay_)); if (this->supports_cool_) { - ESP_LOGCONFIG(TAG, " Cooling Parameters:"); - ESP_LOGCONFIG(TAG, " Deadband: %.1f°C", this->cooling_deadband_); - ESP_LOGCONFIG(TAG, " Overrun: %.1f°C", this->cooling_overrun_); + ESP_LOGCONFIG(TAG, + " Cooling Parameters:\n" + " Deadband: %.1f°C\n" + " Overrun: %.1f°C", + this->cooling_deadband_, this->cooling_overrun_); if ((this->supplemental_cool_delta_ > 0) || (this->timer_duration_(thermostat::TIMER_COOLING_MAX_RUN_TIME) > 0)) { - ESP_LOGCONFIG(TAG, " Supplemental Delta: %.1f°C", this->supplemental_cool_delta_); - ESP_LOGCONFIG(TAG, " Maximum Run Time: %" PRIu32 "s", + ESP_LOGCONFIG(TAG, + " Supplemental Delta: %.1f°C\n" + " Maximum Run Time: %" PRIu32 "s", + this->supplemental_cool_delta_, this->timer_duration_(thermostat::TIMER_COOLING_MAX_RUN_TIME) / 1000); } - ESP_LOGCONFIG(TAG, " Minimum Off Time: %" PRIu32 "s", - this->timer_duration_(thermostat::TIMER_COOLING_OFF) / 1000); - ESP_LOGCONFIG(TAG, " Minimum Run Time: %" PRIu32 "s", + ESP_LOGCONFIG(TAG, + " Minimum Off Time: %" PRIu32 "s\n" + " Minimum Run Time: %" PRIu32 "s", + this->timer_duration_(thermostat::TIMER_COOLING_OFF) / 1000, this->timer_duration_(thermostat::TIMER_COOLING_ON) / 1000); } if (this->supports_heat_) { - ESP_LOGCONFIG(TAG, " Heating Parameters:"); - ESP_LOGCONFIG(TAG, " Deadband: %.1f°C", this->heating_deadband_); - ESP_LOGCONFIG(TAG, " Overrun: %.1f°C", this->heating_overrun_); + ESP_LOGCONFIG(TAG, + " Heating Parameters:\n" + " Deadband: %.1f°C\n" + " Overrun: %.1f°C", + this->heating_deadband_, this->heating_overrun_); if ((this->supplemental_heat_delta_ > 0) || (this->timer_duration_(thermostat::TIMER_HEATING_MAX_RUN_TIME) > 0)) { - ESP_LOGCONFIG(TAG, " Supplemental Delta: %.1f°C", this->supplemental_heat_delta_); - ESP_LOGCONFIG(TAG, " Maximum Run Time: %" PRIu32 "s", + ESP_LOGCONFIG(TAG, + " Supplemental Delta: %.1f°C\n" + " Maximum Run Time: %" PRIu32 "s", + this->supplemental_heat_delta_, this->timer_duration_(thermostat::TIMER_HEATING_MAX_RUN_TIME) / 1000); } - ESP_LOGCONFIG(TAG, " Minimum Off Time: %" PRIu32 "s", - this->timer_duration_(thermostat::TIMER_HEATING_OFF) / 1000); - ESP_LOGCONFIG(TAG, " Minimum Run Time: %" PRIu32 "s", + ESP_LOGCONFIG(TAG, + " Minimum Off Time: %" PRIu32 "s\n" + " Minimum Run Time: %" PRIu32 "s", + this->timer_duration_(thermostat::TIMER_HEATING_OFF) / 1000, this->timer_duration_(thermostat::TIMER_HEATING_ON) / 1000); } if (this->supports_fan_only_) { - ESP_LOGCONFIG(TAG, " Fanning Minimum Off Time: %" PRIu32 "s", - this->timer_duration_(thermostat::TIMER_FANNING_OFF) / 1000); - ESP_LOGCONFIG(TAG, " Fanning Minimum Run Time: %" PRIu32 "s", + ESP_LOGCONFIG(TAG, + " Fanning Minimum Off Time: %" PRIu32 "s\n" + " Fanning Minimum Run Time: %" PRIu32 "s", + this->timer_duration_(thermostat::TIMER_FANNING_OFF) / 1000, this->timer_duration_(thermostat::TIMER_FANNING_ON) / 1000); } if (this->supports_fan_mode_on_ || this->supports_fan_mode_off_ || this->supports_fan_mode_auto_ || @@ -1341,14 +1352,17 @@ void ThermostatClimate::dump_config() { this->timer_duration_(thermostat::TIMER_FAN_MODE) / 1000); } ESP_LOGCONFIG(TAG, " Minimum Idle Time: %" PRIu32 "s", this->timer_[thermostat::TIMER_IDLE_ON].time / 1000); - ESP_LOGCONFIG(TAG, " Supports AUTO: %s", YESNO(this->supports_auto_)); - ESP_LOGCONFIG(TAG, " Supports HEAT/COOL: %s", YESNO(this->supports_heat_cool_)); - ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_)); - ESP_LOGCONFIG(TAG, " Supports DRY: %s", YESNO(this->supports_dry_)); - ESP_LOGCONFIG(TAG, " Supports FAN_ONLY: %s", YESNO(this->supports_fan_only_)); - ESP_LOGCONFIG(TAG, " Supports FAN_ONLY_ACTION_USES_FAN_MODE_TIMER: %s", - YESNO(this->supports_fan_only_action_uses_fan_mode_timer_)); - ESP_LOGCONFIG(TAG, " Supports FAN_ONLY_COOLING: %s", YESNO(this->supports_fan_only_cooling_)); + ESP_LOGCONFIG(TAG, + " Supports AUTO: %s\n" + " Supports HEAT/COOL: %s\n" + " Supports COOL: %s\n" + " Supports DRY: %s\n" + " Supports FAN_ONLY: %s\n" + " Supports FAN_ONLY_ACTION_USES_FAN_MODE_TIMER: %s\n" + " Supports FAN_ONLY_COOLING: %s", + YESNO(this->supports_auto_), YESNO(this->supports_heat_cool_), YESNO(this->supports_cool_), + YESNO(this->supports_dry_), YESNO(this->supports_fan_only_), + YESNO(this->supports_fan_only_action_uses_fan_mode_timer_), YESNO(this->supports_fan_only_cooling_)); if (this->supports_cool_) { ESP_LOGCONFIG(TAG, " Supports FAN_WITH_COOLING: %s", YESNO(this->supports_fan_with_cooling_)); } @@ -1356,21 +1370,31 @@ void ThermostatClimate::dump_config() { ESP_LOGCONFIG(TAG, " Supports FAN_WITH_HEATING: %s", YESNO(this->supports_fan_with_heating_)); } ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE ON: %s", YESNO(this->supports_fan_mode_on_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE OFF: %s", YESNO(this->supports_fan_mode_off_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE AUTO: %s", YESNO(this->supports_fan_mode_auto_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE LOW: %s", YESNO(this->supports_fan_mode_low_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE MEDIUM: %s", YESNO(this->supports_fan_mode_medium_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE HIGH: %s", YESNO(this->supports_fan_mode_high_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE MIDDLE: %s", YESNO(this->supports_fan_mode_middle_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE FOCUS: %s", YESNO(this->supports_fan_mode_focus_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE DIFFUSE: %s", YESNO(this->supports_fan_mode_diffuse_)); - ESP_LOGCONFIG(TAG, " Supports FAN MODE QUIET: %s", YESNO(this->supports_fan_mode_quiet_)); - ESP_LOGCONFIG(TAG, " Supports SWING MODE BOTH: %s", YESNO(this->supports_swing_mode_both_)); - ESP_LOGCONFIG(TAG, " Supports SWING MODE OFF: %s", YESNO(this->supports_swing_mode_off_)); - ESP_LOGCONFIG(TAG, " Supports SWING MODE HORIZONTAL: %s", YESNO(this->supports_swing_mode_horizontal_)); - ESP_LOGCONFIG(TAG, " Supports SWING MODE VERTICAL: %s", YESNO(this->supports_swing_mode_vertical_)); - ESP_LOGCONFIG(TAG, " Supports TWO SET POINTS: %s", YESNO(this->supports_two_points_)); + ESP_LOGCONFIG(TAG, + " Supports FAN MODE ON: %s\n" + " Supports FAN MODE OFF: %s\n" + " Supports FAN MODE AUTO: %s\n" + " Supports FAN MODE LOW: %s\n" + " Supports FAN MODE MEDIUM: %s\n" + " Supports FAN MODE HIGH: %s\n" + " Supports FAN MODE MIDDLE: %s\n" + " Supports FAN MODE FOCUS: %s\n" + " Supports FAN MODE DIFFUSE: %s\n" + " Supports FAN MODE QUIET: %s", + YESNO(this->supports_fan_mode_on_), YESNO(this->supports_fan_mode_off_), + YESNO(this->supports_fan_mode_auto_), YESNO(this->supports_fan_mode_low_), + YESNO(this->supports_fan_mode_medium_), YESNO(this->supports_fan_mode_high_), + YESNO(this->supports_fan_mode_middle_), YESNO(this->supports_fan_mode_focus_), + YESNO(this->supports_fan_mode_diffuse_), YESNO(this->supports_fan_mode_quiet_)); + ESP_LOGCONFIG(TAG, + " Supports SWING MODE BOTH: %s\n" + " Supports SWING MODE OFF: %s\n" + " Supports SWING MODE HORIZONTAL: %s\n" + " Supports SWING MODE VERTICAL: %s\n" + " Supports TWO SET POINTS: %s", + YESNO(this->supports_swing_mode_both_), YESNO(this->supports_swing_mode_off_), + YESNO(this->supports_swing_mode_horizontal_), YESNO(this->supports_swing_mode_vertical_), + YESNO(this->supports_two_points_)); ESP_LOGCONFIG(TAG, " Supported PRESETS: "); for (auto &it : this->preset_config_) { diff --git a/esphome/components/time_based/time_based_cover.cpp b/esphome/components/time_based/time_based_cover.cpp index ec219d6db7..1eb591fe6e 100644 --- a/esphome/components/time_based/time_based_cover.cpp +++ b/esphome/components/time_based/time_based_cover.cpp @@ -12,8 +12,10 @@ using namespace esphome::cover; void TimeBasedCover::dump_config() { LOG_COVER("", "Time Based Cover", this); - ESP_LOGCONFIG(TAG, " Open Duration: %.1fs", this->open_duration_ / 1e3f); - ESP_LOGCONFIG(TAG, " Close Duration: %.1fs", this->close_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, + " Open Duration: %.1fs\n" + " Close Duration: %.1fs", + this->open_duration_ / 1e3f, this->close_duration_ / 1e3f); } void TimeBasedCover::setup() { auto restore = this->restore_state_(); diff --git a/esphome/components/tlc59208f/tlc59208f_output.cpp b/esphome/components/tlc59208f/tlc59208f_output.cpp index 3441a41a59..b1aad42bd7 100644 --- a/esphome/components/tlc59208f/tlc59208f_output.cpp +++ b/esphome/components/tlc59208f/tlc59208f_output.cpp @@ -1,7 +1,7 @@ #include "tlc59208f_output.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace tlc59208f { @@ -73,7 +73,7 @@ static const uint8_t LDR_GRPPWM = 0x03; void TLC59208FOutput::setup() { ESP_LOGCONFIG(TAG, "Running setup"); - ESP_LOGV(TAG, " Resetting all devices on the bus..."); + ESP_LOGV(TAG, " Resetting all devices on the bus"); // Reset all devices on the bus if (this->bus_->write(TLC59208F_SWRST_ADDR >> 1, TLC59208F_SWRST_SEQ, 2) != i2c::ERROR_OK) { @@ -111,8 +111,10 @@ void TLC59208FOutput::setup() { } void TLC59208FOutput::dump_config() { - ESP_LOGCONFIG(TAG, "TLC59208F:"); - ESP_LOGCONFIG(TAG, " Mode: 0x%02X", this->mode_); + ESP_LOGCONFIG(TAG, + "TLC59208F:\n" + " Mode: 0x%02X", + this->mode_); if (this->is_failed()) { ESP_LOGE(TAG, "Setting up TLC59208F failed!"); diff --git a/esphome/components/tm1621/tm1621.cpp b/esphome/components/tm1621/tm1621.cpp index 8f18a3d384..502e45b35e 100644 --- a/esphome/components/tm1621/tm1621.cpp +++ b/esphome/components/tm1621/tm1621.cpp @@ -1,7 +1,7 @@ #include "tm1621.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace tm1621 { diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index db117645bd..358a683efb 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -1,7 +1,7 @@ #include "tm1637.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace tm1637 { @@ -135,10 +135,12 @@ void TM1637Display::setup() { this->display(); } void TM1637Display::dump_config() { - ESP_LOGCONFIG(TAG, "TM1637:"); - ESP_LOGCONFIG(TAG, " Intensity: %d", this->intensity_); - ESP_LOGCONFIG(TAG, " Inverted: %d", this->inverted_); - ESP_LOGCONFIG(TAG, " Length: %d", this->length_); + ESP_LOGCONFIG(TAG, + "TM1637:\n" + " Intensity: %d\n" + " Inverted: %d\n" + " Length: %d", + this->intensity_, this->inverted_, this->length_); LOG_PIN(" CLK Pin: ", this->clk_pin_); LOG_PIN(" DIO Pin: ", this->dio_pin_); LOG_UPDATE_INTERVAL(this); diff --git a/esphome/components/tm1638/tm1638.cpp b/esphome/components/tm1638/tm1638.cpp index a15b006046..f43b496b35 100644 --- a/esphome/components/tm1638/tm1638.cpp +++ b/esphome/components/tm1638/tm1638.cpp @@ -1,8 +1,8 @@ #include "tm1638.h" #include "sevenseg.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace tm1638 { @@ -20,7 +20,7 @@ static const uint8_t TM1638_UNKNOWN_CHAR = 0b11111111; static const uint8_t TM1638_SHIFT_DELAY = 4; // clock pause between commands, default 4ms void TM1638Component::setup() { - ESP_LOGD(TAG, "Setting up TM1638..."); + ESP_LOGCONFIG(TAG, "Running setup"); this->clk_pin_->setup(); // OUTPUT this->dio_pin_->setup(); // OUTPUT @@ -43,8 +43,10 @@ void TM1638Component::setup() { } void TM1638Component::dump_config() { - ESP_LOGCONFIG(TAG, "TM1638:"); - ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_); + ESP_LOGCONFIG(TAG, + "TM1638:\n" + " Intensity: %u", + this->intensity_); LOG_PIN(" CLK Pin: ", this->clk_pin_); LOG_PIN(" DIO Pin: ", this->dio_pin_); LOG_PIN(" STB Pin: ", this->stb_pin_); diff --git a/esphome/components/tm1651/tm1651.cpp b/esphome/components/tm1651/tm1651.cpp index 97beefff64..64c3e62b32 100644 --- a/esphome/components/tm1651/tm1651.cpp +++ b/esphome/components/tm1651/tm1651.cpp @@ -1,8 +1,8 @@ #ifdef USE_ARDUINO #include "tm1651.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace tm1651 { diff --git a/esphome/components/tmp1075/tmp1075.cpp b/esphome/components/tmp1075/tmp1075.cpp index b8f80e4abe..831f905bd2 100644 --- a/esphome/components/tmp1075/tmp1075.cpp +++ b/esphome/components/tmp1075/tmp1075.cpp @@ -47,14 +47,17 @@ void TMP1075Sensor::dump_config() { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); return; } - ESP_LOGCONFIG(TAG, " limit low : %.4f °C", alert_limit_low_); - ESP_LOGCONFIG(TAG, " limit high : %.4f °C", alert_limit_high_); - ESP_LOGCONFIG(TAG, " oneshot : %d", config_.fields.oneshot); - ESP_LOGCONFIG(TAG, " rate : %d", config_.fields.rate); - ESP_LOGCONFIG(TAG, " fault_count: %d", config_.fields.faults); - ESP_LOGCONFIG(TAG, " polarity : %d", config_.fields.polarity); - ESP_LOGCONFIG(TAG, " alert_mode : %d", config_.fields.alert_mode); - ESP_LOGCONFIG(TAG, " shutdown : %d", config_.fields.shutdown); + ESP_LOGCONFIG(TAG, + " limit low : %.4f °C\n" + " limit high : %.4f °C\n" + " oneshot : %d\n" + " rate : %d\n" + " fault_count: %d\n" + " polarity : %d\n" + " alert_mode : %d\n" + " shutdown : %d", + alert_limit_low_, alert_limit_high_, config_.fields.oneshot, config_.fields.rate, config_.fields.faults, + config_.fields.polarity, config_.fields.alert_mode, config_.fields.shutdown); } void TMP1075Sensor::set_fault_count(const int faults) { diff --git a/esphome/components/tormatic/tormatic_cover.cpp b/esphome/components/tormatic/tormatic_cover.cpp index 35224c8ec7..be412d62a8 100644 --- a/esphome/components/tormatic/tormatic_cover.cpp +++ b/esphome/components/tormatic/tormatic_cover.cpp @@ -34,8 +34,10 @@ void Tormatic::dump_config() { LOG_COVER("", "Tormatic Cover", this); this->check_uart_settings(9600, 1, uart::UART_CONFIG_PARITY_NONE, 8); - ESP_LOGCONFIG(TAG, " Open Duration: %.1fs", this->open_duration_ / 1e3f); - ESP_LOGCONFIG(TAG, " Close Duration: %.1fs", this->close_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, + " Open Duration: %.1fs\n" + " Close Duration: %.1fs", + this->open_duration_ / 1e3f, this->close_duration_ / 1e3f); auto restore = this->restore_state_(); if (restore.has_value()) { diff --git a/esphome/components/tsl2561/tsl2561.cpp b/esphome/components/tsl2561/tsl2561.cpp index 4a24153dd5..1b5c9f2635 100644 --- a/esphome/components/tsl2561/tsl2561.cpp +++ b/esphome/components/tsl2561/tsl2561.cpp @@ -45,8 +45,10 @@ void TSL2561Sensor::dump_config() { } int gain = this->gain_ == TSL2561_GAIN_1X ? 1 : 16; - ESP_LOGCONFIG(TAG, " Gain: %dx", gain); - ESP_LOGCONFIG(TAG, " Integration Time: %.1f ms", this->get_integration_time_ms_()); + ESP_LOGCONFIG(TAG, + " Gain: %dx\n" + " Integration Time: %.1f ms", + gain, this->get_integration_time_ms_()); LOG_UPDATE_INTERVAL(this); } @@ -65,7 +67,7 @@ void TSL2561Sensor::update() { float TSL2561Sensor::calculate_lx_(uint16_t ch0, uint16_t ch1) { if ((ch0 == 0xFFFF) || (ch1 == 0xFFFF)) { - ESP_LOGW(TAG, "TSL2561 sensor is saturated."); + ESP_LOGW(TAG, "Sensor is saturated"); return NAN; } diff --git a/esphome/components/tsl2591/tsl2591.cpp b/esphome/components/tsl2591/tsl2591.cpp index 7799d727ba..1734d83dd2 100644 --- a/esphome/components/tsl2591/tsl2591.cpp +++ b/esphome/components/tsl2591/tsl2591.cpp @@ -26,13 +26,13 @@ static const char *const TAG = "tsl2591.sensor"; void TSL2591Component::enable() { // Enable the device by setting the control bit to 0x01. Also turn on ADCs. if (!this->write_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN)) { - ESP_LOGE(TAG, "Failed I2C write during enable()"); + ESP_LOGE(TAG, "I2C write failed"); } } void TSL2591Component::disable() { if (!this->write_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWEROFF)) { - ESP_LOGE(TAG, "Failed I2C write during disable()"); + ESP_LOGE(TAG, "I2C write failed"); } } @@ -43,6 +43,7 @@ void TSL2591Component::disable_if_power_saving_() { } void TSL2591Component::setup() { + ESP_LOGCONFIG(TAG, "Running setup for address 0x%02X", this->address_); switch (this->component_gain_) { case TSL2591_CGAIN_LOW: this->gain_ = TSL2591_GAIN_LOW; @@ -61,21 +62,15 @@ void TSL2591Component::setup() { break; } - uint8_t address = this->address_; - ESP_LOGI(TAG, "Setting up TSL2591 sensor at I2C address 0x%02X", address); - uint8_t id; if (!this->read_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_DEVICE_ID, &id)) { - ESP_LOGE(TAG, "Failed I2C read during setup()"); + ESP_LOGE(TAG, "I2C read failed"); this->mark_failed(); return; } if (id != 0x50) { - ESP_LOGE(TAG, - "Could not find the TSL2591 sensor. The ID register of the device at address 0x%02X reported 0x%02X " - "instead of 0x50.", - address, id); + ESP_LOGE(TAG, "Unknown chip ID"); this->mark_failed(); return; } @@ -119,13 +114,16 @@ void TSL2591Component::dump_config() { gain_word = "auto"; break; } - ESP_LOGCONFIG(TAG, " Gain: %dx (%s)", gain, gain_word.c_str()); TSL2591IntegrationTime raw_timing = this->integration_time_; int timing_ms = (1 + raw_timing) * 100; - ESP_LOGCONFIG(TAG, " Integration Time: %d ms", timing_ms); - ESP_LOGCONFIG(TAG, " Power save mode enabled: %s", ONOFF(this->power_save_mode_enabled_)); - ESP_LOGCONFIG(TAG, " Device factor: %f", this->device_factor_); - ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); + ESP_LOGCONFIG(TAG, + " Gain: %dx (%s)" + " Integration Time: %d ms\n" + " Power save mode enabled: %s\n" + " Device factor: %f\n" + " Glass attenuation factor: %f", + gain, gain_word.c_str(), timing_ms, ONOFF(this->power_save_mode_enabled_), this->device_factor_, + this->glass_attenuation_factor_); LOG_SENSOR(" ", "Full spectrum:", this->full_spectrum_sensor_); LOG_SENSOR(" ", "Infrared:", this->infrared_sensor_); LOG_SENSOR(" ", "Visible:", this->visible_sensor_); @@ -174,7 +172,7 @@ void TSL2591Component::interval_function_for_update_() { uint64_t now = millis(); ESP_LOGD(TAG, "Elapsed %3llu ms; still waiting for valid ADC", (now - this->interval_start_)); if (now > this->interval_timeout_) { - ESP_LOGW(TAG, "Interval timeout for TSL2591 '%s' expired before ADCs became valid.", this->name_); + ESP_LOGW(TAG, "Interval timeout for '%s' expired before ADCs became valid", this->name_); this->cancel_interval(interval_name); } return; @@ -235,7 +233,7 @@ void TSL2591Component::set_integration_time_and_gain(TSL2591IntegrationTime inte this->gain_ = gain; if (!this->write_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, this->integration_time_ | this->gain_)) { // NOLINT - ESP_LOGE(TAG, "Failed I2C write during set_integration_time_and_gain()"); + ESP_LOGE(TAG, "I2C write failed"); } // The ADC values can be confused if gain or integration time are changed in the middle of a cycle. // So, we unconditionally disable the device to turn the ADCs off. When re-enabling, the ADCs @@ -255,7 +253,7 @@ float TSL2591Component::get_setup_priority() const { return setup_priority::DATA bool TSL2591Component::is_adc_valid() { uint8_t status; if (!this->read_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_STATUS, &status)) { - ESP_LOGE(TAG, "Failed I2C read during is_adc_valid()"); + ESP_LOGE(TAG, "I2C read failed"); return false; } return status & 0x01; @@ -281,7 +279,7 @@ uint32_t TSL2591Component::get_combined_illuminance() { if (!avalid) { // still not valid after a sutiable delay // we don't mark the device as failed since it might come around in the future (probably not :-() - ESP_LOGE(TAG, "tsl2591 device '%s' did not return valid readings.", this->name_); + ESP_LOGE(TAG, "Device '%s' returned invalid readings", this->name_); this->disable_if_power_saving_(); return 0; } @@ -295,20 +293,20 @@ uint32_t TSL2591Component::get_combined_illuminance() { uint16_t ch0_16; uint16_t ch1_16; if (!this->read_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_LOW, &ch0low)) { - ESP_LOGE(TAG, "Failed I2C read during get_combined_illuminance()"); + ESP_LOGE(TAG, "I2C read failed"); return 0; } if (!this->read_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_HIGH, &ch0high)) { - ESP_LOGE(TAG, "Failed I2C read during get_combined_illuminance()"); + ESP_LOGE(TAG, "I2C read failed"); return 0; } ch0_16 = (ch0high << 8) | ch0low; if (!this->read_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN1_LOW, &ch1low)) { - ESP_LOGE(TAG, "Failed I2C read during get_combined_illuminance()"); + ESP_LOGE(TAG, "I2C read failed"); return 0; } if (!this->read_byte(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN1_HIGH, &ch1high)) { - ESP_LOGE(TAG, "Failed I2C read during get_combined_illuminance()"); + ESP_LOGE(TAG, "I2C read failed"); return 0; } ch1_16 = (ch1high << 8) | ch1low; @@ -335,7 +333,7 @@ uint16_t TSL2591Component::get_illuminance(TSL2591SensorChannel channel, uint32_ return ((combined_illuminance & 0xFFFF) - (combined_illuminance >> 16)); } // unknown channel! - ESP_LOGE(TAG, "TSL2591Component::get_illuminance() caller requested an unknown channel: %d", channel); + ESP_LOGE(TAG, "get_illuminance() caller requested an unknown channel: %d", channel); return 0; } @@ -358,13 +356,13 @@ float TSL2591Component::get_calculated_lux(uint16_t full_spectrum, uint16_t infr uint16_t max_count = (this->integration_time_ == TSL2591_INTEGRATION_TIME_100MS ? 36863 : 65535); if ((full_spectrum == max_count) || (infrared == max_count)) { // Signal an overflow - ESP_LOGW(TAG, "Apparent saturation on TSL2591 (%s). You could reduce the gain or integration time.", this->name_); + ESP_LOGW(TAG, "Apparent saturation on '%s'; try reducing the gain or integration time", this->name_); return NAN; } if ((full_spectrum == 0) && (infrared == 0)) { // trivial conversion; avoids divide by 0 - ESP_LOGW(TAG, "Zero reading on both TSL2591 (%s) sensors. Is the device having a problem?", this->name_); + ESP_LOGW(TAG, "Zero reading on both '%s' sensors", this->name_); return 0.0F; } diff --git a/esphome/components/tuya/select/tuya_select.cpp b/esphome/components/tuya/select/tuya_select.cpp index 02643e97f4..07b0ff2815 100644 --- a/esphome/components/tuya/select/tuya_select.cpp +++ b/esphome/components/tuya/select/tuya_select.cpp @@ -44,9 +44,11 @@ void TuyaSelect::control(const std::string &value) { void TuyaSelect::dump_config() { LOG_SELECT("", "Tuya Select", this); - ESP_LOGCONFIG(TAG, " Select has datapoint ID %u", this->select_id_); - ESP_LOGCONFIG(TAG, " Data type: %s", this->is_int_ ? "int" : "enum"); - ESP_LOGCONFIG(TAG, " Options are:"); + ESP_LOGCONFIG(TAG, + " Select has datapoint ID %u\n" + " Data type: %s\n" + " Options are:", + this->select_id_, this->is_int_ ? "int" : "enum"); auto options = this->traits.get_options(); for (auto i = 0; i < this->mappings_.size(); i++) { ESP_LOGCONFIG(TAG, " %i: %s", this->mappings_.at(i), options.at(i).c_str()); diff --git a/esphome/components/tx20/tx20.cpp b/esphome/components/tx20/tx20.cpp index 4d614c1e4e..73b865e8b8 100644 --- a/esphome/components/tx20/tx20.cpp +++ b/esphome/components/tx20/tx20.cpp @@ -1,6 +1,6 @@ #include "tx20.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include @@ -44,7 +44,7 @@ float Tx20Component::get_setup_priority() const { return setup_priority::DATA; } std::string Tx20Component::get_wind_cardinal_direction() const { return this->wind_cardinal_direction_; } void Tx20Component::decode_and_publish_() { - ESP_LOGVV(TAG, "Decode Tx20..."); + ESP_LOGVV(TAG, "Decode Tx20"); std::string string_buffer; std::string string_buffer_2; diff --git a/esphome/components/uart/button/uart_button.cpp b/esphome/components/uart/button/uart_button.cpp index 4db164c400..dd228b9bb7 100644 --- a/esphome/components/uart/button/uart_button.cpp +++ b/esphome/components/uart/button/uart_button.cpp @@ -7,7 +7,7 @@ namespace uart { static const char *const TAG = "uart.button"; void UARTButton::press_action() { - ESP_LOGD(TAG, "'%s': Sending data...", this->get_name().c_str()); + ESP_LOGD(TAG, "'%s': Sending data", this->get_name().c_str()); this->write_array(this->data_.data(), this->data_.size()); } diff --git a/esphome/components/uart/switch/uart_switch.cpp b/esphome/components/uart/switch/uart_switch.cpp index 96f50ff50f..4f5ff9fc99 100644 --- a/esphome/components/uart/switch/uart_switch.cpp +++ b/esphome/components/uart/switch/uart_switch.cpp @@ -19,11 +19,11 @@ void UARTSwitch::loop() { void UARTSwitch::write_command_(bool state) { if (state && !this->data_on_.empty()) { - ESP_LOGD(TAG, "'%s': Sending on data...", this->get_name().c_str()); + ESP_LOGD(TAG, "'%s': Sending on data", this->get_name().c_str()); this->write_array(this->data_on_.data(), this->data_on_.size()); } if (!state && !this->data_off_.empty()) { - ESP_LOGD(TAG, "'%s': Sending off data...", this->get_name().c_str()); + ESP_LOGD(TAG, "'%s': Sending off data", this->get_name().c_str()); this->write_array(this->data_off_.data(), this->data_off_.size()); } } diff --git a/esphome/components/uart/uart.cpp b/esphome/components/uart/uart.cpp index 9834462ff9..b18454bf9d 100644 --- a/esphome/components/uart/uart.cpp +++ b/esphome/components/uart/uart.cpp @@ -1,8 +1,8 @@ #include "uart.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/application.h" #include "esphome/core/defines.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include namespace esphome { diff --git a/esphome/components/uart/uart_component_esp32_arduino.cpp b/esphome/components/uart/uart_component_esp32_arduino.cpp index 0ed1a724e9..7441d8c1b3 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.cpp +++ b/esphome/components/uart/uart_component_esp32_arduino.cpp @@ -154,10 +154,12 @@ void ESP32ArduinoUARTComponent::dump_config() { if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); } - ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); - ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + ESP_LOGCONFIG(TAG, + " Baud Rate: %u baud\n" + " Data Bits: %u\n" + " Parity: %s\n" + " Stop bits: %u", + this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_); this->check_logger_conflict(); } @@ -191,7 +193,7 @@ bool ESP32ArduinoUARTComponent::read_array(uint8_t *data, size_t len) { int ESP32ArduinoUARTComponent::available() { return this->hw_serial_->available(); } void ESP32ArduinoUARTComponent::flush() { - ESP_LOGVV(TAG, " Flushing..."); + ESP_LOGVV(TAG, " Flushing"); this->hw_serial_->flush(); } diff --git a/esphome/components/uart/uart_component_esp8266.cpp b/esphome/components/uart/uart_component_esp8266.cpp index b06f553a47..7f4cc7b37c 100644 --- a/esphome/components/uart/uart_component_esp8266.cpp +++ b/esphome/components/uart/uart_component_esp8266.cpp @@ -99,7 +99,7 @@ void ESP8266UartComponent::setup() { } void ESP8266UartComponent::load_settings(bool dump_config) { - ESP_LOGCONFIG(TAG, "Loading UART bus settings..."); + ESP_LOGCONFIG(TAG, "Loading UART bus settings"); if (this->hw_serial_ != nullptr) { SerialConfig config = static_cast(get_config()); this->hw_serial_->begin(this->baud_rate_, config); @@ -121,10 +121,12 @@ void ESP8266UartComponent::dump_config() { if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); // NOLINT } - ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); - ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + ESP_LOGCONFIG(TAG, + " Baud Rate: %u baud\n" + " Data Bits: %u\n" + " Parity: %s\n" + " Stop bits: %u", + this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_); if (this->hw_serial_ != nullptr) { ESP_LOGCONFIG(TAG, " Using hardware serial interface."); } else { @@ -193,7 +195,7 @@ int ESP8266UartComponent::available() { } } void ESP8266UartComponent::flush() { - ESP_LOGVV(TAG, " Flushing..."); + ESP_LOGVV(TAG, " Flushing"); if (this->hw_serial_ != nullptr) { this->hw_serial_->flush(); } else { diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 9d5d22da6b..84bd48d530 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -162,10 +162,12 @@ void IDFUARTComponent::dump_config() { if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); } - ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); - ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + ESP_LOGCONFIG(TAG, + " Baud Rate: %" PRIu32 " baud\n" + " Data Bits: %u\n" + " Parity: %s\n" + " Stop bits: %u", + this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_); this->check_logger_conflict(); } @@ -234,7 +236,7 @@ int IDFUARTComponent::available() { } void IDFUARTComponent::flush() { - ESP_LOGVV(TAG, " Flushing..."); + ESP_LOGVV(TAG, " Flushing"); xSemaphoreTake(this->lock_, portMAX_DELAY); uart_wait_tx_done(this->uart_num_, portMAX_DELAY); xSemaphoreGive(this->lock_); diff --git a/esphome/components/uart/uart_component_host.cpp b/esphome/components/uart/uart_component_host.cpp index 40d3e91ab2..adb11266c5 100644 --- a/esphome/components/uart/uart_component_host.cpp +++ b/esphome/components/uart/uart_component_host.cpp @@ -109,7 +109,7 @@ HostUartComponent::~HostUartComponent() { } void HostUartComponent::setup() { - ESP_LOGCONFIG(TAG, "Opening UART port..."); + ESP_LOGCONFIG(TAG, "Opening UART port"); speed_t baud = get_baud(this->baud_rate_); if (baud == B0) { ESP_LOGE(TAG, "Unsupported baud rate: %d", this->baud_rate_); @@ -188,14 +188,17 @@ void HostUartComponent::dump_config() { } return; } - ESP_LOGCONFIG(TAG, " Port status: opened"); - ESP_LOGCONFIG(TAG, " Baud Rate: %d", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %d", this->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", + ESP_LOGCONFIG(TAG, + " Port status: opened\n" + " Baud Rate: %d\n" + " Data Bits: %d\n" + " Parity: %s\n" + " Stop Bits: %d", + this->baud_rate_, this->data_bits_, this->parity_ == UART_CONFIG_PARITY_NONE ? "None" : this->parity_ == UART_CONFIG_PARITY_EVEN ? "Even" - : "Odd"); - ESP_LOGCONFIG(TAG, " Stop Bits: %d", this->stop_bits_); + : "Odd", + this->stop_bits_); this->check_logger_conflict(); } @@ -283,7 +286,7 @@ void HostUartComponent::flush() { return; } tcflush(this->file_descriptor_, TCIOFLUSH); - ESP_LOGV(TAG, " Flushing..."); + ESP_LOGV(TAG, " Flushing"); } void HostUartComponent::update_error_(const std::string &error) { diff --git a/esphome/components/uart/uart_component_libretiny.cpp b/esphome/components/uart/uart_component_libretiny.cpp index bfb183d964..ffdb329669 100644 --- a/esphome/components/uart/uart_component_libretiny.cpp +++ b/esphome/components/uart/uart_component_libretiny.cpp @@ -108,10 +108,12 @@ void LibreTinyUARTComponent::dump_config() { if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); } - ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); - ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + ESP_LOGCONFIG(TAG, + " Baud Rate: %u baud\n" + " Data Bits: %u\n" + " Parity: %s\n" + " Stop bits: %u", + this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_); this->check_logger_conflict(); } @@ -145,7 +147,7 @@ bool LibreTinyUARTComponent::read_array(uint8_t *data, size_t len) { int LibreTinyUARTComponent::available() { return this->serial_->available(); } void LibreTinyUARTComponent::flush() { - ESP_LOGVV(TAG, " Flushing..."); + ESP_LOGVV(TAG, " Flushing"); this->serial_->flush(); } diff --git a/esphome/components/uart/uart_component_rp2040.cpp b/esphome/components/uart/uart_component_rp2040.cpp index c1a2e50ae0..f375d4a93f 100644 --- a/esphome/components/uart/uart_component_rp2040.cpp +++ b/esphome/components/uart/uart_component_rp2040.cpp @@ -136,10 +136,12 @@ void RP2040UartComponent::dump_config() { if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); } - ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_))); - ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); + ESP_LOGCONFIG(TAG, + " Baud Rate: %u baud\n" + " Data Bits: %u\n" + " Parity: %s\n" + " Stop bits: %u", + this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_); if (this->hw_serial_) { ESP_LOGCONFIG(TAG, " Using hardware serial"); } else { @@ -174,7 +176,7 @@ bool RP2040UartComponent::read_array(uint8_t *data, size_t len) { } int RP2040UartComponent::available() { return this->serial_->available(); } void RP2040UartComponent::flush() { - ESP_LOGVV(TAG, " Flushing..."); + ESP_LOGVV(TAG, " Flushing"); this->serial_->flush(); } diff --git a/esphome/components/udp/udp_component.cpp b/esphome/components/udp/udp_component.cpp index 222c73f82e..62a1189355 100644 --- a/esphome/components/udp/udp_component.cpp +++ b/esphome/components/udp/udp_component.cpp @@ -122,16 +122,20 @@ void UDPComponent::loop() { } void UDPComponent::dump_config() { - ESP_LOGCONFIG(TAG, "UDP:"); - ESP_LOGCONFIG(TAG, " Listen Port: %u", this->listen_port_); - ESP_LOGCONFIG(TAG, " Broadcast Port: %u", this->broadcast_port_); + ESP_LOGCONFIG(TAG, + "UDP:\n" + " Listen Port: %u\n" + " Broadcast Port: %u", + this->listen_port_, this->broadcast_port_); for (const auto &address : this->addresses_) ESP_LOGCONFIG(TAG, " Address: %s", address.c_str()); if (this->listen_address_.has_value()) { ESP_LOGCONFIG(TAG, " Listen address: %s", this->listen_address_.value().str().c_str()); } - ESP_LOGCONFIG(TAG, " Broadcasting: %s", YESNO(this->should_broadcast_)); - ESP_LOGCONFIG(TAG, " Listening: %s", YESNO(this->should_listen_)); + ESP_LOGCONFIG(TAG, + " Broadcasting: %s\n" + " Listening: %s", + YESNO(this->should_broadcast_), YESNO(this->should_listen_)); } void UDPComponent::send_packet(const uint8_t *data, size_t size) { diff --git a/esphome/components/ufire_ec/ufire_ec.cpp b/esphome/components/ufire_ec/ufire_ec.cpp index 6a418e51b7..813e667a00 100644 --- a/esphome/components/ufire_ec/ufire_ec.cpp +++ b/esphome/components/ufire_ec/ufire_ec.cpp @@ -110,8 +110,10 @@ void UFireECComponent::dump_config() { LOG_SENSOR(" ", "EC Sensor", this->ec_sensor_) LOG_SENSOR(" ", "Temperature Sensor", this->temperature_sensor_) LOG_SENSOR(" ", "Temperature Sensor external", this->temperature_sensor_external_) - ESP_LOGCONFIG(TAG, " Temperature Compensation: %f", this->temperature_compensation_); - ESP_LOGCONFIG(TAG, " Temperature Coefficient: %f", this->temperature_coefficient_); + ESP_LOGCONFIG(TAG, + " Temperature Compensation: %f\n" + " Temperature Coefficient: %f", + this->temperature_compensation_, this->temperature_coefficient_); } } // namespace ufire_ec diff --git a/esphome/components/ultrasonic/ultrasonic_sensor.cpp b/esphome/components/ultrasonic/ultrasonic_sensor.cpp index b3ed6833ec..b737dfa4cd 100644 --- a/esphome/components/ultrasonic/ultrasonic_sensor.cpp +++ b/esphome/components/ultrasonic/ultrasonic_sensor.cpp @@ -45,8 +45,10 @@ void UltrasonicSensorComponent::dump_config() { LOG_SENSOR("", "Ultrasonic Sensor", this); LOG_PIN(" Echo Pin: ", this->echo_pin_); LOG_PIN(" Trigger Pin: ", this->trigger_pin_); - ESP_LOGCONFIG(TAG, " Pulse time: %" PRIu32 " µs", this->pulse_time_us_); - ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 " µs", this->timeout_us_); + ESP_LOGCONFIG(TAG, + " Pulse time: %" PRIu32 " µs\n" + " Timeout: %" PRIu32 " µs", + this->pulse_time_us_, this->timeout_us_); LOG_UPDATE_INTERVAL(this); } float UltrasonicSensorComponent::us_to_m(uint32_t us) { diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index c2654520fd..09b0698903 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -111,6 +111,7 @@ async def register_update(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_update(var)) + CORE.register_platform_component("update", var) await setup_update_core_(var, config) diff --git a/esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp b/esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp index cc9b8a0f90..d7e672d8cf 100644 --- a/esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +++ b/esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp @@ -1,7 +1,7 @@ #include "uponor_smatrix_climate.h" +#include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/application.h" namespace esphome { namespace uponor_smatrix { diff --git a/esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp b/esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp index 47ff3a17f5..452660dc14 100644 --- a/esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +++ b/esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp @@ -7,8 +7,10 @@ namespace uponor_smatrix { static const char *const TAG = "uponor_smatrix.sensor"; void UponorSmatrixSensor::dump_config() { - ESP_LOGCONFIG(TAG, "Uponor Smatrix Sensor"); - ESP_LOGCONFIG(TAG, " Device address: 0x%04X", this->address_); + ESP_LOGCONFIG(TAG, + "Uponor Smatrix Sensor\n" + " Device address: 0x%04X", + this->address_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "External Temperature", this->external_temperature_sensor_); LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index 2dbbef72ab..a0017518bf 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -1,6 +1,7 @@ #include "uponor_smatrix.h" -#include "esphome/core/log.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace uponor_smatrix { diff --git a/esphome/components/usb_host/usb_host_client.cpp b/esphome/components/usb_host/usb_host_client.cpp index 09422f570f..fc5f772f41 100644 --- a/esphome/components/usb_host/usb_host_client.cpp +++ b/esphome/components/usb_host/usb_host_client.cpp @@ -381,9 +381,11 @@ void USBClient::transfer_out(uint8_t ep_address, const transfer_cb_t &callback, } } void USBClient::dump_config() { - ESP_LOGCONFIG(TAG, "USBClient"); - ESP_LOGCONFIG(TAG, " Vendor id %04X", this->vid_); - ESP_LOGCONFIG(TAG, " Product id %04X", this->pid_); + ESP_LOGCONFIG(TAG, + "USBClient\n" + " Vendor id %04X\n" + " Product id %04X", + this->vid_, this->pid_); } void USBClient::release_trq(TransferRequest *trq) { this->trq_pool_.push_back(trq); } diff --git a/esphome/components/usb_uart/usb_uart.cpp b/esphome/components/usb_uart/usb_uart.cpp index 30a45f9cb0..e599409f0c 100644 --- a/esphome/components/usb_uart/usb_uart.cpp +++ b/esphome/components/usb_uart/usb_uart.cpp @@ -178,13 +178,16 @@ void USBUartComponent::loop() { USBClient::loop(); } void USBUartComponent::dump_config() { USBClient::dump_config(); for (auto &channel : this->channels_) { - ESP_LOGCONFIG(TAG, " UART Channel %d", channel->index_); - ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", channel->baud_rate_); - ESP_LOGCONFIG(TAG, " Data Bits: %u", channel->data_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", PARITY_NAMES[channel->parity_]); - ESP_LOGCONFIG(TAG, " Stop bits: %s", STOP_BITS_NAMES[channel->stop_bits_]); - ESP_LOGCONFIG(TAG, " Debug: %s", YESNO(channel->debug_)); - ESP_LOGCONFIG(TAG, " Dummy receiver: %s", YESNO(channel->dummy_receiver_)); + ESP_LOGCONFIG(TAG, + " UART Channel %d\n" + " Baud Rate: %" PRIu32 " baud\n" + " Data Bits: %u\n" + " Parity: %s\n" + " Stop bits: %s\n" + " Debug: %s\n" + " Dummy receiver: %s", + channel->index_, channel->baud_rate_, channel->data_bits_, PARITY_NAMES[channel->parity_], + STOP_BITS_NAMES[channel->stop_bits_], YESNO(channel->debug_), YESNO(channel->dummy_receiver_)); } } void USBUartComponent::start_input(USBUartChannel *channel) { diff --git a/esphome/components/valve/__init__.py b/esphome/components/valve/__init__.py index f3c0353777..a6f1428cd2 100644 --- a/esphome/components/valve/__init__.py +++ b/esphome/components/valve/__init__.py @@ -163,6 +163,7 @@ async def register_valve(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_valve(var)) + CORE.register_platform_component("valve", var) await _setup_valve_core(var, config) diff --git a/esphome/components/veml3235/veml3235.cpp b/esphome/components/veml3235/veml3235.cpp index 965e167942..d5489216b6 100644 --- a/esphome/components/veml3235/veml3235.cpp +++ b/esphome/components/veml3235/veml3235.cpp @@ -217,13 +217,17 @@ void VEML3235Sensor::dump_config() { LOG_UPDATE_INTERVAL(this); ESP_LOGCONFIG(TAG, " Auto-gain enabled: %s", YESNO(this->auto_gain_)); if (this->auto_gain_) { - ESP_LOGCONFIG(TAG, " Auto-gain upper threshold: %f%%", this->auto_gain_threshold_high_ * 100.0); - ESP_LOGCONFIG(TAG, " Auto-gain lower threshold: %f%%", this->auto_gain_threshold_low_ * 100.0); - ESP_LOGCONFIG(TAG, " Values below will be used as initial values only"); + ESP_LOGCONFIG(TAG, + " Auto-gain upper threshold: %f%%\n" + " Auto-gain lower threshold: %f%%\n" + " Values below will be used as initial values only", + this->auto_gain_threshold_high_ * 100.0, this->auto_gain_threshold_low_ * 100.0); } - ESP_LOGCONFIG(TAG, " Digital gain: %uX", digital_gain); - ESP_LOGCONFIG(TAG, " Gain: %uX", gain); - ESP_LOGCONFIG(TAG, " Integration time: %ums", integration_time); + ESP_LOGCONFIG(TAG, + " Digital gain: %uX\n" + " Gain: %uX\n" + " Integration time: %ums", + digital_gain, gain, integration_time); } } // namespace veml3235 diff --git a/esphome/components/veml7700/veml7700.cpp b/esphome/components/veml7700/veml7700.cpp index 25f6c761c8..9d87a639a6 100644 --- a/esphome/components/veml7700/veml7700.cpp +++ b/esphome/components/veml7700/veml7700.cpp @@ -93,11 +93,15 @@ void VEML7700Component::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Automatic gain/time: %s", YESNO(this->automatic_mode_enabled_)); if (!this->automatic_mode_enabled_) { - ESP_LOGCONFIG(TAG, " Gain: %s", get_gain_str(this->gain_)); - ESP_LOGCONFIG(TAG, " Integration time: %d ms", get_itime_ms(this->integration_time_)); + ESP_LOGCONFIG(TAG, + " Gain: %s\n" + " Integration time: %d ms", + get_gain_str(this->gain_), get_itime_ms(this->integration_time_)); } - ESP_LOGCONFIG(TAG, " Lux compensation: %s", YESNO(this->lux_compensation_enabled_)); - ESP_LOGCONFIG(TAG, " Glass attenuation factor: %f", this->glass_attenuation_factor_); + ESP_LOGCONFIG(TAG, + " Lux compensation: %s\n" + " Glass attenuation factor: %f", + YESNO(this->lux_compensation_enabled_), this->glass_attenuation_factor_); LOG_UPDATE_INTERVAL(this); LOG_SENSOR(" ", "ALS channel lux", this->ambient_light_sensor_); diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 1aafea7d85..a692a7556e 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -204,7 +204,7 @@ void VoiceAssistant::loop() { break; } case State::START_PIPELINE: { - ESP_LOGD(TAG, "Requesting start..."); + ESP_LOGD(TAG, "Requesting start"); uint32_t flags = 0; if (!this->continue_conversation_ && this->use_wake_word_) flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD; @@ -223,7 +223,7 @@ void VoiceAssistant::loop() { msg.wake_word_phrase = this->wake_word_; this->wake_word_ = ""; - if (this->api_client_ == nullptr || !this->api_client_->send_voice_assistant_request(msg)) { + if (this->api_client_ == nullptr || !this->api_client_->send_message(msg)) { ESP_LOGW(TAG, "Could not request start"); this->error_trigger_->trigger("not-connected", "Could not request start"); this->continuous_ = false; @@ -245,7 +245,7 @@ void VoiceAssistant::loop() { if (this->audio_mode_ == AUDIO_MODE_API) { api::VoiceAssistantAudio msg; msg.data.assign((char *) this->send_buffer_, read_bytes); - this->api_client_->send_voice_assistant_audio(msg); + this->api_client_->send_message(msg); } else { if (!this->udp_socket_running_) { if (!this->start_udp_socket_()) { @@ -331,7 +331,7 @@ void VoiceAssistant::loop() { api::VoiceAssistantAnnounceFinished msg; msg.success = true; - this->api_client_->send_voice_assistant_announce_finished(msg); + this->api_client_->send_message(msg); break; } } @@ -577,10 +577,10 @@ void VoiceAssistant::signal_stop_() { if (this->api_client_ == nullptr) { return; } - ESP_LOGD(TAG, "Signaling stop..."); + ESP_LOGD(TAG, "Signaling stop"); api::VoiceAssistantRequest msg; msg.start = false; - this->api_client_->send_voice_assistant_request(msg); + this->api_client_->send_message(msg); } void VoiceAssistant::start_playback_timeout_() { @@ -590,7 +590,7 @@ void VoiceAssistant::start_playback_timeout_() { api::VoiceAssistantAnnounceFinished msg; msg.success = true; - this->api_client_->send_voice_assistant_announce_finished(msg); + this->api_client_->send_message(msg); }); } diff --git a/esphome/components/wake_on_lan/wake_on_lan.cpp b/esphome/components/wake_on_lan/wake_on_lan.cpp index d18cdf89c8..bed098755a 100644 --- a/esphome/components/wake_on_lan/wake_on_lan.cpp +++ b/esphome/components/wake_on_lan/wake_on_lan.cpp @@ -30,7 +30,7 @@ void WakeOnLanButton::press_action() { ESP_LOGW(TAG, "Network not connected"); return; } - ESP_LOGI(TAG, "Sending Wake-on-LAN Packet..."); + ESP_LOGI(TAG, "Sending Wake-on-LAN Packet"); #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) struct sockaddr_storage saddr {}; auto addr_len = diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 79aae70e41..084747c09e 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -1,7 +1,7 @@ #include "waveshare_epaper.h" -#include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include #include diff --git a/esphome/components/web_server/server_index_v2.h b/esphome/components/web_server/server_index_v2.h index 21a2a97465..ec093d3186 100644 --- a/esphome/components/web_server/server_index_v2.h +++ b/esphome/components/web_server/server_index_v2.h @@ -11,636 +11,638 @@ namespace web_server { const uint8_t INDEX_GZ[] PROGMEM = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x7d, 0xdb, 0x72, 0xdb, 0xc6, 0xb6, 0xe0, 0xf3, - 0xe4, 0x2b, 0x20, 0x44, 0x5b, 0x41, 0x6f, 0x36, 0x21, 0x92, 0x92, 0x6c, 0x19, 0x64, 0x93, 0x5b, 0x96, 0x9d, 0xed, - 0xec, 0xf8, 0x92, 0x58, 0x76, 0xb2, 0x13, 0x86, 0x5b, 0x82, 0x88, 0x26, 0xd9, 0x36, 0x88, 0x66, 0x80, 0x26, 0x25, - 0x85, 0xc4, 0xa9, 0xf9, 0x80, 0xa9, 0x9a, 0xaa, 0x79, 0x9a, 0x97, 0xa9, 0x39, 0x0f, 0xf3, 0x11, 0xf3, 0x7c, 0x3e, - 0xe5, 0xfc, 0xc0, 0xcc, 0x27, 0x4c, 0xad, 0xbe, 0x00, 0x0d, 0x5e, 0x64, 0xe5, 0x72, 0xce, 0x99, 0x4a, 0xc5, 0x22, - 0xfa, 0xba, 0x7a, 0xf5, 0xea, 0x75, 0x6f, 0xa0, 0xb3, 0x17, 0xf1, 0xa1, 0xb8, 0x9b, 0x51, 0x67, 0x22, 0xa6, 0x71, - 0xb7, 0xa3, 0xff, 0xa5, 0x61, 0xd4, 0xed, 0xc4, 0x2c, 0xf9, 0xe8, 0xa4, 0x34, 0x26, 0x6c, 0xc8, 0x13, 0x67, 0x92, - 0xd2, 0x11, 0x89, 0x42, 0x11, 0x06, 0x6c, 0x1a, 0x8e, 0xa9, 0x73, 0xd8, 0xed, 0x4c, 0xa9, 0x08, 0x9d, 0xe1, 0x24, - 0x4c, 0x33, 0x2a, 0xc8, 0xfb, 0x77, 0x5f, 0xd6, 0x4f, 0xbb, 0x9d, 0x6c, 0x98, 0xb2, 0x99, 0x70, 0x60, 0x48, 0x32, - 0xe5, 0xd1, 0x3c, 0xa6, 0xdd, 0xc3, 0xc3, 0x9b, 0x9b, 0x1b, 0xff, 0x43, 0xf6, 0xd9, 0x90, 0x27, 0x99, 0x70, 0x5e, - 0x92, 0x1b, 0x96, 0x44, 0xfc, 0x06, 0x53, 0x41, 0x5e, 0xfa, 0x17, 0x93, 0x30, 0xe2, 0x37, 0x6f, 0x39, 0x17, 0x07, - 0x07, 0x9e, 0x7a, 0xbc, 0x3b, 0xbf, 0xb8, 0x20, 0x84, 0x2c, 0x38, 0x8b, 0x9c, 0xc6, 0x6a, 0x55, 0x16, 0xfa, 0x49, - 0x28, 0xd8, 0x82, 0xaa, 0x2e, 0xe8, 0xe0, 0xc0, 0x0d, 0x23, 0x3e, 0x13, 0x34, 0xba, 0x10, 0x77, 0x31, 0xbd, 0x98, - 0x50, 0x2a, 0x32, 0x97, 0x25, 0xce, 0x33, 0x3e, 0x9c, 0x4f, 0x69, 0x22, 0xfc, 0x59, 0xca, 0x05, 0x07, 0x48, 0x0e, - 0x0e, 0xdc, 0x94, 0xce, 0xe2, 0x70, 0x48, 0xa1, 0xfe, 0xfc, 0xe2, 0xa2, 0xec, 0x51, 0x36, 0xc2, 0x4c, 0x90, 0x8b, - 0xbb, 0xe9, 0x35, 0x8f, 0x3d, 0x84, 0x63, 0x41, 0x12, 0x7a, 0xe3, 0x7c, 0x4f, 0xc3, 0x8f, 0xaf, 0xc2, 0x59, 0x7b, - 0x18, 0x87, 0x59, 0xe6, 0x5c, 0x8b, 0xa5, 0x5c, 0x42, 0x3a, 0x1f, 0x0a, 0x9e, 0x7a, 0x02, 0x53, 0xcc, 0xd0, 0x92, - 0x8d, 0x3c, 0x31, 0x61, 0x99, 0x7f, 0xb9, 0x3f, 0xcc, 0xb2, 0xb7, 0x34, 0x9b, 0xc7, 0x62, 0x9f, 0xec, 0x35, 0x30, - 0xdb, 0x23, 0x84, 0x09, 0x24, 0x26, 0x29, 0xbf, 0x71, 0x9e, 0xa7, 0x29, 0x4f, 0x3d, 0xf7, 0xfc, 0xe2, 0x42, 0xb5, - 0x70, 0x58, 0xe6, 0x24, 0x5c, 0x38, 0xc5, 0x78, 0xe1, 0x75, 0x4c, 0x7d, 0xe7, 0x7d, 0x46, 0x9d, 0xab, 0x79, 0x92, - 0x85, 0x23, 0x7a, 0x7e, 0x71, 0x71, 0xe5, 0xf0, 0xd4, 0xb9, 0x1a, 0x66, 0xd9, 0x95, 0xc3, 0x92, 0x4c, 0xd0, 0x30, - 0xf2, 0x5d, 0xd4, 0x96, 0x93, 0x0d, 0xb3, 0xec, 0x1d, 0xbd, 0x15, 0x44, 0x60, 0xf9, 0x28, 0x08, 0xcd, 0xc7, 0x54, - 0x38, 0x59, 0xb1, 0x2e, 0x0f, 0x2d, 0x63, 0x2a, 0x1c, 0x41, 0x64, 0x3d, 0x6f, 0x2b, 0xdc, 0x53, 0xf5, 0x28, 0xda, - 0x6c, 0xe4, 0x51, 0x71, 0x70, 0x20, 0x0a, 0x3c, 0x23, 0xb5, 0x34, 0x87, 0x11, 0xba, 0x67, 0xca, 0x0e, 0x0e, 0xa8, - 0x1f, 0xd3, 0x64, 0x2c, 0x26, 0x84, 0x90, 0x66, 0x9b, 0x1d, 0x1c, 0x78, 0x82, 0xc4, 0xc2, 0x1f, 0x53, 0xe1, 0x51, - 0x84, 0x70, 0xd9, 0xfb, 0xe0, 0xc0, 0x53, 0x48, 0xe0, 0x44, 0x21, 0xae, 0x82, 0x63, 0xe4, 0x6b, 0xec, 0x5f, 0xdc, - 0x25, 0x43, 0xcf, 0x86, 0x1f, 0x61, 0x76, 0x70, 0x10, 0x0b, 0x3f, 0x83, 0x11, 0xb1, 0x40, 0x28, 0x4f, 0xa9, 0x98, - 0xa7, 0x89, 0x23, 0x72, 0xc1, 0x2f, 0x44, 0xca, 0x92, 0xb1, 0x87, 0x96, 0xa6, 0xcc, 0xea, 0x98, 0xe7, 0x0a, 0xdc, - 0x6f, 0x04, 0x49, 0x49, 0x17, 0x66, 0xbc, 0x16, 0x1e, 0xec, 0x22, 0x1f, 0x39, 0x29, 0x21, 0x6e, 0x26, 0xfb, 0xba, - 0xbd, 0x34, 0x48, 0x6b, 0xae, 0x8b, 0x15, 0x94, 0x98, 0x09, 0x84, 0x3f, 0x12, 0x2f, 0xc5, 0xbe, 0xef, 0x0b, 0x44, - 0xba, 0x4b, 0x83, 0x95, 0xd4, 0x5a, 0x67, 0x2f, 0xed, 0x37, 0x06, 0x81, 0xf0, 0x53, 0x1a, 0xcd, 0x87, 0xd4, 0xf3, - 0x18, 0xce, 0x70, 0x82, 0x48, 0x97, 0xd5, 0x3c, 0x4e, 0xba, 0xb0, 0xdd, 0xbc, 0xba, 0xd7, 0x84, 0xec, 0x35, 0x90, - 0x86, 0x91, 0x1b, 0x00, 0x01, 0xc3, 0x1a, 0x1e, 0x4e, 0x88, 0x9b, 0xcc, 0xa7, 0xd7, 0x34, 0x75, 0x8b, 0x66, 0xed, - 0x0a, 0x59, 0xcc, 0x33, 0xea, 0x0c, 0xb3, 0xcc, 0x19, 0xcd, 0x93, 0xa1, 0x60, 0x3c, 0x71, 0xdc, 0x1a, 0xaf, 0xb9, - 0x8a, 0x1c, 0x0a, 0x6a, 0x70, 0x51, 0x8e, 0xbc, 0x0c, 0xd5, 0xd2, 0x7e, 0x52, 0x6b, 0x0e, 0x30, 0x40, 0x89, 0xda, - 0x7a, 0x3c, 0x8d, 0x00, 0x8a, 0x53, 0x58, 0x63, 0x8e, 0xdf, 0x0b, 0x58, 0xa5, 0x5c, 0x22, 0x15, 0xbd, 0xd4, 0xdf, - 0x3c, 0x28, 0x44, 0xf8, 0xd3, 0x70, 0xe6, 0x51, 0xd2, 0xa5, 0x92, 0xb8, 0xc2, 0x64, 0x08, 0xb0, 0x56, 0xf6, 0xad, - 0x47, 0x03, 0xea, 0x97, 0x24, 0x85, 0x02, 0xe1, 0x8f, 0x78, 0xfa, 0x3c, 0x1c, 0x4e, 0xa0, 0x5f, 0x41, 0x30, 0x91, - 0x39, 0x6f, 0xc3, 0x94, 0x86, 0x82, 0x3e, 0x8f, 0x29, 0x3c, 0x79, 0xae, 0xec, 0xe9, 0x22, 0x9c, 0x91, 0x97, 0x7e, - 0xcc, 0xc4, 0x6b, 0x9e, 0x0c, 0x69, 0x3b, 0xb3, 0xa8, 0x8b, 0xc1, 0xbe, 0x9f, 0x09, 0x91, 0xb2, 0xeb, 0xb9, 0xa0, - 0x9e, 0x9b, 0x40, 0x0b, 0x17, 0x67, 0x08, 0x33, 0x5f, 0xd0, 0x5b, 0x71, 0xce, 0x13, 0x41, 0x13, 0x41, 0xa8, 0x41, - 0x2a, 0x4e, 0xfd, 0x70, 0x36, 0xa3, 0x49, 0x74, 0x3e, 0x61, 0x71, 0xe4, 0x31, 0x94, 0xa3, 0x1c, 0x87, 0x82, 0xc0, - 0x1a, 0x49, 0x37, 0x0d, 0xe0, 0x9f, 0xdd, 0xab, 0xf1, 0x04, 0xe9, 0xca, 0x43, 0x41, 0x89, 0xeb, 0xb6, 0x47, 0x3c, - 0xf5, 0xf4, 0x0a, 0x1c, 0x3e, 0x72, 0x04, 0xcc, 0xf1, 0x76, 0x1e, 0xd3, 0x0c, 0xd1, 0x1a, 0x61, 0xc5, 0x36, 0x6a, - 0x04, 0x7f, 0x03, 0x14, 0x9f, 0x23, 0x2f, 0x45, 0x41, 0xda, 0x5e, 0x84, 0xa9, 0xf3, 0xa5, 0x3e, 0x51, 0xcf, 0x0c, - 0x37, 0x9b, 0x08, 0xf2, 0xcc, 0x17, 0xe9, 0x3c, 0x13, 0x34, 0x7a, 0x77, 0x37, 0xa3, 0x19, 0x7e, 0x27, 0xc8, 0x44, - 0xf4, 0x26, 0xc2, 0xa7, 0xd3, 0x99, 0xb8, 0xbb, 0x90, 0x8c, 0x31, 0x70, 0x5d, 0x3c, 0x84, 0x96, 0x29, 0x0d, 0x87, - 0xc0, 0xcc, 0x34, 0xb6, 0xbe, 0xe1, 0xf1, 0xdd, 0x88, 0xc5, 0xf1, 0xc5, 0x7c, 0x36, 0xe3, 0xa9, 0xc0, 0x7f, 0x25, - 0x4b, 0xc1, 0x4b, 0xd4, 0xc0, 0x5e, 0x2e, 0xb3, 0x1b, 0x26, 0x86, 0x13, 0x4f, 0xa0, 0xe5, 0x30, 0xcc, 0xa8, 0xf3, - 0x94, 0xf3, 0x98, 0x86, 0x49, 0x90, 0x92, 0xb4, 0xf7, 0x4e, 0x04, 0xc9, 0x3c, 0x8e, 0xdb, 0xd7, 0x29, 0x0d, 0x3f, - 0xb6, 0x65, 0xf5, 0x9b, 0xeb, 0x0f, 0x74, 0x28, 0x02, 0xf9, 0xfb, 0x2c, 0x4d, 0xc3, 0x3b, 0x68, 0x48, 0x08, 0x34, - 0xeb, 0xa5, 0xc1, 0xdf, 0x2e, 0xde, 0xbc, 0xf6, 0xd5, 0x21, 0x61, 0xa3, 0x3b, 0x2f, 0x2d, 0x0e, 0x5e, 0x9a, 0xe3, - 0x51, 0xca, 0xa7, 0x6b, 0x53, 0x2b, 0xac, 0xa5, 0xed, 0x1d, 0x20, 0x50, 0x92, 0xee, 0xa9, 0xa1, 0x6d, 0x08, 0x5e, - 0x4b, 0x9a, 0x87, 0x4a, 0xa2, 0xe7, 0x85, 0x7f, 0x02, 0x55, 0xec, 0xa5, 0xe8, 0x7e, 0x68, 0x45, 0x7a, 0xb7, 0xa4, - 0x44, 0xc2, 0x39, 0x03, 0x09, 0x03, 0x30, 0x0e, 0x43, 0x31, 0x9c, 0x2c, 0xa9, 0x1c, 0x2c, 0x37, 0x10, 0xd3, 0x3c, - 0xc7, 0x37, 0x05, 0xbd, 0x8b, 0x3d, 0x42, 0x52, 0xc9, 0xa8, 0x88, 0x58, 0xad, 0x52, 0x42, 0x52, 0x84, 0xbf, 0x27, - 0xcb, 0xd0, 0xac, 0x27, 0xd8, 0x6b, 0x60, 0x38, 0x97, 0x81, 0xe2, 0x2e, 0x78, 0xc8, 0x93, 0x05, 0x4d, 0x05, 0x4d, - 0x83, 0xbf, 0xe2, 0x94, 0x8e, 0x62, 0x80, 0x62, 0xaf, 0x89, 0x27, 0x61, 0x76, 0x3e, 0x09, 0x93, 0x31, 0x8d, 0x82, - 0x1b, 0x91, 0xe3, 0xbf, 0x13, 0x77, 0xc4, 0x92, 0x30, 0x66, 0xbf, 0xd0, 0xc8, 0xd5, 0xd2, 0xe0, 0xcc, 0xa1, 0xb7, - 0x82, 0x26, 0x51, 0xe6, 0xbc, 0x78, 0xf7, 0xea, 0xa5, 0xde, 0xc7, 0x8a, 0x80, 0x40, 0xcb, 0x6c, 0x3e, 0xa3, 0xa9, - 0x87, 0xb0, 0x16, 0x10, 0xcf, 0x99, 0x64, 0x8e, 0xaf, 0xc2, 0x99, 0x2a, 0x61, 0xd9, 0xfb, 0x59, 0x14, 0x0a, 0xfa, - 0x0d, 0x4d, 0x22, 0x96, 0x8c, 0xc9, 0x5e, 0x53, 0x95, 0x4f, 0x42, 0x5d, 0x11, 0x15, 0x45, 0x97, 0xfb, 0xcf, 0x63, - 0xb9, 0xee, 0xe2, 0x71, 0xee, 0xa1, 0x3c, 0x13, 0xa1, 0x60, 0x43, 0x27, 0x8c, 0xa2, 0xaf, 0x12, 0x26, 0x98, 0x04, - 0x30, 0x85, 0xed, 0x01, 0x12, 0xa5, 0x4a, 0x54, 0x18, 0xc0, 0x3d, 0x84, 0x3d, 0x4f, 0x0b, 0x80, 0x09, 0xd2, 0xfb, - 0x75, 0x70, 0x50, 0xb2, 0xfb, 0x1e, 0x0d, 0x54, 0x25, 0xe9, 0x0f, 0x90, 0x3f, 0x9b, 0x67, 0xb0, 0xd1, 0x66, 0x0a, - 0x90, 0x2e, 0xfc, 0x3a, 0xa3, 0xe9, 0x82, 0x46, 0x05, 0x71, 0x64, 0x1e, 0x5a, 0xae, 0xcd, 0xa1, 0x8f, 0x85, 0x20, - 0xfd, 0x41, 0xdb, 0xe6, 0xdb, 0x54, 0xd3, 0x79, 0xca, 0x67, 0x34, 0x15, 0x8c, 0x66, 0x05, 0x2b, 0xf1, 0x40, 0x8a, - 0x16, 0xec, 0x24, 0x23, 0x66, 0x7d, 0x33, 0x8f, 0x61, 0x8a, 0x2a, 0x0c, 0xc3, 0x08, 0xda, 0xe7, 0x0b, 0x29, 0x31, - 0x32, 0xcc, 0x10, 0x16, 0x0a, 0xd2, 0x0c, 0xa1, 0x1c, 0x61, 0x61, 0xc0, 0x55, 0xac, 0x48, 0xcf, 0x76, 0x07, 0xa2, - 0x9a, 0x7c, 0x2f, 0x45, 0x35, 0x30, 0xb4, 0x50, 0xd0, 0x83, 0x03, 0x8f, 0xfa, 0x05, 0x51, 0x90, 0xbd, 0xa6, 0xde, - 0x23, 0x0b, 0x59, 0x3b, 0xc0, 0x86, 0x89, 0x05, 0xa6, 0x08, 0xef, 0x51, 0x3f, 0xe1, 0x67, 0xc3, 0x21, 0xcd, 0x32, - 0x9e, 0x1e, 0x1c, 0xec, 0xc9, 0xf6, 0x85, 0x36, 0x01, 0x7b, 0xf8, 0xe6, 0x26, 0x29, 0x21, 0x40, 0xa5, 0x84, 0xd5, - 0x72, 0x41, 0x80, 0x9c, 0x92, 0x0a, 0x87, 0xdb, 0x33, 0x8a, 0x47, 0xe0, 0x5e, 0x5e, 0xba, 0x35, 0x81, 0x35, 0x1a, - 0xc6, 0xd4, 0x4c, 0x7d, 0xf7, 0x8c, 0x2a, 0xd5, 0x4a, 0x2a, 0x1e, 0x1b, 0x98, 0x51, 0xe7, 0xc7, 0x8f, 0xe8, 0x88, - 0x25, 0xd6, 0xb2, 0x2b, 0x20, 0x61, 0x81, 0x33, 0x94, 0x5b, 0x1b, 0xba, 0x75, 0x68, 0xa9, 0xd3, 0xa8, 0x9d, 0x5b, - 0x8e, 0xa5, 0x1e, 0x61, 0x6d, 0x63, 0x9f, 0x0e, 0x72, 0x2c, 0x51, 0x6f, 0x56, 0x93, 0x48, 0x40, 0xfb, 0x62, 0xd0, - 0xd6, 0xf5, 0x24, 0x53, 0x98, 0x4b, 0xe9, 0xcf, 0x73, 0x9a, 0x09, 0x45, 0xc7, 0x9e, 0xc0, 0x09, 0x66, 0x28, 0x87, - 0xe3, 0x36, 0x62, 0xe3, 0x79, 0x0a, 0xea, 0x0e, 0x1c, 0x45, 0x9a, 0xcc, 0xa7, 0xd4, 0x3c, 0x6d, 0x83, 0xed, 0xcd, - 0x0c, 0x04, 0x62, 0x06, 0x34, 0x7d, 0x3f, 0x39, 0x01, 0xac, 0x02, 0xad, 0x56, 0xdf, 0x9b, 0x41, 0xca, 0xad, 0x2c, - 0x54, 0xb4, 0xb5, 0x3d, 0xf9, 0x3b, 0xd2, 0xf2, 0x78, 0xaf, 0xa9, 0xa0, 0xff, 0xfb, 0x80, 0xec, 0x35, 0x0a, 0x0a, - 0xd6, 0x38, 0x55, 0xc0, 0x28, 0x14, 0xbe, 0x51, 0x03, 0x21, 0x29, 0xdd, 0x2b, 0xc4, 0xe2, 0x4f, 0x36, 0xe8, 0x74, - 0x42, 0xfa, 0xa0, 0x67, 0xf8, 0x93, 0xc1, 0x2e, 0x62, 0x32, 0xdc, 0xc0, 0x13, 0x9b, 0x75, 0x25, 0xd3, 0x58, 0x54, - 0x99, 0xc6, 0xda, 0x22, 0xdc, 0x59, 0xd1, 0xc5, 0x2d, 0x68, 0x4c, 0x1f, 0xf3, 0xb2, 0x0a, 0x33, 0x09, 0x4c, 0xb9, - 0x24, 0x6b, 0x88, 0xd7, 0xe1, 0x94, 0x66, 0x1e, 0x45, 0x78, 0x57, 0x03, 0x45, 0x9c, 0xd0, 0x64, 0x60, 0x89, 0xcd, - 0x0c, 0xc4, 0x26, 0x43, 0x4a, 0x2b, 0xab, 0x1e, 0xb7, 0x0c, 0xd3, 0x7e, 0x36, 0x28, 0x95, 0x39, 0x6b, 0xf1, 0x52, - 0x1e, 0x6b, 0xea, 0x36, 0xf8, 0x53, 0x65, 0x0a, 0x69, 0x52, 0x69, 0xc8, 0x10, 0xde, 0x6b, 0xac, 0xef, 0xa3, 0x69, - 0x55, 0xae, 0xb1, 0x3f, 0x80, 0x7d, 0x90, 0xe2, 0xc2, 0x67, 0x99, 0xfc, 0x5b, 0x39, 0x67, 0x80, 0xb6, 0x0b, 0x20, - 0x0b, 0x7f, 0x14, 0x87, 0xc2, 0x6b, 0x1e, 0x36, 0x40, 0x13, 0x5d, 0x50, 0x90, 0x26, 0x08, 0x6d, 0x2e, 0x85, 0xfa, - 0xf3, 0x24, 0x9b, 0xb0, 0x91, 0xf0, 0x42, 0x21, 0x19, 0x0a, 0x8d, 0x33, 0xea, 0x88, 0x8a, 0x3e, 0x2c, 0x99, 0x4d, - 0x08, 0xa4, 0x56, 0x28, 0x5f, 0xd4, 0x40, 0x2a, 0x99, 0x16, 0xf0, 0x86, 0x52, 0x97, 0x2e, 0x79, 0x8c, 0x69, 0xcd, - 0x40, 0x5f, 0x6c, 0xf6, 0xd4, 0x88, 0x81, 0x66, 0x05, 0xcc, 0x52, 0x59, 0x59, 0x60, 0xf3, 0x07, 0x5d, 0x28, 0x7c, - 0xc1, 0x5f, 0xf2, 0x1b, 0x9a, 0x9e, 0x87, 0x00, 0x7c, 0xa0, 0xba, 0xe7, 0x4a, 0x0c, 0x48, 0x6e, 0x2f, 0xda, 0x86, - 0x5e, 0x2e, 0xe5, 0xc2, 0xbf, 0x49, 0xf9, 0x94, 0x65, 0x14, 0x34, 0x35, 0x85, 0xff, 0x04, 0x4e, 0x99, 0x3c, 0x8e, - 0x20, 0x6a, 0x68, 0x41, 0x5f, 0x67, 0x2f, 0xab, 0xf4, 0x75, 0xb9, 0xff, 0x7c, 0x6c, 0xd8, 0x5f, 0xf5, 0x10, 0x23, - 0xec, 0x69, 0x7b, 0xc2, 0x92, 0x72, 0xfe, 0x04, 0x69, 0xf1, 0xbe, 0x5a, 0x09, 0xcb, 0x6c, 0xab, 0xe8, 0x8a, 0x54, - 0x1d, 0x1b, 0x94, 0x87, 0x51, 0x04, 0x5a, 0x5d, 0xca, 0xe3, 0xd8, 0x12, 0x54, 0x98, 0xb5, 0x0b, 0xd1, 0x74, 0xb9, - 0xff, 0xfc, 0xe2, 0x3e, 0xe9, 0x04, 0xf5, 0xb6, 0x80, 0x32, 0x80, 0x26, 0x11, 0x4d, 0xc1, 0x8c, 0xb4, 0x76, 0x4b, - 0xcb, 0xd8, 0x73, 0x9e, 0x24, 0x74, 0x28, 0x68, 0x04, 0x56, 0x0a, 0x23, 0xc2, 0x9f, 0xf0, 0x4c, 0x14, 0x85, 0x25, - 0xf4, 0xcc, 0x82, 0x9e, 0xf9, 0xc3, 0x30, 0x8e, 0x3d, 0x65, 0x91, 0x4c, 0xf9, 0x82, 0x6e, 0x81, 0xba, 0x5d, 0x01, - 0xb9, 0x18, 0x86, 0x5a, 0xc3, 0x50, 0x3f, 0x9b, 0xc5, 0x6c, 0x48, 0x0b, 0xc1, 0x75, 0xe1, 0xb3, 0x24, 0xa2, 0xb7, - 0xc0, 0x47, 0x50, 0xb7, 0xdb, 0x6d, 0xe0, 0x26, 0xca, 0x15, 0xc2, 0x97, 0x1b, 0x88, 0xbd, 0x47, 0x64, 0x02, 0x91, - 0x91, 0xee, 0x72, 0x1b, 0x3f, 0xa0, 0xc8, 0x92, 0x93, 0xcc, 0x58, 0x56, 0x8a, 0x37, 0x23, 0x1c, 0xd1, 0x98, 0x0a, - 0x6a, 0x78, 0x39, 0xe8, 0xcf, 0xea, 0xe8, 0xbe, 0x2d, 0xf0, 0x57, 0x90, 0x93, 0x39, 0x65, 0x66, 0xcf, 0xb3, 0xc2, - 0x52, 0x2f, 0xb7, 0xa7, 0xc4, 0x76, 0x4f, 0xa8, 0xed, 0x09, 0x85, 0x08, 0x87, 0x13, 0x65, 0xa2, 0x7b, 0x1b, 0x4b, - 0x2a, 0xc7, 0xd0, 0x7c, 0xbd, 0x38, 0x44, 0xef, 0x0d, 0x98, 0xdb, 0x50, 0x70, 0xa1, 0x99, 0x02, 0x05, 0xab, 0x4f, - 0x6d, 0xdb, 0x79, 0x18, 0xc7, 0xd7, 0xe1, 0xf0, 0x63, 0x95, 0xfa, 0x4b, 0x32, 0x20, 0xeb, 0xdc, 0xd8, 0xaa, 0xb2, - 0x58, 0x96, 0xbd, 0x6e, 0xc3, 0xa5, 0x2b, 0x07, 0xc5, 0xdb, 0x6b, 0x94, 0x64, 0x5f, 0xdd, 0xe8, 0x9d, 0xd4, 0x2e, - 0x21, 0x62, 0x7a, 0x65, 0x1e, 0x70, 0x81, 0x4f, 0x52, 0x9c, 0xe1, 0x07, 0x9a, 0xee, 0xc0, 0xd6, 0xc8, 0xd7, 0x00, - 0x11, 0x68, 0x99, 0x47, 0x2c, 0xdb, 0x8d, 0x81, 0x3f, 0x04, 0xca, 0x67, 0xd6, 0x0c, 0x0f, 0x05, 0xb4, 0xe0, 0x71, - 0x5a, 0x65, 0x2e, 0x20, 0xd3, 0xda, 0x84, 0x61, 0x34, 0x5f, 0x83, 0xe6, 0x22, 0xe9, 0xfd, 0x8d, 0xaa, 0x02, 0x9d, - 0x0c, 0xa0, 0xc8, 0xda, 0xb6, 0x32, 0x51, 0xa1, 0x00, 0xcd, 0x53, 0x99, 0x14, 0xb9, 0x49, 0xc5, 0x78, 0xd4, 0xea, - 0xba, 0xb2, 0xbf, 0x35, 0xcb, 0xe5, 0xc4, 0xf3, 0xbc, 0x0c, 0xec, 0x37, 0xa3, 0xd7, 0x97, 0x8b, 0xc8, 0x36, 0x16, - 0x91, 0xf9, 0x96, 0x91, 0x85, 0x4a, 0x5a, 0xb6, 0xba, 0x07, 0x7f, 0x45, 0x76, 0x23, 0x50, 0x56, 0x7d, 0xe0, 0xcf, - 0xa8, 0x60, 0xb7, 0x31, 0x11, 0x98, 0x6b, 0x03, 0x47, 0x53, 0x1a, 0x30, 0x8c, 0xb2, 0x4b, 0x82, 0xd4, 0xd1, 0xa8, - 0x18, 0xbb, 0x09, 0xe6, 0x68, 0x4d, 0xb3, 0xcf, 0x73, 0x8d, 0x23, 0x8a, 0xf4, 0xde, 0x54, 0x54, 0x62, 0x0b, 0x2b, - 0x38, 0x21, 0x5a, 0x0d, 0x56, 0x5a, 0xcf, 0x3a, 0x6e, 0x8a, 0x71, 0xe1, 0xa0, 0x96, 0xa8, 0xa9, 0xe8, 0x93, 0x46, - 0xb1, 0x4a, 0x10, 0x9e, 0x18, 0x8d, 0x94, 0x97, 0xeb, 0x26, 0xc4, 0x35, 0xde, 0x08, 0xb7, 0xb7, 0xac, 0x98, 0x84, - 0x81, 0xd5, 0x2c, 0x0f, 0x80, 0xa5, 0xf2, 0x6d, 0xe8, 0xde, 0x46, 0x33, 0x95, 0x71, 0x2c, 0x84, 0x73, 0x1b, 0xe1, - 0x16, 0x66, 0x13, 0xc5, 0xb9, 0x92, 0x01, 0x99, 0x54, 0xfb, 0x7a, 0x14, 0x73, 0xb5, 0x0f, 0x1b, 0x48, 0x5c, 0x57, - 0x3c, 0x25, 0x09, 0x82, 0x01, 0x9b, 0x81, 0x72, 0x67, 0xcb, 0x07, 0x0f, 0x60, 0x67, 0xab, 0xd5, 0x06, 0xd1, 0x6d, - 0xd5, 0x3f, 0x91, 0x5f, 0x1a, 0x85, 0xab, 0xd5, 0x8d, 0x40, 0x9e, 0xd6, 0x7c, 0x31, 0x45, 0x3d, 0xc3, 0x71, 0xcf, - 0x5e, 0x42, 0x2b, 0xa9, 0x88, 0x96, 0x25, 0x85, 0xc9, 0x50, 0xa5, 0xd9, 0xea, 0x3e, 0x09, 0x8b, 0x6d, 0x9f, 0x6f, - 0x70, 0x2f, 0x59, 0xa8, 0xc5, 0x74, 0xb9, 0xe4, 0x73, 0x3d, 0x34, 0x43, 0x08, 0x05, 0x99, 0xb4, 0x62, 0xf6, 0xb6, - 0x19, 0x96, 0x07, 0x07, 0x99, 0x35, 0xd0, 0x65, 0xc1, 0x26, 0x3e, 0x78, 0x20, 0x92, 0xb3, 0xbb, 0x44, 0xea, 0x2e, - 0x1f, 0x8c, 0x10, 0xda, 0x30, 0x4b, 0x1b, 0x6d, 0xb0, 0xc6, 0xc3, 0x9b, 0x90, 0x09, 0xa7, 0x18, 0x45, 0x59, 0xe3, - 0x1e, 0x45, 0x4b, 0xad, 0x6a, 0xf8, 0x29, 0x05, 0xe5, 0x11, 0x78, 0x82, 0x51, 0xa1, 0x15, 0xdd, 0x0f, 0x27, 0x14, - 0x1c, 0xc1, 0x46, 0x8b, 0x28, 0xec, 0xc2, 0x3d, 0x2d, 0x45, 0xf4, 0xc0, 0xdb, 0x61, 0xcf, 0xd7, 0xbb, 0x57, 0xec, - 0x80, 0x19, 0x4d, 0x47, 0x3c, 0x9d, 0x9a, 0xba, 0x7c, 0xed, 0x59, 0x73, 0x46, 0x36, 0xf2, 0xb6, 0x8e, 0xad, 0xd5, - 0xff, 0xf6, 0x9a, 0xd1, 0x5d, 0x9a, 0xeb, 0x15, 0x51, 0x5a, 0x48, 0x5f, 0xe5, 0x0f, 0x34, 0x94, 0x99, 0xd9, 0xe6, - 0xbd, 0x76, 0xa6, 0xb6, 0x95, 0xc3, 0x64, 0xaf, 0xd9, 0x2e, 0x6c, 0x3e, 0x43, 0x0d, 0x6d, 0xe5, 0xd8, 0xd0, 0x22, - 0x95, 0xcf, 0xe3, 0x48, 0x03, 0xcb, 0x10, 0xa6, 0x9a, 0x8e, 0x6e, 0x58, 0x1c, 0x97, 0xa5, 0xbf, 0x86, 0xaf, 0x67, - 0x9a, 0xaf, 0x27, 0x86, 0xaf, 0x03, 0xa7, 0x00, 0xbe, 0xae, 0x86, 0x2b, 0xbb, 0x27, 0x1b, 0xa7, 0x33, 0x51, 0x1c, - 0x3d, 0x93, 0x76, 0x34, 0xcc, 0x37, 0x37, 0x10, 0xa0, 0x42, 0xf3, 0xfa, 0xe8, 0x69, 0x27, 0x0c, 0x18, 0x80, 0xca, - 0x85, 0x49, 0x6d, 0x17, 0xc5, 0x47, 0x0f, 0xe1, 0x2c, 0xa7, 0x05, 0x65, 0x9f, 0x3d, 0x07, 0x27, 0x9d, 0xb5, 0x1c, - 0x10, 0x62, 0xb2, 0xf8, 0x57, 0x29, 0x51, 0x66, 0x75, 0x4c, 0xaf, 0x2e, 0x33, 0xab, 0x03, 0x4e, 0x5f, 0xae, 0x2e, - 0xba, 0x9f, 0xd7, 0xcb, 0xe5, 0xb1, 0x62, 0x79, 0xe5, 0x7e, 0xaf, 0x56, 0xde, 0x5a, 0x09, 0xf8, 0xef, 0xb5, 0x89, - 0x92, 0x16, 0xa3, 0x03, 0x0f, 0xb0, 0x31, 0x03, 0x05, 0xb9, 0x5a, 0x74, 0x21, 0xe2, 0x5e, 0x7e, 0xca, 0xc1, 0x23, - 0xdd, 0xf4, 0xaa, 0xff, 0x39, 0x9f, 0xce, 0x40, 0x1b, 0x5b, 0x23, 0xe9, 0x31, 0xd5, 0x13, 0x96, 0xf5, 0xf9, 0x96, - 0xb2, 0x4a, 0x1f, 0x79, 0x1e, 0x2b, 0xd4, 0x54, 0xd8, 0xcb, 0x7b, 0x8d, 0x7c, 0x5e, 0x14, 0x15, 0x8c, 0x63, 0x9b, - 0x53, 0xe5, 0x7c, 0xdd, 0x25, 0x63, 0x2a, 0xde, 0x78, 0x4c, 0xf1, 0x61, 0x06, 0xbc, 0xce, 0x62, 0x3f, 0x86, 0xdc, - 0xed, 0xfd, 0xcf, 0x4b, 0xe4, 0x2c, 0xf3, 0x35, 0xf4, 0x2d, 0xf3, 0xfc, 0x4c, 0x19, 0xd9, 0xf8, 0x6c, 0xb7, 0x35, - 0x5c, 0xd6, 0x69, 0x63, 0xb1, 0x3f, 0xc0, 0x67, 0x9b, 0xaa, 0x23, 0x59, 0x4e, 0x79, 0x44, 0x03, 0x97, 0xcf, 0x68, - 0xe2, 0xe6, 0xe0, 0x55, 0xd5, 0x7b, 0x3f, 0x14, 0xde, 0xf2, 0x6d, 0xd5, 0xbd, 0x1a, 0x9c, 0xe5, 0xe0, 0xfd, 0xfa, - 0x72, 0xd3, 0xf1, 0xfa, 0x1d, 0x4d, 0x33, 0xa9, 0x88, 0x16, 0x3a, 0xed, 0x97, 0xa5, 0x58, 0xfa, 0x32, 0xd8, 0xd9, - 0xbe, 0x34, 0x41, 0xdc, 0xa6, 0xff, 0xc8, 0x3f, 0x72, 0x91, 0x74, 0x0b, 0xff, 0xa8, 0x0f, 0xfc, 0x07, 0xe3, 0x16, - 0x7e, 0x4e, 0x3e, 0x54, 0xbd, 0xc2, 0x91, 0x20, 0xcf, 0x7b, 0xcf, 0x8d, 0xc5, 0xcc, 0x63, 0x36, 0xbc, 0xf3, 0xdc, - 0x98, 0x89, 0x3a, 0x84, 0xde, 0x5c, 0xbc, 0x54, 0x15, 0xe0, 0x52, 0x94, 0xee, 0xec, 0xdc, 0xd8, 0x7a, 0x58, 0x08, - 0xe2, 0xee, 0xc7, 0x4c, 0xec, 0xbb, 0x78, 0x4a, 0xae, 0xe0, 0xc7, 0xfe, 0xd2, 0x7b, 0x15, 0x8a, 0x89, 0x9f, 0x86, - 0x49, 0xc4, 0xa7, 0x1e, 0xaa, 0xb9, 0x2e, 0xf2, 0x33, 0x69, 0x6f, 0x3c, 0x41, 0xf9, 0xfe, 0x15, 0xbe, 0x15, 0xc4, - 0xed, 0xb9, 0xb5, 0x29, 0x7e, 0x2d, 0xc8, 0x55, 0x67, 0x7f, 0x79, 0x2b, 0xf2, 0xee, 0x15, 0xbe, 0x2d, 0x3c, 0xf6, - 0xf8, 0x1b, 0xe2, 0x21, 0xd2, 0xbd, 0xd5, 0xd0, 0x9c, 0xf3, 0xa9, 0xf2, 0xdc, 0xbb, 0x08, 0xbf, 0x87, 0xb8, 0x4a, - 0x5a, 0x72, 0x1b, 0x1d, 0x5a, 0xd9, 0x23, 0x2e, 0x97, 0x2e, 0x02, 0xf7, 0xe0, 0xc0, 0x2a, 0x2b, 0x54, 0x05, 0x7c, - 0x26, 0x48, 0xc5, 0x20, 0xc7, 0x6f, 0x65, 0x84, 0xe6, 0x4c, 0x78, 0x29, 0x32, 0xc3, 0x78, 0xc6, 0x0f, 0xad, 0x8f, - 0x66, 0xda, 0x57, 0x1e, 0x06, 0x9f, 0x09, 0x9a, 0x86, 0x82, 0xa7, 0x03, 0x64, 0xab, 0x1f, 0xf8, 0x6f, 0xe4, 0xaa, - 0xef, 0xfc, 0xa7, 0xcf, 0x7e, 0x1a, 0xfd, 0x94, 0x0e, 0xae, 0xf0, 0x1b, 0x72, 0xd8, 0xf1, 0x7a, 0x81, 0xb7, 0x57, - 0xaf, 0xaf, 0x7e, 0x3a, 0xec, 0xff, 0x23, 0xac, 0xff, 0x72, 0x56, 0xff, 0x71, 0x80, 0x56, 0xde, 0x4f, 0x87, 0xbd, - 0xbe, 0x7e, 0xea, 0xff, 0xa3, 0xfb, 0x53, 0x36, 0xf8, 0xb3, 0x2a, 0xdc, 0x47, 0xe8, 0x70, 0x8c, 0xe7, 0x82, 0x1c, - 0xd6, 0xeb, 0xdd, 0xc3, 0x31, 0x9e, 0x09, 0x72, 0x08, 0x7f, 0xaf, 0xc9, 0x5b, 0x3a, 0x7e, 0x7e, 0x3b, 0xf3, 0xae, - 0xba, 0xab, 0xfd, 0xe5, 0xdf, 0x72, 0x18, 0xb5, 0xff, 0x8f, 0x9f, 0x7e, 0xca, 0xdc, 0x2f, 0xba, 0xe4, 0x70, 0x50, - 0x43, 0x1e, 0x94, 0xfe, 0x99, 0xc8, 0x7f, 0xbd, 0x5e, 0xd0, 0xff, 0x87, 0x86, 0xc2, 0xfd, 0xe2, 0xa7, 0xab, 0x4e, - 0x97, 0x0c, 0x56, 0x9e, 0xbb, 0xfa, 0x02, 0xad, 0x10, 0x5a, 0xed, 0xa3, 0x2b, 0xec, 0x8e, 0x5d, 0x84, 0xc7, 0x82, - 0x1c, 0x7e, 0x71, 0x38, 0xc6, 0x0b, 0x41, 0x0e, 0xdd, 0xc3, 0x31, 0x7e, 0x2e, 0xc8, 0xe1, 0x3f, 0xbc, 0x5e, 0xa0, - 0x3c, 0x6c, 0x2b, 0xe9, 0xde, 0x58, 0x41, 0x70, 0x23, 0x4c, 0x69, 0xb8, 0x12, 0x4c, 0xc4, 0x14, 0xed, 0x1f, 0x32, - 0x7c, 0x21, 0xd1, 0xe4, 0x09, 0x70, 0xc2, 0x80, 0x6d, 0xe7, 0x2d, 0x2f, 0x61, 0xb3, 0x81, 0x66, 0xf6, 0x83, 0x14, - 0x2b, 0x3f, 0x40, 0x16, 0x08, 0xbc, 0x08, 0xe3, 0x39, 0xcd, 0x02, 0x9a, 0x23, 0x3c, 0x24, 0x17, 0xc2, 0x6b, 0x22, - 0xfc, 0x42, 0xc0, 0x8f, 0x16, 0xc2, 0x17, 0x3a, 0x80, 0x09, 0x07, 0x59, 0x11, 0x55, 0xc2, 0x95, 0xc6, 0xe2, 0x22, - 0x3c, 0xdb, 0x52, 0x29, 0x26, 0xe0, 0x5d, 0x40, 0x78, 0xbf, 0x12, 0xee, 0xc4, 0x37, 0xc4, 0x90, 0xc4, 0xbb, 0x94, - 0xd2, 0xef, 0xc3, 0xf8, 0x23, 0x4d, 0xbd, 0x5b, 0xdc, 0x6c, 0x3d, 0xc1, 0xd2, 0x05, 0xbd, 0xd7, 0x44, 0xed, 0x22, - 0x56, 0x75, 0x2e, 0x54, 0x8c, 0x00, 0x84, 0x6c, 0xd5, 0x17, 0x03, 0x3b, 0xbe, 0x97, 0x6e, 0x38, 0xac, 0xd2, 0xf0, - 0xc6, 0x45, 0xd5, 0xb8, 0x28, 0x4b, 0x16, 0x61, 0xcc, 0x22, 0x47, 0xd0, 0xe9, 0x2c, 0x0e, 0x05, 0x75, 0xf4, 0x7a, - 0x9d, 0x10, 0x06, 0x72, 0x0b, 0x95, 0x21, 0xb2, 0x0c, 0xce, 0xc8, 0x04, 0x9c, 0xe0, 0xac, 0x78, 0x10, 0x9d, 0xd2, - 0x6a, 0xc7, 0xd3, 0x32, 0xf8, 0xb5, 0x1e, 0xdf, 0xab, 0x37, 0xc1, 0x11, 0x36, 0x90, 0xe2, 0x39, 0xc3, 0x09, 0x01, - 0x21, 0xda, 0xea, 0xb9, 0x9d, 0x6c, 0x31, 0xee, 0xba, 0x10, 0x9b, 0xe1, 0xe4, 0x8d, 0xf4, 0x0b, 0x41, 0x83, 0x09, - 0x69, 0xb4, 0x27, 0x1d, 0xda, 0x9e, 0xd4, 0x6a, 0x46, 0x87, 0x8e, 0x49, 0xda, 0x9f, 0xa8, 0xee, 0x21, 0x8e, 0xf0, - 0x9c, 0xd4, 0x9b, 0x78, 0x4c, 0x1a, 0xb2, 0x4b, 0x7b, 0xdc, 0x89, 0xf5, 0x34, 0x07, 0x07, 0x1e, 0xf7, 0xe3, 0x30, - 0x13, 0x5f, 0x81, 0xb1, 0x4f, 0xc6, 0x38, 0x22, 0xdc, 0xa7, 0xb7, 0x74, 0xe8, 0xc5, 0x08, 0x47, 0x9a, 0xd3, 0xa0, - 0x36, 0x1a, 0x13, 0xab, 0x19, 0x18, 0x11, 0xe4, 0x4d, 0x2f, 0xea, 0x37, 0x07, 0x84, 0x10, 0x77, 0xaf, 0x5e, 0x77, - 0x7b, 0x9c, 0xcc, 0x45, 0x00, 0x25, 0x96, 0xaa, 0x4c, 0x66, 0x50, 0xd4, 0xb2, 0x8a, 0xbc, 0xe7, 0xc2, 0x17, 0x34, - 0x13, 0x1e, 0x14, 0x83, 0xf9, 0x9f, 0x19, 0xc2, 0x76, 0x3b, 0x87, 0x6e, 0x0d, 0x4a, 0x25, 0x71, 0x22, 0xcc, 0xc9, - 0x35, 0x0a, 0xa2, 0xfe, 0xd1, 0xc0, 0xe6, 0xff, 0xb2, 0x10, 0x26, 0xbf, 0xee, 0x45, 0xfd, 0x86, 0x9c, 0xbc, 0xeb, - 0xf6, 0x3c, 0x4e, 0x32, 0xa5, 0xa0, 0xf5, 0xb2, 0xe0, 0x8d, 0x5c, 0x2a, 0x0a, 0x34, 0x70, 0x7a, 0xde, 0x39, 0xa9, - 0xb7, 0x02, 0x6f, 0x6e, 0x2f, 0xa2, 0x0e, 0x93, 0x69, 0x2c, 0xe0, 0x90, 0x40, 0x7b, 0xcc, 0x09, 0xcc, 0x58, 0x76, - 0xbb, 0x0e, 0xf4, 0xf3, 0x17, 0xee, 0x17, 0xbd, 0x85, 0x08, 0xc6, 0x42, 0x4d, 0xbf, 0x10, 0xab, 0x15, 0xfc, 0x1d, - 0x8b, 0x1e, 0x27, 0xd7, 0xb2, 0x68, 0xae, 0x8b, 0x66, 0x50, 0xf4, 0x26, 0x00, 0x50, 0x71, 0x56, 0x28, 0x59, 0x6a, - 0x4f, 0x16, 0x44, 0xc2, 0x7e, 0x70, 0x90, 0xf6, 0x27, 0xb5, 0xe6, 0x00, 0xfc, 0xfb, 0xa9, 0xc8, 0xbe, 0x67, 0x62, - 0xe2, 0xb9, 0x87, 0x5d, 0x17, 0xf5, 0x5c, 0x07, 0xb6, 0xb6, 0x9d, 0xd4, 0x88, 0xc2, 0x70, 0x5c, 0x7b, 0x2d, 0x82, - 0x79, 0x97, 0x34, 0x7a, 0x1e, 0xd3, 0xfe, 0x3c, 0x84, 0x63, 0xcd, 0x38, 0x1b, 0x78, 0x8e, 0x6a, 0x42, 0xd4, 0xcc, - 0xf3, 0x1c, 0xd5, 0xa6, 0xb5, 0x05, 0x0a, 0xe2, 0xda, 0xb4, 0xe6, 0xcd, 0x09, 0x21, 0xf5, 0x56, 0xd1, 0xcd, 0x48, - 0xbf, 0x09, 0x0a, 0x16, 0xc6, 0xd9, 0xd9, 0x97, 0xc7, 0x21, 0xa9, 0x79, 0x69, 0x9f, 0x0e, 0x56, 0x2b, 0xb7, 0xd3, - 0xeb, 0xba, 0xa8, 0xe6, 0x19, 0x42, 0x3b, 0x34, 0x94, 0x86, 0x10, 0x66, 0x83, 0x5c, 0x87, 0x92, 0xde, 0x55, 0xc2, - 0x46, 0xcb, 0xf2, 0xb0, 0x5b, 0x3c, 0x80, 0xe6, 0x85, 0x1d, 0xa3, 0xf4, 0xd5, 0x19, 0x2c, 0xd3, 0x10, 0x73, 0x42, - 0x1a, 0x98, 0x13, 0xe3, 0xbb, 0x9e, 0x10, 0x51, 0x12, 0x7c, 0x4c, 0xca, 0xe6, 0xb8, 0x1f, 0xe2, 0x68, 0x40, 0x9e, - 0x2a, 0x7b, 0xa4, 0x6d, 0xfc, 0xe2, 0x34, 0x26, 0xef, 0xd6, 0xa2, 0xb7, 0x21, 0xc4, 0x56, 0x6e, 0xfc, 0xe1, 0x3c, - 0x4d, 0x69, 0x22, 0x5e, 0xf3, 0x48, 0xab, 0x69, 0x34, 0x06, 0x4b, 0x09, 0xc2, 0xb2, 0x18, 0x74, 0xb4, 0x96, 0x39, - 0x19, 0xf3, 0x8d, 0xea, 0x31, 0x99, 0x2b, 0xf5, 0x49, 0x06, 0x6b, 0xdb, 0x63, 0x6d, 0x17, 0x7b, 0x08, 0xcf, 0x75, - 0x14, 0xd7, 0xf3, 0x7d, 0x7f, 0xec, 0x0f, 0xa1, 0x1a, 0x26, 0xc8, 0x50, 0x2e, 0xcf, 0x91, 0x97, 0x91, 0x1b, 0x3f, - 0xa1, 0xb7, 0x72, 0x56, 0x0f, 0x95, 0x92, 0xd9, 0x1c, 0xaf, 0xce, 0xa4, 0x2d, 0xd9, 0x4d, 0xe6, 0x27, 0x3c, 0xa2, - 0x80, 0x1e, 0x88, 0xdb, 0xeb, 0xa2, 0x49, 0x98, 0xd9, 0xf1, 0xa9, 0x12, 0xbe, 0xbe, 0xed, 0xbc, 0x1e, 0x83, 0xc7, - 0x57, 0xea, 0x5a, 0x45, 0x63, 0xe5, 0x06, 0x47, 0x88, 0x8d, 0xbc, 0xb1, 0x0f, 0x71, 0x3d, 0x49, 0x42, 0x02, 0x4c, - 0xb9, 0xb1, 0x4d, 0x54, 0xd3, 0x62, 0xcc, 0x05, 0x89, 0xfa, 0xbc, 0x56, 0x93, 0x5e, 0xe8, 0xb9, 0x22, 0x89, 0x31, - 0xc2, 0x8b, 0xe2, 0x6c, 0x99, 0x76, 0x6f, 0x04, 0xa9, 0x4e, 0xe5, 0x2d, 0xaa, 0xee, 0xdc, 0x9a, 0x10, 0x48, 0x7a, - 0x0a, 0x85, 0x37, 0x45, 0xf8, 0x15, 0x39, 0xf4, 0xfa, 0x7e, 0xef, 0x2f, 0x03, 0xd4, 0xf3, 0xfc, 0x3f, 0xa3, 0x43, - 0xc5, 0x39, 0x16, 0xa8, 0x1d, 0xab, 0x39, 0x96, 0x32, 0x7e, 0xd9, 0xc4, 0xd2, 0x93, 0x18, 0x24, 0x38, 0x09, 0xa7, - 0x34, 0x78, 0x05, 0x87, 0xdc, 0x10, 0xce, 0x1b, 0x81, 0x81, 0x92, 0x82, 0x57, 0x9a, 0x97, 0xf8, 0x6e, 0xef, 0xa5, - 0x28, 0x9e, 0x7a, 0x6e, 0xef, 0x43, 0xf9, 0xf4, 0x17, 0xb7, 0xf7, 0x95, 0x08, 0x7e, 0xc9, 0xb5, 0xb7, 0xbb, 0x32, - 0xc7, 0x23, 0x33, 0x47, 0xae, 0xb6, 0xc6, 0xc2, 0xdd, 0x1c, 0x6d, 0x3a, 0x3a, 0xc6, 0x28, 0x67, 0xa3, 0x82, 0x19, - 0x65, 0xbe, 0x08, 0xc7, 0x80, 0x54, 0x6b, 0x0f, 0x32, 0x3b, 0xae, 0x5f, 0xae, 0x18, 0x48, 0xc5, 0xd0, 0x2b, 0x20, - 0x73, 0xdc, 0x6d, 0xa0, 0x65, 0xa5, 0xad, 0xd4, 0x99, 0xaa, 0x71, 0xf4, 0x82, 0x4f, 0x2f, 0x48, 0xa3, 0xbd, 0xe8, - 0x8c, 0xdb, 0x8b, 0x5a, 0x0d, 0x65, 0x86, 0xb4, 0xe6, 0xfd, 0xc5, 0x00, 0x7f, 0x03, 0x4e, 0x3d, 0x9b, 0x96, 0x70, - 0x65, 0x79, 0x2d, 0xbd, 0xbc, 0x5a, 0x2d, 0xc9, 0x51, 0xdb, 0xea, 0x3a, 0x56, 0x5d, 0xf3, 0x5c, 0xe1, 0x64, 0x9d, - 0xd4, 0x4e, 0x91, 0x2c, 0x81, 0x64, 0x28, 0x42, 0xc8, 0xad, 0x40, 0x5b, 0x47, 0x85, 0x31, 0xa1, 0xbb, 0x3c, 0xb3, - 0xc0, 0x3e, 0x95, 0x94, 0xf0, 0x00, 0x0b, 0xd0, 0xb5, 0xf0, 0x04, 0x4f, 0xf1, 0xbc, 0xd6, 0x94, 0x64, 0x5e, 0x6f, - 0xb6, 0xab, 0x63, 0x3d, 0x2e, 0xc7, 0xc2, 0xf3, 0x1a, 0x99, 0x16, 0x58, 0xca, 0x93, 0x5a, 0x2d, 0xaf, 0x06, 0x3b, - 0xcd, 0xc9, 0xad, 0x04, 0x20, 0x6e, 0xd7, 0x93, 0x32, 0x8c, 0x84, 0x2d, 0x65, 0x2a, 0xf3, 0x59, 0x92, 0xd0, 0x14, - 0xa4, 0x28, 0x11, 0x98, 0xe5, 0x79, 0x29, 0xd9, 0x41, 0x8c, 0x62, 0x4a, 0x52, 0xe0, 0x3c, 0xd2, 0xee, 0xc2, 0x09, - 0xe6, 0x78, 0x22, 0xf9, 0x06, 0x21, 0xe4, 0xc2, 0xa4, 0xb3, 0x08, 0xc9, 0x83, 0x62, 0xc2, 0x2c, 0x99, 0x94, 0x11, - 0xea, 0x5f, 0xee, 0x9f, 0xf3, 0x7b, 0x6d, 0xb2, 0x3e, 0x1b, 0x04, 0xb2, 0x59, 0xac, 0x39, 0x57, 0x48, 0xde, 0x7b, - 0x02, 0x15, 0xd1, 0x11, 0x5f, 0x32, 0xc0, 0x67, 0x2c, 0xa5, 0x52, 0x07, 0xdf, 0x37, 0x76, 0x5f, 0x5c, 0x55, 0x20, - 0x63, 0xdb, 0x7b, 0x03, 0x88, 0x0c, 0xc1, 0xb9, 0x93, 0x90, 0x8d, 0x66, 0x97, 0xfb, 0x67, 0x6f, 0xb6, 0xd9, 0xc0, - 0xab, 0x95, 0xb6, 0x7e, 0xa5, 0x6e, 0x83, 0xc3, 0x12, 0xd2, 0x58, 0xff, 0x08, 0xbc, 0x58, 0xaa, 0x48, 0xa1, 0x97, - 0x02, 0x15, 0x5d, 0xee, 0x9f, 0xbd, 0xf3, 0x52, 0xe9, 0x5b, 0x42, 0xd8, 0x5e, 0xb6, 0xc7, 0x89, 0x37, 0x21, 0x14, - 0xa9, 0xb5, 0x17, 0xac, 0x8b, 0x5b, 0x02, 0x3c, 0x98, 0xc8, 0x4a, 0xb0, 0x20, 0xfa, 0x6c, 0x40, 0x62, 0x8d, 0x01, - 0x12, 0x23, 0x1c, 0x57, 0xec, 0x32, 0x02, 0x1b, 0x20, 0xe7, 0xba, 0x80, 0x9d, 0xf0, 0x95, 0xea, 0x87, 0x70, 0x2c, - 0x67, 0x15, 0xb9, 0x12, 0x1e, 0xaf, 0x36, 0xb2, 0xd2, 0x4a, 0x73, 0xf4, 0x3b, 0xb0, 0x9d, 0xcc, 0xc3, 0x6b, 0x62, - 0x2c, 0x09, 0x5d, 0xf0, 0xcc, 0xa4, 0x8f, 0x5d, 0xee, 0x9f, 0xbd, 0xd2, 0x19, 0x64, 0xb3, 0xd0, 0xf0, 0xfb, 0x0d, - 0x13, 0xf3, 0xec, 0x95, 0x5f, 0xd6, 0xca, 0xc6, 0x97, 0xfb, 0x67, 0xef, 0xb7, 0x35, 0x83, 0xf2, 0x7c, 0x5e, 0xda, - 0xf8, 0x12, 0xbe, 0x25, 0x8d, 0x83, 0xa5, 0x16, 0x0e, 0x01, 0xcb, 0xb1, 0x14, 0x48, 0x41, 0x96, 0x17, 0xae, 0x91, - 0x67, 0x38, 0x21, 0x32, 0x0c, 0x54, 0xdd, 0x35, 0xad, 0xe6, 0x31, 0x9e, 0x5c, 0x0c, 0xf9, 0x8c, 0xee, 0x88, 0x0d, - 0xdd, 0x22, 0x9f, 0x4d, 0x21, 0x75, 0x46, 0x82, 0xce, 0xf0, 0x5e, 0x03, 0xb5, 0xab, 0xe2, 0x2b, 0x91, 0x44, 0xca, - 0x2b, 0xb2, 0x05, 0x4f, 0x48, 0x03, 0xc7, 0xa4, 0x81, 0x43, 0x92, 0xf5, 0x1b, 0x4a, 0x40, 0xb4, 0xc3, 0x62, 0x5c, - 0x25, 0x66, 0x20, 0x2b, 0x4c, 0x9f, 0x56, 0x25, 0x80, 0xa3, 0x76, 0x28, 0x7d, 0x8f, 0x52, 0xa6, 0x47, 0x92, 0x2c, - 0xde, 0x7a, 0x1c, 0x73, 0x39, 0xf0, 0x05, 0xbb, 0x8e, 0x21, 0xb1, 0x04, 0x56, 0x85, 0x05, 0x0a, 0x8a, 0xa6, 0x4d, - 0xdd, 0x34, 0xf4, 0xe5, 0x3e, 0x71, 0x1c, 0xfa, 0xc0, 0xb9, 0x71, 0xa8, 0xf3, 0x70, 0xb2, 0xcd, 0x2e, 0x8f, 0x0e, - 0x0e, 0x3c, 0xd5, 0xe9, 0x67, 0xe1, 0x71, 0x53, 0x5f, 0x46, 0xee, 0xbe, 0x53, 0xbc, 0x22, 0x42, 0x12, 0xfe, 0x5a, - 0x2d, 0x1e, 0xe4, 0x10, 0x86, 0xf6, 0xc2, 0x2a, 0x06, 0x0d, 0xf0, 0x52, 0xd7, 0xab, 0x2e, 0xbf, 0x56, 0x2b, 0xa2, - 0xb4, 0x55, 0x6c, 0xdd, 0xe2, 0x24, 0x5f, 0x78, 0x45, 0xea, 0x4f, 0x63, 0x23, 0x5f, 0xca, 0x80, 0x80, 0x98, 0x4d, - 0xb3, 0xcc, 0x2c, 0xc6, 0x3a, 0x12, 0x0c, 0xda, 0x7d, 0xa5, 0xb3, 0x16, 0xb0, 0xcc, 0xae, 0xd2, 0x8d, 0x0c, 0x3b, - 0x6b, 0xa1, 0xc0, 0x34, 0x82, 0xa8, 0x14, 0x34, 0xaa, 0xe5, 0x9a, 0xbc, 0xdf, 0x6e, 0xe6, 0x5c, 0xe2, 0x0c, 0x69, - 0x27, 0x97, 0x84, 0x42, 0x22, 0xab, 0x55, 0x20, 0xe5, 0x05, 0x99, 0xed, 0x26, 0xf9, 0x33, 0x8b, 0xe4, 0x9f, 0x12, - 0x6a, 0x91, 0xbf, 0x72, 0x71, 0xf8, 0x5c, 0x3b, 0x17, 0x32, 0x53, 0x75, 0x3e, 0x23, 0xe0, 0x44, 0xab, 0x62, 0xb4, - 0x12, 0x56, 0xdc, 0xc1, 0x50, 0xec, 0x13, 0x22, 0xdd, 0x90, 0xd8, 0xc4, 0x80, 0xbd, 0x32, 0xa8, 0x06, 0x53, 0x6f, - 0xf3, 0xe9, 0xd9, 0x1c, 0xf0, 0xec, 0xfd, 0xfd, 0xf1, 0xd0, 0xf3, 0xd9, 0xe6, 0xc9, 0xb5, 0x72, 0x3f, 0x61, 0xd5, - 0xd6, 0xc1, 0xad, 0x66, 0x82, 0xc2, 0xfc, 0x45, 0x1c, 0xbb, 0xca, 0x7c, 0xd6, 0x0e, 0xa1, 0x91, 0x7f, 0x00, 0x6d, - 0xb3, 0x29, 0x5b, 0x50, 0x6b, 0x58, 0xe0, 0x47, 0x2a, 0x03, 0x35, 0x4c, 0x77, 0xb0, 0x8f, 0x33, 0xd9, 0x80, 0x26, - 0xd1, 0xf6, 0xea, 0xa7, 0xb9, 0x26, 0x13, 0x05, 0x1a, 0x5a, 0x02, 0xff, 0x53, 0x24, 0x0f, 0x74, 0x23, 0xe5, 0x02, - 0x20, 0x68, 0x26, 0xf1, 0x54, 0x22, 0xcc, 0x75, 0x4b, 0xef, 0xfb, 0x8b, 0x3d, 0x42, 0x66, 0xa5, 0xf7, 0xf1, 0x6d, - 0x99, 0x7a, 0x05, 0x64, 0x81, 0x02, 0x30, 0x1f, 0x8b, 0x02, 0x15, 0xbe, 0xbc, 0x30, 0xcd, 0xa5, 0x09, 0xe9, 0x97, - 0x1a, 0xb7, 0x15, 0xda, 0x94, 0x6e, 0x39, 0x55, 0x6f, 0xd0, 0xb0, 0x56, 0xbb, 0x0f, 0xb5, 0x6f, 0x85, 0x84, 0x11, - 0x9e, 0xdf, 0xc9, 0xd6, 0x66, 0xdc, 0xfc, 0xe3, 0x7a, 0xfe, 0xca, 0xda, 0xa6, 0xf8, 0x2c, 0xc9, 0x68, 0x2a, 0x9e, - 0xd2, 0x11, 0x4f, 0x21, 0x66, 0x51, 0xe0, 0x04, 0xe5, 0xfb, 0x96, 0xdf, 0x4e, 0xae, 0xcf, 0x0a, 0x14, 0xac, 0x2d, - 0x50, 0xfe, 0xfa, 0x28, 0x83, 0xd6, 0x97, 0xeb, 0xbd, 0x66, 0x07, 0x07, 0xef, 0x4b, 0x34, 0x69, 0x28, 0x25, 0x14, - 0x16, 0xd3, 0x52, 0x2a, 0x8d, 0x8e, 0xe4, 0xee, 0x7b, 0x85, 0x13, 0xc0, 0x30, 0x0c, 0x9b, 0xf7, 0xbc, 0x20, 0x22, - 0x1f, 0xaf, 0xb3, 0x78, 0xed, 0x9c, 0x60, 0xb6, 0xe1, 0x02, 0x1c, 0x1e, 0x4c, 0x6d, 0xe5, 0x2d, 0xca, 0xca, 0x64, - 0xd8, 0x02, 0x86, 0x73, 0x40, 0x96, 0x27, 0xcd, 0x10, 0x8b, 0x02, 0xb7, 0x9a, 0x25, 0xe7, 0xa0, 0x57, 0x4e, 0x70, - 0xe6, 0x4f, 0x20, 0xfd, 0xb5, 0x72, 0x64, 0x11, 0xc2, 0x2a, 0x31, 0xc7, 0x4a, 0x25, 0x38, 0x7b, 0xb1, 0xcd, 0xa5, - 0x6c, 0x88, 0x9a, 0x4a, 0xa9, 0x23, 0x5b, 0xa0, 0xa2, 0x83, 0xbf, 0xf0, 0x98, 0x56, 0xdc, 0x4c, 0xdc, 0x4c, 0xfa, - 0x25, 0x85, 0xa7, 0x82, 0x51, 0x20, 0x33, 0xb8, 0x3f, 0xf7, 0x2a, 0x53, 0xb7, 0xb9, 0xec, 0x86, 0x35, 0xe2, 0x26, - 0x36, 0x9a, 0xb8, 0x8c, 0xeb, 0x9d, 0x97, 0xbc, 0x74, 0x5f, 0x65, 0x50, 0x0b, 0xc3, 0x05, 0xcb, 0x44, 0x12, 0x6b, - 0xf9, 0xfb, 0x2a, 0x29, 0xba, 0x68, 0x84, 0xa9, 0x04, 0xe3, 0x9d, 0xdc, 0x03, 0x9a, 0xc3, 0xdf, 0xe5, 0x99, 0xb0, - 0x76, 0xd4, 0x38, 0xb1, 0xe5, 0x9c, 0x96, 0xd4, 0x7f, 0x0b, 0xa9, 0x2e, 0xeb, 0x67, 0xfe, 0x85, 0x94, 0x85, 0x0c, - 0x67, 0x15, 0xc6, 0x9e, 0x48, 0xc6, 0x8e, 0x40, 0x4f, 0x33, 0x89, 0xdf, 0x3d, 0x9d, 0xf1, 0xc2, 0xb4, 0x94, 0xd3, - 0x24, 0xf6, 0x4d, 0x11, 0x2d, 0xb7, 0x7e, 0xaf, 0xed, 0x46, 0xc0, 0x08, 0x64, 0x01, 0x61, 0xcd, 0xd9, 0x13, 0x84, - 0xb3, 0x5a, 0xad, 0x9d, 0x75, 0x68, 0xe9, 0x24, 0x29, 0x61, 0x64, 0x10, 0xd0, 0x05, 0x82, 0xaf, 0xc8, 0x50, 0x08, - 0xf9, 0x9b, 0xcc, 0xec, 0x0c, 0x7c, 0xed, 0x67, 0x6f, 0x3d, 0x9b, 0xab, 0xd9, 0x6d, 0x8b, 0xa0, 0x29, 0xac, 0xc7, - 0x2b, 0x03, 0x2e, 0xdf, 0xdc, 0x9f, 0xe0, 0x01, 0x70, 0xef, 0x35, 0x31, 0xa4, 0xa2, 0xa1, 0xb6, 0x50, 0x2c, 0xa1, - 0x38, 0x7d, 0x6d, 0x54, 0x66, 0x25, 0xda, 0x93, 0xb5, 0x45, 0x69, 0xcc, 0x0a, 0x92, 0xe5, 0x79, 0x46, 0xcb, 0xf0, - 0xfe, 0x5a, 0xfa, 0xa5, 0x14, 0x2e, 0x9b, 0xde, 0xf6, 0xf3, 0x19, 0x11, 0xd8, 0x22, 0xd4, 0x6f, 0x76, 0xc5, 0x3e, - 0x4a, 0x30, 0xe1, 0x5c, 0x6b, 0xa1, 0xf8, 0xcb, 0x36, 0xa1, 0x88, 0x13, 0x7d, 0xe4, 0xa5, 0x40, 0x6c, 0x3e, 0x40, - 0x20, 0x6a, 0x37, 0xbb, 0x91, 0x89, 0xa0, 0x8e, 0x54, 0x64, 0x62, 0x75, 0x4b, 0x49, 0x82, 0x99, 0xde, 0x8d, 0x6e, - 0x6b, 0xb5, 0x62, 0xfd, 0x06, 0xb8, 0x91, 0x5c, 0x17, 0x7e, 0x36, 0xd5, 0x4f, 0x8b, 0x13, 0x2b, 0x37, 0xb0, 0xc7, - 0x0a, 0x93, 0x05, 0xf9, 0x90, 0xe0, 0xec, 0xc9, 0xa4, 0x2c, 0x49, 0xd3, 0x9a, 0x82, 0x34, 0x81, 0x13, 0x56, 0x84, - 0x99, 0x00, 0x62, 0x29, 0x2b, 0xb4, 0x01, 0xe9, 0x6d, 0xcd, 0xfd, 0x33, 0xe6, 0xe5, 0xa7, 0x35, 0xd1, 0x8a, 0x5c, - 0x51, 0xea, 0x43, 0x25, 0xdf, 0x40, 0x43, 0xa0, 0xf5, 0xc3, 0x3d, 0x69, 0x82, 0x96, 0xa2, 0x1c, 0xd9, 0x72, 0x08, - 0x37, 0xc0, 0x89, 0xb6, 0xf7, 0x5e, 0x45, 0x78, 0xb7, 0x48, 0x13, 0xcc, 0x2d, 0xba, 0x7e, 0x41, 0x44, 0x85, 0x95, - 0x4c, 0x88, 0xb6, 0x94, 0x70, 0x28, 0xc9, 0x54, 0x90, 0xa4, 0xdf, 0x18, 0x80, 0x02, 0xda, 0x8e, 0x3b, 0x49, 0x69, - 0x02, 0xc7, 0xb5, 0x1a, 0x0a, 0xcd, 0xac, 0x93, 0x3e, 0xab, 0xc5, 0x03, 0x4c, 0x71, 0xac, 0x0c, 0x93, 0x8b, 0x83, - 0x03, 0x2f, 0x2c, 0xe7, 0xed, 0xc7, 0x03, 0x84, 0xf9, 0x6a, 0xe5, 0x49, 0xb0, 0x42, 0xb4, 0x5a, 0x85, 0x36, 0x58, - 0xb2, 0x1a, 0xba, 0xcd, 0x7a, 0x82, 0xcc, 0xa4, 0x00, 0x9c, 0x01, 0x84, 0x35, 0xe2, 0x85, 0xda, 0xbd, 0x17, 0x82, - 0x3b, 0xaa, 0x96, 0xf4, 0xe3, 0x5a, 0x73, 0x60, 0x31, 0xae, 0x7e, 0x3c, 0x20, 0x61, 0xce, 0x0f, 0x0e, 0xf6, 0x32, - 0x2d, 0x22, 0x3f, 0x80, 0x28, 0xfb, 0x20, 0x25, 0x8b, 0x1a, 0xd0, 0xde, 0x8d, 0x75, 0x67, 0x40, 0x41, 0x51, 0x7a, - 0x5b, 0x4d, 0xbb, 0x4a, 0x16, 0x44, 0xd1, 0x08, 0xeb, 0x60, 0x70, 0x0f, 0x2c, 0xfb, 0x82, 0xcc, 0x5f, 0x8a, 0x22, - 0xc7, 0xfa, 0x97, 0xad, 0x99, 0xd5, 0xbe, 0xef, 0x87, 0xe9, 0x58, 0xc6, 0x32, 0x4c, 0x18, 0x56, 0x12, 0xff, 0x91, - 0x06, 0xd3, 0x9a, 0xb8, 0x5f, 0xcc, 0x35, 0x20, 0x0a, 0x7c, 0xa3, 0xda, 0x98, 0xbb, 0x24, 0xcf, 0xb6, 0x7a, 0x19, - 0x14, 0x24, 0x1f, 0x7e, 0x2b, 0x24, 0xc7, 0x1a, 0x12, 0x45, 0x1e, 0x6b, 0x38, 0xdb, 0x81, 0x8b, 0x67, 0x62, 0x0d, - 0x67, 0xbb, 0x71, 0x6b, 0x30, 0xf5, 0xd5, 0x2e, 0xf8, 0x2c, 0xde, 0xa0, 0x00, 0x2d, 0x0b, 0x2c, 0x28, 0x4f, 0xd6, - 0x75, 0x2f, 0xc5, 0x4a, 0x41, 0x98, 0x0a, 0xe2, 0xb1, 0xea, 0x01, 0x28, 0xb5, 0x51, 0xcb, 0xf0, 0x65, 0xc1, 0x0c, - 0x59, 0x2e, 0x81, 0x6a, 0xea, 0x0a, 0x90, 0x93, 0xf6, 0xb6, 0xcf, 0x0e, 0x0e, 0xc0, 0x36, 0x00, 0x25, 0xce, 0x1f, - 0x86, 0x33, 0x31, 0x4f, 0x41, 0x95, 0xca, 0xcc, 0x6f, 0x28, 0x86, 0x5b, 0x20, 0xb2, 0x0c, 0x7e, 0x40, 0xc1, 0x2c, - 0xcc, 0x32, 0xb6, 0x50, 0x65, 0xfa, 0x37, 0xe6, 0xc4, 0x90, 0x72, 0xa6, 0x74, 0xc2, 0x04, 0xb5, 0x13, 0x4d, 0xa7, - 0x55, 0xb4, 0x3d, 0x5f, 0xd0, 0x44, 0xbc, 0x64, 0x99, 0xa0, 0x09, 0x2c, 0xbf, 0xa4, 0x38, 0x58, 0x51, 0x86, 0xe0, - 0xc0, 0x56, 0x7a, 0x85, 0x51, 0x74, 0x6f, 0x17, 0x51, 0xd5, 0x81, 0x26, 0x61, 0x12, 0xc5, 0x6a, 0x12, 0x3b, 0x9f, - 0xd1, 0xe4, 0x70, 0x16, 0x2d, 0xed, 0x7c, 0x9a, 0x52, 0xd9, 0x90, 0xdc, 0xdd, 0x63, 0xc4, 0x48, 0x02, 0x23, 0x3d, - 0xef, 0xd5, 0x5a, 0x20, 0xe2, 0xbd, 0x63, 0x13, 0xec, 0x95, 0x60, 0x61, 0x71, 0x54, 0xbf, 0x0a, 0xa7, 0xa1, 0x9b, - 0x9f, 0xb7, 0x5e, 0x69, 0xdb, 0x26, 0x1c, 0x24, 0x9d, 0x3c, 0xda, 0x6d, 0x59, 0xbd, 0x32, 0x92, 0xc3, 0x48, 0x0b, - 0xf6, 0x50, 0xc6, 0x8c, 0x96, 0x86, 0xbc, 0x90, 0x39, 0x8a, 0x23, 0x41, 0x3e, 0xc0, 0x9d, 0xa1, 0x17, 0x62, 0x1a, - 0xaf, 0x5d, 0x8d, 0x69, 0x8f, 0x0a, 0xed, 0x7f, 0x24, 0xbc, 0x77, 0xf8, 0x2d, 0x04, 0x76, 0x7f, 0x2c, 0x9b, 0x6f, - 0x06, 0x74, 0x7f, 0x2c, 0x11, 0xf4, 0x63, 0xb0, 0xd1, 0xce, 0x0a, 0xe4, 0xb6, 0xfc, 0x53, 0xbf, 0xe1, 0x1a, 0x6d, - 0xe9, 0x17, 0x15, 0x46, 0x52, 0x99, 0x96, 0xf2, 0x3c, 0xe0, 0x32, 0x4f, 0x0d, 0xf2, 0xe5, 0xaa, 0x16, 0x12, 0xd5, - 0x19, 0x86, 0x4a, 0x87, 0xdf, 0xb5, 0x3d, 0x5a, 0xc6, 0x24, 0xca, 0xce, 0xf8, 0x26, 0x4c, 0xc5, 0x3e, 0x9c, 0x32, - 0xbe, 0x71, 0x0f, 0x6f, 0x42, 0xc0, 0x83, 0xf6, 0xb0, 0x29, 0x2c, 0x63, 0x3b, 0x53, 0xf7, 0x80, 0xec, 0xf1, 0x09, - 0x37, 0xba, 0x5b, 0xd5, 0xca, 0xf8, 0x06, 0xec, 0x7f, 0x84, 0x27, 0xe6, 0x72, 0x1c, 0xd5, 0x1c, 0x98, 0x06, 0xcb, - 0xbc, 0x70, 0x0a, 0x70, 0xa5, 0xbc, 0xa5, 0x08, 0xf3, 0x5c, 0x06, 0xb8, 0xbf, 0xc6, 0xdf, 0x6a, 0x96, 0xb8, 0x5f, - 0x70, 0x9c, 0xb3, 0x87, 0x72, 0x44, 0x05, 0x7e, 0x11, 0xbf, 0x07, 0x3a, 0x96, 0x14, 0x9a, 0x1b, 0x2a, 0x7a, 0xc6, - 0xf5, 0x42, 0x76, 0xa6, 0xa5, 0x62, 0x5a, 0xa4, 0xd4, 0xc8, 0x69, 0xb6, 0xe4, 0x71, 0x1a, 0x2b, 0x5b, 0x14, 0xa7, - 0xaa, 0x32, 0x2f, 0xda, 0x81, 0xc5, 0x32, 0xb4, 0xb8, 0x5a, 0x79, 0x55, 0x54, 0x13, 0x66, 0x45, 0x32, 0x10, 0x66, - 0x56, 0x46, 0x45, 0x45, 0xb3, 0x56, 0x7d, 0x3c, 0xb4, 0x9e, 0x50, 0x64, 0x74, 0xf3, 0x0a, 0x1c, 0xb6, 0x0b, 0x41, - 0x75, 0xb7, 0x7d, 0x0a, 0x58, 0xad, 0xae, 0x98, 0xc8, 0xc2, 0xd0, 0x2f, 0x45, 0xaa, 0x6c, 0x99, 0xd3, 0xba, 0x05, - 0xbf, 0xe8, 0x9e, 0x64, 0x59, 0x8d, 0xba, 0xcd, 0x7a, 0x2b, 0xd9, 0xe8, 0x19, 0xdf, 0x95, 0x6c, 0x54, 0xd1, 0x76, - 0xf7, 0x1a, 0xe8, 0xfe, 0xb4, 0x54, 0x35, 0xd7, 0xf6, 0x26, 0xbf, 0x61, 0xba, 0x26, 0xd0, 0xa6, 0x42, 0xb3, 0xe1, - 0x2a, 0x17, 0x79, 0xbe, 0x5f, 0x5c, 0x26, 0x90, 0xb9, 0x3b, 0xfb, 0x8a, 0xfe, 0xb5, 0xd5, 0x28, 0xaf, 0xe3, 0x7a, - 0x5f, 0x93, 0x71, 0xcc, 0xaf, 0xc3, 0xf8, 0x1d, 0xcc, 0x57, 0x56, 0xbe, 0xb8, 0x8b, 0xd2, 0x50, 0x50, 0xcd, 0x5d, - 0x4a, 0x18, 0xbe, 0xb6, 0x60, 0xf8, 0x5a, 0xf1, 0xe9, 0xb2, 0x3f, 0x5e, 0xbe, 0x2c, 0x06, 0x08, 0xf6, 0x73, 0xc3, - 0x32, 0x2e, 0xc5, 0xf6, 0x39, 0xd6, 0x59, 0xd8, 0x65, 0xc1, 0xc2, 0x2e, 0x85, 0xb7, 0x3e, 0x94, 0xe7, 0x7d, 0xbb, - 0x7d, 0x94, 0x4d, 0xce, 0xf6, 0x6d, 0x79, 0xf0, 0xbf, 0x0d, 0xee, 0xed, 0x63, 0x71, 0xb9, 0x23, 0xff, 0x48, 0xa6, - 0xab, 0x28, 0x90, 0x5f, 0x40, 0xda, 0x81, 0x20, 0x5d, 0xeb, 0xce, 0x41, 0x29, 0xa7, 0x4c, 0x22, 0x90, 0x37, 0x9c, - 0x67, 0x82, 0x4f, 0xf5, 0x98, 0x99, 0xbe, 0x66, 0x24, 0x2b, 0xc1, 0x15, 0x2d, 0xa3, 0xed, 0x41, 0xf5, 0x22, 0xd7, - 0xf2, 0x23, 0x4b, 0xa2, 0x20, 0xc3, 0x5a, 0x8a, 0x64, 0x41, 0x92, 0x13, 0x93, 0x6c, 0xbc, 0x59, 0x87, 0x47, 0x2c, - 0x61, 0xd9, 0x84, 0xa6, 0x1e, 0x47, 0xcb, 0x5d, 0x93, 0x71, 0x08, 0xc8, 0xa8, 0xc9, 0xf0, 0x77, 0xe5, 0x85, 0x3f, - 0x1f, 0x46, 0x03, 0x3f, 0xd0, 0x94, 0x8a, 0x09, 0x8f, 0x20, 0x31, 0xc5, 0x8f, 0x8a, 0x1b, 0x4d, 0x07, 0x07, 0x7b, - 0x9e, 0x2b, 0xdd, 0x12, 0x70, 0xf5, 0xdb, 0xae, 0x41, 0xbd, 0x25, 0x5c, 0xcf, 0x29, 0xa7, 0xa6, 0x68, 0x49, 0xd7, - 0x6f, 0xb2, 0x08, 0xff, 0x23, 0xbd, 0xc3, 0x29, 0xca, 0xf3, 0x40, 0x41, 0xed, 0x8e, 0x18, 0x8d, 0x23, 0x17, 0x7f, - 0xa4, 0x77, 0x41, 0x71, 0x5b, 0x5c, 0x5e, 0x6e, 0x96, 0x1b, 0xe8, 0xf2, 0x9b, 0xc4, 0xc5, 0xe5, 0x24, 0xc1, 0x32, - 0xc7, 0x3c, 0x65, 0x63, 0x20, 0xce, 0xaf, 0xe9, 0x5d, 0xa0, 0xc6, 0x63, 0xd6, 0x65, 0x3d, 0xb4, 0x34, 0xa8, 0xf7, - 0xad, 0x62, 0x7b, 0x1b, 0xb4, 0x41, 0xd1, 0x97, 0x7d, 0x07, 0xa4, 0xd2, 0xae, 0x34, 0x0f, 0x11, 0xca, 0x1f, 0xba, - 0x14, 0xfc, 0xa5, 0x2d, 0xda, 0x44, 0x25, 0xf5, 0x75, 0xad, 0x13, 0x85, 0x0e, 0x65, 0xae, 0xc7, 0xa5, 0x97, 0x9a, - 0x53, 0xa7, 0xef, 0x20, 0x58, 0x8e, 0xb0, 0x2f, 0x85, 0x1e, 0x34, 0xf8, 0x4e, 0xa5, 0x84, 0x94, 0x91, 0xa4, 0xa7, - 0x65, 0x3f, 0xe7, 0xd2, 0x03, 0xbc, 0x43, 0x4a, 0x4b, 0x28, 0xaf, 0x63, 0xe6, 0x26, 0x5d, 0xf4, 0x7b, 0x41, 0xbc, - 0xa5, 0x59, 0x42, 0x90, 0xda, 0x58, 0x14, 0x39, 0x50, 0xa1, 0xa6, 0x2f, 0x95, 0x01, 0xc8, 0x46, 0x1e, 0xdb, 0x90, - 0x9a, 0x89, 0x94, 0x9a, 0xbe, 0x85, 0xf1, 0x1d, 0x52, 0x92, 0x4a, 0x64, 0x48, 0x25, 0x52, 0x0a, 0x3d, 0xbd, 0xb9, - 0x9a, 0x84, 0xec, 0x0d, 0x2d, 0xae, 0xcf, 0xa9, 0x3d, 0x4f, 0x2a, 0x60, 0x79, 0x72, 0x1c, 0x94, 0x07, 0xb0, 0x24, - 0xaa, 0x1a, 0xe4, 0xc6, 0x9d, 0x93, 0x9a, 0xfc, 0x56, 0x8f, 0xfb, 0x66, 0x59, 0xc4, 0xa0, 0xc4, 0x9b, 0xa0, 0x65, - 0xea, 0x4d, 0x70, 0x02, 0xf9, 0x88, 0x3c, 0x2f, 0xe0, 0xa7, 0xf6, 0x6e, 0x54, 0xb2, 0x95, 0xb7, 0x5f, 0xf1, 0x03, - 0x65, 0x5e, 0x40, 0x8e, 0x26, 0x4e, 0x0d, 0x4f, 0x49, 0x3d, 0x79, 0xd7, 0xce, 0xda, 0xb6, 0x1f, 0x75, 0x8a, 0x8e, - 0x06, 0xec, 0x7b, 0xe1, 0x2d, 0xad, 0x55, 0xd8, 0x77, 0xb9, 0xf5, 0x95, 0x3f, 0x1d, 0xec, 0x2b, 0x93, 0x48, 0xbd, - 0x8c, 0xac, 0x49, 0x9c, 0xfb, 0x73, 0x2d, 0x7f, 0x9e, 0xd3, 0xf4, 0xee, 0x82, 0x42, 0xae, 0x33, 0x87, 0xbb, 0xbe, - 0xe5, 0x36, 0x94, 0x79, 0xea, 0xbd, 0x44, 0x2a, 0x2b, 0x79, 0xf5, 0x12, 0xe0, 0xfa, 0x15, 0xc1, 0x5c, 0x46, 0x1b, - 0x2d, 0x47, 0x8c, 0x3a, 0x2d, 0x74, 0xe7, 0xe5, 0x49, 0xda, 0x66, 0xe0, 0x5f, 0x2b, 0x31, 0xad, 0x83, 0x05, 0x98, - 0xdb, 0x17, 0x52, 0xfb, 0xd9, 0x60, 0xdd, 0x2b, 0x03, 0x45, 0x10, 0xbe, 0x4b, 0x76, 0x2f, 0x75, 0x5b, 0xd6, 0xec, - 0xee, 0xa5, 0x56, 0x82, 0x7e, 0x32, 0xe5, 0x07, 0xeb, 0x79, 0x8a, 0xcb, 0xcb, 0x2c, 0xcf, 0x51, 0x0e, 0xe0, 0xfd, - 0xd0, 0xf6, 0xbc, 0x1f, 0x74, 0xd2, 0xa0, 0x0f, 0xb1, 0xd8, 0x8b, 0x98, 0x1b, 0x26, 0x5e, 0xce, 0xff, 0xc3, 0xc6, - 0xfc, 0x3f, 0x58, 0x57, 0x4e, 0xc1, 0x34, 0x1a, 0x27, 0x34, 0x32, 0xac, 0x13, 0x29, 0x02, 0x94, 0x7a, 0x5b, 0x26, - 0xc8, 0xc7, 0xab, 0x00, 0x34, 0xae, 0xe5, 0x88, 0x27, 0xa2, 0x3e, 0x0a, 0xa7, 0x2c, 0xbe, 0x0b, 0xe6, 0xac, 0x3e, - 0xe5, 0x09, 0xcf, 0x66, 0xe1, 0x90, 0xe2, 0xec, 0x2e, 0x13, 0x74, 0x5a, 0x9f, 0x33, 0xfc, 0x82, 0xc6, 0x0b, 0x2a, - 0xd8, 0x30, 0xc4, 0xee, 0x59, 0xca, 0xc2, 0xd8, 0x79, 0x1d, 0xa6, 0x29, 0xbf, 0x71, 0xf1, 0x5b, 0x7e, 0xcd, 0x05, - 0xc7, 0x6f, 0x6e, 0xef, 0xc6, 0x34, 0xc1, 0xef, 0xaf, 0xe7, 0x89, 0x98, 0xe3, 0x2c, 0x4c, 0xb2, 0x7a, 0x46, 0x53, - 0x36, 0x6a, 0x0f, 0x79, 0xcc, 0xd3, 0x3a, 0xa4, 0x6c, 0x4f, 0x69, 0x10, 0xb3, 0xf1, 0x44, 0x38, 0x51, 0x98, 0x7e, - 0x6c, 0xd7, 0xeb, 0xb3, 0x94, 0x4d, 0xc3, 0xf4, 0xae, 0x2e, 0x5b, 0x04, 0x9f, 0x37, 0x8e, 0xc2, 0x27, 0xa3, 0xe3, - 0xb6, 0x48, 0xc3, 0x24, 0x63, 0xb0, 0x4d, 0x41, 0x18, 0xc7, 0xce, 0xd1, 0x49, 0x63, 0x9a, 0xed, 0xa9, 0x40, 0x5e, - 0x98, 0x88, 0xfc, 0x0a, 0x7f, 0x04, 0xb8, 0xfd, 0x6b, 0x91, 0xe0, 0xeb, 0xb9, 0x10, 0x3c, 0x59, 0x0e, 0xe7, 0x69, - 0xc6, 0xd3, 0x60, 0xc6, 0x59, 0x22, 0x68, 0xda, 0xbe, 0xe6, 0x69, 0x44, 0xd3, 0x7a, 0x1a, 0x46, 0x6c, 0x9e, 0x05, - 0xc7, 0xb3, 0xdb, 0x36, 0x68, 0x16, 0xe3, 0x94, 0xcf, 0x93, 0x48, 0xcf, 0xc5, 0x92, 0x09, 0x4d, 0x99, 0xb0, 0x2b, - 0xe4, 0x2b, 0x4c, 0x82, 0x98, 0x25, 0x34, 0x4c, 0xeb, 0x63, 0xe8, 0x0c, 0x66, 0x51, 0x23, 0xa2, 0x63, 0x9c, 0x8e, - 0xaf, 0x43, 0xaf, 0xd9, 0x7a, 0x8c, 0xcd, 0xff, 0xfe, 0x09, 0x72, 0x1a, 0xdb, 0x8b, 0x9b, 0x8d, 0xc6, 0x9f, 0x50, - 0x7b, 0x6d, 0x16, 0x09, 0x50, 0xd0, 0x9c, 0xdd, 0x3a, 0x19, 0x87, 0x9c, 0xb6, 0x6d, 0x3d, 0xdb, 0xb3, 0x30, 0x82, - 0x84, 0xe0, 0xa0, 0x35, 0xbb, 0xcd, 0x61, 0x75, 0x81, 0x4a, 0x32, 0xd5, 0x8b, 0xd4, 0x4f, 0xcb, 0xdf, 0x0a, 0xf1, - 0xe9, 0x76, 0x88, 0x5b, 0x06, 0xe2, 0x12, 0xeb, 0xf5, 0x68, 0x9e, 0xca, 0xd8, 0x6a, 0xd0, 0xcc, 0x14, 0x20, 0x13, - 0xbe, 0xa0, 0xa9, 0x81, 0x43, 0x3e, 0xfc, 0x66, 0x30, 0x5a, 0xdb, 0xc1, 0x38, 0xfd, 0x14, 0x18, 0x69, 0x12, 0x2d, - 0xab, 0xfb, 0xda, 0x4c, 0xe9, 0xb4, 0x3d, 0xa1, 0x40, 0x4f, 0x41, 0x0b, 0x7e, 0xdf, 0xb0, 0x48, 0x4c, 0xd4, 0x4f, - 0x49, 0xce, 0x37, 0xaa, 0xee, 0xa4, 0xd1, 0x50, 0xcf, 0x19, 0xfb, 0x85, 0x06, 0x4d, 0x1f, 0x1a, 0xe4, 0x57, 0xf8, - 0x6f, 0xc5, 0x65, 0xde, 0x2a, 0xf7, 0xc4, 0x5f, 0xdb, 0xb7, 0x7c, 0xad, 0x24, 0xc5, 0xf2, 0x46, 0x34, 0x4e, 0x8d, - 0xac, 0x54, 0xc2, 0x07, 0xdc, 0x76, 0xf2, 0x3c, 0x11, 0xd6, 0x2d, 0x6e, 0x71, 0xb2, 0xde, 0xd7, 0x2a, 0xef, 0x22, - 0x80, 0x48, 0x87, 0x95, 0x6c, 0xc8, 0xdb, 0x49, 0x97, 0x34, 0xda, 0x49, 0xbd, 0x8e, 0x3c, 0x4e, 0xd2, 0x7e, 0xa2, - 0xd3, 0xf3, 0x3c, 0xd6, 0xe3, 0xd2, 0xd8, 0xce, 0x50, 0xc0, 0xe1, 0xaa, 0xe9, 0x6a, 0x55, 0x86, 0x01, 0x98, 0xbc, - 0xae, 0xf1, 0x37, 0xa1, 0x1b, 0xe0, 0xcc, 0xe2, 0xe4, 0x89, 0x79, 0xb1, 0x4b, 0x6a, 0x78, 0x45, 0xcc, 0x87, 0x12, - 0x73, 0xfe, 0x2c, 0x14, 0x13, 0xf0, 0x52, 0x14, 0xe2, 0xa7, 0x4c, 0x62, 0x72, 0x0f, 0x5d, 0xd4, 0x4b, 0x8b, 0x0c, - 0x37, 0xc8, 0xe4, 0x4b, 0x73, 0x18, 0xe5, 0x5b, 0x41, 0x60, 0x44, 0xfc, 0x15, 0x51, 0x36, 0x9d, 0xb1, 0xe8, 0xf6, - 0x1f, 0x6a, 0xd1, 0xd1, 0x44, 0x30, 0x99, 0xbb, 0x6d, 0x22, 0x0e, 0x93, 0x30, 0xbb, 0x1c, 0xaa, 0xbb, 0x92, 0x59, - 0x79, 0x33, 0x20, 0x94, 0xd0, 0x2b, 0x23, 0x8d, 0xa6, 0xd2, 0x1e, 0xfd, 0x41, 0xec, 0xb4, 0x4f, 0xd2, 0xfb, 0xec, - 0x93, 0x62, 0xe1, 0x19, 0x9f, 0xa7, 0x43, 0x08, 0x47, 0x6a, 0xa9, 0xb7, 0xe9, 0xb8, 0x71, 0xa5, 0x8a, 0xe1, 0x62, - 0x61, 0x65, 0x82, 0x0a, 0xcc, 0xec, 0x97, 0x4a, 0x50, 0x19, 0xf2, 0x52, 0xf7, 0x35, 0xb4, 0x88, 0x33, 0x4b, 0x02, - 0x99, 0x1d, 0xc9, 0xa4, 0x46, 0x2f, 0x21, 0xdd, 0xc4, 0x9f, 0x27, 0xec, 0xe7, 0x39, 0xbd, 0x64, 0xa0, 0x6b, 0x32, - 0x9f, 0x45, 0x32, 0xd6, 0x04, 0xb2, 0xaf, 0xde, 0x84, 0xe0, 0x05, 0x8b, 0xd4, 0xc6, 0x24, 0xb2, 0x52, 0xe7, 0x36, - 0xb9, 0x75, 0x17, 0xfc, 0xc5, 0xa0, 0x1d, 0x30, 0x1c, 0xf1, 0x69, 0xc8, 0x92, 0x40, 0xba, 0x7c, 0x8b, 0xc1, 0x02, - 0x68, 0x8d, 0x59, 0x14, 0x24, 0x7a, 0x7b, 0x9a, 0xc8, 0xff, 0xc0, 0x59, 0x22, 0xbb, 0xe6, 0x6d, 0x2e, 0x11, 0xaa, - 0xd0, 0x47, 0x0c, 0x82, 0xcf, 0x94, 0x5c, 0xe3, 0x08, 0xdb, 0xd5, 0xc5, 0xb5, 0xf3, 0xca, 0x0e, 0x34, 0xd6, 0x36, - 0x4a, 0x19, 0x01, 0x7c, 0xbd, 0x34, 0xe3, 0xa9, 0xf0, 0xbc, 0x09, 0x8e, 0x11, 0xe9, 0x4e, 0xa4, 0xb3, 0xab, 0x13, - 0xcb, 0x3f, 0xbd, 0x7a, 0x33, 0x68, 0x16, 0xe6, 0x7b, 0xe5, 0x36, 0xb0, 0x4a, 0x8e, 0xd2, 0x37, 0x4a, 0xe5, 0x32, - 0x8a, 0xdf, 0x6a, 0xa9, 0xe5, 0x73, 0xb1, 0x5c, 0xac, 0x8f, 0x9b, 0x12, 0x55, 0x5e, 0x05, 0x08, 0x19, 0x2c, 0xda, - 0x31, 0x15, 0xca, 0xcb, 0x75, 0x17, 0xaa, 0xe4, 0x95, 0x12, 0xd1, 0x97, 0xfb, 0xcb, 0x54, 0xcf, 0x98, 0x5f, 0x31, - 0xe3, 0x64, 0xaa, 0x92, 0x5c, 0xae, 0x31, 0x62, 0xe9, 0xa1, 0xdb, 0x9a, 0x29, 0x58, 0xee, 0x48, 0xba, 0x95, 0x6e, - 0x7d, 0xf5, 0x48, 0x53, 0x52, 0x86, 0xbb, 0x36, 0x06, 0x80, 0x5c, 0xbd, 0x6d, 0x80, 0x81, 0xd9, 0x9a, 0x09, 0xb3, - 0x04, 0xd0, 0xc6, 0x46, 0x14, 0x2e, 0xd2, 0x5c, 0xed, 0x2f, 0xbf, 0x15, 0xf9, 0xa1, 0xd5, 0x54, 0xfe, 0x66, 0x11, - 0xfc, 0x05, 0x09, 0xb8, 0x54, 0x4a, 0x69, 0xe0, 0x7e, 0xf3, 0xe6, 0xe2, 0x9d, 0x8b, 0xe1, 0xdd, 0x5c, 0x34, 0xcd, - 0x82, 0xa5, 0xab, 0x53, 0xe3, 0xea, 0x10, 0x66, 0x75, 0x03, 0x37, 0x9c, 0xc1, 0x55, 0x63, 0xc9, 0x0b, 0x0e, 0x6f, - 0xeb, 0x37, 0x37, 0x37, 0x75, 0xb8, 0x09, 0x55, 0x9f, 0xa7, 0x31, 0x4d, 0x86, 0x3c, 0xa2, 0x91, 0x9b, 0xe7, 0xc8, - 0x17, 0x13, 0x9a, 0x14, 0x6f, 0xef, 0xe1, 0x31, 0xf5, 0x63, 0x3e, 0x56, 0xb7, 0x38, 0xd7, 0xad, 0xea, 0xe1, 0x55, - 0x47, 0xbe, 0x95, 0xaa, 0xdb, 0x11, 0xea, 0x7d, 0x60, 0x22, 0x85, 0x9f, 0x5d, 0x88, 0xb9, 0x74, 0x0e, 0xc5, 0x44, - 0x3e, 0x5c, 0xc0, 0x09, 0x93, 0x4f, 0xfb, 0xcb, 0x0d, 0xea, 0xeb, 0xc1, 0x10, 0x93, 0xae, 0x5a, 0x73, 0x26, 0x5b, - 0x5d, 0x05, 0xc3, 0xab, 0xab, 0xbc, 0x73, 0x08, 0x63, 0x1d, 0x9a, 0x71, 0xaf, 0x79, 0x74, 0x67, 0xfa, 0x17, 0x14, - 0x09, 0x6f, 0x27, 0x4a, 0x49, 0x17, 0x86, 0x80, 0x79, 0xa3, 0x2e, 0x60, 0x05, 0x28, 0x12, 0x7a, 0x47, 0x45, 0x89, - 0x3c, 0xe2, 0xaa, 0x68, 0x17, 0x04, 0xaa, 0x61, 0x79, 0x50, 0x94, 0xfb, 0xb5, 0x24, 0x08, 0x03, 0x52, 0x64, 0x43, - 0x77, 0x85, 0xe0, 0xaf, 0x84, 0xac, 0x73, 0xa8, 0xf0, 0x70, 0x65, 0xbf, 0x0b, 0x45, 0xbd, 0xa7, 0xa0, 0xc0, 0x56, - 0x3f, 0x13, 0xf8, 0xa3, 0xc0, 0x1f, 0xaf, 0x64, 0x53, 0x23, 0xbd, 0x40, 0xad, 0x02, 0x29, 0xdf, 0x30, 0x6a, 0xca, - 0x90, 0xc7, 0x71, 0x38, 0xcb, 0x68, 0x60, 0x7e, 0x68, 0x41, 0x06, 0xf2, 0x70, 0x53, 0x73, 0xd0, 0xf9, 0x38, 0xe7, - 0xa0, 0x5f, 0x6c, 0xaa, 0x35, 0x8b, 0x30, 0xf5, 0xea, 0xf5, 0x61, 0xfd, 0x7a, 0x8c, 0x72, 0x31, 0x59, 0xda, 0x62, - 0xf0, 0x51, 0xa3, 0xd1, 0x86, 0xe4, 0xc9, 0x7a, 0x18, 0xb3, 0x71, 0x12, 0xc4, 0x74, 0x24, 0x72, 0x01, 0xd7, 0xda, - 0x96, 0x46, 0xef, 0xf0, 0x5b, 0x27, 0x29, 0x9d, 0x3a, 0x3e, 0xfc, 0x7b, 0xff, 0xc4, 0xb9, 0x88, 0x82, 0x44, 0x4c, - 0xea, 0x32, 0x4d, 0x17, 0x2e, 0x19, 0x88, 0x49, 0xe5, 0x79, 0x69, 0x4d, 0x34, 0xa4, 0xa0, 0x93, 0xe5, 0x22, 0x75, - 0xc4, 0x04, 0x8b, 0xd4, 0x6e, 0x97, 0xa0, 0xe5, 0xc6, 0x0a, 0x36, 0x55, 0x83, 0x23, 0x94, 0x67, 0x52, 0x93, 0xde, - 0x6c, 0x6c, 0xf4, 0xab, 0xea, 0xd3, 0x06, 0xfa, 0x2c, 0x4d, 0x30, 0x57, 0x9e, 0xe8, 0xa5, 0xea, 0xf1, 0x10, 0x64, - 0x56, 0x74, 0x54, 0x6c, 0xf7, 0x40, 0x39, 0x4b, 0x66, 0x73, 0xd1, 0x97, 0x5e, 0xf0, 0x14, 0x6e, 0x54, 0x0c, 0xb0, - 0x55, 0x02, 0x38, 0x18, 0x2c, 0x15, 0x30, 0xc3, 0x30, 0x1e, 0x7a, 0x00, 0x91, 0x53, 0x77, 0x4e, 0x53, 0x3a, 0x45, - 0xed, 0x29, 0x4b, 0xea, 0xaa, 0xee, 0xc4, 0xd2, 0x63, 0xfc, 0xc7, 0xf0, 0x94, 0xfb, 0x72, 0x34, 0x2c, 0x93, 0x5d, - 0xb7, 0xe0, 0xf2, 0x6a, 0x90, 0xe7, 0xed, 0x54, 0x78, 0xfd, 0xa7, 0x1e, 0x1a, 0xe0, 0xaf, 0xac, 0xb7, 0xb9, 0xb8, - 0xe6, 0xa8, 0xb8, 0xb8, 0x85, 0x76, 0x34, 0xb1, 0xcf, 0x82, 0x6c, 0xf6, 0x15, 0x81, 0x86, 0x2f, 0x3c, 0x97, 0x66, - 0xb3, 0xba, 0x62, 0x76, 0x75, 0x49, 0xb2, 0x2e, 0x74, 0x45, 0xda, 0xb5, 0xfb, 0x83, 0x58, 0x4a, 0x3e, 0xa6, 0x6f, - 0x75, 0x28, 0xef, 0xc3, 0xa0, 0xb8, 0x05, 0xa4, 0x9f, 0xed, 0x7b, 0x3f, 0xa8, 0xc2, 0x4f, 0xae, 0xce, 0xaa, 0x4c, - 0x11, 0x18, 0x59, 0xf1, 0xc6, 0xbb, 0x30, 0x8e, 0x61, 0xc2, 0x2b, 0xa3, 0xef, 0xd8, 0x6f, 0x09, 0xe9, 0x8b, 0x81, - 0x87, 0x72, 0x7d, 0x4e, 0x9f, 0x4a, 0x1d, 0xd4, 0x7a, 0xcd, 0xde, 0x9e, 0x30, 0xd1, 0x25, 0x25, 0xae, 0x19, 0xc4, - 0xc7, 0x2b, 0x89, 0xd4, 0xed, 0x92, 0x77, 0x29, 0x0d, 0xd6, 0x91, 0x0b, 0x22, 0x6e, 0x9a, 0x44, 0xae, 0xf3, 0x97, - 0x61, 0xcc, 0x86, 0x1f, 0x89, 0xbb, 0xbf, 0xf4, 0xd0, 0xe6, 0x3d, 0x49, 0xc9, 0x15, 0x0c, 0x87, 0x47, 0x55, 0xcf, - 0x7b, 0xe2, 0x5b, 0xcc, 0x5b, 0xbd, 0x46, 0xc7, 0xed, 0xee, 0x2f, 0x81, 0xf1, 0xa8, 0x79, 0xba, 0x57, 0xf9, 0x65, - 0xf9, 0x72, 0xac, 0x12, 0x0a, 0x40, 0xb3, 0x2a, 0x77, 0x24, 0x51, 0x11, 0xf7, 0x93, 0x94, 0xe6, 0x3a, 0x8a, 0xa9, - 0x01, 0x9c, 0x42, 0xf3, 0x37, 0xd7, 0xf9, 0x4b, 0x51, 0x46, 0x0b, 0x17, 0x88, 0xcc, 0xe1, 0x20, 0x2e, 0xcc, 0x05, - 0x76, 0xaf, 0x1f, 0x51, 0x11, 0xb2, 0x58, 0x75, 0x69, 0x1b, 0x8b, 0x7d, 0x6d, 0x45, 0xab, 0x55, 0x56, 0x5d, 0x0b, - 0xab, 0x62, 0x50, 0xae, 0xac, 0x73, 0x58, 0xc2, 0x2d, 0x57, 0x26, 0xcf, 0xa4, 0x1d, 0x4b, 0x2c, 0x57, 0xa8, 0xea, - 0x9c, 0xbf, 0x0c, 0xe5, 0x3d, 0x23, 0x00, 0x90, 0x6b, 0x00, 0x21, 0xca, 0xad, 0xee, 0xd1, 0x78, 0x31, 0xe1, 0xbe, - 0x08, 0xd3, 0x31, 0x15, 0x6b, 0x88, 0x8d, 0x55, 0x52, 0x6b, 0xdb, 0x44, 0xb4, 0x37, 0xa0, 0x0d, 0xab, 0xd0, 0x5e, - 0x01, 0xd2, 0x7b, 0xfb, 0x4b, 0x96, 0x93, 0xfd, 0xa5, 0x92, 0x6b, 0xef, 0xdf, 0x7e, 0x05, 0xb7, 0x22, 0x79, 0x02, - 0x96, 0xc8, 0x04, 0x81, 0xa4, 0x95, 0x9b, 0xa3, 0x44, 0x08, 0x97, 0x22, 0x44, 0x71, 0x02, 0x47, 0xce, 0x25, 0x41, - 0xcc, 0x5d, 0xa7, 0xa7, 0x20, 0xa7, 0x91, 0x82, 0x99, 0x24, 0xb2, 0x17, 0xcf, 0x3b, 0x87, 0xaa, 0xb5, 0x12, 0x01, - 0xaa, 0x11, 0x20, 0x41, 0x9e, 0xd3, 0x12, 0x07, 0x90, 0x08, 0x6d, 0xe3, 0x21, 0x62, 0x8b, 0x82, 0xd8, 0xe4, 0x8d, - 0xab, 0x6e, 0x27, 0x0e, 0xaf, 0x69, 0xdc, 0xdd, 0x5f, 0x26, 0xab, 0x55, 0x23, 0xef, 0x1c, 0xaa, 0x47, 0xa7, 0x23, - 0xf9, 0x86, 0x7a, 0x43, 0xa6, 0xdc, 0x62, 0xb8, 0xc6, 0x08, 0xe9, 0xa1, 0x26, 0x2f, 0x2a, 0xd0, 0x03, 0xe4, 0xae, - 0x23, 0x33, 0x32, 0x64, 0xa3, 0x42, 0x83, 0xca, 0x5d, 0x87, 0x45, 0x9b, 0x65, 0x99, 0xa0, 0x33, 0x28, 0x9d, 0xac, - 0x56, 0xcd, 0xdc, 0x75, 0xa6, 0x2c, 0x81, 0xa7, 0x64, 0xb5, 0x92, 0x37, 0x04, 0xa7, 0x2c, 0xf1, 0x1a, 0x40, 0xb6, - 0xae, 0x33, 0x0d, 0x6f, 0xe5, 0x82, 0x4d, 0x4d, 0x78, 0xeb, 0x35, 0x75, 0x95, 0x5f, 0xe0, 0x27, 0x03, 0x8a, 0x2b, - 0x77, 0x34, 0xd6, 0x3b, 0x1a, 0xe1, 0xb9, 0xba, 0xfb, 0x44, 0xbc, 0x88, 0xc4, 0xdb, 0x77, 0x34, 0x32, 0x3b, 0x3a, - 0xdf, 0xb1, 0xa3, 0xf3, 0x7b, 0x76, 0x34, 0xd4, 0xbb, 0xe7, 0x14, 0xb8, 0xe3, 0xab, 0x55, 0xb3, 0x51, 0x62, 0xaf, - 0x73, 0x18, 0xb1, 0x05, 0xec, 0x06, 0xe8, 0x85, 0x82, 0x4d, 0xe9, 0x76, 0xa2, 0xac, 0xa2, 0x98, 0xfe, 0x2a, 0x4c, - 0x96, 0x58, 0x48, 0xaa, 0x58, 0xb0, 0xe9, 0xba, 0x08, 0xd2, 0xfd, 0x91, 0x94, 0xcd, 0x00, 0x0f, 0x19, 0xe0, 0x61, - 0x62, 0xde, 0x98, 0xe9, 0xb9, 0xef, 0x5c, 0xec, 0x3a, 0xae, 0x21, 0xeb, 0xab, 0xfc, 0x12, 0x64, 0x84, 0x5c, 0xdf, - 0x83, 0x68, 0x11, 0x5a, 0xbb, 0xdd, 0xdd, 0x34, 0x07, 0xf1, 0xf4, 0x1b, 0x9e, 0x46, 0x6e, 0xa0, 0x9a, 0xfe, 0x2a, - 0x54, 0x4d, 0x59, 0xa2, 0xb3, 0xb3, 0x76, 0xd2, 0x5a, 0x59, 0x6f, 0x53, 0x5c, 0xeb, 0xe4, 0x44, 0xb5, 0x98, 0x85, - 0x42, 0xd0, 0x34, 0xd1, 0x94, 0xeb, 0xba, 0xff, 0x5f, 0x50, 0xe1, 0x16, 0xbe, 0x12, 0x9a, 0x0d, 0x30, 0x04, 0xa8, - 0x35, 0x7c, 0xcd, 0xf3, 0x95, 0x78, 0xda, 0x2b, 0x35, 0xd8, 0x3b, 0x64, 0x5b, 0x19, 0xaa, 0x08, 0x8c, 0x9e, 0xf9, - 0x94, 0x46, 0x97, 0x92, 0x41, 0xf7, 0x86, 0x57, 0x5a, 0x61, 0x5d, 0x13, 0x77, 0x65, 0x07, 0xec, 0xfe, 0x34, 0x6f, - 0x3d, 0x3e, 0x3e, 0x77, 0xb1, 0xe2, 0xf1, 0x7c, 0x34, 0x72, 0x51, 0xee, 0x3c, 0xac, 0x5b, 0xf3, 0xf8, 0xa7, 0xf9, - 0x97, 0xcf, 0x1b, 0x5f, 0x16, 0x9d, 0x13, 0x20, 0x22, 0x9d, 0x10, 0x60, 0x44, 0x95, 0x05, 0xaf, 0x59, 0xd1, 0x28, - 0x4c, 0x76, 0x2f, 0xa7, 0x6f, 0x2f, 0x27, 0x9b, 0x51, 0x1a, 0x01, 0x71, 0xe2, 0x8d, 0xd2, 0xcb, 0x98, 0x2e, 0xa8, - 0x79, 0x55, 0xe1, 0x96, 0xc9, 0xb6, 0xf4, 0x18, 0xf2, 0x79, 0x22, 0x74, 0x66, 0x84, 0x66, 0xb5, 0xd6, 0x92, 0xae, - 0xe4, 0x1a, 0x6c, 0x1b, 0xe1, 0x4e, 0xc9, 0xb9, 0xaa, 0xf4, 0xca, 0xaf, 0xb0, 0x6b, 0x01, 0xb0, 0x13, 0xb2, 0xde, - 0x8e, 0xf2, 0xa0, 0x81, 0x1b, 0xbb, 0x60, 0xc3, 0x4d, 0x14, 0xb8, 0xee, 0xc0, 0xe0, 0x49, 0x3a, 0x37, 0x2b, 0x6f, - 0x98, 0xd8, 0x89, 0xaf, 0x4f, 0x62, 0xe0, 0x3a, 0x85, 0xc1, 0x12, 0x9a, 0x65, 0x3b, 0x11, 0x50, 0x6c, 0x22, 0x76, - 0xcb, 0xd6, 0xee, 0x8e, 0x51, 0x70, 0x03, 0xc3, 0x09, 0x93, 0x00, 0x17, 0x21, 0x56, 0xdd, 0x8a, 0x8e, 0x46, 0x74, - 0x58, 0xf8, 0x86, 0x21, 0x58, 0x36, 0x62, 0xb1, 0x80, 0x98, 0x91, 0x0c, 0xe6, 0xb8, 0xaf, 0x79, 0x42, 0x5d, 0x64, - 0xd2, 0x3f, 0x35, 0xfc, 0x5a, 0xfe, 0x6f, 0x87, 0x47, 0x8d, 0x58, 0x85, 0x45, 0xcf, 0xb2, 0x5a, 0x19, 0xbf, 0x50, - 0xa5, 0xbc, 0x8a, 0x48, 0x2e, 0x1d, 0x3f, 0xbb, 0x0e, 0xd0, 0xc3, 0x8e, 0xc9, 0xb2, 0xf9, 0xe5, 0x49, 0xb3, 0x91, - 0xbb, 0xd8, 0x85, 0xe1, 0x1e, 0x7a, 0x4a, 0x64, 0xaf, 0x23, 0xe8, 0x35, 0x4f, 0x7e, 0x4d, 0xbf, 0x56, 0xf3, 0x49, - 0xd3, 0xc5, 0xea, 0xcd, 0x03, 0x28, 0x2f, 0x98, 0xc1, 0x10, 0xbc, 0xa5, 0xbf, 0x7b, 0x29, 0xd5, 0xc1, 0x1f, 0x06, - 0xcf, 0xa3, 0x66, 0xc3, 0xc5, 0x6e, 0x26, 0xf8, 0xec, 0x57, 0x2c, 0xe1, 0xc8, 0xc5, 0xee, 0x30, 0xe6, 0x19, 0xb5, - 0xd7, 0xa0, 0xd4, 0xd9, 0xdf, 0xbf, 0x08, 0x05, 0xd1, 0x2c, 0xa5, 0x59, 0xe6, 0xd8, 0xe3, 0x6b, 0x52, 0xfa, 0x04, - 0xc3, 0xdc, 0x4a, 0x71, 0x19, 0x15, 0x12, 0x2f, 0xea, 0xa5, 0x00, 0x36, 0x55, 0xa9, 0xb2, 0x0d, 0x62, 0x93, 0x22, - 0xa0, 0x60, 0x6c, 0x4a, 0xbb, 0xfa, 0xe4, 0xcc, 0x5b, 0x8e, 0x9e, 0x9a, 0x58, 0x05, 0x91, 0x37, 0x27, 0xa8, 0x94, - 0x4c, 0x59, 0x72, 0xb9, 0xa5, 0x34, 0xbc, 0xdd, 0x52, 0x0a, 0x2a, 0x5b, 0x01, 0x9d, 0x7e, 0x5f, 0xcd, 0xa7, 0xb1, - 0x5e, 0x2a, 0x3e, 0x36, 0x88, 0x91, 0x74, 0x74, 0x7e, 0x02, 0x52, 0x6b, 0x1b, 0xe4, 0x08, 0xbf, 0x7d, 0x3a, 0x28, - 0xf9, 0x35, 0xd3, 0x15, 0xa3, 0xfc, 0xbe, 0x15, 0x42, 0x69, 0x1d, 0x1c, 0xde, 0xf1, 0xaf, 0x5a, 0x2b, 0xbd, 0xfd, - 0x34, 0xc1, 0x59, 0x5a, 0xd5, 0xef, 0xd8, 0x7a, 0x7d, 0xf1, 0x7d, 0x7d, 0xef, 0xb7, 0x14, 0x6b, 0xc5, 0xa7, 0xd8, - 0xff, 0x61, 0xcc, 0xa6, 0x25, 0x09, 0x6c, 0x82, 0x29, 0x35, 0x1e, 0xc8, 0x7e, 0xb2, 0x07, 0x51, 0xaa, 0xcf, 0x25, - 0xdc, 0xe9, 0x84, 0x17, 0x67, 0xcc, 0x53, 0x7a, 0x19, 0xf3, 0x9b, 0xf5, 0x17, 0x81, 0xed, 0x6e, 0x3c, 0x61, 0xe3, - 0x89, 0x75, 0x51, 0x8b, 0x92, 0x62, 0x13, 0xee, 0x9d, 0x20, 0xff, 0x97, 0x7f, 0xf6, 0xfd, 0x7f, 0xf9, 0xe7, 0x4f, - 0x36, 0x85, 0xe1, 0xf3, 0x2b, 0x2c, 0xca, 0x61, 0x77, 0x9f, 0xae, 0xed, 0x33, 0x55, 0x71, 0xbe, 0xbd, 0xcd, 0xc6, - 0x26, 0x40, 0xfd, 0xc6, 0x16, 0x6c, 0x14, 0xaa, 0xd3, 0xe7, 0xfc, 0x16, 0xc0, 0x60, 0x5d, 0x9f, 0x84, 0x0c, 0x1a, - 0xfd, 0x2e, 0xd0, 0xae, 0x50, 0xf0, 0xa0, 0x1d, 0xf9, 0xed, 0x18, 0xfe, 0xd4, 0x1a, 0x7e, 0x27, 0xf8, 0xda, 0x3f, - 0x31, 0xbc, 0xba, 0x2a, 0x32, 0xf2, 0xec, 0xae, 0x70, 0xe3, 0xbf, 0xb7, 0x51, 0xa2, 0x15, 0x8f, 0xa0, 0x81, 0xba, - 0xf2, 0x3e, 0x21, 0x19, 0x5e, 0xbd, 0x82, 0xd7, 0xfc, 0x74, 0xae, 0x53, 0xe3, 0xe0, 0xbd, 0x47, 0x38, 0xc0, 0x10, - 0xd5, 0x55, 0xc9, 0x41, 0x37, 0x24, 0x03, 0x94, 0x82, 0xb9, 0x01, 0x60, 0xe2, 0xe1, 0x95, 0xb6, 0x36, 0xcf, 0x95, - 0x1b, 0x26, 0x58, 0x27, 0x6d, 0xed, 0x9e, 0xa9, 0x20, 0x1d, 0x3b, 0xef, 0x24, 0xbe, 0x64, 0x63, 0x5a, 0x5a, 0xf7, - 0xd2, 0xd5, 0x05, 0x76, 0x44, 0xc1, 0x7e, 0x16, 0x61, 0xbc, 0x78, 0x18, 0xe3, 0xdb, 0x2d, 0x50, 0x57, 0xce, 0xea, - 0xdf, 0x5a, 0x25, 0x58, 0xd5, 0x57, 0x15, 0x7d, 0x40, 0x66, 0x25, 0xfc, 0x75, 0x57, 0xe0, 0xf4, 0xef, 0x9f, 0x0e, - 0x9c, 0xf2, 0x07, 0x05, 0x4e, 0xff, 0xfe, 0x87, 0x07, 0x4e, 0xff, 0x6a, 0x07, 0x4e, 0x81, 0x04, 0x7f, 0x7e, 0x50, - 0x70, 0xd3, 0x04, 0x9e, 0xf8, 0x4d, 0x46, 0x9a, 0xda, 0x08, 0x88, 0xf9, 0x18, 0x22, 0x9b, 0xff, 0xf6, 0x81, 0xca, - 0x98, 0x8f, 0xed, 0x30, 0x25, 0xbc, 0xa4, 0x16, 0xe2, 0x92, 0x6d, 0x13, 0x50, 0xd4, 0xa1, 0xc1, 0x46, 0x71, 0x01, - 0xa7, 0x7e, 0x6c, 0x5e, 0x18, 0xe1, 0x06, 0xc5, 0x4b, 0x9f, 0x1a, 0xb8, 0x65, 0x82, 0x87, 0x81, 0x8c, 0x3b, 0x16, - 0x1d, 0x5b, 0x35, 0x73, 0xbb, 0xc4, 0x1e, 0xa1, 0x6d, 0x5e, 0x6a, 0xa3, 0x5e, 0x36, 0xb0, 0x74, 0x7f, 0xba, 0x6d, - 0x3e, 0xed, 0x37, 0xdb, 0x47, 0xcd, 0xa9, 0x1b, 0xb8, 0x20, 0xe0, 0x65, 0x41, 0xa3, 0x7d, 0x74, 0x04, 0x05, 0x37, - 0x56, 0x41, 0x0b, 0x0a, 0x98, 0x55, 0x70, 0x02, 0x05, 0x43, 0xab, 0xe0, 0x11, 0x14, 0x44, 0x56, 0xc1, 0x63, 0x28, - 0x58, 0xb8, 0x79, 0x9f, 0x15, 0xe0, 0x3e, 0x46, 0x03, 0xac, 0xec, 0x2e, 0x53, 0xf6, 0x18, 0x37, 0x21, 0x62, 0x19, - 0x8e, 0x65, 0xa2, 0x15, 0xb8, 0x33, 0x03, 0x8e, 0x6f, 0x26, 0x34, 0x09, 0x20, 0x66, 0xfc, 0x4c, 0x4a, 0x48, 0x5f, - 0xf0, 0x77, 0x6c, 0x4a, 0xcd, 0xe7, 0x41, 0x0c, 0x1e, 0x1c, 0x17, 0xf5, 0x1b, 0x83, 0xbc, 0x5d, 0xec, 0x9c, 0x0a, - 0x75, 0xea, 0xa4, 0x1b, 0xb5, 0x97, 0x65, 0x9d, 0x9a, 0xae, 0x5e, 0xec, 0xf9, 0x8e, 0x08, 0x98, 0xe5, 0x49, 0x19, - 0xc5, 0xfc, 0xa6, 0x7e, 0xeb, 0x76, 0xb7, 0x47, 0xc5, 0x00, 0xa2, 0x22, 0x2a, 0x26, 0xd7, 0x54, 0x3c, 0xbd, 0x0b, - 0xc7, 0xc5, 0xef, 0x57, 0x34, 0xcb, 0xc2, 0xb1, 0x6e, 0xb9, 0x3b, 0x0a, 0x26, 0x41, 0xb4, 0x23, 0x60, 0x06, 0x08, - 0x88, 0x64, 0xc1, 0x66, 0x81, 0x27, 0x42, 0x07, 0xb6, 0x00, 0x3b, 0xd5, 0x98, 0x98, 0x9c, 0xbe, 0x5a, 0x24, 0xc2, - 0x71, 0x59, 0xd0, 0x99, 0xa5, 0x54, 0x96, 0x2a, 0x0c, 0xe7, 0x9d, 0x43, 0x28, 0x50, 0xd5, 0x3b, 0x62, 0x5f, 0xc6, - 0xed, 0xb1, 0x3b, 0x02, 0xe6, 0x98, 0xd8, 0x97, 0x9d, 0x5e, 0x54, 0xe4, 0x16, 0x6d, 0x46, 0x5c, 0x3e, 0x6f, 0x0e, - 0xe1, 0x3f, 0x1d, 0xcf, 0xf9, 0x7c, 0x34, 0x1a, 0xdd, 0x1b, 0x0b, 0xfb, 0x3c, 0x1a, 0xd1, 0x16, 0x3d, 0x69, 0x43, - 0xea, 0x49, 0x5d, 0x47, 0x50, 0x9a, 0xb9, 0xc4, 0xdd, 0xf2, 0x61, 0x8d, 0x21, 0xd8, 0x22, 0x26, 0xcb, 0x87, 0xc7, - 0xc5, 0xf2, 0x59, 0x4a, 0x97, 0xd3, 0x30, 0x1d, 0xb3, 0x24, 0x68, 0xe4, 0xfe, 0x42, 0x07, 0x92, 0x3e, 0x3f, 0x3d, - 0x3d, 0xcd, 0xfd, 0xc8, 0x3c, 0x35, 0xa2, 0x28, 0xf7, 0x87, 0xcb, 0x62, 0x19, 0x8d, 0xc6, 0x68, 0x94, 0xfb, 0xcc, - 0x14, 0x1c, 0xb5, 0x86, 0xd1, 0x51, 0x2b, 0xf7, 0x6f, 0xac, 0x16, 0xb9, 0x4f, 0xf5, 0x53, 0x4a, 0xa3, 0x4a, 0xfe, - 0xca, 0xe3, 0x46, 0x23, 0xf7, 0x15, 0xa1, 0x2d, 0xc1, 0x98, 0x54, 0x3f, 0x83, 0x70, 0x2e, 0x38, 0xb0, 0xe4, 0x36, - 0x17, 0x5e, 0xff, 0x52, 0xbf, 0x1b, 0x44, 0x7d, 0x47, 0x23, 0x47, 0x03, 0xfc, 0xb3, 0x1d, 0xf2, 0x01, 0x62, 0x96, - 0xa1, 0x1e, 0x6e, 0x22, 0x42, 0x95, 0x6a, 0xa0, 0x2c, 0x59, 0xfd, 0x33, 0xe1, 0x65, 0x24, 0x08, 0xf8, 0x0f, 0xb4, - 0x54, 0x2f, 0xb1, 0x13, 0x74, 0x07, 0xd7, 0xa7, 0xf4, 0x93, 0x5c, 0xff, 0xee, 0x21, 0x4c, 0x9f, 0xd2, 0x3f, 0x9a, - 0xe9, 0xeb, 0x37, 0xbd, 0x2a, 0xa6, 0xaf, 0xd8, 0xda, 0x54, 0x10, 0x77, 0x38, 0xa1, 0xc3, 0x8f, 0xd7, 0xfc, 0xb6, - 0x0e, 0x47, 0x22, 0x75, 0x25, 0x3f, 0x1d, 0xfd, 0xd6, 0x5c, 0x17, 0x33, 0x98, 0xf5, 0x19, 0x0e, 0x29, 0xf4, 0xdf, - 0x24, 0xc4, 0x7d, 0x63, 0x2c, 0x52, 0x55, 0x32, 0x1a, 0x11, 0xf7, 0xcd, 0x68, 0xe4, 0x9a, 0x1b, 0x8e, 0xa1, 0xa0, - 0xb2, 0xd5, 0xeb, 0x4a, 0x89, 0x6c, 0xf5, 0xe5, 0x97, 0x76, 0x99, 0x5d, 0xa0, 0x03, 0x46, 0x76, 0x70, 0x48, 0xd7, - 0x44, 0x2c, 0x83, 0xa3, 0x06, 0x5f, 0x07, 0xa9, 0xbe, 0x62, 0x31, 0xad, 0xbc, 0x0d, 0xbb, 0x00, 0x78, 0xcb, 0x2b, - 0xbc, 0xd7, 0xaf, 0xf7, 0x8f, 0xa9, 0xc9, 0x36, 0x7c, 0x7a, 0xf7, 0x55, 0xe4, 0x4d, 0x05, 0xca, 0x59, 0xf6, 0x26, - 0x59, 0xbb, 0xba, 0xa3, 0x60, 0x24, 0xc4, 0x5e, 0x56, 0x2e, 0xf8, 0x78, 0x1c, 0xc3, 0xf7, 0x59, 0x96, 0x95, 0xd7, - 0xbe, 0xaa, 0xee, 0xbd, 0xca, 0x7a, 0x03, 0xbb, 0xa3, 0x7e, 0x49, 0xaa, 0xfc, 0x5c, 0x94, 0x4a, 0xf9, 0x5e, 0xe8, - 0xef, 0x06, 0x49, 0x63, 0x76, 0xa9, 0xf9, 0xff, 0x52, 0x25, 0x0a, 0x0b, 0x48, 0x92, 0x51, 0x03, 0x47, 0x79, 0xae, - 0xaf, 0x58, 0x44, 0x2c, 0x9b, 0xc1, 0xeb, 0x48, 0x55, 0x4f, 0xfa, 0x29, 0x16, 0x9e, 0xdd, 0x58, 0x51, 0x99, 0xca, - 0x76, 0xe5, 0x26, 0x2c, 0xa3, 0xdc, 0xdc, 0x53, 0x91, 0xbb, 0xda, 0x5b, 0x6e, 0x90, 0xe8, 0x3a, 0x0a, 0x9f, 0x2a, - 0x5e, 0x64, 0xad, 0x10, 0x5c, 0xd6, 0xc5, 0x86, 0x98, 0x2a, 0x53, 0x90, 0xdb, 0x51, 0x47, 0x59, 0xa3, 0xb0, 0x25, - 0x63, 0x1c, 0xd9, 0x2c, 0x4c, 0x14, 0x1b, 0x25, 0xae, 0xe2, 0x07, 0xfb, 0xcb, 0x72, 0xe7, 0x73, 0xd7, 0x80, 0xad, - 0x88, 0xb7, 0xdb, 0x39, 0x84, 0x0e, 0x5d, 0xa7, 0x02, 0x7a, 0xb2, 0x11, 0x1a, 0xf9, 0x44, 0x92, 0xc2, 0x95, 0x9f, - 0xdd, 0x60, 0x3f, 0xbb, 0x71, 0xfe, 0xbc, 0xac, 0xdf, 0xd0, 0xeb, 0x8f, 0x4c, 0xd4, 0x45, 0x38, 0xab, 0x83, 0xb9, - 0x22, 0x5d, 0x9a, 0x9a, 0x3d, 0xcb, 0xdc, 0x3c, 0xf5, 0x82, 0x82, 0xf6, 0x3c, 0x83, 0x5c, 0x06, 0xa9, 0x74, 0x07, - 0x09, 0x4f, 0x68, 0xbb, 0x9a, 0x83, 0x69, 0x87, 0xc6, 0x0d, 0xb6, 0x06, 0x4b, 0x0e, 0xb9, 0x0f, 0xe2, 0x2e, 0x68, - 0x68, 0xb6, 0xde, 0x30, 0x71, 0xef, 0xc6, 0xd6, 0xf6, 0x81, 0x46, 0x6e, 0x4d, 0x4a, 0xaf, 0x74, 0x33, 0xfe, 0xbf, - 0x2b, 0x7e, 0xff, 0xa9, 0x8c, 0x44, 0x70, 0x84, 0x9a, 0xff, 0xad, 0x54, 0xce, 0xf5, 0x62, 0x99, 0x91, 0xf8, 0x10, - 0xc8, 0x82, 0x70, 0x24, 0x68, 0x8a, 0x1f, 0xd2, 0xf2, 0x5a, 0x5e, 0x1e, 0x5a, 0x82, 0x98, 0x09, 0x9a, 0xa7, 0xb3, - 0xdb, 0x87, 0x0f, 0x7f, 0xff, 0xf2, 0x73, 0x8d, 0x23, 0xf3, 0x32, 0x1d, 0xd7, 0x6d, 0xc3, 0x41, 0x88, 0xc3, 0xbb, - 0x80, 0x25, 0x52, 0xe6, 0x5d, 0x83, 0x37, 0xb3, 0x3d, 0xe3, 0x3a, 0xb5, 0x36, 0xa5, 0xb1, 0xfc, 0x72, 0x9e, 0xde, - 0x8a, 0xa3, 0x47, 0xb3, 0x5b, 0xb3, 0x1b, 0xcd, 0xb5, 0x94, 0xd9, 0x3f, 0x34, 0x33, 0x76, 0x77, 0x2a, 0x6e, 0x35, - 0xbb, 0xf3, 0x64, 0x76, 0xdb, 0x56, 0x82, 0xb6, 0x9e, 0x2a, 0xa8, 0x1a, 0xb3, 0x5b, 0x3b, 0x37, 0xb8, 0x1c, 0xc8, - 0xf1, 0x8f, 0x32, 0x87, 0x86, 0x19, 0x6d, 0xc3, 0xeb, 0xc2, 0xd9, 0x30, 0x8c, 0xb5, 0x30, 0x9f, 0xb2, 0x28, 0x8a, - 0x69, 0xdb, 0xc8, 0x6b, 0xa7, 0xf9, 0x08, 0x52, 0x6b, 0xed, 0x2d, 0xab, 0xee, 0x8a, 0x85, 0xbc, 0x02, 0x4f, 0xe1, - 0x75, 0xc6, 0x63, 0xf8, 0x56, 0xc7, 0x56, 0x74, 0xea, 0x9c, 0xd3, 0x46, 0x89, 0x3c, 0xf9, 0xbb, 0xba, 0x96, 0x93, - 0xc6, 0x9f, 0xda, 0x72, 0xc3, 0x1b, 0x6d, 0xc1, 0x67, 0x41, 0xfd, 0xa8, 0xba, 0x10, 0xa8, 0x2a, 0x96, 0x80, 0xb7, - 0x2c, 0x0b, 0x83, 0xb4, 0x52, 0x7c, 0xda, 0xf1, 0x9b, 0xba, 0x4c, 0x0e, 0x00, 0xd9, 0x5c, 0x45, 0x51, 0x5e, 0x5d, - 0xcc, 0xbf, 0xcd, 0x69, 0x79, 0xb2, 0xfd, 0xb4, 0x3c, 0x31, 0xa7, 0xe5, 0x7e, 0x8a, 0xfd, 0x7c, 0xd4, 0x84, 0xff, - 0xda, 0xe5, 0x82, 0x82, 0x86, 0x73, 0x34, 0xbb, 0x75, 0x40, 0x4f, 0xab, 0xb7, 0x66, 0xb7, 0x2a, 0x33, 0x1a, 0x22, - 0x2e, 0x0d, 0xc8, 0x15, 0xc6, 0x0d, 0x07, 0x0a, 0xe1, 0xff, 0x46, 0xa5, 0xaa, 0x79, 0x0c, 0x75, 0xd0, 0xeb, 0x64, - 0xb3, 0xae, 0x75, 0xff, 0xa1, 0x0d, 0x12, 0x2e, 0xbc, 0xc0, 0x70, 0x63, 0xe4, 0x8b, 0xf0, 0xfa, 0x9a, 0x46, 0xc1, - 0x88, 0x0f, 0xe7, 0xd9, 0x3f, 0x69, 0xf8, 0x35, 0x12, 0xef, 0x3d, 0xd2, 0x6b, 0xe3, 0x98, 0xae, 0x2a, 0x4f, 0xdb, - 0x8c, 0xb0, 0x2c, 0xf6, 0x29, 0xc8, 0x86, 0x61, 0x4c, 0xbd, 0x96, 0x7f, 0xbc, 0xe5, 0x10, 0xfc, 0xbb, 0xec, 0xcd, - 0xd6, 0xc5, 0xfc, 0x5e, 0x64, 0xdc, 0x8b, 0x84, 0x5f, 0x85, 0x03, 0x7b, 0x0f, 0x1b, 0xa7, 0xdb, 0xc1, 0xed, 0x9b, - 0x99, 0x06, 0x46, 0x28, 0x68, 0xb9, 0x13, 0xd1, 0x51, 0x38, 0x8f, 0xc5, 0xfd, 0xa3, 0xee, 0xa2, 0x8c, 0x8d, 0x51, - 0xef, 0x61, 0xe8, 0x65, 0xdb, 0x07, 0x72, 0xe9, 0xcf, 0x9f, 0x1c, 0xc3, 0x7f, 0x2a, 0x6b, 0xeb, 0xae, 0xd4, 0xd5, - 0x95, 0xad, 0x0a, 0xba, 0xfa, 0xa8, 0xa2, 0x8c, 0x2b, 0x11, 0x2e, 0xf5, 0xf1, 0x87, 0xb6, 0x06, 0xad, 0xf2, 0x41, - 0xcd, 0xb5, 0x96, 0xf5, 0xab, 0x5a, 0xff, 0xba, 0xc1, 0x1f, 0xd8, 0x76, 0xa8, 0x34, 0xd7, 0x6a, 0x5b, 0xfd, 0xe9, - 0xc0, 0x8d, 0xc6, 0x06, 0xe3, 0xb2, 0xfd, 0x88, 0xdc, 0x15, 0x26, 0x8a, 0x8a, 0xa1, 0x82, 0x95, 0x32, 0x52, 0x56, - 0x0a, 0xa3, 0xe4, 0xaa, 0xd3, 0xbb, 0x9d, 0xc6, 0xce, 0x42, 0x5d, 0x72, 0x24, 0x6e, 0xd3, 0x6f, 0xb8, 0x8e, 0x8c, - 0xde, 0xc3, 0xcb, 0xd6, 0x5d, 0xf9, 0x49, 0x5a, 0xb7, 0x07, 0x9a, 0xd6, 0x62, 0x2c, 0x35, 0xbb, 0x97, 0xe1, 0x1d, - 0x4d, 0x2f, 0x5b, 0xae, 0x03, 0xde, 0x95, 0xba, 0x4a, 0x74, 0x90, 0x65, 0x4e, 0xcb, 0x75, 0x6e, 0xa7, 0x71, 0x92, - 0x11, 0x77, 0x22, 0xc4, 0x2c, 0x50, 0xdf, 0xac, 0xbd, 0x39, 0xf2, 0x79, 0x3a, 0x3e, 0x6c, 0x35, 0x1a, 0x0d, 0x78, - 0x71, 0xab, 0xeb, 0x2c, 0x18, 0xbd, 0x79, 0xca, 0x6f, 0x89, 0xdb, 0x70, 0x1a, 0x4e, 0xb3, 0x75, 0xea, 0x34, 0x5b, - 0xc7, 0xfe, 0xa3, 0x53, 0xb7, 0xfb, 0x99, 0xe3, 0x74, 0x22, 0x3a, 0xca, 0xe0, 0x87, 0xe3, 0x74, 0xa4, 0xe2, 0xa5, - 0x7e, 0x3b, 0x8e, 0x3f, 0x8c, 0xb3, 0x7a, 0xd3, 0x59, 0xea, 0x47, 0xc7, 0x81, 0xab, 0xa0, 0x81, 0xf3, 0xf9, 0xa8, - 0x35, 0x3a, 0x1e, 0x3d, 0x69, 0xeb, 0xe2, 0xfc, 0xb3, 0x4a, 0x73, 0xac, 0xfe, 0xb6, 0xac, 0x6e, 0x99, 0x48, 0xf9, - 0x47, 0xaa, 0x33, 0x09, 0x1d, 0x10, 0x3d, 0x5b, 0xbb, 0xb6, 0x36, 0x67, 0x6a, 0x9e, 0x5e, 0x0f, 0x47, 0xad, 0xb2, - 0xb9, 0x84, 0xf1, 0xb0, 0x00, 0xb2, 0x73, 0x68, 0x40, 0xef, 0xd8, 0x68, 0x6a, 0xd6, 0xb7, 0x21, 0xaa, 0xe9, 0xea, - 0x35, 0x8e, 0xcd, 0xfa, 0x3a, 0x70, 0xf3, 0xc0, 0xe8, 0xaa, 0x12, 0x02, 0xd7, 0x89, 0x88, 0xfb, 0xaa, 0xd9, 0x3a, - 0xc5, 0xcd, 0xe6, 0x23, 0xff, 0xd1, 0xe9, 0xb0, 0x81, 0x8f, 0xfd, 0xe3, 0xfa, 0x91, 0xff, 0x08, 0x9f, 0xd6, 0x4f, - 0xf1, 0xe9, 0x8b, 0xd3, 0x61, 0xfd, 0xd8, 0x3f, 0xc6, 0x8d, 0xfa, 0x29, 0x14, 0xd6, 0x4f, 0xeb, 0xa7, 0x8b, 0xfa, - 0xf1, 0xe9, 0xb0, 0x21, 0x4b, 0x5b, 0xfe, 0xc9, 0x49, 0xbd, 0xd9, 0xf0, 0x4f, 0x4e, 0xf0, 0x89, 0xff, 0xe8, 0x51, - 0xbd, 0x79, 0xe4, 0x3f, 0x7a, 0xf4, 0xf2, 0xe4, 0xd4, 0x3f, 0x82, 0xba, 0xa3, 0xa3, 0xe1, 0x91, 0xdf, 0x6c, 0xd6, - 0xe1, 0x1f, 0x7c, 0xea, 0xb7, 0xd4, 0x8f, 0x66, 0xd3, 0x3f, 0x6a, 0xe2, 0x46, 0x7c, 0xd2, 0xf2, 0x1f, 0x3d, 0xc1, - 0xf2, 0x5f, 0xd9, 0x0c, 0xcb, 0x7f, 0x60, 0x18, 0xfc, 0xc4, 0x6f, 0x3d, 0x52, 0xbf, 0xe4, 0x80, 0x8b, 0xe3, 0xd3, - 0x1f, 0xdd, 0xc3, 0x9d, 0x6b, 0x68, 0xaa, 0x35, 0x9c, 0x9e, 0xf8, 0x47, 0x47, 0xf8, 0xb8, 0xe9, 0x9f, 0x1e, 0x4d, - 0xea, 0xc7, 0x2d, 0xff, 0xd1, 0xe3, 0x61, 0xbd, 0xe9, 0x3f, 0x7e, 0x8c, 0x1b, 0xf5, 0x23, 0xbf, 0x85, 0x9b, 0xfe, - 0xf1, 0x91, 0xfc, 0x71, 0xe4, 0xb7, 0x16, 0x8f, 0x9f, 0xf8, 0x8f, 0x4e, 0x26, 0x8f, 0xfc, 0xe3, 0xef, 0x8e, 0x4f, - 0xfd, 0xd6, 0xd1, 0xe4, 0xe8, 0x91, 0xdf, 0x7a, 0xbc, 0x78, 0xe4, 0x1f, 0x4f, 0xea, 0xad, 0x47, 0xf7, 0xf6, 0x6c, - 0xb6, 0x7c, 0xc0, 0x91, 0xac, 0x86, 0x0a, 0xac, 0x2b, 0xe0, 0xff, 0x89, 0xec, 0xfb, 0xef, 0x38, 0x4c, 0xb6, 0xd9, - 0xf5, 0x89, 0x7f, 0xfa, 0x78, 0xa8, 0x9a, 0x43, 0x41, 0xdd, 0xb4, 0x80, 0x2e, 0x8b, 0xba, 0x9a, 0x56, 0x0e, 0x57, - 0x37, 0x03, 0x99, 0xff, 0xf5, 0x64, 0x8b, 0x3a, 0x4c, 0xac, 0xe6, 0xfd, 0x0f, 0x1d, 0xa7, 0xd8, 0xf2, 0xce, 0xe1, - 0x58, 0x91, 0xfe, 0xb8, 0xfb, 0x99, 0x7a, 0x2b, 0xf3, 0x67, 0x57, 0x38, 0xdb, 0xe5, 0xf8, 0x48, 0x3f, 0xed, 0xf8, - 0x48, 0xe8, 0x43, 0x3c, 0x1f, 0xe9, 0x1f, 0xee, 0xf9, 0xc8, 0xe8, 0x9a, 0xbb, 0xfb, 0x4e, 0x6c, 0x38, 0x38, 0xd6, - 0xad, 0xe2, 0x17, 0xc2, 0xeb, 0x33, 0xf8, 0xfc, 0x57, 0xde, 0xbe, 0x83, 0x37, 0xbf, 0xdb, 0x7e, 0x20, 0x0e, 0x2c, - 0xf6, 0x4e, 0x28, 0x1e, 0xcb, 0x77, 0x21, 0x24, 0xfe, 0x34, 0x42, 0xbe, 0x7b, 0x08, 0x3e, 0xe2, 0x3f, 0x1c, 0x1f, - 0xdc, 0xc6, 0x47, 0xc5, 0x03, 0x2f, 0x3d, 0x0d, 0xd2, 0x53, 0x70, 0x21, 0x9f, 0x3d, 0xb8, 0xfa, 0x54, 0x73, 0x0f, - 0x29, 0x14, 0x65, 0xae, 0x8a, 0x57, 0xbd, 0xfe, 0x35, 0xc1, 0x02, 0x75, 0xcf, 0x91, 0xb8, 0xda, 0x2d, 0x33, 0x93, - 0x52, 0x47, 0x3f, 0x14, 0x42, 0xa9, 0xe5, 0x37, 0xfc, 0x46, 0xe1, 0xd2, 0x81, 0xbb, 0xad, 0x64, 0xc9, 0x45, 0x08, - 0x5f, 0x99, 0x8d, 0xf9, 0x58, 0x7e, 0x8f, 0x16, 0xbe, 0x02, 0x20, 0xbf, 0x0c, 0xac, 0x3e, 0xc0, 0x10, 0xb8, 0xae, - 0x7e, 0x23, 0x06, 0xdc, 0x9d, 0xfc, 0x16, 0xee, 0x97, 0x9a, 0x58, 0xc2, 0x14, 0xbc, 0x1d, 0xaf, 0x68, 0xc4, 0x42, - 0xcf, 0xf5, 0x66, 0x29, 0x1d, 0xd1, 0x34, 0xab, 0x57, 0x2e, 0x5d, 0xca, 0xfb, 0x96, 0xc8, 0x35, 0xdf, 0x33, 0x4d, - 0xe1, 0xad, 0xd6, 0xa4, 0xaf, 0xfd, 0x8d, 0xae, 0x36, 0xc0, 0xdc, 0x1c, 0x9b, 0x92, 0x14, 0x64, 0x6d, 0xa9, 0xb4, - 0xb9, 0x4a, 0x6b, 0x6b, 0xfa, 0xad, 0x13, 0xe4, 0xc8, 0x62, 0x78, 0x5b, 0xf0, 0x0f, 0x5e, 0xfd, 0xa8, 0xf1, 0x27, - 0x64, 0x75, 0x2b, 0x06, 0x1a, 0x68, 0x77, 0x5b, 0x5a, 0x7e, 0x07, 0xba, 0x7a, 0x23, 0xd6, 0x55, 0x14, 0xf1, 0xb9, - 0x5a, 0x3b, 0xbc, 0x77, 0x58, 0xc7, 0xa5, 0xd5, 0x7b, 0x1d, 0x46, 0x6c, 0xec, 0xd9, 0x5f, 0xf9, 0x55, 0x6f, 0x23, - 0x96, 0x1f, 0x07, 0x47, 0x79, 0xd9, 0x24, 0x45, 0x4b, 0x19, 0x25, 0x61, 0x89, 0x93, 0xae, 0x56, 0x5e, 0x0a, 0x2e, - 0x72, 0x62, 0xe1, 0x14, 0x9e, 0x51, 0x05, 0xc9, 0x29, 0x2e, 0x00, 0x92, 0x08, 0x26, 0xa9, 0xfa, 0x5b, 0x16, 0x9b, - 0x1f, 0xda, 0xf1, 0xe5, 0xc7, 0x61, 0x32, 0x06, 0x2a, 0x0c, 0x93, 0xf1, 0x86, 0x5b, 0x4d, 0x05, 0x7a, 0xd6, 0x4a, - 0xcb, 0xa1, 0x4a, 0xf7, 0x59, 0xf6, 0xf4, 0xee, 0x9d, 0x7e, 0x6d, 0x99, 0x0b, 0xde, 0x69, 0x19, 0x95, 0x28, 0x5f, - 0xb1, 0x5c, 0x23, 0x5f, 0x74, 0xa6, 0x54, 0x84, 0x2a, 0xcb, 0x12, 0xf4, 0x09, 0xb8, 0xeb, 0xea, 0x68, 0x6b, 0x94, - 0xb8, 0x52, 0xba, 0x93, 0x88, 0x2e, 0xd8, 0x50, 0x8b, 0x7a, 0xec, 0xe8, 0xfb, 0xfe, 0x75, 0xb9, 0x35, 0xa4, 0x89, - 0x95, 0x3f, 0x66, 0x18, 0xca, 0x3c, 0x7a, 0x92, 0x70, 0xb7, 0xfb, 0x45, 0xf1, 0xd1, 0xd2, 0x5d, 0x9b, 0x10, 0xb3, - 0xe4, 0x63, 0x3f, 0xa5, 0xf1, 0x3f, 0x91, 0x2f, 0xd8, 0x90, 0x27, 0x5f, 0x0c, 0xe0, 0x4b, 0xf2, 0xfe, 0x24, 0xa5, - 0x23, 0xf2, 0x05, 0xc8, 0xf8, 0x40, 0x5a, 0x1f, 0xc0, 0x08, 0x6b, 0xb7, 0xd3, 0x18, 0x4b, 0x8d, 0xe9, 0x01, 0x0a, - 0x91, 0x02, 0xd7, 0x6d, 0x9d, 0xb8, 0x8e, 0xb2, 0x89, 0xe5, 0xef, 0xae, 0x12, 0xa7, 0x52, 0x09, 0x70, 0x9a, 0x2d, - 0xff, 0x64, 0xd2, 0xf2, 0x9f, 0x2c, 0x1e, 0xfb, 0xa7, 0x93, 0xe6, 0xe3, 0x45, 0x1d, 0xfe, 0xb6, 0xfc, 0x27, 0x71, - 0xbd, 0xe5, 0x3f, 0x81, 0xff, 0xbf, 0x3b, 0xf6, 0x4f, 0x26, 0xf5, 0xa6, 0x7f, 0xba, 0x38, 0xf2, 0x8f, 0x5e, 0x36, - 0x5b, 0xfe, 0x91, 0xd3, 0x74, 0x54, 0x3f, 0x60, 0xd7, 0x8a, 0x3b, 0x7f, 0xb1, 0x76, 0x20, 0xb6, 0x04, 0xd1, 0x54, - 0xa6, 0xa8, 0x8b, 0xbd, 0xe2, 0xd3, 0x88, 0xfa, 0x7c, 0x6a, 0x67, 0xdd, 0xb3, 0x30, 0x85, 0xef, 0xd3, 0x54, 0xcf, - 0x6e, 0xa5, 0x0e, 0x57, 0xf8, 0xc5, 0x96, 0x29, 0xe0, 0x84, 0xbb, 0xd8, 0xbe, 0x30, 0x0f, 0xb7, 0xcd, 0xe5, 0xdb, - 0xbc, 0xcd, 0x4b, 0x0d, 0x77, 0x93, 0xb6, 0x6a, 0x68, 0x5e, 0x9c, 0x28, 0x99, 0x05, 0x93, 0x5f, 0x4e, 0x90, 0x93, - 0x7c, 0x15, 0xe5, 0xeb, 0xf3, 0x43, 0xc2, 0x6a, 0xca, 0xad, 0x77, 0x06, 0xd0, 0xf2, 0x9a, 0x45, 0xc4, 0xe0, 0x2d, - 0x0f, 0x79, 0x6e, 0x40, 0xaf, 0xb8, 0x69, 0x4b, 0x2c, 0x49, 0x7e, 0x41, 0xb3, 0x9e, 0x0b, 0x45, 0x6e, 0xe0, 0x4a, - 0x17, 0x9f, 0x5b, 0x7c, 0xa3, 0xa7, 0x20, 0xec, 0xb2, 0x00, 0xcb, 0xab, 0x52, 0x70, 0x6a, 0x01, 0x3f, 0x2e, 0x3a, - 0x38, 0xd8, 0x79, 0x5e, 0xa4, 0x02, 0x09, 0x6b, 0x2d, 0xbf, 0xed, 0x61, 0xb3, 0x22, 0xd7, 0x46, 0x74, 0x31, 0xae, - 0x44, 0x21, 0xd2, 0x78, 0xba, 0xa6, 0xa1, 0xf0, 0xc3, 0x44, 0xa5, 0xbe, 0x58, 0x0c, 0x0b, 0x37, 0xe9, 0x11, 0xca, - 0xb9, 0x08, 0xad, 0x8f, 0xf7, 0xea, 0x73, 0xce, 0x45, 0x68, 0x6e, 0xc0, 0x26, 0xa2, 0x72, 0xe3, 0x63, 0xd2, 0xea, - 0xbe, 0x79, 0x77, 0xe6, 0xa8, 0xe3, 0xd9, 0x39, 0x9c, 0xb4, 0xba, 0x1d, 0xe9, 0x33, 0x51, 0xf7, 0xe7, 0x88, 0xba, - 0x3f, 0xe7, 0xe8, 0xbb, 0x94, 0x10, 0x49, 0xcb, 0x0f, 0xd5, 0xb2, 0xa5, 0xcd, 0xa0, 0xbc, 0xbd, 0xd3, 0x79, 0x2c, - 0x18, 0xbc, 0x99, 0xfa, 0x50, 0x5e, 0x9e, 0x83, 0x0d, 0x2b, 0xb2, 0xa7, 0xb5, 0x76, 0x78, 0x2d, 0x12, 0xe3, 0x1b, - 0x1e, 0xb1, 0x98, 0x9a, 0x7c, 0x69, 0x3d, 0x54, 0x91, 0xdf, 0xbf, 0xd9, 0x3a, 0x9b, 0x5f, 0x4f, 0x99, 0x70, 0xcd, - 0x2d, 0x84, 0xf7, 0xba, 0x43, 0x47, 0x4e, 0xd5, 0xbd, 0xca, 0xb5, 0xf3, 0xda, 0x7c, 0x85, 0xa7, 0xba, 0xa5, 0x7a, - 0xf5, 0x5a, 0x42, 0xc0, 0xbd, 0xb6, 0xc9, 0x51, 0xb7, 0x70, 0x17, 0xdb, 0x75, 0x79, 0xe7, 0x70, 0x72, 0xd4, 0xbd, - 0x0a, 0x66, 0x7a, 0xbc, 0x97, 0x7c, 0xbc, 0x7d, 0xac, 0x98, 0x8f, 0x7b, 0xf2, 0x02, 0x87, 0xba, 0x5a, 0x6c, 0x94, - 0x5f, 0x1e, 0xbb, 0xdd, 0x8e, 0x56, 0x06, 0x1c, 0x19, 0x0e, 0x77, 0x4f, 0x1a, 0xe6, 0x4e, 0x48, 0xcc, 0xc7, 0x70, - 0x20, 0x55, 0x17, 0x6b, 0x92, 0x8a, 0xc7, 0x7d, 0xd2, 0xec, 0x76, 0x42, 0x47, 0xf2, 0x16, 0xc9, 0x3c, 0xb2, 0xe0, - 0x10, 0x3a, 0x4f, 0xf8, 0x94, 0xfa, 0x8c, 0x1f, 0xde, 0xd0, 0xeb, 0x7a, 0x38, 0x63, 0xa5, 0x7b, 0x1b, 0x94, 0x8e, - 0x62, 0x4a, 0x6e, 0x3c, 0xe2, 0xfa, 0xc6, 0x54, 0xab, 0x74, 0xb7, 0x1d, 0x83, 0xcd, 0x63, 0x5c, 0x73, 0xd2, 0x27, - 0x67, 0x81, 0xc5, 0xbb, 0x9d, 0xc3, 0x70, 0x0d, 0x23, 0x92, 0xdf, 0xe7, 0xda, 0xd1, 0x0e, 0x86, 0x0d, 0xd0, 0x9b, - 0xeb, 0x28, 0x71, 0x60, 0x1c, 0xf2, 0x5a, 0x50, 0xe7, 0x6e, 0xf7, 0x5f, 0xff, 0xc7, 0xff, 0xd2, 0x3e, 0xf6, 0xce, - 0xe1, 0xa4, 0x69, 0xc6, 0x5a, 0xdb, 0x95, 0xbc, 0x03, 0x97, 0x34, 0xcb, 0xa0, 0x30, 0xbd, 0xad, 0x8f, 0x53, 0x16, - 0xd5, 0x27, 0x61, 0x3c, 0x72, 0xbb, 0xbb, 0xb1, 0x69, 0x5f, 0xb6, 0xd2, 0x50, 0x57, 0x8b, 0x80, 0x5e, 0x7f, 0xd3, - 0x75, 0x21, 0x73, 0xeb, 0x44, 0x1e, 0x6d, 0xfb, 0xf2, 0x50, 0x79, 0xfa, 0x2a, 0x17, 0x88, 0x52, 0xfd, 0x65, 0x2f, - 0xcd, 0x01, 0xd3, 0xca, 0xbd, 0xa1, 0xdc, 0x75, 0x8a, 0xa0, 0xd6, 0xff, 0xfd, 0x9f, 0xff, 0xe5, 0xbf, 0x99, 0x47, - 0x88, 0x55, 0xfd, 0xeb, 0x7f, 0xff, 0xcf, 0xff, 0xe7, 0x7f, 0xff, 0x57, 0xb8, 0x6b, 0xa2, 0xe3, 0x59, 0x92, 0xa9, - 0x38, 0x65, 0x30, 0x4b, 0x71, 0x17, 0x07, 0xd2, 0x31, 0xa7, 0x2c, 0x13, 0x6c, 0x58, 0xbd, 0x49, 0x74, 0x21, 0x27, - 0x94, 0x27, 0x53, 0x43, 0x27, 0x4f, 0x78, 0x5e, 0x12, 0x54, 0x05, 0xe5, 0x92, 0x70, 0xf3, 0xce, 0x21, 0xe0, 0xfb, - 0x61, 0x97, 0x2f, 0xfd, 0x62, 0x3b, 0x96, 0x86, 0x4c, 0xa0, 0x24, 0x2f, 0xcb, 0x1d, 0x88, 0xad, 0x2c, 0xe1, 0x31, - 0x68, 0x59, 0xc5, 0x72, 0xf7, 0x2a, 0x7d, 0xda, 0x1f, 0xe6, 0x99, 0x60, 0x23, 0x40, 0xb9, 0xf2, 0x13, 0xcb, 0x30, - 0x76, 0x1d, 0x74, 0xc5, 0xf8, 0x2e, 0x97, 0xa3, 0x28, 0x02, 0x3d, 0x3e, 0xfd, 0x53, 0xfe, 0x97, 0x29, 0x68, 0x64, - 0x8e, 0x37, 0x0d, 0x6f, 0xb5, 0x79, 0xfe, 0xa8, 0xd1, 0x98, 0xdd, 0xa2, 0x65, 0x39, 0x03, 0xde, 0x35, 0x99, 0xa4, - 0x63, 0x7b, 0x40, 0x19, 0xff, 0x2e, 0xdc, 0xd8, 0x0d, 0x07, 0x7c, 0xe1, 0x4e, 0x23, 0xcf, 0xff, 0xbc, 0x94, 0x9e, - 0x54, 0xf6, 0x0b, 0xc4, 0xa9, 0xb5, 0xd3, 0xf9, 0x9a, 0xdb, 0x8b, 0x5b, 0x5a, 0xbd, 0x5a, 0xaa, 0xd7, 0xa4, 0xb9, - 0x79, 0xa7, 0xd0, 0x8e, 0xb3, 0xdb, 0x11, 0xf2, 0x63, 0x88, 0x79, 0x4f, 0x9a, 0x78, 0xd2, 0x5a, 0x16, 0xc3, 0x0b, - 0xc1, 0xa7, 0x76, 0x60, 0x9d, 0x86, 0x74, 0x48, 0x47, 0xc6, 0x59, 0xaf, 0xeb, 0x55, 0xd0, 0x3c, 0x9f, 0x1c, 0x6d, - 0x99, 0x4b, 0x83, 0x24, 0x03, 0xea, 0x4e, 0x23, 0xff, 0x1c, 0x4e, 0xe0, 0x72, 0x14, 0xf3, 0x50, 0x04, 0x92, 0x60, - 0xdb, 0x76, 0x78, 0x3e, 0x04, 0x9e, 0xc4, 0x97, 0x16, 0x3c, 0x6d, 0xd5, 0x14, 0xdc, 0xe6, 0xd5, 0x9b, 0x9f, 0xb9, - 0x2f, 0xbb, 0xdb, 0x43, 0x29, 0xaf, 0xdb, 0x77, 0x3a, 0xea, 0xfd, 0xba, 0xe2, 0xae, 0xd2, 0x02, 0xa9, 0x85, 0xb6, - 0xd7, 0x2b, 0xb9, 0xae, 0x6a, 0x7f, 0x14, 0x9e, 0x2b, 0xc1, 0x74, 0xd7, 0x5b, 0xc9, 0x42, 0x68, 0xf5, 0x9a, 0x7c, - 0x57, 0x98, 0x4c, 0xe1, 0x6c, 0x26, 0x1b, 0xa2, 0x76, 0xe7, 0x50, 0x69, 0xba, 0xc0, 0x3d, 0x64, 0x4a, 0x87, 0xca, - 0xa0, 0xd0, 0x8d, 0xf4, 0x51, 0x50, 0xbf, 0x74, 0x6e, 0x05, 0x7c, 0xf2, 0xad, 0xfb, 0xff, 0x00, 0x1a, 0x47, 0x0e, - 0xb2, 0x83, 0x89, 0x00, 0x00}; + 0xe4, 0x2b, 0x20, 0x44, 0x5b, 0x41, 0x6f, 0x36, 0x21, 0x92, 0x92, 0x6c, 0x19, 0x54, 0x93, 0x5b, 0x96, 0x9d, 0xed, + 0x64, 0xfb, 0x16, 0xcb, 0x4e, 0x76, 0xc2, 0x68, 0x4b, 0x10, 0xd1, 0x24, 0x3a, 0x06, 0xd1, 0x0c, 0xd0, 0xa4, 0xa4, + 0x90, 0x38, 0x35, 0x1f, 0x30, 0x55, 0x53, 0x35, 0x4f, 0xf3, 0x32, 0x35, 0xe7, 0x61, 0x3e, 0x62, 0x9e, 0xcf, 0xa7, + 0x9c, 0x1f, 0x98, 0xf9, 0x84, 0xa9, 0xd5, 0x17, 0xa0, 0xc1, 0x8b, 0xac, 0x5c, 0xce, 0x39, 0x53, 0x2e, 0xdb, 0x44, + 0xa3, 0x2f, 0xab, 0x57, 0xaf, 0x5e, 0xf7, 0x6e, 0x9c, 0xec, 0x44, 0x7c, 0x28, 0xee, 0xa6, 0xd4, 0x89, 0xc5, 0x24, + 0xe9, 0x9d, 0xe8, 0x7f, 0x69, 0x18, 0xf5, 0x4e, 0x12, 0x96, 0x7e, 0x74, 0x32, 0x9a, 0x10, 0x36, 0xe4, 0xa9, 0x13, + 0x67, 0x74, 0x44, 0xa2, 0x50, 0x84, 0x01, 0x9b, 0x84, 0x63, 0xea, 0xec, 0xf7, 0x4e, 0x26, 0x54, 0x84, 0xce, 0x30, + 0x0e, 0xb3, 0x9c, 0x0a, 0xf2, 0xe1, 0xfd, 0x97, 0xcd, 0xe3, 0xde, 0x49, 0x3e, 0xcc, 0xd8, 0x54, 0x38, 0xd0, 0x25, + 0x99, 0xf0, 0x68, 0x96, 0xd0, 0xde, 0xfe, 0xfe, 0xcd, 0xcd, 0x8d, 0xff, 0x53, 0xfe, 0xd9, 0x90, 0xa7, 0xb9, 0x70, + 0x5e, 0x92, 0x1b, 0x96, 0x46, 0xfc, 0x06, 0x33, 0x41, 0x5e, 0xfa, 0xe7, 0x71, 0x18, 0xf1, 0x9b, 0x77, 0x9c, 0x8b, + 0xbd, 0x3d, 0x4f, 0x3d, 0xde, 0x9d, 0x9d, 0x9f, 0x13, 0x42, 0xe6, 0x9c, 0x45, 0x4e, 0x6b, 0xb9, 0xac, 0x0a, 0xfd, + 0x34, 0x14, 0x6c, 0x4e, 0x55, 0x13, 0xb4, 0xb7, 0xe7, 0x86, 0x11, 0x9f, 0x0a, 0x1a, 0x9d, 0x8b, 0xbb, 0x84, 0x9e, + 0xc7, 0x94, 0x8a, 0xdc, 0x65, 0xa9, 0xf3, 0x8c, 0x0f, 0x67, 0x13, 0x9a, 0x0a, 0x7f, 0x9a, 0x71, 0xc1, 0x01, 0x92, + 0xbd, 0x3d, 0x37, 0xa3, 0xd3, 0x24, 0x1c, 0x52, 0x78, 0x7f, 0x76, 0x7e, 0x5e, 0xb5, 0xa8, 0x2a, 0xe1, 0x5c, 0x90, + 0xf3, 0xbb, 0xc9, 0x35, 0x4f, 0x3c, 0x84, 0x43, 0x41, 0x52, 0x7a, 0xe3, 0x7c, 0x47, 0xc3, 0x8f, 0xaf, 0xc2, 0x69, + 0x77, 0x98, 0x84, 0x79, 0xee, 0xdc, 0x88, 0x85, 0x9c, 0x42, 0x36, 0x1b, 0x0a, 0x9e, 0x79, 0x02, 0x53, 0xcc, 0xd0, + 0x82, 0x8d, 0x3c, 0x11, 0xb3, 0xdc, 0xbf, 0xdc, 0x1d, 0xe6, 0xf9, 0x3b, 0x9a, 0xcf, 0x12, 0xb1, 0x4b, 0x76, 0x5a, + 0x98, 0xed, 0x10, 0x92, 0x0b, 0x24, 0xe2, 0x8c, 0xdf, 0x38, 0xcf, 0xb3, 0x8c, 0x67, 0x9e, 0x7b, 0x76, 0x7e, 0xae, + 0x6a, 0x38, 0x2c, 0x77, 0x52, 0x2e, 0x9c, 0xb2, 0xbf, 0xf0, 0x3a, 0xa1, 0xbe, 0xf3, 0x21, 0xa7, 0xce, 0xd5, 0x2c, + 0xcd, 0xc3, 0x11, 0x3d, 0x3b, 0x3f, 0xbf, 0x72, 0x78, 0xe6, 0x5c, 0x0d, 0xf3, 0xfc, 0xca, 0x61, 0x69, 0x2e, 0x68, + 0x18, 0xf9, 0x2e, 0xea, 0xca, 0xc1, 0x86, 0x79, 0xfe, 0x9e, 0xde, 0x0a, 0x22, 0xb0, 0x7c, 0x14, 0x84, 0x16, 0x63, + 0x2a, 0x9c, 0xbc, 0x9c, 0x97, 0x87, 0x16, 0x09, 0x15, 0x8e, 0x20, 0xf2, 0x3d, 0xef, 0x2a, 0xdc, 0x53, 0xf5, 0x28, + 0xba, 0x6c, 0xe4, 0x31, 0xb1, 0xb7, 0x27, 0x4a, 0x3c, 0x23, 0x35, 0x35, 0x87, 0x11, 0xba, 0x63, 0xca, 0xf6, 0xf6, + 0xa8, 0x9f, 0xd0, 0x74, 0x2c, 0x62, 0x42, 0x48, 0xbb, 0xcb, 0xf6, 0xf6, 0x3c, 0x41, 0x42, 0xe1, 0x8f, 0xa9, 0xf0, + 0x28, 0x42, 0xb8, 0x6a, 0xbd, 0xb7, 0xe7, 0x29, 0x24, 0x70, 0xa2, 0x10, 0x57, 0xc3, 0x31, 0xf2, 0x35, 0xf6, 0xcf, + 0xef, 0xd2, 0xa1, 0x67, 0xc3, 0x8f, 0x30, 0xdb, 0xdb, 0x0b, 0x85, 0x9f, 0x43, 0x8f, 0x58, 0x20, 0x54, 0x64, 0x54, + 0xcc, 0xb2, 0xd4, 0x11, 0x85, 0xe0, 0xe7, 0x22, 0x63, 0xe9, 0xd8, 0x43, 0x0b, 0x53, 0x66, 0x35, 0x2c, 0x0a, 0x05, + 0xee, 0x07, 0x41, 0x52, 0xd2, 0x83, 0x11, 0x6f, 0x84, 0x07, 0xab, 0xc8, 0x47, 0x4e, 0x4a, 0x88, 0x9b, 0xcb, 0xb6, + 0x6e, 0x3f, 0x0d, 0xd2, 0x86, 0xeb, 0x62, 0x05, 0x25, 0xce, 0x05, 0xc2, 0x6f, 0x88, 0x97, 0x62, 0xdf, 0xf7, 0x05, + 0x22, 0xbd, 0x85, 0xc1, 0x4a, 0x6a, 0xcd, 0xb3, 0x9f, 0x0e, 0x5a, 0x17, 0x81, 0xf0, 0x33, 0x1a, 0xcd, 0x86, 0xd4, + 0xf3, 0x18, 0xce, 0x71, 0x86, 0x48, 0x8f, 0x35, 0x3c, 0x4e, 0x7a, 0xb0, 0xdc, 0xbc, 0xbe, 0xd6, 0x84, 0xec, 0xb4, + 0x90, 0x86, 0x91, 0x1b, 0x00, 0x01, 0xc3, 0x1a, 0x1e, 0x4e, 0x88, 0x9b, 0xce, 0x26, 0xd7, 0x34, 0x73, 0xcb, 0x6a, + 0xdd, 0x1a, 0x59, 0xcc, 0x72, 0xea, 0x0c, 0xf3, 0xdc, 0x19, 0xcd, 0xd2, 0xa1, 0x60, 0x3c, 0x75, 0xdc, 0x06, 0x6f, + 0xb8, 0x8a, 0x1c, 0x4a, 0x6a, 0x70, 0x51, 0x81, 0xbc, 0x1c, 0x35, 0xd2, 0x41, 0xd6, 0x68, 0x5f, 0x60, 0x80, 0x12, + 0x75, 0x75, 0x7f, 0x1a, 0x01, 0x14, 0xa7, 0x30, 0xc7, 0x02, 0xbf, 0x17, 0x30, 0x4b, 0x39, 0x45, 0x26, 0xfa, 0xa9, + 0xbf, 0xbe, 0x51, 0x88, 0xf0, 0x27, 0xe1, 0xd4, 0xa3, 0xa4, 0x47, 0x25, 0x71, 0x85, 0xe9, 0x10, 0x60, 0xad, 0xad, + 0x5b, 0x9f, 0x06, 0xd4, 0xaf, 0x48, 0x0a, 0x05, 0xc2, 0x1f, 0xf1, 0xec, 0x79, 0x38, 0x8c, 0xa1, 0x5d, 0x49, 0x30, + 0x91, 0xd9, 0x6f, 0xc3, 0x8c, 0x86, 0x82, 0x3e, 0x4f, 0x28, 0x3c, 0x79, 0xae, 0x6c, 0xe9, 0x22, 0x9c, 0x93, 0x97, + 0x7e, 0xc2, 0xc4, 0x6b, 0x9e, 0x0e, 0x69, 0x37, 0xb7, 0xa8, 0x8b, 0xc1, 0xba, 0x9f, 0x0a, 0x91, 0xb1, 0xeb, 0x99, + 0xa0, 0x9e, 0x9b, 0x42, 0x0d, 0x17, 0xe7, 0x08, 0x33, 0x5f, 0xd0, 0x5b, 0x71, 0xc6, 0x53, 0x41, 0x53, 0x41, 0xa8, + 0x41, 0x2a, 0x4e, 0xfd, 0x70, 0x3a, 0xa5, 0x69, 0x74, 0x16, 0xb3, 0x24, 0xf2, 0x18, 0x2a, 0x50, 0x81, 0x63, 0x41, + 0x60, 0x8e, 0xa4, 0x97, 0x06, 0xf0, 0xcf, 0xf6, 0xd9, 0x78, 0x82, 0xf4, 0xe4, 0xa6, 0xa0, 0xc4, 0x75, 0xbb, 0x23, + 0x9e, 0x79, 0x7a, 0x06, 0x0e, 0x1f, 0x39, 0x02, 0xc6, 0x78, 0x37, 0x4b, 0x68, 0x8e, 0x68, 0x83, 0xb0, 0x72, 0x19, + 0x35, 0x82, 0x3f, 0x00, 0xc5, 0x17, 0xc8, 0x4b, 0x51, 0x90, 0x76, 0xe7, 0x61, 0xe6, 0x7c, 0xa7, 0x77, 0xd4, 0x33, + 0xc3, 0xcd, 0x86, 0x82, 0x3c, 0xf3, 0x45, 0x36, 0xcb, 0x05, 0x8d, 0xde, 0xdf, 0x4d, 0x69, 0x8e, 0x5f, 0x0b, 0x32, + 0x14, 0xfd, 0xa1, 0xf0, 0xe9, 0x64, 0x2a, 0xee, 0xce, 0x25, 0x63, 0x0c, 0x5c, 0x17, 0x47, 0x50, 0x33, 0xa3, 0xe1, + 0x10, 0x98, 0x99, 0xc6, 0xd6, 0x5b, 0x9e, 0xdc, 0x8d, 0x58, 0x92, 0x9c, 0xcf, 0xa6, 0x53, 0x9e, 0x09, 0xfc, 0x77, + 0xb2, 0x10, 0xbc, 0x42, 0x0d, 0xac, 0xe5, 0x22, 0xbf, 0x61, 0x62, 0x18, 0x7b, 0x02, 0x2d, 0x86, 0x61, 0x4e, 0x9d, + 0xa7, 0x9c, 0x27, 0x34, 0x84, 0x49, 0xa7, 0xfd, 0xd7, 0x22, 0x48, 0x67, 0x49, 0xd2, 0xbd, 0xce, 0x68, 0xf8, 0xb1, + 0x2b, 0x5f, 0xbf, 0xb9, 0xfe, 0x89, 0x0e, 0x45, 0x20, 0x7f, 0x9f, 0x66, 0x59, 0x78, 0x07, 0x15, 0x09, 0x81, 0x6a, + 0xfd, 0x34, 0xf8, 0xfa, 0xfc, 0xcd, 0x6b, 0x5f, 0x6d, 0x12, 0x36, 0xba, 0xf3, 0xd2, 0x72, 0xe3, 0xa5, 0x05, 0x1e, + 0x65, 0x7c, 0xb2, 0x32, 0xb4, 0xc2, 0x5a, 0xda, 0xdd, 0x02, 0x02, 0x25, 0xe9, 0x8e, 0xea, 0xda, 0x86, 0xe0, 0xb5, + 0xa4, 0x79, 0x78, 0x49, 0xcc, 0xb8, 0xb3, 0x24, 0x09, 0x54, 0xb1, 0x97, 0xa2, 0xfb, 0xa1, 0x15, 0xd9, 0xdd, 0x82, + 0x12, 0x09, 0xe7, 0x14, 0x24, 0x0c, 0xc0, 0x38, 0x0c, 0xc5, 0x30, 0x5e, 0x50, 0xd9, 0x59, 0x61, 0x20, 0xa6, 0x45, + 0x81, 0x6f, 0x4b, 0x7a, 0x17, 0x00, 0x88, 0x64, 0x54, 0x44, 0x2c, 0x97, 0x30, 0x61, 0x84, 0x7f, 0x20, 0x8b, 0xd0, + 0xcc, 0x27, 0xd8, 0x69, 0x61, 0xd8, 0x97, 0x81, 0xe2, 0x2e, 0x78, 0xc8, 0xd3, 0x39, 0xcd, 0x04, 0xcd, 0x82, 0xbf, + 0xe3, 0x8c, 0x8e, 0x12, 0x80, 0x62, 0xa7, 0x8d, 0xe3, 0x30, 0x3f, 0x8b, 0xc3, 0x74, 0x4c, 0xa3, 0xe0, 0x56, 0x14, + 0x58, 0x08, 0xe2, 0x8e, 0x58, 0x1a, 0x26, 0xec, 0x17, 0x1a, 0xb9, 0x5a, 0x1c, 0x3c, 0x77, 0xe8, 0xad, 0xa0, 0x69, + 0x94, 0x3b, 0x2f, 0xde, 0xbf, 0x7a, 0xa9, 0x17, 0xb2, 0x26, 0x21, 0xd0, 0x22, 0x9f, 0x4d, 0x69, 0xe6, 0x21, 0xac, + 0x25, 0xc4, 0x73, 0x26, 0xb9, 0xe3, 0xab, 0x70, 0xaa, 0x4a, 0x58, 0xfe, 0x61, 0x1a, 0x85, 0x82, 0xbe, 0xa5, 0x69, + 0xc4, 0xd2, 0x31, 0xd9, 0x69, 0xab, 0xf2, 0x38, 0xd4, 0x2f, 0xa2, 0xb2, 0xe8, 0x72, 0xf7, 0x79, 0x22, 0x27, 0x5e, + 0x3e, 0xce, 0x3c, 0x54, 0xe4, 0x22, 0x14, 0x6c, 0xe8, 0x84, 0x51, 0xf4, 0x55, 0xca, 0x04, 0x93, 0x00, 0x66, 0xb0, + 0x3e, 0x40, 0xa3, 0x54, 0xc9, 0x0a, 0x03, 0xb8, 0x87, 0xb0, 0xe7, 0x69, 0x09, 0x10, 0x23, 0xbd, 0x60, 0x7b, 0x7b, + 0x15, 0xbf, 0xef, 0xd3, 0x40, 0xbd, 0x24, 0x83, 0x0b, 0xe4, 0x4f, 0x67, 0x39, 0xac, 0xb4, 0x19, 0x02, 0xc4, 0x0b, + 0xbf, 0xce, 0x69, 0x36, 0xa7, 0x51, 0x49, 0x1d, 0xb9, 0x87, 0x16, 0x2b, 0x63, 0xe8, 0x7d, 0x21, 0xc8, 0xe0, 0xa2, + 0x6b, 0x33, 0x6e, 0xaa, 0x09, 0x3d, 0xe3, 0x53, 0x9a, 0x09, 0x46, 0xf3, 0x92, 0x97, 0x78, 0x20, 0x46, 0x4b, 0x7e, + 0x92, 0x13, 0x33, 0xbf, 0xa9, 0xc7, 0x30, 0x45, 0x35, 0x8e, 0x61, 0x24, 0xed, 0xf3, 0xb9, 0x14, 0x19, 0x39, 0x66, + 0x08, 0x0b, 0x05, 0x69, 0x8e, 0x50, 0x81, 0xb0, 0x30, 0xe0, 0x2a, 0x5e, 0xa4, 0x47, 0xbb, 0x03, 0x59, 0x4d, 0x7e, + 0x90, 0xb2, 0x1a, 0x38, 0x5a, 0x28, 0xe8, 0xde, 0x9e, 0x47, 0xfd, 0x92, 0x2a, 0xc8, 0x4e, 0x5b, 0xaf, 0x91, 0x85, + 0xac, 0x2d, 0x60, 0xc3, 0xc0, 0x02, 0x53, 0x84, 0x77, 0xa8, 0x9f, 0xf2, 0xd3, 0xe1, 0x90, 0xe6, 0x39, 0xcf, 0xf6, + 0xf6, 0x76, 0x64, 0xfd, 0x52, 0x9d, 0x80, 0x35, 0x7c, 0x73, 0x93, 0x56, 0x10, 0xa0, 0x4a, 0xc4, 0x6a, 0xc1, 0x20, + 0x40, 0x50, 0x49, 0x8d, 0xc3, 0xed, 0x1b, 0xcd, 0x23, 0x70, 0x2f, 0x2f, 0xdd, 0x86, 0xc0, 0x1a, 0x0d, 0x63, 0x6a, + 0x86, 0xbe, 0x7b, 0x46, 0x95, 0x6e, 0x25, 0x35, 0x8f, 0x35, 0xcc, 0xa8, 0x0d, 0xe4, 0x47, 0x74, 0xc4, 0x52, 0x6b, + 0xda, 0x35, 0x90, 0xb0, 0xc0, 0x39, 0x2a, 0xac, 0x05, 0xdd, 0xd8, 0xb5, 0x54, 0x6a, 0xd4, 0xca, 0x2d, 0xc6, 0x52, + 0x91, 0xb0, 0x96, 0x71, 0x40, 0x2f, 0x0a, 0x2c, 0x51, 0x6f, 0x66, 0x93, 0x49, 0x40, 0x07, 0xe2, 0xa2, 0xab, 0xdf, + 0x93, 0x5c, 0x61, 0x2e, 0xa3, 0x3f, 0xcf, 0x68, 0x2e, 0x14, 0x1d, 0x7b, 0x02, 0x67, 0x98, 0xa1, 0x02, 0xf6, 0xdb, + 0x88, 0x8d, 0x67, 0x19, 0xe8, 0x3b, 0xb0, 0x17, 0x69, 0x3a, 0x9b, 0x50, 0xf3, 0xb4, 0x09, 0xb6, 0x37, 0x53, 0x90, + 0x88, 0x39, 0xd0, 0xf4, 0xfd, 0xe4, 0x04, 0xb0, 0x0a, 0xb4, 0x5c, 0xfe, 0x60, 0x3a, 0xa9, 0x96, 0xb2, 0xd4, 0xd1, + 0x56, 0xd7, 0x44, 0x20, 0x2d, 0x91, 0x77, 0xda, 0x0a, 0x7c, 0x21, 0x2e, 0xc8, 0x4e, 0xab, 0xa4, 0x61, 0x8d, 0x55, + 0x05, 0x8e, 0x42, 0xe2, 0x1b, 0xd5, 0x15, 0x92, 0x02, 0xbe, 0x46, 0x2e, 0x7e, 0xbc, 0x46, 0xa9, 0x31, 0x19, 0x80, + 0xaa, 0xe1, 0xc7, 0x17, 0xdb, 0xc8, 0xc9, 0xf0, 0x03, 0x4f, 0xac, 0xbf, 0xab, 0xd8, 0xc6, 0xbc, 0xce, 0x36, 0x56, + 0xa6, 0xe1, 0x4e, 0xcb, 0x26, 0x6e, 0x49, 0x65, 0x7a, 0xa3, 0x57, 0xaf, 0x30, 0x93, 0xc0, 0x54, 0x53, 0xb2, 0xba, + 0x78, 0x1d, 0x4e, 0x68, 0xee, 0x51, 0x84, 0xb7, 0x55, 0x50, 0xe4, 0x09, 0x55, 0x2e, 0x2c, 0xc9, 0x99, 0x83, 0xe4, + 0x64, 0x48, 0x29, 0x66, 0xf5, 0x0d, 0x97, 0x63, 0x3a, 0xc8, 0x2f, 0x2a, 0x7d, 0xce, 0x9a, 0xbc, 0x14, 0xc9, 0x9a, + 0xbe, 0x0d, 0xfe, 0x54, 0x99, 0x42, 0x9a, 0xd4, 0x1b, 0x72, 0x84, 0x77, 0x5a, 0xab, 0x2b, 0x69, 0x6a, 0x55, 0x73, + 0x1c, 0x5c, 0xc0, 0x3a, 0x48, 0x89, 0xe1, 0xb3, 0x5c, 0xfe, 0x5f, 0xdb, 0x69, 0x80, 0xb6, 0x73, 0x20, 0x0c, 0x7f, + 0x94, 0x84, 0xc2, 0x6b, 0xef, 0xb7, 0x40, 0x19, 0x9d, 0x53, 0x10, 0x28, 0x08, 0xad, 0x4f, 0x85, 0xfa, 0xb3, 0x34, + 0x8f, 0xd9, 0x48, 0x78, 0xb1, 0x90, 0x2c, 0x85, 0x26, 0x39, 0x75, 0x44, 0x4d, 0x25, 0x96, 0xec, 0x26, 0x06, 0x62, + 0x2b, 0xf5, 0x2f, 0x6a, 0x20, 0x95, 0x6c, 0x0b, 0xb8, 0x43, 0xa5, 0x4e, 0x57, 0x5c, 0xc6, 0xd4, 0x66, 0xa0, 0x32, + 0xb6, 0xfb, 0xaa, 0xc7, 0x40, 0x33, 0x03, 0x66, 0x69, 0xad, 0x2c, 0xb0, 0x39, 0x84, 0x2e, 0x14, 0xbe, 0xe0, 0x2f, + 0xf9, 0x0d, 0xcd, 0xce, 0x42, 0x00, 0x3e, 0x50, 0xcd, 0x0b, 0x25, 0x08, 0x24, 0xbf, 0x17, 0x5d, 0x43, 0x2f, 0x97, + 0x72, 0xe2, 0x6f, 0x33, 0x3e, 0x61, 0x39, 0x05, 0x65, 0x4d, 0xe1, 0x3f, 0x85, 0x7d, 0x26, 0x37, 0x24, 0x08, 0x1b, + 0x5a, 0xd2, 0xd7, 0xe9, 0xcb, 0x3a, 0x7d, 0x5d, 0xee, 0x3e, 0x1f, 0x1b, 0x06, 0x58, 0xdf, 0xc6, 0x08, 0x7b, 0xda, + 0xa4, 0xb0, 0xe4, 0x9c, 0x1f, 0x23, 0x2d, 0xe1, 0x97, 0x4b, 0x61, 0x59, 0x6e, 0x35, 0x75, 0x91, 0xaa, 0x6d, 0x83, + 0x8a, 0x30, 0x8a, 0x40, 0xb1, 0xcb, 0x78, 0x92, 0x58, 0xa2, 0x0a, 0xb3, 0x6e, 0x29, 0x9c, 0x2e, 0x77, 0x9f, 0x9f, + 0xdf, 0x27, 0x9f, 0xe0, 0xbd, 0x2d, 0xa2, 0x0c, 0xa0, 0x69, 0x44, 0x33, 0xb0, 0x24, 0xad, 0xd5, 0xd2, 0x52, 0xf6, + 0x8c, 0xa7, 0x29, 0x1d, 0x0a, 0x1a, 0x81, 0xa1, 0xc2, 0x88, 0xf0, 0x63, 0x9e, 0x8b, 0xb2, 0xb0, 0x82, 0x9e, 0x59, + 0xd0, 0x33, 0x7f, 0x18, 0x26, 0x89, 0xa7, 0x8c, 0x92, 0x09, 0x9f, 0xd3, 0x0d, 0x50, 0x77, 0x6b, 0x20, 0x97, 0xdd, + 0x50, 0xab, 0x1b, 0xea, 0xe7, 0xd3, 0x84, 0x0d, 0x69, 0x29, 0xba, 0xce, 0x7d, 0x96, 0x46, 0xf4, 0x16, 0xf8, 0x08, + 0xea, 0xf5, 0x7a, 0x2d, 0xdc, 0x46, 0x85, 0x42, 0xf8, 0x62, 0x0d, 0xb1, 0xf7, 0x08, 0x4d, 0x20, 0x32, 0xd2, 0x5b, + 0x6c, 0xe2, 0x07, 0x14, 0x59, 0x92, 0x92, 0x19, 0xe3, 0x4a, 0x71, 0x67, 0x84, 0x23, 0x9a, 0x50, 0x41, 0x0d, 0x37, + 0x07, 0x15, 0x5a, 0x6d, 0xdd, 0x77, 0x25, 0xfe, 0x4a, 0x72, 0x32, 0xbb, 0xcc, 0xac, 0x79, 0x5e, 0x1a, 0xeb, 0xd5, + 0xf2, 0x54, 0xd8, 0xee, 0x0b, 0xb5, 0x3c, 0xa1, 0x10, 0xe1, 0x30, 0x56, 0x56, 0xba, 0xb7, 0x36, 0xa5, 0xaa, 0x0f, + 0xcd, 0xd9, 0xcb, 0x4d, 0xf4, 0xde, 0x80, 0xb9, 0x09, 0x05, 0xe7, 0x9a, 0x29, 0x50, 0x30, 0xfc, 0xd4, 0xb2, 0x9d, + 0x85, 0x49, 0x72, 0x1d, 0x0e, 0x3f, 0xd6, 0xa9, 0xbf, 0x22, 0x03, 0xb2, 0xca, 0x8d, 0xad, 0x57, 0x16, 0xcb, 0xb2, + 0xe7, 0x6d, 0xb8, 0x74, 0x6d, 0xa3, 0x78, 0x3b, 0xad, 0x8a, 0xec, 0xeb, 0x0b, 0xbd, 0x95, 0xda, 0x25, 0x44, 0x4c, + 0xcf, 0xcc, 0x03, 0x2e, 0xf0, 0x49, 0x8a, 0x33, 0xfc, 0x40, 0xd3, 0x1d, 0x98, 0x1b, 0xc5, 0x0a, 0x20, 0x02, 0x2d, + 0x8a, 0x88, 0xe5, 0xdb, 0x31, 0xf0, 0x87, 0x40, 0xf9, 0xcc, 0x1a, 0xe1, 0xa1, 0x80, 0x96, 0x3c, 0x4e, 0x6b, 0xcd, + 0x25, 0x64, 0x5a, 0x9f, 0x30, 0x8c, 0xe6, 0x6f, 0xa0, 0xbb, 0x48, 0x7a, 0x7f, 0xa3, 0x5e, 0x81, 0x56, 0x06, 0x50, + 0xe4, 0x5d, 0x5b, 0x9d, 0xa8, 0x51, 0x80, 0xe6, 0xa9, 0x4c, 0x8a, 0xdc, 0xac, 0x66, 0x3f, 0x6a, 0x8d, 0x5d, 0x99, + 0xe0, 0x9a, 0xe5, 0x72, 0xe2, 0x79, 0x5e, 0x0e, 0x26, 0x9c, 0x51, 0xed, 0xab, 0x49, 0xe4, 0x6b, 0x93, 0xc8, 0x7d, + 0xcb, 0xce, 0x42, 0x15, 0x2d, 0x5b, 0xcd, 0x83, 0xbf, 0x23, 0xbb, 0x12, 0xa8, 0xab, 0x3e, 0xf0, 0x67, 0x54, 0xb2, + 0xdb, 0x84, 0x08, 0xcc, 0xb5, 0x8d, 0xa3, 0x29, 0x0d, 0x18, 0x46, 0xd5, 0x24, 0x43, 0x6a, 0x6b, 0xd4, 0xec, 0xdd, + 0x0c, 0x73, 0xb4, 0xa2, 0xdb, 0x17, 0x85, 0xc6, 0x11, 0x45, 0x7a, 0x6d, 0x6a, 0x4a, 0xb1, 0x85, 0x15, 0x9c, 0x11, + 0xad, 0x08, 0x2b, 0xbd, 0x67, 0x15, 0x37, 0x65, 0xbf, 0x3b, 0x84, 0x64, 0x15, 0x6a, 0x6a, 0x1a, 0xa5, 0x51, 0xad, + 0x32, 0x84, 0x63, 0xa3, 0x93, 0xf2, 0x6a, 0xde, 0x84, 0xb8, 0xc6, 0x21, 0xe1, 0xf6, 0x17, 0x35, 0xab, 0x30, 0xb0, + 0xaa, 0x15, 0x01, 0xb0, 0x54, 0xbe, 0x09, 0xdd, 0x9b, 0x68, 0xa6, 0xd6, 0x8f, 0x85, 0x70, 0x6e, 0x23, 0xdc, 0xc2, + 0x6c, 0xa6, 0x38, 0x57, 0x76, 0x41, 0xe2, 0x7a, 0x5b, 0x8f, 0x62, 0xae, 0xd6, 0x61, 0x0d, 0x89, 0xab, 0xaa, 0xa7, + 0x24, 0x41, 0xb0, 0x61, 0x73, 0x50, 0xee, 0x6c, 0xf9, 0xe0, 0x01, 0xec, 0x6c, 0xb9, 0x5c, 0x23, 0xba, 0x8d, 0x1a, + 0x28, 0xf2, 0x2b, 0xbb, 0x70, 0xb9, 0xbc, 0x15, 0xc8, 0xd3, 0xba, 0x2f, 0xa6, 0xa8, 0x6f, 0x38, 0xee, 0xe9, 0x4b, + 0xa8, 0x25, 0x55, 0xd1, 0xaa, 0xa4, 0x34, 0x1a, 0xea, 0x34, 0x5b, 0x5f, 0x27, 0x61, 0xb1, 0xed, 0xb3, 0x35, 0xee, + 0x25, 0x0b, 0xb5, 0x98, 0xae, 0xa6, 0x7c, 0xa6, 0xbb, 0x66, 0x08, 0xa1, 0x20, 0x97, 0x76, 0xcc, 0xce, 0x26, 0xd3, + 0x72, 0x6f, 0x2f, 0xb7, 0x3a, 0xba, 0x2c, 0xd9, 0xc4, 0x4f, 0x1e, 0x88, 0xe4, 0xfc, 0x2e, 0x95, 0xba, 0xcb, 0x4f, + 0x46, 0x08, 0xad, 0x19, 0xa6, 0xad, 0x2e, 0x18, 0xe4, 0xe1, 0x4d, 0xc8, 0x84, 0x53, 0xf6, 0xa2, 0x0c, 0x72, 0x8f, + 0xa2, 0x85, 0x56, 0x35, 0xfc, 0x8c, 0x82, 0xf2, 0x08, 0x3c, 0xc1, 0xa8, 0xd0, 0x8a, 0xee, 0x87, 0x31, 0x05, 0x5f, + 0xb0, 0xd1, 0x22, 0x4a, 0xcb, 0x70, 0x47, 0x4b, 0x11, 0xdd, 0xf1, 0x66, 0xd8, 0x8b, 0xd5, 0xe6, 0x35, 0x4b, 0x60, + 0x4a, 0xb3, 0x11, 0xcf, 0x26, 0xe6, 0x5d, 0xb1, 0xf2, 0xac, 0x39, 0x23, 0x1b, 0x79, 0x1b, 0xfb, 0xd6, 0xfa, 0x7f, + 0x77, 0xc5, 0xec, 0xae, 0x0c, 0xf6, 0x9a, 0x28, 0x2d, 0xa5, 0xaf, 0x72, 0x09, 0x1a, 0xca, 0xcc, 0x6d, 0x03, 0x5f, + 0xfb, 0x53, 0xbb, 0xca, 0x67, 0xb2, 0xd3, 0xee, 0x96, 0x56, 0x9f, 0xa1, 0x86, 0xae, 0xf2, 0x6d, 0x68, 0x91, 0xca, + 0x67, 0x49, 0xa4, 0x81, 0x65, 0x08, 0x53, 0x4d, 0x47, 0x37, 0x2c, 0x49, 0xaa, 0xd2, 0x5f, 0xc3, 0xd7, 0x73, 0xcd, + 0xd7, 0x33, 0xc3, 0xd7, 0x81, 0x53, 0x00, 0x5f, 0x57, 0xdd, 0x55, 0xcd, 0xb3, 0xb5, 0xdd, 0x99, 0x29, 0x8e, 0x9e, + 0x4b, 0x4b, 0x1a, 0xc6, 0x9b, 0x19, 0x08, 0x50, 0xa9, 0x79, 0x7d, 0xf4, 0xb4, 0x1f, 0x06, 0x4c, 0x40, 0xe5, 0xc5, + 0xa4, 0xb6, 0x93, 0xe2, 0xa3, 0x87, 0x70, 0x5e, 0xd0, 0x92, 0xb2, 0x4f, 0x9f, 0x83, 0x9f, 0xce, 0x9a, 0x0e, 0x08, + 0x31, 0x59, 0xfc, 0xab, 0x94, 0x28, 0x33, 0x3b, 0xa6, 0x67, 0x97, 0x9b, 0xd9, 0x01, 0xa7, 0xaf, 0x66, 0x17, 0xdd, + 0xcf, 0xeb, 0xe5, 0xf4, 0x58, 0x39, 0xbd, 0x6a, 0xbd, 0x97, 0x4b, 0x6f, 0xa5, 0x04, 0x5c, 0xf8, 0xda, 0x44, 0xc9, + 0xca, 0xde, 0x81, 0x07, 0xd8, 0x98, 0x81, 0x82, 0x42, 0x4d, 0xba, 0x14, 0x71, 0x2f, 0x3f, 0xe5, 0xe2, 0x91, 0x9e, + 0x7a, 0xd5, 0xfe, 0x8c, 0x4f, 0xa6, 0xa0, 0x8d, 0xad, 0x90, 0xf4, 0x98, 0xea, 0x01, 0xab, 0xf7, 0xc5, 0x86, 0xb2, + 0x5a, 0x1b, 0xb9, 0x1f, 0x6b, 0xd4, 0x54, 0x5a, 0xcc, 0x3b, 0xad, 0x62, 0x56, 0x16, 0x95, 0x8c, 0x63, 0x93, 0x5b, + 0xe5, 0x6c, 0xd5, 0x29, 0x63, 0x5e, 0xbc, 0xf1, 0x98, 0xe2, 0xc3, 0x0c, 0x78, 0x9d, 0xc5, 0x7e, 0x0c, 0xb9, 0xdb, + 0xeb, 0x5f, 0x54, 0xc8, 0x59, 0x14, 0x2b, 0xe8, 0x5b, 0x14, 0xc5, 0x73, 0x6d, 0x65, 0xe3, 0xe7, 0xdb, 0xcd, 0xe1, + 0xea, 0x9d, 0xb6, 0x16, 0x07, 0x17, 0xf8, 0xf9, 0xba, 0xee, 0x48, 0x16, 0x13, 0x1e, 0xd1, 0xc0, 0xe5, 0x53, 0x9a, + 0xba, 0x05, 0x78, 0x56, 0xf5, 0xe2, 0x47, 0xc2, 0x5b, 0xbc, 0xab, 0xbb, 0x58, 0x83, 0xe7, 0x05, 0x38, 0xc0, 0xbe, + 0x5b, 0x77, 0xbe, 0x7e, 0x4b, 0xb3, 0x5c, 0x6a, 0xa2, 0xa5, 0x52, 0xfb, 0x5d, 0x25, 0x97, 0xbe, 0x0b, 0xb6, 0xd6, + 0xaf, 0x6c, 0x10, 0xb7, 0xed, 0x3f, 0xf2, 0x0f, 0x5c, 0x24, 0x5d, 0xc3, 0x5f, 0xeb, 0x1d, 0xff, 0x93, 0x71, 0x0d, + 0x9f, 0x93, 0x9f, 0xea, 0x9e, 0xe1, 0x99, 0x20, 0xe7, 0xfd, 0x73, 0x63, 0x32, 0xf3, 0x84, 0x0d, 0xef, 0x3c, 0x37, + 0x61, 0xa2, 0x09, 0xe1, 0x37, 0x17, 0x2f, 0xd4, 0x0b, 0xf0, 0x2a, 0x4a, 0x97, 0x76, 0x61, 0x8c, 0x3d, 0x4c, 0x05, + 0x71, 0x77, 0x13, 0x26, 0x76, 0x5d, 0x3c, 0x21, 0x57, 0xf0, 0x63, 0x77, 0xe1, 0xbd, 0x0a, 0x45, 0xec, 0x67, 0x61, + 0x1a, 0xf1, 0x89, 0x87, 0x1a, 0xae, 0x8b, 0xfc, 0x5c, 0x1a, 0x1c, 0x4f, 0x50, 0xb1, 0x7b, 0x85, 0x4f, 0x05, 0x71, + 0xfb, 0x6e, 0x63, 0x82, 0xdf, 0x09, 0x72, 0x75, 0xb2, 0xbb, 0x38, 0x15, 0x45, 0xef, 0x0a, 0xdf, 0x96, 0x5e, 0x7b, + 0xfc, 0x81, 0x78, 0x88, 0xf4, 0x6e, 0x35, 0x34, 0x67, 0x7c, 0xa2, 0xbc, 0xf7, 0x2e, 0xc2, 0xef, 0x65, 0x6c, 0xa5, + 0x62, 0x37, 0x3a, 0xbc, 0xb2, 0x43, 0x5c, 0x2e, 0x7d, 0x04, 0xee, 0xde, 0x9e, 0x55, 0x56, 0xea, 0x0a, 0xf8, 0xb9, + 0x20, 0x35, 0x8b, 0x1c, 0xbf, 0x90, 0x51, 0x9a, 0xe7, 0xc2, 0x4b, 0x91, 0xe9, 0xc6, 0x33, 0xbe, 0x68, 0xbd, 0x37, + 0xd3, 0x81, 0x72, 0x31, 0xf8, 0x4c, 0xd0, 0x2c, 0x14, 0x3c, 0xbb, 0x40, 0xb6, 0xfe, 0x81, 0xff, 0x46, 0xae, 0x06, + 0xce, 0x7f, 0xfa, 0xec, 0xc7, 0xd1, 0x8f, 0xd9, 0xc5, 0x15, 0x7e, 0x4b, 0xf6, 0x4f, 0xbc, 0x7e, 0xe0, 0xed, 0x34, + 0x9b, 0xcb, 0x1f, 0xf7, 0x07, 0xff, 0x08, 0x9b, 0xbf, 0x9c, 0x36, 0x7f, 0xb8, 0x40, 0x4b, 0xef, 0xc7, 0xfd, 0xfe, + 0x40, 0x3f, 0x0d, 0xfe, 0xd1, 0xfb, 0x31, 0xbf, 0xf8, 0xb3, 0x2a, 0xdc, 0x45, 0x68, 0x7f, 0x8c, 0xa7, 0x82, 0xec, + 0x37, 0x9b, 0xbd, 0xfd, 0x31, 0x1e, 0x0b, 0xb2, 0x0f, 0xff, 0x5f, 0x93, 0x77, 0x74, 0xfc, 0xfc, 0x76, 0xea, 0x5d, + 0xf5, 0x96, 0xbb, 0x8b, 0xbf, 0x15, 0xd0, 0xeb, 0xe0, 0x1f, 0x3f, 0xfe, 0x98, 0xbb, 0x5f, 0xf4, 0xc8, 0xfe, 0x45, + 0x03, 0x79, 0x50, 0xfa, 0x67, 0x22, 0xff, 0xf5, 0xfa, 0xc1, 0xe0, 0x1f, 0x1a, 0x0a, 0xf7, 0x8b, 0x1f, 0xaf, 0x4e, + 0x7a, 0xe4, 0x62, 0xe9, 0xb9, 0xcb, 0x2f, 0xd0, 0x12, 0xa1, 0xe5, 0x2e, 0xba, 0xc2, 0xee, 0xd8, 0x45, 0x78, 0x2e, + 0xc8, 0xfe, 0x17, 0xfb, 0x63, 0x3c, 0x12, 0x64, 0xdf, 0xdd, 0x1f, 0xe3, 0x73, 0x41, 0xf6, 0xff, 0xe1, 0xf5, 0x03, + 0xe5, 0x64, 0x5b, 0x4a, 0xff, 0xc6, 0x12, 0x02, 0x1c, 0x61, 0x46, 0xc3, 0xa5, 0x60, 0x22, 0xa1, 0x68, 0x77, 0x9f, + 0xe1, 0x33, 0x89, 0x26, 0x4f, 0x80, 0x17, 0x06, 0x8c, 0x3b, 0x6f, 0x71, 0x09, 0x8b, 0x0d, 0x34, 0xb3, 0x1b, 0x40, + 0x64, 0x07, 0x1c, 0x01, 0x79, 0x20, 0xf0, 0x3c, 0x4c, 0x66, 0x34, 0x0f, 0x68, 0x81, 0xf0, 0x90, 0x9c, 0x09, 0xaf, + 0x8d, 0xf0, 0x53, 0x01, 0x3f, 0x3a, 0x08, 0x9f, 0xe9, 0x20, 0x26, 0xec, 0x64, 0x45, 0x54, 0x29, 0x57, 0x2a, 0x8b, + 0x8b, 0xf0, 0x74, 0xc3, 0x4b, 0x11, 0x83, 0x7b, 0x01, 0xe1, 0xdd, 0x5a, 0xc8, 0x13, 0xdf, 0x10, 0x43, 0x12, 0xef, + 0x33, 0x4a, 0xbf, 0x0b, 0x93, 0x8f, 0x34, 0xf3, 0x6e, 0x71, 0xbb, 0xf3, 0x04, 0x4b, 0x2f, 0xf4, 0x4e, 0x1b, 0x75, + 0xcb, 0x78, 0xd5, 0x47, 0xa1, 0xe2, 0x04, 0x20, 0x65, 0xeb, 0xce, 0x18, 0x58, 0xf1, 0x9d, 0x74, 0xcd, 0x63, 0x95, + 0x85, 0x37, 0x2e, 0xaa, 0xc7, 0x46, 0x59, 0x3a, 0x0f, 0x13, 0x16, 0x39, 0x82, 0x4e, 0xa6, 0x49, 0x28, 0xa8, 0xa3, + 0xe7, 0xeb, 0x84, 0xd0, 0x91, 0x5b, 0xea, 0x0c, 0x33, 0xcb, 0xe2, 0x9c, 0x99, 0xa0, 0x13, 0xec, 0x15, 0x0f, 0x22, + 0x54, 0x5a, 0xef, 0x78, 0x55, 0x05, 0xc0, 0x56, 0x63, 0x7c, 0xcd, 0x36, 0x78, 0xc2, 0x2e, 0xa4, 0x7c, 0xce, 0x71, + 0x46, 0x40, 0x8a, 0x76, 0xfa, 0xee, 0x49, 0x3e, 0x1f, 0xf7, 0x5c, 0x88, 0xcf, 0x70, 0xf2, 0x56, 0x3a, 0x86, 0xa0, + 0x42, 0x4c, 0x5a, 0xdd, 0xf8, 0x84, 0x76, 0xe3, 0x46, 0xc3, 0x28, 0xd1, 0x09, 0x49, 0x07, 0xb1, 0x6a, 0x1e, 0xe2, + 0x08, 0xcf, 0x48, 0xb3, 0x8d, 0xc7, 0xa4, 0x25, 0x9b, 0x74, 0xc7, 0x27, 0x89, 0x1e, 0x66, 0x6f, 0xcf, 0xe3, 0x7e, + 0x12, 0xe6, 0xe2, 0x2b, 0xb0, 0xf6, 0xc9, 0x18, 0x47, 0x84, 0xfb, 0xf4, 0x96, 0x0e, 0xbd, 0x04, 0xe1, 0x48, 0x73, + 0x1a, 0xd4, 0x45, 0x63, 0x62, 0x55, 0x03, 0x2b, 0x82, 0xbc, 0xed, 0x47, 0x83, 0xf6, 0x05, 0x21, 0xc4, 0xdd, 0x69, + 0x36, 0xdd, 0x3e, 0x27, 0x53, 0x11, 0x40, 0x89, 0xa5, 0x2b, 0x93, 0x31, 0x14, 0x75, 0xac, 0x22, 0xef, 0x5c, 0xf8, + 0x82, 0xe6, 0xc2, 0x83, 0x62, 0xb0, 0xff, 0x73, 0x43, 0xd8, 0xee, 0xc9, 0xbe, 0xdb, 0x80, 0x52, 0x49, 0x9c, 0x08, + 0x73, 0x72, 0x8d, 0x82, 0x68, 0x70, 0x70, 0x61, 0x0b, 0x00, 0x59, 0x08, 0x83, 0x5f, 0xf7, 0xa3, 0x41, 0x4b, 0x0e, + 0xde, 0x73, 0xfb, 0x1e, 0x27, 0xb9, 0xd2, 0xd0, 0xfa, 0x79, 0xf0, 0x56, 0x4e, 0x15, 0x05, 0x1a, 0x38, 0xb3, 0x02, + 0xa4, 0xd9, 0x09, 0xbc, 0x99, 0x3d, 0x89, 0x26, 0x0c, 0xa6, 0xb1, 0x80, 0x43, 0x02, 0xf5, 0x31, 0x27, 0x30, 0x62, + 0xd5, 0xec, 0x3a, 0xd0, 0xcf, 0x5f, 0xb8, 0x5f, 0xf4, 0x47, 0x22, 0x98, 0x0b, 0x35, 0xfc, 0x48, 0x2c, 0x97, 0xf0, + 0xff, 0x5c, 0xf4, 0x39, 0xb9, 0x96, 0x45, 0x53, 0x5d, 0x34, 0x86, 0xa2, 0xb7, 0x01, 0x80, 0x8a, 0xf3, 0x52, 0xcb, + 0x52, 0x6b, 0x32, 0x27, 0x12, 0xf6, 0xbd, 0xbd, 0x74, 0x10, 0x37, 0xda, 0x17, 0xe0, 0xe2, 0xcf, 0x44, 0xfe, 0x1d, + 0x13, 0xb1, 0xe7, 0xee, 0xf7, 0x5c, 0xd4, 0x77, 0x1d, 0x58, 0xda, 0x6e, 0xd6, 0x20, 0x0a, 0xc3, 0x49, 0xe3, 0x9d, + 0x08, 0x66, 0x3d, 0xd2, 0xea, 0x7b, 0x4c, 0xb1, 0xf0, 0x10, 0xe1, 0x44, 0x33, 0xce, 0x16, 0x9e, 0xa1, 0x06, 0x15, + 0x0d, 0xf3, 0x3c, 0x43, 0x8d, 0x49, 0x63, 0x8e, 0x82, 0xa4, 0x31, 0x69, 0x78, 0x33, 0x42, 0x48, 0xb3, 0x53, 0x36, + 0x33, 0xe2, 0x2f, 0x46, 0xc1, 0xdc, 0x78, 0x3b, 0x07, 0x72, 0x3b, 0x64, 0x0d, 0x2f, 0x1d, 0xd0, 0x8b, 0xe5, 0xd2, + 0x3d, 0xe9, 0xf7, 0x5c, 0xd4, 0xf0, 0x0c, 0xa1, 0xed, 0x1b, 0x4a, 0x43, 0x08, 0xb3, 0x8b, 0x42, 0x47, 0x93, 0x5e, + 0xd7, 0x22, 0x47, 0x8b, 0x6a, 0xb3, 0x5b, 0x3c, 0x80, 0x16, 0xa5, 0x21, 0xa3, 0x14, 0xd6, 0x29, 0x4c, 0xd3, 0x10, + 0x73, 0x46, 0x5a, 0x98, 0x13, 0xe3, 0xbc, 0x8e, 0x89, 0xa8, 0x08, 0x3e, 0x21, 0x55, 0x75, 0x3c, 0x08, 0x71, 0x74, + 0x41, 0x5e, 0x29, 0x83, 0xa4, 0x6b, 0x5c, 0xe3, 0x34, 0x21, 0xaf, 0x57, 0x22, 0xb8, 0x21, 0x84, 0x57, 0x6e, 0xfc, + 0xe1, 0x2c, 0xcb, 0x68, 0x2a, 0x5e, 0xf3, 0x48, 0xeb, 0x69, 0x34, 0x01, 0x53, 0x09, 0x42, 0xb3, 0x18, 0x94, 0xb4, + 0x8e, 0xd9, 0x19, 0xb3, 0xb5, 0xd7, 0x63, 0x32, 0x53, 0xfa, 0x93, 0x0c, 0xd8, 0x76, 0xc7, 0xda, 0x30, 0xf6, 0x10, + 0x9e, 0xe9, 0x48, 0xae, 0xe7, 0xfb, 0xfe, 0xd8, 0x1f, 0xc2, 0x6b, 0x18, 0x20, 0x47, 0x85, 0xdc, 0x47, 0x5e, 0x4e, + 0x6e, 0xfc, 0x94, 0xde, 0xca, 0x51, 0x3d, 0x54, 0x49, 0x66, 0xb3, 0xbd, 0x4e, 0xe2, 0xae, 0x64, 0x37, 0xb9, 0x9f, + 0xf2, 0x88, 0x02, 0x7a, 0x20, 0x76, 0xaf, 0x8b, 0xe2, 0x30, 0xb7, 0x43, 0x54, 0x15, 0x7c, 0x03, 0xdb, 0x7b, 0x3d, + 0x06, 0x97, 0xaf, 0x54, 0xb6, 0xca, 0xca, 0xca, 0x0f, 0x8e, 0x10, 0x1b, 0x79, 0x63, 0x1f, 0x42, 0x7b, 0x92, 0x84, + 0x28, 0xd8, 0x72, 0x63, 0x9b, 0xa8, 0x26, 0x65, 0x9f, 0x73, 0x12, 0x0d, 0x78, 0xa3, 0x21, 0xdd, 0xd0, 0x33, 0x45, + 0x12, 0x63, 0x84, 0xe7, 0xe5, 0xde, 0x32, 0xf5, 0xbe, 0x24, 0xf5, 0x91, 0xbc, 0x79, 0xdd, 0x9d, 0xdb, 0x80, 0x34, + 0x09, 0xf0, 0x14, 0x0a, 0x6f, 0x82, 0xf0, 0x29, 0xd9, 0xf7, 0x06, 0x7e, 0xff, 0x2f, 0x17, 0xa8, 0xef, 0xf9, 0x7f, + 0x46, 0xfb, 0x8a, 0x71, 0xcc, 0x51, 0x37, 0x51, 0x43, 0x2c, 0x64, 0x08, 0xb3, 0x8d, 0xa5, 0x27, 0x31, 0xc8, 0x70, + 0x1a, 0x4e, 0x68, 0x70, 0x0a, 0x7b, 0xdc, 0xd0, 0xcd, 0x97, 0x18, 0xe8, 0x28, 0x38, 0xd5, 0x9c, 0xc4, 0x77, 0xfb, + 0xcf, 0x44, 0xf9, 0xd4, 0x77, 0xfb, 0x5f, 0x55, 0x4f, 0x7f, 0x71, 0xfb, 0x3f, 0x8b, 0xe0, 0x97, 0x42, 0x3b, 0xbb, + 0x6b, 0x43, 0x3c, 0x32, 0x43, 0x14, 0x6a, 0x61, 0x2c, 0xcc, 0xcd, 0xd0, 0xba, 0x9f, 0x63, 0x8c, 0x0a, 0x36, 0x2a, + 0x59, 0x51, 0xee, 0x8b, 0x70, 0x0c, 0x28, 0xb5, 0x56, 0x20, 0xb7, 0x23, 0xfb, 0xd5, 0x84, 0x81, 0x50, 0x0c, 0xb5, + 0x02, 0x2a, 0xc7, 0xbd, 0x16, 0x5a, 0xd4, 0xea, 0x4a, 0x8d, 0xa9, 0x1e, 0x49, 0x2f, 0xb9, 0xf4, 0x9c, 0xb4, 0xba, + 0xf3, 0x93, 0x71, 0x77, 0xde, 0x68, 0xa0, 0xdc, 0x10, 0xd6, 0x6c, 0x30, 0xbf, 0xc0, 0x1f, 0xc0, 0xa7, 0x67, 0x53, + 0x12, 0xae, 0x4d, 0xaf, 0xa3, 0xa7, 0xd7, 0x68, 0x64, 0x05, 0xea, 0x5a, 0x4d, 0xc7, 0xaa, 0x69, 0x51, 0x28, 0x9c, + 0xac, 0x12, 0xda, 0x31, 0x92, 0x25, 0x90, 0x0e, 0x45, 0x08, 0x39, 0x15, 0x68, 0x63, 0xaf, 0xd0, 0x27, 0x34, 0x97, + 0x3b, 0x16, 0x98, 0xa7, 0x92, 0x11, 0x1e, 0x60, 0x01, 0x9a, 0x96, 0x8e, 0xe0, 0x09, 0x9e, 0x35, 0xda, 0x92, 0xc8, + 0x9b, 0xed, 0x6e, 0xbd, 0xaf, 0xc7, 0x55, 0x5f, 0x78, 0xd6, 0x20, 0x93, 0x12, 0x4b, 0x45, 0xd6, 0x68, 0x14, 0xf5, + 0x68, 0xa7, 0xd9, 0xb7, 0xb5, 0xf8, 0xc3, 0xed, 0x6a, 0x5a, 0x86, 0x91, 0xaf, 0x95, 0x44, 0x65, 0x3e, 0x4b, 0x53, + 0x9a, 0x81, 0x0c, 0x25, 0x02, 0xb3, 0xa2, 0xa8, 0xe4, 0x3a, 0x08, 0x51, 0x4c, 0x49, 0x0a, 0x7c, 0x47, 0x9a, 0x5d, + 0x38, 0xc3, 0x1c, 0xc7, 0x92, 0x6b, 0x10, 0x42, 0xce, 0x4c, 0x42, 0x8b, 0x90, 0x1c, 0x28, 0x21, 0xcc, 0x92, 0x48, + 0x39, 0xa1, 0xfe, 0xe5, 0xee, 0x19, 0xbf, 0xd7, 0x24, 0x1b, 0xb0, 0x8b, 0x40, 0x56, 0x4b, 0x34, 0xdf, 0x0a, 0xc9, + 0x7b, 0x4f, 0xa0, 0x32, 0x38, 0xe2, 0x4b, 0xf6, 0xf7, 0x8c, 0x65, 0x54, 0x6a, 0xe0, 0xbb, 0xc6, 0xec, 0x4b, 0xea, + 0xea, 0x63, 0x62, 0x3b, 0x6f, 0x00, 0x91, 0x21, 0xf8, 0x76, 0x32, 0xb2, 0x56, 0xed, 0x72, 0xf7, 0xf4, 0xcd, 0x26, + 0x13, 0x78, 0xb9, 0xd4, 0xc6, 0xaf, 0xd4, 0x6c, 0x70, 0x58, 0x41, 0x9a, 0xe8, 0x1f, 0x81, 0x97, 0x48, 0x05, 0x29, + 0xf4, 0x52, 0xa0, 0xa2, 0xcb, 0xdd, 0xd3, 0xf7, 0x5e, 0x2a, 0x5d, 0x4b, 0x08, 0xdb, 0xd3, 0xf6, 0x38, 0xf1, 0x62, + 0x42, 0x91, 0x9a, 0x7b, 0xc9, 0xb8, 0xb8, 0x25, 0xbe, 0x83, 0x58, 0xbe, 0x04, 0xfb, 0x61, 0xc0, 0x2e, 0x48, 0xa2, + 0x31, 0x40, 0x12, 0x84, 0x93, 0x9a, 0x59, 0x46, 0x60, 0x01, 0xe4, 0x58, 0xe7, 0xb0, 0x12, 0xbe, 0x52, 0xfc, 0x10, + 0x4e, 0xe4, 0xa8, 0xa2, 0x50, 0xa2, 0xe3, 0xe5, 0x5a, 0x5e, 0x5a, 0x65, 0x8d, 0x7e, 0x0b, 0x96, 0x93, 0x79, 0x78, + 0xad, 0xbb, 0x2e, 0x0b, 0x9e, 0x99, 0x04, 0xb2, 0xcb, 0xdd, 0xd3, 0x57, 0x3a, 0x87, 0x6c, 0x1a, 0x1a, 0x6e, 0xbf, + 0x66, 0x61, 0x9e, 0xbe, 0xf2, 0xab, 0xb7, 0xb2, 0xf2, 0xe5, 0xee, 0xe9, 0x87, 0x4d, 0xd5, 0xa0, 0xbc, 0x98, 0x55, + 0x26, 0xbe, 0x84, 0x6f, 0x41, 0x93, 0x60, 0xa1, 0x45, 0x43, 0xc0, 0x0a, 0x2c, 0xc5, 0x51, 0x90, 0x17, 0xa5, 0x67, + 0xe4, 0x19, 0xce, 0x88, 0x8c, 0x02, 0xd5, 0x57, 0x4d, 0x2b, 0x79, 0x8c, 0xa7, 0xe7, 0x43, 0x3e, 0xa5, 0x5b, 0x42, + 0x43, 0xb7, 0xc8, 0x67, 0x13, 0x48, 0x9e, 0x91, 0xa0, 0x33, 0xbc, 0xd3, 0x42, 0xdd, 0xba, 0xf0, 0xca, 0x24, 0x91, + 0xf2, 0x9a, 0x64, 0xc1, 0x31, 0x69, 0xe1, 0x84, 0xb4, 0x70, 0x48, 0xf2, 0x41, 0x4b, 0x89, 0x87, 0x6e, 0x58, 0xf6, + 0xab, 0x84, 0x0c, 0xe4, 0x85, 0xe9, 0xdd, 0xaa, 0xc4, 0x6f, 0xd4, 0x0d, 0xa5, 0xeb, 0x51, 0x4a, 0xf4, 0x48, 0x92, + 0xc5, 0x0b, 0x8f, 0x63, 0x2e, 0x3b, 0x3e, 0x67, 0xd7, 0x09, 0xa4, 0x96, 0xc0, 0xac, 0xb0, 0x40, 0x41, 0x59, 0xb5, + 0xad, 0xab, 0x86, 0xbe, 0x5c, 0x27, 0x8e, 0x43, 0x1f, 0x18, 0x37, 0x0e, 0x75, 0x26, 0x4e, 0xbe, 0xde, 0xe4, 0xd1, + 0xde, 0x9e, 0xa7, 0x1a, 0xfd, 0x22, 0x3c, 0x6e, 0xde, 0x57, 0x81, 0xbb, 0x6f, 0x15, 0xaf, 0x88, 0x90, 0x84, 0xbf, + 0xd1, 0x48, 0x2e, 0x0a, 0x88, 0x42, 0x7b, 0x61, 0x1d, 0x83, 0x06, 0x78, 0xa9, 0xe9, 0xd5, 0xa7, 0xdf, 0x68, 0x94, + 0x41, 0xda, 0x3a, 0xb6, 0x6e, 0x71, 0x56, 0xcc, 0xbd, 0x32, 0xf9, 0xa7, 0xb5, 0x96, 0x31, 0x65, 0x40, 0x40, 0xcc, + 0xa6, 0x59, 0x66, 0x26, 0x63, 0x6d, 0x09, 0x06, 0xf5, 0xbe, 0xd2, 0x69, 0x0b, 0x58, 0xe6, 0x57, 0xe9, 0x4a, 0x86, + 0x9d, 0x75, 0x50, 0x60, 0x2a, 0x41, 0x50, 0x0a, 0x2a, 0x35, 0x0a, 0x4d, 0xde, 0x2f, 0xd6, 0xb3, 0x2e, 0x71, 0x8e, + 0xb4, 0x8f, 0x4b, 0x42, 0x21, 0x91, 0xd5, 0x29, 0x91, 0xf2, 0x82, 0x4c, 0xb7, 0x93, 0xfc, 0xa9, 0x45, 0xf2, 0x4f, + 0x09, 0xb5, 0xc8, 0x5f, 0x79, 0x38, 0x7c, 0xae, 0x5d, 0x0b, 0xb9, 0x79, 0x75, 0x36, 0x25, 0xe0, 0x43, 0xab, 0x63, + 0xb4, 0x16, 0x55, 0xdc, 0xc2, 0x50, 0xec, 0x1d, 0x22, 0xbd, 0x90, 0xd8, 0x84, 0x80, 0xbd, 0x2a, 0xa6, 0x06, 0x43, + 0x6f, 0x72, 0xe9, 0xd9, 0x1c, 0xf0, 0xf4, 0xc3, 0xfd, 0xe1, 0xd0, 0xb3, 0xe9, 0xfa, 0xce, 0xb5, 0xb2, 0x3f, 0x61, + 0xd6, 0xd6, 0xc6, 0xad, 0xe7, 0x82, 0xc2, 0xf8, 0x65, 0x18, 0xbb, 0xce, 0x7c, 0x56, 0x36, 0xa1, 0x91, 0x7f, 0x00, + 0x6d, 0xbb, 0x2d, 0x6b, 0x50, 0xab, 0x5b, 0xe0, 0x47, 0x2a, 0x07, 0x35, 0xcc, 0xb6, 0xb0, 0x8f, 0x53, 0x59, 0x81, + 0xa6, 0xd1, 0xe6, 0xd7, 0x4f, 0x0b, 0x4d, 0x26, 0x0a, 0x34, 0xb4, 0x00, 0xfe, 0xa7, 0x48, 0x1e, 0xe8, 0x46, 0xca, + 0x05, 0x40, 0xd0, 0x54, 0xe2, 0xa9, 0x42, 0x98, 0xeb, 0x56, 0xce, 0xf7, 0x17, 0x3b, 0x84, 0x4c, 0x2b, 0xe7, 0xe3, + 0xbb, 0x2a, 0xf7, 0x0a, 0xc8, 0x02, 0x05, 0x60, 0x3c, 0x96, 0x05, 0x2a, 0x7a, 0x79, 0x66, 0xaa, 0x4b, 0x03, 0xd2, + 0xaf, 0xf4, 0x6d, 0x2b, 0xb2, 0x29, 0xbd, 0x72, 0xea, 0xbd, 0x41, 0xc3, 0xca, 0xdb, 0x5d, 0x78, 0xfb, 0x42, 0x48, + 0x18, 0xe1, 0xf9, 0xbd, 0xac, 0x6d, 0xfa, 0x2d, 0x3e, 0xae, 0x26, 0xb0, 0xac, 0x2c, 0x8a, 0xcf, 0xd2, 0x9c, 0x66, + 0xe2, 0x29, 0x1d, 0xf1, 0x0c, 0x42, 0x16, 0x25, 0x4e, 0x50, 0xb1, 0x6b, 0xb9, 0xed, 0xe4, 0xfc, 0xac, 0x38, 0xc1, + 0xca, 0x04, 0xe5, 0xaf, 0x8f, 0x32, 0x66, 0x7d, 0xb9, 0xda, 0x6a, 0xba, 0xb7, 0xf7, 0xbe, 0x42, 0x93, 0x86, 0x52, + 0x42, 0x61, 0x31, 0x2d, 0xa5, 0xd2, 0xe8, 0x40, 0xee, 0xae, 0x57, 0xba, 0x00, 0x0c, 0xc3, 0xb0, 0x79, 0xcf, 0x0b, + 0x22, 0x8a, 0xf1, 0x2a, 0x8b, 0xd7, 0xae, 0x09, 0x66, 0x9b, 0x2d, 0xc0, 0xe1, 0xc1, 0xd0, 0x56, 0xbe, 0xa2, 0xbc, + 0x4a, 0x87, 0x2d, 0x61, 0x38, 0x03, 0x64, 0x79, 0xd2, 0x08, 0xb1, 0x28, 0x70, 0xa3, 0x51, 0xf2, 0x11, 0xf4, 0xca, + 0x18, 0xe7, 0x7e, 0x0c, 0x09, 0xb0, 0xb5, 0x2d, 0x8b, 0x10, 0x56, 0x79, 0x39, 0x56, 0x26, 0xc1, 0xe9, 0x8b, 0x4d, + 0x1e, 0x65, 0x43, 0xd4, 0x54, 0x4a, 0x1d, 0xa8, 0x91, 0xa1, 0xb2, 0x81, 0x3f, 0xf7, 0x98, 0x56, 0xdc, 0x4c, 0xd8, + 0x0c, 0x18, 0xf0, 0x4b, 0xe1, 0xa9, 0x58, 0x14, 0xc8, 0x0c, 0xee, 0xcf, 0xbc, 0xda, 0xd0, 0x5d, 0x2e, 0x9b, 0x61, + 0x8d, 0xb8, 0xd8, 0x46, 0x13, 0x97, 0x61, 0xbd, 0xb3, 0x8a, 0x97, 0xee, 0xaa, 0x1c, 0x6a, 0x61, 0xb8, 0x60, 0x95, + 0x47, 0x62, 0x4d, 0x7f, 0x57, 0xa5, 0x45, 0x97, 0x95, 0x40, 0x0d, 0xa3, 0x37, 0xce, 0x6b, 0xb9, 0x06, 0xb4, 0x00, + 0xfa, 0x5a, 0x3c, 0x17, 0xd6, 0x8a, 0x1a, 0x1f, 0xb6, 0x1c, 0xd3, 0x92, 0xfa, 0xef, 0x20, 0xd3, 0x65, 0x75, 0xcf, + 0xbf, 0x90, 0xb2, 0x90, 0xe1, 0xbc, 0xc6, 0xd8, 0x33, 0xc9, 0xd8, 0x11, 0xe8, 0x69, 0x26, 0xf5, 0xbb, 0xaf, 0x13, + 0x5e, 0x98, 0x96, 0x72, 0x9a, 0xc4, 0x3e, 0x94, 0xc1, 0x72, 0xeb, 0xf7, 0xca, 0x6a, 0x04, 0x8c, 0x40, 0x12, 0x10, + 0xd6, 0x9c, 0x3d, 0x43, 0x38, 0x6f, 0x34, 0xba, 0xf9, 0x09, 0xad, 0x5c, 0x24, 0x15, 0x8c, 0x0c, 0xe2, 0xb9, 0x40, + 0xf0, 0x35, 0x19, 0x0a, 0x11, 0x7f, 0x93, 0x9b, 0x9d, 0x83, 0xab, 0xfd, 0xf4, 0x9d, 0x67, 0x73, 0x35, 0xbb, 0x6e, + 0x19, 0x33, 0x85, 0xf9, 0x78, 0x55, 0xbc, 0xe5, 0xed, 0xfd, 0xf9, 0x1d, 0x00, 0xf7, 0x4e, 0x1b, 0x43, 0x2e, 0x1a, + 0xea, 0x0a, 0xc5, 0x12, 0xca, 0xdd, 0xd7, 0x45, 0x55, 0x5a, 0xa2, 0x3d, 0x58, 0x57, 0x54, 0xa6, 0xac, 0x20, 0x79, + 0x51, 0xe4, 0xb4, 0x8a, 0xee, 0xaf, 0xe4, 0x5f, 0x4a, 0xe1, 0xb2, 0xee, 0x6c, 0x3f, 0x9b, 0x12, 0x81, 0x2d, 0x42, + 0x7d, 0xbb, 0x2d, 0xf4, 0x51, 0x81, 0x09, 0xfb, 0x5a, 0x0b, 0xc5, 0x5f, 0x36, 0x09, 0x45, 0x9c, 0xe9, 0x2d, 0x2f, + 0x05, 0x62, 0xfb, 0x01, 0x02, 0x51, 0x3b, 0xd9, 0x8d, 0x4c, 0x04, 0x75, 0xa4, 0x26, 0x13, 0xeb, 0x4b, 0x4a, 0x32, + 0xcc, 0xf4, 0x6a, 0xf4, 0x3a, 0xcb, 0x25, 0x1b, 0xb4, 0xc0, 0x89, 0xe4, 0xba, 0xf0, 0xb3, 0xad, 0x7e, 0x5a, 0x9c, + 0x58, 0x39, 0x81, 0x3d, 0x56, 0x9a, 0x2c, 0xc8, 0x87, 0x14, 0x67, 0x4f, 0xe6, 0x64, 0x49, 0x9a, 0xd6, 0x14, 0xa4, + 0x09, 0x9c, 0xb0, 0x32, 0xca, 0x04, 0x10, 0x4b, 0x59, 0xa1, 0x0d, 0x48, 0x6f, 0x63, 0xf2, 0x9f, 0x31, 0x2f, 0x3f, + 0xad, 0x89, 0xd6, 0xe4, 0x8a, 0x52, 0x1f, 0x6a, 0xe9, 0x06, 0x1a, 0x02, 0xad, 0x1f, 0xee, 0x48, 0x13, 0xb4, 0x12, + 0xe5, 0xc8, 0x96, 0x43, 0xb8, 0x05, 0x2e, 0xb4, 0x9d, 0xf7, 0x2a, 0xc0, 0xbb, 0x41, 0x9a, 0x60, 0x6e, 0xd1, 0xf5, + 0x0b, 0x22, 0x6a, 0xac, 0x24, 0x26, 0xda, 0x52, 0xc2, 0xa1, 0x24, 0x53, 0x41, 0xb2, 0x41, 0xeb, 0x02, 0x14, 0xd0, + 0x6e, 0x72, 0x92, 0x55, 0x26, 0x70, 0xd2, 0x68, 0xa0, 0xd0, 0x8c, 0x1a, 0x0f, 0x58, 0x23, 0xb9, 0xc0, 0x14, 0x27, + 0xca, 0x30, 0x39, 0xdb, 0xdb, 0xf3, 0xc2, 0x6a, 0xdc, 0x41, 0x72, 0x81, 0x30, 0x5f, 0x2e, 0x3d, 0x09, 0x56, 0x88, + 0x96, 0xcb, 0xd0, 0x06, 0x4b, 0xbe, 0x86, 0x66, 0xd3, 0xbe, 0x20, 0x53, 0x29, 0x00, 0xa7, 0x00, 0x61, 0x83, 0x78, + 0xa1, 0x76, 0xee, 0x85, 0xe0, 0x8c, 0x6a, 0x64, 0x83, 0xa4, 0xd1, 0xbe, 0xb0, 0x18, 0xd7, 0x20, 0xb9, 0x20, 0x61, + 0xc1, 0xf7, 0xf6, 0x76, 0x72, 0x2d, 0x22, 0x7f, 0x02, 0x51, 0xf6, 0x93, 0x94, 0x2c, 0xaa, 0x43, 0x7b, 0x35, 0x56, + 0x9d, 0x01, 0x25, 0x45, 0xe9, 0x65, 0x35, 0xf5, 0x6a, 0x49, 0x10, 0x65, 0x25, 0xac, 0x63, 0xc1, 0x7d, 0xb0, 0xec, + 0x4b, 0x32, 0x7f, 0x26, 0xca, 0x24, 0xeb, 0x5f, 0x36, 0xa6, 0x56, 0xfb, 0xbe, 0x1f, 0x66, 0x63, 0x19, 0xc9, 0x30, + 0x51, 0x58, 0x49, 0xfc, 0x07, 0x1a, 0x4c, 0x6b, 0xe0, 0x41, 0x39, 0xd6, 0x05, 0x51, 0xe0, 0x1b, 0xd5, 0xc6, 0x9c, + 0x26, 0xf9, 0x69, 0xa3, 0x97, 0x41, 0x41, 0xf2, 0xd5, 0x6f, 0x85, 0xe4, 0x50, 0x43, 0xa2, 0xc8, 0x63, 0x05, 0x67, + 0x5b, 0x70, 0xf1, 0x93, 0x58, 0xc1, 0xd9, 0x76, 0xdc, 0x1a, 0x4c, 0xfd, 0xbc, 0x0d, 0x3e, 0x8b, 0x37, 0x28, 0x40, + 0xab, 0x02, 0x0b, 0xca, 0xa3, 0x55, 0xdd, 0x4b, 0xb1, 0x52, 0x10, 0xa6, 0x82, 0x78, 0xac, 0xbe, 0x01, 0x2a, 0x6d, + 0xd4, 0x32, 0x7c, 0x59, 0x30, 0x45, 0x96, 0x4b, 0xa0, 0x9e, 0xb9, 0x02, 0xe4, 0xa4, 0x7d, 0xed, 0xd3, 0xbd, 0x3d, + 0xb0, 0x0d, 0x40, 0x89, 0xf3, 0x87, 0xe1, 0x54, 0xcc, 0x32, 0x50, 0xa5, 0x72, 0xf3, 0x1b, 0x8a, 0xe1, 0x1c, 0x88, + 0x2c, 0x83, 0x1f, 0x50, 0x30, 0x0d, 0xf3, 0x9c, 0xcd, 0x55, 0x99, 0xfe, 0x8d, 0x39, 0x31, 0xa4, 0x9c, 0x2b, 0x9d, + 0x30, 0x43, 0xdd, 0x4c, 0xd3, 0x69, 0x1d, 0x6d, 0xcf, 0xe7, 0x34, 0x15, 0x2f, 0x59, 0x2e, 0x68, 0x0a, 0xd3, 0xaf, + 0x28, 0x0e, 0x66, 0x94, 0x23, 0xd8, 0xb0, 0xb5, 0x56, 0x61, 0x14, 0xdd, 0xdb, 0x44, 0xd4, 0x75, 0xa0, 0x38, 0x4c, + 0xa3, 0x44, 0x0d, 0x62, 0xa7, 0x33, 0x9a, 0x14, 0xce, 0xb2, 0xa6, 0x9d, 0x4e, 0x53, 0x29, 0x1b, 0x92, 0xbb, 0x7b, + 0x8c, 0x18, 0x49, 0x60, 0xa4, 0xe7, 0xbd, 0x5a, 0x0b, 0x04, 0xbc, 0xb7, 0x2c, 0x82, 0x3d, 0x13, 0x2c, 0x2c, 0x8e, + 0xea, 0xd7, 0xe1, 0x2c, 0x05, 0xc9, 0xc6, 0x43, 0x6d, 0x9b, 0x84, 0x83, 0xa4, 0x93, 0x47, 0xdb, 0x2d, 0xab, 0x57, + 0x46, 0x72, 0x18, 0x69, 0xc1, 0x1e, 0xca, 0x98, 0xd1, 0xc2, 0x90, 0x17, 0x32, 0x5b, 0xf1, 0x52, 0x90, 0x9f, 0xe0, + 0xd4, 0xd0, 0x0b, 0x31, 0x49, 0x56, 0x0e, 0xc7, 0x74, 0x2f, 0x4b, 0xed, 0xff, 0x52, 0x78, 0xaf, 0xf1, 0x0b, 0x08, + 0xeb, 0x7e, 0x5d, 0x55, 0x5f, 0x0f, 0xe7, 0x7e, 0x5d, 0x21, 0xe8, 0xeb, 0x60, 0xad, 0x9e, 0x15, 0xc6, 0xed, 0xf8, + 0xc7, 0x7e, 0xcb, 0x35, 0xda, 0xd2, 0xb7, 0x2a, 0x88, 0xa4, 0x12, 0x2d, 0xe5, 0x7e, 0xc0, 0x55, 0x9a, 0x1a, 0xa4, + 0xcb, 0xd5, 0x2d, 0x24, 0xaa, 0x13, 0x0c, 0x95, 0x0e, 0xbf, 0x6d, 0x79, 0xb4, 0x8c, 0xc9, 0x94, 0x9d, 0xf1, 0x36, + 0xcc, 0xc4, 0x2e, 0xec, 0x32, 0xbe, 0x76, 0x12, 0x2f, 0x26, 0xe0, 0x41, 0x7b, 0xd8, 0x10, 0x96, 0xb1, 0x9d, 0xab, + 0x93, 0x40, 0x76, 0xff, 0x84, 0x1b, 0xdd, 0xad, 0x6e, 0x65, 0x7c, 0x00, 0xfb, 0x1f, 0xe1, 0xd8, 0x1c, 0x8f, 0xa3, + 0x9a, 0x03, 0xd3, 0x60, 0x51, 0x94, 0x4e, 0x01, 0xae, 0x94, 0xb7, 0x14, 0x61, 0x5e, 0xc8, 0xf0, 0xf6, 0x37, 0xf8, + 0x7b, 0xcd, 0x12, 0x47, 0x25, 0xc7, 0x79, 0xfe, 0x50, 0x8e, 0xa8, 0xc0, 0x2f, 0xa3, 0xf7, 0x40, 0xc7, 0x92, 0x42, + 0x0b, 0x43, 0x45, 0xcf, 0xb8, 0x9e, 0xc8, 0xd6, 0xac, 0x54, 0x4c, 0xcb, 0x8c, 0x1a, 0x39, 0xcc, 0x86, 0x34, 0x4e, + 0x63, 0x65, 0x8b, 0x72, 0x57, 0xd5, 0xc6, 0x45, 0x5b, 0xb0, 0x58, 0x05, 0x16, 0x97, 0x4b, 0xaf, 0x8e, 0x6a, 0xc2, + 0xac, 0x38, 0x06, 0xc2, 0xcc, 0x4a, 0xa8, 0xa8, 0x69, 0xd6, 0xaa, 0x8d, 0x87, 0x56, 0xf3, 0x89, 0x8c, 0x6e, 0x5e, + 0x83, 0xc3, 0x76, 0x21, 0xa8, 0xe6, 0xb6, 0x4f, 0x01, 0xab, 0xd9, 0x95, 0x03, 0x59, 0x18, 0xfa, 0xb6, 0xcc, 0x94, + 0xad, 0x52, 0x5a, 0x37, 0xe0, 0x17, 0xdd, 0x93, 0x2b, 0xab, 0x51, 0xb7, 0xfe, 0xde, 0xca, 0x35, 0x7a, 0xc6, 0xb7, + 0xe5, 0x1a, 0xd5, 0xb4, 0xdd, 0x9d, 0x16, 0xba, 0x3f, 0x2b, 0x55, 0x8d, 0xb5, 0xb9, 0xca, 0x6f, 0x18, 0xae, 0x0d, + 0xb4, 0xa9, 0xd0, 0x6c, 0xb8, 0xca, 0x59, 0x51, 0x8c, 0xca, 0xb3, 0x04, 0x32, 0x75, 0x67, 0xa4, 0xe8, 0x5f, 0x5b, + 0x8d, 0xf2, 0x40, 0xae, 0xf7, 0x0d, 0x19, 0x27, 0xfc, 0x3a, 0x4c, 0xde, 0xc3, 0x78, 0xd5, 0xcb, 0x17, 0x77, 0x51, + 0x16, 0x0a, 0xaa, 0xb9, 0x4b, 0x05, 0xc3, 0x37, 0x16, 0x0c, 0xdf, 0x28, 0x3e, 0x5d, 0xb5, 0xc7, 0x8b, 0x97, 0x65, + 0x07, 0xc1, 0xa8, 0x30, 0x2c, 0x63, 0x22, 0x36, 0x8f, 0xb1, 0xca, 0xc2, 0x26, 0x25, 0x0b, 0x9b, 0x08, 0x6f, 0xb5, + 0x2b, 0xcf, 0xfb, 0x7e, 0x73, 0x2f, 0xeb, 0x9c, 0xed, 0xfb, 0x6a, 0xe3, 0x7f, 0x1f, 0xdc, 0xdb, 0xc6, 0xe2, 0x72, + 0x07, 0xfe, 0x81, 0x4c, 0x56, 0x51, 0x20, 0x3f, 0x85, 0xa4, 0x03, 0x41, 0x7a, 0xd6, 0x91, 0x83, 0x4a, 0x4e, 0x99, + 0x3c, 0x20, 0x6f, 0x38, 0xcb, 0x05, 0x9f, 0xe8, 0x3e, 0x73, 0x7d, 0xce, 0x48, 0xbe, 0x04, 0x57, 0xb4, 0x8c, 0xb5, + 0x07, 0xf5, 0x93, 0x5c, 0x8b, 0x8f, 0x2c, 0x8d, 0x82, 0x1c, 0x6b, 0x29, 0x92, 0x07, 0x59, 0x41, 0x4c, 0xae, 0xf1, + 0xfa, 0x3b, 0x3c, 0x62, 0x29, 0xcb, 0x63, 0x9a, 0x79, 0x1c, 0x2d, 0xb6, 0x0d, 0xc6, 0x21, 0x20, 0xa3, 0x06, 0xc3, + 0x5f, 0x56, 0x47, 0xfe, 0x7c, 0xe8, 0x0d, 0xfc, 0x40, 0x13, 0x2a, 0x62, 0x1e, 0x41, 0x5a, 0x8a, 0x1f, 0x95, 0x47, + 0x9a, 0xf6, 0xf6, 0x76, 0x3c, 0x57, 0xba, 0x25, 0xe0, 0xf0, 0xb7, 0xfd, 0x06, 0xf5, 0x17, 0x70, 0x3a, 0xa7, 0x1a, + 0x9a, 0xa2, 0x05, 0x5d, 0x3d, 0xc8, 0x22, 0xfc, 0x8f, 0xf4, 0x0e, 0xa7, 0xa8, 0x28, 0x02, 0x05, 0xb5, 0x3b, 0x62, + 0x34, 0x89, 0x5c, 0xfc, 0x91, 0xde, 0x05, 0xe5, 0x79, 0x71, 0x79, 0xbc, 0x59, 0x2e, 0xa0, 0xcb, 0x6f, 0x52, 0x17, + 0x57, 0x83, 0x04, 0x8b, 0x02, 0xf3, 0x8c, 0x8d, 0x81, 0x38, 0xff, 0x46, 0xef, 0x02, 0xd5, 0x1f, 0xb3, 0x4e, 0xeb, + 0xa1, 0x85, 0x41, 0xbd, 0x6f, 0x15, 0xdb, 0xcb, 0xa0, 0x0d, 0x8a, 0x81, 0x6c, 0x7b, 0x41, 0x6a, 0xf5, 0x2a, 0xf3, + 0x10, 0xa1, 0xe2, 0xa1, 0x53, 0xc1, 0xdf, 0xd9, 0xa2, 0x4d, 0xd4, 0x32, 0x5f, 0x57, 0x1a, 0x51, 0x68, 0x50, 0x65, + 0x7a, 0x5c, 0x7a, 0xa9, 0xd9, 0x75, 0xfa, 0x08, 0x82, 0xe5, 0x08, 0xfb, 0x4e, 0xe8, 0x4e, 0x83, 0x2f, 0x55, 0x42, + 0x48, 0x15, 0x49, 0x7a, 0x55, 0xb5, 0x73, 0x2e, 0x3d, 0xc0, 0x3b, 0x24, 0xb4, 0x84, 0xf2, 0x40, 0x66, 0x61, 0xb2, + 0x45, 0x7f, 0x10, 0xc4, 0x5b, 0x98, 0x29, 0x04, 0xa9, 0x8d, 0x45, 0x51, 0x00, 0x15, 0x6a, 0xfa, 0x52, 0x09, 0x80, + 0x70, 0x86, 0x7d, 0x4d, 0x6a, 0x66, 0x52, 0x6a, 0xfa, 0x16, 0xc6, 0xb7, 0x48, 0x49, 0x2a, 0x91, 0x21, 0x95, 0x48, + 0x29, 0xf4, 0xf4, 0xe2, 0x6a, 0x12, 0xb2, 0x17, 0xb4, 0x3c, 0x3f, 0xa7, 0xd6, 0x3c, 0xab, 0x81, 0xe5, 0xc9, 0x7e, + 0x50, 0x11, 0xc0, 0x94, 0xa8, 0xaa, 0x50, 0x94, 0xc7, 0xb2, 0x4d, 0x7a, 0xab, 0xc7, 0x7d, 0x33, 0x2d, 0x62, 0x50, + 0xe2, 0xc5, 0x68, 0x91, 0x7a, 0x31, 0xce, 0x20, 0x1d, 0x91, 0x17, 0x25, 0xfc, 0xd4, 0x5e, 0x8d, 0x5a, 0xb2, 0xf2, + 0xe6, 0x33, 0x7e, 0xa0, 0xcc, 0x0b, 0x48, 0xd1, 0xc4, 0xa9, 0xe1, 0x29, 0xa9, 0x27, 0x0f, 0xdb, 0x59, 0xcb, 0xf6, + 0xb5, 0x4e, 0xd0, 0xd1, 0x80, 0xfd, 0x20, 0xbc, 0x85, 0x35, 0x0b, 0xfb, 0x34, 0xb7, 0x3e, 0xf3, 0xa7, 0x83, 0x7d, + 0x55, 0x0e, 0xa9, 0x97, 0x93, 0x15, 0x89, 0x73, 0x7f, 0xaa, 0xe5, 0xcf, 0x33, 0x9a, 0xdd, 0x9d, 0x53, 0x48, 0x75, + 0xe6, 0x70, 0xda, 0xb7, 0x5a, 0x86, 0x2a, 0x4d, 0xbd, 0x9f, 0x49, 0x65, 0xa5, 0xa8, 0x9f, 0x02, 0x5c, 0x3d, 0x23, + 0x58, 0xc8, 0x68, 0xa3, 0xe5, 0x88, 0x51, 0xbb, 0x85, 0x6e, 0x3d, 0x3d, 0x49, 0xbb, 0x0c, 0xfc, 0x6b, 0x15, 0xa6, + 0x75, 0xb0, 0x00, 0x73, 0xfb, 0x44, 0xea, 0x20, 0xbf, 0x58, 0xf5, 0xca, 0x40, 0x11, 0x84, 0xef, 0xb2, 0xed, 0x53, + 0xdd, 0x94, 0x34, 0xbb, 0x7d, 0xaa, 0xb5, 0xa0, 0x9f, 0x4c, 0xf8, 0xc1, 0x7a, 0x9c, 0xf2, 0xf8, 0x32, 0x2b, 0x0a, + 0x54, 0x00, 0x78, 0x7f, 0xed, 0x7a, 0xde, 0x5f, 0x75, 0xca, 0xa0, 0x0f, 0xb1, 0xd8, 0xf3, 0x84, 0x1b, 0x26, 0x5e, + 0x8d, 0xff, 0xd7, 0xb5, 0xf1, 0xff, 0x6a, 0x9d, 0x39, 0x05, 0xd3, 0x68, 0x9c, 0xd2, 0xc8, 0xb0, 0x4e, 0xa4, 0x08, + 0x50, 0xea, 0x6d, 0xa9, 0x20, 0x6f, 0xae, 0x02, 0xd0, 0xb8, 0x16, 0x23, 0x9e, 0x8a, 0xe6, 0x28, 0x9c, 0xb0, 0xe4, + 0x2e, 0x98, 0xb1, 0xe6, 0x84, 0xa7, 0x3c, 0x9f, 0x86, 0x43, 0x8a, 0xf3, 0xbb, 0x5c, 0xd0, 0x49, 0x73, 0xc6, 0xf0, + 0x0b, 0x9a, 0xcc, 0xa9, 0x60, 0xc3, 0x10, 0xbb, 0xa7, 0x19, 0x0b, 0x13, 0xe7, 0x75, 0x98, 0x65, 0xfc, 0xc6, 0xc5, + 0xef, 0xf8, 0x35, 0x17, 0x1c, 0xbf, 0xb9, 0xbd, 0x1b, 0xd3, 0x14, 0x7f, 0xb8, 0x9e, 0xa5, 0x62, 0x86, 0xf3, 0x30, + 0xcd, 0x9b, 0x39, 0xcd, 0xd8, 0xa8, 0x3b, 0xe4, 0x09, 0xcf, 0x9a, 0x90, 0xb1, 0x3d, 0xa1, 0x41, 0xc2, 0xc6, 0xb1, + 0x70, 0xa2, 0x30, 0xfb, 0xd8, 0x6d, 0x36, 0xa7, 0x19, 0x9b, 0x84, 0xd9, 0x5d, 0x53, 0xd6, 0x08, 0x3e, 0x6f, 0x1d, + 0x84, 0x4f, 0x46, 0x87, 0x5d, 0x91, 0x85, 0x69, 0xce, 0x60, 0x99, 0x82, 0x30, 0x49, 0x9c, 0x83, 0xa3, 0xd6, 0x24, + 0xdf, 0x51, 0x81, 0xbc, 0x30, 0x15, 0xc5, 0x15, 0x7e, 0x03, 0x70, 0xfb, 0xd7, 0x22, 0xc5, 0xd7, 0x33, 0x21, 0x78, + 0xba, 0x18, 0xce, 0xb2, 0x9c, 0x67, 0xc1, 0x94, 0xb3, 0x54, 0xd0, 0xac, 0x7b, 0xcd, 0xb3, 0x88, 0x66, 0xcd, 0x2c, + 0x8c, 0xd8, 0x2c, 0x0f, 0x0e, 0xa7, 0xb7, 0x5d, 0xd0, 0x2c, 0xc6, 0x19, 0x9f, 0xa5, 0x91, 0x1e, 0x8b, 0xa5, 0x31, + 0xcd, 0x98, 0xb0, 0x5f, 0xc8, 0x4b, 0x4c, 0x82, 0x84, 0xa5, 0x34, 0xcc, 0x9a, 0x63, 0x68, 0x0c, 0x66, 0x51, 0x2b, + 0xa2, 0x63, 0x9c, 0x8d, 0xaf, 0x43, 0xaf, 0xdd, 0x79, 0x8c, 0xcd, 0x5f, 0xff, 0x08, 0x39, 0xad, 0xcd, 0xc5, 0xed, + 0x56, 0xeb, 0x4f, 0xa8, 0xbb, 0x32, 0x8a, 0x04, 0x28, 0x68, 0x4f, 0x6f, 0x9d, 0x9c, 0x43, 0x46, 0xdb, 0xa6, 0x96, + 0xdd, 0x69, 0x18, 0x41, 0x3e, 0x70, 0xd0, 0x99, 0xde, 0x16, 0x30, 0xbb, 0x40, 0xa5, 0x98, 0xea, 0x49, 0xea, 0xa7, + 0xc5, 0x6f, 0x85, 0xf8, 0x78, 0x33, 0xc4, 0x1d, 0x03, 0x71, 0x85, 0xf5, 0x66, 0x34, 0xcb, 0x64, 0x6c, 0x35, 0x68, + 0xe7, 0x0a, 0x90, 0x98, 0xcf, 0x69, 0x66, 0xe0, 0x90, 0x0f, 0xbf, 0x19, 0x8c, 0xce, 0x66, 0x30, 0x8e, 0x3f, 0x05, + 0x46, 0x96, 0x46, 0x8b, 0xfa, 0xba, 0xb6, 0x33, 0x3a, 0xe9, 0xc6, 0x14, 0xe8, 0x29, 0xe8, 0xc0, 0xef, 0x1b, 0x16, + 0x89, 0x58, 0xfd, 0x94, 0xe4, 0x7c, 0xa3, 0xde, 0x1d, 0xb5, 0x5a, 0xea, 0x39, 0x67, 0xbf, 0xd0, 0xa0, 0xed, 0x43, + 0x85, 0xe2, 0x0a, 0xff, 0xad, 0x3c, 0xcb, 0x5b, 0xe7, 0x9e, 0xf8, 0x1b, 0xfb, 0x90, 0xaf, 0x95, 0xa2, 0x58, 0x1d, + 0x89, 0xc6, 0x99, 0x91, 0x95, 0x4a, 0xf8, 0x80, 0xdb, 0x4e, 0x72, 0x47, 0xc2, 0x7a, 0xe5, 0x21, 0x4e, 0xd6, 0xff, + 0x46, 0xe5, 0x5d, 0x04, 0x10, 0xe9, 0xb0, 0x52, 0x0d, 0x79, 0x37, 0xeb, 0x91, 0x56, 0x37, 0x6b, 0x36, 0x91, 0xc7, + 0x49, 0x3a, 0xc8, 0x74, 0x72, 0x9e, 0xc7, 0xfa, 0x5c, 0x1a, 0xdb, 0x39, 0x0a, 0x38, 0x9c, 0x34, 0x5d, 0x2e, 0xab, + 0x30, 0x00, 0x93, 0xa7, 0x35, 0xfe, 0x26, 0x74, 0x05, 0x9c, 0x5b, 0x9c, 0x9c, 0x9b, 0xab, 0x5d, 0x52, 0xc3, 0x2b, + 0x12, 0x3e, 0x94, 0x98, 0xf3, 0xa7, 0xa1, 0x88, 0xc1, 0x4b, 0x51, 0x8a, 0x9f, 0x2a, 0x85, 0xc9, 0xdd, 0x77, 0x51, + 0x3f, 0x2d, 0xf3, 0xdb, 0x20, 0x8f, 0x2f, 0x2d, 0xa0, 0x97, 0xef, 0x05, 0x81, 0x1e, 0xf1, 0x57, 0x44, 0xd9, 0x74, + 0xc6, 0xa2, 0x1b, 0x3d, 0xd4, 0xa2, 0xa3, 0xa9, 0x60, 0x32, 0x73, 0xdb, 0x44, 0x1c, 0xe2, 0x30, 0xbf, 0x1c, 0xaa, + 0xa3, 0x92, 0x79, 0x75, 0x30, 0x20, 0x94, 0xd0, 0x2b, 0x23, 0x8d, 0x66, 0xd2, 0x1e, 0xfd, 0xab, 0xd8, 0x6a, 0x9f, + 0xa4, 0xf7, 0xd9, 0x27, 0xe5, 0xc4, 0x73, 0x3e, 0xcb, 0x86, 0x10, 0x8e, 0xd4, 0x52, 0x6f, 0xdd, 0x71, 0xe3, 0x4a, + 0x15, 0xc3, 0xc5, 0xc2, 0xca, 0x03, 0x15, 0x98, 0xd9, 0xd7, 0x4a, 0x50, 0x19, 0xf2, 0x52, 0xc7, 0x35, 0xb4, 0x88, + 0x33, 0x53, 0x02, 0x99, 0x1d, 0xc9, 0x94, 0x46, 0x2f, 0x23, 0xbd, 0xcc, 0x9f, 0xa5, 0xec, 0xe7, 0x19, 0xbd, 0x64, + 0xa0, 0x6b, 0x32, 0x9f, 0x45, 0x32, 0xd6, 0x04, 0xb2, 0xaf, 0xd9, 0x86, 0xe0, 0x05, 0x8b, 0xd4, 0xc2, 0x64, 0xf2, + 0xa5, 0xce, 0x6d, 0x72, 0x9b, 0x2e, 0xf8, 0x8b, 0x41, 0x3b, 0x60, 0x38, 0xe2, 0x93, 0x90, 0xa5, 0x81, 0x74, 0xf9, + 0x96, 0x9d, 0x05, 0x50, 0x1b, 0xb3, 0x28, 0xc8, 0xf4, 0xf2, 0xb4, 0x91, 0xff, 0x13, 0x67, 0xa9, 0x6c, 0x5a, 0x74, + 0xb9, 0x44, 0xa8, 0x42, 0x1f, 0x31, 0x08, 0x3e, 0x55, 0x72, 0x8d, 0x23, 0x6c, 0xbf, 0x2e, 0x4f, 0x9d, 0xd7, 0x56, + 0xa0, 0xb5, 0xb2, 0x50, 0xca, 0x08, 0xe0, 0xab, 0xa5, 0x39, 0xcf, 0x84, 0xe7, 0xc5, 0x38, 0x41, 0xa4, 0x17, 0x4b, + 0x67, 0xd7, 0x49, 0x22, 0xff, 0xeb, 0x37, 0xdb, 0x41, 0xbb, 0x34, 0xdf, 0x6b, 0x87, 0x81, 0x55, 0x72, 0x94, 0x3e, + 0x50, 0x2a, 0xa7, 0x51, 0xfe, 0x56, 0x53, 0xad, 0x9e, 0xcb, 0xe9, 0x62, 0xbd, 0xdd, 0x94, 0xa8, 0xf2, 0x6a, 0x40, + 0xc8, 0x60, 0xd1, 0x96, 0xa1, 0x50, 0x51, 0xcd, 0xbb, 0x54, 0x25, 0xaf, 0x94, 0x88, 0xbe, 0xdc, 0x5d, 0xa4, 0x7a, + 0xc4, 0xe2, 0x8a, 0x19, 0x27, 0x53, 0x9d, 0xe4, 0x0a, 0x8d, 0x11, 0x4b, 0x0f, 0xdd, 0x54, 0x4d, 0xc1, 0x72, 0x47, + 0xd2, 0x8d, 0x74, 0xeb, 0xab, 0x47, 0xaa, 0x14, 0x84, 0xcd, 0x55, 0x64, 0xaa, 0xde, 0x26, 0xc0, 0xc0, 0x6c, 0xcd, + 0x85, 0x99, 0x02, 0x68, 0x63, 0x23, 0x0a, 0xe7, 0x68, 0xae, 0x76, 0x17, 0xdf, 0x8b, 0x62, 0xdf, 0xaa, 0x2a, 0x7f, + 0xb3, 0x08, 0xfe, 0x07, 0x09, 0xb8, 0x50, 0x4a, 0x69, 0xe0, 0xbe, 0x7d, 0x73, 0xfe, 0xde, 0xc5, 0x70, 0x3b, 0x17, + 0xcd, 0xf2, 0x60, 0xe1, 0xea, 0xd4, 0xb8, 0x26, 0x84, 0x59, 0xdd, 0xc0, 0x0d, 0xa7, 0x70, 0xd2, 0x58, 0xf2, 0x82, + 0xfd, 0xdb, 0xe6, 0xcd, 0xcd, 0x4d, 0x13, 0x0e, 0x42, 0x35, 0x67, 0x59, 0x42, 0xd3, 0x21, 0x8f, 0x68, 0xe4, 0x16, + 0x05, 0xf2, 0x45, 0x4c, 0xd3, 0xf2, 0xfe, 0x1e, 0x9e, 0x50, 0x3f, 0xe1, 0x63, 0x75, 0x88, 0x73, 0xd5, 0xaa, 0x1e, + 0x5e, 0x9d, 0xc8, 0x7b, 0xa9, 0x7a, 0x27, 0x42, 0xdd, 0x08, 0x26, 0x32, 0xf8, 0xd9, 0x83, 0x98, 0xcb, 0xc9, 0xbe, + 0x88, 0xe5, 0xc3, 0x39, 0xec, 0x30, 0xf9, 0xb4, 0xbb, 0x58, 0xa3, 0xbe, 0x3e, 0x74, 0x11, 0xf7, 0xd4, 0x9c, 0x73, + 0x59, 0xeb, 0x2a, 0x18, 0x5e, 0x5d, 0x15, 0x27, 0xfb, 0xd0, 0xd7, 0xbe, 0xe9, 0xf7, 0x9a, 0x47, 0x77, 0xa6, 0x7d, + 0x49, 0x91, 0x70, 0x3f, 0x51, 0x4a, 0x7a, 0xd0, 0x05, 0x8c, 0x1b, 0xf5, 0x00, 0x2b, 0x40, 0x91, 0xd0, 0x3a, 0x2a, + 0x4b, 0xe4, 0x16, 0x57, 0x45, 0xdb, 0x20, 0x50, 0x15, 0xab, 0x8d, 0xa2, 0xdc, 0xaf, 0x15, 0x41, 0x18, 0x90, 0x22, + 0x1b, 0xba, 0x2b, 0x04, 0xff, 0x4b, 0xc8, 0x4e, 0xf6, 0x15, 0x1e, 0xae, 0xec, 0xcb, 0x50, 0xd4, 0x35, 0x05, 0x25, + 0xb6, 0x06, 0xa9, 0xc0, 0x6f, 0x04, 0x7e, 0x73, 0x25, 0xab, 0x1a, 0xe9, 0x05, 0x6a, 0x15, 0x48, 0xf9, 0x96, 0x51, + 0x53, 0x86, 0x3c, 0x49, 0xc2, 0x69, 0x4e, 0x03, 0xf3, 0x43, 0x0b, 0x32, 0x90, 0x87, 0xeb, 0x9a, 0x83, 0xce, 0xc7, + 0x39, 0x03, 0xfd, 0x62, 0x5d, 0xad, 0x99, 0x87, 0x99, 0xd7, 0x6c, 0x0e, 0x9b, 0xd7, 0x63, 0x54, 0x88, 0x78, 0x61, + 0x8b, 0xc1, 0x47, 0xad, 0x56, 0x17, 0x92, 0x27, 0x9b, 0x61, 0xc2, 0xc6, 0x69, 0x90, 0xd0, 0x91, 0x28, 0x04, 0x9c, + 0x6a, 0x5b, 0x18, 0xbd, 0xc3, 0xef, 0x1c, 0x65, 0x74, 0xe2, 0xf8, 0xf0, 0xef, 0xfd, 0x03, 0x17, 0x22, 0x0a, 0x52, + 0x11, 0x37, 0x65, 0x92, 0x2e, 0x1c, 0x31, 0x10, 0x71, 0xed, 0x79, 0x61, 0x0d, 0x34, 0xa4, 0xa0, 0x93, 0x15, 0x22, + 0x73, 0x44, 0x8c, 0x45, 0x66, 0xd7, 0x4b, 0xd1, 0x62, 0x6d, 0x06, 0xeb, 0xaa, 0xc1, 0x01, 0x2a, 0x72, 0xa9, 0x49, + 0xaf, 0x57, 0x36, 0xfa, 0x55, 0xfd, 0x69, 0x0d, 0x7d, 0x96, 0x26, 0x58, 0x28, 0x4f, 0xf4, 0x42, 0xb5, 0x78, 0x08, + 0x32, 0x6b, 0x3a, 0x2a, 0xb6, 0x5b, 0xa0, 0x82, 0xa5, 0xd3, 0x99, 0x18, 0x48, 0x2f, 0x78, 0x06, 0xe7, 0x29, 0x2e, + 0xb0, 0x55, 0x02, 0x38, 0xb8, 0x58, 0x28, 0x60, 0x86, 0x61, 0x32, 0xf4, 0x00, 0x22, 0xa7, 0xe9, 0x1c, 0x67, 0x74, + 0x82, 0xba, 0x13, 0x96, 0x36, 0xd5, 0xbb, 0x23, 0x4b, 0x8f, 0xf1, 0x1f, 0xc3, 0x53, 0xe1, 0xcb, 0xde, 0xb0, 0x4c, + 0x76, 0xdd, 0x80, 0xcb, 0xab, 0x8b, 0xa2, 0xe8, 0x66, 0xc2, 0x1b, 0xbc, 0xf2, 0xd0, 0x05, 0xfe, 0xca, 0xba, 0xce, + 0xc5, 0x35, 0x5b, 0xc5, 0xc5, 0x1d, 0xb4, 0xa5, 0x8a, 0xbd, 0x17, 0x64, 0xb5, 0xaf, 0x08, 0x54, 0x7c, 0xea, 0xb9, + 0x34, 0x9f, 0x36, 0x15, 0xb3, 0x6b, 0x4a, 0x92, 0x75, 0xa1, 0x29, 0xd2, 0xae, 0xdd, 0xbf, 0x8a, 0x85, 0xe4, 0x63, + 0xfa, 0x4c, 0x87, 0xf2, 0x3e, 0x5c, 0x94, 0x67, 0x80, 0xf4, 0xb3, 0x7d, 0xea, 0x07, 0xd5, 0xf8, 0xc9, 0xd5, 0x69, + 0x9d, 0x29, 0x02, 0x23, 0x2b, 0xef, 0xbc, 0x0b, 0x93, 0x04, 0x06, 0xbc, 0x32, 0xfa, 0x8e, 0x7d, 0x49, 0xc8, 0x40, + 0x5c, 0x78, 0xa8, 0xd0, 0xfb, 0xf4, 0xa9, 0xd4, 0x41, 0xad, 0x8b, 0xf6, 0x76, 0x84, 0x89, 0x2e, 0x29, 0x71, 0xcd, + 0x20, 0x3e, 0x5e, 0xcb, 0xa3, 0xee, 0x56, 0xbc, 0x4b, 0x69, 0xb0, 0x8e, 0x9c, 0x10, 0x71, 0xb3, 0x34, 0x72, 0x9d, + 0xbf, 0x0c, 0x13, 0x36, 0xfc, 0x48, 0xdc, 0xdd, 0x85, 0x87, 0xd6, 0x8f, 0x49, 0x4a, 0xae, 0x60, 0x38, 0x3c, 0xaa, + 0x7b, 0xde, 0x33, 0xdf, 0x62, 0xde, 0xea, 0x1e, 0x1d, 0xb7, 0xb7, 0xbb, 0x00, 0xc6, 0xa3, 0xc6, 0xe9, 0x5d, 0x15, + 0x97, 0xd5, 0xf5, 0x58, 0x15, 0x14, 0x80, 0x66, 0x55, 0xee, 0x48, 0xa2, 0x22, 0xee, 0x27, 0x29, 0xcd, 0x75, 0x14, + 0x53, 0x03, 0x38, 0x85, 0xe6, 0x6f, 0xae, 0xf3, 0x97, 0xb2, 0x8c, 0x96, 0x2e, 0x10, 0x99, 0xc3, 0x41, 0x5c, 0x18, + 0x0b, 0xec, 0x5e, 0x3f, 0xa2, 0x22, 0x64, 0x89, 0x6a, 0xd2, 0x35, 0x16, 0xfb, 0xca, 0x8c, 0x96, 0xcb, 0xbc, 0x3e, + 0x17, 0x56, 0xc7, 0xa0, 0x9c, 0xd9, 0xc9, 0x7e, 0x05, 0xb7, 0x9c, 0x99, 0xdc, 0x93, 0x76, 0x2c, 0xb1, 0x9a, 0xa1, + 0x7a, 0xe7, 0xfc, 0x65, 0x28, 0x4f, 0x19, 0x01, 0x80, 0x5c, 0x03, 0x08, 0x51, 0x6e, 0x75, 0x8a, 0xc6, 0x4b, 0x08, + 0xf7, 0x45, 0x98, 0x8d, 0xa9, 0x58, 0x41, 0x6c, 0xa2, 0x92, 0x5a, 0xbb, 0x26, 0xa2, 0xbd, 0x06, 0x6d, 0x58, 0x87, + 0xf6, 0x0a, 0x90, 0xde, 0xdf, 0x5d, 0xb0, 0x82, 0xec, 0x2e, 0x94, 0x5c, 0xfb, 0xf0, 0xee, 0x2b, 0x38, 0x14, 0xc9, + 0x53, 0xb0, 0x44, 0x62, 0x04, 0x92, 0x56, 0x2e, 0x8e, 0x12, 0x21, 0x5c, 0x8a, 0x10, 0xc5, 0x09, 0x1c, 0x39, 0x96, + 0x04, 0xb1, 0x70, 0x9d, 0xbe, 0x82, 0x9c, 0x46, 0x0a, 0x66, 0x92, 0xc9, 0x56, 0xbc, 0x38, 0xd9, 0x57, 0xb5, 0x95, + 0x08, 0x50, 0x95, 0x00, 0x09, 0x72, 0x9f, 0x56, 0x38, 0x80, 0x44, 0x68, 0x1b, 0x0f, 0x11, 0x9b, 0x97, 0xc4, 0x26, + 0xcf, 0x5b, 0xf5, 0x4e, 0x92, 0xf0, 0x9a, 0x26, 0xbd, 0xdd, 0x45, 0xb6, 0x5c, 0xb6, 0x8a, 0x93, 0x7d, 0xf5, 0xe8, + 0x9c, 0x48, 0xbe, 0xa1, 0xee, 0xc8, 0x94, 0x4b, 0x0c, 0x87, 0x18, 0x21, 0x3d, 0xd4, 0xe4, 0x45, 0x05, 0xba, 0x83, + 0xc2, 0x75, 0x64, 0x46, 0x86, 0xac, 0x54, 0x6a, 0x50, 0x85, 0xeb, 0xb0, 0x68, 0xbd, 0x2c, 0x17, 0x74, 0x0a, 0xa5, + 0xf1, 0x72, 0xd9, 0x2e, 0x5c, 0x67, 0xc2, 0x52, 0x78, 0xca, 0x96, 0x4b, 0x79, 0x3e, 0x70, 0xc2, 0x52, 0xaf, 0x05, + 0x64, 0xeb, 0x3a, 0x93, 0xf0, 0x56, 0x4e, 0xd8, 0xbc, 0x09, 0x6f, 0xbd, 0xb6, 0x7e, 0xe5, 0x97, 0xf8, 0xc9, 0x81, + 0xe2, 0xaa, 0x15, 0x4d, 0xf4, 0x8a, 0x46, 0x78, 0xa6, 0x4e, 0x3e, 0x11, 0x2f, 0x22, 0xc9, 0xe6, 0x15, 0x8d, 0xcc, + 0x8a, 0xce, 0xb6, 0xac, 0xe8, 0xec, 0x9e, 0x15, 0x0d, 0xf5, 0xea, 0x39, 0x25, 0xee, 0xf8, 0x72, 0xd9, 0x6e, 0x55, + 0xd8, 0x3b, 0xd9, 0x8f, 0xd8, 0x1c, 0x56, 0x03, 0xf4, 0x42, 0xc1, 0x26, 0x74, 0x33, 0x51, 0xd6, 0x51, 0x4c, 0x7f, + 0x15, 0x26, 0x2b, 0x2c, 0x64, 0x75, 0x2c, 0xd8, 0x74, 0x5d, 0x06, 0xe9, 0xfe, 0x48, 0xca, 0x66, 0x80, 0x87, 0x1c, + 0xf0, 0x10, 0x9b, 0x3b, 0x33, 0x3d, 0xf7, 0xbd, 0x8b, 0x5d, 0xc7, 0x35, 0x64, 0x7d, 0x55, 0x5c, 0x82, 0x8c, 0x90, + 0xf3, 0x7b, 0x10, 0x2d, 0x42, 0x6d, 0xb7, 0xb7, 0x9d, 0xe6, 0x20, 0x9e, 0x7e, 0xc3, 0xb3, 0xc8, 0x0d, 0x54, 0xd5, + 0x5f, 0x85, 0xaa, 0x09, 0x4b, 0x75, 0x76, 0xd6, 0x56, 0x5a, 0xab, 0xde, 0xdb, 0x14, 0xd7, 0x39, 0x3a, 0x52, 0x35, + 0xa6, 0xa1, 0x10, 0x34, 0x4b, 0x35, 0xe5, 0xba, 0xee, 0xff, 0x17, 0x54, 0xb8, 0x81, 0xaf, 0x84, 0x66, 0x01, 0x0c, + 0x01, 0x6a, 0x0d, 0x5f, 0xf3, 0x7c, 0x25, 0x9e, 0x76, 0x2a, 0x0d, 0xf6, 0x0e, 0xd9, 0x56, 0x86, 0x2a, 0x02, 0xa3, + 0x67, 0x36, 0xa1, 0xd1, 0xa5, 0x64, 0xd0, 0xfd, 0xe1, 0x95, 0x56, 0x58, 0x57, 0xc4, 0x5d, 0xd5, 0x00, 0xbb, 0x3f, + 0xce, 0x3a, 0x8f, 0x0f, 0xcf, 0x5c, 0xac, 0x78, 0x3c, 0x1f, 0x8d, 0x5c, 0x54, 0x38, 0x0f, 0x6b, 0xd6, 0x3e, 0xfc, + 0x71, 0xf6, 0xe5, 0xf3, 0xd6, 0x97, 0x65, 0xe3, 0x14, 0x88, 0x48, 0x27, 0x04, 0x18, 0x51, 0x65, 0xc1, 0x6b, 0x66, + 0x34, 0x0a, 0xd3, 0xed, 0xd3, 0x19, 0xd8, 0xd3, 0xc9, 0xa7, 0x94, 0x46, 0x40, 0x9c, 0x78, 0xad, 0xf4, 0x32, 0xa1, + 0x73, 0x6a, 0xee, 0x2a, 0xdc, 0x30, 0xd8, 0x86, 0x16, 0x43, 0x3e, 0x4b, 0x85, 0xce, 0x8c, 0xd0, 0xac, 0xd6, 0x9a, + 0xd2, 0x95, 0x9c, 0x83, 0x6d, 0x23, 0xdc, 0x29, 0x39, 0x57, 0x97, 0x5e, 0xc5, 0x15, 0x76, 0x2d, 0x00, 0xb6, 0x42, + 0xd6, 0xdf, 0x52, 0x1e, 0xb4, 0x70, 0x6b, 0x1b, 0x6c, 0xb8, 0x8d, 0x02, 0xd7, 0xbd, 0x30, 0x78, 0x92, 0xce, 0xcd, + 0xda, 0x05, 0x13, 0x5b, 0xf1, 0xf5, 0x49, 0x0c, 0x5c, 0x67, 0xd0, 0x59, 0x4a, 0xf3, 0x7c, 0x2b, 0x02, 0xca, 0x45, + 0xc4, 0x6e, 0x55, 0xdb, 0xdd, 0xd2, 0x0b, 0x6e, 0x61, 0xd8, 0x61, 0x12, 0xe0, 0x32, 0xc4, 0xaa, 0x6b, 0xd1, 0xd1, + 0x88, 0x0e, 0x4b, 0xdf, 0x30, 0x04, 0xcb, 0x46, 0x2c, 0x11, 0x10, 0x33, 0x92, 0xc1, 0x1c, 0xf7, 0x35, 0x4f, 0xa9, + 0x8b, 0x4c, 0xfa, 0xa7, 0x86, 0x5f, 0xcb, 0xff, 0xcd, 0xf0, 0xa8, 0x1e, 0xeb, 0xb0, 0xe8, 0x51, 0x96, 0x4b, 0xe3, + 0x17, 0xaa, 0x95, 0xd7, 0x11, 0xc9, 0xa5, 0xe3, 0x67, 0xdb, 0x06, 0x7a, 0xd8, 0x36, 0x59, 0xb4, 0xbf, 0x3c, 0x6a, + 0xb7, 0x0a, 0x17, 0xbb, 0xd0, 0xdd, 0x43, 0x77, 0x89, 0x6c, 0x75, 0x00, 0xad, 0x66, 0xe9, 0xaf, 0x69, 0xd7, 0x69, + 0x3f, 0x69, 0xbb, 0x58, 0xdd, 0x3b, 0x80, 0x8a, 0x92, 0x19, 0x0c, 0xc1, 0x5b, 0xfa, 0xbb, 0xa7, 0x52, 0xef, 0xfc, + 0x61, 0xf0, 0x3c, 0x6a, 0xb7, 0x5c, 0xec, 0xe6, 0x82, 0x4f, 0x7f, 0xc5, 0x14, 0x0e, 0x5c, 0xec, 0x0e, 0x13, 0x9e, + 0x53, 0x7b, 0x0e, 0x4a, 0x9d, 0xfd, 0xfd, 0x93, 0x50, 0x10, 0x4d, 0x33, 0x9a, 0xe7, 0x8e, 0xdd, 0xbf, 0x26, 0xa5, + 0x4f, 0x30, 0xcc, 0x8d, 0x14, 0x97, 0x53, 0x21, 0xf1, 0xa2, 0xae, 0x04, 0xb0, 0xa9, 0x4a, 0x95, 0xad, 0x11, 0x9b, + 0x14, 0x01, 0x25, 0x63, 0x53, 0xda, 0xd5, 0x27, 0x47, 0xde, 0xb0, 0xf5, 0xd4, 0xc0, 0x2a, 0x88, 0xbc, 0x3e, 0x40, + 0xad, 0x64, 0xc2, 0xd2, 0xcb, 0x0d, 0xa5, 0xe1, 0xed, 0x86, 0x52, 0x50, 0xd9, 0x4a, 0xe8, 0xf4, 0x75, 0x35, 0x9f, + 0xc6, 0x7a, 0xa5, 0xf8, 0xd8, 0x20, 0x46, 0xd2, 0xd1, 0xf9, 0x09, 0x48, 0xad, 0x65, 0x90, 0x3d, 0xfc, 0xf6, 0xe1, + 0xa0, 0xe4, 0xd7, 0x0c, 0x57, 0xf6, 0xf2, 0xfb, 0x66, 0x08, 0xa5, 0x4d, 0x70, 0x78, 0x27, 0xbf, 0x6a, 0xae, 0xf4, + 0xf6, 0xd3, 0x04, 0x67, 0x69, 0x55, 0xbf, 0x63, 0xe9, 0xf5, 0xb1, 0xf7, 0xd5, 0xb5, 0xdf, 0x50, 0xac, 0x15, 0x9f, + 0x72, 0xfd, 0x87, 0x09, 0x9b, 0x54, 0x24, 0xb0, 0x0e, 0xa6, 0xd4, 0x78, 0x20, 0xfb, 0xc9, 0xee, 0x44, 0xa9, 0x3e, + 0x97, 0x70, 0xa6, 0x13, 0xae, 0xcd, 0x98, 0x65, 0xf4, 0x32, 0xe1, 0x37, 0xab, 0xf7, 0x80, 0x6d, 0xaf, 0x1c, 0xb3, + 0x71, 0x6c, 0x1d, 0xd4, 0xa2, 0xa4, 0x5c, 0x84, 0x7b, 0x07, 0x28, 0xfe, 0xe5, 0x9f, 0x7d, 0xff, 0x5f, 0xfe, 0xf9, + 0x93, 0x55, 0xa1, 0xfb, 0xe2, 0x0a, 0x8b, 0xaa, 0xdb, 0xed, 0xbb, 0x6b, 0xf3, 0x48, 0x75, 0x9c, 0x6f, 0xae, 0xb3, + 0xb6, 0x08, 0xf0, 0x7e, 0x6d, 0x09, 0xd6, 0x0a, 0xd5, 0xee, 0x73, 0x7e, 0x0b, 0x60, 0x30, 0xaf, 0x4f, 0x42, 0x06, + 0x95, 0x7e, 0x17, 0x68, 0x57, 0x28, 0x78, 0xd0, 0x8a, 0xfc, 0x76, 0x0c, 0x7f, 0x6a, 0x0e, 0xbf, 0x13, 0x7c, 0xed, + 0x9f, 0x18, 0x5e, 0x5d, 0x95, 0x19, 0x79, 0x76, 0x53, 0x38, 0xef, 0xdf, 0x5f, 0x2b, 0xd1, 0x8a, 0x47, 0xd0, 0x42, + 0x3d, 0x79, 0x9e, 0x90, 0x0c, 0xaf, 0x5e, 0xc1, 0x25, 0x3f, 0x27, 0xd7, 0x99, 0x71, 0xf0, 0xde, 0x23, 0x1c, 0xa0, + 0x8b, 0xfa, 0xac, 0x64, 0xa7, 0x6b, 0x92, 0x01, 0x4a, 0xc1, 0xdc, 0x00, 0x30, 0xf1, 0xf0, 0x4a, 0x5b, 0x9b, 0x67, + 0xca, 0x0d, 0x13, 0xac, 0x92, 0xb6, 0x76, 0xcf, 0xd4, 0x90, 0x8e, 0x9d, 0xf7, 0x12, 0x5f, 0xb2, 0x32, 0xad, 0xac, + 0x7b, 0xe9, 0xea, 0x02, 0x3b, 0xa2, 0x64, 0x3f, 0xf3, 0x30, 0x99, 0x3f, 0x8c, 0xf1, 0x6d, 0x17, 0xa8, 0x4b, 0x67, + 0xf9, 0x6f, 0xad, 0x12, 0x2c, 0x9b, 0xcb, 0x9a, 0x3e, 0x20, 0xb3, 0x12, 0xfe, 0xbe, 0x2d, 0x70, 0x2a, 0xe8, 0x27, + 0x03, 0xa7, 0xc9, 0x83, 0x02, 0xa7, 0xea, 0x86, 0xbe, 0x3f, 0x32, 0x70, 0xfa, 0x77, 0x3b, 0x70, 0x0a, 0x24, 0xf8, + 0xf3, 0x83, 0x82, 0x9b, 0x26, 0xf0, 0xc4, 0x6f, 0x72, 0xd2, 0xd6, 0x46, 0x40, 0xc2, 0xc7, 0x10, 0xd9, 0xfc, 0xb7, + 0x0f, 0x54, 0x26, 0x7c, 0x6c, 0x87, 0x29, 0xe1, 0x8e, 0x5a, 0x88, 0x4b, 0xe2, 0x8c, 0x2c, 0xdc, 0x1f, 0x6f, 0xdb, + 0x4f, 0x07, 0xed, 0xee, 0x41, 0x7b, 0xe2, 0x06, 0x2e, 0x48, 0x5d, 0x59, 0xd0, 0xea, 0x1e, 0x1c, 0x40, 0xc1, 0x8d, + 0x55, 0xd0, 0x81, 0x02, 0x66, 0x15, 0x1c, 0x41, 0xc1, 0xd0, 0x2a, 0x78, 0x04, 0x05, 0x91, 0x55, 0xf0, 0x18, 0x0a, + 0xe6, 0x6e, 0x31, 0x60, 0x65, 0x74, 0xf8, 0x31, 0x92, 0xd7, 0x59, 0xec, 0x64, 0xf5, 0x54, 0xfe, 0x98, 0x98, 0x2a, + 0x8f, 0xcb, 0x63, 0x40, 0xcd, 0x43, 0x73, 0x6b, 0xc5, 0xd5, 0x67, 0x57, 0x08, 0x27, 0x04, 0x4e, 0xe5, 0x61, 0x30, + 0xca, 0x55, 0xcd, 0x03, 0xf3, 0xda, 0x0d, 0xca, 0x7b, 0xa9, 0x5a, 0xb8, 0x63, 0x22, 0x9c, 0x81, 0x8b, 0xf0, 0xac, + 0xac, 0x7c, 0xd4, 0x88, 0x74, 0xb7, 0x70, 0x21, 0x44, 0x75, 0x1b, 0xcb, 0x01, 0xc2, 0xea, 0x02, 0xec, 0x67, 0x52, + 0x3e, 0xfa, 0x82, 0xbf, 0x67, 0x13, 0x6a, 0x3e, 0x0f, 0x62, 0x06, 0x70, 0x5c, 0x04, 0x07, 0xb8, 0xe3, 0xea, 0x0a, + 0xb3, 0x2f, 0xf1, 0x69, 0x75, 0x01, 0xd0, 0x5b, 0x41, 0xd4, 0x8d, 0x0a, 0x19, 0x56, 0x86, 0xde, 0x18, 0x8b, 0x70, + 0x1c, 0x40, 0xc8, 0x12, 0x7c, 0xa6, 0xc1, 0x29, 0x21, 0xa4, 0xd5, 0x9f, 0x05, 0x5f, 0xe2, 0x9b, 0x98, 0xa6, 0xc1, + 0xbc, 0xe8, 0x96, 0x04, 0xa0, 0x22, 0xa6, 0x6f, 0x45, 0x79, 0x6f, 0x9c, 0xa4, 0x8a, 0xea, 0xb5, 0x82, 0xb3, 0x59, + 0x52, 0xcf, 0x96, 0x58, 0x9a, 0xe5, 0x93, 0x19, 0x25, 0xfc, 0xa6, 0x79, 0xeb, 0xf6, 0x36, 0xc7, 0xd7, 0x60, 0x76, + 0x65, 0x7c, 0x4d, 0x02, 0x5b, 0x3e, 0xbd, 0x0f, 0xc7, 0xe5, 0xef, 0x57, 0x34, 0xcf, 0xc3, 0xb1, 0xae, 0xb9, 0x3d, + 0x9e, 0x26, 0x41, 0xb4, 0x63, 0x69, 0x06, 0x08, 0x88, 0x89, 0x01, 0x46, 0xc0, 0xa7, 0xa1, 0x43, 0x64, 0x30, 0xf5, + 0x7a, 0x74, 0x4d, 0x0e, 0x5f, 0x2f, 0x12, 0xe1, 0xb8, 0x2a, 0x38, 0x99, 0x66, 0x54, 0x96, 0x2a, 0x34, 0x16, 0x27, + 0xfb, 0x50, 0xa0, 0x5e, 0x6f, 0x89, 0xa2, 0x19, 0x07, 0xca, 0xf6, 0x58, 0x9a, 0x63, 0xa2, 0x68, 0x76, 0xa2, 0x52, + 0x99, 0xa5, 0xb4, 0x1e, 0xbb, 0xf9, 0xbc, 0x3d, 0x84, 0x3f, 0x3a, 0x32, 0xf4, 0xf9, 0x68, 0x34, 0xba, 0x37, 0xaa, + 0xf6, 0x79, 0x34, 0xa2, 0x1d, 0x7a, 0xd4, 0x85, 0x24, 0x96, 0xa6, 0x8e, 0xc5, 0xb4, 0x0b, 0x89, 0xbb, 0xc5, 0xc3, + 0x2a, 0x43, 0xd8, 0x46, 0xc4, 0x8b, 0x87, 0x47, 0xd8, 0x8a, 0x69, 0x46, 0x17, 0x93, 0x30, 0x1b, 0xb3, 0x34, 0x68, + 0x15, 0xfe, 0x5c, 0x87, 0xa4, 0x3e, 0x3f, 0x3e, 0x3e, 0x2e, 0xfc, 0xc8, 0x3c, 0xb5, 0xa2, 0xa8, 0xf0, 0x87, 0x8b, + 0x72, 0x1a, 0xad, 0xd6, 0x68, 0x54, 0xf8, 0xcc, 0x14, 0x1c, 0x74, 0x86, 0xd1, 0x41, 0xa7, 0xf0, 0x6f, 0xac, 0x1a, + 0x85, 0x4f, 0xf5, 0x53, 0x46, 0xa3, 0x5a, 0x26, 0xcc, 0xe3, 0x56, 0xab, 0xf0, 0x15, 0xa1, 0x2d, 0xc0, 0x2c, 0x55, + 0x3f, 0x83, 0x70, 0x26, 0x38, 0x30, 0xf7, 0x6e, 0x22, 0xbc, 0xc1, 0xa5, 0xbe, 0x65, 0x44, 0x7d, 0x93, 0xa3, 0x40, + 0x17, 0xf8, 0x67, 0x3b, 0x78, 0x04, 0xc4, 0x2c, 0x83, 0x46, 0x89, 0x89, 0x2d, 0xd5, 0x5e, 0x03, 0x65, 0xc9, 0xd7, + 0x3f, 0x93, 0xa4, 0x8a, 0x29, 0x01, 0x27, 0x83, 0x9a, 0xea, 0x32, 0x3c, 0x4a, 0xb7, 0xc8, 0x0f, 0xf6, 0x69, 0xf9, + 0x71, 0xf7, 0x10, 0xf1, 0xc1, 0xfe, 0x70, 0xf1, 0x41, 0xa9, 0x25, 0x3e, 0x14, 0xf3, 0xb8, 0x13, 0xc4, 0x1d, 0xc6, + 0x74, 0xf8, 0xf1, 0x9a, 0xdf, 0x36, 0x61, 0x4b, 0x64, 0xae, 0x14, 0x2c, 0xbb, 0xbf, 0x35, 0x6b, 0xc6, 0x74, 0x66, + 0x7d, 0xd1, 0x43, 0xaa, 0x0f, 0x6f, 0x52, 0xe2, 0xbe, 0x31, 0xb6, 0xad, 0x2a, 0x19, 0x8d, 0x88, 0xfb, 0x66, 0x34, + 0x72, 0xcd, 0x59, 0xc9, 0x50, 0x50, 0x59, 0xeb, 0x75, 0xad, 0x44, 0xd6, 0xfa, 0xf2, 0x4b, 0xbb, 0xcc, 0x2e, 0xd0, + 0xa1, 0x27, 0x3b, 0xcc, 0xa4, 0xdf, 0x44, 0x2c, 0x87, 0xad, 0x06, 0x1f, 0x1a, 0xa9, 0xdf, 0xd5, 0x98, 0xd6, 0xae, + 0xd5, 0x2e, 0x01, 0xde, 0x70, 0x17, 0xf8, 0xea, 0x45, 0x01, 0x63, 0x6a, 0xf2, 0x16, 0x9f, 0xde, 0x7d, 0x15, 0x79, + 0x77, 0x02, 0x15, 0x2c, 0x7f, 0x93, 0xae, 0x1c, 0x02, 0x52, 0x30, 0x12, 0x62, 0x4f, 0xab, 0x10, 0x7c, 0x3c, 0x4e, + 0xe0, 0x5b, 0x2f, 0x8b, 0xda, 0xfd, 0xb1, 0xaa, 0x79, 0xbf, 0x36, 0xdf, 0xc0, 0x6e, 0xa8, 0x6f, 0x5b, 0x95, 0x9f, + 0x9e, 0x52, 0xc9, 0xe3, 0x73, 0xfd, 0x0d, 0x22, 0x69, 0x16, 0x2f, 0x34, 0x93, 0x5f, 0xa8, 0x94, 0x63, 0x01, 0xe9, + 0x36, 0xaa, 0xe3, 0xa8, 0x28, 0xf4, 0x61, 0x8d, 0x88, 0xe5, 0x53, 0xb8, 0xd7, 0x54, 0xb5, 0xa4, 0x9f, 0x62, 0xe1, + 0xf9, 0x8d, 0x15, 0xdf, 0xa9, 0x2d, 0x57, 0x61, 0x02, 0x3c, 0xca, 0x61, 0x7e, 0x27, 0x0a, 0x57, 0xfb, 0xdd, 0x0d, + 0x12, 0x5d, 0x47, 0xe1, 0x53, 0x45, 0x9e, 0xac, 0x19, 0x82, 0xf3, 0xbb, 0x5c, 0x10, 0xf3, 0xca, 0x14, 0x14, 0x76, + 0xfc, 0x52, 0xbe, 0x51, 0xd8, 0x92, 0xd1, 0x92, 0x7c, 0x1a, 0xa6, 0x8a, 0x8d, 0x12, 0x57, 0xf1, 0x83, 0xdd, 0x45, + 0xb5, 0xf2, 0x85, 0x6b, 0xc0, 0x56, 0xc4, 0xdb, 0x3b, 0xd9, 0x87, 0x06, 0x3d, 0xa7, 0x06, 0x7a, 0xba, 0x16, 0x64, + 0xf9, 0x44, 0xba, 0xc3, 0x95, 0x9f, 0xdf, 0x60, 0x3f, 0xbf, 0x71, 0xfe, 0xbc, 0x68, 0xde, 0xd0, 0xeb, 0x8f, 0x4c, + 0x34, 0x45, 0x38, 0x6d, 0x82, 0xe1, 0x23, 0x9d, 0xa3, 0x9a, 0x3d, 0xcb, 0x2c, 0x3f, 0x75, 0xd5, 0x41, 0x77, 0x96, + 0x43, 0x56, 0x84, 0x54, 0xdf, 0x83, 0x94, 0xa7, 0xb4, 0x5b, 0xcf, 0xe6, 0xb4, 0x83, 0xec, 0x06, 0x5b, 0x17, 0x0b, + 0x0e, 0x59, 0x14, 0xe2, 0x2e, 0x68, 0x69, 0xb6, 0xde, 0x32, 0x11, 0xf4, 0xd6, 0xc6, 0xfa, 0x81, 0x46, 0x6e, 0x43, + 0x4a, 0xaf, 0x6c, 0x3d, 0x93, 0x60, 0x5b, 0x26, 0xc0, 0xa7, 0x72, 0x1b, 0xc1, 0xa5, 0x6a, 0xfe, 0x5a, 0x49, 0xa1, + 0xab, 0xc5, 0x32, 0xb7, 0xf1, 0x21, 0x90, 0x05, 0xe1, 0x48, 0xd0, 0x0c, 0x3f, 0xa4, 0xe6, 0xb5, 0x3c, 0x86, 0xb4, + 0x00, 0x31, 0x13, 0xb4, 0x8f, 0xa7, 0xb7, 0x0f, 0xef, 0xfe, 0xfe, 0xe9, 0x17, 0x1a, 0x47, 0xe6, 0x5a, 0x1e, 0xd7, + 0xed, 0xc2, 0x46, 0x48, 0xc2, 0xbb, 0x80, 0xa5, 0x52, 0xe6, 0x5d, 0x83, 0x5f, 0xb4, 0x3b, 0xe5, 0x3a, 0x49, 0x37, + 0xa3, 0x89, 0xfc, 0x0a, 0x9f, 0x5e, 0x8a, 0x83, 0x47, 0xd3, 0x5b, 0xb3, 0x1a, 0xed, 0x95, 0xe4, 0xdb, 0x3f, 0x34, + 0xc7, 0x76, 0x7b, 0x52, 0x6f, 0x3d, 0x4f, 0xf4, 0x68, 0x7a, 0xdb, 0x55, 0x82, 0xb6, 0x99, 0x29, 0xa8, 0x5a, 0xd3, + 0x5b, 0x3b, 0xcb, 0xb8, 0xea, 0xc8, 0xf1, 0x0f, 0x72, 0x87, 0x86, 0x39, 0xed, 0xc2, 0xbd, 0xe3, 0x6c, 0x18, 0x26, + 0x5a, 0x98, 0x4f, 0x58, 0x14, 0x25, 0xb4, 0x6b, 0xe4, 0xb5, 0xd3, 0x7e, 0x04, 0x49, 0xba, 0xf6, 0x92, 0xd5, 0x57, + 0xc5, 0x42, 0x5e, 0x89, 0xa7, 0xf0, 0x3a, 0xe7, 0x09, 0x7c, 0xf4, 0x63, 0x23, 0x3a, 0x75, 0xf6, 0x6a, 0xab, 0x42, + 0x9e, 0xfc, 0x5d, 0x9f, 0xcb, 0x51, 0xeb, 0x4f, 0x5d, 0xb9, 0xe0, 0xad, 0xae, 0xe0, 0xd3, 0xa0, 0x79, 0x50, 0x9f, + 0x08, 0xbc, 0x2a, 0xa7, 0x80, 0x37, 0x4c, 0x0b, 0x83, 0xb4, 0x52, 0x7c, 0xda, 0xf1, 0xdb, 0xba, 0x4c, 0x76, 0x00, + 0x79, 0x61, 0x65, 0x51, 0x51, 0x9f, 0xcc, 0xbf, 0xcd, 0x6e, 0x79, 0xb2, 0x79, 0xb7, 0x3c, 0x31, 0xbb, 0xe5, 0x7e, + 0x8a, 0xfd, 0x7c, 0xd4, 0x86, 0x3f, 0xdd, 0x6a, 0x42, 0x41, 0xcb, 0x39, 0x98, 0xde, 0x3a, 0xa0, 0xa7, 0x35, 0x3b, + 0xd3, 0x5b, 0x95, 0x63, 0x0d, 0xb1, 0x9b, 0x16, 0x64, 0x1d, 0xe3, 0x96, 0x03, 0x85, 0xf0, 0xb7, 0x55, 0x7b, 0xd5, + 0x3e, 0x84, 0x77, 0xd0, 0xea, 0x68, 0xfd, 0x5d, 0xe7, 0xfe, 0x4d, 0x1b, 0xa4, 0x5c, 0x78, 0x81, 0xe1, 0xc6, 0xc8, + 0x17, 0xe1, 0xf5, 0x35, 0x8d, 0x82, 0x11, 0x1f, 0xce, 0xf2, 0x7f, 0xd2, 0xf0, 0x6b, 0x24, 0xde, 0xbb, 0xa5, 0x57, + 0xfa, 0x31, 0x4d, 0x55, 0xc6, 0xb7, 0xe9, 0x61, 0x51, 0xae, 0x53, 0x90, 0x0f, 0xc3, 0x84, 0x7a, 0x1d, 0xff, 0x70, + 0xc3, 0x26, 0xf8, 0x77, 0x59, 0x9b, 0x8d, 0x93, 0xf9, 0xbd, 0xc8, 0xb8, 0x17, 0x09, 0xbf, 0x0a, 0x07, 0xf6, 0x1a, + 0xb6, 0x8e, 0x37, 0x83, 0x3b, 0x30, 0x23, 0x5d, 0x18, 0xa1, 0xa0, 0xe5, 0x4e, 0x44, 0x47, 0xe1, 0x2c, 0x11, 0xf7, + 0xf7, 0xba, 0x8d, 0x32, 0xd6, 0x7a, 0xbd, 0x87, 0xa1, 0x57, 0x75, 0x1f, 0xc8, 0xa5, 0x3f, 0x7f, 0x72, 0x08, 0x7f, + 0x54, 0xfe, 0xd7, 0x5d, 0xa5, 0xab, 0x2b, 0xbb, 0x17, 0x74, 0xf5, 0xdd, 0x9a, 0x32, 0xae, 0x44, 0xb8, 0xd4, 0xc7, + 0x1f, 0x5a, 0x1b, 0xb4, 0xca, 0x07, 0x55, 0xd7, 0x5a, 0xd6, 0xaf, 0xaa, 0xfd, 0xeb, 0x3a, 0x7f, 0x60, 0xdd, 0xa1, + 0xd2, 0x5c, 0xeb, 0x75, 0xf5, 0x67, 0x08, 0xd7, 0x2a, 0x1b, 0x8c, 0xcb, 0xfa, 0xbb, 0xe4, 0xae, 0x34, 0x51, 0x54, + 0x34, 0x16, 0xac, 0x94, 0x5d, 0x65, 0xa5, 0xe4, 0x94, 0x5c, 0x9d, 0xf4, 0x6f, 0x27, 0x89, 0x33, 0x57, 0xc7, 0x25, + 0x89, 0xdb, 0xf6, 0x5b, 0xae, 0x23, 0xf3, 0x00, 0xe0, 0xd6, 0x76, 0x57, 0x7e, 0xde, 0xd6, 0xed, 0x83, 0xa6, 0x35, + 0x1f, 0x4b, 0xcd, 0xee, 0x65, 0x78, 0x47, 0xb3, 0xcb, 0x8e, 0xeb, 0x80, 0x9f, 0xa6, 0xa9, 0x52, 0x26, 0x64, 0x99, + 0xd3, 0x71, 0x9d, 0xdb, 0x49, 0x92, 0xe6, 0xc4, 0x8d, 0x85, 0x98, 0x06, 0xea, 0xfb, 0xb7, 0x37, 0x07, 0x3e, 0xcf, + 0xc6, 0xfb, 0x9d, 0x56, 0xab, 0x05, 0x17, 0xc0, 0xba, 0xce, 0x9c, 0xd1, 0x9b, 0xa7, 0xfc, 0x96, 0xb8, 0x2d, 0xa7, + 0xe5, 0xb4, 0x3b, 0xc7, 0x4e, 0xbb, 0x73, 0xe8, 0x3f, 0x3a, 0x76, 0x7b, 0x9f, 0x39, 0xce, 0x49, 0x44, 0x47, 0x39, + 0xfc, 0x70, 0x9c, 0x13, 0xa9, 0x78, 0xa9, 0xdf, 0x8e, 0xe3, 0x0f, 0x93, 0xbc, 0xd9, 0x76, 0x16, 0xfa, 0xd1, 0x71, + 0xe0, 0x50, 0x69, 0xe0, 0x7c, 0x3e, 0xea, 0x8c, 0x0e, 0x47, 0x4f, 0xba, 0xba, 0xb8, 0xf8, 0xac, 0x56, 0x1d, 0xab, + 0xff, 0x3b, 0x56, 0xb3, 0x5c, 0x64, 0xfc, 0x23, 0xd5, 0x39, 0x89, 0x0e, 0x88, 0x9e, 0x8d, 0x4d, 0x3b, 0xeb, 0x23, + 0xb5, 0x8f, 0xaf, 0x87, 0xa3, 0x4e, 0x55, 0x5d, 0xc2, 0xb8, 0x5f, 0x02, 0x79, 0xb2, 0x6f, 0x40, 0x3f, 0xb1, 0xd1, + 0xd4, 0x6e, 0x6e, 0x42, 0x54, 0xdb, 0xd5, 0x73, 0x1c, 0x9b, 0xf9, 0x9d, 0xc0, 0x19, 0x06, 0xa3, 0xab, 0x4a, 0x08, + 0x5c, 0x27, 0x22, 0xee, 0xab, 0x76, 0xe7, 0x18, 0xb7, 0xdb, 0x8f, 0xfc, 0x47, 0xc7, 0xc3, 0x16, 0x3e, 0xf4, 0x0f, + 0x9b, 0x07, 0xfe, 0x23, 0x7c, 0xdc, 0x3c, 0xc6, 0xc7, 0x2f, 0x8e, 0x87, 0xcd, 0x43, 0xff, 0x10, 0xb7, 0x9a, 0xc7, + 0x50, 0xd8, 0x3c, 0x6e, 0x1e, 0xcf, 0x9b, 0x87, 0xc7, 0xc3, 0x96, 0x2c, 0xed, 0xf8, 0x47, 0x47, 0xcd, 0x76, 0xcb, + 0x3f, 0x3a, 0xc2, 0x47, 0xfe, 0xa3, 0x47, 0xcd, 0xf6, 0x81, 0xff, 0xe8, 0xd1, 0xcb, 0xa3, 0x63, 0xff, 0x00, 0xde, + 0x1d, 0x1c, 0x0c, 0x0f, 0xfc, 0x76, 0xbb, 0x09, 0xff, 0xe0, 0x63, 0xbf, 0xa3, 0x7e, 0xb4, 0xdb, 0xfe, 0x41, 0x1b, + 0xb7, 0x92, 0xa3, 0x8e, 0xff, 0xe8, 0x09, 0x96, 0xff, 0xca, 0x6a, 0x58, 0xfe, 0x03, 0xdd, 0xe0, 0x27, 0x7e, 0xe7, + 0x91, 0xfa, 0x25, 0x3b, 0x9c, 0x1f, 0x1e, 0xff, 0xe0, 0xee, 0x6f, 0x9d, 0x43, 0x5b, 0xcd, 0xe1, 0xf8, 0xc8, 0x3f, + 0x38, 0xc0, 0x87, 0x6d, 0xff, 0xf8, 0x20, 0x6e, 0x1e, 0x76, 0xfc, 0x47, 0x8f, 0x87, 0xcd, 0xb6, 0xff, 0xf8, 0x31, + 0x6e, 0x35, 0x0f, 0xfc, 0x0e, 0x6e, 0xfb, 0x87, 0x07, 0xf2, 0xc7, 0x81, 0xdf, 0x99, 0x3f, 0x7e, 0xe2, 0x3f, 0x3a, + 0x8a, 0x1f, 0xf9, 0x87, 0xdf, 0x1e, 0x1e, 0xfb, 0x9d, 0x83, 0xf8, 0xe0, 0x91, 0xdf, 0x79, 0x3c, 0x7f, 0xe4, 0x1f, + 0xc6, 0xcd, 0xce, 0xa3, 0x7b, 0x5b, 0xb6, 0x3b, 0x3e, 0xe0, 0x48, 0xbe, 0x86, 0x17, 0x58, 0xbf, 0x80, 0xbf, 0xb1, + 0x6c, 0xfb, 0xef, 0xd8, 0x4d, 0xbe, 0xde, 0xf4, 0x89, 0x7f, 0xfc, 0x78, 0xa8, 0xaa, 0x43, 0x41, 0xd3, 0xd4, 0x80, + 0x26, 0xf3, 0xa6, 0x1a, 0x56, 0x76, 0xd7, 0x34, 0x1d, 0x99, 0xbf, 0x7a, 0xb0, 0x79, 0x13, 0x06, 0x56, 0xe3, 0xfe, + 0x87, 0xf6, 0x53, 0x2e, 0xf9, 0xc9, 0xfe, 0x58, 0x91, 0xfe, 0xb8, 0xf7, 0x99, 0xba, 0xdd, 0xf9, 0xb3, 0x2b, 0x9c, + 0x6e, 0x73, 0x7c, 0x64, 0x9f, 0x76, 0x7c, 0x70, 0xfa, 0x10, 0xcf, 0x47, 0xf6, 0x87, 0x7b, 0x3e, 0x52, 0xba, 0xe2, + 0x38, 0xbf, 0x16, 0x6b, 0x0e, 0x8e, 0x55, 0xab, 0xf8, 0xa9, 0xf0, 0x06, 0x39, 0x7c, 0x47, 0xac, 0xe8, 0x5e, 0x0b, + 0xc2, 0xa9, 0xed, 0x07, 0xe2, 0xc0, 0x62, 0xaf, 0x85, 0xe2, 0xb1, 0xc9, 0x36, 0x84, 0x84, 0x9f, 0x46, 0xc8, 0xb7, + 0x0f, 0xc1, 0x47, 0xf8, 0x87, 0xe3, 0x23, 0xb1, 0xf1, 0x51, 0xf3, 0xe5, 0x4b, 0x4f, 0x83, 0xf4, 0x14, 0x9c, 0xcb, + 0x67, 0x0f, 0x0e, 0x51, 0x35, 0xdc, 0x7d, 0x0a, 0x45, 0xb9, 0xab, 0x22, 0x5f, 0xef, 0x7e, 0x4d, 0xd8, 0x41, 0x9d, + 0x98, 0x24, 0xae, 0x76, 0xcb, 0x4c, 0xa5, 0xd4, 0xd1, 0x0f, 0xa5, 0x50, 0xea, 0xf8, 0x2d, 0xbf, 0x55, 0xba, 0x74, + 0xe0, 0x94, 0x2c, 0x59, 0x70, 0x11, 0xc2, 0x17, 0x6b, 0x13, 0x3e, 0x96, 0xdf, 0xb6, 0x85, 0xaf, 0x09, 0x40, 0xd2, + 0xcf, 0x50, 0x7d, 0xc8, 0x21, 0x70, 0x5d, 0x7d, 0xb7, 0x06, 0x9c, 0xc2, 0xfc, 0x06, 0x4e, 0xaa, 0x9a, 0xa8, 0xc4, + 0x04, 0xbc, 0x1d, 0xaf, 0x68, 0xc4, 0x42, 0xcf, 0xf5, 0xa6, 0x19, 0x1d, 0xd1, 0x2c, 0x6f, 0xd6, 0x8e, 0x6f, 0xca, + 0x93, 0x9b, 0xc8, 0x35, 0x9f, 0x46, 0xcd, 0xe0, 0x76, 0x6c, 0x32, 0xd0, 0xfe, 0x46, 0x57, 0x1b, 0x60, 0x6e, 0x81, + 0x4d, 0x49, 0x06, 0xb2, 0xb6, 0x52, 0xda, 0x5c, 0xa5, 0xb5, 0xb5, 0xfd, 0xce, 0x11, 0x72, 0x64, 0x31, 0xdc, 0x3b, + 0xfc, 0xbd, 0xd7, 0x3c, 0x68, 0xfd, 0x09, 0x59, 0xcd, 0xca, 0x8e, 0x2e, 0xb4, 0xbb, 0x2d, 0xad, 0xbe, 0x29, 0x5d, + 0x3f, 0x5b, 0xeb, 0x2a, 0x8a, 0xf8, 0x5c, 0xcd, 0xdd, 0x45, 0xdd, 0x54, 0x47, 0xb8, 0xd5, 0x0d, 0x11, 0x23, 0x36, + 0xf6, 0xec, 0x2f, 0x06, 0xab, 0x7b, 0x8d, 0xe5, 0x87, 0xc6, 0x51, 0x51, 0x55, 0x49, 0xd1, 0x42, 0xc6, 0x5b, 0x58, + 0xea, 0xa4, 0xcb, 0xa5, 0x97, 0x82, 0x8b, 0x9c, 0x58, 0x38, 0x85, 0x67, 0x54, 0x43, 0x72, 0x8a, 0x4b, 0x80, 0x24, + 0x82, 0x49, 0xaa, 0xfe, 0xaf, 0x8a, 0xcd, 0x0f, 0xed, 0xf8, 0xf2, 0x93, 0x30, 0x1d, 0x03, 0x15, 0x86, 0xe9, 0x78, + 0xcd, 0xad, 0xa6, 0x42, 0x46, 0x2b, 0xa5, 0x55, 0x57, 0x95, 0xfb, 0x2c, 0x7f, 0x7a, 0xf7, 0x5e, 0x5f, 0x80, 0xe6, + 0x82, 0x77, 0x5a, 0x46, 0x38, 0xaa, 0xcb, 0x9a, 0x1b, 0xe4, 0x8b, 0x93, 0x09, 0x15, 0xa1, 0xca, 0xd7, 0x04, 0x7d, + 0x02, 0x4e, 0xcd, 0x3a, 0xda, 0x1a, 0x25, 0xae, 0x94, 0xee, 0x24, 0xa2, 0x73, 0x36, 0xd4, 0xa2, 0x1e, 0x3b, 0xfa, + 0xe6, 0x80, 0xa6, 0x5c, 0x1a, 0xd2, 0xc6, 0xca, 0x1f, 0x33, 0x0c, 0x65, 0x46, 0x3e, 0x49, 0xb9, 0xdb, 0xfb, 0xa2, + 0xfc, 0xfa, 0xe9, 0xb6, 0x45, 0x48, 0x58, 0xfa, 0x71, 0x90, 0xd1, 0xe4, 0x9f, 0xc8, 0x17, 0x6c, 0xc8, 0xd3, 0x2f, + 0x2e, 0xe0, 0xab, 0xf4, 0x7e, 0x9c, 0xd1, 0x11, 0xf9, 0x02, 0x64, 0x7c, 0x20, 0xad, 0x0f, 0x60, 0x84, 0x8d, 0xdb, + 0x49, 0x82, 0xa5, 0xc6, 0xf4, 0x00, 0x85, 0x48, 0x81, 0xeb, 0x76, 0x8e, 0x5c, 0x47, 0xd9, 0xc4, 0xf2, 0x77, 0x4f, + 0x89, 0x53, 0xa9, 0x04, 0x38, 0xed, 0x8e, 0x7f, 0x14, 0x77, 0xfc, 0x27, 0xf3, 0xc7, 0xfe, 0x71, 0xdc, 0x7e, 0x3c, + 0x6f, 0xc2, 0xff, 0x1d, 0xff, 0x49, 0xd2, 0xec, 0xf8, 0x4f, 0xe0, 0xef, 0xb7, 0x87, 0xfe, 0x51, 0xdc, 0x6c, 0xfb, + 0xc7, 0xf3, 0x03, 0xff, 0xe0, 0x65, 0xbb, 0xe3, 0x1f, 0x38, 0x6d, 0x47, 0xb5, 0x03, 0x76, 0xad, 0xb8, 0xf3, 0x17, + 0x2b, 0x1b, 0x62, 0x43, 0x38, 0x4e, 0xe5, 0x9c, 0xba, 0xd8, 0x2b, 0xbf, 0xb1, 0xa8, 0xf7, 0xa7, 0x76, 0xd6, 0x3d, + 0x0b, 0x33, 0xf8, 0xd0, 0x4d, 0x7d, 0xef, 0xd6, 0xde, 0xe1, 0x1a, 0xbf, 0xd8, 0x30, 0x04, 0xec, 0x70, 0x17, 0xdb, + 0x47, 0xef, 0xe1, 0xdc, 0xba, 0xbc, 0x17, 0xdc, 0x5c, 0x8f, 0xb8, 0x9d, 0xb4, 0x55, 0x45, 0x73, 0x05, 0xa3, 0x64, + 0x16, 0x4c, 0x7e, 0x81, 0x41, 0x0e, 0xf2, 0x55, 0x54, 0xac, 0x8e, 0x0f, 0xa9, 0xaf, 0x19, 0xb7, 0x6e, 0x1f, 0xa0, + 0xd5, 0x81, 0x8d, 0x88, 0xc1, 0x7d, 0x11, 0x45, 0x61, 0x40, 0xaf, 0xb9, 0x69, 0x2b, 0x2c, 0x49, 0x7e, 0x41, 0xf3, + 0xbe, 0x0b, 0x45, 0x6e, 0xe0, 0x4a, 0x17, 0x9f, 0x5b, 0x7e, 0xec, 0xa7, 0x24, 0xec, 0xaa, 0x00, 0xcb, 0x43, 0x57, + 0xb0, 0x6b, 0x01, 0x3f, 0x2e, 0xda, 0xdb, 0xdb, 0xba, 0x5f, 0xa4, 0x02, 0x09, 0x73, 0xad, 0xbe, 0x11, 0x62, 0xb3, + 0x22, 0xd7, 0x46, 0x74, 0xd9, 0xaf, 0x44, 0x21, 0xd2, 0x78, 0xba, 0xa6, 0xa1, 0xf0, 0xc3, 0x54, 0x25, 0xd1, 0x58, + 0x0c, 0x0b, 0xb7, 0xe9, 0x01, 0x2a, 0xb8, 0x08, 0xad, 0xef, 0x00, 0xeb, 0x7d, 0xce, 0x45, 0x68, 0xce, 0xd2, 0x5a, + 0xd7, 0x06, 0x81, 0xa3, 0x37, 0xee, 0xf4, 0xde, 0xbc, 0x3f, 0x75, 0xd4, 0xf6, 0x3c, 0xd9, 0x8f, 0x3b, 0xbd, 0x13, + 0xe9, 0x33, 0x51, 0x27, 0xf1, 0x88, 0x3a, 0x89, 0xe7, 0xe8, 0x53, 0x99, 0x10, 0x49, 0x2b, 0xf6, 0xd5, 0xb4, 0xa5, + 0xcd, 0xa0, 0xbc, 0xbd, 0x93, 0x59, 0x22, 0x18, 0xdc, 0x71, 0xbd, 0x2f, 0x8f, 0xe1, 0xc1, 0x82, 0x95, 0x79, 0xd8, + 0x5a, 0x3b, 0xbc, 0x16, 0xa9, 0xf1, 0x0d, 0x8f, 0x58, 0x42, 0x4d, 0xe6, 0xb5, 0xee, 0xaa, 0x3c, 0x29, 0xb0, 0x5e, + 0x3b, 0x9f, 0x5d, 0x4f, 0x98, 0x70, 0xcd, 0x79, 0x86, 0x0f, 0xba, 0xc1, 0x89, 0x1c, 0xaa, 0x77, 0x55, 0x68, 0xe7, + 0xb5, 0xf9, 0x9a, 0x4f, 0x7d, 0x49, 0xf5, 0xec, 0xb5, 0x84, 0x80, 0x13, 0x72, 0xf1, 0x41, 0xaf, 0x74, 0x17, 0xdb, + 0xef, 0x8a, 0x93, 0xfd, 0xf8, 0xa0, 0x77, 0x15, 0x4c, 0x75, 0x7f, 0x2f, 0xf9, 0x78, 0x73, 0x5f, 0x09, 0x1f, 0xf7, + 0xe5, 0x51, 0x10, 0x75, 0x48, 0xd9, 0x28, 0xbf, 0x3c, 0x71, 0x7b, 0x27, 0x5a, 0x19, 0x70, 0x64, 0x60, 0xdd, 0x3d, + 0x6a, 0x99, 0xd3, 0x25, 0x09, 0x1f, 0xc3, 0x86, 0x54, 0x4d, 0xac, 0x41, 0x6a, 0x1e, 0xf7, 0xb8, 0xdd, 0x3b, 0x09, + 0x1d, 0xc9, 0x5b, 0x24, 0xf3, 0xc8, 0x83, 0x7d, 0x68, 0x1c, 0xf3, 0x09, 0xf5, 0x19, 0xdf, 0xbf, 0xa1, 0xd7, 0xcd, + 0x70, 0xca, 0x2a, 0xf7, 0x36, 0x28, 0x1d, 0xe5, 0x90, 0xdc, 0x78, 0xc4, 0xf5, 0xd9, 0xab, 0x4e, 0xe5, 0x6e, 0x3b, + 0x04, 0x9b, 0xc7, 0xb8, 0xe6, 0xa4, 0x4f, 0xce, 0x02, 0x8b, 0xf7, 0x4e, 0xf6, 0xc3, 0x15, 0x8c, 0x48, 0x7e, 0x5f, + 0x68, 0x47, 0x3b, 0x18, 0x36, 0x40, 0x6f, 0xae, 0xa3, 0xc4, 0x81, 0x71, 0xc8, 0x6b, 0x41, 0x5d, 0xb8, 0xbd, 0x7f, + 0xfd, 0x1f, 0xff, 0x4b, 0xfb, 0xd8, 0x4f, 0xf6, 0xe3, 0xb6, 0xe9, 0x6b, 0x65, 0x55, 0x8a, 0x13, 0x38, 0xee, 0x59, + 0x05, 0x85, 0xe9, 0x6d, 0x73, 0x9c, 0xb1, 0xa8, 0x19, 0x87, 0xc9, 0xc8, 0xed, 0x6d, 0xc7, 0xa6, 0x7d, 0x6c, 0x4b, + 0x43, 0x5d, 0x2f, 0x02, 0x7a, 0xfd, 0x4d, 0x07, 0x8f, 0xcc, 0xf9, 0x15, 0xb9, 0xb5, 0xed, 0x63, 0x48, 0xd5, 0xee, + 0xab, 0x1d, 0x45, 0x4a, 0xf5, 0x27, 0xc2, 0x34, 0x07, 0x4c, 0x6b, 0x27, 0x90, 0x0a, 0xd7, 0x29, 0x83, 0x5a, 0xff, + 0xf7, 0x7f, 0xfe, 0x97, 0xff, 0x66, 0x1e, 0x21, 0x56, 0xf5, 0xaf, 0xff, 0xfd, 0x3f, 0xff, 0x9f, 0xff, 0xfd, 0x5f, + 0xe1, 0xd4, 0x8a, 0x8e, 0x67, 0x49, 0xa6, 0xe2, 0x54, 0xc1, 0x2c, 0xc5, 0x5d, 0x1c, 0x48, 0xec, 0x9c, 0xb0, 0x5c, + 0xb0, 0x61, 0xfd, 0x4c, 0xd2, 0xb9, 0x1c, 0x50, 0xee, 0x4c, 0x0d, 0x9d, 0xdc, 0xe1, 0x45, 0x45, 0x50, 0x35, 0x94, + 0x4b, 0xc2, 0x2d, 0x4e, 0xf6, 0x01, 0xdf, 0x0f, 0x3b, 0xc6, 0xe9, 0x97, 0xcb, 0xb1, 0x30, 0x64, 0x02, 0x25, 0x45, + 0x55, 0xee, 0x40, 0x6c, 0x65, 0x01, 0x8f, 0x41, 0xc7, 0x2a, 0x96, 0xab, 0x57, 0x6b, 0xd3, 0xfd, 0x69, 0x96, 0x0b, + 0x36, 0x02, 0x94, 0x2b, 0x3f, 0xb1, 0x0c, 0x63, 0x37, 0x41, 0x57, 0x4c, 0xee, 0x0a, 0xd9, 0x8b, 0x22, 0xd0, 0xc3, + 0xe3, 0x3f, 0x15, 0x7f, 0x99, 0x80, 0x46, 0xe6, 0x78, 0x93, 0xf0, 0x56, 0x9b, 0xe7, 0x8f, 0x5a, 0xad, 0xe9, 0x2d, + 0x5a, 0x54, 0x23, 0xe0, 0x6d, 0x83, 0x49, 0x3a, 0xb6, 0x3b, 0x94, 0xf1, 0xef, 0xd2, 0x8d, 0xdd, 0x72, 0xc0, 0x17, + 0xee, 0xb4, 0x8a, 0xe2, 0xcf, 0x0b, 0xe9, 0x49, 0x65, 0xbf, 0x40, 0x9c, 0x5a, 0x3b, 0x9d, 0xaf, 0xb9, 0x3d, 0xb9, + 0x85, 0xd5, 0xaa, 0xa3, 0x5a, 0xc5, 0xed, 0xf5, 0xd3, 0x89, 0x76, 0x9c, 0xdd, 0x8e, 0x90, 0x1f, 0x42, 0xcc, 0x3b, + 0x6e, 0xe3, 0xb8, 0xb3, 0x28, 0xbb, 0x17, 0x82, 0x4f, 0xec, 0xc0, 0x3a, 0x0d, 0xe9, 0x90, 0x8e, 0x8c, 0xb3, 0x5e, + 0xbf, 0x57, 0x41, 0xf3, 0x22, 0x3e, 0xd8, 0x30, 0x96, 0x06, 0x49, 0x06, 0xd4, 0x9d, 0x56, 0xf1, 0x39, 0xec, 0xc0, + 0xc5, 0x28, 0xe1, 0xa1, 0x08, 0x24, 0xc1, 0x76, 0xed, 0xf0, 0x7c, 0x08, 0x3c, 0x89, 0x2f, 0x2c, 0x78, 0xba, 0xaa, + 0x2a, 0xb8, 0xcd, 0xeb, 0x67, 0x48, 0x0b, 0x5f, 0x36, 0xb7, 0xbb, 0x52, 0x5e, 0xb7, 0x6f, 0x75, 0xd4, 0xfb, 0x5d, + 0xcd, 0x5d, 0xa5, 0x05, 0x52, 0x07, 0x6d, 0x7e, 0xaf, 0xe4, 0xba, 0x7a, 0xfb, 0xb5, 0xf0, 0x5c, 0x09, 0xa6, 0xbb, + 0x5a, 0x4b, 0x16, 0x42, 0xad, 0x77, 0xe4, 0xdb, 0xd2, 0x64, 0x0a, 0xa7, 0x53, 0x59, 0x11, 0x75, 0x4f, 0xf6, 0x95, + 0xa6, 0x0b, 0xdc, 0x43, 0xa6, 0x74, 0xa8, 0x0c, 0x0a, 0x5d, 0x49, 0x6f, 0x05, 0xf5, 0x4b, 0xe7, 0x56, 0xc0, 0xa7, + 0xe3, 0x7a, 0xff, 0x0f, 0x82, 0x7a, 0x0b, 0xa7, 0xcf, 0x89, 0x00, 0x00}; } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/server_index_v3.h b/esphome/components/web_server/server_index_v3.h index 98a4f255f5..39518197a3 100644 --- a/esphome/components/web_server/server_index_v3.h +++ b/esphome/components/web_server/server_index_v3.h @@ -3636,415 +3636,417 @@ const uint8_t INDEX_GZ[] PROGMEM = { 0x9d, 0x85, 0xdf, 0xf1, 0x24, 0xec, 0x6a, 0x98, 0x92, 0x35, 0x98, 0x2e, 0x20, 0x16, 0xef, 0xfe, 0x43, 0xc1, 0x7e, 0x86, 0xbf, 0xb3, 0x14, 0xfe, 0x56, 0xb5, 0x77, 0x30, 0xbc, 0x7b, 0x7b, 0xf6, 0x01, 0x14, 0x1c, 0x31, 0x6a, 0x24, 0x37, 0x81, 0x36, 0x66, 0x18, 0x82, 0xca, 0x20, 0x88, 0x82, 0x78, 0x05, 0x27, 0x3b, 0xb2, 0x8e, 0x87, 0x77, 0xc3, - 0xdb, 0xdb, 0xdb, 0xff, 0xd3, 0xdc, 0xd3, 0x6e, 0xb7, 0x6d, 0x23, 0xfb, 0xbf, 0x4f, 0xc1, 0x30, 0xd9, 0x94, 0x4c, - 0x48, 0x9a, 0x94, 0x2c, 0x5b, 0x91, 0x2c, 0xb9, 0xcd, 0x47, 0xb7, 0xee, 0xba, 0x4d, 0x4f, 0xe2, 0xf6, 0xee, 0xae, - 0xeb, 0x63, 0x51, 0x12, 0x24, 0x71, 0x43, 0x91, 0x3a, 0x24, 0xe5, 0x8f, 0x2a, 0xdc, 0x67, 0xd9, 0x47, 0xb8, 0xcf, - 0xd0, 0x27, 0xbb, 0x67, 0x66, 0x00, 0x12, 0xfc, 0x92, 0xe4, 0x4d, 0xda, 0xde, 0xd3, 0x26, 0x11, 0x41, 0x00, 0x04, - 0x06, 0xc0, 0x60, 0xbe, 0xc7, 0x04, 0xd3, 0x46, 0x73, 0x1d, 0xf9, 0x2c, 0x98, 0x84, 0x90, 0x98, 0x24, 0x15, 0x08, - 0x9f, 0x95, 0x10, 0x3e, 0xc4, 0x45, 0xe5, 0x89, 0x35, 0xde, 0x2f, 0xc2, 0xdb, 0xaf, 0x7d, 0x5f, 0xe6, 0xdf, 0x05, - 0xd1, 0xc7, 0x59, 0xda, 0x02, 0x02, 0xd1, 0x40, 0x0d, 0x61, 0x79, 0xf1, 0x35, 0x57, 0x1c, 0x4f, 0xaf, 0xc7, 0xf7, - 0xd7, 0x5c, 0x38, 0x9d, 0x05, 0xa6, 0x7d, 0x35, 0x3a, 0x99, 0x7a, 0x37, 0x0a, 0x52, 0xa6, 0x03, 0x15, 0xbc, 0x7a, - 0x7c, 0x36, 0x5e, 0x27, 0x49, 0x18, 0x98, 0x51, 0x78, 0xab, 0x0e, 0x4f, 0xe8, 0x41, 0x54, 0x70, 0xe9, 0x51, 0x55, - 0xbe, 0x9a, 0xf8, 0xde, 0xe4, 0xc3, 0x40, 0x7d, 0xb2, 0xf1, 0x06, 0xc3, 0x12, 0xfd, 0x69, 0xa7, 0xea, 0x10, 0xc6, - 0xaa, 0x7c, 0xed, 0xfb, 0x27, 0x07, 0xd4, 0x62, 0x78, 0x72, 0x30, 0xf5, 0x6e, 0x86, 0x52, 0x8e, 0x10, 0xae, 0x40, - 0x1b, 0xf0, 0x58, 0x8c, 0x99, 0xc9, 0x51, 0x8c, 0xce, 0xfd, 0x13, 0xa6, 0xe5, 0x5c, 0x10, 0x04, 0x1d, 0xa1, 0xf1, - 0x6a, 0x13, 0x94, 0xab, 0xfa, 0x40, 0xf3, 0x7f, 0xfc, 0xa8, 0x65, 0x06, 0x89, 0x0b, 0x29, 0x5a, 0x17, 0xea, 0x7b, - 0xb0, 0x8a, 0x81, 0x21, 0x47, 0x74, 0x4d, 0xc4, 0x14, 0xf3, 0x75, 0x63, 0x92, 0x1a, 0x98, 0x6a, 0xc5, 0x5d, 0x01, - 0x8d, 0xc0, 0x7f, 0x4a, 0xac, 0xd1, 0x04, 0xd2, 0x2b, 0x4b, 0x08, 0x5e, 0x97, 0x84, 0xef, 0x74, 0x36, 0x79, 0xc0, - 0x38, 0x90, 0x9a, 0xe3, 0x77, 0x48, 0x20, 0xae, 0xf9, 0x3a, 0xa4, 0xf7, 0xca, 0xa2, 0xb4, 0xb8, 0xa9, 0x48, 0xa8, - 0x25, 0xe0, 0x72, 0x5a, 0x58, 0xa1, 0x5e, 0x79, 0xbd, 0x44, 0xf8, 0xc0, 0x47, 0x71, 0xd3, 0x92, 0x81, 0x32, 0x47, - 0x4b, 0x8c, 0xd2, 0x7d, 0x0c, 0xee, 0x5d, 0x92, 0x06, 0x81, 0x19, 0xda, 0x65, 0x6c, 0x84, 0x57, 0xf9, 0x1d, 0x16, - 0x13, 0xfa, 0xec, 0x85, 0x69, 0x1e, 0xc9, 0x97, 0x56, 0x7d, 0xf8, 0x64, 0x13, 0xe0, 0xa5, 0x17, 0x0f, 0x86, 0xc5, - 0x7d, 0x90, 0xb8, 0x63, 0x93, 0x36, 0xb3, 0xaa, 0x7c, 0x35, 0x1d, 0xfb, 0xd9, 0x62, 0xd3, 0xd1, 0x58, 0xb8, 0xc1, - 0xd4, 0x67, 0x17, 0xee, 0xf8, 0x5b, 0xac, 0xf3, 0x7a, 0xec, 0xbf, 0x82, 0x0a, 0xa9, 0x3a, 0x7c, 0xb2, 0xa1, 0x6b, - 0xbd, 0x0e, 0x8d, 0xa7, 0xb4, 0x05, 0xca, 0xdf, 0xe1, 0xb9, 0x77, 0x58, 0x44, 0xad, 0x71, 0xb0, 0x74, 0x15, 0x13, - 0x9e, 0x2d, 0x8e, 0x8c, 0xe7, 0x7e, 0x81, 0xbd, 0xa9, 0xf0, 0x43, 0x09, 0xe3, 0x0a, 0xc5, 0x01, 0x95, 0x77, 0xa6, - 0x3c, 0x58, 0xba, 0x72, 0xdf, 0x85, 0xb7, 0x62, 0xa4, 0x1c, 0x00, 0x14, 0xab, 0xf0, 0xf4, 0xd5, 0xe8, 0x44, 0xd6, - 0x0f, 0xa0, 0x10, 0x95, 0xfa, 0x85, 0x5f, 0xa9, 0xaa, 0xe4, 0x99, 0x80, 0x56, 0x77, 0xea, 0xf0, 0xe4, 0x40, 0xae, - 0x3d, 0x1c, 0xf5, 0xce, 0xa5, 0xc9, 0x61, 0xaf, 0x00, 0x84, 0x62, 0x59, 0xe5, 0xd6, 0x81, 0xe4, 0x78, 0xf9, 0xbd, - 0x44, 0xdb, 0x43, 0xa0, 0xc5, 0x50, 0xef, 0x65, 0x6b, 0x44, 0x36, 0x78, 0xa2, 0xb7, 0x11, 0xff, 0x37, 0x9f, 0x33, - 0xca, 0x34, 0x59, 0x10, 0x87, 0x91, 0x0a, 0xf3, 0x28, 0x67, 0xc8, 0x51, 0xa4, 0xcc, 0x5c, 0x38, 0xa3, 0xda, 0xdb, - 0x14, 0x20, 0x72, 0x50, 0x6e, 0x2a, 0x4d, 0x6c, 0xa4, 0xe7, 0x3f, 0x14, 0x3e, 0x99, 0x12, 0x56, 0xca, 0x06, 0xd8, - 0x9c, 0x79, 0xe8, 0xf2, 0xad, 0x67, 0xfc, 0x4f, 0x68, 0xcc, 0x5d, 0x63, 0xe9, 0x1a, 0xef, 0x83, 0xab, 0xb4, 0x76, - 0x75, 0xb2, 0xac, 0x61, 0x06, 0xeb, 0x6b, 0x10, 0x6b, 0x87, 0x4b, 0x40, 0xb8, 0x5c, 0xc0, 0xb3, 0xb8, 0x75, 0xc0, - 0x85, 0x1b, 0xcd, 0x99, 0x48, 0xd6, 0x25, 0xde, 0x26, 0x1c, 0x2a, 0xba, 0x04, 0x16, 0x08, 0x44, 0x25, 0x18, 0x1c, - 0xcf, 0x9a, 0x24, 0x91, 0xff, 0x37, 0x76, 0x0f, 0x9c, 0x67, 0x9c, 0x84, 0x2b, 0x90, 0x4e, 0xb8, 0x73, 0x2e, 0x6d, - 0x36, 0x80, 0x96, 0xd9, 0xe7, 0x73, 0x1f, 0x3f, 0x32, 0x29, 0x7f, 0x54, 0x12, 0xce, 0xe7, 0x3e, 0xd3, 0xa4, 0x3c, - 0x53, 0xd9, 0x67, 0x4e, 0x1f, 0xd9, 0x22, 0x46, 0xb1, 0x9e, 0x36, 0x9d, 0x9c, 0x9c, 0x14, 0x14, 0x7a, 0x5d, 0x62, - 0xd6, 0x51, 0x1b, 0x75, 0x83, 0x0a, 0x5d, 0xbe, 0x2e, 0xf9, 0xc9, 0x34, 0xa7, 0xe1, 0x7a, 0xec, 0x33, 0x13, 0xb7, - 0x3b, 0x7c, 0x72, 0x33, 0x5e, 0x8f, 0xc7, 0x3e, 0x25, 0x86, 0x82, 0x48, 0x5b, 0x61, 0x8c, 0x12, 0xb0, 0x54, 0xef, - 0x23, 0x81, 0x96, 0x94, 0x87, 0x0f, 0xd6, 0x71, 0xc0, 0x36, 0xd0, 0x07, 0x12, 0x90, 0x76, 0x55, 0x0f, 0xed, 0x40, - 0x05, 0x76, 0x85, 0xc5, 0x6a, 0xbf, 0x86, 0x92, 0x1b, 0x5c, 0xaa, 0xef, 0x11, 0xc2, 0x98, 0xbd, 0xfe, 0x15, 0xed, - 0x5d, 0xd5, 0x50, 0xc9, 0xc8, 0x87, 0xe7, 0x11, 0x53, 0x0d, 0xf5, 0xb5, 0xe7, 0xce, 0x83, 0x30, 0x4e, 0xbc, 0x89, - 0x7a, 0xd5, 0x3f, 0xf3, 0xb4, 0xcb, 0x65, 0xa2, 0xe9, 0x57, 0xc6, 0x5f, 0xe5, 0x8c, 0x4f, 0x02, 0x15, 0x62, 0xc2, - 0xa7, 0x86, 0x3a, 0xf2, 0xe9, 0xd9, 0x56, 0x4f, 0xa0, 0x5c, 0xac, 0xf3, 0xd7, 0x01, 0xd4, 0x2a, 0xe5, 0x8e, 0xc2, - 0xa4, 0x80, 0x90, 0x3b, 0xea, 0xaf, 0x7a, 0x9f, 0xa4, 0x32, 0xaf, 0xd6, 0x1b, 0xa4, 0x15, 0x92, 0xfc, 0x76, 0xc5, - 0x70, 0xe7, 0xc2, 0x47, 0x90, 0x9e, 0x1f, 0xc9, 0xf6, 0xed, 0x85, 0x7b, 0x7a, 0xf4, 0x75, 0x91, 0xf0, 0x00, 0x02, - 0x01, 0x8c, 0xcb, 0x82, 0x30, 0x51, 0x20, 0x86, 0x17, 0x7c, 0x70, 0x54, 0xb6, 0x87, 0xe5, 0xbd, 0x6a, 0x7a, 0xca, - 0xb1, 0xc0, 0x4b, 0xbc, 0x2c, 0x45, 0xf6, 0x77, 0x0c, 0x47, 0x59, 0x88, 0xd8, 0xc3, 0xbd, 0xb0, 0x60, 0xf9, 0x0a, - 0x64, 0x9b, 0x84, 0xd8, 0x8b, 0x17, 0xf6, 0x93, 0x4d, 0x7c, 0x2a, 0x6e, 0xed, 0xb3, 0x18, 0xd7, 0x12, 0xe8, 0x11, - 0x7e, 0x8d, 0xa7, 0xaa, 0x72, 0x2a, 0xae, 0x1a, 0xac, 0x5b, 0xc0, 0x9f, 0x9a, 0xa0, 0x72, 0x45, 0x52, 0x77, 0x8d, - 0xa7, 0xa0, 0x16, 0x74, 0x57, 0xe9, 0xe8, 0x41, 0x58, 0x9e, 0x8c, 0xa4, 0x4a, 0xc0, 0xb6, 0x16, 0x6f, 0x04, 0xc0, - 0x5c, 0x9c, 0x08, 0x18, 0xa5, 0xd7, 0x40, 0x3f, 0x42, 0xac, 0x2a, 0x31, 0x47, 0x23, 0x94, 0xd3, 0x85, 0x79, 0xc1, - 0x6a, 0x9d, 0x60, 0x0c, 0x72, 0x18, 0x00, 0x4b, 0x55, 0x05, 0xb9, 0x45, 0x40, 0xe6, 0x39, 0x17, 0x94, 0xaa, 0x8a, - 0x37, 0xad, 0x96, 0x71, 0xd1, 0x0d, 0xe0, 0x38, 0x9c, 0x06, 0x4a, 0xf0, 0xe1, 0x31, 0xe2, 0xd3, 0x98, 0x18, 0x79, - 0x02, 0x0f, 0x6d, 0x82, 0x9a, 0xee, 0x1a, 0x04, 0x32, 0xa1, 0x7e, 0xfa, 0x9a, 0x5f, 0x3b, 0x59, 0x88, 0x4b, 0x5c, - 0x98, 0xe6, 0xe8, 0xc9, 0x26, 0x48, 0x4f, 0x01, 0x76, 0x83, 0x27, 0x1b, 0x37, 0x33, 0xa2, 0x52, 0x2f, 0x54, 0xb2, - 0xa0, 0x1a, 0x21, 0x18, 0x46, 0xe9, 0x75, 0xee, 0xd2, 0x98, 0xcf, 0x17, 0xb6, 0x24, 0x95, 0x2b, 0x68, 0xd3, 0x34, - 0xe0, 0x96, 0x4b, 0xab, 0xc8, 0x5b, 0xba, 0xd1, 0x3d, 0x19, 0x3a, 0x19, 0xb2, 0x35, 0x94, 0xae, 0x2a, 0x74, 0x1f, - 0x10, 0x00, 0xe8, 0x6a, 0x50, 0x95, 0xaf, 0xb2, 0x32, 0xc6, 0x67, 0x9b, 0x59, 0x7b, 0xc0, 0xb7, 0xae, 0xd5, 0xe7, - 0xcc, 0x22, 0x91, 0x06, 0x35, 0xe9, 0x6b, 0x71, 0xc3, 0xf4, 0xe2, 0xe2, 0xf4, 0x82, 0xe2, 0x46, 0xc3, 0xc9, 0xd0, - 0x4d, 0x41, 0xe3, 0xc6, 0x99, 0x61, 0xba, 0xc3, 0xfa, 0x15, 0xa5, 0x77, 0x7f, 0xe8, 0x72, 0x30, 0x58, 0x8e, 0x00, - 0x96, 0x83, 0xa8, 0xeb, 0x9f, 0xde, 0x9d, 0x65, 0xf9, 0x15, 0x41, 0x34, 0x3e, 0xe2, 0x1b, 0x33, 0x46, 0x32, 0x23, - 0x42, 0x12, 0x83, 0x32, 0x21, 0x2a, 0xd9, 0x16, 0x8a, 0xe0, 0x68, 0xd0, 0xd8, 0xe9, 0x68, 0x44, 0x83, 0x41, 0x88, - 0xad, 0xa2, 0xf4, 0xe4, 0x80, 0x6a, 0xd3, 0xa5, 0x48, 0x95, 0x00, 0x0c, 0x11, 0xcc, 0x30, 0x87, 0x02, 0xa4, 0x82, - 0x1e, 0x38, 0x39, 0x7f, 0x63, 0x2d, 0x51, 0x01, 0xe9, 0x9c, 0x16, 0x29, 0x1a, 0x6c, 0xa5, 0x0e, 0x4f, 0x30, 0xb9, - 0x23, 0x5c, 0xeb, 0x10, 0xfe, 0xe8, 0xe4, 0x80, 0x1e, 0x95, 0xd2, 0x89, 0xc8, 0x3b, 0x11, 0x02, 0xca, 0x1e, 0xef, - 0xe0, 0x41, 0x47, 0x25, 0x4e, 0xd8, 0x0a, 0x4a, 0xdd, 0x54, 0x55, 0x96, 0x9c, 0x82, 0xe2, 0x71, 0xd6, 0x20, 0x08, - 0x8b, 0x0d, 0xc6, 0xef, 0xaa, 0xb2, 0x74, 0xef, 0x70, 0xe6, 0xe2, 0x8d, 0x7b, 0xa7, 0x39, 0xfc, 0x55, 0x7e, 0xd6, - 0xe2, 0xe2, 0x59, 0x9b, 0xf0, 0xc5, 0x05, 0x0f, 0x2b, 0x41, 0x39, 0x6b, 0x0b, 0xb4, 0x5c, 0xa9, 0x59, 0xdc, 0x85, - 0x58, 0xdc, 0x69, 0xc3, 0xe2, 0x4e, 0xb7, 0x2c, 0xae, 0xcf, 0x17, 0x52, 0xc9, 0x40, 0x17, 0xa1, 0xd7, 0x6c, 0x06, - 0x3c, 0x4e, 0x8f, 0xf4, 0xf8, 0x39, 0x43, 0x38, 0x99, 0xb1, 0x0f, 0x56, 0xa3, 0x0d, 0xb0, 0xaa, 0x83, 0x8b, 0x04, - 0x88, 0xea, 0xc4, 0xb3, 0x53, 0x37, 0x91, 0x04, 0x02, 0x9a, 0x5f, 0x9e, 0x2f, 0xec, 0x52, 0x6c, 0x68, 0x68, 0x8b, - 0x86, 0x99, 0x2e, 0xb6, 0xcc, 0x74, 0x52, 0x38, 0xba, 0x7c, 0xda, 0x74, 0x08, 0xe5, 0x49, 0xc1, 0x1e, 0x04, 0x4b, - 0x7a, 0xdc, 0x32, 0xc5, 0x7d, 0xd8, 0x8c, 0x63, 0xa5, 0x1d, 0xb5, 0x72, 0xe3, 0xf8, 0x36, 0x8c, 0x40, 0x15, 0x0d, - 0xdd, 0x3c, 0x6c, 0x4b, 0x2d, 0xbd, 0x80, 0x47, 0xb9, 0x6a, 0xdc, 0x4c, 0xf9, 0x7b, 0x79, 0x4b, 0xb5, 0x3a, 0x1d, - 0xaa, 0xb1, 0x72, 0x93, 0x84, 0x45, 0x08, 0x74, 0x17, 0xd2, 0x21, 0xfc, 0x3f, 0xd9, 0x66, 0x35, 0x38, 0xc4, 0x97, - 0xb0, 0x3a, 0x62, 0xe8, 0x15, 0x90, 0x60, 0xa4, 0x7b, 0x0a, 0xf4, 0x8d, 0x14, 0x31, 0x33, 0xca, 0x00, 0xff, 0x03, - 0x1e, 0x57, 0x2d, 0x92, 0x7c, 0x3a, 0x9d, 0x23, 0xdd, 0x5a, 0xb9, 0xd3, 0xf7, 0x60, 0xf1, 0xa0, 0xb5, 0x0c, 0xf0, - 0x5e, 0x90, 0xe3, 0x63, 0x46, 0x44, 0x13, 0x4e, 0x72, 0x24, 0x89, 0x58, 0x92, 0xdb, 0x86, 0x82, 0x5b, 0xb9, 0x6b, - 0xce, 0xae, 0x36, 0xad, 0xf4, 0x60, 0xee, 0xe9, 0x15, 0xac, 0x09, 0xa8, 0xcd, 0x1f, 0x0c, 0x33, 0x59, 0x9b, 0x6f, - 0x38, 0x47, 0x3a, 0xa8, 0xc4, 0x2e, 0x21, 0xf1, 0xb5, 0x2d, 0xb8, 0xe5, 0x51, 0x04, 0xb7, 0xd6, 0xa5, 0x7d, 0x95, - 0x3e, 0x9d, 0xe3, 0x2f, 0xe7, 0x2a, 0x7d, 0x3a, 0xc6, 0x5f, 0xad, 0x2b, 0x4c, 0xe9, 0x59, 0x23, 0x26, 0x90, 0xe6, - 0xac, 0x0e, 0x0b, 0xfb, 0x89, 0x0c, 0x73, 0x1f, 0xb0, 0x6d, 0xf8, 0x02, 0x3f, 0x7e, 0xb2, 0x89, 0xc1, 0x15, 0x5d, - 0x9e, 0x43, 0x60, 0x45, 0x7a, 0x5a, 0x5b, 0x3e, 0x6f, 0x28, 0x1f, 0xeb, 0x7f, 0xf0, 0xc5, 0x8f, 0xbb, 0x24, 0xcc, - 0xef, 0x94, 0xa2, 0x90, 0xe3, 0x7a, 0xec, 0x05, 0x6e, 0x74, 0x7f, 0x4d, 0x5c, 0x88, 0x26, 0x49, 0x7b, 0x1f, 0xe5, - 0xdc, 0xff, 0x7d, 0xd1, 0x0e, 0x20, 0x91, 0x74, 0x59, 0xf7, 0xfc, 0xa2, 0x1f, 0xfc, 0x3d, 0x92, 0xe8, 0xbb, 0x02, - 0x9f, 0xca, 0x17, 0xa4, 0xf0, 0xa1, 0xeb, 0x27, 0x1b, 0x8d, 0x55, 0xbb, 0x29, 0xcd, 0xb6, 0x44, 0x40, 0xc2, 0xf2, - 0x20, 0xcf, 0xbb, 0x9c, 0x7a, 0x3d, 0x54, 0xf4, 0x8f, 0xc3, 0x3b, 0xf3, 0xc9, 0x26, 0x39, 0x55, 0x97, 0x6e, 0xf4, - 0x81, 0x4d, 0xcd, 0x89, 0x17, 0x4d, 0x7c, 0x20, 0x1e, 0xc7, 0xbe, 0x1b, 0x7c, 0xe0, 0x8f, 0x66, 0xb8, 0x4e, 0xd0, - 0x74, 0x67, 0x27, 0x8b, 0x2c, 0x60, 0x42, 0xf2, 0x43, 0xa4, 0x6a, 0x6b, 0xa0, 0xa0, 0xbc, 0xca, 0xe4, 0x6f, 0x39, - 0xa1, 0x98, 0xd7, 0x32, 0xc0, 0xf2, 0x1c, 0xac, 0x89, 0xc0, 0x95, 0xdf, 0x50, 0x71, 0xbd, 0x54, 0x43, 0x9e, 0x2a, - 0xa9, 0xdc, 0xb2, 0x5c, 0xb4, 0xd7, 0xd8, 0xc3, 0x7f, 0xff, 0x39, 0x28, 0x79, 0xc8, 0xe7, 0xb2, 0x5e, 0x3e, 0x6d, - 0x86, 0x50, 0x6a, 0x92, 0x0b, 0xd9, 0x03, 0x3e, 0xce, 0x09, 0xcc, 0xe6, 0x4f, 0xcb, 0x8d, 0xdd, 0x38, 0x5e, 0x2f, - 0xd9, 0x94, 0x54, 0x6b, 0xa7, 0xf9, 0xa0, 0x8a, 0x7c, 0x88, 0x3c, 0xb0, 0x5f, 0xd6, 0xad, 0xe3, 0xc3, 0x57, 0x60, - 0xca, 0x05, 0x04, 0x65, 0x38, 0x9b, 0xa9, 0xb9, 0x28, 0x60, 0x47, 0x33, 0xe7, 0xf0, 0x97, 0xf5, 0x37, 0x6f, 0xec, - 0x6f, 0xb2, 0xc6, 0x01, 0x10, 0xc6, 0xc2, 0x2e, 0x85, 0xd3, 0xc5, 0xd2, 0x78, 0xc5, 0x8c, 0x66, 0x6e, 0xd0, 0x3c, - 0x9d, 0xcb, 0xc2, 0x16, 0x5f, 0x31, 0x36, 0x05, 0x82, 0xdb, 0xa8, 0x94, 0x5e, 0xfb, 0xec, 0x86, 0x65, 0x36, 0x2f, - 0xd5, 0x8f, 0xd5, 0xb4, 0xc0, 0xa0, 0x9c, 0x5c, 0x93, 0xc9, 0xa9, 0x3a, 0x69, 0x4a, 0x23, 0x9c, 0x03, 0x9f, 0xb9, - 0x7c, 0xc4, 0x4a, 0x47, 0x6a, 0x64, 0xa8, 0xd2, 0x00, 0x1a, 0x47, 0x76, 0xda, 0x50, 0xde, 0x03, 0x44, 0xdd, 0x30, - 0x36, 0xc3, 0xd1, 0x7b, 0x90, 0xc4, 0x80, 0xc3, 0xc9, 0x87, 0x93, 0xa7, 0xe5, 0x52, 0x93, 0x26, 0x88, 0xd5, 0xc9, - 0xd2, 0x54, 0x12, 0xd2, 0x08, 0x33, 0x70, 0xf4, 0x87, 0x10, 0xe2, 0xaa, 0xda, 0xb5, 0x51, 0x8a, 0x33, 0x1f, 0x63, - 0x8a, 0xef, 0x80, 0xc5, 0x71, 0x23, 0xc0, 0xb2, 0x45, 0x37, 0xd4, 0xbc, 0x76, 0x11, 0x1e, 0x79, 0xb9, 0x61, 0x1b, - 0x40, 0x12, 0xe0, 0x04, 0xcb, 0xdf, 0xc2, 0xeb, 0xe5, 0x7a, 0xc9, 0x0d, 0xf9, 0xa2, 0xf9, 0x58, 0xe5, 0x46, 0x56, - 0x4d, 0xef, 0x6f, 0x55, 0x3e, 0xa8, 0xc2, 0x35, 0x5d, 0x3b, 0x34, 0xad, 0x80, 0x7a, 0x2b, 0x52, 0x25, 0xec, 0x40, - 0x8c, 0xa9, 0x84, 0x5f, 0xd9, 0x6c, 0xc6, 0x26, 0x49, 0xac, 0x0b, 0x19, 0x53, 0x16, 0x56, 0x1b, 0xb4, 0x77, 0x8f, - 0x06, 0xea, 0x0f, 0x10, 0x5c, 0x44, 0x44, 0x9f, 0xe3, 0x03, 0x12, 0x3c, 0x53, 0x3d, 0x98, 0xa8, 0xc7, 0x22, 0x88, - 0xf8, 0x57, 0x40, 0xcc, 0x5c, 0x53, 0x8e, 0x43, 0xe3, 0xf7, 0x4f, 0xbe, 0x2f, 0xc2, 0xcc, 0xdc, 0x6f, 0x3b, 0x2a, - 0xda, 0x76, 0x7c, 0x37, 0xce, 0x37, 0x1d, 0xc7, 0x4e, 0x55, 0x03, 0x9c, 0x5a, 0x3f, 0x94, 0xb6, 0x31, 0x5d, 0x50, - 0x03, 0xf5, 0xfc, 0xed, 0xab, 0xbf, 0xbd, 0x79, 0xbd, 0x2f, 0x46, 0xc0, 0x2e, 0xdb, 0xd0, 0xe5, 0x3a, 0xd8, 0xd2, - 0xe9, 0x4f, 0x3f, 0x3c, 0xac, 0xdb, 0x96, 0xf3, 0xc2, 0x51, 0x0d, 0xb2, 0x43, 0x96, 0xf0, 0xe2, 0x24, 0xbc, 0x61, - 0xd1, 0x27, 0x83, 0x41, 0xee, 0xbc, 0x7e, 0xb8, 0x6f, 0x7f, 0x7c, 0xf3, 0xc3, 0xde, 0x43, 0x3d, 0x72, 0x6c, 0xc0, - 0xed, 0x49, 0xb8, 0x7a, 0xc0, 0xec, 0xda, 0xaa, 0xa1, 0x4e, 0xfc, 0x30, 0x66, 0x0d, 0x23, 0x78, 0x75, 0xfe, 0xf6, - 0x3d, 0x82, 0x2b, 0x27, 0x41, 0xa8, 0xab, 0x4f, 0x9b, 0xfc, 0x8f, 0xef, 0xde, 0xbc, 0x7f, 0xaf, 0x1a, 0x98, 0x96, - 0x39, 0x96, 0x7b, 0xe7, 0x9b, 0x78, 0xc7, 0x8d, 0x53, 0xbb, 0xd7, 0xe9, 0x56, 0x23, 0x46, 0xba, 0x38, 0x1b, 0x2a, - 0xab, 0x6c, 0x73, 0x7e, 0xdb, 0xf1, 0x2f, 0x13, 0xf7, 0xbb, 0xd7, 0xbc, 0x6a, 0xf0, 0xd1, 0xf6, 0x2b, 0xb5, 0x50, - 0xb2, 0xf4, 0x82, 0xeb, 0x9a, 0x52, 0xf7, 0xae, 0xa6, 0x14, 0xd8, 0xc7, 0x0a, 0x7e, 0x5c, 0x87, 0x4b, 0x89, 0x1c, - 0x61, 0x77, 0xbb, 0xc1, 0x25, 0xf1, 0x70, 0x9f, 0x30, 0x68, 0x9e, 0x56, 0xa3, 0x3c, 0xea, 0x9a, 0x62, 0xce, 0x78, - 0x65, 0xb0, 0x9d, 0xf8, 0x60, 0x7d, 0xcd, 0x64, 0x3d, 0x63, 0x91, 0x54, 0xe5, 0xbe, 0x13, 0x83, 0x12, 0x57, 0x40, - 0xcd, 0x48, 0x37, 0xc3, 0xef, 0x94, 0x95, 0x3b, 0x05, 0x93, 0x66, 0x73, 0x1c, 0x26, 0x49, 0xb8, 0xec, 0x39, 0xf6, - 0xea, 0x4e, 0x55, 0xfa, 0x42, 0xd8, 0xc1, 0x2d, 0xae, 0x7b, 0xbf, 0xfd, 0xa7, 0x84, 0xe6, 0xa9, 0xfc, 0x3a, 0x61, - 0xcb, 0x15, 0x8b, 0xdc, 0x64, 0x1d, 0xb1, 0x54, 0xf9, 0xed, 0x7f, 0x5f, 0x95, 0x18, 0xfb, 0xbe, 0xdc, 0x86, 0x48, - 0x7a, 0xb9, 0xc9, 0xb5, 0x1f, 0xde, 0x3e, 0xca, 0x7d, 0xab, 0x76, 0x54, 0x5e, 0x78, 0xf3, 0x45, 0x56, 0xfb, 0x34, - 0xd9, 0x32, 0x37, 0x31, 0x7a, 0xd2, 0x07, 0x28, 0xe7, 0xe1, 0x6d, 0xef, 0xb7, 0xff, 0x64, 0x02, 0x9b, 0x9d, 0xbb, - 0xae, 0x7e, 0xa0, 0xc5, 0x15, 0xad, 0xaf, 0x53, 0x59, 0x62, 0x78, 0x5f, 0x59, 0xe0, 0x4a, 0x21, 0xed, 0xca, 0xaa, - 0xf2, 0x6d, 0xcb, 0x9c, 0xbe, 0xf5, 0xe6, 0x8b, 0x4f, 0x9d, 0x14, 0x00, 0x74, 0xe7, 0xac, 0xa0, 0xd2, 0x67, 0x98, - 0xd6, 0xa8, 0xb7, 0xff, 0x82, 0x7d, 0xe2, 0xbc, 0x76, 0x4d, 0xe9, 0x73, 0xcc, 0x86, 0x4b, 0x6e, 0x5f, 0x8d, 0x46, - 0x59, 0x5a, 0x52, 0xb9, 0x3d, 0x78, 0x87, 0x9d, 0x56, 0x4a, 0x38, 0x79, 0xd1, 0xb3, 0x75, 0x0a, 0xdb, 0xb2, 0x07, - 0x40, 0xd0, 0xce, 0xb9, 0x06, 0x1c, 0xcd, 0xf8, 0x9a, 0xdc, 0x95, 0x2a, 0xdf, 0xae, 0x20, 0x6b, 0x28, 0xc5, 0x94, - 0x96, 0x99, 0xd6, 0xd0, 0xa8, 0x1f, 0xce, 0x6d, 0xe4, 0xae, 0x48, 0x49, 0xa0, 0xa0, 0xc6, 0x04, 0x84, 0x2e, 0x25, - 0x2e, 0xfa, 0xc6, 0xf5, 0x6f, 0xf6, 0x63, 0xa8, 0x9a, 0x6f, 0x30, 0xbc, 0x9a, 0xff, 0xbc, 0xcb, 0x1b, 0xef, 0xe5, - 0xfd, 0xef, 0x6e, 0x4c, 0x15, 0xf6, 0xb6, 0xc9, 0xbc, 0xfa, 0xc7, 0xdd, 0xe6, 0xd5, 0x17, 0x7b, 0x99, 0x57, 0xff, - 0xf8, 0xd9, 0xcd, 0xab, 0xdf, 0xca, 0xe6, 0xd5, 0xb0, 0x89, 0xdf, 0xb0, 0xbd, 0x8c, 0x9e, 0x85, 0x91, 0x51, 0x78, - 0x1b, 0x0f, 0x1c, 0xce, 0xf4, 0xc4, 0x93, 0x05, 0x03, 0x29, 0x12, 0x07, 0x97, 0x1f, 0xce, 0xc1, 0x36, 0xb9, 0xd9, - 0xfa, 0xf8, 0x73, 0xd9, 0x1e, 0xfb, 0xe1, 0x5c, 0x95, 0x82, 0xa5, 0x07, 0x3c, 0x58, 0x7a, 0x1e, 0x00, 0x91, 0x0c, - 0xe6, 0x6c, 0x43, 0x84, 0x4b, 0x34, 0x0f, 0x75, 0x61, 0x78, 0xd7, 0x53, 0xf5, 0xcc, 0xf0, 0xbb, 0x25, 0x4c, 0xea, - 0x7a, 0x2a, 0x84, 0x4e, 0xca, 0x1a, 0xb6, 0x9e, 0x8b, 0xb0, 0x50, 0x72, 0x0f, 0x99, 0x83, 0x0d, 0x85, 0x58, 0xda, - 0xa8, 0xbf, 0xdc, 0x39, 0x2f, 0x2f, 0x9d, 0x7e, 0xdb, 0x81, 0xb8, 0x26, 0x20, 0x83, 0xc0, 0x02, 0xbb, 0xdf, 0x6e, - 0x43, 0xc1, 0xad, 0x54, 0xd0, 0x82, 0x02, 0x4f, 0x2a, 0xe8, 0x40, 0xc1, 0x44, 0x2a, 0x38, 0x82, 0x82, 0xa9, 0x54, - 0x70, 0x0c, 0x05, 0x37, 0x6a, 0x7a, 0x19, 0x64, 0xc3, 0x3d, 0xd6, 0xaf, 0x0c, 0x62, 0x3b, 0x45, 0xd9, 0xb1, 0xe1, - 0x80, 0x59, 0x9c, 0x3b, 0xef, 0x85, 0x06, 0xc9, 0x9f, 0x7b, 0x91, 0x71, 0xbb, 0x60, 0x94, 0x63, 0xe1, 0x35, 0x52, - 0x08, 0x56, 0x12, 0x82, 0xcb, 0x91, 0x88, 0x5d, 0x24, 0xe0, 0xa0, 0xa8, 0x3a, 0x88, 0x14, 0xfb, 0xd9, 0xca, 0x89, - 0xf8, 0x4f, 0xd2, 0x5a, 0xe6, 0xef, 0xe8, 0x73, 0x66, 0xb6, 0x05, 0x72, 0x8b, 0x27, 0x4d, 0x96, 0x5b, 0x7f, 0x0e, - 0xfb, 0x94, 0xd7, 0x6c, 0xbc, 0x9e, 0x2b, 0xe7, 0xe1, 0x7c, 0xa7, 0x2d, 0x8a, 0xfc, 0x0a, 0x46, 0xa9, 0x92, 0x82, - 0xce, 0x14, 0xdb, 0x92, 0x7f, 0x8b, 0x1e, 0xd3, 0x62, 0xfd, 0x04, 0xc6, 0xa6, 0x24, 0x84, 0x6a, 0xe1, 0x3b, 0x00, - 0x23, 0xc9, 0x18, 0xe4, 0x1c, 0xe0, 0x2c, 0x3d, 0x5f, 0xb8, 0xd2, 0x78, 0x86, 0xdf, 0xb3, 0x38, 0x76, 0xe7, 0xa2, - 0x7e, 0x75, 0x9c, 0xe0, 0x1b, 0x93, 0x71, 0xe8, 0x08, 0x40, 0x90, 0xf5, 0x7a, 0x15, 0x1b, 0x1e, 0x30, 0x41, 0x06, - 0x73, 0x35, 0xd8, 0x50, 0xb9, 0xc1, 0x8b, 0x67, 0xc1, 0x12, 0x16, 0x4d, 0x53, 0xe0, 0xf0, 0xdf, 0x30, 0xbf, 0x5c, - 0x98, 0xb8, 0xf3, 0x72, 0x11, 0xed, 0x83, 0x54, 0x1e, 0x5b, 0x66, 0x19, 0x52, 0x28, 0xfc, 0x14, 0x53, 0x07, 0x3f, - 0x9c, 0xff, 0xae, 0x76, 0x0e, 0x5b, 0xec, 0x53, 0xde, 0x07, 0x46, 0x90, 0x8c, 0x2c, 0x84, 0xb1, 0x62, 0x01, 0x08, - 0x7b, 0x41, 0xb2, 0x30, 0xd1, 0x2b, 0x5b, 0x6b, 0x05, 0xba, 0x61, 0xe1, 0xda, 0x6e, 0xca, 0xb1, 0x28, 0x7a, 0xd1, - 0x7c, 0xec, 0x6a, 0x4e, 0xeb, 0xd8, 0x10, 0x7f, 0x2c, 0xbb, 0xa3, 0xa7, 0xd8, 0x83, 0x32, 0xf5, 0x6e, 0x36, 0xb3, - 0x30, 0x48, 0xcc, 0x99, 0xbb, 0xf4, 0xfc, 0xfb, 0xde, 0x32, 0x0c, 0xc2, 0x78, 0xe5, 0x4e, 0x58, 0x3f, 0x17, 0xb9, - 0xf4, 0x31, 0xca, 0x11, 0x77, 0xb4, 0x77, 0xac, 0x56, 0xc4, 0x96, 0xd4, 0x3a, 0x0b, 0x62, 0x34, 0xf3, 0xd9, 0x5d, - 0xca, 0x3f, 0x5f, 0xa8, 0x4c, 0x55, 0x71, 0xcb, 0x51, 0x0b, 0xe0, 0x1f, 0x78, 0x84, 0x24, 0x88, 0x0b, 0xd8, 0xe7, - 0x44, 0x78, 0xcf, 0x6a, 0x75, 0x22, 0xb6, 0x54, 0xac, 0x4e, 0x63, 0xe7, 0x51, 0x78, 0x3b, 0x84, 0xd1, 0x62, 0x63, - 0x33, 0x66, 0xfe, 0x0c, 0xdf, 0x98, 0xe8, 0x94, 0x29, 0xfa, 0x31, 0x51, 0x54, 0x03, 0xbd, 0xb1, 0x65, 0x1f, 0x5e, - 0xf7, 0x5a, 0x8a, 0xdd, 0x5f, 0x7a, 0x81, 0x49, 0xd3, 0x39, 0xb6, 0x57, 0x52, 0x5f, 0x32, 0xfc, 0xf4, 0x0d, 0x56, - 0x77, 0x14, 0xbb, 0x0f, 0x2c, 0xf9, 0xcc, 0x0f, 0x6f, 0x7b, 0x0b, 0x6f, 0x3a, 0x65, 0x41, 0x1f, 0xc7, 0x9c, 0x15, - 0x32, 0xdf, 0xf7, 0x56, 0xb1, 0x17, 0xf7, 0x97, 0xee, 0x1d, 0xef, 0xf5, 0xb0, 0xa9, 0xd7, 0x36, 0xef, 0xb5, 0xbd, - 0x77, 0xaf, 0x52, 0x37, 0xe0, 0x00, 0x4a, 0xfd, 0xf0, 0xa1, 0x75, 0x14, 0xbb, 0x34, 0xcf, 0xbd, 0x7b, 0x5d, 0x45, - 0x6c, 0xb3, 0x74, 0xa3, 0xb9, 0x17, 0xf4, 0xec, 0xd4, 0xba, 0xd9, 0xd0, 0xc6, 0x78, 0xdc, 0xed, 0x76, 0x53, 0x6b, - 0x2a, 0x9e, 0xec, 0xe9, 0x34, 0xb5, 0x26, 0xe2, 0x69, 0x36, 0xb3, 0xed, 0xd9, 0x2c, 0xb5, 0x3c, 0x51, 0xd0, 0x6e, - 0x4d, 0xa6, 0xed, 0x56, 0x6a, 0xdd, 0x4a, 0x35, 0x52, 0x8b, 0xf1, 0xa7, 0x88, 0x4d, 0xfb, 0xb8, 0x91, 0xb8, 0x3d, - 0xf9, 0xb1, 0x6d, 0xa7, 0x88, 0x01, 0x2e, 0x0b, 0xb8, 0x09, 0xa5, 0x81, 0x57, 0x9b, 0xbd, 0x6b, 0x2a, 0xf9, 0xe7, - 0x26, 0x93, 0xda, 0x7a, 0x53, 0x37, 0xfa, 0x70, 0xa5, 0x48, 0xb3, 0x70, 0x5d, 0xaa, 0xb6, 0x11, 0x60, 0x30, 0xef, - 0x7a, 0x10, 0xed, 0xb2, 0x3f, 0x0e, 0x23, 0x38, 0xb3, 0x91, 0x3b, 0xf5, 0xd6, 0x71, 0xcf, 0x69, 0xad, 0xee, 0x44, - 0x11, 0xdf, 0xeb, 0x79, 0x01, 0x9e, 0xbd, 0x5e, 0x1c, 0xfa, 0xde, 0x54, 0x14, 0x35, 0x9d, 0x25, 0xa7, 0xa5, 0xf7, - 0x31, 0xd6, 0x8b, 0x87, 0x11, 0x8b, 0x5c, 0xdf, 0x57, 0xac, 0x76, 0xac, 0x30, 0x37, 0x46, 0x0d, 0x84, 0x62, 0xc7, - 0x04, 0x17, 0x8c, 0xeb, 0xe2, 0x1c, 0xae, 0xee, 0xb2, 0x3d, 0xef, 0x1c, 0xad, 0xee, 0xd2, 0xaf, 0x96, 0x6c, 0xea, - 0xb9, 0x8a, 0x96, 0xef, 0x26, 0xc7, 0x06, 0x2d, 0x85, 0xbe, 0x69, 0xd8, 0xa6, 0xe2, 0x58, 0x40, 0x54, 0xe0, 0x47, - 0xde, 0x72, 0x15, 0x46, 0x89, 0x1b, 0x24, 0x69, 0x3a, 0xba, 0x4a, 0xd3, 0xfe, 0x85, 0xa7, 0x5d, 0xfe, 0x43, 0xa3, - 0x7b, 0x9a, 0xb4, 0x7a, 0xa9, 0x7e, 0x65, 0xbc, 0x61, 0xb2, 0x05, 0x12, 0x5c, 0x63, 0x68, 0x7d, 0x24, 0x57, 0xa6, - 0x5b, 0xb2, 0x5a, 0x99, 0x80, 0x9c, 0x55, 0x27, 0x83, 0xa6, 0x62, 0x15, 0xbc, 0x81, 0xa0, 0xc2, 0x1b, 0x36, 0xb8, - 0x90, 0xcc, 0x99, 0x80, 0x58, 0xc1, 0xca, 0xe4, 0x92, 0xf7, 0xa4, 0x89, 0x66, 0xfc, 0x7a, 0x37, 0xcd, 0xf8, 0xcf, - 0x64, 0x1f, 0x9a, 0xf1, 0xeb, 0xcf, 0x4e, 0x33, 0x3e, 0xa9, 0xba, 0xe4, 0x9d, 0x85, 0x03, 0x35, 0xd3, 0x41, 0xc1, - 0xd5, 0x14, 0x51, 0xb0, 0xbb, 0xb3, 0xe4, 0xbf, 0x75, 0xa1, 0x13, 0xbd, 0x51, 0xfa, 0x56, 0xba, 0xb9, 0x81, 0xf0, - 0x7e, 0x1b, 0x0c, 0xfe, 0x1e, 0xc9, 0xcf, 0xb3, 0xd9, 0xe0, 0x75, 0x28, 0x15, 0x64, 0x4f, 0xdc, 0x3c, 0xa7, 0x10, - 0x98, 0x88, 0xde, 0x64, 0x06, 0x54, 0x90, 0xba, 0x09, 0xe2, 0x9a, 0x90, 0x91, 0xfc, 0x34, 0x33, 0x63, 0xec, 0x17, - 0x87, 0xa0, 0x65, 0x86, 0xc1, 0xc2, 0x7b, 0xb5, 0x22, 0x6c, 0x9e, 0xb3, 0x84, 0x87, 0x9b, 0x78, 0x79, 0x7f, 0x36, - 0xd5, 0xce, 0x42, 0x3d, 0xf5, 0xe2, 0xb7, 0x65, 0xdf, 0x51, 0xc1, 0x3a, 0xc8, 0xd3, 0x49, 0xb9, 0x29, 0xa2, 0x14, - 0x22, 0x06, 0x5f, 0x53, 0xf3, 0xd3, 0xc2, 0x4c, 0x7b, 0x72, 0x43, 0x9e, 0x23, 0xb2, 0x72, 0x19, 0x73, 0x57, 0xbc, - 0x0d, 0xa7, 0x00, 0x31, 0xed, 0x25, 0x86, 0xdc, 0x98, 0x52, 0x73, 0x6f, 0x9a, 0xa6, 0x7a, 0x5f, 0x00, 0x42, 0xba, - 0x68, 0xd9, 0x2e, 0x22, 0x2e, 0xce, 0x19, 0x51, 0xae, 0x43, 0x26, 0x05, 0xf1, 0x19, 0x98, 0x5c, 0x70, 0x75, 0x32, - 0x87, 0x99, 0xaa, 0x10, 0xf8, 0xc8, 0x14, 0x47, 0x9a, 0x10, 0xd8, 0x08, 0xc8, 0x06, 0x6c, 0x85, 0x05, 0xa9, 0x1a, - 0x03, 0x13, 0x70, 0xd0, 0x66, 0x04, 0x02, 0xe4, 0x08, 0x29, 0x15, 0xa1, 0x1d, 0x5e, 0x07, 0x1f, 0x52, 0x35, 0xa3, - 0xfd, 0x70, 0xfb, 0x0d, 0x4f, 0x0e, 0xa0, 0xc1, 0xb0, 0x24, 0x81, 0xda, 0x61, 0xea, 0x0a, 0xa4, 0x44, 0x7c, 0x6b, - 0x58, 0xf1, 0xad, 0xf2, 0x6c, 0x23, 0x82, 0x4b, 0x25, 0xee, 0xca, 0x04, 0xb1, 0x07, 0xe2, 0x5e, 0x8e, 0xf1, 0xa4, - 0x38, 0x56, 0xfd, 0x75, 0x0c, 0xb8, 0x11, 0x39, 0x70, 0xc4, 0x3f, 0xfd, 0xc9, 0x3a, 0x8a, 0xc3, 0xa8, 0xb7, 0x0a, - 0xbd, 0x20, 0x61, 0x51, 0x8a, 0xa0, 0xba, 0x44, 0xf8, 0x08, 0xf0, 0x5c, 0x6d, 0xc2, 0x95, 0x3b, 0xf1, 0x92, 0xfb, - 0x9e, 0xcd, 0x49, 0x0a, 0xbb, 0xcf, 0xa9, 0x03, 0xbb, 0xb6, 0x7e, 0x8f, 0x43, 0xf3, 0x39, 0x12, 0x7e, 0x51, 0x95, - 0x9c, 0x91, 0xb7, 0x79, 0x5f, 0x7a, 0x4b, 0xe1, 0xb5, 0x80, 0xfc, 0x70, 0x23, 0x73, 0x0e, 0x58, 0x1e, 0x96, 0xda, - 0x9e, 0xb2, 0xb9, 0x81, 0x58, 0x1b, 0x34, 0x37, 0xe2, 0x8f, 0xd5, 0xd1, 0x15, 0xbb, 0xbe, 0x18, 0x28, 0x1e, 0x7d, - 0x9f, 0x91, 0xf5, 0x5c, 0x48, 0x46, 0x69, 0xec, 0x53, 0x73, 0xcc, 0x66, 0x61, 0xc4, 0x28, 0x14, 0xbb, 0xd3, 0x5d, - 0xdd, 0xed, 0xdf, 0xfd, 0xf6, 0xe9, 0xd7, 0xf7, 0x13, 0x84, 0x89, 0x26, 0x3a, 0xd3, 0x77, 0xf4, 0x56, 0xbd, 0xcf, - 0x80, 0x34, 0x24, 0xc8, 0x4f, 0xc8, 0x51, 0xa4, 0xa7, 0xaa, 0xfd, 0xda, 0x88, 0x97, 0xab, 0x90, 0xdf, 0x79, 0x11, - 0xf3, 0xdd, 0xc4, 0xbb, 0x11, 0x34, 0x63, 0xfb, 0x68, 0x75, 0x27, 0xd6, 0x18, 0x2f, 0xbc, 0x07, 0x2c, 0x52, 0x69, - 0x28, 0x62, 0x91, 0xca, 0xc5, 0xb8, 0x48, 0xfd, 0xca, 0x6c, 0x44, 0x10, 0xa8, 0xd2, 0x4d, 0xdf, 0x59, 0xdd, 0xc9, - 0x57, 0x74, 0xde, 0x2c, 0xbb, 0xa9, 0xcb, 0xd1, 0x3b, 0x97, 0xde, 0x74, 0xea, 0xb3, 0xb4, 0xb0, 0xd0, 0xc5, 0xb5, - 0x94, 0x80, 0x93, 0xc1, 0xc1, 0x1d, 0xc7, 0xa1, 0xbf, 0x4e, 0x58, 0x3d, 0xb8, 0x08, 0x38, 0x2d, 0x3b, 0x07, 0x0e, - 0xfe, 0x2e, 0x8e, 0xb5, 0x03, 0xe4, 0x36, 0x6c, 0x13, 0xbb, 0x0f, 0xc1, 0xfa, 0xcd, 0x76, 0x71, 0xe8, 0xf0, 0x2a, - 0x1b, 0xb4, 0x51, 0x33, 0x11, 0x03, 0xae, 0x25, 0xc2, 0xde, 0x8a, 0xe5, 0xf0, 0xb2, 0x2c, 0x60, 0x79, 0x56, 0x94, - 0x16, 0x27, 0xf3, 0xfb, 0x9c, 0xb1, 0x17, 0xf5, 0x67, 0xec, 0x85, 0x38, 0x63, 0xdb, 0x77, 0xe6, 0xe3, 0x99, 0x03, - 0xff, 0xf5, 0xf3, 0x09, 0xf5, 0x6c, 0xa5, 0xbd, 0xba, 0x53, 0x9c, 0xd5, 0x9d, 0x62, 0xb6, 0x56, 0x77, 0x0a, 0x76, - 0x8d, 0x16, 0x43, 0x86, 0xd5, 0xd2, 0x0d, 0x5b, 0x81, 0x42, 0xf8, 0x63, 0x17, 0x5e, 0x39, 0x87, 0xf0, 0x0e, 0x5a, - 0x75, 0xaa, 0xef, 0x5a, 0xdb, 0x8f, 0x3a, 0x9d, 0x25, 0x81, 0xb4, 0x75, 0x2b, 0x71, 0xc7, 0x63, 0x36, 0xed, 0xcd, - 0xc2, 0xc9, 0x3a, 0xfe, 0x37, 0x1f, 0x3f, 0x07, 0xe2, 0x56, 0x44, 0x50, 0xea, 0x47, 0x34, 0x05, 0xa9, 0xdc, 0x0d, - 0x13, 0x3d, 0x6c, 0xb2, 0x75, 0xea, 0x51, 0x66, 0x81, 0x96, 0x75, 0x58, 0xb3, 0xc9, 0xeb, 0x01, 0xfd, 0xbb, 0xad, - 0x52, 0x33, 0x8a, 0xf9, 0x04, 0xb0, 0x6c, 0x05, 0xc7, 0xc3, 0xa1, 0xc1, 0x57, 0xd3, 0xee, 0xd6, 0x0f, 0xf7, 0x52, - 0x7c, 0xe9, 0x4a, 0x5c, 0x2a, 0xfc, 0xde, 0xe2, 0xee, 0x4b, 0xdb, 0x7b, 0x6d, 0xda, 0x23, 0x95, 0x5e, 0xb7, 0x5c, - 0x08, 0x79, 0xdd, 0x3d, 0xb1, 0xfc, 0xe3, 0x17, 0x87, 0xf0, 0x1f, 0x51, 0xf5, 0xff, 0x4c, 0xea, 0x08, 0xf5, 0xb3, - 0xa4, 0x40, 0xa8, 0x13, 0xa9, 0x84, 0x84, 0xf8, 0xfe, 0xf5, 0x67, 0xb3, 0x87, 0x35, 0xd8, 0xbb, 0x36, 0x19, 0xdb, - 0x95, 0x6b, 0xbf, 0x0c, 0x43, 0xc8, 0x7a, 0x5d, 0xad, 0x2e, 0xc0, 0x43, 0x9e, 0x13, 0xc9, 0x00, 0x1a, 0x09, 0x3e, - 0x82, 0xec, 0x3c, 0x54, 0x6c, 0x43, 0xac, 0xc4, 0x9b, 0x26, 0x56, 0xe2, 0xf5, 0x6e, 0x56, 0xe2, 0xbb, 0xbd, 0x58, - 0x89, 0xd7, 0x9f, 0x9d, 0x95, 0x78, 0x53, 0x65, 0x25, 0x2e, 0x42, 0x61, 0x61, 0x6d, 0x9c, 0xad, 0xf9, 0xcf, 0x9f, - 0x49, 0x85, 0x7a, 0x1e, 0x0e, 0x3a, 0x36, 0x65, 0x0b, 0xb8, 0xf8, 0xaf, 0x19, 0x0b, 0xdc, 0x88, 0xef, 0xd0, 0xe0, - 0x30, 0x67, 0x2d, 0x38, 0x66, 0xc7, 0xef, 0x48, 0xc5, 0x7e, 0x18, 0xcc, 0x7f, 0x04, 0x15, 0x3a, 0x88, 0x03, 0x23, - 0xe9, 0x85, 0x17, 0xff, 0x18, 0xae, 0xd6, 0xab, 0x33, 0xe8, 0xeb, 0x67, 0x2f, 0xf6, 0xc6, 0x3e, 0xcb, 0xa2, 0x78, - 0x90, 0x81, 0x24, 0x97, 0x89, 0x83, 0x4d, 0xb2, 0xf8, 0xe9, 0xde, 0x89, 0x9f, 0x68, 0xb5, 0xcc, 0x7f, 0x93, 0xe5, - 0xa5, 0x5a, 0xcf, 0x88, 0x40, 0xb8, 0xbb, 0xd2, 0xa0, 0x1f, 0xce, 0x8c, 0x5c, 0x84, 0x7a, 0xcd, 0x2c, 0x85, 0x45, - 0x4c, 0x63, 0x3f, 0xac, 0xc2, 0xd4, 0xac, 0x75, 0x23, 0x8b, 0x5e, 0x59, 0x15, 0xc3, 0x2f, 0xc3, 0x75, 0xcc, 0xa6, - 0xe1, 0x6d, 0xa0, 0x1a, 0x01, 0x37, 0xe3, 0xa4, 0x04, 0x80, 0x59, 0x1b, 0xcc, 0xbb, 0xfc, 0x1e, 0x09, 0x65, 0x88, - 0x74, 0x00, 0x69, 0xbf, 0xd7, 0x2b, 0x93, 0x0c, 0x03, 0x4c, 0x9c, 0xa2, 0x9a, 0x25, 0x08, 0x7c, 0xa4, 0x69, 0xe1, - 0xe0, 0x61, 0x2d, 0x85, 0x31, 0x4f, 0x68, 0x71, 0xa9, 0x70, 0xac, 0x05, 0x42, 0xb8, 0x28, 0x42, 0x48, 0xd5, 0x2c, - 0x1c, 0x7f, 0x43, 0x21, 0x3a, 0xf2, 0xb7, 0x10, 0xd1, 0x21, 0x5d, 0xf3, 0xf5, 0xe0, 0x01, 0x95, 0xe8, 0xf1, 0x95, - 0x04, 0xc6, 0xb7, 0x37, 0x2c, 0xf2, 0xdd, 0x7b, 0x4d, 0x4f, 0xc3, 0xe0, 0x7b, 0x00, 0xc0, 0xeb, 0xf0, 0x36, 0x90, - 0x2b, 0x60, 0x9e, 0xb3, 0x9a, 0xbd, 0x54, 0x1b, 0xfa, 0x0b, 0xdc, 0xa0, 0xa4, 0x11, 0x40, 0x86, 0xf9, 0x39, 0xfb, - 0xbb, 0x41, 0xff, 0xfe, 0x43, 0x4f, 0x8d, 0xf3, 0x30, 0xfb, 0xd0, 0x4f, 0xab, 0x3d, 0x3e, 0xf3, 0xf4, 0xe9, 0xa3, - 0xe6, 0x69, 0x6b, 0x13, 0x9f, 0xb9, 0x22, 0x6f, 0xbc, 0x56, 0xd3, 0x5a, 0x6f, 0x3c, 0x05, 0x30, 0x8a, 0x8b, 0x70, - 0x3d, 0x59, 0xa0, 0x29, 0xf4, 0xe7, 0x9b, 0x6f, 0x02, 0x7d, 0x62, 0x82, 0xef, 0x6c, 0xea, 0xa5, 0xa2, 0x1c, 0x0a, - 0xf8, 0xfd, 0x37, 0x10, 0xbb, 0xfa, 0x4f, 0x04, 0x43, 0x75, 0xd7, 0x64, 0x6e, 0xd2, 0x0f, 0xda, 0xbc, 0x7d, 0xc8, - 0x43, 0xcd, 0xa3, 0x42, 0x09, 0xe5, 0x5a, 0x3d, 0x92, 0x49, 0xcb, 0x40, 0x93, 0x23, 0xb0, 0x36, 0x05, 0x97, 0x15, - 0x5f, 0x61, 0x16, 0xb1, 0xe9, 0xdc, 0x15, 0xc5, 0x60, 0x1c, 0x5b, 0x95, 0x90, 0x0c, 0x37, 0x50, 0x61, 0x88, 0xbe, - 0xca, 0xef, 0x96, 0x5e, 0x60, 0x60, 0x02, 0x95, 0xea, 0x1b, 0xf7, 0x0e, 0x52, 0x08, 0x00, 0x72, 0x2b, 0xbf, 0x82, - 0x42, 0x43, 0x76, 0xc0, 0x84, 0x2c, 0x89, 0x6a, 0x2d, 0x24, 0x84, 0x16, 0x6f, 0xf4, 0x85, 0xa2, 0x28, 0x4a, 0xc6, - 0x46, 0x28, 0x19, 0x1f, 0x81, 0xe5, 0xc8, 0x0e, 0x80, 0xb6, 0x24, 0x5d, 0xdd, 0x51, 0x09, 0x70, 0x06, 0xa8, 0x92, - 0x16, 0x05, 0x3c, 0x4a, 0x6e, 0xc7, 0x16, 0x05, 0x82, 0xa1, 0x87, 0x08, 0xa7, 0x6e, 0x04, 0xc1, 0xf4, 0x7b, 0x0a, - 0x32, 0xec, 0xf8, 0x96, 0x4b, 0x82, 0x15, 0x9b, 0x1e, 0x47, 0x7d, 0x56, 0x1f, 0x4e, 0x35, 0x90, 0xb0, 0x20, 0x68, - 0x1d, 0x4a, 0xd9, 0x11, 0x0c, 0x56, 0x83, 0x1b, 0x91, 0x2f, 0xba, 0x4b, 0x96, 0x2c, 0x58, 0xab, 0x98, 0x4e, 0x11, - 0xc3, 0xdb, 0x42, 0x9d, 0xd7, 0x44, 0x6c, 0x01, 0xb6, 0xa9, 0x6f, 0xb9, 0xa0, 0xbb, 0x30, 0xe6, 0x28, 0xd5, 0x35, - 0x26, 0x5c, 0xb1, 0x19, 0x73, 0xdc, 0x56, 0xbe, 0x21, 0xf8, 0x92, 0x86, 0x45, 0x6c, 0xce, 0xbd, 0x88, 0x91, 0x52, - 0xa0, 0xc8, 0x52, 0x5c, 0x5c, 0x24, 0xc0, 0xae, 0xb9, 0xe5, 0x45, 0xcb, 0x34, 0x32, 0x6e, 0x49, 0x50, 0x14, 0xe9, - 0xd5, 0x6e, 0xf8, 0x38, 0x21, 0xa6, 0x5f, 0x63, 0x3f, 0x93, 0x4a, 0x3f, 0x0d, 0x93, 0xfe, 0xc0, 0xee, 0xe9, 0x22, - 0x21, 0x50, 0x7d, 0x60, 0xf7, 0xa0, 0x6f, 0x7f, 0x03, 0xd2, 0x14, 0x75, 0x0b, 0xba, 0x36, 0x20, 0x4b, 0xce, 0x04, - 0xe2, 0x3c, 0x6e, 0x39, 0x40, 0x76, 0xba, 0x05, 0x8b, 0x23, 0x88, 0x03, 0x23, 0xee, 0x8b, 0x43, 0xcc, 0x9d, 0x40, - 0xb4, 0x5a, 0x18, 0x9b, 0x35, 0x47, 0x43, 0x7f, 0xe6, 0xd8, 0xf6, 0x41, 0xa5, 0x3e, 0x08, 0xb2, 0xeb, 0x6a, 0xeb, - 0x46, 0x32, 0x70, 0x6c, 0xd3, 0x7b, 0x66, 0xb5, 0xfa, 0x95, 0x3b, 0x5a, 0x0a, 0xc3, 0x3c, 0x42, 0xf1, 0xd7, 0xf0, - 0xc9, 0x46, 0xab, 0x1c, 0x48, 0xbd, 0xec, 0x54, 0x81, 0x63, 0x4b, 0xb9, 0xfc, 0x6b, 0x54, 0xbd, 0xfa, 0x29, 0x08, - 0x34, 0xa5, 0x04, 0x1b, 0x41, 0x22, 0x01, 0x0d, 0x8e, 0xd1, 0x5f, 0x94, 0xe7, 0x8a, 0x46, 0xc7, 0x47, 0xd7, 0x47, - 0x7d, 0x81, 0x51, 0x84, 0xd7, 0xa1, 0xdc, 0x41, 0xe9, 0x8b, 0x71, 0x19, 0xc3, 0xf1, 0x90, 0xe5, 0x2c, 0xd7, 0xe8, - 0x6d, 0xa5, 0x16, 0xb0, 0xff, 0x86, 0xeb, 0xd3, 0x1a, 0x43, 0x5c, 0x0c, 0xa8, 0x01, 0x69, 0x47, 0x76, 0x76, 0x08, - 0xe1, 0x8e, 0xe4, 0xee, 0x8a, 0x97, 0xe4, 0xfe, 0x9d, 0xe1, 0xa5, 0x83, 0x3a, 0xb4, 0xac, 0xbf, 0xfa, 0xeb, 0xee, - 0x81, 0x5d, 0xb2, 0x60, 0x5a, 0xec, 0xb0, 0x74, 0x7f, 0xed, 0xdf, 0x5d, 0x01, 0xa3, 0x40, 0x3e, 0x9e, 0xb0, 0x06, - 0xa3, 0xa4, 0x61, 0x80, 0x9b, 0x9f, 0x8e, 0x9b, 0xb7, 0x17, 0x15, 0x83, 0x0d, 0x28, 0x98, 0x66, 0xd6, 0x4c, 0x12, - 0x8a, 0x43, 0xd2, 0x07, 0x74, 0x4a, 0xd6, 0x04, 0x21, 0xda, 0xb8, 0x13, 0x13, 0x61, 0x01, 0x9a, 0xb7, 0xf1, 0x78, - 0x18, 0xe7, 0x7d, 0xa5, 0xd6, 0xde, 0x6e, 0xa9, 0x75, 0xb2, 0x4b, 0x6a, 0x4d, 0x0e, 0x77, 0x64, 0xb6, 0x94, 0x39, - 0x1e, 0x0a, 0xe2, 0x5c, 0x76, 0xdd, 0x2c, 0x88, 0xba, 0xd1, 0x3f, 0x4f, 0xb4, 0xaa, 0xf4, 0x46, 0x36, 0x9d, 0x28, - 0xfe, 0x96, 0x18, 0x14, 0xa1, 0x50, 0x97, 0x65, 0xe3, 0x17, 0xb9, 0x6c, 0x9c, 0xb8, 0x9a, 0xdc, 0xd5, 0x4a, 0x50, - 0xff, 0x92, 0x1b, 0x63, 0xc6, 0x1d, 0xe4, 0xee, 0x8c, 0xf9, 0x48, 0x25, 0x07, 0xbd, 0x9c, 0xd1, 0x90, 0xdc, 0x3e, - 0x05, 0x97, 0x51, 0xf4, 0xfe, 0x2c, 0x56, 0xcd, 0xfd, 0xf3, 0xf2, 0x72, 0x90, 0xba, 0xe3, 0x90, 0xb3, 0x62, 0x79, - 0xdb, 0x14, 0x1d, 0xb4, 0xe4, 0xd7, 0xd2, 0x26, 0xc9, 0x3c, 0xa9, 0x08, 0xc0, 0x42, 0x4c, 0x5f, 0xd2, 0x6b, 0x67, - 0x36, 0x10, 0x38, 0xc8, 0x1a, 0xc7, 0xcf, 0xdd, 0xd2, 0x79, 0x4a, 0x35, 0x94, 0xab, 0xae, 0x1d, 0xbc, 0xdd, 0x49, - 0x13, 0x2c, 0xcb, 0x23, 0x10, 0xd6, 0x57, 0x92, 0x04, 0xa1, 0x67, 0x2b, 0x76, 0xbf, 0x86, 0x00, 0xc0, 0xfb, 0xbf, - 0xfc, 0xcc, 0x49, 0x01, 0x90, 0x44, 0x2a, 0xb6, 0xac, 0xf3, 0xc7, 0x43, 0x6c, 0x92, 0xd9, 0x18, 0x56, 0xad, 0x7e, - 0x93, 0xe4, 0x3d, 0x1b, 0xee, 0x66, 0x55, 0x14, 0xe7, 0xf3, 0x1a, 0x3d, 0x31, 0x0e, 0xbe, 0xcb, 0xa2, 0x75, 0x80, - 0x19, 0x64, 0xcc, 0x24, 0x72, 0x27, 0x1f, 0x36, 0xd2, 0xf7, 0xb8, 0x48, 0x14, 0xc4, 0xc5, 0x45, 0xa5, 0x42, 0xdf, - 0xc5, 0x80, 0xcb, 0xac, 0x67, 0xb5, 0x62, 0x49, 0x50, 0xd3, 0x7b, 0x6c, 0xb7, 0xdd, 0x17, 0xb3, 0xc3, 0x92, 0xfc, - 0xb4, 0xd5, 0x29, 0x4a, 0xd7, 0xb3, 0x71, 0x2c, 0xc3, 0x5f, 0xb9, 0x43, 0xea, 0x1f, 0xff, 0xe9, 0x98, 0x7f, 0xb3, - 0xb4, 0x46, 0x9f, 0x32, 0x04, 0x68, 0x5f, 0x50, 0x4c, 0xcb, 0x6a, 0x9a, 0x4a, 0x49, 0xd3, 0xb0, 0x66, 0x9e, 0xef, - 0x9b, 0x3e, 0xb8, 0x05, 0x6d, 0x3e, 0x69, 0x7a, 0xd8, 0xcf, 0x1a, 0x42, 0xfd, 0x7f, 0x42, 0x3f, 0xc5, 0x9d, 0x92, - 0x2c, 0xd6, 0xcb, 0xf1, 0x46, 0x16, 0x94, 0x4b, 0xf2, 0xf3, 0xaa, 0xcc, 0x5c, 0xfe, 0xec, 0x6c, 0x36, 0x2b, 0x4a, - 0x8d, 0x6d, 0xe5, 0x10, 0x25, 0xbf, 0x8f, 0x6d, 0xdb, 0x2e, 0xc3, 0xb7, 0xe9, 0xa0, 0xd0, 0xc1, 0x30, 0x51, 0x08, - 0xdf, 0xdd, 0xbd, 0xa7, 0xfe, 0xa0, 0xd1, 0x52, 0x57, 0x4d, 0xe7, 0x91, 0xb6, 0xda, 0xff, 0x8b, 0xa1, 0x20, 0x6a, - 0xd8, 0x75, 0xfc, 0xab, 0x7b, 0x65, 0x4b, 0x4f, 0xe5, 0x03, 0xfc, 0xb0, 0xc6, 0x3b, 0xf6, 0xfa, 0x1e, 0x4d, 0x9b, - 0xb6, 0x77, 0x6a, 0xe5, 0xd7, 0x6e, 0xc1, 0x66, 0xa9, 0x4f, 0x96, 0x4a, 0x5e, 0xc2, 0x96, 0x71, 0x6f, 0xc2, 0x50, - 0x41, 0x6a, 0x49, 0xb7, 0x2d, 0x5a, 0xf5, 0x98, 0x73, 0xb0, 0xe3, 0x72, 0x04, 0x1e, 0xb6, 0x15, 0x54, 0x56, 0x55, - 0x34, 0x6b, 0xe2, 0x23, 0x78, 0x8b, 0x6d, 0xaa, 0x0a, 0x27, 0xdc, 0xa6, 0x1d, 0xfb, 0x2f, 0x85, 0x7a, 0x0a, 0x50, - 0xa7, 0x1b, 0x61, 0x6d, 0x42, 0xca, 0x13, 0xfc, 0x3b, 0x53, 0xce, 0xbd, 0x58, 0xdd, 0x15, 0x8d, 0xbb, 0xba, 0xa0, - 0x6e, 0xca, 0xaf, 0x32, 0x1a, 0x75, 0x1d, 0xea, 0xcb, 0x4c, 0x80, 0x66, 0xb2, 0x75, 0x0b, 0x58, 0xd0, 0x14, 0x12, - 0xdb, 0xd5, 0xe8, 0xc6, 0x90, 0x9d, 0x85, 0x9d, 0x97, 0xcb, 0xf7, 0xf3, 0xb4, 0xcc, 0x30, 0x07, 0xe3, 0x79, 0x17, - 0x95, 0x7b, 0x85, 0xad, 0x8a, 0xa6, 0x32, 0xb8, 0x07, 0x04, 0x47, 0xaa, 0xac, 0x23, 0xdf, 0xa4, 0xac, 0x6f, 0x9a, - 0xbe, 0xa9, 0xce, 0xbb, 0xb9, 0x7b, 0xa7, 0x03, 0x7a, 0x8d, 0x2a, 0xa8, 0xf6, 0x52, 0xed, 0x95, 0x75, 0xd8, 0x62, - 0x9c, 0xb0, 0x02, 0xe0, 0x42, 0xa2, 0xa0, 0xd1, 0x90, 0x52, 0xc2, 0x7d, 0x34, 0xe9, 0xec, 0xad, 0x8c, 0xac, 0xc5, - 0x3c, 0xb1, 0xbb, 0xfa, 0x2a, 0xd4, 0xb7, 0xd0, 0x0c, 0x02, 0xec, 0x38, 0x76, 0xc2, 0x67, 0x13, 0x76, 0x8c, 0x8c, - 0xae, 0x1c, 0xdc, 0x41, 0x78, 0x4a, 0x4d, 0x8a, 0x4b, 0x4b, 0xa7, 0x14, 0x75, 0x09, 0xdf, 0xd5, 0x0a, 0xef, 0x2f, - 0x0a, 0xd2, 0x78, 0xee, 0xc7, 0xd3, 0xd2, 0xf7, 0xaa, 0xbd, 0xf4, 0x82, 0xfd, 0xeb, 0xba, 0x77, 0x7b, 0xd7, 0x05, - 0xe2, 0x70, 0xef, 0xca, 0x40, 0x5d, 0x92, 0x95, 0x52, 0x32, 0xf8, 0x4e, 0x52, 0x1e, 0xc8, 0x31, 0x28, 0x54, 0x6c, - 0x45, 0x1c, 0xfd, 0xc5, 0x7a, 0x30, 0x3a, 0x39, 0xbd, 0x5b, 0xfa, 0xca, 0x0d, 0x8b, 0x20, 0x03, 0xe6, 0x40, 0x75, - 0x2c, 0x5b, 0x55, 0x30, 0xa2, 0x82, 0x17, 0xcc, 0x07, 0xea, 0x4f, 0x17, 0xdf, 0x98, 0x5d, 0xf5, 0x14, 0xcc, 0x31, - 0x6e, 0xe6, 0x48, 0xe2, 0x9e, 0xbb, 0xf7, 0x2c, 0xba, 0x6e, 0xa9, 0x0a, 0x26, 0xba, 0x24, 0xe2, 0x16, 0xcb, 0x94, - 0x96, 0xba, 0x47, 0x3e, 0x35, 0x45, 0xa4, 0x44, 0x56, 0x01, 0xb1, 0x3a, 0xad, 0xae, 0xe2, 0xb4, 0x0e, 0xad, 0xa3, - 0xae, 0x3a, 0xfc, 0x42, 0x51, 0x4e, 0xa6, 0x6c, 0x16, 0x0f, 0x51, 0x1c, 0x73, 0x82, 0xf4, 0x20, 0xfd, 0x56, 0x14, - 0x6b, 0xe2, 0xc7, 0xa6, 0xa3, 0x6c, 0xf8, 0xa3, 0xa2, 0x00, 0x32, 0xea, 0x29, 0x8f, 0x67, 0xad, 0xd9, 0xe1, 0xec, - 0x45, 0x9f, 0x17, 0xa7, 0x5f, 0x14, 0xaa, 0x1b, 0xf4, 0x6f, 0x4b, 0x6a, 0x16, 0x27, 0x51, 0xf8, 0x81, 0x71, 0x5a, - 0x52, 0xc9, 0x04, 0x45, 0xe5, 0xa6, 0xad, 0xea, 0x97, 0x9c, 0xee, 0x78, 0x32, 0x6b, 0xe5, 0xd5, 0x71, 0x8c, 0x07, - 0xd9, 0x20, 0x4f, 0x0e, 0xc4, 0xd0, 0x4f, 0x64, 0x30, 0x39, 0x66, 0x1d, 0xa0, 0x1c, 0x95, 0xcf, 0x71, 0x2e, 0xe6, - 0x77, 0x02, 0xe1, 0xca, 0x73, 0xcf, 0x8b, 0x18, 0x9b, 0x0d, 0xd4, 0xef, 0x9d, 0x56, 0xd7, 0x70, 0x9c, 0x23, 0xeb, - 0xa8, 0x3b, 0xb1, 0x8d, 0x43, 0xeb, 0xd0, 0x6c, 0x5b, 0x47, 0x46, 0xd7, 0xec, 0x1a, 0xdd, 0x6f, 0xbb, 0x13, 0xf3, - 0xd0, 0x3a, 0x34, 0x6c, 0xb3, 0x0b, 0x85, 0x66, 0xd7, 0xec, 0xde, 0x98, 0x87, 0xdd, 0x89, 0x8d, 0xa5, 0x2d, 0xab, - 0xd3, 0x31, 0x1d, 0xdb, 0xea, 0x74, 0x8c, 0x8e, 0x75, 0x74, 0x64, 0x3a, 0x6d, 0xeb, 0xe8, 0xe8, 0xbc, 0xd3, 0xb5, - 0xda, 0xf0, 0xae, 0xdd, 0x9e, 0xb4, 0x2d, 0xc7, 0x31, 0xe1, 0x2f, 0xa3, 0x6b, 0xb5, 0xe8, 0x87, 0xe3, 0x58, 0x6d, - 0xc7, 0xb0, 0xfd, 0x4e, 0xcb, 0x3a, 0x7a, 0x61, 0xe0, 0xdf, 0x58, 0xcd, 0xc0, 0xbf, 0xa0, 0x1b, 0xe3, 0x85, 0xd5, - 0x3a, 0xa2, 0x5f, 0xd8, 0xe1, 0xcd, 0x61, 0xf7, 0x9f, 0xea, 0x41, 0xe3, 0x1c, 0x1c, 0x9a, 0x43, 0xb7, 0x63, 0xb5, - 0xdb, 0xc6, 0xa1, 0x63, 0x75, 0xdb, 0x0b, 0xf3, 0xb0, 0x65, 0x1d, 0x1d, 0x4f, 0x4c, 0xc7, 0x3a, 0x3e, 0x36, 0x6c, - 0xb3, 0x6d, 0xb5, 0x0c, 0xc7, 0x3a, 0x6c, 0xe3, 0x8f, 0xb6, 0xd5, 0xba, 0x39, 0x7e, 0x61, 0x1d, 0x75, 0x16, 0x47, - 0xd6, 0xe1, 0xcf, 0x87, 0x5d, 0xab, 0xd5, 0x5e, 0xb4, 0x8f, 0xac, 0xd6, 0xf1, 0xcd, 0x91, 0x75, 0xb8, 0x30, 0x5b, - 0x47, 0x5b, 0x5b, 0x3a, 0x2d, 0x0b, 0x60, 0x84, 0xaf, 0xe1, 0x85, 0xc1, 0x5f, 0xc0, 0x9f, 0x05, 0xb6, 0xfd, 0x03, - 0xbb, 0x89, 0xab, 0x4d, 0x5f, 0x58, 0xdd, 0xe3, 0x09, 0x55, 0x87, 0x02, 0x53, 0xd4, 0x80, 0x26, 0x37, 0x26, 0x7d, - 0x16, 0xbb, 0x33, 0x45, 0x47, 0xe2, 0x0f, 0xff, 0xd8, 0x8d, 0x09, 0x1f, 0xa6, 0xef, 0xfe, 0xa9, 0xfd, 0x64, 0x4b, - 0x0e, 0x09, 0xde, 0xbf, 0xe0, 0xff, 0x50, 0x6e, 0xc4, 0x91, 0x71, 0xde, 0xa4, 0x94, 0x7c, 0xb7, 0x5b, 0x29, 0xf9, - 0xcd, 0x7a, 0x1f, 0xa5, 0xe4, 0xbb, 0xcf, 0xae, 0x94, 0x3c, 0x2f, 0xfb, 0xc4, 0xbc, 0x2b, 0xa7, 0x70, 0xfa, 0x6e, - 0x53, 0x16, 0x39, 0x78, 0xae, 0x76, 0x79, 0xb1, 0xbe, 0x82, 0x90, 0x7c, 0xef, 0xc2, 0xc1, 0x37, 0xeb, 0x82, 0xc1, - 0x67, 0x08, 0x38, 0xf6, 0x5d, 0x48, 0x38, 0xf6, 0x87, 0xf5, 0x00, 0xac, 0xcc, 0x38, 0x99, 0xe3, 0x4d, 0xcd, 0x85, - 0xeb, 0xcf, 0x32, 0x12, 0x09, 0x4a, 0xfa, 0x58, 0x0c, 0x0e, 0x67, 0x70, 0x3d, 0x03, 0x27, 0xb3, 0x5e, 0x06, 0x31, - 0x58, 0x04, 0x83, 0x25, 0xc7, 0x2c, 0x4a, 0x4b, 0x8d, 0x2d, 0x11, 0xc4, 0xf0, 0x9a, 0x7b, 0x2f, 0x35, 0xbe, 0x47, - 0x03, 0xe0, 0xfa, 0xde, 0x9d, 0x6a, 0xbf, 0x0a, 0x58, 0xd6, 0x09, 0x03, 0x69, 0xa0, 0xf6, 0xeb, 0xde, 0x17, 0xcd, - 0x70, 0x4b, 0x86, 0xd7, 0xcd, 0x23, 0x85, 0x91, 0x94, 0xdb, 0x3b, 0x45, 0x33, 0xde, 0x5d, 0xd3, 0xac, 0xf9, 0x7c, - 0xa1, 0xf9, 0x16, 0x1b, 0xe2, 0xac, 0xe3, 0x32, 0xa8, 0x4a, 0x09, 0x88, 0x6b, 0x01, 0x92, 0x33, 0xa8, 0xb9, 0xa1, - 0x71, 0x4e, 0xa9, 0xda, 0x0a, 0xd2, 0x3b, 0xb6, 0xf4, 0xae, 0xd0, 0xa7, 0x6c, 0x9c, 0xfc, 0x6c, 0x83, 0x7c, 0x85, - 0xf7, 0x2b, 0x50, 0xa2, 0x9c, 0xe2, 0x19, 0x87, 0x32, 0x9c, 0x37, 0x52, 0xbf, 0x24, 0x8d, 0x48, 0x17, 0xce, 0xa6, - 0x4a, 0x8b, 0x36, 0xba, 0x25, 0x38, 0x6c, 0x29, 0xa8, 0x20, 0xfc, 0x3c, 0x39, 0x01, 0xa4, 0xe4, 0xa8, 0x81, 0x7e, - 0x0e, 0xdb, 0x3a, 0x13, 0xf5, 0x1e, 0xc3, 0x26, 0xe6, 0xc1, 0x92, 0x15, 0x39, 0x4a, 0xcc, 0x66, 0xe6, 0x87, 0x6e, - 0xd2, 0x43, 0x32, 0x4d, 0x22, 0x79, 0x5b, 0xe8, 0xb1, 0xd0, 0xdf, 0x62, 0x4c, 0x27, 0x77, 0xcc, 0x3b, 0x41, 0xcf, - 0x87, 0x6d, 0xf6, 0x77, 0x99, 0xa3, 0xd8, 0xa6, 0x60, 0x8e, 0xe2, 0x74, 0x8e, 0x0d, 0xe7, 0xc8, 0xb0, 0x8e, 0x3b, - 0x7a, 0x2a, 0x0e, 0x9c, 0xdc, 0x65, 0x01, 0x20, 0xe0, 0x00, 0x91, 0x0d, 0xd3, 0x0b, 0xbc, 0xc4, 0x73, 0xfd, 0x14, - 0xe8, 0xe1, 0x22, 0x93, 0xf2, 0xaf, 0x75, 0x9c, 0xc0, 0x1c, 0x05, 0xd1, 0x8b, 0xce, 0x1f, 0xe6, 0x98, 0x25, 0xb7, - 0x8c, 0x05, 0x0d, 0x86, 0x31, 0x65, 0x5f, 0x92, 0xdf, 0xcf, 0xb2, 0x3e, 0x25, 0xab, 0xb5, 0x71, 0x12, 0xf0, 0xfd, - 0x21, 0x1c, 0x1f, 0xd2, 0x91, 0xf1, 0x6b, 0x13, 0xc2, 0xfd, 0xd7, 0x6e, 0x84, 0x9b, 0xb0, 0x7d, 0x10, 0xee, 0xbf, - 0x3e, 0x3b, 0xc2, 0xfd, 0x55, 0x46, 0xb8, 0x05, 0xbf, 0xbf, 0x5c, 0xc3, 0xf4, 0x1e, 0x9f, 0x35, 0x48, 0x7e, 0xf2, - 0x5c, 0x3d, 0x20, 0x02, 0x1e, 0xf2, 0x42, 0x88, 0xe8, 0x5b, 0x2f, 0x0b, 0x49, 0x36, 0x51, 0x00, 0x8a, 0x89, 0x35, - 0x28, 0xa1, 0x9f, 0x37, 0x18, 0x0c, 0xec, 0x2c, 0xa9, 0x1f, 0xbb, 0x55, 0xce, 0x82, 0xc4, 0xb7, 0xde, 0x71, 0x3e, - 0x12, 0x14, 0xba, 0xdf, 0x84, 0xd1, 0xd2, 0xc5, 0xa8, 0xad, 0x2a, 0x26, 0xe7, 0x86, 0x07, 0x1b, 0x9c, 0x68, 0x27, - 0x61, 0x30, 0xcd, 0xb4, 0x92, 0x6c, 0x70, 0x49, 0x14, 0xb7, 0x7a, 0xcf, 0xdc, 0x48, 0x35, 0xe8, 0x35, 0x2c, 0xee, - 0xb3, 0xb6, 0xfd, 0xac, 0x75, 0xf8, 0xec, 0xc8, 0x86, 0xff, 0x1d, 0xd6, 0x4e, 0x0d, 0x5e, 0x71, 0x19, 0x06, 0x90, - 0x1f, 0x50, 0xd4, 0x6c, 0xaa, 0x76, 0xcb, 0xd8, 0x87, 0xbc, 0xd6, 0x71, 0x7d, 0xa5, 0xa9, 0x7b, 0x9f, 0xd7, 0xa9, - 0xad, 0xb1, 0x08, 0xd7, 0xd2, 0xb0, 0x6a, 0x46, 0xe3, 0x05, 0x6b, 0x90, 0xb3, 0x4b, 0x35, 0xe4, 0xd7, 0x7c, 0xba, - 0xf9, 0xbc, 0x58, 0x3b, 0xbd, 0xca, 0x93, 0x90, 0x8a, 0x64, 0x88, 0x3b, 0x21, 0xc8, 0x55, 0x94, 0x36, 0xc6, 0xe9, - 0xc6, 0x4c, 0x11, 0x10, 0xa5, 0x3b, 0x4b, 0x1d, 0xe9, 0xd2, 0x02, 0x25, 0xd1, 0x3a, 0x98, 0x68, 0xf8, 0xd3, 0x1d, - 0xc7, 0x9a, 0x77, 0x10, 0x59, 0xfc, 0xc3, 0x3a, 0xae, 0x9a, 0x3b, 0xb4, 0xf3, 0x8c, 0x6d, 0xb1, 0x58, 0x15, 0xf7, - 0x59, 0x62, 0x44, 0xa8, 0xc7, 0xa6, 0xa5, 0x35, 0x07, 0xee, 0xb3, 0xac, 0xe1, 0xb3, 0xc4, 0x08, 0x9e, 0x83, 0xee, - 0x73, 0x60, 0x3f, 0x7d, 0x4a, 0xb5, 0x20, 0xfb, 0x39, 0x4d, 0xeb, 0x74, 0x92, 0x07, 0xfb, 0x54, 0xdc, 0x79, 0x48, - 0xf1, 0x3e, 0x7b, 0x13, 0x23, 0x7c, 0xfe, 0x7c, 0x38, 0x70, 0x74, 0xcc, 0x06, 0x2a, 0xb2, 0x7a, 0xf3, 0x44, 0xb3, - 0xe7, 0xfb, 0x19, 0x1a, 0xe9, 0xb5, 0x2e, 0xb0, 0x2b, 0xe0, 0x99, 0x6c, 0xe1, 0x8e, 0xc0, 0xb1, 0x17, 0x24, 0x7e, - 0x23, 0x83, 0x02, 0x57, 0x18, 0xfc, 0x88, 0x3a, 0x19, 0xd7, 0xd5, 0xb6, 0x6c, 0xcb, 0x56, 0xb3, 0x86, 0x33, 0x6f, - 0x3e, 0xd8, 0x84, 0x89, 0x0b, 0x29, 0x34, 0xfd, 0x70, 0x0e, 0x7e, 0x74, 0x89, 0x97, 0xf8, 0x90, 0x8f, 0x11, 0x1c, - 0xea, 0x96, 0xc4, 0x97, 0xa7, 0xdc, 0xbb, 0xc1, 0x8d, 0x3e, 0x60, 0x4e, 0x6e, 0xe1, 0x42, 0x8b, 0xf1, 0xe7, 0xbe, - 0x87, 0xcb, 0x50, 0x53, 0x35, 0x90, 0x0d, 0xb0, 0x28, 0x36, 0x65, 0x6f, 0xa1, 0x9e, 0x02, 0x6d, 0x74, 0x95, 0x4f, - 0x62, 0x16, 0xb9, 0x4b, 0xc8, 0x5d, 0xb4, 0x49, 0x0d, 0x8e, 0x69, 0x55, 0x8e, 0x6a, 0x15, 0xe7, 0xc5, 0x91, 0xa1, - 0xb4, 0x1c, 0x43, 0xb1, 0x01, 0xdd, 0xaa, 0xa9, 0xb1, 0x49, 0xaf, 0xfa, 0xbb, 0x0c, 0x1e, 0x08, 0xbf, 0x3c, 0xa6, - 0x79, 0x90, 0xa9, 0x03, 0x57, 0x25, 0x25, 0x14, 0x77, 0x58, 0x93, 0x32, 0x92, 0x78, 0xa4, 0xf4, 0xbc, 0x60, 0x77, - 0x89, 0x8e, 0xf9, 0x0a, 0x79, 0x15, 0x4f, 0xdf, 0xa0, 0xa3, 0xaf, 0x17, 0x28, 0xde, 0xc7, 0x8f, 0x9a, 0x07, 0xce, - 0x4c, 0x03, 0x09, 0x3e, 0xf0, 0xac, 0x17, 0x00, 0xe6, 0xe5, 0x6a, 0x7a, 0x04, 0x16, 0x78, 0x1a, 0xc2, 0xbf, 0x79, - 0xb1, 0xf8, 0xc1, 0xcd, 0x24, 0x2c, 0xdf, 0x0d, 0xe6, 0x80, 0xd2, 0xdc, 0x60, 0x5e, 0x31, 0xc7, 0x22, 0x5f, 0xe5, - 0x52, 0x69, 0xde, 0x55, 0x6e, 0x2a, 0x15, 0xbf, 0xbc, 0xbf, 0xa0, 0x7c, 0xac, 0x9a, 0x0a, 0xb7, 0x1c, 0x3a, 0xd6, - 0xe6, 0x9a, 0xdc, 0xe7, 0x83, 0x2f, 0x4f, 0x96, 0x2c, 0x71, 0x49, 0x0d, 0x04, 0xcc, 0x2f, 0x90, 0x03, 0x0a, 0xbf, - 0x68, 0x78, 0x4c, 0xa7, 0xc1, 0x94, 0xdd, 0x78, 0x13, 0xce, 0x97, 0x1a, 0x0a, 0xbf, 0xa7, 0x4c, 0xb4, 0xf8, 0x1c, - 0x38, 0x06, 0x39, 0x1c, 0x4c, 0x5c, 0x0c, 0x51, 0x3c, 0x08, 0x42, 0x75, 0xf8, 0x65, 0xe6, 0x9b, 0xd9, 0xb4, 0x08, - 0x90, 0x14, 0xfd, 0x32, 0x62, 0xfe, 0xbf, 0x07, 0x5f, 0xc2, 0xc5, 0xfd, 0xe5, 0x95, 0xaa, 0xf7, 0x13, 0x6b, 0x11, - 0xb1, 0xd9, 0xe0, 0xcb, 0x9a, 0xe4, 0xe0, 0xc8, 0xde, 0xd3, 0x58, 0xd4, 0x76, 0x2b, 0x0f, 0x15, 0xd7, 0xde, 0x8b, - 0xa9, 0x1f, 0x72, 0x6e, 0x1d, 0x38, 0xc0, 0x4d, 0x81, 0xc7, 0x76, 0xfa, 0xc8, 0x3f, 0x8f, 0x7d, 0x77, 0xf2, 0xa1, - 0x4f, 0x6f, 0x0a, 0x0f, 0x26, 0xdc, 0xd6, 0x13, 0x77, 0xd5, 0xc3, 0xeb, 0x55, 0x2e, 0x04, 0xd7, 0x6c, 0x2a, 0xcd, - 0x28, 0xbb, 0xda, 0xbd, 0x8c, 0x5b, 0x79, 0x83, 0x5f, 0xc6, 0x4f, 0xdd, 0x2e, 0xbc, 0x84, 0x89, 0x4f, 0xe1, 0x43, - 0x9a, 0x0a, 0x46, 0x9d, 0x58, 0x54, 0x64, 0xac, 0xad, 0xb6, 0xe2, 0x74, 0xbf, 0xed, 0xdc, 0x38, 0xf6, 0xa2, 0xe5, - 0x58, 0xdd, 0x9f, 0x9d, 0xee, 0xa2, 0x6d, 0x1d, 0xfb, 0x66, 0xdb, 0x3a, 0x86, 0x3f, 0x3f, 0x1f, 0x5b, 0xdd, 0x85, - 0xd9, 0xb2, 0x0e, 0x7f, 0x76, 0x5a, 0xbe, 0xd9, 0xb5, 0x8e, 0xe1, 0xcf, 0x39, 0xb5, 0x02, 0x06, 0x88, 0xf8, 0x9d, - 0x2f, 0x0b, 0x58, 0x40, 0xfa, 0x9d, 0xe9, 0x64, 0x8d, 0xc2, 0xf5, 0x56, 0xa3, 0xd7, 0x05, 0x94, 0x41, 0x29, 0x7b, - 0xd0, 0x14, 0xa1, 0xaf, 0x05, 0x03, 0x46, 0x49, 0x7a, 0x84, 0x79, 0x9b, 0xf0, 0x41, 0x17, 0x79, 0x51, 0x6a, 0x8f, - 0x11, 0x6f, 0x53, 0x9f, 0x0b, 0x44, 0x24, 0x70, 0x25, 0x45, 0xf0, 0x4f, 0x2b, 0x0c, 0x69, 0x27, 0xd2, 0x5e, 0x49, - 0x58, 0x29, 0x4f, 0x22, 0x9e, 0xee, 0x1e, 0x38, 0x7a, 0xe1, 0xb3, 0x2c, 0x89, 0xe5, 0x67, 0xed, 0x5b, 0xca, 0x2e, - 0xf6, 0x49, 0xfd, 0x60, 0x56, 0xa5, 0x3c, 0x21, 0x12, 0x44, 0x02, 0x9f, 0x7a, 0x51, 0x36, 0x3c, 0x09, 0x45, 0x3b, - 0xf5, 0x49, 0x54, 0x74, 0xc8, 0xf6, 0x77, 0x06, 0x54, 0xf2, 0x8d, 0xeb, 0x4b, 0x86, 0x6c, 0x52, 0xcb, 0x47, 0x19, - 0xe6, 0x7f, 0xfa, 0x34, 0x1f, 0x9c, 0x59, 0x1a, 0xf7, 0x89, 0xd3, 0x81, 0x6b, 0xb7, 0xc3, 0xda, 0x5b, 0x6d, 0x2a, - 0x77, 0xc7, 0x90, 0xcf, 0x83, 0x47, 0x0b, 0xbb, 0x29, 0x61, 0xb1, 0xd1, 0x68, 0xd8, 0x59, 0xb1, 0xd7, 0x80, 0xe8, - 0xfb, 0x25, 0x56, 0x47, 0xd5, 0xfb, 0x81, 0x30, 0x3f, 0x08, 0xb6, 0xc4, 0xcd, 0xe7, 0xbc, 0x98, 0x0a, 0xa0, 0xd9, - 0x32, 0x8f, 0x1d, 0x0e, 0xe2, 0x7f, 0xf6, 0x24, 0xd0, 0x59, 0x13, 0xec, 0x25, 0x4a, 0xa7, 0xb5, 0xe0, 0xbc, 0x97, - 0xdd, 0xab, 0x74, 0xa1, 0xb2, 0xf8, 0x54, 0x85, 0x22, 0x48, 0x03, 0x8b, 0x99, 0x9f, 0x33, 0x63, 0xd1, 0xec, 0xb6, - 0xc8, 0x0b, 0x0c, 0x0f, 0x93, 0x90, 0x08, 0xc7, 0x51, 0xfd, 0xe9, 0xd3, 0xc6, 0x4b, 0x88, 0x8c, 0x73, 0x62, 0x96, - 0x64, 0xb9, 0x29, 0x55, 0x19, 0xbf, 0xa9, 0x32, 0x8a, 0xc9, 0xfa, 0x45, 0xac, 0x21, 0x6c, 0x5c, 0x69, 0xef, 0xe1, - 0xcf, 0x31, 0x73, 0x13, 0x8b, 0x2b, 0x4b, 0x35, 0xe9, 0x72, 0x37, 0x1c, 0xd6, 0x06, 0xeb, 0x56, 0x1e, 0xf9, 0x92, - 0x47, 0x96, 0x7d, 0xb2, 0x79, 0xb9, 0xe6, 0x51, 0x1d, 0xa0, 0x8f, 0x8f, 0x76, 0x1e, 0x38, 0xec, 0x6d, 0xe2, 0x52, - 0x40, 0x17, 0xf9, 0xca, 0x0d, 0x13, 0x57, 0xa4, 0x5b, 0x04, 0xba, 0xbc, 0x5f, 0x6b, 0x7e, 0x21, 0x45, 0x7e, 0x18, - 0xbe, 0xbd, 0xf8, 0x5a, 0xe1, 0xfb, 0x9f, 0xac, 0x05, 0x90, 0x91, 0xa1, 0x94, 0x3c, 0x03, 0x4a, 0xc9, 0xa3, 0xf0, - 0x9c, 0x50, 0x90, 0xa7, 0x26, 0x3d, 0x20, 0x08, 0xa2, 0x00, 0x9a, 0x6c, 0x28, 0x96, 0x6b, 0x3f, 0xf1, 0x56, 0x6e, - 0x94, 0x1c, 0x60, 0x3e, 0x1e, 0x40, 0x72, 0x6a, 0x53, 0x3c, 0x08, 0x32, 0xc3, 0x10, 0x01, 0x57, 0x93, 0x40, 0xd8, - 0x61, 0xcc, 0x3c, 0x3f, 0x33, 0xc3, 0x10, 0x1f, 0x70, 0x27, 0x13, 0xb6, 0x4a, 0x06, 0x85, 0xbc, 0x3f, 0xe1, 0x24, - 0x61, 0x89, 0x19, 0x27, 0x11, 0x73, 0x97, 0x6a, 0x16, 0xd8, 0xbb, 0xda, 0x5f, 0xbc, 0x1e, 0x2f, 0xbd, 0x24, 0x8b, - 0x8c, 0x4b, 0x13, 0x04, 0x83, 0x08, 0x18, 0xe2, 0x70, 0x94, 0x72, 0x10, 0x9e, 0x87, 0xf3, 0xd2, 0x8e, 0xca, 0x29, - 0x97, 0x53, 0x8c, 0xbb, 0x4e, 0x9c, 0x0c, 0x48, 0x8b, 0x27, 0xa1, 0x7f, 0xcd, 0x63, 0x58, 0x64, 0x01, 0x7c, 0xd5, - 0xe1, 0x09, 0x67, 0x6f, 0x15, 0x0c, 0xbb, 0xa2, 0x76, 0x6c, 0x88, 0x2c, 0xdf, 0x14, 0xdd, 0xe2, 0x80, 0x57, 0x86, - 0xab, 0x89, 0x7a, 0xc6, 0xe4, 0x20, 0x34, 0x96, 0x0b, 0x20, 0x84, 0x0a, 0x06, 0x33, 0x0b, 0x67, 0x98, 0xb9, 0x53, - 0xe2, 0xa8, 0x90, 0x56, 0xfa, 0xf8, 0xf1, 0xd5, 0xe8, 0xb7, 0xff, 0x40, 0x06, 0x93, 0x85, 0x23, 0x62, 0x4a, 0x5c, - 0xca, 0xb5, 0x38, 0xf5, 0x69, 0x8c, 0xd0, 0x58, 0x8a, 0x4d, 0x45, 0x68, 0x1d, 0xb1, 0xb5, 0xd2, 0xd1, 0x95, 0x08, - 0xad, 0x08, 0xc9, 0x8d, 0x74, 0x11, 0xf9, 0x62, 0x04, 0xcb, 0x3b, 0x12, 0x01, 0x57, 0x94, 0x5f, 0xee, 0x5e, 0x1e, - 0x2b, 0x79, 0xec, 0xa1, 0x3a, 0x8b, 0x1e, 0xda, 0x43, 0xc3, 0x13, 0x57, 0x41, 0xa2, 0x05, 0xc9, 0x8f, 0xb8, 0x77, - 0x00, 0xd3, 0x5c, 0x84, 0x4b, 0x66, 0x79, 0xe1, 0xc1, 0x2d, 0x1b, 0x9b, 0xee, 0xca, 0x23, 0xbb, 0x1c, 0x94, 0xbb, - 0x29, 0x44, 0xf9, 0x65, 0xe6, 0x2e, 0x44, 0x5f, 0xa7, 0x39, 0x28, 0xc3, 0x62, 0x2c, 0xcd, 0x4e, 0x2b, 0xd7, 0x03, - 0x42, 0xfc, 0x02, 0x09, 0x8e, 0xe1, 0xf0, 0xe4, 0xc0, 0x1d, 0x16, 0x83, 0xf9, 0x5a, 0x22, 0xeb, 0x4c, 0xf1, 0x12, - 0x38, 0xa5, 0x98, 0xbc, 0x22, 0xfc, 0x6e, 0xfe, 0x60, 0x86, 0xb3, 0x99, 0x1c, 0x80, 0xd7, 0x2a, 0x0e, 0x2f, 0x03, - 0x5a, 0xbe, 0xa5, 0xc3, 0x15, 0x7d, 0xa9, 0xfa, 0x89, 0xec, 0xa7, 0xda, 0xc3, 0xc8, 0xdb, 0x30, 0x67, 0x38, 0xee, - 0x95, 0x40, 0xbe, 0x19, 0xc4, 0x1e, 0x53, 0x25, 0x8e, 0x47, 0xca, 0x69, 0x23, 0x1a, 0x28, 0x97, 0x47, 0x83, 0x01, - 0xa1, 0xb9, 0x32, 0xb6, 0x03, 0x20, 0xd6, 0x64, 0xe0, 0x81, 0xc9, 0x26, 0xd0, 0xd0, 0x24, 0x77, 0x59, 0x6c, 0x54, - 0x9e, 0x4e, 0x75, 0x8c, 0x07, 0xae, 0xd8, 0x7e, 0x85, 0x0d, 0x0a, 0x1b, 0x8f, 0xaf, 0x3b, 0xe0, 0x77, 0xd1, 0x4f, - 0x09, 0xcd, 0x2b, 0x5f, 0x11, 0x46, 0x37, 0x7d, 0xf7, 0x3e, 0x94, 0xcc, 0x98, 0x78, 0x44, 0x93, 0x73, 0x2c, 0xbd, - 0x10, 0x9e, 0xc4, 0x95, 0x83, 0x96, 0x25, 0x32, 0xa9, 0x1e, 0x36, 0x39, 0xf9, 0xc8, 0xae, 0xb3, 0x26, 0xd7, 0x2d, - 0x4e, 0x06, 0x91, 0x67, 0x9a, 0x9f, 0xc3, 0xc2, 0x4b, 0x44, 0x0b, 0xe9, 0xc9, 0x01, 0xcc, 0x0f, 0xa2, 0xb0, 0x14, - 0x08, 0x27, 0x4f, 0x87, 0x50, 0x2f, 0x6e, 0x4c, 0xa6, 0x58, 0x67, 0x53, 0x41, 0xf3, 0x21, 0x63, 0x29, 0x65, 0xe5, - 0x93, 0xaa, 0x54, 0x69, 0x19, 0xbb, 0x9e, 0x08, 0xdc, 0x9d, 0xf5, 0xe7, 0x87, 0x35, 0xa6, 0xfc, 0x49, 0xfb, 0x09, - 0x13, 0x41, 0x0e, 0xce, 0x93, 0x86, 0x38, 0x08, 0x4d, 0x55, 0x88, 0x9e, 0xdd, 0x52, 0x21, 0xdf, 0xc7, 0xdb, 0x6a, - 0xe5, 0x94, 0x53, 0x56, 0x6d, 0xe5, 0x6a, 0xea, 0x63, 0xdc, 0xf1, 0x95, 0xda, 0x58, 0x0a, 0xf5, 0xce, 0x93, 0x01, - 0x54, 0x15, 0xb2, 0x78, 0x77, 0xb5, 0xa2, 0xca, 0x7a, 0xff, 0xe4, 0x80, 0xd8, 0xd2, 0x21, 0xed, 0xb0, 0xe1, 0x09, - 0x98, 0x72, 0xd3, 0xa2, 0xbb, 0xab, 0x15, 0x5f, 0x52, 0xfa, 0x45, 0x6f, 0x0e, 0x16, 0xc9, 0xd2, 0x1f, 0xfe, 0x1f, - 0x59, 0xea, 0xe1, 0x3d, 0xe8, 0x69, 0x03, 0x00}; + 0xdb, 0xdb, 0xdb, 0xff, 0xd3, 0xdc, 0xb3, 0x6e, 0xb7, 0x6d, 0x23, 0xfd, 0xbf, 0x4f, 0xc1, 0x30, 0xd9, 0x94, 0x4c, + 0x48, 0x9a, 0x94, 0x2c, 0x5b, 0x91, 0x2c, 0xb9, 0xcd, 0xa5, 0x5b, 0x77, 0xdd, 0xa6, 0x27, 0x71, 0xfb, 0xed, 0xae, + 0xeb, 0x63, 0x51, 0x12, 0x24, 0x71, 0x43, 0x91, 0x3a, 0x24, 0xe5, 0x4b, 0x15, 0xee, 0xb3, 0xec, 0x23, 0x7c, 0xcf, + 0xd0, 0x27, 0xfb, 0xce, 0xcc, 0x00, 0x24, 0x78, 0x93, 0xe4, 0x4d, 0xda, 0x7e, 0xa7, 0x4d, 0x22, 0x82, 0x00, 0x08, + 0x0c, 0x80, 0xb9, 0x61, 0x2e, 0x26, 0x98, 0x36, 0x9a, 0xeb, 0xc8, 0x67, 0xc1, 0x24, 0x84, 0xc4, 0x24, 0xa9, 0x40, + 0xf8, 0xac, 0x84, 0xf0, 0x21, 0x2e, 0x2a, 0x4f, 0xac, 0xf1, 0x7e, 0x11, 0xde, 0x7e, 0xed, 0xfb, 0xb2, 0xfc, 0x2e, + 0x98, 0x3e, 0x2e, 0xd2, 0x16, 0x10, 0x88, 0x06, 0xd7, 0x10, 0x96, 0x17, 0x5f, 0xf3, 0x8b, 0xe3, 0xe9, 0xf5, 0xf8, + 0xfe, 0x9a, 0x2b, 0xa7, 0xb3, 0xc0, 0xb4, 0xaf, 0x46, 0x27, 0x53, 0xef, 0x46, 0x41, 0xce, 0x74, 0xa0, 0x82, 0x57, + 0x8f, 0xcf, 0xc6, 0xeb, 0x24, 0x09, 0x03, 0x33, 0x0a, 0x6f, 0xd5, 0xe1, 0x09, 0x3d, 0x88, 0x0a, 0x2e, 0x3d, 0xaa, + 0xca, 0x57, 0x13, 0xdf, 0x9b, 0x7c, 0x18, 0xa8, 0x4f, 0x36, 0xde, 0x60, 0x58, 0xe2, 0x3f, 0xed, 0x54, 0x1d, 0xc2, + 0x58, 0x95, 0xaf, 0x7d, 0xff, 0xe4, 0x80, 0x5a, 0x0c, 0x4f, 0x0e, 0xa6, 0xde, 0xcd, 0x50, 0xca, 0x11, 0xc2, 0x2f, + 0xd0, 0x06, 0x3c, 0x16, 0x63, 0x66, 0x72, 0x14, 0xa3, 0x73, 0xff, 0x84, 0x69, 0xb9, 0x14, 0x04, 0x41, 0x47, 0x68, + 0xbc, 0xda, 0x04, 0xf5, 0xaa, 0x3e, 0xf0, 0xfc, 0x1f, 0x3f, 0x6a, 0x99, 0x41, 0xe2, 0x42, 0x8a, 0xd6, 0x85, 0xf7, + 0x3d, 0x58, 0xc5, 0xc0, 0x90, 0x23, 0xba, 0x26, 0x62, 0x8a, 0xf9, 0xba, 0x31, 0x49, 0x0d, 0x4c, 0xb5, 0xe2, 0xae, + 0x80, 0x47, 0xe0, 0x3f, 0x25, 0xd1, 0x68, 0x02, 0xe9, 0x95, 0x25, 0x04, 0xaf, 0x4b, 0xca, 0x77, 0x3a, 0x9b, 0x3c, + 0x60, 0x1c, 0x68, 0xcd, 0xf1, 0x3b, 0xa4, 0x10, 0xd7, 0x7c, 0x1d, 0xd2, 0x7b, 0x65, 0x51, 0x5a, 0xdc, 0x54, 0x24, + 0xd4, 0x12, 0x70, 0x39, 0x2d, 0xac, 0x50, 0xaf, 0xbc, 0x5e, 0x22, 0x7c, 0xe0, 0xa3, 0xb8, 0x69, 0xc9, 0xe0, 0x32, + 0x47, 0x4b, 0x8c, 0x12, 0x3d, 0x06, 0xf7, 0x2e, 0xe9, 0x06, 0x81, 0x19, 0xda, 0x65, 0x6c, 0x84, 0x57, 0x39, 0x0d, + 0x8b, 0x09, 0x7d, 0xf6, 0xc2, 0x34, 0x8f, 0xe4, 0x4b, 0xab, 0x3e, 0x7c, 0xb2, 0x09, 0x90, 0xe8, 0xc5, 0x83, 0x61, + 0x71, 0x1f, 0x24, 0xee, 0xd8, 0xa4, 0xcd, 0xac, 0x2a, 0x5f, 0x4d, 0xc7, 0x7e, 0xb6, 0xd8, 0x74, 0x34, 0x16, 0x6e, + 0x30, 0xf5, 0xd9, 0x85, 0x3b, 0xfe, 0x16, 0xeb, 0xbc, 0x1e, 0xfb, 0xaf, 0xa0, 0x42, 0xaa, 0x0e, 0x9f, 0x6c, 0x88, + 0xac, 0xd7, 0xa1, 0xf1, 0x94, 0xb6, 0x40, 0xf9, 0x3b, 0x3c, 0xf7, 0x0e, 0x8b, 0xa8, 0x35, 0x0e, 0x96, 0x48, 0x31, + 0xe1, 0xd9, 0xe2, 0xc8, 0x78, 0xee, 0x17, 0xd8, 0x9b, 0x0a, 0x3f, 0x94, 0x30, 0xae, 0x50, 0x1c, 0x50, 0x79, 0x67, + 0xca, 0x83, 0x25, 0x92, 0xfb, 0x2e, 0xbc, 0x15, 0x23, 0xe5, 0x00, 0xa0, 0x58, 0x85, 0xa7, 0xaf, 0x46, 0x27, 0xf2, + 0xfd, 0x00, 0x2a, 0x51, 0xa9, 0x5f, 0xf8, 0x95, 0xaa, 0x4a, 0x9e, 0x09, 0x68, 0x75, 0xa7, 0x0e, 0x4f, 0x0e, 0xe4, + 0xda, 0xc3, 0x51, 0xef, 0x5c, 0x9a, 0x1c, 0xf6, 0x0a, 0x40, 0x28, 0x96, 0x55, 0xa8, 0x0e, 0x24, 0xc7, 0xcb, 0xe9, + 0x12, 0x6d, 0x0f, 0x81, 0x16, 0x43, 0xbd, 0x97, 0xad, 0x11, 0xd9, 0xe0, 0x89, 0xde, 0x46, 0xfc, 0xdf, 0x7c, 0xce, + 0xa8, 0xd3, 0x64, 0x41, 0x1c, 0x46, 0x2a, 0xcc, 0xa3, 0x9c, 0x21, 0x47, 0x91, 0x32, 0x73, 0xe1, 0x8c, 0x6a, 0xa9, + 0x29, 0x40, 0xe4, 0xa0, 0xdc, 0x54, 0x9a, 0xd8, 0x48, 0xcf, 0x7f, 0x28, 0x7c, 0x32, 0x25, 0xac, 0x94, 0x0d, 0xb0, + 0x39, 0xf3, 0xd0, 0xe5, 0x5b, 0xcf, 0xf8, 0x9f, 0xd0, 0x98, 0xbb, 0xc6, 0xd2, 0x35, 0xde, 0x07, 0x57, 0x69, 0xed, + 0xea, 0x64, 0x59, 0xc3, 0x0c, 0xd6, 0xd7, 0x20, 0xd6, 0x0e, 0xd7, 0x80, 0x70, 0xbd, 0x80, 0x67, 0x71, 0xeb, 0x80, + 0x0b, 0x37, 0x9a, 0x33, 0x91, 0xac, 0x4b, 0xbc, 0x4d, 0x38, 0x54, 0x74, 0x09, 0x2c, 0x10, 0x88, 0x4a, 0x08, 0x38, + 0x9e, 0x35, 0x49, 0x22, 0xff, 0x6f, 0xec, 0x1e, 0x24, 0xcf, 0x38, 0x09, 0x57, 0xa0, 0x9d, 0x70, 0xe7, 0x5c, 0xdb, + 0x6c, 0x00, 0x2f, 0xb3, 0xcf, 0xe7, 0x3e, 0x7e, 0x64, 0x52, 0xfe, 0xa8, 0x24, 0x9c, 0xcf, 0x7d, 0xa6, 0x49, 0x79, + 0xa6, 0xb2, 0xcf, 0x9c, 0x3e, 0xb2, 0x45, 0x8c, 0x62, 0x3d, 0x6d, 0x3a, 0x39, 0x39, 0x2b, 0x28, 0xee, 0x75, 0x49, + 0x58, 0xc7, 0xdb, 0xa8, 0x1b, 0xbc, 0xd0, 0xe5, 0xeb, 0x92, 0x9f, 0x4c, 0x73, 0x1a, 0xae, 0xc7, 0x3e, 0x33, 0x71, + 0xbb, 0xc3, 0x27, 0x37, 0xe3, 0xf5, 0x78, 0xec, 0x53, 0x62, 0x28, 0x88, 0xb4, 0x15, 0xc6, 0xa8, 0x01, 0x4b, 0xf5, + 0x3e, 0x32, 0x68, 0x49, 0x79, 0xf8, 0x60, 0x1d, 0x07, 0x62, 0x03, 0x7d, 0x20, 0x01, 0x6d, 0x57, 0xf5, 0xd0, 0x0e, + 0x54, 0x10, 0x57, 0x58, 0xac, 0xf6, 0x6b, 0x38, 0xb9, 0xc1, 0xa5, 0xfa, 0x1e, 0x21, 0x8c, 0xd9, 0xeb, 0x5f, 0xd1, + 0xde, 0x55, 0x0d, 0x95, 0x8c, 0x7c, 0x78, 0x1e, 0x31, 0xd5, 0x50, 0x5f, 0x7b, 0xee, 0x3c, 0x08, 0xe3, 0xc4, 0x9b, + 0xa8, 0x57, 0xfd, 0x33, 0x4f, 0xbb, 0x5c, 0x26, 0x9a, 0x7e, 0x65, 0xfc, 0x55, 0xce, 0xf8, 0x24, 0x50, 0x21, 0x26, + 0x7c, 0x6a, 0xa8, 0x23, 0x9f, 0x9e, 0x6d, 0xf5, 0x04, 0xca, 0xc5, 0x3a, 0x7f, 0x1d, 0x40, 0xad, 0x52, 0xee, 0x28, + 0x4c, 0x0a, 0x08, 0xb9, 0xa3, 0xfe, 0xaa, 0xf7, 0x49, 0x2b, 0xf3, 0x6a, 0xbd, 0x41, 0x5e, 0x21, 0xc9, 0xa9, 0x2b, + 0x86, 0x3b, 0x17, 0x3e, 0x82, 0xf4, 0xfc, 0x48, 0xb6, 0x6f, 0x2f, 0xd0, 0xe9, 0xd1, 0xd7, 0x45, 0xc6, 0x03, 0x18, + 0x04, 0x30, 0x2e, 0x0b, 0xc2, 0x44, 0x81, 0x18, 0x5e, 0xf0, 0xc1, 0x51, 0xd9, 0x1e, 0x96, 0xf7, 0xaa, 0xe9, 0x29, + 0xc7, 0x02, 0x2f, 0x91, 0x58, 0x8a, 0xec, 0xef, 0x18, 0x8e, 0xb2, 0x10, 0xb1, 0x87, 0x7b, 0x61, 0xc1, 0xf2, 0x15, + 0xd8, 0x36, 0x09, 0xb1, 0x17, 0x09, 0xf6, 0x93, 0x4d, 0x7c, 0x2a, 0xa8, 0xf6, 0x59, 0x8c, 0x6b, 0x09, 0xfc, 0x08, + 0x27, 0xe3, 0xa9, 0xaa, 0x9c, 0x0a, 0x52, 0x83, 0x75, 0x0b, 0xf8, 0x53, 0x13, 0x5c, 0xae, 0x48, 0xea, 0xae, 0xf1, + 0x14, 0xd4, 0x82, 0xef, 0x2a, 0x1d, 0x3d, 0x08, 0xcb, 0x93, 0xb1, 0x54, 0x09, 0xd8, 0xd6, 0x22, 0x45, 0x00, 0xcc, + 0xc5, 0x99, 0x80, 0x51, 0x7a, 0x0d, 0xfc, 0x23, 0xc4, 0xaa, 0x12, 0x73, 0x34, 0x42, 0x39, 0x5d, 0x98, 0x17, 0xac, + 0xd6, 0x09, 0xc6, 0x20, 0x87, 0x01, 0xb0, 0x54, 0x55, 0x50, 0x5a, 0x04, 0x64, 0x9e, 0x4b, 0x41, 0xa9, 0xaa, 0x78, + 0xd3, 0x6a, 0x19, 0x57, 0xdd, 0x00, 0x8e, 0xc3, 0x69, 0xa0, 0x06, 0x1f, 0x1e, 0x23, 0x3e, 0x8d, 0x89, 0x91, 0x27, + 0xf0, 0xd0, 0x26, 0x78, 0xd3, 0x5d, 0x83, 0x40, 0x26, 0xd4, 0x4f, 0x5f, 0xf3, 0x6b, 0x27, 0x0b, 0x71, 0x89, 0x0b, + 0xd3, 0x1c, 0x3d, 0xd9, 0x04, 0xe9, 0x29, 0xc0, 0x6e, 0xf0, 0x64, 0xe3, 0x66, 0x46, 0x54, 0xea, 0x85, 0x4a, 0x16, + 0x54, 0x23, 0x04, 0xc3, 0x28, 0xbd, 0xce, 0x5d, 0x1a, 0xf3, 0xf9, 0xc2, 0x96, 0xa4, 0x72, 0x05, 0x6d, 0x9a, 0x06, + 0xdc, 0x72, 0x69, 0x15, 0x79, 0x4b, 0x37, 0xba, 0x27, 0x43, 0x27, 0x43, 0xb6, 0x86, 0xd2, 0x55, 0x85, 0xe8, 0x01, + 0x01, 0x80, 0x48, 0x83, 0xaa, 0x7c, 0x95, 0x95, 0x31, 0x3e, 0xdb, 0xcc, 0xda, 0x03, 0xbe, 0x75, 0xad, 0x3e, 0x67, + 0x16, 0xa9, 0x34, 0xa8, 0x49, 0x5f, 0x8b, 0x1b, 0xa6, 0x17, 0x17, 0xa7, 0x17, 0x14, 0x37, 0x1a, 0x4e, 0x86, 0x28, + 0x05, 0x8d, 0x1b, 0x67, 0x86, 0xe9, 0x0e, 0xeb, 0x57, 0x94, 0xde, 0xfd, 0xa1, 0xcb, 0xc1, 0x60, 0x39, 0x02, 0x58, + 0x0e, 0xe2, 0xae, 0x7f, 0x7a, 0x77, 0x96, 0xe5, 0x57, 0x04, 0xd5, 0xf8, 0x88, 0x6f, 0xcc, 0x18, 0xd9, 0x8c, 0x08, + 0x59, 0x0c, 0xca, 0x84, 0xa8, 0x64, 0x5b, 0x28, 0x82, 0xa3, 0x41, 0x63, 0xa7, 0xa3, 0x11, 0x0d, 0x06, 0x21, 0xb6, + 0x8a, 0xd2, 0x93, 0x03, 0xaa, 0x4d, 0x44, 0x91, 0x2a, 0x01, 0x18, 0x22, 0x98, 0x61, 0x0e, 0x05, 0x48, 0x05, 0x3d, + 0x70, 0x72, 0xf9, 0xc6, 0x5a, 0xe2, 0x05, 0xa4, 0x73, 0x5a, 0xe4, 0x68, 0xb0, 0x95, 0x3a, 0x3c, 0xc1, 0xe4, 0x8e, + 0x40, 0xd6, 0x21, 0xfc, 0xd1, 0xc9, 0x01, 0x3d, 0x2a, 0xa5, 0x13, 0x91, 0x77, 0x22, 0x14, 0x94, 0x3d, 0xde, 0xc1, + 0x83, 0x8e, 0x4a, 0x9c, 0xb0, 0x15, 0x94, 0xba, 0xa9, 0xaa, 0x2c, 0x39, 0x07, 0xc5, 0xe3, 0xac, 0x41, 0x10, 0x16, + 0x1b, 0x8c, 0xdf, 0x55, 0x65, 0xe9, 0xde, 0xe1, 0xcc, 0xc5, 0x1b, 0xf7, 0x4e, 0x73, 0xf8, 0xab, 0xfc, 0xac, 0xc5, + 0xc5, 0xb3, 0x36, 0xe1, 0x8b, 0x0b, 0x1e, 0x56, 0x82, 0x73, 0xd6, 0x16, 0x68, 0xb9, 0x52, 0xb3, 0xb8, 0x0b, 0xb1, + 0xb8, 0xd3, 0x86, 0xc5, 0x9d, 0x6e, 0x59, 0x5c, 0x9f, 0x2f, 0xa4, 0x92, 0x81, 0x2e, 0x42, 0xaf, 0xd9, 0x0c, 0x78, + 0x9c, 0x1f, 0xe9, 0xf1, 0x73, 0x86, 0x70, 0x32, 0x63, 0x1f, 0xac, 0x46, 0x1b, 0x60, 0x55, 0x07, 0x17, 0x09, 0x10, + 0xd5, 0x89, 0x67, 0xa7, 0x6e, 0x22, 0x29, 0x04, 0x34, 0xbf, 0x3c, 0x5f, 0xd8, 0xa5, 0xd8, 0xd0, 0xd0, 0x16, 0x0d, + 0x33, 0x5d, 0x6c, 0x99, 0xe9, 0xa4, 0x70, 0x74, 0xf9, 0xb4, 0xe9, 0x10, 0xca, 0x93, 0x82, 0x3d, 0x08, 0x96, 0xf4, + 0xb8, 0x65, 0x8a, 0xfb, 0xb0, 0x19, 0xc7, 0x4a, 0x3b, 0x6a, 0xe5, 0xc6, 0xf1, 0x6d, 0x18, 0xc1, 0x55, 0x34, 0x74, + 0xf3, 0xb0, 0x2d, 0xb5, 0xf4, 0x02, 0x1e, 0xe5, 0xaa, 0x71, 0x33, 0xe5, 0xef, 0xe5, 0x2d, 0xd5, 0xea, 0x74, 0xa8, + 0xc6, 0xca, 0x4d, 0x12, 0x16, 0x21, 0xd0, 0x5d, 0x48, 0x87, 0xf0, 0xff, 0x64, 0x9b, 0xd5, 0xe0, 0x10, 0x5f, 0xc2, + 0xea, 0x88, 0xa1, 0x57, 0xc0, 0x82, 0xd1, 0xdd, 0x53, 0xa0, 0x6f, 0xa4, 0x88, 0x99, 0x51, 0x06, 0xf8, 0x1f, 0xf0, + 0xb8, 0x6a, 0x91, 0xe4, 0xd3, 0xe9, 0x1c, 0xe9, 0xd6, 0xca, 0x9d, 0xbe, 0x07, 0x8b, 0x07, 0xad, 0x65, 0x80, 0xf7, + 0x82, 0x1c, 0x1f, 0x33, 0x22, 0x9e, 0x70, 0x92, 0x23, 0x49, 0xc4, 0x92, 0xdc, 0x36, 0x14, 0xdc, 0xca, 0x5d, 0x73, + 0x76, 0xb5, 0x69, 0xa5, 0x07, 0x73, 0x4f, 0xaf, 0x60, 0x4d, 0x40, 0x6d, 0xfe, 0x60, 0x98, 0xe9, 0xda, 0x7c, 0xc3, + 0x39, 0xd2, 0xe1, 0x4a, 0xec, 0x12, 0x12, 0x5f, 0xdb, 0x42, 0x5a, 0x1e, 0x45, 0x40, 0xb5, 0x2e, 0xed, 0xab, 0xf4, + 0xe9, 0x1c, 0x7f, 0x39, 0x57, 0xe9, 0xd3, 0x31, 0xfe, 0x6a, 0x5d, 0x61, 0x4a, 0xcf, 0x1a, 0x35, 0x81, 0x34, 0x67, + 0x75, 0x58, 0xd8, 0x4f, 0x64, 0x98, 0xfb, 0x80, 0x6d, 0xc3, 0x17, 0xf8, 0xf1, 0x93, 0x4d, 0x0c, 0xae, 0xe8, 0xf2, + 0x1c, 0x02, 0x2b, 0xd2, 0xd3, 0xda, 0xf2, 0x79, 0x43, 0xf9, 0x58, 0xff, 0x83, 0x09, 0x3f, 0xee, 0x92, 0x30, 0xa7, + 0x29, 0x45, 0x25, 0xc7, 0xf5, 0xd8, 0x0b, 0xdc, 0xe8, 0xfe, 0x9a, 0xa4, 0x10, 0x4d, 0xd2, 0xf6, 0x3e, 0xca, 0xa5, + 0xff, 0xfb, 0xa2, 0x1d, 0x40, 0x22, 0xdd, 0x65, 0xdd, 0x73, 0x42, 0x3f, 0xf8, 0x7b, 0x24, 0xf1, 0x77, 0x05, 0x39, + 0x95, 0x2f, 0x48, 0xe1, 0x43, 0xd7, 0x4f, 0x36, 0x1a, 0xab, 0x76, 0x53, 0x9a, 0x6d, 0x89, 0x81, 0x84, 0xe5, 0x41, + 0x99, 0x77, 0x39, 0xf5, 0x7a, 0x78, 0xd1, 0x3f, 0x0e, 0xef, 0xcc, 0x27, 0x9b, 0xe4, 0x54, 0x5d, 0xba, 0xd1, 0x07, + 0x36, 0x35, 0x27, 0x5e, 0x34, 0xf1, 0x81, 0x79, 0x1c, 0xfb, 0x6e, 0xf0, 0x81, 0x3f, 0x9a, 0xe1, 0x3a, 0x41, 0xd3, + 0x9d, 0x9d, 0x22, 0xb2, 0x80, 0x09, 0xe9, 0x0f, 0x91, 0xab, 0xad, 0x81, 0x82, 0xf2, 0x2a, 0xd3, 0xbf, 0xe5, 0x8c, + 0x62, 0x5e, 0xcb, 0x00, 0xcb, 0x73, 0xb0, 0x26, 0x02, 0x57, 0x7e, 0x43, 0xc5, 0xf5, 0x52, 0x0d, 0x79, 0xaa, 0x74, + 0xe5, 0x96, 0xe5, 0xa2, 0xbd, 0xc6, 0x1e, 0xfe, 0xfb, 0xcf, 0x41, 0xc9, 0x43, 0x3e, 0x97, 0xf5, 0xf2, 0x69, 0x33, + 0x84, 0x52, 0x93, 0x5c, 0xc8, 0x1e, 0xf0, 0x71, 0xce, 0x60, 0x36, 0x7f, 0x5a, 0x6e, 0xec, 0xc6, 0xf1, 0x7a, 0xc9, + 0xa6, 0x74, 0xb5, 0x76, 0x9a, 0x0f, 0xaa, 0x28, 0x87, 0xc8, 0x03, 0xfb, 0x65, 0xdd, 0x3a, 0x3e, 0x7c, 0x05, 0xa6, + 0x5c, 0xc0, 0x50, 0x86, 0xb3, 0x99, 0x9a, 0xab, 0x02, 0x76, 0x34, 0x73, 0x0e, 0x7f, 0x59, 0x7f, 0xf3, 0xc6, 0xfe, + 0x26, 0x6b, 0x1c, 0x00, 0x63, 0x2c, 0xec, 0x52, 0x38, 0x5f, 0x2c, 0x8d, 0x57, 0xcc, 0x68, 0xe6, 0x06, 0xcd, 0xd3, + 0xb9, 0x2c, 0x6c, 0xf1, 0x15, 0x63, 0x53, 0x60, 0xb8, 0x8d, 0x4a, 0xe9, 0xb5, 0xcf, 0x6e, 0x58, 0x66, 0xf3, 0x52, + 0xfd, 0x58, 0x4d, 0x0b, 0x0c, 0xca, 0xc9, 0x6f, 0x32, 0x39, 0x57, 0x27, 0x4d, 0x69, 0x84, 0x73, 0xe0, 0x33, 0x97, + 0x8f, 0x58, 0xe9, 0x48, 0x8d, 0x0c, 0x55, 0x1a, 0x40, 0xe3, 0xc8, 0x4e, 0x1b, 0xca, 0x7b, 0x80, 0xa8, 0x1b, 0xc6, + 0x66, 0x38, 0x7a, 0x0f, 0x92, 0x18, 0x70, 0x38, 0xf9, 0x70, 0xf2, 0xb4, 0x5c, 0x6b, 0xd2, 0x04, 0xb1, 0x3a, 0x5d, + 0x9a, 0x4a, 0x4a, 0x1a, 0x61, 0x06, 0x8e, 0xfe, 0x10, 0x42, 0x5d, 0x55, 0xbb, 0x36, 0x4a, 0x71, 0xe6, 0x63, 0x4c, + 0xf1, 0x1d, 0xb0, 0x38, 0x6e, 0x04, 0x58, 0xb6, 0xe8, 0x86, 0x9a, 0xd7, 0x2e, 0xc2, 0x23, 0x2f, 0x37, 0x6c, 0x03, + 0x58, 0x02, 0x9c, 0x60, 0xf9, 0x5b, 0x48, 0x5e, 0xae, 0x97, 0xdc, 0x90, 0x2f, 0x9a, 0x8f, 0x55, 0x6e, 0x64, 0xd5, + 0xf4, 0xfe, 0x56, 0xe5, 0x83, 0x2a, 0x90, 0xe9, 0xda, 0xa1, 0x69, 0x05, 0xd4, 0x5b, 0xd1, 0x2a, 0x61, 0x07, 0x62, + 0x4c, 0x25, 0xfc, 0xca, 0x66, 0x33, 0x36, 0x49, 0x62, 0x5d, 0xe8, 0x98, 0xb2, 0xb0, 0xda, 0x70, 0x7b, 0xf7, 0x68, + 0xa0, 0xfe, 0x00, 0xc1, 0x45, 0x44, 0xf4, 0x39, 0x3e, 0x20, 0x21, 0x33, 0xd5, 0x83, 0x89, 0x7a, 0x2c, 0x82, 0x88, + 0x7f, 0x05, 0xd4, 0xcc, 0x35, 0xe5, 0x38, 0x34, 0x4e, 0x7f, 0xf2, 0x7d, 0x11, 0x66, 0xe6, 0x7e, 0xdb, 0x51, 0xd1, + 0xb6, 0xe3, 0xbb, 0x71, 0xbe, 0xe9, 0x38, 0x76, 0xaa, 0x1a, 0xe0, 0xd4, 0xfa, 0xa1, 0xb4, 0x8d, 0x89, 0x40, 0x0d, + 0xd4, 0xf3, 0xb7, 0xaf, 0xfe, 0xf6, 0xe6, 0xf5, 0xbe, 0x18, 0x01, 0xbb, 0x6c, 0x43, 0x97, 0xeb, 0x60, 0x4b, 0xa7, + 0x3f, 0xfd, 0xf0, 0xb0, 0x6e, 0x5b, 0xce, 0x0b, 0x47, 0x35, 0xc8, 0x0e, 0x59, 0xc2, 0x8b, 0x93, 0xf0, 0x86, 0x45, + 0x9f, 0x0c, 0x06, 0xb9, 0xf3, 0xfa, 0xe1, 0xbe, 0xfd, 0xf1, 0xcd, 0x0f, 0x7b, 0x0f, 0xf5, 0xc8, 0xb1, 0x01, 0xb7, + 0x27, 0xe1, 0xea, 0x01, 0xb3, 0x6b, 0xab, 0x86, 0x3a, 0xf1, 0xc3, 0x98, 0x35, 0x8c, 0xe0, 0xd5, 0xf9, 0xdb, 0xf7, + 0x08, 0xae, 0x9c, 0x05, 0xa1, 0xae, 0x3e, 0x6d, 0xf2, 0x3f, 0xbe, 0x7b, 0xf3, 0xfe, 0xbd, 0x6a, 0x60, 0x5a, 0xe6, + 0x58, 0xee, 0x9d, 0x6f, 0xe2, 0x1d, 0x14, 0xa7, 0x76, 0xaf, 0x13, 0x55, 0x23, 0x41, 0xba, 0x38, 0x1b, 0x2a, 0xab, + 0x6c, 0x73, 0x4e, 0xed, 0xf8, 0x97, 0x49, 0xfa, 0xdd, 0x6b, 0x5e, 0x35, 0xf8, 0x68, 0x3b, 0x49, 0x2d, 0x94, 0x2c, + 0xbd, 0xe0, 0xba, 0xa6, 0xd4, 0xbd, 0xab, 0x29, 0x05, 0xf1, 0xb1, 0x82, 0x1f, 0xd7, 0xe1, 0x52, 0x62, 0x47, 0xd8, + 0xdd, 0x6e, 0x70, 0x49, 0x32, 0xdc, 0x27, 0x0c, 0x9a, 0xa7, 0xd5, 0x28, 0x8f, 0xba, 0xa6, 0x98, 0x0b, 0x5e, 0x19, + 0x6c, 0x27, 0x3e, 0x58, 0x5f, 0x33, 0xf9, 0x9e, 0xb1, 0xc8, 0xaa, 0x72, 0xdf, 0x89, 0x41, 0x49, 0x2a, 0xa0, 0x66, + 0x74, 0x37, 0xc3, 0x69, 0xca, 0xca, 0x9d, 0x82, 0x49, 0xb3, 0x39, 0x0e, 0x93, 0x24, 0x5c, 0xf6, 0x1c, 0x7b, 0x75, + 0xa7, 0x2a, 0x7d, 0xa1, 0xec, 0xe0, 0x16, 0xd7, 0xbd, 0xdf, 0xfe, 0x53, 0x42, 0xf3, 0x54, 0x7e, 0x9d, 0xb0, 0xe5, + 0x8a, 0x45, 0x6e, 0xb2, 0x8e, 0x58, 0xaa, 0xfc, 0xf6, 0xbf, 0xaf, 0x4a, 0x82, 0x7d, 0x5f, 0x6e, 0x43, 0x2c, 0xbd, + 0xdc, 0xe4, 0xda, 0x0f, 0x6f, 0x1f, 0xe5, 0xbe, 0x55, 0x3b, 0x2a, 0x2f, 0xbc, 0xf9, 0x22, 0xab, 0x7d, 0x9a, 0x6c, + 0x99, 0x9b, 0x18, 0x3d, 0xdd, 0x07, 0x28, 0xe7, 0xe1, 0x6d, 0xef, 0xb7, 0xff, 0x64, 0x0a, 0x9b, 0x9d, 0xbb, 0xae, + 0x7e, 0xa0, 0xc5, 0x15, 0xad, 0xaf, 0x53, 0x59, 0x62, 0x78, 0x5f, 0x59, 0xe0, 0x4a, 0x21, 0xed, 0xca, 0xea, 0xe5, + 0xdb, 0x96, 0x39, 0x7d, 0xeb, 0xcd, 0x17, 0x9f, 0x3a, 0x29, 0x00, 0xe8, 0xce, 0x59, 0x41, 0xa5, 0xcf, 0x30, 0xad, + 0x51, 0x6f, 0xff, 0x05, 0xfb, 0xc4, 0x79, 0xed, 0x9a, 0xd2, 0xe7, 0x98, 0x0d, 0xd7, 0xdc, 0xbe, 0x1a, 0x8d, 0xb2, + 0xb4, 0xa4, 0x72, 0x7b, 0xf0, 0x0e, 0x3b, 0xad, 0x94, 0x70, 0xf6, 0xa2, 0x67, 0xeb, 0x14, 0xb6, 0x65, 0x0f, 0x80, + 0xa0, 0x9d, 0x73, 0x0d, 0x38, 0x9a, 0xf1, 0x35, 0xb9, 0x2b, 0x55, 0xbe, 0x5d, 0x41, 0xd6, 0x50, 0x8a, 0x29, 0x2d, + 0xb3, 0x5b, 0x43, 0xa3, 0x7e, 0x38, 0xb7, 0x91, 0xbb, 0xa2, 0x4b, 0x02, 0x05, 0x6f, 0x4c, 0x40, 0xe9, 0x52, 0x92, + 0xa2, 0x6f, 0x5c, 0xff, 0x66, 0x3f, 0x81, 0xaa, 0x99, 0x82, 0x21, 0x69, 0xfe, 0xf3, 0x88, 0x37, 0xd2, 0xe5, 0xfd, + 0x69, 0x37, 0xa6, 0x0a, 0x7b, 0xdb, 0x64, 0x5e, 0xfd, 0xe3, 0x6e, 0xf3, 0xea, 0x8b, 0xbd, 0xcc, 0xab, 0x7f, 0xfc, + 0xec, 0xe6, 0xd5, 0x6f, 0x65, 0xf3, 0x6a, 0xd8, 0xc4, 0x6f, 0xd8, 0x5e, 0x46, 0xcf, 0xc2, 0xc8, 0x28, 0xbc, 0x8d, + 0x07, 0x0e, 0x17, 0x7a, 0xe2, 0xc9, 0x82, 0x81, 0x16, 0x89, 0x83, 0xcb, 0x0f, 0xe7, 0x60, 0x9b, 0xdc, 0x6c, 0x7d, + 0xfc, 0xb9, 0x6c, 0x8f, 0xfd, 0x70, 0xae, 0x4a, 0xc1, 0xd2, 0x03, 0x11, 0x2c, 0x1d, 0x1c, 0xc4, 0x7f, 0xb9, 0x73, + 0x5e, 0x5e, 0x3a, 0xfd, 0xb6, 0x03, 0xc1, 0x46, 0x40, 0x31, 0x80, 0x05, 0x76, 0xbf, 0xdd, 0x86, 0x82, 0x5b, 0xa9, + 0xa0, 0x05, 0x05, 0x9e, 0x54, 0xd0, 0x81, 0x82, 0x89, 0x54, 0x70, 0x04, 0x05, 0x53, 0xa9, 0xe0, 0x18, 0x0a, 0x6e, + 0xd4, 0xf4, 0x32, 0xc8, 0x8c, 0xc7, 0x8f, 0xf5, 0xab, 0x42, 0x9e, 0x8c, 0x3c, 0xff, 0x3c, 0xaf, 0x72, 0x6c, 0x88, + 0xa0, 0x8d, 0xe6, 0xa1, 0xce, 0xcd, 0xff, 0x46, 0x5f, 0x8c, 0xc0, 0x9d, 0x1a, 0x94, 0x7a, 0x06, 0xa8, 0x44, 0xa9, + 0x66, 0x5b, 0xbc, 0x56, 0x7b, 0xaa, 0x9e, 0x7d, 0xa0, 0x25, 0xec, 0xfe, 0x7a, 0xe8, 0x4a, 0x23, 0x2a, 0x77, 0x9e, + 0x2f, 0xb2, 0x08, 0x4e, 0xeb, 0x41, 0xee, 0x91, 0xd6, 0x86, 0x38, 0xb6, 0x70, 0x35, 0xfd, 0x1a, 0xf9, 0x03, 0x2b, + 0x09, 0xc1, 0xe1, 0x48, 0x44, 0x2e, 0x12, 0x1f, 0x50, 0x54, 0xfd, 0xd2, 0xbe, 0xea, 0xbb, 0x79, 0x90, 0x29, 0x1e, + 0xef, 0x8c, 0x46, 0xbf, 0xcc, 0xc2, 0x48, 0x91, 0x98, 0xbb, 0x36, 0x12, 0x77, 0xde, 0x5b, 0x18, 0xa4, 0xe3, 0xee, + 0xcd, 0x21, 0x2e, 0xe8, 0xe9, 0xb4, 0xb7, 0x32, 0x6e, 0x17, 0x2c, 0xe8, 0xcd, 0xb8, 0x39, 0x28, 0xac, 0x3f, 0x59, + 0xf1, 0x2c, 0x75, 0x61, 0x94, 0x86, 0x7b, 0x22, 0x7f, 0x4b, 0xa3, 0x34, 0xb3, 0xad, 0x94, 0x5b, 0x4e, 0x69, 0xb2, + 0xfe, 0xfb, 0x73, 0xd8, 0xb9, 0xbc, 0x66, 0xe3, 0xf5, 0x5c, 0x39, 0x0f, 0xe7, 0x3b, 0x6d, 0x5a, 0xe4, 0x57, 0x30, + 0x4a, 0x95, 0x2e, 0xfa, 0x4c, 0xb1, 0xbd, 0xf9, 0xb7, 0xe8, 0x31, 0x2d, 0xd6, 0x4f, 0x60, 0x6c, 0x4a, 0x42, 0x28, + 0x1b, 0xbe, 0x03, 0xd0, 0x96, 0x8c, 0x4a, 0xce, 0x01, 0x7e, 0xd2, 0xf3, 0x85, 0x2b, 0x8d, 0x67, 0xf8, 0x3d, 0x8b, + 0x63, 0x77, 0x2e, 0xea, 0x57, 0xc7, 0x09, 0x3e, 0x36, 0x99, 0xa4, 0x8f, 0x00, 0x04, 0x9d, 0xb1, 0x57, 0xb1, 0x05, + 0x02, 0x53, 0x66, 0x30, 0x7b, 0x83, 0x45, 0xcb, 0x0d, 0x67, 0x3c, 0x0b, 0x96, 0xa7, 0x68, 0xe2, 0x02, 0x48, 0xe4, + 0x86, 0xf9, 0xe5, 0xc2, 0xc4, 0x9d, 0x97, 0x8b, 0x68, 0xad, 0x53, 0x79, 0x6c, 0x99, 0x85, 0x49, 0xa1, 0xf0, 0x53, + 0x4c, 0x26, 0xfc, 0x70, 0xfe, 0xbb, 0xda, 0x4b, 0x6c, 0xb1, 0x73, 0x79, 0x1f, 0x18, 0x41, 0x32, 0xb2, 0x10, 0xc6, + 0x8a, 0x05, 0x20, 0xec, 0x05, 0xc9, 0xc2, 0x44, 0xef, 0x6e, 0xad, 0x15, 0xe8, 0x86, 0x85, 0x6b, 0xbb, 0x29, 0xc7, + 0xb4, 0xe8, 0x45, 0xf3, 0xb1, 0xab, 0x39, 0xad, 0x63, 0x43, 0xfc, 0xb1, 0xec, 0x8e, 0x9e, 0x62, 0x0f, 0xca, 0xd4, + 0xbb, 0xd9, 0xcc, 0xc2, 0x20, 0x31, 0x67, 0xee, 0xd2, 0xf3, 0xef, 0x7b, 0xcb, 0x30, 0x08, 0xe3, 0x95, 0x3b, 0x61, + 0xfd, 0x5c, 0x75, 0xd3, 0xc7, 0x68, 0x49, 0xdc, 0x61, 0xdf, 0xb1, 0x5a, 0x11, 0x5b, 0x52, 0xeb, 0x2c, 0x18, 0xd2, + 0xcc, 0x67, 0x77, 0x29, 0xff, 0x7c, 0xa1, 0x32, 0x55, 0xc5, 0x2d, 0x47, 0x2d, 0x40, 0x0e, 0xe1, 0x91, 0x96, 0x20, + 0xbe, 0x60, 0x9f, 0x33, 0xf3, 0x3d, 0xab, 0xd5, 0x89, 0xd8, 0x52, 0xb1, 0x3a, 0x8d, 0x9d, 0x47, 0xe1, 0xed, 0x10, + 0x46, 0x8b, 0x8d, 0xcd, 0x98, 0xf9, 0x33, 0x7c, 0x63, 0xa2, 0x73, 0xa7, 0xe8, 0xc7, 0x44, 0x95, 0x0f, 0xf4, 0xc6, + 0x96, 0x7d, 0x78, 0xdd, 0x6b, 0x29, 0x76, 0x7f, 0xe9, 0x05, 0x26, 0x4d, 0xe7, 0xd8, 0x5e, 0x49, 0x7d, 0xc9, 0xf0, + 0xd3, 0x37, 0x58, 0xdd, 0x51, 0xec, 0x3e, 0x88, 0xf6, 0x33, 0x3f, 0xbc, 0xed, 0x2d, 0xbc, 0xe9, 0x94, 0x05, 0x7d, + 0x1c, 0x73, 0x56, 0xc8, 0x7c, 0xdf, 0x5b, 0xc5, 0x5e, 0xdc, 0x5f, 0xba, 0x77, 0xbc, 0xd7, 0xc3, 0xa6, 0x5e, 0xdb, + 0xbc, 0xd7, 0xf6, 0xde, 0xbd, 0x4a, 0xdd, 0x80, 0x23, 0x29, 0xf5, 0xc3, 0x87, 0xd6, 0x51, 0xec, 0xd2, 0x3c, 0xf7, + 0xee, 0x75, 0x15, 0xb1, 0xcd, 0xd2, 0x8d, 0xe6, 0x5e, 0xd0, 0xb3, 0x53, 0xeb, 0x66, 0x43, 0x1b, 0xe3, 0x71, 0xb7, + 0xdb, 0x4d, 0xad, 0xa9, 0x78, 0xb2, 0xa7, 0xd3, 0xd4, 0x9a, 0x88, 0xa7, 0xd9, 0xcc, 0xb6, 0x67, 0xb3, 0xd4, 0xf2, + 0x44, 0x41, 0xbb, 0x35, 0x99, 0xb6, 0x5b, 0xa9, 0x75, 0x2b, 0xd5, 0x48, 0x2d, 0xc6, 0x9f, 0x22, 0x36, 0xed, 0xe3, + 0x46, 0xe2, 0x76, 0xe9, 0xc7, 0xb6, 0x9d, 0x22, 0x06, 0xb8, 0x2c, 0xe0, 0x26, 0xd4, 0x2a, 0x5e, 0x6d, 0xf6, 0xae, + 0xa9, 0xe4, 0x9f, 0x9b, 0x4c, 0x6a, 0xeb, 0x4d, 0xdd, 0xe8, 0xc3, 0x95, 0x22, 0xcd, 0xc2, 0x75, 0xa9, 0xda, 0x46, + 0x80, 0xc1, 0xbc, 0xeb, 0x41, 0xd4, 0xcc, 0xfe, 0x38, 0x8c, 0xe0, 0xcc, 0x46, 0xee, 0xd4, 0x5b, 0xc7, 0x3d, 0xa7, + 0xb5, 0xba, 0x13, 0x45, 0x7c, 0xaf, 0xe7, 0x05, 0x78, 0xf6, 0x7a, 0x71, 0xe8, 0x7b, 0x53, 0x51, 0xd4, 0x74, 0x96, + 0x9c, 0x96, 0xde, 0xc7, 0x98, 0x31, 0x1e, 0x46, 0x3e, 0x72, 0x7d, 0x5f, 0xb1, 0xda, 0xb1, 0xc2, 0xdc, 0x18, 0x6f, + 0x32, 0x14, 0x3b, 0x26, 0xb8, 0x60, 0x7c, 0x18, 0xe7, 0x70, 0x75, 0x97, 0xed, 0x79, 0xe7, 0x68, 0x75, 0x97, 0x7e, + 0xb5, 0x64, 0x53, 0xcf, 0x55, 0xb4, 0x7c, 0x37, 0x39, 0x36, 0xdc, 0x76, 0xe8, 0x9b, 0x86, 0x6d, 0x2a, 0x8e, 0x05, + 0x44, 0x17, 0x7e, 0xe4, 0x2d, 0x57, 0x61, 0x94, 0xb8, 0x41, 0x92, 0xa6, 0xa3, 0xab, 0x34, 0xed, 0x5f, 0x78, 0xda, + 0xe5, 0x3f, 0x34, 0xa2, 0x85, 0x74, 0x3b, 0x98, 0xea, 0x57, 0xc6, 0x1b, 0x26, 0x5b, 0x32, 0x01, 0x19, 0x43, 0x2b, + 0x26, 0xb9, 0x32, 0xd1, 0xdb, 0x6a, 0x65, 0x02, 0x72, 0x56, 0x9d, 0x0c, 0xa3, 0x8a, 0x55, 0x90, 0x02, 0x41, 0x85, + 0x37, 0x6c, 0x70, 0x21, 0x99, 0x45, 0x01, 0xd3, 0x83, 0x95, 0xc9, 0xb5, 0xef, 0x49, 0x13, 0xef, 0xf9, 0xf5, 0x6e, + 0xde, 0xf3, 0x9f, 0xc9, 0x3e, 0xbc, 0xe7, 0xd7, 0x9f, 0x9d, 0xf7, 0x7c, 0x52, 0x75, 0xed, 0x3b, 0x0b, 0x07, 0x6a, + 0x76, 0x97, 0x05, 0xa4, 0x29, 0xa2, 0xa0, 0x79, 0x67, 0xc9, 0x7f, 0xeb, 0x8a, 0x27, 0x7a, 0xa3, 0x34, 0xb0, 0x44, + 0xb9, 0x81, 0x81, 0x7f, 0x1b, 0x0c, 0xfe, 0x1e, 0xc9, 0xcf, 0xb3, 0xd9, 0xe0, 0x75, 0x28, 0x15, 0x64, 0x4f, 0xdc, + 0xcc, 0xa7, 0x10, 0xe0, 0x88, 0xde, 0x64, 0x86, 0x58, 0x90, 0x02, 0x0a, 0xe2, 0xa3, 0x90, 0xb1, 0xfd, 0x34, 0x33, + 0x87, 0xec, 0x17, 0x87, 0xa0, 0x65, 0x06, 0xc6, 0xc2, 0x0b, 0xb6, 0xa2, 0xb4, 0x9e, 0xb3, 0x84, 0x87, 0xad, 0x78, + 0x79, 0x7f, 0x36, 0xd5, 0xce, 0x42, 0x3d, 0xf5, 0xe2, 0xb7, 0x65, 0x1f, 0x54, 0x21, 0x82, 0xc8, 0xd3, 0x49, 0xb9, + 0x49, 0xa3, 0x14, 0x6a, 0x06, 0x5f, 0x53, 0xf3, 0xd3, 0xc2, 0x4c, 0x7b, 0x72, 0x43, 0x9e, 0x6b, 0xb2, 0x42, 0x8c, + 0xb9, 0x4b, 0xdf, 0x86, 0x73, 0x79, 0x98, 0x3e, 0x13, 0x43, 0x77, 0x4c, 0xa9, 0xb9, 0x37, 0x4d, 0x53, 0xbd, 0x2f, + 0x00, 0x21, 0x11, 0x5a, 0xb6, 0x8b, 0x89, 0x8b, 0x73, 0x81, 0x96, 0xdf, 0x45, 0xd3, 0x45, 0xf3, 0x19, 0x98, 0x6e, + 0xf0, 0x6b, 0x69, 0x0e, 0x33, 0x55, 0x21, 0xf0, 0x91, 0x49, 0x8f, 0x34, 0x21, 0xb0, 0x35, 0x90, 0x0d, 0xe1, 0x0a, + 0x0b, 0x52, 0x35, 0x2a, 0x26, 0xe0, 0xa0, 0xed, 0x09, 0x04, 0xda, 0x11, 0xda, 0x2e, 0x42, 0x3b, 0xbc, 0x0e, 0x3e, + 0xa4, 0x6a, 0xc6, 0xfb, 0xe1, 0xf6, 0x1b, 0x9e, 0x1c, 0x40, 0x83, 0x61, 0x49, 0x93, 0xb5, 0xc3, 0x64, 0x16, 0x58, + 0x89, 0xf8, 0xd6, 0xb0, 0xe2, 0x5b, 0xe5, 0xd9, 0x46, 0x04, 0xa9, 0x4a, 0xdc, 0x95, 0x09, 0xea, 0x13, 0xc4, 0xbd, + 0x1c, 0xe3, 0x49, 0xf1, 0xb0, 0xfa, 0xeb, 0x18, 0x70, 0x23, 0x4a, 0xf2, 0x88, 0x7f, 0xfa, 0x93, 0x75, 0x14, 0x87, + 0x51, 0x6f, 0x15, 0x7a, 0x41, 0xc2, 0xa2, 0x14, 0x41, 0x75, 0x89, 0xf0, 0x11, 0xe0, 0xb9, 0xda, 0x84, 0x2b, 0x77, + 0xe2, 0x25, 0xf7, 0x3d, 0x9b, 0xb3, 0x14, 0x76, 0x9f, 0x73, 0x07, 0x76, 0x6d, 0xfd, 0x1e, 0x87, 0xe6, 0x73, 0x64, + 0xfc, 0xa2, 0x2a, 0x3b, 0x23, 0x6f, 0xf3, 0xbe, 0xf4, 0x96, 0xc2, 0x74, 0x01, 0xfb, 0xe1, 0x46, 0xe6, 0x1c, 0xb0, + 0x3c, 0x2c, 0xb5, 0x3d, 0x65, 0x73, 0x03, 0xb1, 0x36, 0xdc, 0x00, 0x89, 0x3f, 0x56, 0x47, 0x57, 0xec, 0xfa, 0x62, + 0xe0, 0x78, 0xf4, 0x7d, 0x46, 0xd6, 0x73, 0x21, 0xa9, 0xa5, 0xb1, 0x4f, 0xcd, 0x31, 0x9b, 0x85, 0x11, 0xa3, 0x90, + 0xee, 0x4e, 0x77, 0x75, 0xb7, 0x7f, 0xf7, 0xdb, 0xa7, 0x5f, 0xdf, 0x4f, 0x10, 0x26, 0x9a, 0xe8, 0x4c, 0xdf, 0xd1, + 0x5b, 0x95, 0x9e, 0x01, 0x6b, 0x48, 0x90, 0x9f, 0x90, 0xc3, 0x49, 0x4f, 0x55, 0xfb, 0xb5, 0x91, 0x33, 0x57, 0x21, + 0xa7, 0x79, 0x11, 0xf3, 0xdd, 0xc4, 0xbb, 0x11, 0x3c, 0x63, 0xfb, 0x68, 0x75, 0x27, 0xd6, 0x18, 0x09, 0xde, 0x03, + 0x16, 0xa9, 0x34, 0x14, 0xb1, 0x48, 0xe5, 0x62, 0x5c, 0xa4, 0x7e, 0x65, 0x36, 0x22, 0x98, 0x54, 0x89, 0xd2, 0x77, + 0x56, 0x77, 0x32, 0x89, 0xce, 0x9b, 0x65, 0x94, 0xba, 0x1c, 0x05, 0x74, 0xe9, 0x4d, 0xa7, 0x3e, 0x4b, 0x0b, 0x0b, + 0x5d, 0x5c, 0x4b, 0x09, 0x38, 0x19, 0x1c, 0xdc, 0x71, 0x1c, 0xfa, 0xeb, 0x84, 0xd5, 0x83, 0x8b, 0x80, 0xd3, 0xb2, + 0x73, 0xe0, 0xe0, 0xef, 0xe2, 0x58, 0x3b, 0xc0, 0x6e, 0xc3, 0x36, 0xb1, 0xfb, 0x10, 0xf4, 0xdf, 0x6c, 0x17, 0x87, + 0x0e, 0xaf, 0xb2, 0x41, 0x1b, 0x35, 0x13, 0x31, 0x80, 0x2c, 0x11, 0xf6, 0x56, 0x2c, 0x87, 0x97, 0x65, 0x81, 0xcf, + 0xb3, 0xa2, 0xb4, 0x38, 0x99, 0xdf, 0xe7, 0x8c, 0xbd, 0xa8, 0x3f, 0x63, 0x2f, 0xc4, 0x19, 0xdb, 0xbe, 0x33, 0x1f, + 0xcf, 0x1c, 0xf8, 0xaf, 0x9f, 0x4f, 0xa8, 0x67, 0x2b, 0xed, 0xd5, 0x9d, 0xe2, 0xac, 0xee, 0x14, 0xb3, 0xb5, 0xba, + 0x53, 0xb0, 0x6b, 0xb4, 0x3c, 0x32, 0xac, 0x96, 0x6e, 0xd8, 0x0a, 0x14, 0xc2, 0x1f, 0xbb, 0xf0, 0xca, 0x39, 0x84, + 0x77, 0xd0, 0xaa, 0x53, 0x7d, 0xd7, 0xda, 0x7e, 0xd4, 0xe9, 0x2c, 0x09, 0xa4, 0xad, 0x5b, 0x89, 0x3b, 0x1e, 0xb3, + 0x69, 0x6f, 0x16, 0x4e, 0xd6, 0xf1, 0xbf, 0xf9, 0xf8, 0x39, 0x10, 0xb7, 0x22, 0x82, 0x52, 0x3f, 0xa2, 0x29, 0x68, + 0xf7, 0x6e, 0x98, 0xe8, 0x61, 0x93, 0xad, 0x53, 0x8f, 0x32, 0x14, 0xb4, 0xac, 0xc3, 0x9a, 0x4d, 0x5e, 0x0f, 0xe8, + 0xdf, 0x6d, 0x95, 0x9a, 0x51, 0xcc, 0x27, 0x80, 0x65, 0x2b, 0x38, 0x1e, 0x0e, 0x0d, 0xbe, 0x9a, 0x76, 0xb7, 0x7e, + 0xb8, 0x97, 0xe2, 0x4b, 0x57, 0x82, 0xa8, 0x70, 0xba, 0xc5, 0xdd, 0xa0, 0xb6, 0xf7, 0xda, 0xb4, 0x47, 0x2a, 0xbd, + 0x6e, 0x21, 0x08, 0x79, 0xdd, 0x3d, 0xb1, 0xfc, 0xe3, 0x17, 0x87, 0xf0, 0x1f, 0x71, 0xf5, 0xff, 0x4c, 0xea, 0x18, + 0xf5, 0xb3, 0xa4, 0xc0, 0xa8, 0x13, 0xab, 0x84, 0x8c, 0xf8, 0xfe, 0xf5, 0x67, 0xb3, 0x87, 0x35, 0xd8, 0xbb, 0x36, + 0x19, 0xed, 0x95, 0x6b, 0xbf, 0x0c, 0x43, 0xc8, 0x9e, 0x5d, 0xad, 0x2e, 0xc0, 0x43, 0x1e, 0x18, 0xc9, 0x00, 0x1a, + 0x09, 0x39, 0x82, 0xec, 0x45, 0x54, 0x6c, 0x43, 0xa2, 0xc4, 0x9b, 0x26, 0x51, 0xe2, 0xf5, 0x6e, 0x51, 0xe2, 0xbb, + 0xbd, 0x44, 0x89, 0xd7, 0x9f, 0x5d, 0x94, 0x78, 0x53, 0x15, 0x25, 0x2e, 0x42, 0x61, 0xa9, 0x6d, 0x9c, 0xad, 0xf9, + 0xcf, 0x9f, 0xe9, 0x2a, 0xf6, 0x3c, 0x1c, 0x74, 0x6c, 0xca, 0x3a, 0x70, 0xf1, 0x5f, 0x0b, 0x16, 0xb8, 0x11, 0xdf, + 0xa1, 0xe1, 0x62, 0x2e, 0x5a, 0x70, 0xcc, 0x8e, 0xdf, 0x91, 0x8a, 0xfd, 0x30, 0x98, 0xff, 0x08, 0x57, 0xf1, 0xa0, + 0x0e, 0x8c, 0xa4, 0x17, 0x5e, 0xfc, 0x63, 0xb8, 0x5a, 0xaf, 0xce, 0xa0, 0xaf, 0x9f, 0xbd, 0xd8, 0x1b, 0xfb, 0x2c, + 0x8b, 0x06, 0x42, 0x86, 0x96, 0x5c, 0xb7, 0x0e, 0xb6, 0xcd, 0xe2, 0xa7, 0x7b, 0x27, 0x7e, 0xa2, 0xf5, 0x33, 0xff, + 0x4d, 0x16, 0x9c, 0x6a, 0xbd, 0x20, 0x02, 0x61, 0xf3, 0x4a, 0x83, 0x7e, 0xb8, 0x30, 0x72, 0x11, 0xea, 0x35, 0xb3, + 0x14, 0x96, 0x35, 0x8d, 0xfd, 0xb0, 0x8a, 0x50, 0xb3, 0xd6, 0x8d, 0x2c, 0x0a, 0x66, 0x55, 0x9d, 0xbf, 0x0c, 0xd7, + 0x31, 0x9b, 0x86, 0xb7, 0x81, 0x6a, 0x04, 0xdc, 0x1c, 0x94, 0x12, 0x09, 0x66, 0x6d, 0x30, 0x7f, 0xf3, 0x7b, 0x64, + 0x94, 0x21, 0x62, 0x02, 0xa4, 0x0f, 0x5f, 0xaf, 0x4c, 0x32, 0x30, 0x30, 0x71, 0x8a, 0x6a, 0x96, 0x68, 0xf0, 0x91, + 0xa6, 0x85, 0x83, 0x87, 0xb5, 0x14, 0x46, 0x41, 0xa1, 0xc5, 0xb5, 0xc2, 0xb1, 0x16, 0x08, 0xe5, 0xa2, 0x08, 0x45, + 0x55, 0xb3, 0x70, 0xfc, 0x0d, 0x85, 0xfa, 0xc8, 0xdf, 0x42, 0x64, 0x88, 0x74, 0xcd, 0xd7, 0x83, 0x07, 0x66, 0xa2, + 0xc7, 0x57, 0x12, 0x18, 0xdf, 0xde, 0xb0, 0xc8, 0x77, 0xef, 0x35, 0x3d, 0x0d, 0x83, 0xef, 0x01, 0x00, 0xaf, 0xc3, + 0xdb, 0x40, 0xae, 0x80, 0xf9, 0xd2, 0x6a, 0xf6, 0x52, 0x6d, 0x08, 0x31, 0x70, 0xa7, 0x92, 0x46, 0x00, 0x99, 0xea, + 0xe7, 0xec, 0xef, 0x06, 0xfd, 0xfb, 0x0f, 0x3d, 0x35, 0xce, 0xc3, 0xec, 0x43, 0x3f, 0xad, 0xf6, 0xf8, 0xcc, 0xd3, + 0xa7, 0x8f, 0x9a, 0xa7, 0xad, 0x4d, 0x7c, 0xe6, 0x8a, 0xfc, 0xf3, 0x5a, 0x4d, 0x6b, 0xbd, 0xf1, 0x14, 0xc0, 0x28, + 0x2e, 0xc2, 0xf5, 0x64, 0x81, 0x26, 0xd5, 0x9f, 0x6f, 0xbe, 0x09, 0xf4, 0x89, 0x89, 0xc2, 0xb3, 0xa9, 0x97, 0x8a, + 0x72, 0x28, 0xe0, 0xf7, 0xdf, 0x40, 0x0c, 0xec, 0x3f, 0x11, 0x0c, 0xd5, 0x5d, 0x93, 0xb9, 0x5b, 0x3f, 0x68, 0xf3, + 0xf6, 0x21, 0x9f, 0x35, 0x8f, 0x2e, 0x25, 0x2e, 0xe9, 0xea, 0x91, 0x4c, 0x5a, 0x06, 0x9a, 0x1c, 0xc9, 0xb5, 0x29, + 0x48, 0xad, 0xf8, 0x0a, 0xb3, 0x48, 0x4c, 0xe7, 0x2e, 0x2d, 0x06, 0xe3, 0xd8, 0xaa, 0x84, 0x64, 0xb8, 0xa1, 0x0b, + 0x43, 0xf4, 0x55, 0x7e, 0xb7, 0xf4, 0x02, 0x03, 0x13, 0xb1, 0x54, 0xdf, 0xb8, 0x77, 0x90, 0x8a, 0x00, 0x90, 0x5b, + 0xf9, 0x15, 0x14, 0x1a, 0xb2, 0x23, 0x27, 0x64, 0x5b, 0x54, 0x6b, 0x21, 0x21, 0x6e, 0x03, 0x47, 0x5f, 0x28, 0x8a, + 0xa2, 0x64, 0x62, 0x84, 0x92, 0xc9, 0x11, 0x58, 0x8e, 0xe2, 0x00, 0xdc, 0x96, 0xa4, 0xab, 0x3b, 0x2a, 0x01, 0xc9, + 0x00, 0xaf, 0xb6, 0x45, 0x01, 0x8f, 0xb6, 0xdb, 0xb1, 0x45, 0x81, 0x10, 0xe8, 0x21, 0x52, 0xaa, 0x1b, 0x41, 0x50, + 0xfe, 0x9e, 0x82, 0x02, 0x3b, 0xbe, 0xe5, 0x9a, 0x60, 0xc5, 0xa6, 0xc7, 0x51, 0x9f, 0xd5, 0x87, 0x65, 0x0d, 0x24, + 0x2c, 0x08, 0xb7, 0x0e, 0xa5, 0x2c, 0x0b, 0x06, 0xab, 0xc1, 0x8d, 0x28, 0x17, 0xdd, 0x25, 0x4b, 0x16, 0xac, 0x55, + 0x4c, 0xcb, 0x88, 0x61, 0x72, 0xa1, 0xce, 0x6b, 0x62, 0xb6, 0x00, 0xdb, 0xd4, 0xb7, 0x5c, 0x10, 0x2d, 0x8c, 0x39, + 0x4a, 0x75, 0x8d, 0x09, 0xf7, 0x4d, 0x8c, 0x39, 0x6e, 0x2b, 0x53, 0x08, 0xbe, 0xa4, 0x61, 0x11, 0x9b, 0x73, 0x6f, + 0x64, 0xe4, 0x14, 0x28, 0x42, 0x15, 0x57, 0x17, 0x09, 0xb0, 0x6b, 0x6e, 0x79, 0xd1, 0xb2, 0x1b, 0x19, 0xb7, 0xa4, + 0x28, 0x8a, 0xf4, 0x6a, 0x37, 0x7c, 0x9c, 0x10, 0x1b, 0xb0, 0xb1, 0x9f, 0x49, 0xa5, 0x9f, 0x86, 0x49, 0x7f, 0x60, + 0xf7, 0x44, 0x48, 0x08, 0x54, 0x1f, 0xd8, 0x3d, 0xdc, 0xdb, 0xbf, 0x01, 0x6d, 0x8a, 0xba, 0x05, 0x5d, 0x1b, 0x90, + 0x6d, 0x67, 0x02, 0xf1, 0x22, 0xb7, 0x1c, 0x20, 0x3b, 0xdd, 0x82, 0xc5, 0x11, 0xc4, 0x81, 0x11, 0xf7, 0xc5, 0x21, + 0xe6, 0xce, 0x24, 0x5a, 0x2d, 0x8c, 0xcd, 0x9a, 0xa3, 0xa1, 0x3f, 0x73, 0x6c, 0xfb, 0xa0, 0x52, 0x1f, 0x14, 0xd9, + 0x75, 0xb5, 0x75, 0x23, 0x19, 0x38, 0xb6, 0xe9, 0x3d, 0xb3, 0x5a, 0xfd, 0x0a, 0x8d, 0x96, 0xc2, 0x39, 0x8f, 0x50, + 0xfd, 0x35, 0x7c, 0xb2, 0xd1, 0x2a, 0x07, 0x52, 0x2f, 0x3b, 0x67, 0xe0, 0xd8, 0x52, 0xae, 0xff, 0x1a, 0x55, 0x49, + 0x3f, 0x05, 0x93, 0xa6, 0xd4, 0x62, 0x23, 0x48, 0x48, 0xa0, 0xc1, 0x31, 0xfa, 0x8b, 0xf2, 0x5c, 0xd1, 0xe8, 0xf8, + 0xe8, 0xfa, 0xa8, 0x2f, 0x30, 0x8a, 0xf0, 0x5e, 0x94, 0x3b, 0x28, 0x7d, 0x31, 0x2e, 0x63, 0x38, 0x1e, 0xfa, 0x9c, + 0xe5, 0x37, 0x7a, 0x5b, 0xb9, 0x05, 0xec, 0xbf, 0x81, 0x7c, 0x5a, 0x63, 0x88, 0xaf, 0x01, 0x35, 0x20, 0x7d, 0xc9, + 0xce, 0x0e, 0x21, 0x6c, 0x92, 0xdc, 0x5d, 0x91, 0x48, 0xee, 0xdf, 0x19, 0x12, 0x1d, 0xbc, 0x43, 0xcb, 0xfa, 0xab, + 0x27, 0x77, 0x0f, 0xec, 0x92, 0x05, 0xd3, 0x62, 0x87, 0x25, 0xfa, 0xb5, 0x7f, 0x77, 0x05, 0x8c, 0x02, 0x79, 0x7d, + 0xc2, 0x1a, 0x8c, 0x92, 0x86, 0x01, 0x6e, 0x7e, 0x3a, 0x6e, 0xde, 0x5e, 0x5c, 0x0c, 0x36, 0xa0, 0xa0, 0x9c, 0x59, + 0x33, 0x49, 0x29, 0x0e, 0xc9, 0x23, 0xd0, 0xb9, 0x59, 0x13, 0x8c, 0x68, 0xe3, 0x4e, 0x4c, 0x84, 0x25, 0x69, 0xde, + 0xc6, 0xe3, 0xe1, 0xa0, 0xf7, 0xd5, 0x5a, 0x7b, 0xbb, 0xb5, 0xd6, 0xc9, 0x2e, 0xad, 0x35, 0x39, 0xee, 0x91, 0xf9, + 0x53, 0xe6, 0xc0, 0x28, 0x98, 0x73, 0xd9, 0x05, 0xb4, 0xa0, 0xea, 0x46, 0x3f, 0x3f, 0xd1, 0xaa, 0xd2, 0x1b, 0xd9, + 0x86, 0xa2, 0xfa, 0x5b, 0x12, 0x50, 0xc4, 0x85, 0xba, 0xac, 0x1b, 0xbf, 0xc8, 0x75, 0xe3, 0x24, 0xd5, 0xe4, 0x2e, + 0x5b, 0x82, 0xfb, 0x97, 0xdc, 0x21, 0x33, 0xe9, 0x20, 0x77, 0x8b, 0xcc, 0x47, 0x2a, 0x39, 0xfa, 0xe5, 0x82, 0x86, + 0xe4, 0x3e, 0x2a, 0xa4, 0x8c, 0xa2, 0x17, 0x69, 0xb1, 0x6a, 0xee, 0xe7, 0x97, 0x97, 0x83, 0xd6, 0x1d, 0x87, 0x9c, + 0x15, 0xcb, 0xdb, 0xa6, 0xe8, 0xe8, 0x25, 0xbf, 0x96, 0x36, 0x49, 0xe6, 0x91, 0x45, 0x00, 0x16, 0x6a, 0xfa, 0xd2, + 0xbd, 0x76, 0x66, 0x03, 0x81, 0x83, 0xac, 0x71, 0x20, 0xdd, 0xad, 0x9d, 0xa7, 0x94, 0x45, 0xf9, 0xd5, 0xb5, 0x83, + 0xd4, 0x9d, 0x6e, 0x82, 0x65, 0x7d, 0x04, 0xc2, 0xfa, 0x4a, 0xd2, 0x20, 0xf4, 0x6c, 0xc5, 0xee, 0xd7, 0x30, 0x00, + 0x48, 0xff, 0xcb, 0xcf, 0x9c, 0x15, 0x00, 0x4d, 0xa4, 0x62, 0xcb, 0x77, 0xfe, 0x78, 0x88, 0x4d, 0x32, 0x3f, 0xc3, + 0xaa, 0xd5, 0x6f, 0x92, 0xbe, 0x67, 0xc3, 0xdd, 0xb5, 0x8a, 0xea, 0x7c, 0x5e, 0xa3, 0x27, 0xc6, 0xc1, 0x77, 0x59, + 0xb4, 0x0e, 0x30, 0x13, 0x8d, 0x99, 0x44, 0xee, 0xe4, 0xc3, 0x46, 0xfa, 0x1e, 0x57, 0x89, 0x82, 0xba, 0xb8, 0x78, + 0xa9, 0xd0, 0x77, 0x31, 0x70, 0x33, 0xeb, 0x59, 0xad, 0x58, 0x52, 0xd4, 0xf4, 0x1e, 0xdb, 0x6d, 0xf7, 0xc5, 0xec, + 0xb0, 0xa4, 0x3f, 0x6d, 0x75, 0x8a, 0xda, 0xf5, 0x6c, 0x1c, 0xcb, 0xf0, 0x57, 0xee, 0xd8, 0xfa, 0xc7, 0x7f, 0x3a, + 0xe6, 0xdf, 0x2c, 0xad, 0xd1, 0xa7, 0x0c, 0x01, 0xda, 0x17, 0x2e, 0xa6, 0xe5, 0x6b, 0x9a, 0x4a, 0x49, 0xd3, 0xb0, + 0x66, 0x9e, 0xef, 0x9b, 0x3e, 0xb8, 0x17, 0x6d, 0x3e, 0x69, 0x7a, 0xd8, 0xcf, 0x1a, 0x52, 0x06, 0x7c, 0x42, 0x3f, + 0xc5, 0x9d, 0x92, 0x2c, 0xd6, 0xcb, 0xf1, 0x46, 0x56, 0x94, 0x4b, 0xfa, 0xf3, 0xaa, 0xce, 0x5c, 0xfe, 0xec, 0x6c, + 0x36, 0x2b, 0x6a, 0x8d, 0x6d, 0xe5, 0x10, 0x35, 0xbf, 0x8f, 0x6d, 0xdb, 0x2e, 0xc3, 0xb7, 0xe9, 0xa0, 0xd0, 0xc1, + 0x30, 0x51, 0x09, 0xdf, 0xdd, 0xbd, 0xa7, 0xfe, 0xa0, 0xd1, 0x52, 0x57, 0x4d, 0xe7, 0x91, 0xb6, 0xda, 0xff, 0x8b, + 0xa1, 0x20, 0x6a, 0xd8, 0x75, 0xfc, 0xab, 0x7b, 0x65, 0x4b, 0x4f, 0xe5, 0x03, 0xfc, 0xb0, 0xc6, 0x3b, 0xf6, 0xfa, + 0x1e, 0x4d, 0x9b, 0xb6, 0x77, 0x6a, 0xe5, 0x64, 0xb7, 0x60, 0xb3, 0xd4, 0x27, 0x4b, 0x25, 0x2f, 0x61, 0xcb, 0xb8, + 0x37, 0x61, 0x78, 0x41, 0x6a, 0x49, 0xd4, 0x16, 0xad, 0x7a, 0xcc, 0x39, 0xd8, 0x71, 0x39, 0x02, 0x0f, 0xdb, 0x0a, + 0x5e, 0x56, 0x55, 0x6e, 0xd6, 0xc4, 0x47, 0x90, 0x8a, 0x6d, 0xaa, 0x17, 0x4e, 0xb8, 0x4d, 0x3b, 0xf6, 0x5f, 0x0a, + 0xf5, 0x14, 0xe0, 0x4e, 0x37, 0xc2, 0xda, 0x84, 0x2e, 0x4f, 0xf0, 0xef, 0xec, 0x72, 0xee, 0xc5, 0xea, 0xae, 0x68, + 0xdc, 0xd5, 0x85, 0xeb, 0xa6, 0x9c, 0x94, 0xd1, 0xa8, 0xeb, 0x50, 0x5f, 0x66, 0x02, 0x34, 0x93, 0xad, 0x5b, 0xc0, + 0x82, 0xa6, 0x90, 0x20, 0xaf, 0xe6, 0x6e, 0x0c, 0xc5, 0x59, 0xd8, 0x79, 0xb9, 0x7e, 0x3f, 0x4f, 0xef, 0x0c, 0x73, + 0x30, 0x9e, 0x77, 0xf1, 0x72, 0xaf, 0xb0, 0x55, 0xd1, 0x54, 0x06, 0xf7, 0x80, 0x90, 0x48, 0x95, 0x75, 0xe4, 0x9b, + 0x94, 0x3d, 0x4e, 0xd3, 0x37, 0xd5, 0x79, 0x37, 0x77, 0xef, 0x74, 0xe0, 0x5e, 0xa3, 0x0a, 0xaa, 0xbd, 0xae, 0xf6, + 0xca, 0x77, 0xd8, 0x62, 0x9c, 0xb0, 0x02, 0xe0, 0x8a, 0xa2, 0xa0, 0xd1, 0x90, 0x52, 0xc2, 0x7d, 0x34, 0xe9, 0xec, + 0xad, 0x8c, 0xac, 0xc5, 0x3c, 0xb1, 0xbb, 0xfa, 0x2a, 0xd4, 0xb7, 0xb8, 0x19, 0x04, 0xd8, 0x71, 0xec, 0x84, 0xcf, + 0x26, 0xec, 0x18, 0x19, 0x5d, 0x39, 0xb8, 0x83, 0xf0, 0x94, 0x9a, 0x14, 0xdf, 0x96, 0x4e, 0x29, 0xde, 0x25, 0x7c, + 0x57, 0xab, 0xbc, 0xbf, 0x28, 0x68, 0xe3, 0xb9, 0x3f, 0x50, 0x4b, 0xdf, 0xab, 0xf6, 0xd2, 0x0b, 0xf6, 0xaf, 0xeb, + 0xde, 0xed, 0x5d, 0x17, 0x98, 0xc3, 0xbd, 0x2b, 0x03, 0x77, 0x49, 0x56, 0x4a, 0xc9, 0xe0, 0x3b, 0xe9, 0xf2, 0x40, + 0x8e, 0x65, 0xa1, 0x62, 0x2b, 0x92, 0xe8, 0x2f, 0xd6, 0x83, 0xd1, 0xc9, 0xe9, 0xdd, 0xd2, 0x57, 0x6e, 0x58, 0x04, + 0x99, 0x34, 0x07, 0xaa, 0x63, 0xd9, 0xaa, 0x82, 0x91, 0x19, 0xbc, 0x60, 0x3e, 0x50, 0x7f, 0xba, 0xf8, 0xc6, 0xec, + 0xaa, 0xa7, 0x60, 0x8e, 0x71, 0x33, 0x47, 0x16, 0xf7, 0xdc, 0xbd, 0x67, 0xd1, 0x75, 0x4b, 0x55, 0x30, 0x61, 0x26, + 0x31, 0xb7, 0x58, 0xa6, 0xb4, 0xd4, 0x3d, 0xf2, 0xb2, 0x29, 0x22, 0xb5, 0xb2, 0x0a, 0x88, 0xd5, 0x69, 0x75, 0x15, + 0xa7, 0x75, 0x68, 0x1d, 0x75, 0xd5, 0xe1, 0x17, 0x8a, 0x72, 0x32, 0x65, 0xb3, 0x78, 0x88, 0xea, 0x98, 0x13, 0xe4, + 0x07, 0xe9, 0xb7, 0xa2, 0x58, 0x13, 0x3f, 0x36, 0x1d, 0x65, 0xc3, 0x1f, 0x15, 0x05, 0x90, 0x51, 0x4f, 0x79, 0x3c, + 0x6b, 0xcd, 0x0e, 0x67, 0x2f, 0xfa, 0xbc, 0x38, 0xfd, 0xa2, 0x50, 0xdd, 0xa0, 0x7f, 0x5b, 0x52, 0xb3, 0x38, 0x89, + 0xc2, 0x0f, 0x8c, 0xf3, 0x92, 0x4a, 0xa6, 0x28, 0x2a, 0x37, 0x6d, 0x55, 0xbf, 0xe4, 0x74, 0xc7, 0x93, 0x59, 0x2b, + 0xaf, 0x8e, 0x63, 0x3c, 0xc8, 0x06, 0x79, 0x72, 0x20, 0x86, 0x7e, 0x22, 0x83, 0xc9, 0x31, 0xeb, 0x00, 0xe5, 0xa8, + 0x7c, 0x8e, 0x73, 0x31, 0xbf, 0x13, 0x08, 0x7b, 0x9e, 0x7b, 0x70, 0xc4, 0xd8, 0x6c, 0xa0, 0x7e, 0xef, 0xb4, 0xba, + 0x86, 0xe3, 0x1c, 0x59, 0x47, 0xdd, 0x89, 0x6d, 0x1c, 0x5a, 0x87, 0x66, 0xdb, 0x3a, 0x32, 0xba, 0x66, 0xd7, 0xe8, + 0x7e, 0xdb, 0x9d, 0x98, 0x87, 0xd6, 0xa1, 0x61, 0x9b, 0x5d, 0x28, 0x34, 0xbb, 0x66, 0xf7, 0xc6, 0x3c, 0xec, 0x4e, + 0x6c, 0x2c, 0x6d, 0x59, 0x9d, 0x8e, 0xe9, 0xd8, 0x56, 0xa7, 0x63, 0x74, 0xac, 0xa3, 0x23, 0xd3, 0x69, 0x5b, 0x47, + 0x47, 0xe7, 0x9d, 0xae, 0xd5, 0x86, 0x77, 0xed, 0xf6, 0xa4, 0x6d, 0x39, 0x8e, 0x09, 0x7f, 0x19, 0x5d, 0xab, 0x45, + 0x3f, 0x1c, 0xc7, 0x6a, 0x3b, 0x86, 0xed, 0x77, 0x5a, 0xd6, 0xd1, 0x0b, 0x03, 0xff, 0xc6, 0x6a, 0x06, 0xfe, 0x05, + 0xdd, 0x18, 0x2f, 0xac, 0xd6, 0x11, 0xfd, 0xc2, 0x0e, 0x6f, 0x0e, 0xbb, 0xff, 0x54, 0x0f, 0x1a, 0xe7, 0xe0, 0xd0, + 0x1c, 0xba, 0x1d, 0xab, 0xdd, 0x36, 0x0e, 0x1d, 0xab, 0xdb, 0x5e, 0x98, 0x87, 0x2d, 0xeb, 0xe8, 0x78, 0x62, 0x3a, + 0xd6, 0xf1, 0xb1, 0x61, 0x9b, 0x6d, 0xab, 0x65, 0x38, 0xd6, 0x61, 0x1b, 0x7f, 0xb4, 0xad, 0xd6, 0xcd, 0xf1, 0x0b, + 0xeb, 0xa8, 0xb3, 0x38, 0xb2, 0x0e, 0x7f, 0x3e, 0xec, 0x5a, 0xad, 0xf6, 0xa2, 0x7d, 0x64, 0xb5, 0x8e, 0x6f, 0x8e, + 0xac, 0xc3, 0x85, 0xd9, 0x3a, 0xda, 0xda, 0xd2, 0x69, 0x59, 0x00, 0x23, 0x7c, 0x0d, 0x2f, 0x0c, 0xfe, 0x02, 0xfe, + 0x2c, 0xb0, 0xed, 0x1f, 0xd8, 0x4d, 0x5c, 0x6d, 0xfa, 0xc2, 0xea, 0x1e, 0x4f, 0xa8, 0x3a, 0x14, 0x98, 0xa2, 0x06, + 0x34, 0xb9, 0x31, 0xe9, 0xb3, 0xd8, 0x9d, 0x29, 0x3a, 0x12, 0x7f, 0xf8, 0xc7, 0x6e, 0x4c, 0xf8, 0x30, 0x7d, 0xf7, + 0x4f, 0xed, 0x27, 0x5b, 0x72, 0x48, 0x14, 0xff, 0x05, 0xff, 0x87, 0x72, 0x2c, 0x8e, 0x8c, 0xf3, 0xa6, 0x4b, 0xc9, + 0x77, 0xbb, 0x2f, 0x25, 0xbf, 0x59, 0xef, 0x73, 0x29, 0xf9, 0xee, 0xb3, 0x5f, 0x4a, 0x9e, 0x97, 0x7d, 0x6b, 0xde, + 0x95, 0x53, 0x41, 0x7d, 0xb7, 0x29, 0xab, 0x1c, 0x3c, 0x57, 0xbb, 0xbc, 0x58, 0x5f, 0x41, 0x68, 0xbf, 0x77, 0xe1, + 0xe0, 0x9b, 0x75, 0xc1, 0xe0, 0x33, 0x04, 0x1c, 0xfb, 0x2e, 0x24, 0x1c, 0xfb, 0xc3, 0x7a, 0x00, 0x56, 0x66, 0x9c, + 0xcd, 0xf1, 0xa6, 0xe6, 0xc2, 0xf5, 0x67, 0x19, 0x8b, 0x04, 0x25, 0x7d, 0x2c, 0x06, 0xc7, 0x35, 0x20, 0xcf, 0x20, + 0xc9, 0xac, 0x97, 0x41, 0x0c, 0x16, 0xc1, 0x60, 0xc9, 0x31, 0x8b, 0xd2, 0x52, 0x63, 0x4b, 0x04, 0x43, 0xbc, 0xe6, + 0x5e, 0x50, 0x8d, 0xef, 0xd1, 0x00, 0xb8, 0xbe, 0x77, 0xa7, 0xda, 0xaf, 0x02, 0x96, 0x75, 0xc2, 0x40, 0x1a, 0xb8, + 0xfd, 0xba, 0xf7, 0x45, 0x33, 0xdc, 0x92, 0xe1, 0x75, 0xf3, 0x48, 0x61, 0x24, 0xe5, 0xf6, 0x4e, 0xd1, 0x8c, 0x77, + 0xd7, 0x34, 0x6b, 0x3e, 0x5f, 0x68, 0xbe, 0xc5, 0x86, 0x38, 0xeb, 0xb8, 0x0c, 0xaa, 0x52, 0x22, 0xe3, 0x5a, 0x80, + 0xe4, 0x02, 0x6a, 0x6e, 0x68, 0x9c, 0x73, 0xaa, 0xb6, 0x82, 0xfc, 0x8e, 0x2d, 0xbd, 0x2b, 0xf4, 0x29, 0x1b, 0x27, + 0x3f, 0xdb, 0xa0, 0x5c, 0xe1, 0xfd, 0x0a, 0x9c, 0x28, 0xe7, 0x78, 0xc6, 0xa1, 0x0c, 0xe7, 0x8d, 0xd4, 0x2f, 0x69, + 0x23, 0xd2, 0x85, 0xb3, 0xa9, 0xf2, 0xa2, 0x8d, 0x6e, 0x09, 0x0e, 0x5b, 0x0a, 0x2e, 0x08, 0x3f, 0x4f, 0x4e, 0x00, + 0x29, 0x39, 0x6a, 0xa0, 0x9f, 0xc3, 0xb6, 0xce, 0x44, 0xbd, 0xc7, 0xb0, 0x89, 0x79, 0xd0, 0x65, 0x45, 0x8e, 0x36, + 0xb3, 0x99, 0xf9, 0xa1, 0x9b, 0xf4, 0x90, 0x4d, 0x93, 0x58, 0xde, 0x16, 0x7a, 0x2c, 0xf4, 0xb7, 0x18, 0xd3, 0xc9, + 0x1d, 0xf3, 0x4e, 0xd0, 0xf3, 0x61, 0x9b, 0xfd, 0x5d, 0xe6, 0x70, 0xb6, 0x29, 0x98, 0xa3, 0x38, 0x9d, 0x63, 0xc3, + 0x39, 0x32, 0xac, 0xe3, 0x8e, 0x9e, 0x8a, 0x03, 0x27, 0x77, 0x59, 0x00, 0x08, 0x38, 0x40, 0x64, 0xc3, 0xf4, 0x02, + 0x2f, 0xf1, 0x5c, 0x3f, 0x05, 0x7e, 0xb8, 0x28, 0xa4, 0xfc, 0x6b, 0x1d, 0x27, 0x30, 0x47, 0xc1, 0xf4, 0xa2, 0xf3, + 0x87, 0x39, 0x66, 0xc9, 0x2d, 0x63, 0x41, 0x83, 0x61, 0x4c, 0xd9, 0x97, 0xe4, 0xf7, 0xb3, 0xac, 0x4f, 0xc9, 0x6a, + 0x6d, 0x9c, 0x04, 0x7c, 0x7f, 0x08, 0xc7, 0x87, 0x74, 0x64, 0xfc, 0xda, 0x84, 0x70, 0xff, 0xb5, 0x1b, 0xe1, 0x26, + 0x6c, 0x1f, 0x84, 0xfb, 0xaf, 0xcf, 0x8e, 0x70, 0x7f, 0x95, 0x11, 0x6e, 0xc1, 0x7f, 0x30, 0xbf, 0x61, 0x7a, 0x8f, + 0xcf, 0x1a, 0x24, 0x51, 0x79, 0xae, 0x1e, 0x10, 0x03, 0x0f, 0xf9, 0x25, 0x44, 0x14, 0xaf, 0x97, 0x85, 0x64, 0x9d, + 0xa8, 0x00, 0xc5, 0x04, 0x1d, 0x94, 0x18, 0xd0, 0x03, 0x57, 0xb7, 0x2c, 0x39, 0x20, 0xbb, 0x55, 0xce, 0x82, 0xc4, + 0xb7, 0xde, 0x71, 0x39, 0x12, 0x2e, 0x74, 0xbf, 0x09, 0xa3, 0xa5, 0x8b, 0xd1, 0x5f, 0x55, 0x4c, 0xf2, 0x0d, 0x0f, + 0x36, 0x38, 0xe3, 0x4e, 0xc2, 0x60, 0x9a, 0xdd, 0x4a, 0xb2, 0xc1, 0x25, 0x71, 0xdc, 0xea, 0x3d, 0x73, 0x23, 0xd5, + 0xa0, 0xd7, 0xb0, 0xb8, 0xcf, 0xda, 0xf6, 0xb3, 0xd6, 0xe1, 0xb3, 0x23, 0x1b, 0xfe, 0x77, 0x58, 0x3b, 0x35, 0x78, + 0xc5, 0x65, 0x18, 0x40, 0x9e, 0x41, 0x51, 0xb3, 0xa9, 0xda, 0x2d, 0x63, 0x1f, 0xf2, 0x5a, 0xc7, 0xf5, 0x95, 0xa6, + 0xee, 0x7d, 0x5e, 0xa7, 0xb6, 0xc6, 0x22, 0x5c, 0x4b, 0xc3, 0xaa, 0x19, 0x8d, 0x17, 0xac, 0x41, 0xcf, 0x2e, 0xd5, + 0x90, 0x5f, 0xf3, 0xe9, 0xe6, 0xf3, 0x62, 0xed, 0xf4, 0x2a, 0x4f, 0x66, 0x2a, 0x92, 0x2a, 0xee, 0x84, 0x20, 0xbf, + 0xa2, 0xb4, 0x31, 0xde, 0x37, 0x66, 0x9c, 0x80, 0x68, 0xdf, 0x59, 0x0a, 0x4a, 0x97, 0x16, 0x28, 0x89, 0xd6, 0xc1, + 0x44, 0xc3, 0x9f, 0xee, 0x38, 0xd6, 0xbc, 0x83, 0xc8, 0xe2, 0x1f, 0xd6, 0x71, 0xd5, 0xdc, 0xa1, 0x9d, 0x67, 0x7e, + 0x8b, 0xc5, 0xaa, 0xb8, 0xcf, 0x12, 0x23, 0xc2, 0x7b, 0x6c, 0x5a, 0x5a, 0x73, 0xe0, 0x3e, 0xcb, 0x1a, 0x3e, 0x4b, + 0x8c, 0xe0, 0x39, 0xdc, 0x7d, 0x0e, 0xec, 0xa7, 0x4f, 0xa9, 0x16, 0x64, 0x51, 0xa7, 0x69, 0x9d, 0x4e, 0xf2, 0xa0, + 0xa1, 0x8a, 0x3b, 0x0f, 0x29, 0x6e, 0x68, 0x6f, 0x62, 0x84, 0xcf, 0x9f, 0x0f, 0x07, 0x8e, 0x8e, 0x59, 0x45, 0x45, + 0x76, 0x70, 0x9e, 0xb0, 0xf6, 0x7c, 0x3f, 0x43, 0x23, 0xbd, 0xd6, 0x95, 0x76, 0x05, 0x32, 0x93, 0x2d, 0xdc, 0x11, + 0x38, 0xf6, 0x82, 0x04, 0x72, 0x64, 0x50, 0xe0, 0x0a, 0x83, 0x1f, 0x51, 0x27, 0x93, 0xba, 0xda, 0x96, 0x6d, 0xd9, + 0x6a, 0xd6, 0x70, 0xe6, 0xcd, 0x07, 0x9b, 0x30, 0x71, 0x21, 0x15, 0xa7, 0x1f, 0xce, 0xc1, 0x8f, 0x2e, 0xf1, 0x12, + 0x1f, 0xf2, 0x3a, 0x82, 0x43, 0xdd, 0x92, 0xe4, 0xf2, 0x94, 0x7b, 0x37, 0xb8, 0xd1, 0x07, 0xcc, 0xed, 0x2d, 0x5c, + 0x71, 0x31, 0x8e, 0xdd, 0xf7, 0x40, 0x0c, 0x35, 0x55, 0x03, 0xdd, 0x00, 0x8b, 0x62, 0x53, 0xf6, 0x16, 0xea, 0x29, + 0xd0, 0x46, 0x57, 0xf9, 0x24, 0x66, 0x91, 0xbb, 0x84, 0x1c, 0x48, 0x9b, 0xd4, 0xe0, 0x98, 0x56, 0xe5, 0xa8, 0x56, + 0x71, 0x5e, 0x1c, 0x19, 0x4a, 0xcb, 0x31, 0x14, 0x1b, 0xd0, 0xad, 0x9a, 0x1a, 0x9b, 0xf4, 0xaa, 0xbf, 0xcb, 0xe0, + 0x81, 0xf0, 0xcb, 0x63, 0x9a, 0x07, 0x99, 0x3a, 0xf0, 0xab, 0xa4, 0x84, 0xe2, 0x17, 0x6b, 0x52, 0x66, 0x13, 0x8f, + 0x2e, 0x3d, 0x2f, 0xd8, 0x5d, 0xa2, 0x63, 0xde, 0x43, 0x5e, 0xc5, 0xd3, 0x37, 0xe8, 0x30, 0xec, 0x05, 0x8a, 0xf7, + 0xf1, 0xa3, 0xe6, 0x81, 0x33, 0xd3, 0x40, 0x82, 0x0f, 0x3c, 0xeb, 0x05, 0x80, 0x79, 0xf9, 0x35, 0x3d, 0x02, 0x0b, + 0x3c, 0x0d, 0xe1, 0xdf, 0xbc, 0x58, 0xfc, 0xe0, 0x66, 0x12, 0x96, 0xef, 0x06, 0x73, 0x40, 0x69, 0x6e, 0x30, 0xaf, + 0x98, 0x63, 0x91, 0xcf, 0x73, 0xa9, 0x34, 0xef, 0x2a, 0x37, 0x95, 0x8a, 0x5f, 0xde, 0x5f, 0x50, 0x5e, 0x57, 0x4d, + 0x05, 0x2a, 0x87, 0x2e, 0xba, 0xf9, 0x4d, 0xee, 0xf3, 0xc1, 0x97, 0x27, 0x4b, 0x96, 0xb8, 0x74, 0x0d, 0x04, 0xc2, + 0x2f, 0xb0, 0x03, 0x0a, 0x27, 0x34, 0x3c, 0x36, 0xd4, 0x60, 0xca, 0x6e, 0xbc, 0x09, 0x97, 0x4b, 0x0d, 0x85, 0xd3, + 0x29, 0x13, 0x2d, 0x3e, 0x07, 0x8e, 0x41, 0x0e, 0x07, 0x13, 0x17, 0x43, 0x1d, 0x0f, 0x82, 0x50, 0x1d, 0x7e, 0x99, + 0xf9, 0x66, 0x36, 0x2d, 0x02, 0x24, 0x57, 0xbf, 0x8c, 0x98, 0xff, 0xef, 0xc1, 0x97, 0x40, 0xb8, 0xbf, 0xbc, 0x52, + 0xf5, 0x7e, 0x62, 0x2d, 0x22, 0x36, 0x1b, 0x7c, 0x59, 0x93, 0x64, 0x1c, 0xc5, 0x7b, 0x1a, 0x8b, 0xda, 0x6e, 0xe5, + 0x21, 0xe7, 0xda, 0x7b, 0x09, 0xf5, 0x43, 0x2e, 0xad, 0x83, 0x04, 0xb8, 0x29, 0xc8, 0xd8, 0x4e, 0x1f, 0xe5, 0xe7, + 0xb1, 0xef, 0x4e, 0x3e, 0xf4, 0xe9, 0x4d, 0xe1, 0xc1, 0x04, 0x6a, 0x3d, 0x71, 0x57, 0x3d, 0x24, 0xaf, 0x72, 0x21, + 0x78, 0x4f, 0x53, 0x69, 0xc6, 0xd9, 0xd5, 0xee, 0x65, 0xdc, 0xca, 0x1b, 0xfc, 0x32, 0x7e, 0xea, 0x76, 0xe1, 0x25, + 0x4c, 0x7c, 0x0a, 0x1f, 0xd2, 0x54, 0x08, 0xea, 0x24, 0xa2, 0xa2, 0x60, 0x6d, 0xb5, 0x15, 0xa7, 0xfb, 0x6d, 0xe7, + 0xc6, 0xb1, 0x17, 0x2d, 0xc7, 0xea, 0xfe, 0xec, 0x74, 0x17, 0x6d, 0xeb, 0xd8, 0x37, 0xdb, 0xd6, 0x31, 0xfc, 0xf9, + 0xf9, 0xd8, 0xea, 0x2e, 0xcc, 0x96, 0x75, 0xf8, 0xb3, 0xd3, 0xf2, 0xcd, 0xae, 0x75, 0x0c, 0x7f, 0xce, 0xa9, 0x15, + 0x08, 0x40, 0x24, 0xef, 0x7c, 0x59, 0xc0, 0x02, 0xd2, 0xef, 0xec, 0x4e, 0xd6, 0x28, 0x90, 0xb7, 0x9a, 0x7b, 0x5d, + 0x40, 0x19, 0x94, 0xfa, 0x07, 0x4d, 0x11, 0xfa, 0x5a, 0x30, 0x60, 0x94, 0xec, 0x47, 0x98, 0xb7, 0x09, 0x3f, 0x74, + 0x91, 0x5f, 0xa5, 0xf6, 0x18, 0xf1, 0x36, 0xf5, 0x39, 0x45, 0x44, 0x22, 0x58, 0xba, 0x08, 0xfe, 0x69, 0x85, 0xa1, + 0xf1, 0x44, 0xfa, 0x2c, 0x09, 0x2b, 0xe5, 0xc9, 0xc8, 0xd3, 0xdd, 0x03, 0x47, 0x6f, 0x7e, 0x96, 0x25, 0xc3, 0xfc, + 0xac, 0x7d, 0x4b, 0x59, 0xca, 0x3e, 0xa9, 0x1f, 0xcc, 0xce, 0x94, 0x27, 0x56, 0x82, 0x88, 0xe2, 0x53, 0x2f, 0xca, + 0x86, 0x27, 0xa1, 0x68, 0xa7, 0x3e, 0x19, 0x8b, 0x0e, 0x59, 0x03, 0xcf, 0x80, 0x4b, 0xbe, 0x71, 0x7d, 0xc9, 0x90, + 0x4d, 0x6a, 0xf9, 0x28, 0xc3, 0xfc, 0x4f, 0x9f, 0xe6, 0x83, 0x33, 0x4b, 0xe3, 0x3e, 0x71, 0x3a, 0x40, 0x76, 0x3b, + 0xac, 0xbd, 0xd5, 0xa6, 0x72, 0x77, 0x2c, 0xfa, 0x3c, 0x08, 0xb5, 0xb0, 0x9b, 0x12, 0x16, 0x1b, 0x8d, 0x86, 0x9d, + 0x15, 0x7b, 0x0d, 0x88, 0xe2, 0x5f, 0x12, 0x75, 0x54, 0xbd, 0x1f, 0x08, 0xf3, 0x83, 0x60, 0x4b, 0xfc, 0x7d, 0x2e, + 0x8b, 0xa9, 0x00, 0x9a, 0x2d, 0xf3, 0xd8, 0xe1, 0x20, 0xfe, 0x67, 0x4f, 0x02, 0x9d, 0x35, 0xc1, 0x5e, 0xa2, 0x74, + 0x5a, 0x0b, 0xce, 0x7b, 0x19, 0x5d, 0x25, 0x82, 0xca, 0xe2, 0x53, 0x15, 0x8a, 0x20, 0x9d, 0x2c, 0x66, 0x90, 0xce, + 0x8c, 0x45, 0x33, 0x6a, 0x91, 0x17, 0x18, 0x1e, 0x26, 0x33, 0x11, 0x8e, 0xa3, 0xfa, 0xd3, 0xa7, 0x8d, 0x44, 0x88, + 0x8c, 0x73, 0x62, 0x96, 0x64, 0x39, 0x2e, 0x55, 0x19, 0xbf, 0xa9, 0x32, 0x8a, 0xc9, 0xfa, 0x45, 0xac, 0x21, 0x6c, + 0x5c, 0x69, 0xef, 0xe1, 0xcf, 0x31, 0x73, 0x13, 0x8b, 0x5f, 0x96, 0x6a, 0x12, 0x71, 0x37, 0x1c, 0xd6, 0x06, 0xeb, + 0x56, 0x1e, 0x41, 0x93, 0x47, 0xa8, 0x7d, 0xb2, 0x79, 0xb9, 0xe6, 0x51, 0x1d, 0xa0, 0x8f, 0x8f, 0x76, 0x1e, 0x80, + 0xec, 0x6d, 0xe2, 0x52, 0x60, 0x18, 0x99, 0xe4, 0x86, 0x89, 0x2b, 0xd2, 0x36, 0x02, 0x5f, 0xde, 0xaf, 0x35, 0xbf, + 0x90, 0x22, 0x3f, 0x0c, 0xdf, 0x5e, 0x7c, 0xad, 0xf0, 0xfd, 0x4f, 0xd6, 0x02, 0x28, 0xc8, 0x50, 0x6a, 0x9f, 0x01, + 0xa5, 0xf6, 0x51, 0x78, 0x6e, 0x29, 0xc8, 0x77, 0x93, 0x1e, 0x10, 0x04, 0x51, 0x01, 0x4d, 0x36, 0x14, 0xcb, 0xb5, + 0x9f, 0x78, 0x2b, 0x37, 0x4a, 0x0e, 0x30, 0xaf, 0x0f, 0x20, 0x39, 0xb5, 0x29, 0x1e, 0x04, 0x99, 0x61, 0x88, 0xc0, + 0xad, 0x49, 0x20, 0xec, 0x30, 0x66, 0x9e, 0x9f, 0x99, 0x61, 0x88, 0x0f, 0xb8, 0x93, 0x09, 0x5b, 0x25, 0x83, 0x42, + 0xfe, 0xa0, 0x70, 0x92, 0xb0, 0xc4, 0x8c, 0x93, 0x88, 0xb9, 0x4b, 0x35, 0x0b, 0x10, 0x5e, 0xed, 0x2f, 0x5e, 0x8f, + 0x97, 0x5e, 0x92, 0x45, 0xd8, 0xa5, 0x09, 0x82, 0x41, 0x04, 0x0c, 0x71, 0x38, 0x4a, 0x39, 0x08, 0xcf, 0xc3, 0x79, + 0x69, 0x47, 0xe5, 0x9c, 0xcb, 0x29, 0xc6, 0x6f, 0x27, 0x49, 0x06, 0xb4, 0xc5, 0x93, 0xd0, 0xbf, 0xe6, 0x31, 0x2c, + 0xb2, 0x40, 0xc0, 0xea, 0xf0, 0x84, 0x8b, 0xb7, 0x0a, 0x86, 0x6f, 0x51, 0x3b, 0x36, 0x44, 0xa8, 0x6f, 0x8a, 0x6e, + 0x71, 0xc0, 0x2b, 0x03, 0x69, 0xa2, 0x9e, 0x31, 0xc9, 0x08, 0x8d, 0xe5, 0x02, 0x18, 0xa1, 0x82, 0xc1, 0xcc, 0xc2, + 0x19, 0x66, 0xee, 0x94, 0x38, 0x2a, 0xe4, 0x95, 0x3e, 0x7e, 0x7c, 0x35, 0xfa, 0xed, 0x3f, 0x90, 0x09, 0x65, 0xe1, + 0x88, 0x98, 0x12, 0x97, 0x72, 0x2d, 0xce, 0x7d, 0x1a, 0x23, 0x34, 0x96, 0x62, 0x53, 0x11, 0xa2, 0x47, 0x6c, 0xad, + 0x74, 0x74, 0x25, 0x42, 0x34, 0x42, 0x92, 0x24, 0x5d, 0x44, 0xbe, 0x18, 0xc1, 0xf2, 0x8e, 0x44, 0x4c, 0x14, 0xe5, + 0x97, 0xbb, 0x97, 0xc7, 0x4a, 0x1e, 0xc3, 0xa8, 0xce, 0xa2, 0x87, 0xf6, 0xd0, 0xf0, 0xc4, 0x55, 0x90, 0x69, 0x41, + 0xf6, 0x23, 0xee, 0x1d, 0xc0, 0x34, 0x17, 0xe1, 0x92, 0x59, 0x5e, 0x78, 0x70, 0xcb, 0xc6, 0xa6, 0xbb, 0xf2, 0xc8, + 0x2e, 0x07, 0xf5, 0x6e, 0x0a, 0x71, 0x7e, 0x99, 0xb9, 0x0b, 0xf1, 0xd7, 0x69, 0x0e, 0xca, 0xb0, 0x18, 0x93, 0xb3, + 0xd3, 0xca, 0xef, 0x01, 0x21, 0x7e, 0x81, 0x04, 0xc7, 0x70, 0x78, 0x72, 0xe0, 0x0e, 0x8b, 0x41, 0x81, 0x2d, 0x91, + 0xbd, 0xa6, 0x48, 0x04, 0x4e, 0x29, 0xb6, 0xaf, 0x08, 0xe3, 0x9b, 0x3f, 0x98, 0xe1, 0x6c, 0x26, 0x07, 0xf2, 0xb5, + 0x8a, 0xc3, 0xcb, 0x80, 0x96, 0x6f, 0xe9, 0x70, 0x45, 0x5f, 0xaa, 0x7e, 0x22, 0xfb, 0xa9, 0xf6, 0x30, 0x82, 0x37, + 0xcc, 0x19, 0x8e, 0x7b, 0x25, 0x20, 0x70, 0x06, 0xb1, 0xc7, 0x54, 0x89, 0xe3, 0x91, 0x72, 0xfa, 0x89, 0x06, 0xce, + 0xe5, 0xd1, 0x60, 0x40, 0x68, 0xae, 0x8c, 0xed, 0x00, 0x88, 0x35, 0x99, 0x7c, 0x60, 0xb2, 0x09, 0x34, 0x34, 0xc9, + 0x5d, 0x16, 0x1b, 0x95, 0xa7, 0x53, 0x1d, 0xe3, 0x81, 0x2b, 0xb6, 0x5f, 0x61, 0x83, 0xc2, 0xc6, 0xe3, 0xeb, 0x0e, + 0xf8, 0x5d, 0xf4, 0x53, 0x42, 0xf3, 0xca, 0x57, 0x84, 0xd1, 0x4d, 0xdf, 0xbd, 0x0f, 0x25, 0x33, 0x26, 0x1e, 0xd1, + 0xe4, 0x1c, 0x4b, 0x2f, 0x84, 0x27, 0x71, 0xe5, 0xa0, 0x65, 0x09, 0x51, 0xaa, 0x87, 0x4d, 0x4e, 0x62, 0xb2, 0xeb, + 0xac, 0xc9, 0x75, 0x8b, 0x93, 0x41, 0xe4, 0x99, 0xe6, 0xe7, 0xb0, 0xf0, 0x12, 0xd1, 0x42, 0x7a, 0x72, 0x00, 0xf3, + 0x83, 0x28, 0x2c, 0x05, 0xc6, 0xc9, 0xd3, 0x21, 0xd4, 0x8b, 0x1b, 0x93, 0x29, 0xd6, 0xd9, 0x54, 0xf0, 0x7c, 0x28, + 0x58, 0x4a, 0xd9, 0xfd, 0xa4, 0x2a, 0x55, 0x5e, 0xc6, 0xae, 0x67, 0x02, 0x77, 0x67, 0x0f, 0xfa, 0x61, 0x8d, 0xa9, + 0x83, 0xd2, 0x7e, 0xc2, 0x44, 0x90, 0x83, 0xf3, 0xa4, 0x21, 0x0e, 0x42, 0x53, 0x15, 0xe2, 0x67, 0xb7, 0x54, 0xc8, + 0xf7, 0xf1, 0xb6, 0x5a, 0x39, 0xe7, 0x94, 0x55, 0x5b, 0xb9, 0x9a, 0xfa, 0x18, 0x77, 0x7c, 0xa5, 0x36, 0x96, 0x42, + 0xbd, 0xf3, 0x64, 0x00, 0x55, 0x85, 0x2e, 0xde, 0x5d, 0xad, 0xa8, 0xb2, 0xde, 0x3f, 0x39, 0x20, 0xb1, 0x74, 0x48, + 0x3b, 0x6c, 0x78, 0x02, 0xa6, 0xdc, 0xb4, 0xe8, 0xee, 0x6a, 0xc5, 0x97, 0x94, 0x7e, 0xd1, 0x9b, 0x83, 0x45, 0xb2, + 0xf4, 0x87, 0xff, 0x07, 0x52, 0xaf, 0x09, 0x6c, 0x30, 0x6a, 0x03, 0x00}; } // namespace web_server } // namespace esphome diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 4caac025aa..7ae30522f4 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -282,8 +282,10 @@ void WebServer::loop() { this->events_.loop(); } void WebServer::dump_config() { - ESP_LOGCONFIG(TAG, "Web Server:"); - ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port()); + ESP_LOGCONFIG(TAG, + "Web Server:\n" + " Address: %s:%u", + network::get_use_address().c_str(), this->base_->get_port()); } float WebServer::get_setup_priority() const { return setup_priority::WIFI - 1.0f; } @@ -553,7 +555,7 @@ std::string WebServer::button_json(button::Button *obj, JsonDetail start_config) #endif #ifdef USE_BINARY_SENSOR -void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) { +void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) { if (this->events_.empty()) return; this->events_.deferrable_send_state(obj, "state", binary_sensor_state_json_generator); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index e4f044c50b..f4d6ad8e86 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -269,7 +269,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { #endif #ifdef USE_BINARY_SENSOR - void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override; + void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override; /// Handle a binary sensor request under '/binary_sensor/'. void handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match); diff --git a/esphome/components/web_server_base/web_server_base.cpp b/esphome/components/web_server_base/web_server_base.cpp index 7c09022f27..2835585387 100644 --- a/esphome/components/web_server_base/web_server_base.cpp +++ b/esphome/components/web_server_base/web_server_base.cpp @@ -1,8 +1,8 @@ #include "web_server_base.h" #ifdef USE_NETWORK -#include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ARDUINO #include diff --git a/esphome/components/web_server_idf/utils.cpp b/esphome/components/web_server_idf/utils.cpp index 6299937ce1..349acce50d 100644 --- a/esphome/components/web_server_idf/utils.cpp +++ b/esphome/components/web_server_idf/utils.cpp @@ -1,7 +1,7 @@ #ifdef USE_ESP_IDF #include -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "http_parser.h" #include "utils.h" diff --git a/esphome/components/web_server_idf/web_server_idf.cpp b/esphome/components/web_server_idf/web_server_idf.cpp index 428bd262e8..6bfc49c675 100644 --- a/esphome/components/web_server_idf/web_server_idf.cpp +++ b/esphome/components/web_server_idf/web_server_idf.cpp @@ -2,8 +2,8 @@ #include -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esp_tls_crypto.h" diff --git a/esphome/components/weikai/__init__.py b/esphome/components/weikai/__init__.py index 4c8f7e700d..796423438e 100644 --- a/esphome/components/weikai/__init__.py +++ b/esphome/components/weikai/__init__.py @@ -16,6 +16,7 @@ CODEOWNERS = ["@DrCoolZic"] AUTO_LOAD = ["uart"] MULTI_CONF = True +CONF_DATA_BITS = "data_bits" CONF_STOP_BITS = "stop_bits" CONF_PARITY = "parity" CONF_CRYSTAL = "crystal" @@ -60,6 +61,7 @@ WKBASE_SCHEMA = cv.Schema( cv.Required(CONF_ID): cv.declare_id(WeikaiChannel), cv.Optional(CONF_CHANNEL, default=0): cv.int_range(min=0, max=3), cv.Required(CONF_BAUD_RATE): cv.int_range(min=1), + cv.Optional(CONF_DATA_BITS, default=8): cv.one_of(8, int=True), cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True), cv.Optional(CONF_PARITY, default="NONE"): cv.enum( uart.UART_PARITY_OPTIONS, upper=True diff --git a/esphome/components/weikai/weikai.cpp b/esphome/components/weikai/weikai.cpp index 19aa09e20d..2211fc77d5 100644 --- a/esphome/components/weikai/weikai.cpp +++ b/esphome/components/weikai/weikai.cpp @@ -112,7 +112,7 @@ void WeikaiComponent::loop() { transferred += child->xfer_fifo_to_buffer_(); } if (transferred > 0) { - ESP_LOGV(TAG, "we transferred %d bytes from fifo to buffer...", transferred); + ESP_LOGV(TAG, "transferred %d bytes from fifo to buffer", transferred); } #ifdef TEST_COMPONENT @@ -121,8 +121,8 @@ void WeikaiComponent::loop() { uint32_t time = 0; if (test_mode_ == 1) { // test component in loopback - ESP_LOGI(TAG, "Component loop %" PRIu32 " for %s : %" PRIu32 " ms since last call ...", loop_count++, - this->get_name(), millis() - loop_time); + ESP_LOGI(TAG, "Component loop %" PRIu32 " for %s : %" PRIu32 " ms since last call", loop_count++, this->get_name(), + millis() - loop_time); loop_time = millis(); char message[64]; elapsed_ms(time); // set time to now @@ -134,14 +134,14 @@ void WeikaiComponent::loop() { uint32_t const start_time = millis(); while (children_[i]->tx_fifo_is_not_empty_()) { // wait until buffer empty if (millis() - start_time > 1500) { - ESP_LOGE(TAG, "timeout while flushing - %d bytes left in buffer...", children_[i]->tx_in_fifo_()); + ESP_LOGE(TAG, "timeout while flushing - %d bytes left in buffer", children_[i]->tx_in_fifo_()); break; } yield(); // reschedule our thread to avoid blocking } bool status = children_[i]->uart_receive_test_(message); - ESP_LOGI(TAG, "Test %s => send/received %u bytes %s - execution time %" PRIu32 " ms...", message, - RING_BUFFER_SIZE, status ? "correctly" : "with error", elapsed_ms(time)); + ESP_LOGI(TAG, "Test %s => send/received %u bytes %s - execution time %" PRIu32 " ms", message, RING_BUFFER_SIZE, + status ? "correctly" : "with error", elapsed_ms(time)); } } @@ -255,10 +255,10 @@ std::string WeikaiGPIOPin::dump_summary() const { // The WeikaiChannel methods /////////////////////////////////////////////////////////////////////////////// void WeikaiChannel::setup_channel() { - ESP_LOGCONFIG(TAG, " Setting up UART %s:%s ...", this->parent_->get_name(), this->get_channel_name()); + ESP_LOGCONFIG(TAG, " Setting up UART %s:%s", this->parent_->get_name(), this->get_channel_name()); // we enable transmit and receive on this channel if (this->check_channel_down()) { - ESP_LOGCONFIG(TAG, " Error channel %s not working...", this->get_channel_name()); + ESP_LOGCONFIG(TAG, " Error channel %s not working", this->get_channel_name()); } this->reset_fifo_(); this->receive_buffer_.clear(); @@ -267,11 +267,13 @@ void WeikaiChannel::setup_channel() { } void WeikaiChannel::dump_channel() { - ESP_LOGCONFIG(TAG, " UART %s ...", this->get_channel_name()); - ESP_LOGCONFIG(TAG, " Baud rate: %" PRIu32 " Bd", this->baud_rate_); - ESP_LOGCONFIG(TAG, " Data bits: %u", this->data_bits_); - ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_); - ESP_LOGCONFIG(TAG, " Parity: %s", p2s(this->parity_)); + ESP_LOGCONFIG(TAG, + " UART %s\n" + " Baud rate: %" PRIu32 " Bd\n" + " Data bits: %u\n" + " Stop bits: %u\n" + " Parity: %s", + this->get_channel_name(), this->baud_rate_, this->data_bits_, this->stop_bits_, p2s(this->parity_)); } void WeikaiChannel::reset_fifo_() { @@ -407,7 +409,7 @@ bool WeikaiChannel::read_array(uint8_t *buffer, size_t length) { bool status = true; auto available = this->receive_buffer_.count(); if (length > available) { - ESP_LOGW(TAG, "read_array: buffer underflow requested %d bytes only %d bytes available...", length, available); + ESP_LOGW(TAG, "read_array: buffer underflow requested %d bytes only %d bytes available", length, available); length = available; status = false; } @@ -422,7 +424,7 @@ bool WeikaiChannel::read_array(uint8_t *buffer, size_t length) { void WeikaiChannel::write_array(const uint8_t *buffer, size_t length) { if (length > XFER_MAX_SIZE) { - ESP_LOGE(TAG, "Write_array: invalid call - requested %d bytes but max size %d ...", length, XFER_MAX_SIZE); + ESP_LOGE(TAG, "Write_array: invalid call - requested %d bytes but max size %d", length, XFER_MAX_SIZE); length = XFER_MAX_SIZE; } this->reg(0).write_fifo(const_cast(buffer), length); @@ -432,7 +434,7 @@ void WeikaiChannel::flush() { uint32_t const start_time = millis(); while (this->tx_fifo_is_not_empty_()) { // wait until buffer empty if (millis() - start_time > 200) { - ESP_LOGW(TAG, "WARNING flush timeout - still %d bytes not sent after 200 ms...", this->tx_in_fifo_()); + ESP_LOGW(TAG, "WARNING flush timeout - still %d bytes not sent after 200 ms", this->tx_in_fifo_()); return; } yield(); // reschedule our thread to avoid blocking @@ -509,7 +511,7 @@ void WeikaiChannel::uart_send_test_(char *message) { this->flush(); to_send -= XFER_MAX_SIZE; } - ESP_LOGV(TAG, "%s => sent %d bytes - exec time %d µs ...", message, RING_BUFFER_SIZE, micros() - start_exec); + ESP_LOGV(TAG, "%s => sent %d bytes - exec time %d µs", message, RING_BUFFER_SIZE, micros() - start_exec); } /// @brief test read_array method @@ -526,7 +528,7 @@ bool WeikaiChannel::uart_receive_test_(char *message) { while (XFER_MAX_SIZE > this->available()) { this->xfer_fifo_to_buffer_(); if (millis() - start_time > 1500) { - ESP_LOGE(TAG, "uart_receive_test_() timeout: only %d bytes received...", this->available()); + ESP_LOGE(TAG, "uart_receive_test_() timeout: only %d bytes received", this->available()); break; } yield(); // reschedule our thread to avoid blocking @@ -538,20 +540,20 @@ bool WeikaiChannel::uart_receive_test_(char *message) { uint8_t peek_value = 0; this->peek_byte(&peek_value); if (peek_value != 0) { - ESP_LOGE(TAG, "Peek first byte value error..."); + ESP_LOGE(TAG, "Peek first byte value error"); status = false; } for (size_t i = 0; i < RING_BUFFER_SIZE; i++) { if (buffer[i] != i % XFER_MAX_SIZE) { - ESP_LOGE(TAG, "Read buffer contains error...b=%x i=%x", buffer[i], i % XFER_MAX_SIZE); + ESP_LOGE(TAG, "Read buffer contains error b=%x i=%x", buffer[i], i % XFER_MAX_SIZE); print_buffer(buffer); status = false; break; } } - ESP_LOGV(TAG, "%s => received %d bytes status %s - exec time %d µs ...", message, received, status ? "OK" : "ERROR", + ESP_LOGV(TAG, "%s => received %d bytes status %s - exec time %d µs", message, received, status ? "OK" : "ERROR", micros() - start_exec); return status; } diff --git a/esphome/components/weikai_i2c/weikai_i2c.cpp b/esphome/components/weikai_i2c/weikai_i2c.cpp index 3b353eb662..32e7ec4f23 100644 --- a/esphome/components/weikai_i2c/weikai_i2c.cpp +++ b/esphome/components/weikai_i2c/weikai_i2c.cpp @@ -96,7 +96,7 @@ void WeikaiRegisterI2C::read_fifo(uint8_t *data, size_t length) const { #endif } else { // error this->comp_->status_set_warning(); - ESP_LOGE(TAG, "WeikaiRegisterI2C::read_fifo() @%02X reg=N/A ch=%d I2C_code:%d len=%d buf=%02X...", address, + ESP_LOGE(TAG, "WeikaiRegisterI2C::read_fifo() @%02X reg=N/A ch=%d I2C_code:%d len=%d buf=%02X", address, this->channel_, (int) error, length, data[0]); } } @@ -131,8 +131,8 @@ void WeikaiRegisterI2C::write_fifo(uint8_t *data, size_t length) { #endif } else { // error this->comp_->status_set_warning(); - ESP_LOGE(TAG, "WK2168Reg::write_fifo() @%02X reg=N/A, ch=%d I2C_code:%d len=%d, buf=%02X...", address, - this->channel_, (int) error, length, data[0]); + ESP_LOGE(TAG, "WK2168Reg::write_fifo() @%02X reg=N/A, ch=%d I2C_code:%d len=%d, buf=%02X", address, this->channel_, + (int) error, length, data[0]); } } @@ -160,11 +160,16 @@ void WeikaiComponentI2C::setup() { } void WeikaiComponentI2C::dump_config() { - ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size()); - ESP_LOGCONFIG(TAG, " Crystal: %" PRIu32, this->crystal_); - if (test_mode_) - ESP_LOGCONFIG(TAG, " Test mode: %d", test_mode_); - ESP_LOGCONFIG(TAG, " Transfer buffer size: %d", XFER_MAX_SIZE); + ESP_LOGCONFIG(TAG, + "Initialization of %s with %d UARTs completed\n" + " Crystal: %" PRIu32, + this->get_name(), this->children_.size(), this->crystal_); + if (test_mode_) { + ESP_LOGCONFIG(TAG, + " Test mode: %d\n" + " Transfer buffer size: %d", + test_mode_, XFER_MAX_SIZE); + } this->address_ = this->base_address_; // we restore the base_address before display (less confusing) LOG_I2C_DEVICE(this); diff --git a/esphome/components/weikai_spi/weikai_spi.cpp b/esphome/components/weikai_spi/weikai_spi.cpp index a81f69a4aa..a43e0e6599 100644 --- a/esphome/components/weikai_spi/weikai_spi.cpp +++ b/esphome/components/weikai_spi/weikai_spi.cpp @@ -156,7 +156,7 @@ void WeikaiRegisterSPI::write_fifo(uint8_t *data, size_t length) { /////////////////////////////////////////////////////////////////////////////// void WeikaiComponentSPI::setup() { using namespace weikai; - ESP_LOGCONFIG(TAG, "Running setup for '%s' with %d UARTs...", this->get_name(), this->children_.size()); + ESP_LOGCONFIG(TAG, "Running setup for '%s' with %d UARTs", this->get_name(), this->children_.size()); this->spi_setup(); // enable all channels this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN; @@ -173,11 +173,16 @@ void WeikaiComponentSPI::setup() { } void WeikaiComponentSPI::dump_config() { - ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size()); - ESP_LOGCONFIG(TAG, " Crystal: %" PRIu32 "", this->crystal_); - if (test_mode_) - ESP_LOGCONFIG(TAG, " Test mode: %d", test_mode_); - ESP_LOGCONFIG(TAG, " Transfer buffer size: %d", XFER_MAX_SIZE); + ESP_LOGCONFIG(TAG, + "Initialization of %s with %d UARTs completed\n" + " Crystal: %" PRIu32, + this->get_name(), this->children_.size(), this->crystal_); + if (test_mode_) { + ESP_LOGCONFIG(TAG, + " Test mode: %d\n" + " Transfer buffer size: %d", + test_mode_, XFER_MAX_SIZE); + } LOG_PIN(" CS Pin: ", this->cs_); for (auto *child : this->children_) { diff --git a/esphome/components/wiegand/wiegand.cpp b/esphome/components/wiegand/wiegand.cpp index 10c77a8aa2..5a2bb8deee 100644 --- a/esphome/components/wiegand/wiegand.cpp +++ b/esphome/components/wiegand/wiegand.cpp @@ -1,6 +1,6 @@ #include "wiegand.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace wiegand { diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index baa273d39f..f2f9d712fc 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -58,8 +58,10 @@ void WiFiComponent::setup() { } void WiFiComponent::start() { - ESP_LOGCONFIG(TAG, "Starting"); - ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str()); + ESP_LOGCONFIG(TAG, + "Starting\n" + " Local MAC: %s", + get_mac_address_pretty().c_str()); this->last_connected_ = millis(); uint32_t hash = this->has_sta() ? fnv1_hash(App.get_compilation_time()) : 88491487UL; @@ -260,15 +262,19 @@ void WiFiComponent::setup_ap_config_() { this->ap_.set_ssid(name); } - ESP_LOGCONFIG(TAG, "Setting up AP..."); + ESP_LOGCONFIG(TAG, "Setting up AP"); - ESP_LOGCONFIG(TAG, " AP SSID: '%s'", this->ap_.get_ssid().c_str()); - ESP_LOGCONFIG(TAG, " AP Password: '%s'", this->ap_.get_password().c_str()); + ESP_LOGCONFIG(TAG, + " AP SSID: '%s'\n" + " AP Password: '%s'", + this->ap_.get_ssid().c_str(), this->ap_.get_password().c_str()); if (this->ap_.get_manual_ip().has_value()) { auto manual = *this->ap_.get_manual_ip(); - ESP_LOGCONFIG(TAG, " AP Static IP: '%s'", manual.static_ip.str().c_str()); - ESP_LOGCONFIG(TAG, " AP Gateway: '%s'", manual.gateway.str().c_str()); - ESP_LOGCONFIG(TAG, " AP Subnet: '%s'", manual.subnet.str().c_str()); + ESP_LOGCONFIG(TAG, + " AP Static IP: '%s'\n" + " AP Gateway: '%s'\n" + " AP Subnet: '%s'", + manual.static_ip.str().c_str(), manual.gateway.str().c_str(), manual.subnet.str().c_str()); } this->ap_setup_ = this->wifi_start_ap_(this->ap_); @@ -436,22 +442,29 @@ void WiFiComponent::print_connect_params_() { ESP_LOGCONFIG(TAG, " IP Address: %s", ip.str().c_str()); } } - ESP_LOGCONFIG(TAG, " BSSID: " LOG_SECRET("%02X:%02X:%02X:%02X:%02X:%02X"), bssid[0], bssid[1], bssid[2], bssid[3], - bssid[4], bssid[5]); - ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str()); int8_t rssi = wifi_rssi(); - ESP_LOGCONFIG(TAG, " Signal strength: %d dB %s", rssi, LOG_STR_ARG(get_signal_bars(rssi))); + ESP_LOGCONFIG(TAG, + " BSSID: " LOG_SECRET("%02X:%02X:%02X:%02X:%02X:%02X") "\n" + " Hostname: '%s'\n" + " Signal strength: %d dB %s", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], App.get_name().c_str(), rssi, + LOG_STR_ARG(get_signal_bars(rssi))); if (this->selected_ap_.get_bssid().has_value()) { ESP_LOGV(TAG, " Priority: %.1f", this->get_sta_priority(*this->selected_ap_.get_bssid())); } - ESP_LOGCONFIG(TAG, " Channel: %" PRId32, get_wifi_channel()); - ESP_LOGCONFIG(TAG, " Subnet: %s", wifi_subnet_mask_().str().c_str()); - ESP_LOGCONFIG(TAG, " Gateway: %s", wifi_gateway_ip_().str().c_str()); - ESP_LOGCONFIG(TAG, " DNS1: %s", wifi_dns_ip_(0).str().c_str()); - ESP_LOGCONFIG(TAG, " DNS2: %s", wifi_dns_ip_(1).str().c_str()); + ESP_LOGCONFIG(TAG, + " Channel: %" PRId32 "\n" + " Subnet: %s\n" + " Gateway: %s\n" + " DNS1: %s\n" + " DNS2: %s", + get_wifi_channel(), wifi_subnet_mask_().str().c_str(), wifi_gateway_ip_().str().c_str(), + wifi_dns_ip_(0).str().c_str(), wifi_dns_ip_(1).str().c_str()); #ifdef USE_WIFI_11KV_SUPPORT - ESP_LOGCONFIG(TAG, " BTM: %s", this->btm_ ? "enabled" : "disabled"); - ESP_LOGCONFIG(TAG, " RRM: %s", this->rrm_ ? "enabled" : "disabled"); + ESP_LOGCONFIG(TAG, + " BTM: %s\n" + " RRM: %s", + this->btm_ ? "enabled" : "disabled", this->rrm_ ? "enabled" : "disabled"); #endif } @@ -479,7 +492,7 @@ bool WiFiComponent::is_disabled() { return this->state_ == WIFI_COMPONENT_STATE_ void WiFiComponent::start_scanning() { this->action_started_ = millis(); - ESP_LOGD(TAG, "Starting scan..."); + ESP_LOGD(TAG, "Starting scan"); this->wifi_scan_start_(this->passive_scan_); this->state_ = WIFI_COMPONENT_STATE_STA_SCANNING; } @@ -623,7 +636,7 @@ void WiFiComponent::check_connecting_finished() { captive_portal::global_captive_portal->end(); } #endif - ESP_LOGD(TAG, "Disabling AP..."); + ESP_LOGD(TAG, "Disabling AP"); this->wifi_mode_({}, false); } #ifdef USE_IMPROV @@ -687,14 +700,14 @@ void WiFiComponent::retry_connect() { (this->num_retried_ > 3 || this->error_from_callback_)) { if (this->num_retried_ > 5) { // If retry failed for more than 5 times, let's restart STA - ESP_LOGW(TAG, "Restarting WiFi adapter..."); + ESP_LOGW(TAG, "Restarting WiFi adapter"); this->wifi_mode_(false, {}); delay(100); // NOLINT this->num_retried_ = 0; this->retry_hidden_ = false; } else { // Try hidden networks after 3 failed retries - ESP_LOGD(TAG, "Retrying with hidden networks..."); + ESP_LOGD(TAG, "Retrying with hidden networks"); this->retry_hidden_ = true; this->num_retried_++; } diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 23fc03f471..2dc3acda77 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -590,7 +590,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ // Mitigate CVE-2020-12638 // https://lbsfilm.at/blog/wpa2-authenticationmode-downgrade-in-espressif-microprocessors if (it.old_mode != WIFI_AUTH_OPEN && it.new_mode == WIFI_AUTH_OPEN) { - ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting..."); + ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting"); // we can't call retry_connect() from this context, so disconnect immediately // and notify main thread with error_from_callback_ err_t err = esp_wifi_disconnect(); diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 8e1c2e70d8..3e121098e7 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -32,11 +32,11 @@ extern "C" { #endif } +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" #include "esphome/core/util.h" -#include "esphome/core/application.h" namespace esphome { namespace wifi { @@ -525,7 +525,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { // Mitigate CVE-2020-12638 // https://lbsfilm.at/blog/wpa2-authenticationmode-downgrade-in-espressif-microprocessors if (it.old_mode != AUTH_OPEN && it.new_mode == AUTH_OPEN) { - ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting..."); + ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting"); // we can't call retry_connect() from this context, so disconnect immediately // and notify main thread with error_from_callback_ wifi_station_disconnect(); diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index 9f50b62924..eb88ed81ad 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -9,10 +9,10 @@ #include "lwip/err.h" #include "lwip/dns.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" -#include "esphome/core/application.h" #include "esphome/core/util.h" namespace esphome { @@ -315,7 +315,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ // Mitigate CVE-2020-12638 // https://lbsfilm.at/blog/wpa2-authenticationmode-downgrade-in-espressif-microprocessors if (it.old_mode != WIFI_AUTH_OPEN && it.new_mode == WIFI_AUTH_OPEN) { - ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting..."); + ESP_LOGW(TAG, "Potential Authmode downgrade detected, disconnecting"); // we can't call retry_connect() from this context, so disconnect immediately // and notify main thread with error_from_callback_ WiFi.disconnect(); diff --git a/esphome/components/wireguard/wireguard.cpp b/esphome/components/wireguard/wireguard.cpp index 431bf52227..1f61e2dda3 100644 --- a/esphome/components/wireguard/wireguard.cpp +++ b/esphome/components/wireguard/wireguard.cpp @@ -21,13 +21,13 @@ static const char *const TAG = "wireguard"; * Cannot use `static const char*` for LOGMSG_PEER_STATUS on esp8266 platform * because log messages in `Wireguard::update()` method fail. */ -#define LOGMSG_PEER_STATUS "WireGuard remote peer is %s (latest handshake %s)" +#define LOGMSG_PEER_STATUS "Remote peer is %s (latest handshake %s)" static const char *const LOGMSG_ONLINE = "online"; static const char *const LOGMSG_OFFLINE = "offline"; void Wireguard::setup() { - ESP_LOGD(TAG, "initializing WireGuard..."); + ESP_LOGCONFIG(TAG, "Running setup"); this->wg_config_.address = this->address_.c_str(); this->wg_config_.private_key = this->private_key_.c_str(); @@ -45,7 +45,7 @@ void Wireguard::setup() { this->wg_initialized_ = esp_wireguard_init(&(this->wg_config_), &(this->wg_ctx_)); if (this->wg_initialized_ == ESP_OK) { - ESP_LOGI(TAG, "WireGuard initialized"); + ESP_LOGI(TAG, "Initialized"); this->wg_peer_offline_time_ = millis(); this->srctime_->add_on_time_sync_callback(std::bind(&Wireguard::start_connection_, this)); this->defer(std::bind(&Wireguard::start_connection_, this)); // defer to avoid blocking setup @@ -56,7 +56,7 @@ void Wireguard::setup() { } #endif } else { - ESP_LOGE(TAG, "cannot initialize WireGuard, error code %d", this->wg_initialized_); + ESP_LOGE(TAG, "Cannot initialize: error code %d", this->wg_initialized_); this->mark_failed(); } } @@ -67,7 +67,7 @@ void Wireguard::loop() { } if ((this->wg_initialized_ == ESP_OK) && (this->wg_connected_ == ESP_OK) && (!network::is_connected())) { - ESP_LOGV(TAG, "local network connection has been lost, stopping WireGuard..."); + ESP_LOGV(TAG, "Local network connection has been lost, stopping"); this->stop_connection_(); } } @@ -109,7 +109,7 @@ void Wireguard::update() { // check reboot timeout every time the peer is down if (this->enabled_ && this->reboot_timeout_ > 0) { if (millis() - this->wg_peer_offline_time_ > this->reboot_timeout_) { - ESP_LOGE(TAG, "WireGuard remote peer is unreachable, rebooting..."); + ESP_LOGE(TAG, "Remote peer is unreachable; rebooting"); App.reboot(); } } @@ -201,14 +201,14 @@ void Wireguard::disable_auto_proceed() { this->proceed_allowed_ = false; } void Wireguard::enable() { this->enabled_ = true; - ESP_LOGI(TAG, "WireGuard enabled"); + ESP_LOGI(TAG, "Enabled"); this->publish_enabled_state(); } void Wireguard::disable() { this->enabled_ = false; this->defer(std::bind(&Wireguard::stop_connection_, this)); // defer to avoid blocking running loop - ESP_LOGI(TAG, "WireGuard disabled"); + ESP_LOGI(TAG, "Disabled"); this->publish_enabled_state(); } @@ -224,44 +224,44 @@ bool Wireguard::is_enabled() { return this->enabled_; } void Wireguard::start_connection_() { if (!this->enabled_) { - ESP_LOGV(TAG, "WireGuard is disabled, cannot start connection"); + ESP_LOGV(TAG, "Disabled, cannot start connection"); return; } if (this->wg_initialized_ != ESP_OK) { - ESP_LOGE(TAG, "cannot start WireGuard, initialization in error with code %d", this->wg_initialized_); + ESP_LOGE(TAG, "Cannot start: error code %d", this->wg_initialized_); return; } if (!network::is_connected()) { - ESP_LOGD(TAG, "WireGuard is waiting for local network connection to be available"); + ESP_LOGD(TAG, "Waiting for local network connection to be available"); return; } if (!this->srctime_->now().is_valid()) { - ESP_LOGD(TAG, "WireGuard is waiting for system time to be synchronized"); + ESP_LOGD(TAG, "Waiting for system time to be synchronized"); return; } if (this->wg_connected_ == ESP_OK) { - ESP_LOGV(TAG, "WireGuard connection already started"); + ESP_LOGV(TAG, "Connection already started"); return; } - ESP_LOGD(TAG, "starting WireGuard connection..."); + ESP_LOGD(TAG, "Starting connection"); this->wg_connected_ = esp_wireguard_connect(&(this->wg_ctx_)); if (this->wg_connected_ == ESP_OK) { - ESP_LOGI(TAG, "WireGuard connection started"); + ESP_LOGI(TAG, "Connection started"); } else if (this->wg_connected_ == ESP_ERR_RETRY) { - ESP_LOGD(TAG, "WireGuard is waiting for endpoint IP address to be available"); + ESP_LOGD(TAG, "Waiting for endpoint IP address to be available"); return; } else { - ESP_LOGW(TAG, "cannot start WireGuard connection, error code %d", this->wg_connected_); + ESP_LOGW(TAG, "Cannot start connection, error code %d", this->wg_connected_); return; } - ESP_LOGD(TAG, "configuring WireGuard allowed IPs list..."); + ESP_LOGD(TAG, "Configuring allowed IPs list"); bool allowed_ips_ok = true; for (std::tuple ip : this->allowed_ips_) { allowed_ips_ok &= @@ -269,9 +269,9 @@ void Wireguard::start_connection_() { } if (allowed_ips_ok) { - ESP_LOGD(TAG, "allowed IPs list configured correctly"); + ESP_LOGD(TAG, "Allowed IPs list configured correctly"); } else { - ESP_LOGE(TAG, "cannot configure WireGuard allowed IPs list, aborting..."); + ESP_LOGE(TAG, "Cannot configure allowed IPs list, aborting"); this->stop_connection_(); this->mark_failed(); } @@ -279,7 +279,7 @@ void Wireguard::start_connection_() { void Wireguard::stop_connection_() { if (this->wg_initialized_ == ESP_OK && this->wg_connected_ == ESP_OK) { - ESP_LOGD(TAG, "stopping WireGuard connection..."); + ESP_LOGD(TAG, "Stopping connection"); esp_wireguard_disconnect(&(this->wg_ctx_)); this->wg_connected_ = ESP_FAIL; } diff --git a/esphome/components/wled/wled_light_effect.cpp b/esphome/components/wled/wled_light_effect.cpp index 84842dff39..25577ccc11 100644 --- a/esphome/components/wled/wled_light_effect.cpp +++ b/esphome/components/wled/wled_light_effect.cpp @@ -1,8 +1,8 @@ #ifdef USE_ARDUINO #include "wled_light_effect.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ESP32 #include diff --git a/esphome/components/x9c/x9c.cpp b/esphome/components/x9c/x9c.cpp index caad16edf9..ccd0c60b50 100644 --- a/esphome/components/x9c/x9c.cpp +++ b/esphome/components/x9c/x9c.cpp @@ -68,8 +68,10 @@ void X9cOutput::dump_config() { LOG_PIN(" Chip Select Pin: ", this->cs_pin_); LOG_PIN(" Increment Pin: ", this->inc_pin_); LOG_PIN(" Up/Down Pin: ", this->ud_pin_); - ESP_LOGCONFIG(TAG, " Initial Value: %f", this->initial_value_); - ESP_LOGCONFIG(TAG, " Step Delay: %d", this->step_delay_); + ESP_LOGCONFIG(TAG, + " Initial Value: %f\n" + " Step Delay: %d", + this->initial_value_, this->step_delay_); LOG_FLOAT_OUTPUT(this); } diff --git a/esphome/components/xgzp68xx/xgzp68xx.cpp b/esphome/components/xgzp68xx/xgzp68xx.cpp index ad6217845d..52933ebdef 100644 --- a/esphome/components/xgzp68xx/xgzp68xx.cpp +++ b/esphome/components/xgzp68xx/xgzp68xx.cpp @@ -1,7 +1,7 @@ #include "xgzp68xx.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/components/i2c/i2c.h" #include @@ -69,22 +69,24 @@ void XGZP68XXComponent::update() { } void XGZP68XXComponent::setup() { - ESP_LOGD(TAG, "Setting up XGZP68xx..."); + ESP_LOGCONFIG(TAG, "Running setup"); uint8_t config; // Display some sample bits to confirm we are talking to the sensor this->read_register(SYSCONFIG_ADDRESS, &config, 1); - ESP_LOGCONFIG(TAG, "Gain value is %d", (config >> 3) & 0b111); - ESP_LOGCONFIG(TAG, "XGZP68xx started!"); + ESP_LOGCONFIG(TAG, + "Gain value is %d\n" + "XGZP68xx started!", + (config >> 3) & 0b111); } void XGZP68XXComponent::dump_config() { - ESP_LOGCONFIG(TAG, "XGZP68xx"); + ESP_LOGCONFIG(TAG, "XGZP68xx:"); LOG_SENSOR(" ", "Temperature: ", this->temperature_sensor_); LOG_SENSOR(" ", "Pressure: ", this->pressure_sensor_); LOG_I2C_DEVICE(this); if (this->is_failed()) { - ESP_LOGE(TAG, " Connection with XGZP68xx failed!"); + ESP_LOGE(TAG, " Connection failed"); } LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/xiaomi_cgd1/xiaomi_cgd1.cpp b/esphome/components/xiaomi_cgd1/xiaomi_cgd1.cpp index baf9cb8075..4642768f90 100644 --- a/esphome/components/xiaomi_cgd1/xiaomi_cgd1.cpp +++ b/esphome/components/xiaomi_cgd1/xiaomi_cgd1.cpp @@ -9,8 +9,10 @@ namespace xiaomi_cgd1 { static const char *const TAG = "xiaomi_cgd1"; void XiaomiCGD1::dump_config() { - ESP_LOGCONFIG(TAG, "Xiaomi CGD1"); - ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + ESP_LOGCONFIG(TAG, + "Xiaomi CGD1\n" + " Bindkey: %s", + format_hex_pretty(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); diff --git a/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp b/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp index c74794f4f4..0dcbcbd05c 100644 --- a/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp +++ b/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp @@ -9,8 +9,10 @@ namespace xiaomi_cgdk2 { static const char *const TAG = "xiaomi_cgdk2"; void XiaomiCGDK2::dump_config() { - ESP_LOGCONFIG(TAG, "Xiaomi CGDK2"); - ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + ESP_LOGCONFIG(TAG, + "Xiaomi CGDK2\n" + " Bindkey: %s", + format_hex_pretty(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); diff --git a/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp b/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp index c20c7578d0..f9fffa3f20 100644 --- a/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp +++ b/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp @@ -9,8 +9,10 @@ namespace xiaomi_cgg1 { static const char *const TAG = "xiaomi_cgg1"; void XiaomiCGG1::dump_config() { - ESP_LOGCONFIG(TAG, "Xiaomi CGG1"); - ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + ESP_LOGCONFIG(TAG, + "Xiaomi CGG1\n" + " Bindkey: %s", + format_hex_pretty(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); diff --git a/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp index 45d4cceb52..2bc52b8085 100644 --- a/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp +++ b/esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.cpp @@ -1,6 +1,6 @@ #include "xiaomi_hhccjcy10.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #ifdef USE_ESP32 diff --git a/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp b/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp index cc122f2264..dff1228f64 100644 --- a/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp +++ b/esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp @@ -9,8 +9,10 @@ namespace xiaomi_lywsd02mmc { static const char *const TAG = "xiaomi_lywsd02mmc"; void XiaomiLYWSD02MMC::dump_config() { - ESP_LOGCONFIG(TAG, "Xiaomi LYWSD02MMC"); - ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + ESP_LOGCONFIG(TAG, + "Xiaomi LYWSD02MMC\n" + " Bindkey: %s", + format_hex_pretty(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); diff --git a/esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.cpp b/esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.cpp index d0319c9474..fb0165a21f 100644 --- a/esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.cpp +++ b/esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.cpp @@ -9,8 +9,10 @@ namespace xiaomi_lywsd03mmc { static const char *const TAG = "xiaomi_lywsd03mmc"; void XiaomiLYWSD03MMC::dump_config() { - ESP_LOGCONFIG(TAG, "Xiaomi LYWSD03MMC"); - ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + ESP_LOGCONFIG(TAG, + "Xiaomi LYWSD03MMC\n" + " Bindkey: %s", + format_hex_pretty(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); diff --git a/esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.cpp b/esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.cpp index 9ec2b10e12..90b654873b 100644 --- a/esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.cpp +++ b/esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.cpp @@ -9,8 +9,10 @@ namespace xiaomi_mhoc401 { static const char *const TAG = "xiaomi_mhoc401"; void XiaomiMHOC401::dump_config() { - ESP_LOGCONFIG(TAG, "Xiaomi MHOC401"); - ESP_LOGCONFIG(TAG, " Bindkey: %s", format_hex_pretty(this->bindkey_, 16).c_str()); + ESP_LOGCONFIG(TAG, + "Xiaomi MHOC401\n" + " Bindkey: %s", + format_hex_pretty(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); diff --git a/esphome/components/xpt2046/touchscreen/xpt2046.cpp b/esphome/components/xpt2046/touchscreen/xpt2046.cpp index aa11ed4b77..fa99e3afa7 100644 --- a/esphome/components/xpt2046/touchscreen/xpt2046.cpp +++ b/esphome/components/xpt2046/touchscreen/xpt2046.cpp @@ -1,6 +1,6 @@ #include "xpt2046.h" -#include "esphome/core/log.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include @@ -62,16 +62,17 @@ void XPT2046Component::dump_config() { ESP_LOGCONFIG(TAG, "XPT2046:"); LOG_PIN(" IRQ Pin: ", this->irq_pin_); - ESP_LOGCONFIG(TAG, " X min: %d", this->x_raw_min_); - ESP_LOGCONFIG(TAG, " X max: %d", this->x_raw_max_); - ESP_LOGCONFIG(TAG, " Y min: %d", this->y_raw_min_); - ESP_LOGCONFIG(TAG, " Y max: %d", this->y_raw_max_); - - ESP_LOGCONFIG(TAG, " Swap X/Y: %s", YESNO(this->swap_x_y_)); - ESP_LOGCONFIG(TAG, " Invert X: %s", YESNO(this->invert_x_)); - ESP_LOGCONFIG(TAG, " Invert Y: %s", YESNO(this->invert_y_)); - - ESP_LOGCONFIG(TAG, " threshold: %d", this->threshold_); + ESP_LOGCONFIG(TAG, + " X min: %d\n" + " X max: %d\n" + " Y min: %d\n" + " Y max: %d\n" + " Swap X/Y: %s\n" + " Invert X: %s\n" + " Invert Y: %s\n" + " threshold: %d", + this->x_raw_min_, this->x_raw_max_, this->y_raw_min_, this->y_raw_max_, YESNO(this->swap_x_y_), + YESNO(this->invert_x_), YESNO(this->invert_y_), this->threshold_); LOG_UPDATE_INTERVAL(this); } diff --git a/esphome/components/xpt2046/touchscreen/xpt2046.h b/esphome/components/xpt2046/touchscreen/xpt2046.h index a635c08f82..f691ae2c7b 100644 --- a/esphome/components/xpt2046/touchscreen/xpt2046.h +++ b/esphome/components/xpt2046/touchscreen/xpt2046.h @@ -1,9 +1,9 @@ #pragma once -#include "esphome/core/component.h" -#include "esphome/core/automation.h" #include "esphome/components/spi/spi.h" #include "esphome/components/touchscreen/touchscreen.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" diff --git a/esphome/config.py b/esphome/config.py index c6351cdabd..ca3686a0e6 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -389,6 +389,7 @@ class LoadValidationStep(ConfigValidationStep): result.add_str_error(f"Platform not found: '{p_domain}'", path) continue CORE.loaded_integrations.add(p_name) + CORE.loaded_platforms.add(f"{self.domain}/{p_name}") # Process AUTO_LOAD for load in platform.auto_load: diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 54056240ce..964f533215 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1667,6 +1667,26 @@ class OnlyWith(Optional): pass +class OnlyWithout(Optional): + """Set the default value only if the given component is NOT loaded.""" + + def __init__(self, key, component, default=None): + super().__init__(key) + self._component = component + self._default = vol.default_factory(default) + + @property + def default(self): + if self._component not in CORE.loaded_integrations: + return self._default + return vol.UNDEFINED + + @default.setter + def default(self, value): + # Ignore default set from vol.Optional + pass + + def _entity_base_validator(config): if CONF_NAME not in config and CONF_ID not in config: raise Invalid("At least one of 'id:' or 'name:' is required!") diff --git a/esphome/const.py b/esphome/const.py index 2ca79e70c2..c01f30c3ff 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2025.6.0-dev" +__version__ = "2025.7.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( @@ -976,7 +976,9 @@ CONF_WIND_DIRECTION_DEGREES = "wind_direction_degrees" CONF_WIND_SPEED = "wind_speed" CONF_WINDOW_SIZE = "window_size" CONF_WRITE_PIN = "write_pin" +CONF_X = "x" CONF_X_GRID = "x_grid" +CONF_Y = "y" CONF_Y_GRID = "y_grid" CONF_YEAR = "year" CONF_ZERO = "zero" diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index bf61307021..e95bd7edcc 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -1,3 +1,4 @@ +from collections import defaultdict import logging import math import os @@ -512,8 +513,13 @@ class EsphomeCore: self.platformio_options: dict[str, str | list[str]] = {} # A set of strings of names of loaded integrations, used to find namespace ID conflicts self.loaded_integrations = set() + # A set of strings for platform/integration combos + self.loaded_platforms: set[str] = set() # A set of component IDs to track what Component subclasses are declared self.component_ids = set() + # Dict to track platform entity counts for pre-allocation + # Key: platform name (e.g. "sensor", "binary_sensor"), Value: count + self.platform_counts: defaultdict[str, int] = defaultdict(int) # Whether ESPHome was started in verbose mode self.verbose = False # Whether ESPHome was started in quiet mode @@ -543,6 +549,7 @@ class EsphomeCore: self.platformio_options = {} self.loaded_integrations = set() self.component_ids = set() + self.platform_counts = defaultdict(int) PIN_SCHEMA_REGISTRY.reset() @property @@ -667,16 +674,17 @@ class EsphomeCore: def using_esp_idf(self): return self.target_framework == "esp-idf" - def add_job(self, func, *args, **kwargs): + def add_job(self, func, *args, **kwargs) -> None: self.event_loop.add_job(func, *args, **kwargs) - def flush_tasks(self): + def flush_tasks(self) -> None: try: self.event_loop.flush_tasks() except RuntimeError as e: raise EsphomeError(str(e)) from e - def add(self, expression): + def add(self, expression, prepend=False) -> "Statement": + """Add an expression or statement to the main setup() block.""" from esphome.cpp_generator import Expression, Statement, statement if isinstance(expression, Expression): @@ -686,11 +694,14 @@ class EsphomeCore: f"Add '{expression}' must be expression or statement, not {type(expression)}" ) - self.main_statements.append(expression) + if prepend: + self.main_statements.insert(0, expression) + else: + self.main_statements.append(expression) _LOGGER.debug("Adding: %s", expression) return expression - def add_global(self, expression, prepend=False): + def add_global(self, expression, prepend=False) -> "Statement": from esphome.cpp_generator import Expression, Statement, statement if isinstance(expression, Expression): @@ -820,6 +831,14 @@ class EsphomeCore: def has_id(self, id): return id in self.variables + def register_platform_component(self, platform_name: str, var) -> None: + """Register a component for a platform and track its count. + + :param platform_name: The name of the platform (e.g., 'sensor', 'binary_sensor') + :param var: The variable (component) being registered (currently unused but kept for future use) + """ + self.platform_counts[platform_name] += 1 + @property def cpp_main_section(self): from esphome.cpp_generator import statement diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index ad1ec33436..75a7052c63 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -45,8 +45,8 @@ void Application::register_component_(Component *comp) { this->components_.push_back(comp); } void Application::setup() { - ESP_LOGI(TAG, "Running through setup()..."); - ESP_LOGV(TAG, "Sorting components by setup priority..."); + ESP_LOGI(TAG, "Running through setup()"); + ESP_LOGV(TAG, "Sorting components by setup priority"); std::stable_sort(this->components_.begin(), this->components_.end(), [](const Component *a, const Component *b) { return a->get_actual_setup_priority() > b->get_actual_setup_priority(); }); @@ -126,63 +126,7 @@ void Application::loop() { next_schedule = std::max(next_schedule, delay_time / 2); delay_time = std::min(next_schedule, delay_time); -#ifdef USE_SOCKET_SELECT_SUPPORT - if (!this->socket_fds_.empty()) { - // Use select() with timeout when we have sockets to monitor - - // Update fd_set if socket list has changed - if (this->socket_fds_changed_) { - FD_ZERO(&this->base_read_fds_); - for (int fd : this->socket_fds_) { - if (fd >= 0 && fd < FD_SETSIZE) { - FD_SET(fd, &this->base_read_fds_); - } - } - this->socket_fds_changed_ = false; - } - - // Copy base fd_set before each select - this->read_fds_ = this->base_read_fds_; - - // Convert delay_time (milliseconds) to timeval - struct timeval tv; - tv.tv_sec = delay_time / 1000; - tv.tv_usec = (delay_time - tv.tv_sec * 1000) * 1000; - - // Call select with timeout -#if defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || (defined(USE_ESP32) && defined(USE_SOCKET_IMPL_BSD_SOCKETS)) - // Use lwip_select() on platforms with lwIP - it's faster - // Note: On ESP32 with BSD sockets, select() is already mapped to lwip_select() via macros, - // but we explicitly call lwip_select() for clarity and to ensure we get the optimized version - int ret = lwip_select(this->max_fd_ + 1, &this->read_fds_, nullptr, nullptr, &tv); -#else - // Use standard select() on other platforms (e.g., host/native builds) - int ret = ::select(this->max_fd_ + 1, &this->read_fds_, nullptr, nullptr, &tv); -#endif - - // Process select() result: - // ret < 0: error (except EINTR which is normal) - // ret > 0: socket(s) have data ready - normal and expected - // ret == 0: timeout occurred - normal and expected - if (ret < 0) { - if (errno == EINTR) { - // Interrupted by signal - this is normal, just continue - // No need to delay as some time has already passed - ESP_LOGVV(TAG, "select() interrupted by signal"); - } else { - // Actual error - log and fall back to delay - ESP_LOGW(TAG, "select() failed with errno %d", errno); - delay(delay_time); - } - } - } else { - // No sockets registered, use regular delay - delay(delay_time); - } -#else - // No select support, use regular delay - delay(delay_time); -#endif + this->delay_with_select_(delay_time); } this->last_loop_ = last_op_end_time; @@ -215,15 +159,17 @@ void IRAM_ATTR HOT Application::feed_wdt(uint32_t time) { } } void Application::reboot() { - ESP_LOGI(TAG, "Forcing a reboot..."); + ESP_LOGI(TAG, "Forcing a reboot"); for (auto it = this->components_.rbegin(); it != this->components_.rend(); ++it) { (*it)->on_shutdown(); } arch_restart(); } void Application::safe_reboot() { - ESP_LOGI(TAG, "Rebooting safely..."); + ESP_LOGI(TAG, "Rebooting safely"); run_safe_shutdown_hooks(); + teardown_components(TEARDOWN_TIMEOUT_REBOOT_MS); + run_powerdown_hooks(); arch_restart(); } @@ -236,6 +182,56 @@ void Application::run_safe_shutdown_hooks() { } } +void Application::run_powerdown_hooks() { + for (auto it = this->components_.rbegin(); it != this->components_.rend(); ++it) { + (*it)->on_powerdown(); + } +} + +void Application::teardown_components(uint32_t timeout_ms) { + uint32_t start_time = millis(); + + // Copy all components in reverse order using reverse iterators + // Reverse order matches the behavior of run_safe_shutdown_hooks() above and ensures + // components are torn down in the opposite order of their setup_priority (which is + // used to sort components during Application::setup()) + std::vector pending_components(this->components_.rbegin(), this->components_.rend()); + + uint32_t now = start_time; + while (!pending_components.empty() && (now - start_time) < timeout_ms) { + // Feed watchdog during teardown to prevent triggering + this->feed_wdt(now); + + // Use iterator to safely erase elements + for (auto it = pending_components.begin(); it != pending_components.end();) { + if ((*it)->teardown()) { + // Component finished teardown, erase it + it = pending_components.erase(it); + } else { + // Component still needs time + ++it; + } + } + + // Give some time for I/O operations if components are still pending + if (!pending_components.empty()) { + this->delay_with_select_(1); + } + + // Update time for next iteration + now = millis(); + } + + if (!pending_components.empty()) { + // Note: At this point, connections are either disconnected or in a bad state, + // so this warning will only appear via serial rather than being transmitted to clients + for (auto *component : pending_components) { + ESP_LOGW(TAG, "%s did not complete teardown within %" PRIu32 " ms", component->get_component_source(), + timeout_ms); + } + } +} + void Application::calculate_looping_components_() { for (auto *obj : this->components_) { if (obj->has_overridden_loop()) @@ -297,6 +293,8 @@ bool Application::is_socket_ready(int fd) const { // This function is thread-safe for reading the result of select() // However, it should only be called after select() has been executed in the main loop // The read_fds_ is only modified by select() in the main loop + if (HighFrequencyLoopRequester::is_high_frequency()) + return true; // fd sets via select are not updated in high frequency looping - so force true fallback behavior if (fd < 0 || fd >= FD_SETSIZE) return false; @@ -304,6 +302,54 @@ bool Application::is_socket_ready(int fd) const { } #endif +void Application::delay_with_select_(uint32_t delay_ms) { +#ifdef USE_SOCKET_SELECT_SUPPORT + if (!this->socket_fds_.empty()) { + // Update fd_set if socket list has changed + if (this->socket_fds_changed_) { + FD_ZERO(&this->base_read_fds_); + for (int fd : this->socket_fds_) { + if (fd >= 0 && fd < FD_SETSIZE) { + FD_SET(fd, &this->base_read_fds_); + } + } + this->socket_fds_changed_ = false; + } + + // Copy base fd_set before each select + this->read_fds_ = this->base_read_fds_; + + // Convert delay_ms to timeval + struct timeval tv; + tv.tv_sec = delay_ms / 1000; + tv.tv_usec = (delay_ms - tv.tv_sec * 1000) * 1000; + + // Call select with timeout +#if defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || (defined(USE_ESP32) && defined(USE_SOCKET_IMPL_BSD_SOCKETS)) + int ret = lwip_select(this->max_fd_ + 1, &this->read_fds_, nullptr, nullptr, &tv); +#else + int ret = ::select(this->max_fd_ + 1, &this->read_fds_, nullptr, nullptr, &tv); +#endif + + // Process select() result: + // ret < 0: error (except EINTR which is normal) + // ret > 0: socket(s) have data ready - normal and expected + // ret == 0: timeout occurred - normal and expected + if (ret < 0 && errno != EINTR) { + // Actual error - log and fall back to delay + ESP_LOGW(TAG, "select() failed with errno %d", errno); + delay(delay_ms); + } + } else { + // No sockets registered, use regular delay + delay(delay_ms); + } +#else + // No select support, use regular delay + delay(delay_ms); +#endif +} + Application App; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) } // namespace esphome diff --git a/esphome/core/application.h b/esphome/core/application.h index f3aa59ad00..d4cd1acb5e 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -80,6 +80,12 @@ namespace esphome { +// Teardown timeout constant (in milliseconds) +// For reboots, it's more important to shut down quickly than disconnect cleanly +// since we're not entering deep sleep. The only consequence of not shutting down +// cleanly is a warning in the log. +static const uint32_t TEARDOWN_TIMEOUT_REBOOT_MS = 1000; // 1 second for quick reboot + class Application { public: void pre_setup(const std::string &name, const std::string &friendly_name, const std::string &area, @@ -193,6 +199,73 @@ class Application { void register_update(update::UpdateEntity *update) { this->updates_.push_back(update); } #endif + /// Reserve space for components to avoid memory fragmentation + void reserve_components(size_t count) { this->components_.reserve(count); } + +#ifdef USE_BINARY_SENSOR + void reserve_binary_sensor(size_t count) { this->binary_sensors_.reserve(count); } +#endif +#ifdef USE_SWITCH + void reserve_switch(size_t count) { this->switches_.reserve(count); } +#endif +#ifdef USE_BUTTON + void reserve_button(size_t count) { this->buttons_.reserve(count); } +#endif +#ifdef USE_SENSOR + void reserve_sensor(size_t count) { this->sensors_.reserve(count); } +#endif +#ifdef USE_TEXT_SENSOR + void reserve_text_sensor(size_t count) { this->text_sensors_.reserve(count); } +#endif +#ifdef USE_FAN + void reserve_fan(size_t count) { this->fans_.reserve(count); } +#endif +#ifdef USE_COVER + void reserve_cover(size_t count) { this->covers_.reserve(count); } +#endif +#ifdef USE_CLIMATE + void reserve_climate(size_t count) { this->climates_.reserve(count); } +#endif +#ifdef USE_LIGHT + void reserve_light(size_t count) { this->lights_.reserve(count); } +#endif +#ifdef USE_NUMBER + void reserve_number(size_t count) { this->numbers_.reserve(count); } +#endif +#ifdef USE_DATETIME_DATE + void reserve_date(size_t count) { this->dates_.reserve(count); } +#endif +#ifdef USE_DATETIME_TIME + void reserve_time(size_t count) { this->times_.reserve(count); } +#endif +#ifdef USE_DATETIME_DATETIME + void reserve_datetime(size_t count) { this->datetimes_.reserve(count); } +#endif +#ifdef USE_SELECT + void reserve_select(size_t count) { this->selects_.reserve(count); } +#endif +#ifdef USE_TEXT + void reserve_text(size_t count) { this->texts_.reserve(count); } +#endif +#ifdef USE_LOCK + void reserve_lock(size_t count) { this->locks_.reserve(count); } +#endif +#ifdef USE_VALVE + void reserve_valve(size_t count) { this->valves_.reserve(count); } +#endif +#ifdef USE_MEDIA_PLAYER + void reserve_media_player(size_t count) { this->media_players_.reserve(count); } +#endif +#ifdef USE_ALARM_CONTROL_PANEL + void reserve_alarm_control_panel(size_t count) { this->alarm_control_panels_.reserve(count); } +#endif +#ifdef USE_EVENT + void reserve_event(size_t count) { this->events_.reserve(count); } +#endif +#ifdef USE_UPDATE + void reserve_update(size_t count) { this->updates_.reserve(count); } +#endif + /// Register the component in this Application instance. template C *register_component(C *c) { static_assert(std::is_base_of::value, "Only Component subclasses can be registered"); @@ -264,6 +337,14 @@ class Application { void run_safe_shutdown_hooks(); + void run_powerdown_hooks(); + + /** Teardown all components with a timeout. + * + * @param timeout_ms Maximum time to wait for teardown in milliseconds + */ + void teardown_components(uint32_t timeout_ms); + uint32_t get_app_state() const { return this->app_state_; } #ifdef USE_BINARY_SENSOR @@ -506,6 +587,9 @@ class Application { void feed_wdt_arch_(); + /// Perform a delay while also monitoring socket file descriptors for readiness + void delay_with_select_(uint32_t delay_ms); + std::vector components_{}; std::vector looping_components_{}; diff --git a/esphome/core/component.h b/esphome/core/component.h index 549bebaee4..c4962067fe 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -111,6 +111,19 @@ class Component { virtual void on_shutdown() {} virtual void on_safe_shutdown() {} + /** Called during teardown to allow component to gracefully finish operations. + * + * @return true if teardown is complete, false if more time is needed + */ + virtual bool teardown() { return true; } + + /** Called after teardown is complete to power down hardware. + * + * This is called after all components have finished their teardown process, + * making it safe to power down hardware like ethernet PHY. + */ + virtual void on_powerdown() {} + uint32_t get_component_state() const; /** Mark this component as failed. Any future timeouts/intervals/setup/loop will no longer be called. diff --git a/esphome/core/config.py b/esphome/core/config.py index 72e9f6a65c..c407e1c11a 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -329,6 +329,12 @@ async def _add_automations(config): await automation.build_automation(trigger, [], conf) +@coroutine_with_priority(-100.0) +async def _add_platform_reserves() -> None: + for platform_name, count in sorted(CORE.platform_counts.items()): + cg.add(cg.RawStatement(f"App.reserve_{platform_name}({count});"), prepend=True) + + @coroutine_with_priority(100.0) async def to_code(config): cg.add_global(cg.global_ns.namespace("esphome").using) @@ -347,6 +353,12 @@ async def to_code(config): config[CONF_NAME_ADD_MAC_SUFFIX], ) ) + # Reserve space for components to avoid reallocation during registration + cg.add( + cg.RawStatement(f"App.reserve_components({len(CORE.component_ids)});"), + ) + + CORE.add_job(_add_platform_reserves) CORE.add_job(_add_automations, config) diff --git a/esphome/core/controller.cpp b/esphome/core/controller.cpp index d6d98a4316..f7ff5a9734 100644 --- a/esphome/core/controller.cpp +++ b/esphome/core/controller.cpp @@ -7,8 +7,10 @@ namespace esphome { void Controller::setup_controller(bool include_internal) { #ifdef USE_BINARY_SENSOR for (auto *obj : App.get_binary_sensors()) { - if (include_internal || !obj->is_internal()) - obj->add_on_state_callback([this, obj](bool state) { this->on_binary_sensor_update(obj, state); }); + if (include_internal || !obj->is_internal()) { + obj->add_full_state_callback( + [this, obj](optional previous, optional state) { this->on_binary_sensor_update(obj); }); + } } #endif #ifdef USE_FAN diff --git a/esphome/core/controller.h b/esphome/core/controller.h index 39e0b2ba26..1a5b9ea6b4 100644 --- a/esphome/core/controller.h +++ b/esphome/core/controller.h @@ -71,7 +71,7 @@ class Controller { public: void setup_controller(bool include_internal = false); #ifdef USE_BINARY_SENSOR - virtual void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state){}; + virtual void on_binary_sensor_update(binary_sensor::BinarySensor *obj){}; #endif #ifdef USE_FAN virtual void on_fan_update(fan::Fan *obj){}; diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 9313f07720..f7a937c28d 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -154,9 +154,12 @@ #endif #ifdef USE_ESP_IDF -#define USE_ESP_IDF_VERSION_CODE VERSION_CODE(5, 1, 6) +#define USE_ESP_IDF_VERSION_CODE VERSION_CODE(5, 3, 2) #define USE_MICRO_WAKE_WORD #define USE_MICRO_WAKE_WORD_VAD +#if defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) +#define USE_OPENTHREAD +#endif #endif #if defined(USE_ESP32_VARIANT_ESP32S2) diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 4ca21f9ee5..a2e1d4adbc 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -3,6 +3,8 @@ #include #include #include "string_ref.h" +#include "helpers.h" +#include "log.h" namespace esphome { @@ -29,7 +31,7 @@ class EntityBase { // Get the unique Object ID of this Entity uint32_t get_object_id_hash(); - // Get/set whether this Entity should be hidden from outside of ESPHome + // Get/set whether this Entity should be hidden outside ESPHome bool is_internal() const; void set_internal(bool internal); @@ -56,11 +58,12 @@ class EntityBase { StringRef name_; const char *object_id_c_str_{nullptr}; const char *icon_c_str_{nullptr}; - uint32_t object_id_hash_; + uint32_t object_id_hash_{}; bool has_own_name_{false}; bool internal_{false}; bool disabled_by_default_{false}; EntityCategory entity_category_{ENTITY_CATEGORY_NONE}; + bool has_state_{}; }; class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming) @@ -85,4 +88,58 @@ class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming) const char *unit_of_measurement_{nullptr}; ///< Unit of measurement override }; +/** + * An entity that has a state. + * @tparam T The type of the state + */ +template class StatefulEntityBase : public EntityBase { + public: + virtual bool has_state() const { return this->state_.has_value(); } + virtual const T &get_state() const { return this->state_.value(); } + virtual T get_state_default(T default_value) const { return this->state_.value_or(default_value); } + void invalidate_state() { this->set_state_({}); } + + void add_full_state_callback(std::function previous, optional current)> &&callback) { + if (this->full_state_callbacks_ == nullptr) + this->full_state_callbacks_ = new CallbackManager previous, optional current)>(); // NOLINT + this->full_state_callbacks_->add(std::move(callback)); + } + void add_on_state_callback(std::function &&callback) { + if (this->state_callbacks_ == nullptr) + this->state_callbacks_ = new CallbackManager(); // NOLINT + this->state_callbacks_->add(std::move(callback)); + } + + void set_trigger_on_initial_state(bool trigger_on_initial_state) { + this->trigger_on_initial_state_ = trigger_on_initial_state; + } + + protected: + optional state_{}; + /** + * Set a new state for this entity. This will trigger callbacks only if the new state is different from the previous. + * + * @param state The new state. + * @return True if the state was changed, false if it was the same as before. + */ + bool set_state_(const optional &state) { + if (this->state_ != state) { + // call the full state callbacks with the previous and new state + if (this->full_state_callbacks_ != nullptr) + this->full_state_callbacks_->call(this->state_, state); + // trigger legacy callbacks only if the new state is valid and either the trigger on initial state is enabled or + // the previous state was valid + auto had_state = this->has_state(); + this->state_ = state; + if (this->state_callbacks_ != nullptr && state.has_value() && (this->trigger_on_initial_state_ || had_state)) + this->state_callbacks_->call(state.value()); + return true; + } + return false; + } + bool trigger_on_initial_state_{true}; + // callbacks with full state and previous state + CallbackManager previous, optional current)> *full_state_callbacks_{}; + CallbackManager *state_callbacks_{}; +}; } // namespace esphome diff --git a/esphome/core/hal.h b/esphome/core/hal.h index 034f9d692f..0ccf21ad83 100644 --- a/esphome/core/hal.h +++ b/esphome/core/hal.h @@ -24,6 +24,11 @@ #define PROGMEM ICACHE_RODATA_ATTR #endif +#elif defined(USE_RP2040) + +#define IRAM_ATTR __attribute__((noinline, long_call, section(".time_critical"))) +#define PROGMEM + #else #define IRAM_ATTR diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 36bc7f949b..ec79cb8bbb 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -30,7 +30,6 @@ #elif defined(USE_ESP_IDF) #include #include -#include "esp_mac.h" #include "esp_random.h" #include "esp_system.h" #elif defined(USE_RP2040) @@ -45,6 +44,7 @@ #endif #ifdef USE_ESP32 #include "rom/crc.h" +#include "esp_mac.h" #include "esp_efuse.h" #include "esp_efuse_table.h" #endif diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 4212aeca98..7d25e7d261 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -192,15 +192,15 @@ bool random_bytes(uint8_t *data, size_t len); constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb) { return (static_cast(msb) << 8) | (static_cast(lsb)); } +/// Encode a 24-bit value given three bytes in most to least significant byte order. +constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3) { + return (static_cast(byte1) << 16) | (static_cast(byte2) << 8) | (static_cast(byte3)); +} /// Encode a 32-bit value given four bytes in most to least significant byte order. constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) { return (static_cast(byte1) << 24) | (static_cast(byte2) << 16) | (static_cast(byte3) << 8) | (static_cast(byte4)); } -/// Encode a 24-bit value given three bytes in most to least significant byte order. -constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3) { - return ((static_cast(byte1) << 16) | (static_cast(byte2) << 8) | (static_cast(byte3))); -} /// Encode a value from its constituent bytes (from most to least significant) in an array with length sizeof(T). template::value, int> = 0> diff --git a/esphome/core/log.h b/esphome/core/log.h index adf72e4bac..cade6a74c1 100644 --- a/esphome/core/log.h +++ b/esphome/core/log.h @@ -165,6 +165,8 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT #define YESNO(b) ((b) ? "YES" : "NO") #define ONOFF(b) ((b) ? "ON" : "OFF") #define TRUEFALSE(b) ((b) ? "TRUE" : "FALSE") +// for use with optional values +#define ONOFFMAYBE(b) (((b).has_value()) ? ONOFF((b).value()) : "UNKNOWN") // Helper class that identifies strings that may be stored in flash storage (similar to Arduino's __FlashStringHelper) struct LogString; diff --git a/esphome/core/log_const_en.h b/esphome/core/log_const_en.h index 75e71ecd81..ccb1f446e4 100644 --- a/esphome/core/log_const_en.h +++ b/esphome/core/log_const_en.h @@ -1,11 +1,4 @@ #pragma once -#include "defines.h" - -#ifdef USE_ESP8266 #define ESP_LOG_MSG_COMM_FAIL "Communication failed" #define ESP_LOG_MSG_COMM_FAIL_FOR "Communication failed for '%s'" -#else -constexpr const char *const ESP_LOG_MSG_COMM_FAIL = "Communication failed"; -constexpr const char *const ESP_LOG_MSG_COMM_FAIL_FOR = "Communication failed for '%s'"; -#endif diff --git a/esphome/core/optional.h b/esphome/core/optional.h index 591bc7aa68..7f9db7817d 100644 --- a/esphome/core/optional.h +++ b/esphome/core/optional.h @@ -52,6 +52,11 @@ template class optional { // NOLINT reset(); return *this; } + bool operator==(optional const &rhs) const { + if (has_value() && rhs.has_value()) + return value() == rhs.value(); + return !has_value() && !rhs.has_value(); + } template optional &operator=(optional const &other) { has_value_ = other.has_value(); diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index 2dea450ead..eed222c974 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -2,9 +2,9 @@ #include "application.h" #include "esphome/core/defines.h" -#include "esphome/core/log.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include #include diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index e2d067390d..bbfa6af815 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -579,13 +579,13 @@ def new_Pvariable(id_: ID, *args: SafeExpType) -> Pvariable: return Pvariable(id_, rhs) -def add(expression: Expression | Statement): +def add(expression: Expression | Statement, prepend: bool = False): """Add an expression to the codegen section. After this is called, the given given expression will show up in the setup() function after this has been called. """ - CORE.add(expression) + CORE.add(expression, prepend) def add_global(expression: SafeExpType | Statement, prepend: bool = False): diff --git a/esphome/log.py b/esphome/log.py index 7e69a2fef8..0e91eb32c2 100644 --- a/esphome/log.py +++ b/esphome/log.py @@ -59,7 +59,13 @@ class ESPHomeLogFormatter(logging.Formatter): "ERROR": AnsiFore.RED.value, "CRITICAL": AnsiFore.RED.value, }.get(record.levelname, "") - return f"{prefix}{formatted}{AnsiStyle.RESET_ALL.value}" + message = f"{prefix}{formatted}{AnsiStyle.RESET_ALL.value}" + if CORE.dashboard: + try: + message = message.replace("\033", "\\033") + except UnicodeEncodeError: + pass + return message def setup_log( diff --git a/esphome/pins.py b/esphome/pins.py index 724cd25d82..0dfd5a245b 100644 --- a/esphome/pins.py +++ b/esphome/pins.py @@ -1,5 +1,8 @@ +from collections.abc import Callable from functools import reduce +from logging import Logger import operator +from typing import Any import esphome.config_validation as cv from esphome.const import ( @@ -15,6 +18,7 @@ from esphome.const import ( CONF_PULLUP, ) from esphome.core import CORE +from esphome.cpp_generator import MockObjClass class PinRegistry(dict): @@ -262,7 +266,7 @@ internal_gpio_input_pullup_pin_number = _internal_number_creator( ) -def check_strapping_pin(conf, strapping_pin_list, logger): +def check_strapping_pin(conf, strapping_pin_list: set[int], logger: Logger): num = conf[CONF_NUMBER] if num in strapping_pin_list and not conf.get(CONF_IGNORE_STRAPPING_WARNING): logger.warning( @@ -291,11 +295,11 @@ def gpio_validate_modes(value): def gpio_base_schema( - pin_type, - number_validator, + pin_type: MockObjClass, + number_validator: Callable[[Any], Any], modes=GPIO_STANDARD_MODES, - mode_validator=gpio_validate_modes, - invertable=True, + mode_validator: Callable[[Any], Any] = gpio_validate_modes, + invertible: bool = True, ): """ Generate a base gpio pin schema @@ -303,7 +307,7 @@ def gpio_base_schema( :param number_validator: A validator for the pin number :param modes: The available modes, default is all standard modes :param mode_validator: A validator function for the pin mode - :param invertable: If the pin supports hardware inversion + :param invertible: If the pin supports hardware inversion :return: A schema for the pin """ mode_default = len(modes) == 1 @@ -328,7 +332,7 @@ def gpio_base_schema( } ) - if invertable: + if invertible: return schema.extend({cv.Optional(CONF_INVERTED, default=False): cv.boolean}) return schema diff --git a/esphome/storage_json.py b/esphome/storage_json.py index fa9fe43d4d..b69dc2dd3f 100644 --- a/esphome/storage_json.py +++ b/esphome/storage_json.py @@ -46,15 +46,16 @@ class StorageJSON: storage_version: int, name: str, friendly_name: str, - comment: str, - esphome_version: str, + comment: str | None, + esphome_version: str | None, src_version: int | None, address: str, web_port: int | None, target_platform: str, - build_path: str, - firmware_bin_path: str, + build_path: str | None, + firmware_bin_path: str | None, loaded_integrations: set[str], + loaded_platforms: set[str], no_mdns: bool, framework: str | None = None, core_platform: str | None = None, @@ -86,6 +87,8 @@ class StorageJSON: self.firmware_bin_path = firmware_bin_path # A set of strings of names of loaded integrations self.loaded_integrations = loaded_integrations + # A set of strings for platform/integration combos + self.loaded_platforms = loaded_platforms # Is mDNS disabled self.no_mdns = no_mdns # The framework used to compile the firmware @@ -107,6 +110,7 @@ class StorageJSON: "build_path": self.build_path, "firmware_bin_path": self.firmware_bin_path, "loaded_integrations": sorted(self.loaded_integrations), + "loaded_platforms": sorted(self.loaded_platforms), "no_mdns": self.no_mdns, "framework": self.framework, "core_platform": self.core_platform, @@ -138,6 +142,7 @@ class StorageJSON: build_path=esph.build_path, firmware_bin_path=esph.firmware_bin, loaded_integrations=esph.loaded_integrations, + loaded_platforms=esph.loaded_platforms, no_mdns=( CONF_MDNS in esph.config and CONF_DISABLED in esph.config[CONF_MDNS] @@ -164,6 +169,7 @@ class StorageJSON: build_path=None, firmware_bin_path=None, loaded_integrations=set(), + loaded_platforms=set(), no_mdns=False, framework=None, core_platform=platform.lower(), @@ -187,6 +193,7 @@ class StorageJSON: build_path = storage.get("build_path") firmware_bin_path = storage.get("firmware_bin_path") loaded_integrations = set(storage.get("loaded_integrations", [])) + loaded_platforms = set(storage.get("loaded_platforms", [])) no_mdns = storage.get("no_mdns", False) framework = storage.get("framework") core_platform = storage.get("core_platform") @@ -203,6 +210,7 @@ class StorageJSON: build_path, firmware_bin_path, loaded_integrations, + loaded_platforms, no_mdns, framework, core_platform, @@ -252,7 +260,7 @@ class EsphomeStorageJSON: def last_update_check(self, new: datetime) -> None: self.last_update_check_str = new.strftime("%Y-%m-%dT%H:%M:%S") - def to_json(self) -> dict: + def to_json(self) -> str: return f"{json.dumps(self.as_dict(), indent=2)}\n" def save(self, path: str) -> None: diff --git a/esphome/writer.py b/esphome/writer.py index 0452098e24..a47112e1fd 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -107,7 +107,10 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool: return True if old.build_path != new.build_path: return True - if old.loaded_integrations != new.loaded_integrations: + if ( + old.loaded_integrations != new.loaded_integrations + or old.loaded_platforms != new.loaded_platforms + ): if new.core_platform == PLATFORM_ESP32: from esphome.components.esp32 import FRAMEWORK_ESP_IDF diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index 02778a6de9..78deec8e65 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -604,6 +604,10 @@ class ESPHomeDumper(yaml.SafeDumper): return self.represent_secret(value.id) return self.represent_stringify(value.id) + # The below override configures this dumper to indent output YAML properly: + def increase_indent(self, flow=False, indentless=False): + return super().increase_indent(flow, False) + ESPHomeDumper.add_multi_representer( dict, lambda dumper, value: dumper.represent_mapping("tag:yaml.org,2002:map", value) diff --git a/platformio.ini b/platformio.ini index ec1e54de09..27da883ab3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -323,6 +323,17 @@ build_flags = ${flags:clangtidy.build_flags} -DUSE_ESP32_VARIANT_ESP32C3 +;;;;;;;; ESP32-C6 ;;;;;;;; + +[env:esp32c6-idf] +extends = common:esp32-idf +board = esp32-c6-devkitc-1 +board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32c6-idf +build_flags = + ${common:esp32-idf.build_flags} + ${flags:runtime.build_flags} + -DUSE_ESP32_VARIANT_ESP32C6 + ;;;;;;;; ESP32-S2 ;;;;;;;; [env:esp32s2-arduino] @@ -413,6 +424,18 @@ build_flags = ${flags:clangtidy.build_flags} -DUSE_ESP32_VARIANT_ESP32S3 +;;;;;;;; ESP32-P4 ;;;;;;;; + +[env:esp32p4-idf] +extends = common:esp32-idf +board = esp32-p4-evboard + +board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32p4-idf +build_flags = + ${common:esp32-idf.build_flags} + ${flags:runtime.build_flags} + -DUSE_ESP32_VARIANT_ESP32P4 + ;;;;;;;; RP2040 ;;;;;;;; [env:rp2040-pico-arduino] diff --git a/pyproject.toml b/pyproject.toml index 4ee2d3a390..3bec607150 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,7 @@ ignore = [ "PLR0915", # Too many statements ({statements} > {max_statements}) "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target + "UP038", # https://github.com/astral-sh/ruff/issues/7871 https://github.com/astral-sh/ruff/pull/16681 ] [tool.ruff.lint.isort] diff --git a/requirements.txt b/requirements.txt index 87319dbba0..d4bd0b7543 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,10 +13,10 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile esptool==4.8.1 click==8.1.7 esphome-dashboard==20250514.0 -aioesphomeapi==31.1.0 +aioesphomeapi==32.2.1 zeroconf==0.147.0 puremagic==1.29 -ruamel.yaml==0.18.11 # dashboard_import +ruamel.yaml==0.18.14 # dashboard_import esphome-glyphsets==0.2.0 pillow==10.4.0 cairosvg==2.8.2 diff --git a/requirements_test.txt b/requirements_test.txt index ebbc933622..689cd9e75e 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,11 +1,11 @@ pylint==3.3.7 flake8==7.2.0 # also change in .pre-commit-config.yaml when updating -ruff==0.11.11 # also change in .pre-commit-config.yaml when updating +ruff==0.11.13 # also change in .pre-commit-config.yaml when updating pyupgrade==3.20.0 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==8.3.5 +pytest==8.4.0 pytest-cov==6.1.1 pytest-mock==3.14.1 pytest-asyncio==0.26.0 diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 63c1efa1ee..d634be98c4 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -258,6 +258,14 @@ class TypeInfo(ABC): force: Whether to force encoding the field even if it has a default value """ + @abstractmethod + def get_estimated_size(self) -> int: + """Get estimated size in bytes for this field with typical values. + + Returns: + Estimated size in bytes including field ID and typical data + """ + TYPE_INFO: dict[int, TypeInfo] = {} @@ -291,6 +299,9 @@ class DoubleType(TypeInfo): o = f"ProtoSize::add_fixed_field<8>(total_size, {field_id_size}, {name} != 0.0, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 8 # field ID + 8 bytes for double + @register_type(2) class FloatType(TypeInfo): @@ -310,6 +321,9 @@ class FloatType(TypeInfo): o = f"ProtoSize::add_fixed_field<4>(total_size, {field_id_size}, {name} != 0.0f, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 4 # field ID + 4 bytes for float + @register_type(3) class Int64Type(TypeInfo): @@ -329,6 +343,9 @@ class Int64Type(TypeInfo): o = f"ProtoSize::add_int64_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint + @register_type(4) class UInt64Type(TypeInfo): @@ -348,6 +365,9 @@ class UInt64Type(TypeInfo): o = f"ProtoSize::add_uint64_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint + @register_type(5) class Int32Type(TypeInfo): @@ -367,6 +387,9 @@ class Int32Type(TypeInfo): o = f"ProtoSize::add_int32_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint + @register_type(6) class Fixed64Type(TypeInfo): @@ -386,6 +409,9 @@ class Fixed64Type(TypeInfo): o = f"ProtoSize::add_fixed_field<8>(total_size, {field_id_size}, {name} != 0, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 8 # field ID + 8 bytes fixed + @register_type(7) class Fixed32Type(TypeInfo): @@ -405,6 +431,9 @@ class Fixed32Type(TypeInfo): o = f"ProtoSize::add_fixed_field<4>(total_size, {field_id_size}, {name} != 0, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 4 # field ID + 4 bytes fixed + @register_type(8) class BoolType(TypeInfo): @@ -423,6 +452,9 @@ class BoolType(TypeInfo): o = f"ProtoSize::add_bool_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 1 # field ID + 1 byte + @register_type(9) class StringType(TypeInfo): @@ -443,6 +475,9 @@ class StringType(TypeInfo): o = f"ProtoSize::add_string_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string + @register_type(11) class MessageType(TypeInfo): @@ -478,6 +513,11 @@ class MessageType(TypeInfo): o = f"ProtoSize::add_message_object(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return ( + self.calculate_field_id_size() + 16 + ) # field ID + 16 bytes estimated submessage + @register_type(12) class BytesType(TypeInfo): @@ -498,6 +538,9 @@ class BytesType(TypeInfo): o = f"ProtoSize::add_string_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical bytes + @register_type(13) class UInt32Type(TypeInfo): @@ -517,6 +560,9 @@ class UInt32Type(TypeInfo): o = f"ProtoSize::add_uint32_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint + @register_type(14) class EnumType(TypeInfo): @@ -544,6 +590,9 @@ class EnumType(TypeInfo): o = f"ProtoSize::add_enum_field(total_size, {field_id_size}, static_cast({name}), {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 1 # field ID + 1 byte typical enum + @register_type(15) class SFixed32Type(TypeInfo): @@ -563,6 +612,9 @@ class SFixed32Type(TypeInfo): o = f"ProtoSize::add_fixed_field<4>(total_size, {field_id_size}, {name} != 0, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 4 # field ID + 4 bytes fixed + @register_type(16) class SFixed64Type(TypeInfo): @@ -582,6 +634,9 @@ class SFixed64Type(TypeInfo): o = f"ProtoSize::add_fixed_field<8>(total_size, {field_id_size}, {name} != 0, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 8 # field ID + 8 bytes fixed + @register_type(17) class SInt32Type(TypeInfo): @@ -601,6 +656,9 @@ class SInt32Type(TypeInfo): o = f"ProtoSize::add_sint32_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint + @register_type(18) class SInt64Type(TypeInfo): @@ -620,6 +678,9 @@ class SInt64Type(TypeInfo): o = f"ProtoSize::add_sint64_field(total_size, {field_id_size}, {name}, {force_str(force)});" return o + def get_estimated_size(self) -> int: + return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint + class RepeatedTypeInfo(TypeInfo): def __init__(self, field: descriptor.FieldDescriptorProto) -> None: @@ -738,6 +799,15 @@ class RepeatedTypeInfo(TypeInfo): o += "}" return o + def get_estimated_size(self) -> int: + # For repeated fields, estimate underlying type size * 2 (assume 2 items typically) + underlying_size = ( + self._ti.get_estimated_size() + if hasattr(self._ti, "get_estimated_size") + else 8 + ) + return underlying_size * 2 + def build_enum_type(desc) -> tuple[str, str]: """Builds the enum type.""" @@ -762,6 +832,22 @@ def build_enum_type(desc) -> tuple[str, str]: return out, cpp +def calculate_message_estimated_size(desc: descriptor.DescriptorProto) -> int: + """Calculate estimated size for a complete message based on typical values.""" + total_size = 0 + + for field in desc.field: + if field.label == 3: # repeated + ti = RepeatedTypeInfo(field) + else: + ti = TYPE_INFO[field.type](field) + + # Add estimated size for this field + total_size += ti.get_estimated_size() + + return total_size + + def build_message_type(desc: descriptor.DescriptorProto) -> tuple[str, str]: public_content: list[str] = [] protected_content: list[str] = [] @@ -773,6 +859,28 @@ def build_message_type(desc: descriptor.DescriptorProto) -> tuple[str, str]: dump: list[str] = [] size_calc: list[str] = [] + # Get message ID if it's a service message + message_id: int | None = get_opt(desc, pb.id) + + # Add MESSAGE_TYPE method if this is a service message + if message_id is not None: + # Add static constexpr for message type + public_content.append(f"static constexpr uint16_t MESSAGE_TYPE = {message_id};") + + # Add estimated size constant + estimated_size = calculate_message_estimated_size(desc) + public_content.append( + f"static constexpr uint16_t ESTIMATED_SIZE = {estimated_size};" + ) + + # Add message_name method for debugging + public_content.append("#ifdef HAS_PROTO_MESSAGE_DUMP") + snake_name = camel_to_snake(desc.name) + public_content.append( + f'static constexpr const char *message_name() {{ return "{snake_name}"; }}' + ) + public_content.append("#endif") + for field in desc.field: if field.label == 3: ti = RepeatedTypeInfo(field) @@ -941,24 +1049,18 @@ def build_service_message_type( hout = "" cout = "" + # Store ifdef for later use if ifdef is not None: ifdefs[str(mt.name)] = ifdef - hout += f"#ifdef {ifdef}\n" - cout += f"#ifdef {ifdef}\n" if source in (SOURCE_BOTH, SOURCE_SERVER): - # Generate send - func = f"send_{snake}" - hout += f"bool {func}(const {mt.name} &msg);\n" - cout += f"bool APIServerConnectionBase::{func}(const {mt.name} &msg) {{\n" - if log: - cout += "#ifdef HAS_PROTO_MESSAGE_DUMP\n" - cout += f' ESP_LOGVV(TAG, "{func}: %s", msg.dump().c_str());\n' - cout += "#endif\n" - # cout += f' this->set_nodelay({str(nodelay).lower()});\n' - cout += f" return this->send_message_<{mt.name}>(msg, {id_});\n" - cout += "}\n" + # Don't generate individual send methods anymore + # The generic send_message method will be used instead + pass if source in (SOURCE_BOTH, SOURCE_CLIENT): + # Only add ifdef when we're actually generating content + if ifdef is not None: + hout += f"#ifdef {ifdef}\n" # Generate receive func = f"on_{snake}" hout += f"virtual void {func}(const {mt.name} &value){{}};\n" @@ -977,9 +1079,9 @@ def build_service_message_type( case += "break;" RECEIVE_CASES[id_] = case - if ifdef is not None: - hout += "#endif\n" - cout += "#endif\n" + # Only close ifdef if we opened it + if ifdef is not None: + hout += "#endif\n" return hout, cout @@ -1083,6 +1185,29 @@ def main() -> None: hpp += f"class {class_name} : public ProtoService {{\n" hpp += " public:\n" + # Add logging helper method declaration + hpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n" + hpp += " protected:\n" + hpp += " void log_send_message_(const char *name, const std::string &dump);\n" + hpp += " public:\n" + hpp += "#endif\n\n" + + # Add generic send_message method + hpp += " template\n" + hpp += " bool send_message(const T &msg) {\n" + hpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n" + hpp += " this->log_send_message_(T::message_name(), msg.dump());\n" + hpp += "#endif\n" + hpp += " return this->send_message_(msg, T::MESSAGE_TYPE);\n" + hpp += " }\n\n" + + # Add logging helper method implementation to cpp + cpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n" + cpp += f"void {class_name}::log_send_message_(const char *name, const std::string &dump) {{\n" + cpp += ' ESP_LOGVV(TAG, "send_message %s: %s", name, dump.c_str());\n' + cpp += "}\n" + cpp += "#endif\n\n" + for mt in file.message_type: obj = build_service_message_type(mt) if obj is None: @@ -1155,8 +1280,7 @@ def main() -> None: body += f"this->{func}(msg);\n" else: body += f"{ret} ret = this->{func}(msg);\n" - ret_snake = camel_to_snake(ret) - body += f"if (!this->send_{ret_snake}(ret)) {{\n" + body += "if (!this->send_message(ret)) {\n" body += " this->on_fatal_error();\n" body += "}\n" cpp += indent(body) + "\n" + "}\n" diff --git a/script/list-components.py b/script/list-components.py index 0d4777436b..0afcaa0f9d 100755 --- a/script/list-components.py +++ b/script/list-components.py @@ -56,6 +56,8 @@ def create_components_graph(): CORE.data[KEY_CORE] = TARGET_CONFIGURATIONS[0] components_graph = {} + platforms = [] + components = [] for path in components_dir.iterdir(): if not path.is_dir(): @@ -70,6 +72,13 @@ def create_components_graph(): ) sys.exit(1) + components.append((comp, name, path)) + if comp.is_platform_component: + platforms.append(name) + + platforms = set(platforms) + + for comp, name, path in components: for dependency in comp.dependencies: add_item_to_components_graph( components_graph, dependency.split(".")[0], name @@ -84,6 +93,8 @@ def create_components_graph(): for platform_path in path.iterdir(): platform_name = platform_path.stem + if platform_name == name or platform_name not in platforms: + continue platform = get_platform(platform_name, name) if platform is None: continue diff --git a/tests/components/binary_sensor/common.yaml b/tests/components/binary_sensor/common.yaml new file mode 100644 index 0000000000..148b7d2405 --- /dev/null +++ b/tests/components/binary_sensor/common.yaml @@ -0,0 +1,15 @@ +binary_sensor: + - platform: template + trigger_on_initial_state: true + id: some_binary_sensor + name: "Random binary" + lambda: return (random_uint32() & 1) == 0; + on_state_change: + then: + - logger.log: + format: "Old state was %s" + args: ['x_previous.has_value() ? ONOFF(x_previous) : "Unknown"'] + - logger.log: + format: "New state is %s" + args: ['x.has_value() ? ONOFF(x) : "Unknown"'] + - binary_sensor.invalidate_state: some_binary_sensor diff --git a/tests/components/binary_sensor/test.bk72xx-ard.yaml b/tests/components/binary_sensor/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.bk72xx-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.esp32-ard.yaml b/tests/components/binary_sensor/test.esp32-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.esp32-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.esp32-c3-ard.yaml b/tests/components/binary_sensor/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.esp32-c3-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.esp32-c3-idf.yaml b/tests/components/binary_sensor/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.esp32-c3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.esp32-idf.yaml b/tests/components/binary_sensor/test.esp32-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.esp32-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.esp32-s3-idf.yaml b/tests/components/binary_sensor/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.esp32-s3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.esp8266-ard.yaml b/tests/components/binary_sensor/test.esp8266-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.esp8266-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/binary_sensor/test.rp2040-ard.yaml b/tests/components/binary_sensor/test.rp2040-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/binary_sensor/test.rp2040-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/esp32/test.esp32-idf.yaml b/tests/components/esp32/test.esp32-idf.yaml new file mode 100644 index 0000000000..582b2c22ce --- /dev/null +++ b/tests/components/esp32/test.esp32-idf.yaml @@ -0,0 +1,12 @@ +esp32: + board: esp32dev + framework: + type: esp-idf + advanced: + enable_lwip_mdns_queries: true + enable_lwip_bridge_interface: true + +wifi: + ssid: MySSID + password: password1 + diff --git a/tests/components/esp32_ble/test.esp32-c3-idf.yaml b/tests/components/esp32_ble/test.esp32-c3-idf.yaml index dade44d145..f8defaf28f 100644 --- a/tests/components/esp32_ble/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_ble/test.esp32-c3-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +esp32_ble: + io_capability: keyboard_only + disable_bt_logs: false diff --git a/tests/components/esp32_ble/test.esp32-idf.yaml b/tests/components/esp32_ble/test.esp32-idf.yaml index dade44d145..f8defaf28f 100644 --- a/tests/components/esp32_ble/test.esp32-idf.yaml +++ b/tests/components/esp32_ble/test.esp32-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +esp32_ble: + io_capability: keyboard_only + disable_bt_logs: false diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-ard.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-ard.yaml index c75ac73ace..d5a9ec9435 100644 --- a/tests/components/esp32_rmt_led_strip/test.esp32-ard.yaml +++ b/tests/components/esp32_rmt_led_strip/test.esp32-ard.yaml @@ -2,4 +2,5 @@ substitutions: pin1: GPIO13 pin2: GPIO14 -<<: !include common-ard.yaml +packages: + common: !include common-ard.yaml diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-c3-ard.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-c3-ard.yaml index 7b4560a0d7..2a3cdec60d 100644 --- a/tests/components/esp32_rmt_led_strip/test.esp32-c3-ard.yaml +++ b/tests/components/esp32_rmt_led_strip/test.esp32-c3-ard.yaml @@ -2,4 +2,5 @@ substitutions: pin1: GPIO3 pin2: GPIO4 -<<: !include common-ard.yaml +packages: + common: !include common-ard.yaml diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml index b4110199f1..8feded852c 100644 --- a/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml +++ b/tests/components/esp32_rmt_led_strip/test.esp32-c3-idf.yaml @@ -2,4 +2,5 @@ substitutions: pin1: GPIO3 pin2: GPIO4 -<<: !include common-idf.yaml +packages: + common: !include common-idf.yaml diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml index 5adeba4f8c..bb26436e5b 100644 --- a/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml +++ b/tests/components/esp32_rmt_led_strip/test.esp32-idf.yaml @@ -2,4 +2,5 @@ substitutions: pin1: GPIO13 pin2: GPIO14 -<<: !include common-idf.yaml +packages: + common: !include common-idf.yaml diff --git a/tests/components/esp32_rmt_led_strip/test.esp32-s3-idf.yaml b/tests/components/esp32_rmt_led_strip/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..f64bb9d8a5 --- /dev/null +++ b/tests/components/esp32_rmt_led_strip/test.esp32-s3-idf.yaml @@ -0,0 +1,12 @@ +substitutions: + pin1: GPIO3 + pin2: GPIO4 + +packages: + common: !include common-idf.yaml + +light: + - id: !extend led_strip1 + use_dma: "true" + - id: !extend led_strip2 + use_dma: "false" diff --git a/tests/components/esp_ldo/test.esp32-p4-idf.yaml b/tests/components/esp_ldo/test.esp32-p4-idf.yaml new file mode 100644 index 0000000000..0e91aaf082 --- /dev/null +++ b/tests/components/esp_ldo/test.esp32-p4-idf.yaml @@ -0,0 +1,15 @@ +esp_ldo: + - id: ldo_id + channel: 3 + voltage: 2.5V + adjustable: true + - id: ldo_4 + channel: 4 + voltage: 2.0V + +esphome: + on_boot: + then: + - esp_ldo.voltage.adjust: + id: ldo_id + voltage: !lambda return 2.5; diff --git a/tests/components/inkplate6/test.esp32-idf.yaml b/tests/components/inkplate6/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/inkplate6/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/lc709203f/common.yaml b/tests/components/lc709203f/common.yaml new file mode 100644 index 0000000000..53177c0d4a --- /dev/null +++ b/tests/components/lc709203f/common.yaml @@ -0,0 +1,16 @@ +i2c: + - id: i2c_lc709203f + scl: ${scl_pin} + sda: ${sda_pin} + +sensor: + - platform: lc709203f + size: 2000 + voltage: 3.7 + battery_voltage: + name: "Battery Voltage" + battery_level: + name: "Battery" + temperature: + name: "Pack Temperature" + b_constant: 0xA5A5 diff --git a/tests/components/lc709203f/test.esp32-ard.yaml b/tests/components/lc709203f/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/lc709203f/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/lc709203f/test.esp32-c3-ard.yaml b/tests/components/lc709203f/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/lc709203f/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/lc709203f/test.esp32-c3-idf.yaml b/tests/components/lc709203f/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/lc709203f/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/lc709203f/test.esp32-idf.yaml b/tests/components/lc709203f/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/lc709203f/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/lc709203f/test.esp8266-ard.yaml b/tests/components/lc709203f/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/lc709203f/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/lc709203f/test.rp2040-ard.yaml b/tests/components/lc709203f/test.rp2040-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/lc709203f/test.rp2040-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/lvgl/common.yaml b/tests/components/lvgl/common.yaml index 174df56749..59602414a7 100644 --- a/tests/components/lvgl/common.yaml +++ b/tests/components/lvgl/common.yaml @@ -63,7 +63,7 @@ binary_sensor: id: lvgl_pressbutton name: Pressbutton widget: spin_up - publish_initial_state: true + trigger_on_initial_state: true - platform: lvgl name: ButtonMatrix button widget: button_a diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index c77983461d..d8452bdd2a 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -170,6 +170,12 @@ lvgl: lvgl.page.is_showing: page1 then: logger.log: "Yes, page1 showing" + - if: + condition: + lvgl.is_idle: + timeout: !lambda return 5000; + then: + logger.log: LVGL is idle on_unload: - logger.log: page unloaded - lvgl.widget.focus: mark diff --git a/tests/components/nextion/common.yaml b/tests/components/nextion/common.yaml index 44d6cdfbc9..767c868d0b 100644 --- a/tests/components/nextion/common.yaml +++ b/tests/components/nextion/common.yaml @@ -281,6 +281,8 @@ display: id: main_lcd update_interval: 5s command_spacing: 5ms + max_commands_per_loop: 20 + max_queue_size: 50 on_sleep: then: lambda: 'ESP_LOGD("display","Display went to sleep");' diff --git a/tests/components/online_image/common.yaml b/tests/components/online_image/common.yaml index 25809930b5..422a24b540 100644 --- a/tests/components/online_image/common.yaml +++ b/tests/components/online_image/common.yaml @@ -11,6 +11,9 @@ online_image: format: PNG type: BINARY resize: 50x50 + request_headers: + X-Test1: 'Test1' + X-Test2: !lambda 'static int x; return to_string(x++);' on_download_finished: lambda: |- if (cached) { diff --git a/tests/components/openthread/test.esp32-c6-idf.yaml b/tests/components/openthread/test.esp32-c6-idf.yaml new file mode 100644 index 0000000000..482fd1a453 --- /dev/null +++ b/tests/components/openthread/test.esp32-c6-idf.yaml @@ -0,0 +1,11 @@ +network: + enable_ipv6: true + +openthread: + channel: 13 + network_name: OpenThread-8f28 + network_key: 0xdfd34f0f05cad978ec4e32b0413038ff + pan_id: 0x8f28 + ext_pan_id: 0xd63e8e3e495ebbc3 + pskc: 0xc23a76e98f1a6483639b1ac1271e2e27 + force_dataset: true diff --git a/tests/components/openthread_info/test.esp32-c6-idf.yaml b/tests/components/openthread_info/test.esp32-c6-idf.yaml new file mode 100644 index 0000000000..ded0f17611 --- /dev/null +++ b/tests/components/openthread_info/test.esp32-c6-idf.yaml @@ -0,0 +1,30 @@ +network: + enable_ipv6: true + +openthread: + channel: 13 + network_key: 0xdfd34f0f05cad978ec4e32b0413038ff + pan_id: 0x8f28 + +text_sensor: + - platform: openthread_info + ip_address: + name: "Off-mesh routable IP Address" + channel: + name: "Channel" + role: + name: "Device Role" + rloc16: + name: "RLOC16" + ext_addr: + name: "Extended Address" + eui64: + name: "EUI64" + network_name: + name: "Network Name" + network_key: + name: "Network Key" + pan_id: + name: "PAN ID" + ext_pan_id: + name: "Extended PAN ID" diff --git a/tests/components/psram/test.esp32-p4-idf.yaml b/tests/components/psram/test.esp32-p4-idf.yaml new file mode 100644 index 0000000000..9ebd80328d --- /dev/null +++ b/tests/components/psram/test.esp32-p4-idf.yaml @@ -0,0 +1,9 @@ +esp32: + cpu_frequency: 360MHz + framework: + type: esp-idf + advanced: + enable_idf_experimental_features: yes + +psram: + speed: 200MHz diff --git a/tests/components/remote_receiver/esp32-common-idf.yaml b/tests/components/remote_receiver/esp32-common-idf.yaml index b314880f8a..14effcbd2c 100644 --- a/tests/components/remote_receiver/esp32-common-idf.yaml +++ b/tests/components/remote_receiver/esp32-common-idf.yaml @@ -7,7 +7,6 @@ remote_receiver: filter_symbols: ${filter_symbols} receive_symbols: ${receive_symbols} rmt_symbols: ${rmt_symbols} - use_dma: ${use_dma} <<: !include common-actions.yaml binary_sensor: diff --git a/tests/components/remote_receiver/test.esp32-c3-idf.yaml b/tests/components/remote_receiver/test.esp32-c3-idf.yaml index 495bb293c3..f017a2d807 100644 --- a/tests/components/remote_receiver/test.esp32-c3-idf.yaml +++ b/tests/components/remote_receiver/test.esp32-c3-idf.yaml @@ -4,7 +4,6 @@ substitutions: filter_symbols: "2" receive_symbols: "4" rmt_symbols: "64" - use_dma: "true" packages: common: !include esp32-common-idf.yaml diff --git a/tests/components/remote_receiver/test.esp32-idf.yaml b/tests/components/remote_receiver/test.esp32-idf.yaml index 495bb293c3..f017a2d807 100644 --- a/tests/components/remote_receiver/test.esp32-idf.yaml +++ b/tests/components/remote_receiver/test.esp32-idf.yaml @@ -4,7 +4,6 @@ substitutions: filter_symbols: "2" receive_symbols: "4" rmt_symbols: "64" - use_dma: "true" packages: common: !include esp32-common-idf.yaml diff --git a/tests/components/remote_receiver/test.esp32-s3-idf.yaml b/tests/components/remote_receiver/test.esp32-s3-idf.yaml index e678ba456d..74f49866cd 100644 --- a/tests/components/remote_receiver/test.esp32-s3-idf.yaml +++ b/tests/components/remote_receiver/test.esp32-s3-idf.yaml @@ -4,7 +4,10 @@ substitutions: filter_symbols: "2" receive_symbols: "4" rmt_symbols: "64" - use_dma: "true" packages: common: !include esp32-common-idf.yaml + +remote_receiver: + - id: !extend rcvr + use_dma: "true" diff --git a/tests/components/remote_transmitter/esp32-common-idf.yaml b/tests/components/remote_transmitter/esp32-common-idf.yaml index c5d4ab7b96..8b26c45149 100644 --- a/tests/components/remote_transmitter/esp32-common-idf.yaml +++ b/tests/components/remote_transmitter/esp32-common-idf.yaml @@ -4,7 +4,6 @@ remote_transmitter: carrier_duty_percent: 50% clock_resolution: ${clock_resolution} rmt_symbols: ${rmt_symbols} - use_dma: ${use_dma} packages: buttons: !include common-buttons.yaml diff --git a/tests/components/remote_transmitter/test.esp32-c3-idf.yaml b/tests/components/remote_transmitter/test.esp32-c3-idf.yaml index be526014bd..cc1fe69b4d 100644 --- a/tests/components/remote_transmitter/test.esp32-c3-idf.yaml +++ b/tests/components/remote_transmitter/test.esp32-c3-idf.yaml @@ -2,7 +2,6 @@ substitutions: pin: GPIO2 clock_resolution: "2000000" rmt_symbols: "64" - use_dma: "true" packages: common: !include esp32-common-idf.yaml diff --git a/tests/components/remote_transmitter/test.esp32-idf.yaml b/tests/components/remote_transmitter/test.esp32-idf.yaml index be526014bd..cc1fe69b4d 100644 --- a/tests/components/remote_transmitter/test.esp32-idf.yaml +++ b/tests/components/remote_transmitter/test.esp32-idf.yaml @@ -2,7 +2,6 @@ substitutions: pin: GPIO2 clock_resolution: "2000000" rmt_symbols: "64" - use_dma: "true" packages: common: !include esp32-common-idf.yaml diff --git a/tests/components/remote_transmitter/test.esp32-s3-idf.yaml b/tests/components/remote_transmitter/test.esp32-s3-idf.yaml index cb86020064..d23463b531 100644 --- a/tests/components/remote_transmitter/test.esp32-s3-idf.yaml +++ b/tests/components/remote_transmitter/test.esp32-s3-idf.yaml @@ -2,7 +2,10 @@ substitutions: pin: GPIO38 clock_resolution: "2000000" rmt_symbols: "64" - use_dma: "true" packages: common: !include esp32-common-idf.yaml + +remote_transmitter: + - id: !extend xmitr + use_dma: "true" diff --git a/tests/components/spi/test.esp32-p4-idf.yaml b/tests/components/spi/test.esp32-p4-idf.yaml new file mode 100644 index 0000000000..061e3dd44a --- /dev/null +++ b/tests/components/spi/test.esp32-p4-idf.yaml @@ -0,0 +1,38 @@ +spi: + - id: quad_spi + type: quad + interface: spi3 + clk_pin: + number: 47 + data_pins: + - allow_other_uses: true + number: 40 + - allow_other_uses: true + number: 41 + - allow_other_uses: true + number: 42 + - allow_other_uses: true + number: 43 + - id: octal_spi + type: octal + interface: hardware + clk_pin: + number: 0 + data_pins: + - 36 + - 37 + - 38 + - 39 + - allow_other_uses: true + number: 40 + - allow_other_uses: true + number: 41 + - allow_other_uses: true + number: 42 + - allow_other_uses: true + number: 43 + - id: spi_id_3 + interface: any + clk_pin: 8 + mosi_pin: 9 + diff --git a/tests/components/wk2132_i2c/common.yaml b/tests/components/wk2132_i2c/common.yaml index f9c8ab756d..942e01aafc 100644 --- a/tests/components/wk2132_i2c/common.yaml +++ b/tests/components/wk2132_i2c/common.yaml @@ -17,4 +17,10 @@ wk2132_i2c: parity: none - id: wk2132_id_1 channel: 1 - baud_rate: 19200 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: wk2132_id_1 + id: distance_sensor diff --git a/tests/components/wk2132_i2c/test.esp32-ard.yaml b/tests/components/wk2132_i2c/test.esp32-ard.yaml index 3b761d3fc1..94552c5a40 100644 --- a/tests/components/wk2132_i2c/test.esp32-ard.yaml +++ b/tests/components/wk2132_i2c/test.esp32-ard.yaml @@ -3,3 +3,4 @@ substitutions: sda_pin: GPIO21 <<: !include common.yaml + diff --git a/tests/components/wk2132_spi/common.yaml b/tests/components/wk2132_spi/common.yaml index b21e89120c..a077b36998 100644 --- a/tests/components/wk2132_spi/common.yaml +++ b/tests/components/wk2132_spi/common.yaml @@ -18,4 +18,10 @@ wk2132_spi: parity: none - id: wk2132_spi_id1 channel: 1 - baud_rate: 921600 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: wk2132_spi_id1 + id: distance_sensor diff --git a/tests/components/wk2168_i2c/common.yaml b/tests/components/wk2168_i2c/common.yaml index fe4689d6db..10463e8abf 100644 --- a/tests/components/wk2168_i2c/common.yaml +++ b/tests/components/wk2168_i2c/common.yaml @@ -24,7 +24,13 @@ wk2168_i2c: baud_rate: 115200 - id: id3 channel: 3 - baud_rate: 115200 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: id3 + id: distance_sensor # individual binary_sensor inputs binary_sensor: diff --git a/tests/components/wk2168_spi/common.yaml b/tests/components/wk2168_spi/common.yaml index 7626e18df6..fb126193fc 100644 --- a/tests/components/wk2168_spi/common.yaml +++ b/tests/components/wk2168_spi/common.yaml @@ -24,7 +24,13 @@ wk2168_spi: baud_rate: 115200 - id: id3 channel: 3 - baud_rate: 115200 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: id3 + id: distance_sensor # individual binary_sensor inputs binary_sensor: diff --git a/tests/components/wk2204_i2c/common.yaml b/tests/components/wk2204_i2c/common.yaml index 80f636c690..70c0f4babf 100644 --- a/tests/components/wk2204_i2c/common.yaml +++ b/tests/components/wk2204_i2c/common.yaml @@ -25,4 +25,10 @@ wk2204_i2c: parity: none - id: wk2204_id_3 channel: 3 - baud_rate: 19200 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: wk2204_id_3 + id: distance_sensor diff --git a/tests/components/wk2204_spi/common.yaml b/tests/components/wk2204_spi/common.yaml index 3bae9c9a6d..a08cdb906f 100644 --- a/tests/components/wk2204_spi/common.yaml +++ b/tests/components/wk2204_spi/common.yaml @@ -26,4 +26,10 @@ wk2204_spi: parity: none - id: wk2204_spi_id3 channel: 3 - baud_rate: 921600 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: wk2204_spi_id3 + id: distance_sensor diff --git a/tests/components/wk2212_i2c/common.yaml b/tests/components/wk2212_i2c/common.yaml index 2e891c5520..0759ef8688 100644 --- a/tests/components/wk2212_i2c/common.yaml +++ b/tests/components/wk2212_i2c/common.yaml @@ -18,10 +18,16 @@ wk2212_i2c: parity: none - id: uart_i2c_id1 channel: 1 - baud_rate: 115200 + baud_rate: 9600 stop_bits: 1 parity: none +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: uart_i2c_id1 + id: distance_sensor + # individual binary_sensor inputs binary_sensor: - platform: gpio diff --git a/tests/components/wk2212_spi/common.yaml b/tests/components/wk2212_spi/common.yaml index ad9f11d9e8..693d2a9ab2 100644 --- a/tests/components/wk2212_spi/common.yaml +++ b/tests/components/wk2212_spi/common.yaml @@ -18,7 +18,13 @@ wk2212_spi: parity: none - id: id1 channel: 1 - baud_rate: 115200 + baud_rate: 9600 + +# Ensures a sensor doesn't break validation +sensor: + - platform: a02yyuw + uart_id: id1 + id: distance_sensor # individual binary_sensor inputs binary_sensor: @@ -55,4 +61,3 @@ switch: mode: output: true inverted: true - diff --git a/tests/integration/fixtures/host_mode_batch_delay.yaml b/tests/integration/fixtures/host_mode_batch_delay.yaml new file mode 100644 index 0000000000..8abe1da6fb --- /dev/null +++ b/tests/integration/fixtures/host_mode_batch_delay.yaml @@ -0,0 +1,55 @@ +esphome: + name: host-batch-delay-test +host: +api: + batch_delay: 0ms +logger: + +# Add multiple sensors to test batching +sensor: + - platform: template + name: "Test Sensor 1" + id: test_sensor1 + lambda: |- + return 1.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 2" + id: test_sensor2 + lambda: |- + return 2.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 3" + id: test_sensor3 + lambda: |- + return 3.0; + update_interval: 0.1s + +binary_sensor: + - platform: template + name: "Test Binary Sensor 1" + id: test_binary_sensor1 + lambda: |- + return millis() % 1000 < 500; + - platform: template + name: "Test Binary Sensor 2" + id: test_binary_sensor2 + lambda: |- + return millis() % 2000 < 1000; + +switch: + - platform: template + name: "Test Switch 1" + id: test_switch1 + turn_on_action: + - logger.log: "Switch 1 turned on" + turn_off_action: + - logger.log: "Switch 1 turned off" + - platform: template + name: "Test Switch 2" + id: test_switch2 + turn_on_action: + - logger.log: "Switch 2 turned on" + turn_off_action: + - logger.log: "Switch 2 turned off" diff --git a/tests/integration/fixtures/host_mode_many_entities.yaml b/tests/integration/fixtures/host_mode_many_entities.yaml new file mode 100644 index 0000000000..3d1aa36196 --- /dev/null +++ b/tests/integration/fixtures/host_mode_many_entities.yaml @@ -0,0 +1,322 @@ +esphome: + name: host-mode-many-entities + friendly_name: "Host Mode Many Entities Test" + +logger: + +host: + +api: + +sensor: + # 50 test sensors with predictable values for batching test + - platform: template + name: "Test Sensor 1" + lambda: return 1.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 2" + lambda: return 2.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 3" + lambda: return 3.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 4" + lambda: return 4.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 5" + lambda: return 5.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 6" + lambda: return 6.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 7" + lambda: return 7.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 8" + lambda: return 8.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 9" + lambda: return 9.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 10" + lambda: return 10.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 11" + lambda: return 11.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 12" + lambda: return 12.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 13" + lambda: return 13.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 14" + lambda: return 14.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 15" + lambda: return 15.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 16" + lambda: return 16.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 17" + lambda: return 17.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 18" + lambda: return 18.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 19" + lambda: return 19.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 20" + lambda: return 20.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 21" + lambda: return 21.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 22" + lambda: return 22.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 23" + lambda: return 23.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 24" + lambda: return 24.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 25" + lambda: return 25.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 26" + lambda: return 26.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 27" + lambda: return 27.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 28" + lambda: return 28.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 29" + lambda: return 29.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 30" + lambda: return 30.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 31" + lambda: return 31.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 32" + lambda: return 32.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 33" + lambda: return 33.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 34" + lambda: return 34.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 35" + lambda: return 35.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 36" + lambda: return 36.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 37" + lambda: return 37.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 38" + lambda: return 38.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 39" + lambda: return 39.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 40" + lambda: return 40.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 41" + lambda: return 41.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 42" + lambda: return 42.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 43" + lambda: return 43.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 44" + lambda: return 44.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 45" + lambda: return 45.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 46" + lambda: return 46.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 47" + lambda: return 47.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 48" + lambda: return 48.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 49" + lambda: return 49.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 50" + lambda: return 50.0; + update_interval: 0.1s + +# Mixed entity types for comprehensive batching test +binary_sensor: + - platform: template + name: "Test Binary Sensor 1" + lambda: return millis() % 1000 < 500; + - platform: template + name: "Test Binary Sensor 2" + lambda: return millis() % 2000 < 1000; + +switch: + - platform: template + name: "Test Switch 1" + lambda: return true; + turn_on_action: + - logger.log: "Switch 1 ON" + turn_off_action: + - logger.log: "Switch 1 OFF" + - platform: template + name: "Test Switch 2" + lambda: return false; + turn_on_action: + - logger.log: "Switch 2 ON" + turn_off_action: + - logger.log: "Switch 2 OFF" + +text_sensor: + - platform: template + name: "Test Text Sensor 1" + lambda: return std::string("Test Value 1"); + - platform: template + name: "Test Text Sensor 2" + lambda: return std::string("Test Value 2"); + - platform: version + name: "ESPHome Version" + +number: + - platform: template + name: "Test Number" + min_value: 0 + max_value: 100 + step: 1 + lambda: return 50.0; + set_action: + - logger.log: "Number set" + +select: + - platform: template + name: "Test Select" + options: + - "Option 1" + - "Option 2" + initial_option: "Option 1" + optimistic: true + set_action: + - logger.log: "Select changed" + +text: + - platform: template + name: "Test Text" + mode: text + initial_value: "Hello" + set_action: + - logger.log: "Text changed" + +valve: + - platform: template + name: "Test Valve" + open_action: + - logger.log: "Valve opening" + close_action: + - logger.log: "Valve closing" + stop_action: + - logger.log: "Valve stopping" + +alarm_control_panel: + - platform: template + name: "Test Alarm" + codes: + - "1234" + arming_away_time: 0s + arming_home_time: 0s + pending_time: 0s + trigger_time: 300s + restore_mode: ALWAYS_DISARMED + on_disarmed: + - logger.log: "Alarm disarmed" + on_arming: + - logger.log: "Alarm arming" + on_armed_away: + - logger.log: "Alarm armed away" + on_armed_home: + - logger.log: "Alarm armed home" + on_pending: + - logger.log: "Alarm pending" + on_triggered: + - logger.log: "Alarm triggered" + +event: + - platform: template + name: "Test Event" + event_types: + - first_event + - second_event + +button: + - platform: template + name: "Test Button" + on_press: + - logger.log: "Button pressed" diff --git a/tests/integration/fixtures/host_mode_many_entities_multiple_connections.yaml b/tests/integration/fixtures/host_mode_many_entities_multiple_connections.yaml new file mode 100644 index 0000000000..296cb2455f --- /dev/null +++ b/tests/integration/fixtures/host_mode_many_entities_multiple_connections.yaml @@ -0,0 +1,136 @@ +esphome: + name: host-mode-many-entities-multi + friendly_name: "Host Mode Many Entities Multiple Connections Test" + +logger: + +host: + +api: + +sensor: + # 20 test sensors for faster testing with multiple connections + - platform: template + name: "Test Sensor 1" + lambda: return 1.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 2" + lambda: return 2.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 3" + lambda: return 3.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 4" + lambda: return 4.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 5" + lambda: return 5.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 6" + lambda: return 6.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 7" + lambda: return 7.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 8" + lambda: return 8.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 9" + lambda: return 9.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 10" + lambda: return 10.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 11" + lambda: return 11.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 12" + lambda: return 12.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 13" + lambda: return 13.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 14" + lambda: return 14.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 15" + lambda: return 15.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 16" + lambda: return 16.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 17" + lambda: return 17.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 18" + lambda: return 18.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 19" + lambda: return 19.0; + update_interval: 0.1s + - platform: template + name: "Test Sensor 20" + lambda: return 20.0; + update_interval: 0.1s + +# Mixed entity types for comprehensive batching test +binary_sensor: + - platform: template + name: "Test Binary Sensor 1" + lambda: return millis() % 1000 < 500; + - platform: template + name: "Test Binary Sensor 2" + lambda: return millis() % 2000 < 1000; + +text_sensor: + - platform: template + name: "Test Text Sensor 1" + lambda: return std::string("Test Value 1"); + - platform: template + name: "Test Text Sensor 2" + lambda: return std::string("Test Value 2"); + - platform: version + name: "ESPHome Version" + +switch: + - platform: template + name: "Test Switch 1" + lambda: return true; + turn_on_action: + - logger.log: "Switch 1 ON" + turn_off_action: + - logger.log: "Switch 1 OFF" + +button: + - platform: template + name: "Test Button" + on_press: + - logger.log: "Button pressed" + +number: + - platform: template + name: "Test Number" + min_value: 0 + max_value: 100 + step: 1 + lambda: return 50.0; + set_action: + - logger.log: "Number set" diff --git a/tests/integration/fixtures/host_mode_noise_encryption.yaml b/tests/integration/fixtures/host_mode_noise_encryption.yaml index 83605e28a3..da817fdc3b 100644 --- a/tests/integration/fixtures/host_mode_noise_encryption.yaml +++ b/tests/integration/fixtures/host_mode_noise_encryption.yaml @@ -5,3 +5,46 @@ api: encryption: key: N4Yle5YirwZhPiHHsdZLdOA73ndj/84veVaLhTvxCuU= logger: + +# Test sensors to verify batching works with noise encryption +sensor: + - platform: template + name: "Noise Test Sensor 1" + lambda: return 1.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 2" + lambda: return 2.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 3" + lambda: return 3.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 4" + lambda: return 4.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 5" + lambda: return 5.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 6" + lambda: return 6.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 7" + lambda: return 7.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 8" + lambda: return 8.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 9" + lambda: return 9.0; + update_interval: 2s + - platform: template + name: "Noise Test Sensor 10" + lambda: return 10.0; + update_interval: 2s diff --git a/tests/integration/test_host_mode_batch_delay.py b/tests/integration/test_host_mode_batch_delay.py new file mode 100644 index 0000000000..5165b90e47 --- /dev/null +++ b/tests/integration/test_host_mode_batch_delay.py @@ -0,0 +1,80 @@ +"""Integration test for API batch_delay setting.""" + +from __future__ import annotations + +import asyncio +import time + +from aioesphomeapi import EntityState +import pytest + +from .types import APIClientConnectedFactory, RunCompiledFunction + + +@pytest.mark.asyncio +async def test_host_mode_batch_delay( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test API with batch_delay set to 0ms - messages should be sent immediately without batching.""" + # Write, compile and run the ESPHome device, then connect to API + loop = asyncio.get_running_loop() + async with run_compiled(yaml_config), api_client_connected() as client: + # Verify we can get device info + device_info = await client.device_info() + assert device_info is not None + assert device_info.name == "host-batch-delay-test" + + # Subscribe to state changes + states: dict[int, EntityState] = {} + state_timestamps: dict[int, float] = {} + entity_count_future: asyncio.Future[int] = loop.create_future() + + def on_state(state: EntityState) -> None: + """Track when states are received.""" + states[state.key] = state + state_timestamps[state.key] = time.monotonic() + # When we have received all expected entities, resolve the future + if len(states) >= 7 and not entity_count_future.done(): + entity_count_future.set_result(len(states)) + + client.subscribe_states(on_state) + + # Wait for states from all entities with timeout + try: + entity_count = await asyncio.wait_for(entity_count_future, timeout=5.0) + except asyncio.TimeoutError: + pytest.fail( + f"Did not receive states from at least 7 entities within 5 seconds. " + f"Received {len(states)} states" + ) + + # Verify we received all states + assert entity_count >= 7, f"Expected at least 7 entities, got {entity_count}" + assert len(states) >= 7 # 3 sensors + 2 binary sensors + 2 switches + + # When batch_delay is 0ms, states are sent immediately without batching + # This means each state arrives in its own packet, which may actually be slower + # than batching due to network overhead + if state_timestamps: + first_timestamp = min(state_timestamps.values()) + last_timestamp = max(state_timestamps.values()) + time_spread = last_timestamp - first_timestamp + + # With batch_delay=0ms, states arrive individually which may take longer + # We just verify they all arrive within a reasonable time + assert time_spread < 1.0, f"States took {time_spread:.3f}s to arrive" + + # Also test list_entities - with batch_delay=0ms each entity is sent separately + start_time = time.monotonic() + entity_info, services = await client.list_entities_services() + end_time = time.monotonic() + + list_time = end_time - start_time + + # Verify we got all expected entities + assert len(entity_info) >= 7 # 3 sensors + 2 binary sensors + 2 switches + + # With batch_delay=0ms, listing sends each entity separately which may be slower + assert list_time < 1.0, f"list_entities took {list_time:.3f}s" diff --git a/tests/integration/test_host_mode_many_entities.py b/tests/integration/test_host_mode_many_entities.py new file mode 100644 index 0000000000..d5622e6fa4 --- /dev/null +++ b/tests/integration/test_host_mode_many_entities.py @@ -0,0 +1,57 @@ +"""Integration test for many entities to test API batching.""" + +from __future__ import annotations + +import asyncio + +from aioesphomeapi import EntityState +import pytest + +from .types import APIClientConnectedFactory, RunCompiledFunction + + +@pytest.mark.asyncio +async def test_host_mode_many_entities( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test API batching with many entities of different types.""" + # Write, compile and run the ESPHome device, then connect to API + loop = asyncio.get_running_loop() + async with run_compiled(yaml_config), api_client_connected() as client: + # Subscribe to state changes + states: dict[int, EntityState] = {} + entity_count_future: asyncio.Future[int] = loop.create_future() + + def on_state(state: EntityState) -> None: + states[state.key] = state + # When we have received states from a good number of entities, resolve the future + if len(states) >= 50 and not entity_count_future.done(): + entity_count_future.set_result(len(states)) + + client.subscribe_states(on_state) + + # Wait for states from at least 50 entities with timeout + try: + entity_count = await asyncio.wait_for(entity_count_future, timeout=10.0) + except asyncio.TimeoutError: + pytest.fail( + f"Did not receive states from at least 50 entities within 10 seconds. " + f"Received {len(states)} states: {list(states.keys())}" + ) + + # Verify we received a good number of entity states + assert entity_count >= 50, f"Expected at least 50 entities, got {entity_count}" + assert len(states) >= 50, f"Expected at least 50 states, got {len(states)}" + + # Verify we have different entity types by checking some expected values + sensor_states = [ + s + for s in states.values() + if hasattr(s, "state") and isinstance(s.state, float) + ] + + assert len(sensor_states) >= 50, ( + f"Expected at least 50 sensor states, got {len(sensor_states)}" + ) diff --git a/tests/integration/test_host_mode_many_entities_multiple_connections.py b/tests/integration/test_host_mode_many_entities_multiple_connections.py new file mode 100644 index 0000000000..a4e5f8a45c --- /dev/null +++ b/tests/integration/test_host_mode_many_entities_multiple_connections.py @@ -0,0 +1,71 @@ +"""Integration test for shared buffer optimization with multiple API connections.""" + +from __future__ import annotations + +import asyncio + +from aioesphomeapi import EntityState +import pytest + +from .types import APIClientConnectedFactory, RunCompiledFunction + + +@pytest.mark.asyncio +async def test_host_mode_many_entities_multiple_connections( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test shared buffer optimization with multiple API connections.""" + # Write, compile and run the ESPHome device + loop = asyncio.get_running_loop() + async with ( + run_compiled(yaml_config), + api_client_connected() as client1, + api_client_connected() as client2, + ): + # Subscribe both clients to state changes + states1: dict[int, EntityState] = {} + states2: dict[int, EntityState] = {} + + client1_ready = loop.create_future() + client2_ready = loop.create_future() + + def on_state1(state: EntityState) -> None: + states1[state.key] = state + if len(states1) >= 20 and not client1_ready.done(): + client1_ready.set_result(len(states1)) + + def on_state2(state: EntityState) -> None: + states2[state.key] = state + if len(states2) >= 20 and not client2_ready.done(): + client2_ready.set_result(len(states2)) + + client1.subscribe_states(on_state1) + client2.subscribe_states(on_state2) + + # Wait for both clients to receive states + try: + count1, count2 = await asyncio.gather( + asyncio.wait_for(client1_ready, timeout=10.0), + asyncio.wait_for(client2_ready, timeout=10.0), + ) + except asyncio.TimeoutError: + pytest.fail( + f"One or both clients did not receive enough states within 10 seconds. " + f"Client1: {len(states1)}, Client2: {len(states2)}" + ) + + # Verify both clients received states successfully + assert count1 >= 20, ( + f"Client 1 should have received at least 20 states, got {count1}" + ) + assert count2 >= 20, ( + f"Client 2 should have received at least 20 states, got {count2}" + ) + + # Verify both clients received the same entity keys (same device state) + common_keys = set(states1.keys()) & set(states2.keys()) + assert len(common_keys) >= 20, ( + f"Expected at least 20 common entity keys, got {len(common_keys)}" + ) diff --git a/tests/test_build_components/build_components_base.esp32-c6-idf.yaml b/tests/test_build_components/build_components_base.esp32-c6-idf.yaml new file mode 100644 index 0000000000..9dbc465ca2 --- /dev/null +++ b/tests/test_build_components/build_components_base.esp32-c6-idf.yaml @@ -0,0 +1,17 @@ +esphome: + name: componenttestesp32c6idf + friendly_name: $component_name + +esp32: + board: esp32-c6-devkitc-1 + framework: + type: esp-idf + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_test_file: $component_test_file diff --git a/tests/test_build_components/build_components_base.esp32-p4-idf.yaml b/tests/test_build_components/build_components_base.esp32-p4-idf.yaml new file mode 100644 index 0000000000..e2b975f643 --- /dev/null +++ b/tests/test_build_components/build_components_base.esp32-p4-idf.yaml @@ -0,0 +1,18 @@ +esphome: + name: componenttestesp32p4idf + friendly_name: $component_name + +esp32: + board: esp32-p4-evboard + framework: + type: esp-idf + +logger: + level: VERY_VERBOSE + +packages: + component_under_test: !include + file: $component_test_file + vars: + component_test_file: $component_test_file +