From 1f7f03f563e3500beeda9a3c163ee48e309e7617 Mon Sep 17 00:00:00 2001 From: luar123 <49960470+luar123@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:18:10 +0100 Subject: [PATCH 001/139] Fix temperature and humidity for bme680 with bsec2 (#7728) --- .../components/bme68x_bsec2/bme68x_bsec2.cpp | 95 ++++++++++--------- .../components/bme68x_bsec2/bme68x_bsec2.h | 2 - 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp b/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp index 5425bbd5b7..f83f20f1a5 100644 --- a/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +++ b/esphome/components/bme68x_bsec2/bme68x_bsec2.cpp @@ -204,11 +204,11 @@ void BME68xBSEC2Component::update_subscription_() { } void BME68xBSEC2Component::run_() { + this->op_mode_ = this->bsec_settings_.op_mode; int64_t curr_time_ns = this->get_time_ns_(); - if (curr_time_ns < this->next_call_ns_) { + if (curr_time_ns < this->bsec_settings_.next_call) { return; } - this->op_mode_ = this->bsec_settings_.op_mode; uint8_t status; ESP_LOGV(TAG, "Performing sensor run"); @@ -219,57 +219,60 @@ void BME68xBSEC2Component::run_() { ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC2 error code %d)", this->bsec_status_); return; } - this->next_call_ns_ = this->bsec_settings_.next_call; - if (this->bsec_settings_.trigger_measurement) { - bme68x_get_conf(&bme68x_conf, &this->bme68x_); + switch (this->bsec_settings_.op_mode) { + case BME68X_FORCED_MODE: + bme68x_get_conf(&bme68x_conf, &this->bme68x_); - bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling; - bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling; - bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling; - bme68x_set_conf(&bme68x_conf, &this->bme68x_); + bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling; + bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling; + bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling; + bme68x_set_conf(&bme68x_conf, &this->bme68x_); + this->bme68x_heatr_conf_.enable = BME68X_ENABLE; + this->bme68x_heatr_conf_.heatr_temp = this->bsec_settings_.heater_temperature; + this->bme68x_heatr_conf_.heatr_dur = this->bsec_settings_.heater_duration; + + // status = bme68x_set_op_mode(this->bsec_settings_.op_mode, &this->bme68x_); + status = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &this->bme68x_heatr_conf_, &this->bme68x_); + status = bme68x_set_op_mode(BME68X_FORCED_MODE, &this->bme68x_); + this->op_mode_ = BME68X_FORCED_MODE; + ESP_LOGV(TAG, "Using forced mode"); + + break; + case BME68X_PARALLEL_MODE: + if (this->op_mode_ != this->bsec_settings_.op_mode) { + bme68x_get_conf(&bme68x_conf, &this->bme68x_); + + bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling; + bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling; + bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling; + bme68x_set_conf(&bme68x_conf, &this->bme68x_); - switch (this->bsec_settings_.op_mode) { - case BME68X_FORCED_MODE: this->bme68x_heatr_conf_.enable = BME68X_ENABLE; - this->bme68x_heatr_conf_.heatr_temp = this->bsec_settings_.heater_temperature; - this->bme68x_heatr_conf_.heatr_dur = this->bsec_settings_.heater_duration; + this->bme68x_heatr_conf_.heatr_temp_prof = this->bsec_settings_.heater_temperature_profile; + this->bme68x_heatr_conf_.heatr_dur_prof = this->bsec_settings_.heater_duration_profile; + this->bme68x_heatr_conf_.profile_len = this->bsec_settings_.heater_profile_len; + this->bme68x_heatr_conf_.shared_heatr_dur = + BSEC_TOTAL_HEAT_DUR - + (bme68x_get_meas_dur(BME68X_PARALLEL_MODE, &bme68x_conf, &this->bme68x_) / INT64_C(1000)); - status = bme68x_set_op_mode(this->bsec_settings_.op_mode, &this->bme68x_); - status = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &this->bme68x_heatr_conf_, &this->bme68x_); - status = bme68x_set_op_mode(BME68X_FORCED_MODE, &this->bme68x_); - this->op_mode_ = BME68X_FORCED_MODE; - this->sleep_mode_ = false; - ESP_LOGV(TAG, "Using forced mode"); + status = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &this->bme68x_heatr_conf_, &this->bme68x_); - break; - case BME68X_PARALLEL_MODE: - if (this->op_mode_ != this->bsec_settings_.op_mode) { - this->bme68x_heatr_conf_.enable = BME68X_ENABLE; - this->bme68x_heatr_conf_.heatr_temp_prof = this->bsec_settings_.heater_temperature_profile; - this->bme68x_heatr_conf_.heatr_dur_prof = this->bsec_settings_.heater_duration_profile; - this->bme68x_heatr_conf_.profile_len = this->bsec_settings_.heater_profile_len; - this->bme68x_heatr_conf_.shared_heatr_dur = - BSEC_TOTAL_HEAT_DUR - - (bme68x_get_meas_dur(BME68X_PARALLEL_MODE, &bme68x_conf, &this->bme68x_) / INT64_C(1000)); - - status = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &this->bme68x_heatr_conf_, &this->bme68x_); - - status = bme68x_set_op_mode(BME68X_PARALLEL_MODE, &this->bme68x_); - this->op_mode_ = BME68X_PARALLEL_MODE; - this->sleep_mode_ = false; - ESP_LOGV(TAG, "Using parallel mode"); - } - break; - case BME68X_SLEEP_MODE: - if (!this->sleep_mode_) { - bme68x_set_op_mode(BME68X_SLEEP_MODE, &this->bme68x_); - this->sleep_mode_ = true; - ESP_LOGV(TAG, "Using sleep mode"); - } - break; - } + status = bme68x_set_op_mode(BME68X_PARALLEL_MODE, &this->bme68x_); + this->op_mode_ = BME68X_PARALLEL_MODE; + ESP_LOGV(TAG, "Using parallel mode"); + } + break; + case BME68X_SLEEP_MODE: + if (this->op_mode_ != this->bsec_settings_.op_mode) { + bme68x_set_op_mode(BME68X_SLEEP_MODE, &this->bme68x_); + this->op_mode_ = BME68X_SLEEP_MODE; + ESP_LOGV(TAG, "Using sleep mode"); + } + break; + } + if (this->bsec_settings_.trigger_measurement && this->bsec_settings_.op_mode != BME68X_SLEEP_MODE) { uint32_t meas_dur = 0; meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_); ESP_LOGV(TAG, "Queueing read in %uus", meas_dur); diff --git a/esphome/components/bme68x_bsec2/bme68x_bsec2.h b/esphome/components/bme68x_bsec2/bme68x_bsec2.h index 7b9db2b7bf..86d3e5dfbf 100644 --- a/esphome/components/bme68x_bsec2/bme68x_bsec2.h +++ b/esphome/components/bme68x_bsec2/bme68x_bsec2.h @@ -113,13 +113,11 @@ class BME68xBSEC2Component : public Component { struct bme68x_heatr_conf bme68x_heatr_conf_; uint8_t op_mode_; // operating mode of sensor - bool sleep_mode_; bsec_library_return_t bsec_status_{BSEC_OK}; int8_t bme68x_status_{BME68X_OK}; int64_t last_time_ms_{0}; uint32_t millis_overflow_counter_{0}; - int64_t next_call_ns_{0}; std::queue> queue_; From a2cab960a9d2f138fe736ce8147b383f13146475 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:16:13 +1300 Subject: [PATCH 002/139] Bump version to 2024.12.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 5645c9eaab..d42ee5ee72 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.11.0-dev" +__version__ = "2024.12.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From c7c8711c9c8380d9d90875973e2e8c0e70678667 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 13 Nov 2024 12:39:02 -0500 Subject: [PATCH 003/139] [i2s_audio] Bugfix: Adjust I2S speaker setup priority (#7759) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 11 +---------- .../components/i2s_audio/speaker/i2s_audio_speaker.h | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index c3f4566411..53b3cc8dc0 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -99,14 +99,6 @@ void I2SAudioSpeaker::setup() { this->mark_failed(); return; } - - this->i2s_event_queue_ = xQueueCreate(I2S_EVENT_QUEUE_COUNT, sizeof(i2s_event_t)); - - if (this->i2s_event_queue_ == nullptr) { - ESP_LOGE(TAG, "Failed to create I2S event queue"); - this->mark_failed(); - return; - } } void I2SAudioSpeaker::loop() { @@ -339,7 +331,7 @@ void I2SAudioSpeaker::speaker_task(void *params) { } void I2SAudioSpeaker::start() { - if (this->is_failed() || this->status_has_error()) + if (!this->is_ready() || this->is_failed() || this->status_has_error()) return; if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING)) return; @@ -519,7 +511,6 @@ void I2SAudioSpeaker::delete_task_(size_t buffer_size) { } xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPED); - xQueueReset(this->i2s_event_queue_); this->task_created_ = false; vTaskDelete(nullptr); diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 8b7386ba58..2b90f39399 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -23,7 +23,7 @@ namespace i2s_audio { class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Component { public: - float get_setup_priority() const override { return esphome::setup_priority::LATE; } + float get_setup_priority() const override { return esphome::setup_priority::PROCESSOR; } void setup() override; void loop() override; From 39c889e6625a212b582d519012c6b69a45862bc6 Mon Sep 17 00:00:00 2001 From: Roving Ronin <108674933+Roving-Ronin@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:43:21 +1100 Subject: [PATCH 004/139] Update UNIT_VOLT_AMPS_REACTIVE = "var" (Currently 'VAR') (#7643) --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index d42ee5ee72..6a643e1e30 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1095,7 +1095,7 @@ UNIT_STEPS = "steps" UNIT_VOLT = "V" UNIT_VOLT_AMPS = "VA" UNIT_VOLT_AMPS_HOURS = "VAh" -UNIT_VOLT_AMPS_REACTIVE = "VAR" +UNIT_VOLT_AMPS_REACTIVE = "var" UNIT_VOLT_AMPS_REACTIVE_HOURS = "VARh" UNIT_WATT = "W" UNIT_WATT_HOURS = "Wh" From d01508885531c31a2ebb518c8b07f550d5768ccc Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 13 Nov 2024 21:44:18 -0300 Subject: [PATCH 005/139] Fix reactive power unit of measurement from VAR to var (#7757) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/sdm_meter/sdm_meter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sdm_meter/sdm_meter.cpp b/esphome/components/sdm_meter/sdm_meter.cpp index 9c35d306ad..18e06e2b04 100644 --- a/esphome/components/sdm_meter/sdm_meter.cpp +++ b/esphome/components/sdm_meter/sdm_meter.cpp @@ -38,7 +38,7 @@ void SDMMeter::on_modbus_data(const std::vector &data) { ESP_LOGD( TAG, - "SDMMeter Phase %c: V=%.3f V, I=%.3f A, Active P=%.3f W, Apparent P=%.3f VA, Reactive P=%.3f VAR, PF=%.3f, " + "SDMMeter Phase %c: V=%.3f V, I=%.3f A, Active P=%.3f W, Apparent P=%.3f VA, Reactive P=%.3f var, PF=%.3f, " "PA=%.3f °", i + 'A', voltage, current, active_power, apparent_power, reactive_power, power_factor, phase_angle); if (phase.voltage_sensor_ != nullptr) From 5e62c489b08a70295f3247c19c907de57507e263 Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Wed, 13 Nov 2024 16:57:09 -0800 Subject: [PATCH 006/139] Disable bluetooth proxy during update (#7695) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp | 3 +++ tests/components/esp32_ble_tracker/common.yaml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 74b4b9aa89..b86d32ee61 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -65,6 +65,9 @@ void ESP32BLETracker::setup() { [this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) { if (state == ota::OTA_STARTED) { this->stop_scan(); + for (auto *client : this->clients_) { + client->disconnect(); + } } }); #endif diff --git a/tests/components/esp32_ble_tracker/common.yaml b/tests/components/esp32_ble_tracker/common.yaml index ef23635c9e..018bbb42b3 100644 --- a/tests/components/esp32_ble_tracker/common.yaml +++ b/tests/components/esp32_ble_tracker/common.yaml @@ -39,3 +39,10 @@ esp32_ble_tracker: - then: - lambda: |- ESP_LOGD("ble_auto", "The scan has ended!"); + +wifi: + ssid: MySSID + password: password1 + +ota: + - platform: esphome From 0b51ec2c88793191f8d28fecfe9b514b9195312f Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Thu, 14 Nov 2024 01:57:51 +0100 Subject: [PATCH 007/139] ld2420: fix typo in log message (#7758) --- esphome/components/ld2420/ld2420.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index e57fdbc84e..9d628cc14f 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -180,7 +180,7 @@ void LD2420Component::apply_config_action() { } void LD2420Component::factory_reset_action() { - ESP_LOGCONFIG(TAG, "Setiing 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(); From b29c1194089f4770b7a3e9ab99b12ac890c3e2cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:43:52 +0100 Subject: [PATCH 008/139] Bump codecov/codecov-action from 4 to 5 (#7771) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82a55d0e2a..f5af3ec9e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -219,7 +219,7 @@ jobs: . venv/bin/activate pytest -vv --cov-report=xml --tb=native tests - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} From e81191ebd2583d44b4237db8b7dad3ed18877d0d Mon Sep 17 00:00:00 2001 From: pethans <38168907+pethans@users.noreply.github.com> Date: Sun, 17 Nov 2024 10:47:29 -0800 Subject: [PATCH 009/139] TuyaFan control should use oscillation_type (#7776) Co-authored-by: Peter Hanson --- esphome/components/tuya/fan/tuya_fan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/tuya/fan/tuya_fan.cpp b/esphome/components/tuya/fan/tuya_fan.cpp index 8a613d0bae..9b132e0de6 100644 --- a/esphome/components/tuya/fan/tuya_fan.cpp +++ b/esphome/components/tuya/fan/tuya_fan.cpp @@ -86,7 +86,7 @@ void TuyaFan::control(const fan::FanCall &call) { if (this->oscillation_id_.has_value() && call.get_oscillating().has_value()) { if (this->oscillation_type_ == TuyaDatapointType::ENUM) { this->parent_->set_enum_datapoint_value(*this->oscillation_id_, *call.get_oscillating()); - } else if (this->speed_type_ == TuyaDatapointType::BOOLEAN) { + } else if (this->oscillation_type_ == TuyaDatapointType::BOOLEAN) { this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, *call.get_oscillating()); } } From 6e41c22e9d7f777a5c556725b1a54cf33a669e39 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:44:39 +1300 Subject: [PATCH 010/139] Bump esphome-dashboard to 20241118.0 (#7782) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e11e629743..4bea8cf4ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.16 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20241025.0 +esphome-dashboard==20241118.0 aioesphomeapi==24.6.2 zeroconf==0.132.2 puremagic==1.27 From 49e9c4333979bfeae77f25ee32c3065bc610b7a5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:54:19 +1300 Subject: [PATCH 011/139] [http_request] Feed watchdog timeout around http request functions (#7786) --- esphome/components/http_request/http_request_arduino.cpp | 2 ++ esphome/components/http_request/http_request_idf.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index af1eb6f459..85a1312aaa 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -104,7 +104,9 @@ std::shared_ptr HttpRequestArduino::start(std::string url, std::s static const size_t HEADER_COUNT = sizeof(header_keys) / sizeof(header_keys[0]); container->client_.collectHeaders(header_keys, HEADER_COUNT); + App.feed_wdt(); container->status_code = container->client_.sendRequest(method.c_str(), body.c_str()); + App.feed_wdt(); if (container->status_code < 0) { ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url.c_str(), HTTPClient::errorToString(container->status_code).c_str()); diff --git a/esphome/components/http_request/http_request_idf.cpp b/esphome/components/http_request/http_request_idf.cpp index c6c567b620..b449f046ee 100644 --- a/esphome/components/http_request/http_request_idf.cpp +++ b/esphome/components/http_request/http_request_idf.cpp @@ -117,8 +117,11 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin return nullptr; } + App.feed_wdt(); container->content_length = esp_http_client_fetch_headers(client); + App.feed_wdt(); container->status_code = esp_http_client_get_status_code(client); + App.feed_wdt(); if (is_success(container->status_code)) { container->duration_ms = millis() - start; return container; @@ -148,8 +151,11 @@ std::shared_ptr HttpRequestIDF::start(std::string url, std::strin return nullptr; } + App.feed_wdt(); container->content_length = esp_http_client_fetch_headers(client); + App.feed_wdt(); container->status_code = esp_http_client_get_status_code(client); + App.feed_wdt(); if (is_success(container->status_code)) { container->duration_ms = millis() - start; return container; From cf63d627fee4224f3652a0d101fae4cad1039da4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 20 Nov 2024 17:39:28 +1300 Subject: [PATCH 012/139] Bump esphome-dashboard to 20241120.0 (#7787) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4bea8cf4ef..7bc1c895df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.16 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20241118.0 +esphome-dashboard==20241120.0 aioesphomeapi==24.6.2 zeroconf==0.132.2 puremagic==1.27 From 372d68a177196d6efb688b9f15943c5fd05dd202 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:27:23 -0500 Subject: [PATCH 013/139] [remote_base] Fix extra comma in dump raw (#7774) Co-authored-by: Jonathan Swoboda --- esphome/components/remote_base/raw_protocol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/remote_base/raw_protocol.cpp b/esphome/components/remote_base/raw_protocol.cpp index bdeb935dc4..ef0cb8454e 100644 --- a/esphome/components/remote_base/raw_protocol.cpp +++ b/esphome/components/remote_base/raw_protocol.cpp @@ -28,7 +28,7 @@ bool RawDumper::dump(RemoteReceiveData src) { ESP_LOGI(TAG, "%s", buffer); buffer_offset = 0; written = sprintf(buffer, " "); - if (i + 1 < src.size()) { + if (i + 1 < src.size() - 1) { written += sprintf(buffer + written, "%" PRId32 ", ", value); } else { written += sprintf(buffer + written, "%" PRId32, value); From 846b091aacbe72078996cd0c89419a40c32cb1f8 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Wed, 20 Nov 2024 19:28:21 +0100 Subject: [PATCH 014/139] [nextion] New trigger `on_buffer_overflow` (#7772) --- esphome/components/nextion/automation.h | 7 +++++++ esphome/components/nextion/base_component.py | 1 + esphome/components/nextion/display.py | 15 +++++++++++++++ esphome/components/nextion/nextion.cpp | 8 +++++++- esphome/components/nextion/nextion.h | 7 +++++++ tests/components/nextion/test.esp32-ard.yaml | 3 +++ tests/components/nextion/test.esp32-c3-ard.yaml | 3 +++ tests/components/nextion/test.esp32-c3-idf.yaml | 3 +++ tests/components/nextion/test.esp32-idf.yaml | 3 +++ tests/components/nextion/test.esp8266-ard.yaml | 3 +++ tests/components/nextion/test.rp2040-ard.yaml | 3 +++ 11 files changed, 55 insertions(+), 1 deletion(-) diff --git a/esphome/components/nextion/automation.h b/esphome/components/nextion/automation.h index f51fe6b4f8..5182e07229 100644 --- a/esphome/components/nextion/automation.h +++ b/esphome/components/nextion/automation.h @@ -42,5 +42,12 @@ class TouchTrigger : public Trigger { } }; +class BufferOverflowTrigger : public Trigger<> { + public: + explicit BufferOverflowTrigger(Nextion *nextion) { + nextion->add_buffer_overflow_event_callback([this]() { this->trigger(); }); + } +}; + } // namespace nextion } // namespace esphome diff --git a/esphome/components/nextion/base_component.py b/esphome/components/nextion/base_component.py index 2924f66d3c..9708379861 100644 --- a/esphome/components/nextion/base_component.py +++ b/esphome/components/nextion/base_component.py @@ -18,6 +18,7 @@ CONF_ON_SLEEP = "on_sleep" CONF_ON_WAKE = "on_wake" CONF_ON_SETUP = "on_setup" CONF_ON_PAGE = "on_page" +CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow" CONF_TOUCH_SLEEP_TIMEOUT = "touch_sleep_timeout" CONF_WAKE_UP_PAGE = "wake_up_page" CONF_START_UP_PAGE = "start_up_page" diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py index e403ba7ae8..6f284376af 100644 --- a/esphome/components/nextion/display.py +++ b/esphome/components/nextion/display.py @@ -13,6 +13,7 @@ from esphome.const import ( from esphome.core import CORE from . import Nextion, nextion_ns, nextion_ref from .base_component import ( + CONF_ON_BUFFER_OVERFLOW, CONF_ON_SLEEP, CONF_ON_WAKE, CONF_ON_SETUP, @@ -36,6 +37,9 @@ SleepTrigger = nextion_ns.class_("SleepTrigger", automation.Trigger.template()) WakeTrigger = nextion_ns.class_("WakeTrigger", automation.Trigger.template()) PageTrigger = nextion_ns.class_("PageTrigger", automation.Trigger.template()) TouchTrigger = nextion_ns.class_("TouchTrigger", automation.Trigger.template()) +BufferOverflowTrigger = nextion_ns.class_( + "BufferOverflowTrigger", automation.Trigger.template() +) CONFIG_SCHEMA = ( display.BASIC_DISPLAY_SCHEMA.extend( @@ -68,6 +72,13 @@ CONFIG_SCHEMA = ( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TouchTrigger), } ), + cv.Optional(CONF_ON_BUFFER_OVERFLOW): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + BufferOverflowTrigger + ), + } + ), 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, @@ -151,3 +162,7 @@ async def to_code(config): ], conf, ) + + for conf in config.get(CONF_ON_BUFFER_OVERFLOW, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index a80f6efc91..984db09c57 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -190,6 +190,10 @@ void Nextion::add_touch_event_callback(std::functiontouch_callback_.add(std::move(callback)); } +void Nextion::add_buffer_overflow_event_callback(std::function &&callback) { + this->buffer_overflow_callback_.add(std::move(callback)); +} + void Nextion::update_all_components() { if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping()) return; @@ -458,7 +462,9 @@ void Nextion::process_nextion_commands_() { this->remove_from_q_(); break; case 0x24: // Serial Buffer overflow occurs - ESP_LOGW(TAG, "Nextion reported Serial Buffer overflow!"); + // Buffer will continue to receive the current instruction, all previous instructions are lost. + ESP_LOGE(TAG, "Nextion reported Serial Buffer overflow!"); + this->buffer_overflow_callback_.call(); break; case 0x65: { // touch event return data if (to_process_length != 3) { diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index 732ee9b455..f539c79718 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -1134,6 +1134,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe */ void add_touch_event_callback(std::function &&callback); + /** Add a callback to be notified when the nextion reports a buffer overflow. + * + * @param callback The void() callback. + */ + void add_buffer_overflow_event_callback(std::function &&callback); + void update_all_components(); /** @@ -1323,6 +1329,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe CallbackManager wake_callback_{}; CallbackManager page_callback_{}; CallbackManager touch_callback_{}; + CallbackManager buffer_overflow_callback_{}; optional writer_; float brightness_{1.0}; diff --git a/tests/components/nextion/test.esp32-ard.yaml b/tests/components/nextion/test.esp32-ard.yaml index 27568ebc2a..ba76236fc6 100644 --- a/tests/components/nextion/test.esp32-ard.yaml +++ b/tests/components/nextion/test.esp32-ard.yaml @@ -58,3 +58,6 @@ display: on_page: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-c3-ard.yaml b/tests/components/nextion/test.esp32-c3-ard.yaml index 5881d6e165..5d253268f8 100644 --- a/tests/components/nextion/test.esp32-c3-ard.yaml +++ b/tests/components/nextion/test.esp32-c3-ard.yaml @@ -58,3 +58,6 @@ display: on_page: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-c3-idf.yaml b/tests/components/nextion/test.esp32-c3-idf.yaml index 5881d6e165..5d253268f8 100644 --- a/tests/components/nextion/test.esp32-c3-idf.yaml +++ b/tests/components/nextion/test.esp32-c3-idf.yaml @@ -58,3 +58,6 @@ display: on_page: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-idf.yaml b/tests/components/nextion/test.esp32-idf.yaml index 27568ebc2a..ba76236fc6 100644 --- a/tests/components/nextion/test.esp32-idf.yaml +++ b/tests/components/nextion/test.esp32-idf.yaml @@ -58,3 +58,6 @@ display: on_page: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp8266-ard.yaml b/tests/components/nextion/test.esp8266-ard.yaml index 5881d6e165..5d253268f8 100644 --- a/tests/components/nextion/test.esp8266-ard.yaml +++ b/tests/components/nextion/test.esp8266-ard.yaml @@ -58,3 +58,6 @@ display: on_page: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.rp2040-ard.yaml b/tests/components/nextion/test.rp2040-ard.yaml index a1c5848ce6..9b04433095 100644 --- a/tests/components/nextion/test.rp2040-ard.yaml +++ b/tests/components/nextion/test.rp2040-ard.yaml @@ -53,3 +53,6 @@ display: on_page: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" From 5e27a8df1f5fc3978939521d421d6330d1296128 Mon Sep 17 00:00:00 2001 From: Kjell Braden Date: Wed, 20 Nov 2024 19:29:48 +0100 Subject: [PATCH 015/139] enable rp2040 for online_image (#7769) --- esphome/components/online_image/__init__.py | 1 + .../online_image/common-rp2040.yaml | 19 +++++++++++++++++++ .../online_image/test.rp2040-ard.yaml | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 tests/components/online_image/common-rp2040.yaml create mode 100644 tests/components/online_image/test.rp2040-ard.yaml diff --git a/esphome/components/online_image/__init__.py b/esphome/components/online_image/__init__.py index dfb10137aa..be1bfb4a00 100644 --- a/esphome/components/online_image/__init__.py +++ b/esphome/components/online_image/__init__.py @@ -98,6 +98,7 @@ CONFIG_SCHEMA = cv.Schema( # esp8266_arduino=cv.Version(2, 7, 0), esp32_arduino=cv.Version(0, 0, 0), esp_idf=cv.Version(4, 0, 0), + rp2040_arduino=cv.Version(0, 0, 0), ), ) ) diff --git a/tests/components/online_image/common-rp2040.yaml b/tests/components/online_image/common-rp2040.yaml new file mode 100644 index 0000000000..16bb2b2c44 --- /dev/null +++ b/tests/components/online_image/common-rp2040.yaml @@ -0,0 +1,19 @@ +<<: !include common.yaml + +spi: + - id: spi_main_lcd + clk_pin: 18 + mosi_pin: 19 + miso_pin: 16 + +display: + - platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 20 + dc_pin: 17 + reset_pin: 21 + invert_colors: true + lambda: |- + it.fill(Color(0, 0, 0)); + it.image(0, 0, id(online_rgba_image)); diff --git a/tests/components/online_image/test.rp2040-ard.yaml b/tests/components/online_image/test.rp2040-ard.yaml new file mode 100644 index 0000000000..d10f36b4e9 --- /dev/null +++ b/tests/components/online_image/test.rp2040-ard.yaml @@ -0,0 +1,4 @@ +<<: !include common-rp2040.yaml + +http_request: + verify_ssl: false From 6d4f787f67b6d4dc16fcdbdca3a1984db8d9df62 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:10:28 +1100 Subject: [PATCH 016/139] [http_request] Fix within context with parameters. (Bugfix) (#7790) --- esphome/components/http_request/http_request.h | 2 +- tests/components/http_request/common.yaml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index 4ed2c834f8..b2ce718ec4 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -189,7 +189,7 @@ template class HttpRequestSendAction : public Action { if (container == nullptr) { for (auto *trigger : this->error_triggers_) - trigger->trigger(x...); + trigger->trigger(); return; } diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml index 593b85e435..8408f27a05 100644 --- a/tests/components/http_request/common.yaml +++ b/tests/components/http_request/common.yaml @@ -39,6 +39,14 @@ http_request: timeout: 10s verify_ssl: ${verify_ssl} +script: + - id: does_not_compile + parameters: + api_url: string + then: + - http_request.get: + url: "http://google.com" + ota: - platform: http_request on_begin: From fbb9967117d248951906b0bb19ef200e7f546360 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 21 Nov 2024 19:22:02 +1300 Subject: [PATCH 017/139] [rtttl] Clamp gain between 0 and 1 (#7793) --- esphome/components/rtttl/rtttl.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/esphome/components/rtttl/rtttl.h b/esphome/components/rtttl/rtttl.h index 10c290c5fb..420948bfbf 100644 --- a/esphome/components/rtttl/rtttl.h +++ b/esphome/components/rtttl/rtttl.h @@ -40,13 +40,7 @@ class Rtttl : public Component { void set_speaker(speaker::Speaker *speaker) { this->speaker_ = speaker; } #endif float get_gain() { return gain_; } - void set_gain(float gain) { - if (gain < 0.1f) - gain = 0.1f; - if (gain > 1.0f) - gain = 1.0f; - this->gain_ = gain; - } + void set_gain(float gain) { this->gain_ = clamp(gain, 0.0f, 1.0f); } void play(std::string rtttl); void stop(); void dump_config() override; From 6bcbbcce02ca9441cffe6d7f559eceb92ab76811 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:10:20 +1300 Subject: [PATCH 018/139] [speaker] Add missing auto-load for ``audio`` (#7794) --- esphome/components/speaker/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/speaker/__init__.py b/esphome/components/speaker/__init__.py index 7a668dc2f3..948fe4b534 100644 --- a/esphome/components/speaker/__init__.py +++ b/esphome/components/speaker/__init__.py @@ -7,6 +7,7 @@ from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME from esphome.core import CORE from esphome.coroutine import coroutine_with_priority +AUTO_LOAD = ["audio"] CODEOWNERS = ["@jesserockz", "@kahrendt"] IS_PLATFORM_COMPONENT = True From 03ae6b2c1b6e4ae2a509c109c2381214e0cdb131 Mon Sep 17 00:00:00 2001 From: Manuel Kasper Date: Thu, 21 Nov 2024 10:46:49 +0100 Subject: [PATCH 019/139] [qspi_dbi] Fix garbled graphics on RM690B0 (#7795) --- esphome/components/qspi_dbi/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/qspi_dbi/models.py b/esphome/components/qspi_dbi/models.py index 071ea72d73..cbd9c4663f 100644 --- a/esphome/components/qspi_dbi/models.py +++ b/esphome/components/qspi_dbi/models.py @@ -55,6 +55,7 @@ chip.cmd(PAGESEL, 0x00) chip.cmd(0xC2, 0x00) chip.delay(10) chip.cmd(TEON, 0x00) +chip.cmd(PIXFMT, 0x55) chip = DriverChip("AXS15231") chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5) From ccf2854b612a1659c27cedeb22eaf49b871f157c Mon Sep 17 00:00:00 2001 From: Spencer Owen Date: Thu, 21 Nov 2024 12:24:10 -0700 Subject: [PATCH 020/139] Check for min_version earlier in validation (#7797) --- esphome/core/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/core/config.py b/esphome/core/config.py index 8c130eb6db..367e61c413 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -184,6 +184,9 @@ PRELOAD_CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_ESP8266_RESTORE_FROM_FLASH): cv.valid, cv.Optional(CONF_BOARD_FLASH_MODE): cv.valid, cv.Optional(CONF_ARDUINO_VERSION): cv.valid, + cv.Optional(CONF_MIN_VERSION, default=ESPHOME_VERSION): cv.All( + cv.version_number, cv.validate_esphome_version + ), }, extra=cv.ALLOW_EXTRA, ) From 3232866dc337b0e3332f9b7283d834f025e2a642 Mon Sep 17 00:00:00 2001 From: Alain Turbide <7193213+Dilbert66@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:39:32 -0500 Subject: [PATCH 021/139] Fix for OTA mode not activating in safe_mode when OTA section has an on_xxxx action (#7796) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/esphome/ota/__init__.py | 8 ++++---- esphome/components/ota/__init__.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index a852d8d001..86006e3e18 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -1,10 +1,9 @@ import logging import esphome.codegen as cg -import esphome.config_validation as cv -import esphome.final_validate as fv -from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent +from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code from esphome.config_helpers import merge_config +import esphome.config_validation as cv from esphome.const import ( CONF_ESPHOME, CONF_ID, @@ -18,6 +17,7 @@ from esphome.const import ( CONF_VERSION, ) from esphome.core import coroutine_with_priority +import esphome.final_validate as fv _LOGGER = logging.getLogger(__name__) @@ -124,7 +124,6 @@ FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate @coroutine_with_priority(52.0) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - await ota_to_code(var, config) cg.add(var.set_port(config[CONF_PORT])) if CONF_PASSWORD in config: cg.add(var.set_auth_password(config[CONF_PASSWORD])) @@ -132,3 +131,4 @@ async def to_code(config): cg.add_define("USE_OTA_VERSION", config[CONF_VERSION]) await cg.register_component(var, config) + await ota_to_code(var, config) diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index d9917a2aae..627c55e910 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -92,6 +92,7 @@ async def to_code(config): async def ota_to_code(var, config): + await cg.past_safe_mode() use_state_callback = False for conf in config.get(CONF_ON_STATE_CHANGE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) From 122ff731ef43206212976da35354494e928639f6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 21 Nov 2024 14:41:31 -0600 Subject: [PATCH 022/139] Ensure storage I/O for ignored devices runs in the executor (#7792) --- esphome/dashboard/core.py | 2 +- esphome/dashboard/web_server.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/esphome/dashboard/core.py b/esphome/dashboard/core.py index 563ca1506d..f53cb7ffb1 100644 --- a/esphome/dashboard/core.py +++ b/esphome/dashboard/core.py @@ -103,7 +103,7 @@ class ESPHomeDashboard: self.loop = asyncio.get_running_loop() self.ping_request = asyncio.Event() self.entries = DashboardEntries(self) - self.load_ignored_devices() + await self.loop.run_in_executor(None, self.load_ignored_devices) def load_ignored_devices(self) -> None: storage_path = Path(ignored_devices_storage_path()) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index 07f7f019f8..0fed8e9c53 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -544,7 +544,7 @@ class ImportRequestHandler(BaseHandler): class IgnoreDeviceRequestHandler(BaseHandler): @authenticated - def post(self) -> None: + async def post(self) -> None: dashboard = DASHBOARD try: args = json.loads(self.request.body.decode()) @@ -576,7 +576,8 @@ class IgnoreDeviceRequestHandler(BaseHandler): else: dashboard.ignored_devices.discard(ignored_device.device_name) - dashboard.save_ignored_devices() + loop = asyncio.get_running_loop() + await loop.run_in_executor(None, dashboard.save_ignored_devices) self.set_status(204) self.finish() From dea297c8d7d73f0c4f366e58994cd6a9a3995e11 Mon Sep 17 00:00:00 2001 From: Petr Kejval Date: Sat, 23 Nov 2024 05:52:02 +0100 Subject: [PATCH 023/139] [nextion] Add publish actions (#7646) Co-authored-by: Keith Burzinski --- esphome/components/nextion/__init__.py | 2 + esphome/components/nextion/automation.h | 75 ++++- .../nextion/binary_sensor/__init__.py | 45 ++- esphome/components/nextion/sensor/__init__.py | 43 ++- esphome/components/nextion/switch/__init__.py | 40 ++- .../nextion/text_sensor/__init__.py | 39 ++- tests/components/nextion/common.yaml | 293 ++++++++++++++++++ tests/components/nextion/test.esp32-ard.yaml | 65 +--- .../components/nextion/test.esp32-c3-ard.yaml | 65 +--- .../components/nextion/test.esp32-c3-idf.yaml | 65 +--- tests/components/nextion/test.esp32-idf.yaml | 65 +--- .../components/nextion/test.esp8266-ard.yaml | 65 +--- tests/components/nextion/test.rp2040-ard.yaml | 61 +--- 13 files changed, 558 insertions(+), 365 deletions(-) create mode 100644 tests/components/nextion/common.yaml diff --git a/esphome/components/nextion/__init__.py b/esphome/components/nextion/__init__.py index 924d58198d..fb75daf4ba 100644 --- a/esphome/components/nextion/__init__.py +++ b/esphome/components/nextion/__init__.py @@ -6,3 +6,5 @@ Nextion = nextion_ns.class_("Nextion", cg.PollingComponent, uart.UARTDevice) nextion_ref = Nextion.operator("ref") CONF_NEXTION_ID = "nextion_id" +CONF_PUBLISH_STATE = "publish_state" +CONF_SEND_TO_NEXTION = "send_to_nextion" diff --git a/esphome/components/nextion/automation.h b/esphome/components/nextion/automation.h index 5182e07229..65f1fd0058 100644 --- a/esphome/components/nextion/automation.h +++ b/esphome/components/nextion/automation.h @@ -5,6 +5,13 @@ namespace esphome { namespace nextion { +class BufferOverflowTrigger : public Trigger<> { + public: + explicit BufferOverflowTrigger(Nextion *nextion) { + nextion->add_buffer_overflow_event_callback([this]() { this->trigger(); }); + } +}; + class SetupTrigger : public Trigger<> { public: explicit SetupTrigger(Nextion *nextion) { @@ -42,11 +49,73 @@ class TouchTrigger : public Trigger { } }; -class BufferOverflowTrigger : public Trigger<> { +template class NextionPublishFloatAction : public Action { public: - explicit BufferOverflowTrigger(Nextion *nextion) { - nextion->add_buffer_overflow_event_callback([this]() { this->trigger(); }); + explicit NextionPublishFloatAction(NextionComponent *component) : component_(component) {} + + TEMPLATABLE_VALUE(float, state) + TEMPLATABLE_VALUE(bool, publish_state) + TEMPLATABLE_VALUE(bool, send_to_nextion) + + void play(Ts... x) override { + this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...), + this->send_to_nextion_.value(x...)); } + + void set_state(std::function state) { this->state_ = state; } + void set_publish_state(std::function publish_state) { this->publish_state_ = publish_state; } + void set_send_to_nextion(std::function send_to_nextion) { + this->send_to_nextion_ = send_to_nextion; + } + + protected: + NextionComponent *component_; +}; + +template class NextionPublishTextAction : public Action { + public: + explicit NextionPublishTextAction(NextionComponent *component) : component_(component) {} + + TEMPLATABLE_VALUE(const char *, state) + TEMPLATABLE_VALUE(bool, publish_state) + TEMPLATABLE_VALUE(bool, send_to_nextion) + + void play(Ts... x) override { + this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...), + this->send_to_nextion_.value(x...)); + } + + void set_state(std::function state) { this->state_ = state; } + void set_publish_state(std::function publish_state) { this->publish_state_ = publish_state; } + void set_send_to_nextion(std::function send_to_nextion) { + this->send_to_nextion_ = send_to_nextion; + } + + protected: + NextionComponent *component_; +}; + +template class NextionPublishBoolAction : public Action { + public: + explicit NextionPublishBoolAction(NextionComponent *component) : component_(component) {} + + TEMPLATABLE_VALUE(bool, state) + TEMPLATABLE_VALUE(bool, publish_state) + TEMPLATABLE_VALUE(bool, send_to_nextion) + + void play(Ts... x) override { + this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...), + this->send_to_nextion_.value(x...)); + } + + void set_state(std::function state) { this->state_ = state; } + void set_publish_state(std::function publish_state) { this->publish_state_ = publish_state; } + void set_send_to_nextion(std::function send_to_nextion) { + this->send_to_nextion_ = send_to_nextion; + } + + protected: + NextionComponent *component_; }; } // namespace nextion diff --git a/esphome/components/nextion/binary_sensor/__init__.py b/esphome/components/nextion/binary_sensor/__init__.py index 8b4a45cc60..a257587e13 100644 --- a/esphome/components/nextion/binary_sensor/__init__.py +++ b/esphome/components/nextion/binary_sensor/__init__.py @@ -1,9 +1,16 @@ +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor -from esphome.const import CONF_COMPONENT_ID, CONF_PAGE_ID, CONF_ID -from .. import nextion_ns, CONF_NEXTION_ID +from esphome.const import ( + CONF_ID, + CONF_STATE, + CONF_COMPONENT_ID, + CONF_PAGE_ID, +) + +from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION from ..base_component import ( @@ -19,6 +26,10 @@ NextionBinarySensor = nextion_ns.class_( "NextionBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent ) +NextionPublishBoolAction = nextion_ns.class_( + "NextionPublishBoolAction", automation.Action +) + CONFIG_SCHEMA = cv.All( binary_sensor.binary_sensor_schema(NextionBinarySensor) .extend( @@ -52,3 +63,33 @@ async def to_code(config): if CONF_COMPONENT_NAME in config or CONF_VARIABLE_NAME in config: await setup_component_core_(var, config, ".val") cg.add(hub.register_binarysensor_component(var)) + + +@automation.register_action( + "binary_sensor.nextion.publish", + NextionPublishBoolAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(NextionBinarySensor), + cv.Required(CONF_STATE): cv.templatable(cv.boolean), + cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean), + cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable( + cv.boolean + ), + } + ), +) +async def sensor_nextion_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + template_ = await cg.templatable(config[CONF_STATE], args, bool) + cg.add(var.set_state(template_)) + + template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool) + cg.add(var.set_publish_state(template_)) + + template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool) + cg.add(var.set_send_to_nextion(template_)) + + return var diff --git a/esphome/components/nextion/sensor/__init__.py b/esphome/components/nextion/sensor/__init__.py index eefbe34d58..1058c2a04b 100644 --- a/esphome/components/nextion/sensor/__init__.py +++ b/esphome/components/nextion/sensor/__init__.py @@ -1,12 +1,11 @@ +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor -from esphome.const import ( - CONF_ID, - CONF_COMPONENT_ID, -) -from .. import nextion_ns, CONF_NEXTION_ID +from esphome.const import CONF_ID, CONF_COMPONENT_ID, CONF_STATE + +from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION from ..base_component import ( setup_component_core_, @@ -25,6 +24,10 @@ CODEOWNERS = ["@senexcrenshaw"] NextionSensor = nextion_ns.class_("NextionSensor", sensor.Sensor, cg.PollingComponent) +NextionPublishFloatAction = nextion_ns.class_( + "NextionPublishFloatAction", automation.Action +) + def CheckWaveID(value): value = cv.int_(value) @@ -95,3 +98,33 @@ async def to_code(config): if CONF_WAVE_MAX_LENGTH in config: cg.add(var.set_wave_max_length(config[CONF_WAVE_MAX_LENGTH])) + + +@automation.register_action( + "sensor.nextion.publish", + NextionPublishFloatAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(NextionSensor), + cv.Required(CONF_STATE): cv.templatable(cv.float_), + cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean), + cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable( + cv.boolean + ), + } + ), +) +async def sensor_nextion_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + template_ = await cg.templatable(config[CONF_STATE], args, float) + cg.add(var.set_state(template_)) + + template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool) + cg.add(var.set_publish_state(template_)) + + template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool) + cg.add(var.set_send_to_nextion(template_)) + + return var diff --git a/esphome/components/nextion/switch/__init__.py b/esphome/components/nextion/switch/__init__.py index 91ab0cc81f..de1a061478 100644 --- a/esphome/components/nextion/switch/__init__.py +++ b/esphome/components/nextion/switch/__init__.py @@ -1,9 +1,11 @@ +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import switch -from esphome.const import CONF_ID -from .. import nextion_ns, CONF_NEXTION_ID +from esphome.const import CONF_ID, CONF_STATE + +from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION from ..base_component import ( setup_component_core_, @@ -16,6 +18,10 @@ CODEOWNERS = ["@senexcrenshaw"] NextionSwitch = nextion_ns.class_("NextionSwitch", switch.Switch, cg.PollingComponent) +NextionPublishBoolAction = nextion_ns.class_( + "NextionPublishBoolAction", automation.Action +) + CONFIG_SCHEMA = cv.All( switch.switch_schema(NextionSwitch) .extend(CONFIG_SWITCH_COMPONENT_SCHEMA) @@ -33,3 +39,33 @@ async def to_code(config): cg.add(hub.register_switch_component(var)) await setup_component_core_(var, config, ".val") + + +@automation.register_action( + "switch.nextion.publish", + NextionPublishBoolAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(NextionSwitch), + cv.Required(CONF_STATE): cv.templatable(cv.boolean), + cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean), + cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable( + cv.boolean + ), + } + ), +) +async def sensor_nextion_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + template_ = await cg.templatable(config[CONF_STATE], args, bool) + cg.add(var.set_state(template_)) + + template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool) + cg.add(var.set_publish_state(template_)) + + template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool) + cg.add(var.set_send_to_nextion(template_)) + + return var diff --git a/esphome/components/nextion/text_sensor/__init__.py b/esphome/components/nextion/text_sensor/__init__.py index 826ff2354e..793397b1f4 100644 --- a/esphome/components/nextion/text_sensor/__init__.py +++ b/esphome/components/nextion/text_sensor/__init__.py @@ -1,9 +1,10 @@ +from esphome import automation from esphome.components import text_sensor import esphome.config_validation as cv import esphome.codegen as cg -from esphome.const import CONF_ID +from esphome.const import CONF_ID, CONF_STATE -from .. import nextion_ns, CONF_NEXTION_ID +from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION from ..base_component import ( setup_component_core_, @@ -16,6 +17,10 @@ NextionTextSensor = nextion_ns.class_( "NextionTextSensor", text_sensor.TextSensor, cg.PollingComponent ) +NextionPublishTextAction = nextion_ns.class_( + "NextionPublishTextAction", automation.Action +) + CONFIG_SCHEMA = ( text_sensor.text_sensor_schema(NextionTextSensor) .extend(CONFIG_TEXT_COMPONENT_SCHEMA) @@ -32,3 +37,33 @@ async def to_code(config): cg.add(hub.register_textsensor_component(var)) await setup_component_core_(var, config, ".txt") + + +@automation.register_action( + "text_sensor.nextion.publish", + NextionPublishTextAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(NextionTextSensor), + cv.Required(CONF_STATE): cv.templatable(cv.string_strict), + cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean), + cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable( + cv.boolean + ), + } + ), +) +async def sensor_nextion_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + template_ = await cg.templatable(config[CONF_STATE], args, cg.const_char_ptr) + cg.add(var.set_state(template_)) + + template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, cg.bool_) + cg.add(var.set_publish_state(template_)) + + template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, cg.bool_) + cg.add(var.set_send_to_nextion(template_)) + + return var diff --git a/tests/components/nextion/common.yaml b/tests/components/nextion/common.yaml new file mode 100644 index 0000000000..e84cd08422 --- /dev/null +++ b/tests/components/nextion/common.yaml @@ -0,0 +1,293 @@ +esphome: + on_boot: + # Binary sensor publish action tests + - binary_sensor.nextion.publish: + id: r0_sensor + state: True + + - binary_sensor.nextion.publish: + id: r0_sensor + state: True + publish_state: True + send_to_nextion: True + + - binary_sensor.nextion.publish: + id: r0_sensor + state: True + publish_state: False + send_to_nextion: True + + - binary_sensor.nextion.publish: + id: r0_sensor + state: True + publish_state: True + send_to_nextion: False + + - binary_sensor.nextion.publish: + id: r0_sensor + state: True + publish_state: False + send_to_nextion: False + + # Templated + - binary_sensor.nextion.publish: + id: r0_sensor + state: !lambda 'return true;' + + - binary_sensor.nextion.publish: + id: r0_sensor + state: !lambda 'return true;' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return true;' + + - binary_sensor.nextion.publish: + id: r0_sensor + state: !lambda 'return true;' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return true;' + + - binary_sensor.nextion.publish: + id: r0_sensor + state: !lambda 'return true;' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return false;' + + - binary_sensor.nextion.publish: + id: r0_sensor + state: !lambda 'return true;' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return false;' + + # Sensor publish action tests + - sensor.nextion.publish: + id: testnumber + state: 42.0 + + - sensor.nextion.publish: + id: testnumber + state: 42.0 + publish_state: True + send_to_nextion: True + + - sensor.nextion.publish: + id: testnumber + state: 42.0 + publish_state: False + send_to_nextion: True + + - sensor.nextion.publish: + id: testnumber + state: 42.0 + publish_state: True + send_to_nextion: False + + - sensor.nextion.publish: + id: testnumber + state: 42.0 + publish_state: False + send_to_nextion: False + + # Templated + - sensor.nextion.publish: + id: testnumber + state: !lambda 'return 42.0;' + + - sensor.nextion.publish: + id: testnumber + state: !lambda 'return 42.0;' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return true;' + + - sensor.nextion.publish: + id: testnumber + state: !lambda 'return 42.0;' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return true;' + + - sensor.nextion.publish: + id: testnumber + state: !lambda 'return 42.0;' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return false;' + + - sensor.nextion.publish: + id: testnumber + state: !lambda 'return 42.0;' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return false;' + + # Switch publish action tests + - switch.nextion.publish: + id: r0 + state: True + + - switch.nextion.publish: + id: r0 + state: True + publish_state: true + send_to_nextion: true + + - switch.nextion.publish: + id: r0 + state: True + publish_state: false + send_to_nextion: true + + - switch.nextion.publish: + id: r0 + state: True + publish_state: true + send_to_nextion: false + + - switch.nextion.publish: + id: r0 + state: True + publish_state: false + send_to_nextion: false + + # Templated + - switch.nextion.publish: + id: r0 + state: !lambda 'return true;' + + - switch.nextion.publish: + id: r0 + state: !lambda 'return true;' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return true;' + + - switch.nextion.publish: + id: r0 + state: !lambda 'return true;' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return true;' + + - switch.nextion.publish: + id: r0 + state: !lambda 'return true;' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return false;' + + - switch.nextion.publish: + id: r0 + state: !lambda 'return true;' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return false;' + + # Test sensor publish action tests + - text_sensor.nextion.publish: + id: text0 + state: 'Test' + publish_state: true + send_to_nextion: true + + - text_sensor.nextion.publish: + id: text0 + state: 'Test' + publish_state: false + send_to_nextion: true + + - text_sensor.nextion.publish: + id: text0 + state: 'Test' + publish_state: true + send_to_nextion: false + + - text_sensor.nextion.publish: + id: text0 + state: 'Test' + publish_state: false + send_to_nextion: false + + # Templated + - text_sensor.nextion.publish: + id: text0 + state: !lambda 'return "Test";' + + - text_sensor.nextion.publish: + id: text0 + state: !lambda 'return "Test";' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return true;' + + - text_sensor.nextion.publish: + id: text0 + state: !lambda 'return "Test";' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return true;' + + - text_sensor.nextion.publish: + id: text0 + state: !lambda 'return "Test";' + publish_state: !lambda 'return true;' + send_to_nextion: !lambda 'return false;' + + - text_sensor.nextion.publish: + id: text0 + state: !lambda 'return "Test";' + publish_state: !lambda 'return false;' + send_to_nextion: !lambda 'return false;' + +wifi: + ssid: MySSID + password: password1 + +uart: + - id: uart_nextion + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + baud_rate: 115200 + +binary_sensor: + - platform: nextion + page_id: 0 + component_id: 2 + name: Nextion Touch Component + - platform: nextion + id: r0_sensor + name: R0 Sensor + component_name: page0.r0 + +sensor: + - platform: nextion + id: testnumber + name: testnumber + variable_name: testnumber + - platform: nextion + id: testwave + name: testwave + component_id: 2 + wave_channel_id: 1 + +switch: + - platform: nextion + id: r0 + name: R0 Switch + component_name: page0.r0 + +text_sensor: + - platform: nextion + name: text0 + id: text0 + update_interval: 4s + component_name: text0 + +display: + - platform: nextion + id: main_lcd + update_interval: 5s + on_sleep: + then: + lambda: 'ESP_LOGD("display","Display went to sleep");' + on_wake: + then: + lambda: 'ESP_LOGD("display","Display woke up");' + on_setup: + then: + lambda: 'ESP_LOGD("display","Display setup completed");' + on_page: + then: + lambda: 'ESP_LOGD("display","Display shows new page %u", x);' + on_buffer_overflow: + then: + logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-ard.yaml b/tests/components/nextion/test.esp32-ard.yaml index ba76236fc6..d5e02b8b85 100644 --- a/tests/components/nextion/test.esp32-ard.yaml +++ b/tests/components/nextion/test.esp32-ard.yaml @@ -1,63 +1,10 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO17 + rx_pin: GPIO16 -uart: - - id: uart_nextion - tx_pin: 17 - rx_pin: 16 - baud_rate: 115200 - -binary_sensor: - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Touch Component - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 - -sensor: - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - -switch: - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -text_sensor: - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 +packages: + base: !include common.yaml display: - - platform: nextion + - id: !extend main_lcd tft_url: http://esphome.io/default35.tft - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - on_buffer_overflow: - then: - logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-c3-ard.yaml b/tests/components/nextion/test.esp32-c3-ard.yaml index 5d253268f8..5135c7e4f4 100644 --- a/tests/components/nextion/test.esp32-c3-ard.yaml +++ b/tests/components/nextion/test.esp32-c3-ard.yaml @@ -1,63 +1,10 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_nextion - tx_pin: 4 - rx_pin: 5 - baud_rate: 115200 - -binary_sensor: - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Touch Component - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 - -sensor: - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - -switch: - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -text_sensor: - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 +packages: + base: !include common.yaml display: - - platform: nextion + - id: !extend main_lcd tft_url: http://esphome.io/default35.tft - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - on_buffer_overflow: - then: - logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-c3-idf.yaml b/tests/components/nextion/test.esp32-c3-idf.yaml index 5d253268f8..5135c7e4f4 100644 --- a/tests/components/nextion/test.esp32-c3-idf.yaml +++ b/tests/components/nextion/test.esp32-c3-idf.yaml @@ -1,63 +1,10 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_nextion - tx_pin: 4 - rx_pin: 5 - baud_rate: 115200 - -binary_sensor: - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Touch Component - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 - -sensor: - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - -switch: - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -text_sensor: - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 +packages: + base: !include common.yaml display: - - platform: nextion + - id: !extend main_lcd tft_url: http://esphome.io/default35.tft - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - on_buffer_overflow: - then: - logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp32-idf.yaml b/tests/components/nextion/test.esp32-idf.yaml index ba76236fc6..d5e02b8b85 100644 --- a/tests/components/nextion/test.esp32-idf.yaml +++ b/tests/components/nextion/test.esp32-idf.yaml @@ -1,63 +1,10 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO17 + rx_pin: GPIO16 -uart: - - id: uart_nextion - tx_pin: 17 - rx_pin: 16 - baud_rate: 115200 - -binary_sensor: - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Touch Component - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 - -sensor: - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - -switch: - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -text_sensor: - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 +packages: + base: !include common.yaml display: - - platform: nextion + - id: !extend main_lcd tft_url: http://esphome.io/default35.tft - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - on_buffer_overflow: - then: - logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.esp8266-ard.yaml b/tests/components/nextion/test.esp8266-ard.yaml index 5d253268f8..5135c7e4f4 100644 --- a/tests/components/nextion/test.esp8266-ard.yaml +++ b/tests/components/nextion/test.esp8266-ard.yaml @@ -1,63 +1,10 @@ -wifi: - ssid: MySSID - password: password1 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -uart: - - id: uart_nextion - tx_pin: 4 - rx_pin: 5 - baud_rate: 115200 - -binary_sensor: - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Touch Component - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 - -sensor: - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - -switch: - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -text_sensor: - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 +packages: + base: !include common.yaml display: - - platform: nextion + - id: !extend main_lcd tft_url: http://esphome.io/default35.tft - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - on_buffer_overflow: - then: - logger.log: "Nextion reported a buffer overflow!" diff --git a/tests/components/nextion/test.rp2040-ard.yaml b/tests/components/nextion/test.rp2040-ard.yaml index 9b04433095..20347c6eff 100644 --- a/tests/components/nextion/test.rp2040-ard.yaml +++ b/tests/components/nextion/test.rp2040-ard.yaml @@ -1,58 +1,7 @@ -uart: - - id: uart_nextion - tx_pin: 4 - rx_pin: 5 - baud_rate: 115200 +substitutions: + tx_pin: GPIO4 + rx_pin: GPIO5 -binary_sensor: - - platform: nextion - page_id: 0 - component_id: 2 - name: Nextion Touch Component - - platform: nextion - id: r0_sensor - name: R0 Sensor - component_name: page0.r0 +packages: + base: !include common.yaml -sensor: - - platform: nextion - id: testnumber - name: testnumber - variable_name: testnumber - - platform: nextion - id: testwave - name: testwave - component_id: 2 - wave_channel_id: 1 - -switch: - - platform: nextion - id: r0 - name: R0 Switch - component_name: page0.r0 - -text_sensor: - - platform: nextion - name: text0 - id: text0 - update_interval: 4s - component_name: text0 - -display: - - platform: nextion - update_interval: 5s - on_sleep: - then: - lambda: 'ESP_LOGD("display","Display went to sleep");' - on_wake: - then: - lambda: 'ESP_LOGD("display","Display woke up");' - on_setup: - then: - lambda: 'ESP_LOGD("display","Display setup completed");' - on_page: - then: - lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - on_buffer_overflow: - then: - logger.log: "Nextion reported a buffer overflow!" From 2ecd5cff0701b807e5fa5558355c7beb7e6204ce Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Sun, 24 Nov 2024 21:16:51 +0100 Subject: [PATCH 024/139] [wifi] Make wifi_channel_() public (#7818) --- esphome/components/wifi/wifi_component.cpp | 4 ++-- esphome/components/wifi/wifi_component.h | 4 +++- esphome/components/wifi/wifi_component_esp32_arduino.cpp | 2 +- esphome/components/wifi/wifi_component_esp8266.cpp | 2 +- esphome/components/wifi/wifi_component_esp_idf.cpp | 2 +- esphome/components/wifi/wifi_component_libretiny.cpp | 2 +- esphome/components/wifi/wifi_component_pico_w.cpp | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 8788711d5a..eef962b8c4 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -444,7 +444,7 @@ void WiFiComponent::print_connect_params_() { 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, wifi_channel_()); + 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()); @@ -763,7 +763,7 @@ void WiFiComponent::load_fast_connect_settings_() { void WiFiComponent::save_fast_connect_settings_() { bssid_t bssid = wifi_bssid(); - uint8_t channel = wifi_channel_(); + uint8_t channel = get_wifi_channel(); if (bssid != this->selected_ap_.get_bssid() || channel != this->selected_ap_.get_channel()) { SavedWifiFastConnectSettings fast_connect_save{}; diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index dde0d1d5a5..5995f72e0b 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -317,6 +317,8 @@ class WiFiComponent : public Component { Trigger<> *get_connect_trigger() const { return this->connect_trigger_; }; Trigger<> *get_disconnect_trigger() const { return this->disconnect_trigger_; }; + int32_t get_wifi_channel(); + protected: static std::string format_mac_addr(const uint8_t mac[6]); @@ -344,7 +346,7 @@ class WiFiComponent : public Component { #endif // USE_WIFI_AP bool wifi_disconnect_(); - int32_t wifi_channel_(); + network::IPAddress wifi_subnet_mask_(); network::IPAddress wifi_gateway_ip_(); network::IPAddress wifi_dns_ip_(int num); diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 88648093c6..18c706cb01 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -799,7 +799,7 @@ bssid_t WiFiComponent::wifi_bssid() { } std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } -int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } +int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); } network::IPAddress WiFiComponent::wifi_subnet_mask_() { return network::IPAddress(WiFi.subnetMask()); } network::IPAddress WiFiComponent::wifi_gateway_ip_() { return network::IPAddress(WiFi.gatewayIP()); } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return network::IPAddress(WiFi.dnsIP(num)); } diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 4568895950..a18d078967 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -825,7 +825,7 @@ bssid_t WiFiComponent::wifi_bssid() { } std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } -int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } +int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); } network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {(const ip_addr_t *) WiFi.subnetMask()}; } network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t *) WiFi.gatewayIP()}; } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {(const ip_addr_t *) WiFi.dnsIP(num)}; } diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 13870136d4..1bf14ff40b 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -973,7 +973,7 @@ int8_t WiFiComponent::wifi_rssi() { } return info.rssi; } -int32_t WiFiComponent::wifi_channel_() { +int32_t WiFiComponent::get_wifi_channel() { uint8_t primary; wifi_second_chan_t second; esp_err_t err = esp_wifi_get_channel(&primary, &second); diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index afb30c3bcf..b02f8ef0ce 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -473,7 +473,7 @@ bssid_t WiFiComponent::wifi_bssid() { } std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } -int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } +int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); } network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask()}; } network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; } diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index bac986d899..23fd766abe 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -189,7 +189,7 @@ bssid_t WiFiComponent::wifi_bssid() { } std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); } int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); } -int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); } +int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); } network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() { network::IPAddresses addresses; From 4936ca17003404796d388363469badfab340d8b8 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:25:16 +1100 Subject: [PATCH 025/139] [lvgl] Bugfixes (#7803) --- esphome/components/lvgl/__init__.py | 2 +- esphome/components/lvgl/lv_validation.py | 3 ++- esphome/components/lvgl/schemas.py | 1 + esphome/components/lvgl/widgets/line.py | 5 ++++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index d03adc9624..8fdd03f647 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -322,8 +322,8 @@ async def to_code(configs): await encoders_to_code(lv_component, config, default_group) await keypads_to_code(lv_component, config, default_group) await theme_to_code(config) - await styles_to_code(config) await gradients_to_code(config) + await styles_to_code(config) await set_obj_properties(lv_scr_act, config) await add_widgets(lv_scr_act, config) await add_pages(lv_component, config) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index b91b0905df..766c010244 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -30,7 +30,7 @@ from .defines import ( call_lambda, literal, ) -from .helpers import esphome_fonts_used, lv_fonts_used, requires_component +from .helpers import add_lv_use, esphome_fonts_used, lv_fonts_used, requires_component from .types import lv_font_t, lv_gradient_t, lv_img_t opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") @@ -326,6 +326,7 @@ def image_validator(value): value = requires_component("image")(value) value = cv.use_id(Image_)(value) lv_images_used.add(value) + add_lv_use("img", "label") return value diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index 516627708e..3f56b3345f 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -341,6 +341,7 @@ FLEX_OBJ_SCHEMA = { cv.Optional(df.CONF_FLEX_GROW): cv.int_, } + DISP_BG_SCHEMA = cv.Schema( { cv.Optional(df.CONF_DISP_BG_IMAGE): lv_image, diff --git a/esphome/components/lvgl/widgets/line.py b/esphome/components/lvgl/widgets/line.py index 4c6439fde4..548dfa8452 100644 --- a/esphome/components/lvgl/widgets/line.py +++ b/esphome/components/lvgl/widgets/line.py @@ -39,7 +39,10 @@ LINE_SCHEMA = { class LineType(WidgetType): def __init__(self): super().__init__( - CONF_LINE, LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA, modify_schema={} + CONF_LINE, + LvType("lv_line_t"), + (CONF_MAIN,), + LINE_SCHEMA, ) async def to_code(self, w: Widget, config): From 4001d82ca269472b6ef813fa4b894e1071d5571e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:25:51 +1100 Subject: [PATCH 026/139] [docker] Leave run-time required libraries installed. (#7804) --- docker/Dockerfile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index ed6ce083a8..c2902a9dd1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -99,15 +99,17 @@ BUILD_DEPS=" libfreetype-dev=2.12.1+dfsg-5+deb12u3 libssl-dev=3.0.15-1~deb12u1 libffi-dev=3.4.4-1 - libopenjp2-7=2.5.0-2 - libtiff6=4.5.0-6+deb12u1 cargo=0.66.0+ds1-1 pkg-config=1.8.1-1 " +LIB_DEPS=" + libtiff6=4.5.0-6+deb12u1 + libopenjp2-7=2.5.0-2 +" if [ "$TARGETARCH$TARGETVARIANT" = "arm64" ] || [ "$TARGETARCH$TARGETVARIANT" = "armv7" ] then apt-get update - apt-get install -y --no-install-recommends $BUILD_DEPS + apt-get install -y --no-install-recommends $BUILD_DEPS $LIB_DEPS fi CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo From 13077095c2ece197c41c41324d578cb2a284edd8 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:27:09 +1100 Subject: [PATCH 027/139] [qspi_dbi] Fix init sequences (Bugfix) (#7805) --- esphome/components/qspi_dbi/models.py | 2 ++ esphome/components/qspi_dbi/qspi_dbi.cpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/qspi_dbi/models.py b/esphome/components/qspi_dbi/models.py index cbd9c4663f..c1fe434853 100644 --- a/esphome/components/qspi_dbi/models.py +++ b/esphome/components/qspi_dbi/models.py @@ -1,6 +1,7 @@ # Commands SW_RESET_CMD = 0x01 SLEEP_OUT = 0x11 +NORON = 0x13 INVERT_OFF = 0x20 INVERT_ON = 0x21 ALL_ON = 0x23 @@ -56,6 +57,7 @@ chip.cmd(0xC2, 0x00) chip.delay(10) chip.cmd(TEON, 0x00) chip.cmd(PIXFMT, 0x55) +chip.cmd(NORON) chip = DriverChip("AXS15231") chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5) diff --git a/esphome/components/qspi_dbi/qspi_dbi.cpp b/esphome/components/qspi_dbi/qspi_dbi.cpp index a649a25ea6..785885d4ec 100644 --- a/esphome/components/qspi_dbi/qspi_dbi.cpp +++ b/esphome/components/qspi_dbi/qspi_dbi.cpp @@ -111,7 +111,6 @@ void QspiDbi::reset_params_(bool ready) { mad |= MADCTL_MY; this->write_command_(MADCTL_CMD, mad); this->write_command_(BRIGHTNESS, this->brightness_); - this->write_command_(NORON); this->write_command_(DISPLAY_ON); } From e3e3d9234756b94a74f3788f64aa4d9b37d40f7a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 24 Nov 2024 10:42:46 -1000 Subject: [PATCH 028/139] fix modbus crashing when bad data returned (#7810) Co-authored-by: Samuel Sieb --- esphome/components/modbus/modbus.cpp | 3 +- .../modbus_controller/modbus_controller.cpp | 72 ++++++++++++++----- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index 8544b50261..47deea83e6 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -38,8 +38,9 @@ void Modbus::loop() { // stop blocking new send commands after sent_wait_time_ ms after response received if (now - this->last_send_ > send_wait_time_) { - if (waiting_for_response > 0) + if (waiting_for_response > 0) { ESP_LOGV(TAG, "Stop waiting for response from %d", waiting_for_response); + } waiting_for_response = 0; } } diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index e1102516ca..f8b72af817 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -622,51 +622,87 @@ int64_t payload_to_number(const std::vector &data, SensorValueType sens uint32_t bitmask) { int64_t value = 0; // int64_t because it can hold signed and unsigned 32 bits + size_t size = data.size() - offset; + bool error = false; switch (sensor_value_type) { case SensorValueType::U_WORD: - value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); // default is 0xFFFF ; + if (size >= 2) { + value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); // default is 0xFFFF ; + } else { + error = true; + } break; case SensorValueType::U_DWORD: case SensorValueType::FP32: - value = get_data(data, offset); - value = mask_and_shift_by_rightbit((uint32_t) value, bitmask); + if (size >= 4) { + value = get_data(data, offset); + value = mask_and_shift_by_rightbit((uint32_t) value, bitmask); + } else { + error = true; + } break; case SensorValueType::U_DWORD_R: case SensorValueType::FP32_R: - value = get_data(data, offset); - value = static_cast(value & 0xFFFF) << 16 | (value & 0xFFFF0000) >> 16; - value = mask_and_shift_by_rightbit((uint32_t) value, bitmask); + if (size >= 4) { + value = get_data(data, offset); + value = static_cast(value & 0xFFFF) << 16 | (value & 0xFFFF0000) >> 16; + value = mask_and_shift_by_rightbit((uint32_t) value, bitmask); + } else { + error = true; + } break; case SensorValueType::S_WORD: - value = mask_and_shift_by_rightbit(get_data(data, offset), - bitmask); // default is 0xFFFF ; + if (size >= 2) { + value = mask_and_shift_by_rightbit(get_data(data, offset), + bitmask); // default is 0xFFFF ; + } else { + error = true; + } break; case SensorValueType::S_DWORD: - value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); + if (size >= 4) { + value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); + } else { + error = true; + } break; case SensorValueType::S_DWORD_R: { - value = get_data(data, offset); - // Currently the high word is at the low position - // the sign bit is therefore at low before the switch - uint32_t sign_bit = (value & 0x8000) << 16; - value = mask_and_shift_by_rightbit( - static_cast(((value & 0x7FFF) << 16 | (value & 0xFFFF0000) >> 16) | sign_bit), bitmask); + if (size >= 4) { + value = get_data(data, offset); + // Currently the high word is at the low position + // the sign bit is therefore at low before the switch + uint32_t sign_bit = (value & 0x8000) << 16; + value = mask_and_shift_by_rightbit( + static_cast(((value & 0x7FFF) << 16 | (value & 0xFFFF0000) >> 16) | sign_bit), bitmask); + } else { + error = true; + } } break; case SensorValueType::U_QWORD: case SensorValueType::S_QWORD: // Ignore bitmask for QWORD - value = get_data(data, offset); + if (size >= 8) { + value = get_data(data, offset); + } else { + error = true; + } break; case SensorValueType::U_QWORD_R: case SensorValueType::S_QWORD_R: { // Ignore bitmask for QWORD - uint64_t tmp = get_data(data, offset); - value = (tmp << 48) | (tmp >> 48) | ((tmp & 0xFFFF0000) << 16) | ((tmp >> 16) & 0xFFFF0000); + if (size >= 8) { + uint64_t tmp = get_data(data, offset); + value = (tmp << 48) | (tmp >> 48) | ((tmp & 0xFFFF0000) << 16) | ((tmp >> 16) & 0xFFFF0000); + } else { + error = true; + } } break; case SensorValueType::RAW: default: break; } + if (error) + ESP_LOGE(TAG, "not enough data for value"); return value; } From 9fc1377b448fab25c91e3342834a0b38df0c4a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Mart=C3=ADn?= Date: Sun, 24 Nov 2024 23:06:21 +0100 Subject: [PATCH 029/139] feat(WiFi): Add wifi.configure action (#7335) --- esphome/components/wifi/__init__.py | 42 +++++++++++++ esphome/components/wifi/wifi_component.h | 79 ++++++++++++++++++++++++ tests/components/wifi/common.yaml | 7 +++ 3 files changed, 128 insertions(+) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index ea03cc16d1..ad1a4f5262 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -27,6 +27,7 @@ from esphome.const import ( CONF_NETWORKS, CONF_ON_CONNECT, CONF_ON_DISCONNECT, + CONF_ON_ERROR, CONF_PASSWORD, CONF_POWER_SAVE_MODE, CONF_PRIORITY, @@ -34,6 +35,7 @@ from esphome.const import ( CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, + CONF_TIMEOUT, CONF_TTLS_PHASE_2, CONF_USE_ADDRESS, CONF_USERNAME, @@ -46,6 +48,7 @@ from . import wpa2_eap AUTO_LOAD = ["network"] NO_WIFI_VARIANTS = [const.VARIANT_ESP32H2] +CONF_SAVE = "save" wifi_ns = cg.esphome_ns.namespace("wifi") EAPAuth = wifi_ns.struct("EAPAuth") @@ -63,6 +66,9 @@ WiFiConnectedCondition = wifi_ns.class_("WiFiConnectedCondition", Condition) WiFiEnabledCondition = wifi_ns.class_("WiFiEnabledCondition", Condition) WiFiEnableAction = wifi_ns.class_("WiFiEnableAction", automation.Action) WiFiDisableAction = wifi_ns.class_("WiFiDisableAction", automation.Action) +WiFiConfigureAction = wifi_ns.class_( + "WiFiConfigureAction", automation.Action, cg.Component +) def validate_password(value): @@ -483,3 +489,39 @@ async def wifi_enable_to_code(config, action_id, template_arg, args): @automation.register_action("wifi.disable", WiFiDisableAction, cv.Schema({})) async def wifi_disable_to_code(config, action_id, template_arg, args): return cg.new_Pvariable(action_id, template_arg) + + +@automation.register_action( + "wifi.configure", + WiFiConfigureAction, + cv.Schema( + { + cv.Required(CONF_SSID): cv.templatable(cv.ssid), + cv.Required(CONF_PASSWORD): cv.templatable(validate_password), + cv.Optional(CONF_SAVE, default=True): cv.templatable(cv.boolean), + cv.Optional(CONF_TIMEOUT, default="30000ms"): cv.templatable( + cv.positive_time_period_milliseconds + ), + cv.Optional(CONF_ON_CONNECT): automation.validate_automation(single=True), + cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True), + } + ), +) +async def wifi_set_sta_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + ssid = await cg.templatable(config[CONF_SSID], args, cg.std_string) + password = await cg.templatable(config[CONF_PASSWORD], args, cg.std_string) + save = await cg.templatable(config[CONF_SAVE], args, cg.bool_) + timeout = await cg.templatable(config.get(CONF_TIMEOUT), args, cg.uint32) + cg.add(var.set_ssid(ssid)) + cg.add(var.set_password(password)) + cg.add(var.set_save(save)) + cg.add(var.set_connection_timeout(timeout)) + if on_connect_config := config.get(CONF_ON_CONNECT): + await automation.build_automation( + var.get_connect_trigger(), [], on_connect_config + ) + if on_error_config := config.get(CONF_ON_ERROR): + await automation.build_automation(var.get_error_trigger(), [], on_error_config) + await cg.register_component(var, config) + return var diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index 5995f72e0b..abedfab3a6 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -209,6 +209,7 @@ class WiFiComponent : public Component { WiFiComponent(); void set_sta(const WiFiAP &ap); + WiFiAP get_sta() { return this->selected_ap_; } void add_sta(const WiFiAP &ap); void clear_sta(); @@ -443,6 +444,84 @@ template class WiFiDisableAction : public Action { void play(Ts... x) override { global_wifi_component->disable(); } }; +template class WiFiConfigureAction : public Action, public Component { + public: + TEMPLATABLE_VALUE(std::string, ssid) + TEMPLATABLE_VALUE(std::string, password) + TEMPLATABLE_VALUE(bool, save) + TEMPLATABLE_VALUE(uint32_t, connection_timeout) + + void play(Ts... x) override { + auto ssid = this->ssid_.value(x...); + auto password = this->password_.value(x...); + // Avoid multiple calls + if (this->connecting_) + return; + // If already connected to the same AP, do nothing + if (global_wifi_component->wifi_ssid() == ssid) { + // Callback to notify the user that the connection was successful + this->connect_trigger_->trigger(); + return; + } + // Create a new WiFiAP object with the new SSID and password + this->new_sta_.set_ssid(ssid); + this->new_sta_.set_password(password); + // Save the current STA + this->old_sta_ = global_wifi_component->get_sta(); + // Disable WiFi + global_wifi_component->disable(); + // Set the state to connecting + this->connecting_ = true; + // Store the new STA so once the WiFi is enabled, it will connect to it + // This is necessary because the WiFiComponent will raise an error and fallback to the saved STA + // if trying to connect to a new STA while already connected to another one + if (this->save_.value(x...)) { + global_wifi_component->save_wifi_sta(new_sta_.get_ssid(), new_sta_.get_password()); + } else { + global_wifi_component->set_sta(new_sta_); + } + // Enable WiFi + global_wifi_component->enable(); + // Set timeout for the connection + this->set_timeout("wifi-connect-timeout", this->connection_timeout_.value(x...), [this]() { + this->connecting_ = false; + // If the timeout is reached, stop connecting and revert to the old AP + global_wifi_component->disable(); + global_wifi_component->save_wifi_sta(old_sta_.get_ssid(), old_sta_.get_password()); + global_wifi_component->enable(); + // Callback to notify the user that the connection failed + this->error_trigger_->trigger(); + }); + } + + Trigger<> *get_connect_trigger() const { return this->connect_trigger_; } + Trigger<> *get_error_trigger() const { return this->error_trigger_; } + + void loop() override { + if (!this->connecting_) + return; + if (global_wifi_component->is_connected()) { + // The WiFi is connected, stop the timeout and reset the connecting flag + this->cancel_timeout("wifi-connect-timeout"); + this->connecting_ = false; + if (global_wifi_component->wifi_ssid() == this->new_sta_.get_ssid()) { + // Callback to notify the user that the connection was successful + this->connect_trigger_->trigger(); + } else { + // Callback to notify the user that the connection failed + this->error_trigger_->trigger(); + } + } + } + + protected: + bool connecting_{false}; + WiFiAP new_sta_; + WiFiAP old_sta_; + Trigger<> *connect_trigger_{new Trigger<>()}; + Trigger<> *error_trigger_{new Trigger<>()}; +}; + } // namespace wifi } // namespace esphome #endif diff --git a/tests/components/wifi/common.yaml b/tests/components/wifi/common.yaml index 003f6347be..343d44b177 100644 --- a/tests/components/wifi/common.yaml +++ b/tests/components/wifi/common.yaml @@ -3,6 +3,13 @@ esphome: then: - wifi.disable - wifi.enable + - wifi.configure: + ssid: MySSID + password: password1 + on_connect: + - logger.log: "Connected to WiFi!" + on_error: + - logger.log: "Failed to connect to WiFi!" wifi: ssid: MySSID From d4d630823ccc3bdddb6e6b39176c188d353d0807 Mon Sep 17 00:00:00 2001 From: TFGF Date: Sun, 24 Nov 2024 19:15:10 -0300 Subject: [PATCH 030/139] [Modbus Controller] Fix issue #6477. Online automation triggering Offline (#7801) --- esphome/components/modbus_controller/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 5c407d6fff..2a08075831 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -163,7 +163,7 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_ON_OFFLINE): automation.validate_automation( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ModbusOnlineTrigger), + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ModbusOfflineTrigger), } ), } From e02f3cdac7b7e8a58711763b5d7f9dfac8ea6991 Mon Sep 17 00:00:00 2001 From: Ramil Valitov Date: Mon, 25 Nov 2024 01:23:30 +0300 Subject: [PATCH 031/139] [fix] Status sensor does not check if required network component is missing (#7734) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/status/binary_sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/status/binary_sensor.py b/esphome/components/status/binary_sensor.py index 1f2b7c9d18..adc342ed4d 100644 --- a/esphome/components/status/binary_sensor.py +++ b/esphome/components/status/binary_sensor.py @@ -6,6 +6,8 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ) +DEPENDENCIES = ["network"] + status_ns = cg.esphome_ns.namespace("status") StatusBinarySensor = status_ns.class_( "StatusBinarySensor", binary_sensor.BinarySensor, cg.Component From 59653ec7853a349e9e736710867daedc017a725e Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 24 Nov 2024 12:40:28 -1000 Subject: [PATCH 032/139] allow multiple graphical menus (#7809) Co-authored-by: Samuel Sieb --- esphome/components/display_menu_base/__init__.py | 2 -- esphome/components/graphical_display_menu/__init__.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/display_menu_base/__init__.py b/esphome/components/display_menu_base/__init__.py index 8ae9cbc2a4..f9c0424104 100644 --- a/esphome/components/display_menu_base/__init__.py +++ b/esphome/components/display_menu_base/__init__.py @@ -68,8 +68,6 @@ IsActiveCondition = display_menu_base_ns.class_( "IsActiveCondition", automation.Condition ) -MULTI_CONF = True - MenuItemType = display_menu_base_ns.enum("MenuItemType") MENU_ITEM_TYPES = { diff --git a/esphome/components/graphical_display_menu/__init__.py b/esphome/components/graphical_display_menu/__init__.py index f4d59b22b8..56b720e75c 100644 --- a/esphome/components/graphical_display_menu/__init__.py +++ b/esphome/components/graphical_display_menu/__init__.py @@ -36,6 +36,8 @@ CODEOWNERS = ["@MrMDavidson"] AUTO_LOAD = ["display_menu_base"] +MULTI_CONF = True + CONFIG_SCHEMA = DISPLAY_MENU_BASE_SCHEMA.extend( cv.Schema( { From b95b4a069417ea6fd31f96b5e9150ca16dd1c3f5 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 24 Nov 2024 12:40:51 -1000 Subject: [PATCH 033/139] keypad binary sensors should be initially off (#7808) Co-authored-by: Samuel Sieb --- esphome/components/binary_sensor/binary_sensor.h | 2 +- .../matrix_keypad/binary_sensor/matrix_keypad_binary_sensor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index 301a472810..57cae9e2f5 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -58,7 +58,7 @@ class BinarySensor : public EntityBase, public EntityBase_DeviceClass { void publish_initial_state(bool state); /// The current reported state of the binary sensor. - bool state; + bool state{false}; void add_filter(Filter *filter); void add_filters(const std::vector &filters); diff --git a/esphome/components/matrix_keypad/binary_sensor/matrix_keypad_binary_sensor.h b/esphome/components/matrix_keypad/binary_sensor/matrix_keypad_binary_sensor.h index d8a217f55e..2c1ce96f0a 100644 --- a/esphome/components/matrix_keypad/binary_sensor/matrix_keypad_binary_sensor.h +++ b/esphome/components/matrix_keypad/binary_sensor/matrix_keypad_binary_sensor.h @@ -6,7 +6,7 @@ namespace esphome { namespace matrix_keypad { -class MatrixKeypadBinarySensor : public MatrixKeypadListener, public binary_sensor::BinarySensor { +class MatrixKeypadBinarySensor : public MatrixKeypadListener, public binary_sensor::BinarySensorInitiallyOff { public: MatrixKeypadBinarySensor(uint8_t key) : has_key_(true), key_(key){}; MatrixKeypadBinarySensor(const char *key) : has_key_(true), key_((uint8_t) key[0]){}; From 71496574e9e104433ded1f4da497454b1b266e3d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:26:36 +1300 Subject: [PATCH 034/139] Move ``CONF_NAME_ADD_MAC_SUFFIX`` to ``const.py`` (#7820) --- esphome/const.py | 1 + esphome/core/config.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/const.py b/esphome/const.py index 6a643e1e30..50528b7363 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -528,6 +528,7 @@ CONF_MULTIPLE = "multiple" CONF_MULTIPLEXER = "multiplexer" CONF_MULTIPLY = "multiply" CONF_NAME = "name" +CONF_NAME_ADD_MAC_SUFFIX = "name_add_mac_suffix" CONF_NAME_FONT = "name_font" CONF_NBITS = "nbits" CONF_NEC = "nec" diff --git a/esphome/core/config.py b/esphome/core/config.py index 367e61c413..eee8b73934 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -21,6 +21,7 @@ from esphome.const import ( CONF_LIBRARIES, CONF_MIN_VERSION, CONF_NAME, + CONF_NAME_ADD_MAC_SUFFIX, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, @@ -59,8 +60,6 @@ ProjectUpdateTrigger = cg.esphome_ns.class_( VERSION_REGEX = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(?:[ab]\d+)?$") -CONF_NAME_ADD_MAC_SUFFIX = "name_add_mac_suffix" - VALID_INCLUDE_EXTS = {".h", ".hpp", ".tcc", ".ino", ".cpp", ".c"} From c49f7293fef3c052691f388b6c9af6f8709b7aca Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sun, 24 Nov 2024 21:24:23 -1000 Subject: [PATCH 035/139] binary_sensor for switch state (#7819) --- CODEOWNERS | 1 + .../switch/binary_sensor/__init__.py | 31 +++++++++++++++++++ .../binary_sensor/switch_binary_sensor.cpp | 17 ++++++++++ .../binary_sensor/switch_binary_sensor.h | 22 +++++++++++++ tests/components/switch/common.yaml | 11 +++++++ tests/components/switch/test.bk72xx-ard.yaml | 2 ++ tests/components/switch/test.esp32-ard.yaml | 2 ++ .../components/switch/test.esp32-c3-ard.yaml | 2 ++ .../components/switch/test.esp32-c3-idf.yaml | 2 ++ tests/components/switch/test.esp32-idf.yaml | 2 ++ .../components/switch/test.esp32-s3-idf.yaml | 2 ++ tests/components/switch/test.esp8266-ard.yaml | 2 ++ tests/components/switch/test.rp2040-ard.yaml | 2 ++ 13 files changed, 98 insertions(+) create mode 100644 esphome/components/switch/binary_sensor/__init__.py create mode 100644 esphome/components/switch/binary_sensor/switch_binary_sensor.cpp create mode 100644 esphome/components/switch/binary_sensor/switch_binary_sensor.h create mode 100644 tests/components/switch/common.yaml create mode 100644 tests/components/switch/test.bk72xx-ard.yaml create mode 100644 tests/components/switch/test.esp32-ard.yaml create mode 100644 tests/components/switch/test.esp32-c3-ard.yaml create mode 100644 tests/components/switch/test.esp32-c3-idf.yaml create mode 100644 tests/components/switch/test.esp32-idf.yaml create mode 100644 tests/components/switch/test.esp32-s3-idf.yaml create mode 100644 tests/components/switch/test.esp8266-ard.yaml create mode 100644 tests/components/switch/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 8fbbacef59..dd3926d283 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -408,6 +408,7 @@ esphome/components/substitutions/* @esphome/core esphome/components/sun/* @OttoWinter esphome/components/sun_gtil2/* @Mat931 esphome/components/switch/* @esphome/core +esphome/components/switch/binary_sensor/* @ssieb esphome/components/t6615/* @tylermenezes esphome/components/tc74/* @sethgirvan esphome/components/tca9548a/* @andreashergert1984 diff --git a/esphome/components/switch/binary_sensor/__init__.py b/esphome/components/switch/binary_sensor/__init__.py new file mode 100644 index 0000000000..61ca1a14a2 --- /dev/null +++ b/esphome/components/switch/binary_sensor/__init__.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +from esphome.components import binary_sensor +import esphome.config_validation as cv +from esphome.const import CONF_SOURCE_ID + +from .. import Switch, switch_ns + +CODEOWNERS = ["@ssieb"] + +SwitchBinarySensor = switch_ns.class_( + "SwitchBinarySensor", binary_sensor.BinarySensor, cg.Component +) + + +CONFIG_SCHEMA = ( + binary_sensor.binary_sensor_schema(SwitchBinarySensor) + .extend( + { + cv.Required(CONF_SOURCE_ID): cv.use_id(Switch), + } + ) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = await binary_sensor.new_binary_sensor(config) + await cg.register_component(var, config) + + source = await cg.get_variable(config[CONF_SOURCE_ID]) + cg.add(var.set_source(source)) diff --git a/esphome/components/switch/binary_sensor/switch_binary_sensor.cpp b/esphome/components/switch/binary_sensor/switch_binary_sensor.cpp new file mode 100644 index 0000000000..ba57154446 --- /dev/null +++ b/esphome/components/switch/binary_sensor/switch_binary_sensor.cpp @@ -0,0 +1,17 @@ +#include "switch_binary_sensor.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace switch_ { + +static const char *const TAG = "switch.binary_sensor"; + +void SwitchBinarySensor::setup() { + source_->add_on_state_callback([this](bool value) { this->publish_state(value); }); + this->publish_state(source_->state); +} + +void SwitchBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Switch Binary Sensor", this); } + +} // namespace switch_ +} // namespace esphome diff --git a/esphome/components/switch/binary_sensor/switch_binary_sensor.h b/esphome/components/switch/binary_sensor/switch_binary_sensor.h new file mode 100644 index 0000000000..5a947c2fb4 --- /dev/null +++ b/esphome/components/switch/binary_sensor/switch_binary_sensor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../switch.h" +#include "esphome/core/component.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace switch_ { + +class SwitchBinarySensor : public binary_sensor::BinarySensor, public Component { + public: + void set_source(Switch *source) { source_ = source; } + void setup() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + + protected: + Switch *source_; +}; + +} // namespace switch_ +} // namespace esphome diff --git a/tests/components/switch/common.yaml b/tests/components/switch/common.yaml new file mode 100644 index 0000000000..8d6972f91b --- /dev/null +++ b/tests/components/switch/common.yaml @@ -0,0 +1,11 @@ +binary_sensor: + - platform: switch + id: some_binary_sensor + name: "Template Switch State" + source_id: the_switch + +switch: + - platform: template + name: "Template Switch" + id: the_switch + optimistic: true diff --git a/tests/components/switch/test.bk72xx-ard.yaml b/tests/components/switch/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.bk72xx-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.esp32-ard.yaml b/tests/components/switch/test.esp32-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.esp32-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.esp32-c3-ard.yaml b/tests/components/switch/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.esp32-c3-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.esp32-c3-idf.yaml b/tests/components/switch/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.esp32-c3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.esp32-idf.yaml b/tests/components/switch/test.esp32-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.esp32-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.esp32-s3-idf.yaml b/tests/components/switch/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.esp32-s3-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.esp8266-ard.yaml b/tests/components/switch/test.esp8266-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.esp8266-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml diff --git a/tests/components/switch/test.rp2040-ard.yaml b/tests/components/switch/test.rp2040-ard.yaml new file mode 100644 index 0000000000..25cb37a0b4 --- /dev/null +++ b/tests/components/switch/test.rp2040-ard.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common.yaml From 7f75f2135d74c6daaaf5251c12a3a1f986ec6694 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 02:22:50 -0600 Subject: [PATCH 036/139] [nextion] Remove assignment within `if` (#7824) --- esphome/components/nextion/nextion_upload_idf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp index b5bb5478c1..7541a57d56 100644 --- a/esphome/components/nextion/nextion_upload_idf.cpp +++ b/esphome/components/nextion/nextion_upload_idf.cpp @@ -36,8 +36,8 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r ESP_LOGV(TAG, "Requesting range: %s", range_header); esp_http_client_set_header(http_client, "Range", range_header); ESP_LOGV(TAG, "Opening HTTP connetion"); - esp_err_t err; - if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) { + 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)); return -1; } From 6c548a15966b0486226d0fd7c33a105b6776d3f4 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 02:23:00 -0600 Subject: [PATCH 037/139] [ota] `void` functions should return nothing (#7825) --- esphome/components/ota/automation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/ota/automation.h b/esphome/components/ota/automation.h index 4605193480..7e1a60f3ce 100644 --- a/esphome/components/ota/automation.h +++ b/esphome/components/ota/automation.h @@ -12,7 +12,7 @@ class OTAStateChangeTrigger : public Trigger { explicit OTAStateChangeTrigger(OTAComponent *parent) { parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { if (!parent->is_failed()) { - return trigger(state); + trigger(state); } }); } From 46a435f5f2ec8f8dfb306f953280b5b2be265195 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 02:24:35 -0600 Subject: [PATCH 038/139] [safe_mode] Remove unused capture (#7826) --- esphome/components/safe_mode/automation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/safe_mode/automation.h b/esphome/components/safe_mode/automation.h index d1388449ee..1ffa86a588 100644 --- a/esphome/components/safe_mode/automation.h +++ b/esphome/components/safe_mode/automation.h @@ -9,7 +9,7 @@ namespace safe_mode { class SafeModeTrigger : public Trigger<> { public: explicit SafeModeTrigger(SafeModeComponent *parent) { - parent->add_on_safe_mode_callback([this, parent]() { trigger(); }); + parent->add_on_safe_mode_callback([this]() { trigger(); }); } }; From ebf895990b494ec8c09b7dbab051b0d53cc2d029 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 02:25:04 -0600 Subject: [PATCH 039/139] [stepper] Remove unnecessary ``#include`` (#7827) --- esphome/components/stepper/stepper.h | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/stepper/stepper.h b/esphome/components/stepper/stepper.h index 560362e4d0..ba2b3182d7 100644 --- a/esphome/components/stepper/stepper.h +++ b/esphome/components/stepper/stepper.h @@ -2,7 +2,6 @@ #include "esphome/core/component.h" #include "esphome/core/automation.h" -#include "esphome/components/stepper/stepper.h" namespace esphome { namespace stepper { From aa6cea6f7e4ea4b656fa6d3a152581e623227bd3 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 02:27:36 -0600 Subject: [PATCH 040/139] [sx1509] Fix up includes (#7828) --- esphome/components/sx1509/sx1509_gpio_pin.cpp | 3 ++- esphome/components/sx1509/sx1509_gpio_pin.h | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/esphome/components/sx1509/sx1509_gpio_pin.cpp b/esphome/components/sx1509/sx1509_gpio_pin.cpp index 56b51ae311..a74c8b60b8 100644 --- a/esphome/components/sx1509/sx1509_gpio_pin.cpp +++ b/esphome/components/sx1509/sx1509_gpio_pin.cpp @@ -1,5 +1,6 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "sx1509.h" #include "sx1509_gpio_pin.h" namespace esphome { @@ -13,7 +14,7 @@ bool SX1509GPIOPin::digital_read() { return this->parent_->digital_read(this->pi void SX1509GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } std::string SX1509GPIOPin::dump_summary() const { char buffer[32]; - snprintf(buffer, sizeof(buffer), "%u via sx1509", pin_); + snprintf(buffer, sizeof(buffer), "%u via sx1509", this->pin_); return buffer; } diff --git a/esphome/components/sx1509/sx1509_gpio_pin.h b/esphome/components/sx1509/sx1509_gpio_pin.h index 4d8aa5ec83..1cfa341ee7 100644 --- a/esphome/components/sx1509/sx1509_gpio_pin.h +++ b/esphome/components/sx1509/sx1509_gpio_pin.h @@ -1,6 +1,6 @@ #pragma once -#include "sx1509.h" +#include "esphome/core/gpio.h" namespace esphome { namespace sx1509 { @@ -15,10 +15,10 @@ class SX1509GPIOPin : public GPIOPin { void digital_write(bool value) override; std::string dump_summary() const override; - void set_parent(SX1509Component *parent) { parent_ = parent; } - void set_pin(uint8_t pin) { pin_ = pin; } - void set_inverted(bool inverted) { inverted_ = inverted; } - void set_flags(gpio::Flags flags) { flags_ = flags; } + void set_parent(SX1509Component *parent) { this->parent_ = parent; } + void set_pin(uint8_t pin) { this->pin_ = pin; } + void set_inverted(bool inverted) { this->inverted_ = inverted; } + void set_flags(gpio::Flags flags) { this->flags_ = flags; } protected: SX1509Component *parent_; From 1bd2d41ffd1273eefa03aa331944d7f47d5cd7c9 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 02:39:22 -0600 Subject: [PATCH 041/139] [uart] `void` functions should return nothing (#7829) --- esphome/components/uart/uart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/uart/uart.h b/esphome/components/uart/uart.h index d41dbe26e6..dc6962fbae 100644 --- a/esphome/components/uart/uart.h +++ b/esphome/components/uart/uart.h @@ -40,7 +40,7 @@ class UARTDevice { int available() { return this->parent_->available(); } - void flush() { return this->parent_->flush(); } + void flush() { this->parent_->flush(); } // Compat APIs int read() { From 17a09cd22151d95d510c858253b78dadae8e53e8 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 03:50:18 -0600 Subject: [PATCH 042/139] [audio] Header modernization (#7832) --- esphome/components/audio/audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/audio/audio.h b/esphome/components/audio/audio.h index b0968dc8da..caf325cf54 100644 --- a/esphome/components/audio/audio.h +++ b/esphome/components/audio/audio.h @@ -1,7 +1,7 @@ #pragma once +#include #include -#include namespace esphome { namespace audio { From cf835d15806481c50361cd6d8d193cc7b0b0175e Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 03:50:24 -0600 Subject: [PATCH 043/139] [opentherm] Follow variable naming convention (#7833) --- esphome/components/opentherm/opentherm.cpp | 6 +++--- esphome/components/opentherm/opentherm.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index 26c707f9a0..78ecb53428 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -29,7 +29,7 @@ using std::to_string; static const char *const TAG = "opentherm"; #ifdef ESP8266 -OpenTherm *OpenTherm::instance_ = nullptr; +OpenTherm *OpenTherm::instance = nullptr; #endif OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout) @@ -53,7 +53,7 @@ OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t bool OpenTherm::initialize() { #ifdef ESP8266 - OpenTherm::instance_ = this; + OpenTherm::instance = this; #endif this->in_pin_->pin_mode(gpio::FLAG_INPUT); this->out_pin_->pin_mode(gpio::FLAG_OUTPUT); @@ -216,7 +216,7 @@ bool IRAM_ATTR OpenTherm::timer_isr(OpenTherm *arg) { } #ifdef ESP8266 -void IRAM_ATTR OpenTherm::esp8266_timer_isr() { OpenTherm::timer_isr(OpenTherm::instance_); } +void IRAM_ATTR OpenTherm::esp8266_timer_isr() { OpenTherm::timer_isr(OpenTherm::instance); } #endif void IRAM_ATTR OpenTherm::bit_read_(uint8_t value) { diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index 85f4611125..5088bb2aa3 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -371,7 +371,7 @@ class OpenTherm { #ifdef ESP8266 // ESP8266 timer can accept callback with no parameters, so we have this hack to save a static instance of OpenTherm - static OpenTherm *instance_; + static OpenTherm *instance; #endif }; From 89ecfc20049d2358ecdbe63dacaed9143c9d9ed5 Mon Sep 17 00:00:00 2001 From: Oleg Tarasov Date: Tue, 26 Nov 2024 00:47:01 +0300 Subject: [PATCH 044/139] [opentherm] Fix out of memory errors on ESP8266 (#7835) --- esphome/components/opentherm/hub.cpp | 13 ++++---- esphome/components/opentherm/opentherm.cpp | 36 ++++++---------------- esphome/components/opentherm/opentherm.h | 7 ++--- esphome/core/helpers.cpp | 12 ++++++++ esphome/core/helpers.h | 8 +++++ 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/esphome/components/opentherm/hub.cpp b/esphome/components/opentherm/hub.cpp index dfa8ea95c5..aac2966ed1 100644 --- a/esphome/components/opentherm/hub.cpp +++ b/esphome/components/opentherm/hub.cpp @@ -138,7 +138,7 @@ OpenthermHub::OpenthermHub() : Component(), in_pin_{}, out_pin_{} {} void OpenthermHub::process_response(OpenthermData &data) { ESP_LOGD(TAG, "Received OpenTherm response with id %d (%s)", data.id, this->opentherm_->message_id_to_str((MessageId) data.id)); - ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(data).c_str()); + this->opentherm_->debug_data(data); switch (data.id) { OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_RESPONSE_MESSAGE, OPENTHERM_MESSAGE_RESPONSE_ENTITY, , @@ -315,7 +315,7 @@ void OpenthermHub::start_conversation_() { ESP_LOGD(TAG, "Sending request with id %d (%s)", request.id, this->opentherm_->message_id_to_str((MessageId) request.id)); - ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(request).c_str()); + this->opentherm_->debug_data(request); // Send the request this->last_conversation_start_ = millis(); this->opentherm_->send(request); @@ -340,19 +340,18 @@ void OpenthermHub::stop_opentherm_() { this->opentherm_->stop(); this->last_conversation_end_ = millis(); } - void OpenthermHub::handle_protocol_write_error_() { ESP_LOGW(TAG, "Error while sending request: %s", this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode())); - ESP_LOGW(TAG, "%s", this->opentherm_->debug_data(this->last_request_).c_str()); + this->opentherm_->debug_data(this->last_request_); } - void OpenthermHub::handle_protocol_read_error_() { OpenThermError error; this->opentherm_->get_protocol_error(error); - ESP_LOGW(TAG, "Protocol error occured while receiving response: %s", this->opentherm_->debug_error(error).c_str()); + ESP_LOGW(TAG, "Protocol error occured while receiving response: %s", + this->opentherm_->protocol_error_to_to_str(error.error_type)); + this->opentherm_->debug_error(error); } - void OpenthermHub::handle_timeout_error_() { ESP_LOGW(TAG, "Receive response timed out at a protocol level"); this->stop_opentherm_(); diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index 78ecb53428..e40fc66b7d 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -15,15 +15,11 @@ #include "Arduino.h" #endif #include -#include -#include namespace esphome { namespace opentherm { using std::string; -using std::bitset; -using std::stringstream; using std::to_string; static const char *const TAG = "opentherm"; @@ -545,29 +541,17 @@ const char *OpenTherm::message_id_to_str(MessageId id) { } } -string OpenTherm::debug_data(OpenthermData &data) { - stringstream result; - result << bitset<8>(data.type) << " " << bitset<8>(data.id) << " " << bitset<8>(data.valueHB) << " " - << bitset<8>(data.valueLB) << "\n"; - result << "type: " << this->message_type_to_str((MessageType) data.type) << "; "; - result << "id: " << to_string(data.id) << "; "; - result << "HB: " << to_string(data.valueHB) << "; "; - result << "LB: " << to_string(data.valueLB) << "; "; - result << "uint_16: " << to_string(data.u16()) << "; "; - result << "float: " << to_string(data.f88()); - - return result.str(); +void OpenTherm::debug_data(OpenthermData &data) { + ESP_LOGD(TAG, "%s %s %s %s", format_bin(data.type).c_str(), format_bin(data.id).c_str(), + format_bin(data.valueHB).c_str(), format_bin(data.valueLB).c_str()); + ESP_LOGD(TAG, "type: %s; id: %s; HB: %s; LB: %s; uint_16: %s; float: %s", + this->message_type_to_str((MessageType) data.type), to_string(data.id).c_str(), + to_string(data.valueHB).c_str(), to_string(data.valueLB).c_str(), to_string(data.u16()).c_str(), + to_string(data.f88()).c_str()); } -std::string OpenTherm::debug_error(OpenThermError &error) { - stringstream result; - result << "type: " << this->protocol_error_to_to_str(error.error_type) << "; "; - result << "data: "; - result << format_hex(error.data); - result << "; clock: " << to_string(clock_); - result << "; capture: " << bitset<32>(error.capture); - result << "; bit_pos: " << to_string(error.bit_pos); - - return result.str(); +void OpenTherm::debug_error(OpenThermError &error) const { + ESP_LOGD(TAG, "data: %s; clock: %s; capture: %s; bit_pos: %s", format_hex(error.data).c_str(), + to_string(clock_).c_str(), format_bin(error.capture).c_str(), to_string(error.bit_pos).c_str()); } float OpenthermData::f88() { return ((float) this->s16()) / 256.0; } diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index 5088bb2aa3..9532a77821 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -8,10 +8,9 @@ #pragma once #include -#include -#include #include "esphome/core/hal.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" #if defined(ESP32) || defined(USE_ESP_IDF) #include "driver/timer.h" @@ -318,8 +317,8 @@ class OpenTherm { OperationMode get_mode() { return mode_; } - std::string debug_data(OpenthermData &data); - std::string debug_error(OpenThermError &error); + void debug_data(OpenthermData &data); + void debug_error(OpenThermError &error) const; const char *protocol_error_to_to_str(ProtocolErrorType error_type); const char *message_type_to_str(MessageType message_type); diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index dae60a4e1d..befc84516c 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -397,6 +397,18 @@ std::string format_hex_pretty(const uint16_t *data, size_t length) { } std::string format_hex_pretty(const std::vector &data) { return format_hex_pretty(data.data(), data.size()); } +std::string format_bin(const uint8_t *data, size_t length) { + std::string result; + result.resize(length * 8); + for (size_t byte_idx = 0; byte_idx < length; byte_idx++) { + for (size_t bit_idx = 0; bit_idx < 8; bit_idx++) { + result[byte_idx * 8 + bit_idx] = ((data[byte_idx] >> (7 - bit_idx)) & 1) + '0'; + } + } + + return result; +} + ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) { if (on == nullptr && strcasecmp(str, "on") == 0) return PARSE_ON; diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 43001bafdd..305ec47f76 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -420,6 +420,14 @@ template::value, int> = 0> std::stri return format_hex_pretty(reinterpret_cast(&val), sizeof(T)); } +/// Format the byte array \p data of length \p len in binary. +std::string format_bin(const uint8_t *data, size_t length); +/// Format an unsigned integer in binary, starting with the most significant byte. +template::value, int> = 0> std::string format_bin(T val) { + val = convert_big_endian(val); + return format_bin(reinterpret_cast(&val), sizeof(T)); +} + /// Return values for parse_on_off(). enum ParseOnOffState { PARSE_NONE = 0, From b027b6a711be401153847ca6607a4f7b90bc6688 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 15:57:40 -0600 Subject: [PATCH 045/139] [opentherm] Add nolint for 8266 static global (#7837) --- esphome/components/opentherm/opentherm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index 9532a77821..3be0191c63 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -370,7 +370,7 @@ class OpenTherm { #ifdef ESP8266 // ESP8266 timer can accept callback with no parameters, so we have this hack to save a static instance of OpenTherm - static OpenTherm *instance; + static OpenTherm *instance; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) #endif }; From bdb91112eada52df7c31a0b86e2f6f3b16ab9a49 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 16:20:03 -0600 Subject: [PATCH 046/139] [helpers] Add NOLINT for Mutex private field ``handle_`` (#7838) --- esphome/core/helpers.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 305ec47f76..fcbd8d8683 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -565,7 +565,8 @@ class Mutex { #if defined(USE_ESP32) || defined(USE_LIBRETINY) SemaphoreHandle_t handle_; #else - void *handle_; // d-pointer to store private data on new platforms + // d-pointer to store private data on new platforms + void *handle_; // NOLINT(clang-diagnostic-unused-private-field) #endif }; From d6f4f0509081ea38cfe799806c8225903e6cd1be Mon Sep 17 00:00:00 2001 From: programmingbgloDE <47243850+programmingbgloDE@users.noreply.github.com> Date: Mon, 25 Nov 2024 23:26:48 +0100 Subject: [PATCH 047/139] Add waveshare 1 45 in v2 b support (#7052) --- .../components/waveshare_epaper/display.py | 4 + .../waveshare_epaper/waveshare_epaper.cpp | 84 +++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 18 ++++ 3 files changed, 106 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 8287788de5..fbb5e1353d 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -27,6 +27,9 @@ WaveshareEPaperBWR = waveshare_epaper_ns.class_( WaveshareEPaperTypeA = waveshare_epaper_ns.class_( "WaveshareEPaperTypeA", WaveshareEPaper ) +WaveshareEpaper1P54INBV2 = waveshare_epaper_ns.class_( + "WaveshareEPaper1P54InBV2", WaveshareEPaperBWR +) WaveshareEPaper2P7In = waveshare_epaper_ns.class_( "WaveshareEPaper2P7In", WaveshareEPaper ) @@ -105,6 +108,7 @@ WaveshareEPaperTypeBModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeBModel" MODELS = { "1.54in": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_1_54_IN), "1.54inv2": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_1_54_IN_V2), + "1.54inv2-b": ("b", WaveshareEpaper1P54INBV2), "2.13in": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_13_IN), "2.13inv2": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_13_IN_V2), "2.13in-ttgo": ("a", WaveshareEPaperTypeAModel.TTGO_EPAPER_2_13_IN), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 7c1d436673..1e27d594b8 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -808,6 +808,90 @@ void WaveshareEPaper2P7InV2::dump_config() { LOG_UPDATE_INTERVAL(this); } +// ======================================================== +// 1.54inch_v2_e-paper_b +// ======================================================== +// Datasheet: +// - https://files.waveshare.com/upload/9/9e/1.54inch-e-paper-b-v2-specification.pdf +// - https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)_Manual + +void WaveshareEPaper1P54InBV2::initialize() { + this->reset_(); + + this->wait_until_idle_(); + + this->command(0x12); + this->wait_until_idle_(); + + this->command(0x01); + this->data(0xC7); + this->data(0x00); + this->data(0x01); + + this->command(0x11); // data entry mode + this->data(0x01); + + this->command(0x44); // set Ram-X address start/end position + this->data(0x00); + this->data(0x18); // 0x18-->(24+1)*8=200 + + this->command(0x45); // set Ram-Y address start/end position + this->data(0xC7); // 0xC7-->(199+1)=200 + this->data(0x00); + this->data(0x00); + this->data(0x00); + + this->command(0x3C); // BorderWavefrom + this->data(0x05); + + this->command(0x18); // Read built-in temperature sensor + this->data(0x80); + + this->command(0x4E); // set RAM x address count to 0; + this->data(0x00); + this->command(0x4F); // set RAM y address count to 0X199; + this->data(0xC7); + this->data(0x00); + + this->wait_until_idle_(); +} + +void HOT WaveshareEPaper1P54InBV2::display() { + uint32_t buf_len_half = this->get_buffer_length_() >> 1; + this->initialize(); + + // COMMAND DATA START TRANSMISSION 1 (BLACK) + this->command(0x24); + delay(2); + for (uint32_t i = 0; i < buf_len_half; i++) { + this->data(~this->buffer_[i]); + } + delay(2); + + // COMMAND DATA START TRANSMISSION 2 (RED) + this->command(0x26); + delay(2); + for (uint32_t i = buf_len_half; i < buf_len_half * 2u; i++) { + this->data(this->buffer_[i]); + } + this->command(0x22); + this->data(0xf7); + this->command(0x20); + this->wait_until_idle_(); + + this->deep_sleep(); +} +int WaveshareEPaper1P54InBV2::get_height_internal() { return 200; } +int WaveshareEPaper1P54InBV2::get_width_internal() { return 200; } +void WaveshareEPaper1P54InBV2::dump_config() { + LOG_DISPLAY("", "Waveshare E-Paper", this); + ESP_LOGCONFIG(TAG, " Model: 1.54in V2 B"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} + // ======================================================== // 2.7inch_e-paper_b // ======================================================== diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 7572982a20..a319b078d0 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -166,6 +166,24 @@ enum WaveshareEPaperTypeBModel { WAVESHARE_EPAPER_13_3_IN_K, }; +class WaveshareEPaper1P54InBV2 : public WaveshareEPaperBWR { + public: + void initialize() override; + + void display() override; + + void dump_config() override; + + void deep_sleep() override { + this->command(0x10); + this->data(0x01); + } + + protected: + int get_width_internal() override; + int get_height_internal() override; +}; + class WaveshareEPaper2P7In : public WaveshareEPaper { public: void initialize() override; From 140d77061b33895054b35c6e1245fe4217f81a1e Mon Sep 17 00:00:00 2001 From: JonasB2497 <45214989+JonasB2497@users.noreply.github.com> Date: Mon, 25 Nov 2024 23:29:58 +0100 Subject: [PATCH 048/139] added Waveshare BWR Mode for the 7.5in Display (#7687) --- .../components/waveshare_epaper/display.py | 4 + .../waveshare_epaper/waveshare_epaper.cpp | 107 ++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 38 +++++++ .../waveshare_epaper/test.esp32-ard.yaml | 17 +++ .../waveshare_epaper/test.esp32-c3-ard.yaml | 16 +++ .../waveshare_epaper/test.esp32-c3-idf.yaml | 16 +++ .../waveshare_epaper/test.esp32-idf.yaml | 16 +++ .../waveshare_epaper/test.esp8266-ard.yaml | 16 +++ .../waveshare_epaper/test.rp2040-ard.yaml | 16 +++ 9 files changed, 246 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index fbb5e1353d..d5240b2674 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -79,6 +79,9 @@ WaveshareEPaper7P5InBV2 = waveshare_epaper_ns.class_( WaveshareEPaper7P5InBV3 = waveshare_epaper_ns.class_( "WaveshareEPaper7P5InBV3", WaveshareEPaper ) +WaveshareEPaper7P5InBV3BWR = waveshare_epaper_ns.class_( + "WaveshareEPaper7P5InBV3BWR", WaveshareEPaperBWR +) WaveshareEPaper7P5InV2 = waveshare_epaper_ns.class_( "WaveshareEPaper7P5InV2", WaveshareEPaper ) @@ -133,6 +136,7 @@ MODELS = { "7.50in": ("b", WaveshareEPaper7P5In), "7.50in-bv2": ("b", WaveshareEPaper7P5InBV2), "7.50in-bv3": ("b", WaveshareEPaper7P5InBV3), + "7.50in-bv3-bwr": ("b", WaveshareEPaper7P5InBV3BWR), "7.50in-bc": ("b", WaveshareEPaper7P5InBC), "7.50inv2": ("b", WaveshareEPaper7P5InV2), "7.50inv2alt": ("b", WaveshareEPaper7P5InV2alt), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 1e27d594b8..cb3b19aa1a 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -2399,6 +2399,113 @@ void WaveshareEPaper7P5InBV3::dump_config() { LOG_UPDATE_INTERVAL(this); } +void WaveshareEPaper7P5InBV3BWR::initialize() { this->init_display_(); } +bool WaveshareEPaper7P5InBV3BWR::wait_until_idle_() { + if (this->busy_pin_ == nullptr) { + return true; + } + + const uint32_t start = millis(); + while (this->busy_pin_->digital_read()) { + this->command(0x71); + if (millis() - start > this->idle_timeout_()) { + ESP_LOGI(TAG, "Timeout while displaying image!"); + return false; + } + App.feed_wdt(); + delay(10); + } + delay(200); // NOLINT + return true; +}; +void WaveshareEPaper7P5InBV3BWR::init_display_() { + this->reset_(); + + // COMMAND POWER SETTING + this->command(0x01); + + // 1-0=11: internal power + this->data(0x07); + this->data(0x17); // VGH&VGL + this->data(0x3F); // VSH + this->data(0x26); // VSL + this->data(0x11); // VSHR + + // VCOM DC Setting + this->command(0x82); + this->data(0x24); // VCOM + + // Booster Setting + this->command(0x06); + this->data(0x27); + this->data(0x27); + this->data(0x2F); + this->data(0x17); + + // POWER ON + this->command(0x04); + + delay(100); // NOLINT + this->wait_until_idle_(); + // COMMAND PANEL SETTING + this->command(0x00); + this->data(0x0F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f + + // COMMAND RESOLUTION SETTING + this->command(0x61); + this->data(0x03); // source 800 + this->data(0x20); + this->data(0x01); // gate 480 + this->data(0xE0); + // COMMAND ...? + this->command(0x15); + this->data(0x00); + // COMMAND VCOM AND DATA INTERVAL SETTING + this->command(0x50); + this->data(0x20); + this->data(0x00); + // COMMAND TCON SETTING + this->command(0x60); + this->data(0x22); + // Resolution setting + this->command(0x65); + this->data(0x00); + this->data(0x00); // 800*480 + this->data(0x00); + this->data(0x00); +}; +void HOT WaveshareEPaper7P5InBV3BWR::display() { + this->init_display_(); + const uint32_t buf_len = this->get_buffer_length_() / 2u; + + this->command(0x10); // Send BW data Transmission + delay(2); + for (uint32_t i = 0; i < buf_len; i++) { + this->data(this->buffer_[i]); + } + + this->command(0x13); // Send red data Transmission + delay(2); + for (uint32_t i = 0; i < buf_len; i++) { + this->data(this->buffer_[i + buf_len]); + } + + this->command(0x12); // Display Refresh + delay(100); // NOLINT + this->wait_until_idle_(); + this->deep_sleep(); +} +int WaveshareEPaper7P5InBV3BWR::get_width_internal() { return 800; } +int WaveshareEPaper7P5InBV3BWR::get_height_internal() { return 480; } +void WaveshareEPaper7P5InBV3BWR::dump_config() { + LOG_DISPLAY("", "Waveshare E-Paper", this); + ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3 BWR-Mode"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} + void WaveshareEPaper7P5In::initialize() { // COMMAND POWER SETTING this->command(0x01); diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index a319b078d0..4544f7df59 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -637,6 +637,44 @@ class WaveshareEPaper7P5InBV3 : public WaveshareEPaper { void init_display_(); }; +class WaveshareEPaper7P5InBV3BWR : public WaveshareEPaperBWR { + public: + bool wait_until_idle_(); + + void initialize() override; + + void display() override; + + void dump_config() override; + + void deep_sleep() override { + this->command(0x02); // Power off + this->wait_until_idle_(); + this->command(0x07); // Deep sleep + this->data(0xA5); + } + + void clear_screen(); + + protected: + int get_width_internal() override; + + int get_height_internal() override; + + void reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(true); + delay(200); // NOLINT + this->reset_pin_->digital_write(false); + delay(5); + this->reset_pin_->digital_write(true); + delay(200); // NOLINT + } + }; + + void init_display_(); +}; + class WaveshareEPaper7P5InBC : public WaveshareEPaper { public: void initialize() override; diff --git a/tests/components/waveshare_epaper/test.esp32-ard.yaml b/tests/components/waveshare_epaper/test.esp32-ard.yaml index 2f06c5c51b..944f98a1e9 100644 --- a/tests/components/waveshare_epaper/test.esp32-ard.yaml +++ b/tests/components/waveshare_epaper/test.esp32-ard.yaml @@ -188,3 +188,20 @@ display: full_update_every: 30 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + model: 7.50in-bv3-bwr + spi_id: spi_id_1 + cs_pin: + allow_other_uses: true + number: GPIO25 + dc_pin: + allow_other_uses: true + number: GPIO26 + busy_pin: + allow_other_uses: true + number: GPIO27 + reset_pin: + allow_other_uses: true + number: GPIO32 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp32-c3-ard.yaml b/tests/components/waveshare_epaper/test.esp32-c3-ard.yaml index 1c4547b7b4..5d651bd180 100644 --- a/tests/components/waveshare_epaper/test.esp32-c3-ard.yaml +++ b/tests/components/waveshare_epaper/test.esp32-c3-ard.yaml @@ -105,3 +105,19 @@ display: model: 1.54in-m5coreink-m09 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 7.50in-bv3-bwr + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml b/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml index 1c4547b7b4..5d651bd180 100644 --- a/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml +++ b/tests/components/waveshare_epaper/test.esp32-c3-idf.yaml @@ -105,3 +105,19 @@ display: model: 1.54in-m5coreink-m09 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 7.50in-bv3-bwr + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp32-idf.yaml b/tests/components/waveshare_epaper/test.esp32-idf.yaml index b6082fcfbf..47f894d967 100644 --- a/tests/components/waveshare_epaper/test.esp32-idf.yaml +++ b/tests/components/waveshare_epaper/test.esp32-idf.yaml @@ -105,3 +105,19 @@ display: model: 1.54in-m5coreink-m09 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 7.50in-bv3-bwr + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.esp8266-ard.yaml b/tests/components/waveshare_epaper/test.esp8266-ard.yaml index 1f076a67be..ceda328598 100644 --- a/tests/components/waveshare_epaper/test.esp8266-ard.yaml +++ b/tests/components/waveshare_epaper/test.esp8266-ard.yaml @@ -105,3 +105,19 @@ display: model: 1.54in-m5coreink-m09 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 4 + dc_pin: + allow_other_uses: true + number: 4 + busy_pin: + allow_other_uses: true + number: 4 + reset_pin: + allow_other_uses: true + number: 4 + model: 7.50in-bv3-bwr + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); diff --git a/tests/components/waveshare_epaper/test.rp2040-ard.yaml b/tests/components/waveshare_epaper/test.rp2040-ard.yaml index 6050062d7e..be7e780033 100644 --- a/tests/components/waveshare_epaper/test.rp2040-ard.yaml +++ b/tests/components/waveshare_epaper/test.rp2040-ard.yaml @@ -105,3 +105,19 @@ display: model: 1.54in-m5coreink-m09 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + - platform: waveshare_epaper + cs_pin: + allow_other_uses: true + number: 5 + dc_pin: + allow_other_uses: true + number: 5 + busy_pin: + allow_other_uses: true + number: 5 + reset_pin: + allow_other_uses: true + number: 5 + model: 7.50in-bv3-bwr + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); From 6ee02c47c29712c2b8cffa2ef5cebe25b29719a1 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 16:42:12 -0600 Subject: [PATCH 049/139] [homeassistant.number] Return when value not set (#7839) --- .../components/homeassistant/number/homeassistant_number.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/homeassistant/number/homeassistant_number.cpp b/esphome/components/homeassistant/number/homeassistant_number.cpp index d3e285f4ac..a7f71c3244 100644 --- a/esphome/components/homeassistant/number/homeassistant_number.cpp +++ b/esphome/components/homeassistant/number/homeassistant_number.cpp @@ -27,6 +27,7 @@ void HomeassistantNumber::min_retrieved_(const std::string &min) { auto min_value = parse_number(min); if (!min_value.has_value()) { ESP_LOGE(TAG, "'%s': Can't convert 'min' value '%s' to number!", this->entity_id_.c_str(), min.c_str()); + return; } ESP_LOGD(TAG, "'%s': Min retrieved: %s", get_name().c_str(), min.c_str()); this->traits.set_min_value(min_value.value()); @@ -36,6 +37,7 @@ void HomeassistantNumber::max_retrieved_(const std::string &max) { auto max_value = parse_number(max); if (!max_value.has_value()) { ESP_LOGE(TAG, "'%s': Can't convert 'max' value '%s' to number!", this->entity_id_.c_str(), max.c_str()); + return; } ESP_LOGD(TAG, "'%s': Max retrieved: %s", get_name().c_str(), max.c_str()); this->traits.set_max_value(max_value.value()); @@ -45,6 +47,7 @@ void HomeassistantNumber::step_retrieved_(const std::string &step) { auto step_value = parse_number(step); if (!step_value.has_value()) { ESP_LOGE(TAG, "'%s': Can't convert 'step' value '%s' to number!", this->entity_id_.c_str(), step.c_str()); + return; } ESP_LOGD(TAG, "'%s': Step Retrieved %s", get_name().c_str(), step.c_str()); this->traits.set_step(step_value.value()); From 4fbf41472a318bf923632508a3ba9473f06f3171 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 17:41:27 -0600 Subject: [PATCH 050/139] [CI] Add/update some system include paths (#7831) --- .clang-tidy | 6 ++++-- script/clang-tidy | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 946f2950d8..994416b2f1 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -63,15 +63,16 @@ Checks: >- -misc-non-private-member-variables-in-classes, -misc-no-recursion, -misc-unused-parameters, - -modernize-avoid-c-arrays, -modernize-avoid-bind, + -modernize-avoid-c-arrays, -modernize-concat-nested-namespaces, -modernize-return-braced-init-list, -modernize-use-auto, -modernize-use-default-member-init, -modernize-use-equals-default, - -modernize-use-trailing-return-type, -modernize-use-nodiscard, + -modernize-use-nullptr, + -modernize-use-trailing-return-type, -mpi-*, -objc-*, -readability-container-data-pointer, @@ -82,6 +83,7 @@ Checks: >- -readability-isolate-declaration, -readability-magic-numbers, -readability-make-member-function-const, + -readability-named-parameter, -readability-redundant-string-init, -readability-uppercase-literal-suffix, -readability-use-anyofallof, diff --git a/script/clang-tidy b/script/clang-tidy index 61199edce3..319fab70a2 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -100,10 +100,13 @@ def clang_options(idedata): # add library include directories using -isystem to suppress their errors for directory in list(idedata["includes"]["build"]): # skip our own directories, we add those later - if ( - not directory.startswith(f"{root_path}/") - or directory.startswith(f"{root_path}/.pio/") - or directory.startswith(f"{root_path}/managed_components/") + if not directory.startswith(f"{root_path}") or directory.startswith( + ( + f"{root_path}/.pio", + f"{root_path}/.platformio", + f"{root_path}/.temp", + f"{root_path}/managed_components", + ) ): cmd.extend(["-isystem", directory]) From f4766ab74fda60c5e43eaea00c1f91f2a5e77ce2 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 25 Nov 2024 13:58:21 -1000 Subject: [PATCH 051/139] [wifi] fix 32 char SSIDs (#7834) Co-authored-by: Samuel Sieb --- .../wifi/wifi_component_esp32_arduino.cpp | 24 +++++++++++++++---- .../wifi/wifi_component_esp8266.cpp | 24 +++++++++++++++---- .../wifi/wifi_component_esp_idf.cpp | 24 +++++++++++++++---- 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 18c706cb01..bc10bbd1e5 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -137,8 +137,16 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - snprintf(reinterpret_cast(conf.sta.ssid), sizeof(conf.sta.ssid), "%s", ap.get_ssid().c_str()); - snprintf(reinterpret_cast(conf.sta.password), sizeof(conf.sta.password), "%s", ap.get_password().c_str()); + if (ap.get_ssid().size() > sizeof(conf.sta.ssid)) { + ESP_LOGE(TAG, "SSID is too long"); + return false; + } + if (ap.get_password().size() > sizeof(conf.sta.password)) { + ESP_LOGE(TAG, "password is too long"); + return false; + } + memcpy(reinterpret_cast(conf.sta.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); + memcpy(reinterpret_cast(conf.sta.password), ap.get_password().c_str(), ap.get_password().size()); // The weakest authmode to accept in the fast scan mode if (ap.get_password().empty()) { @@ -746,7 +754,11 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - snprintf(reinterpret_cast(conf.ap.ssid), sizeof(conf.ap.ssid), "%s", ap.get_ssid().c_str()); + if (ap.get_ssid().size() > sizeof(conf.ap.ssid)) { + ESP_LOGE(TAG, "AP SSID is too long"); + return false; + } + memcpy(reinterpret_cast(conf.ap.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); conf.ap.channel = ap.get_channel().value_or(1); conf.ap.ssid_hidden = ap.get_ssid().size(); conf.ap.max_connection = 5; @@ -757,7 +769,11 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { *conf.ap.password = 0; } else { conf.ap.authmode = WIFI_AUTH_WPA2_PSK; - snprintf(reinterpret_cast(conf.ap.password), sizeof(conf.ap.password), "%s", ap.get_password().c_str()); + if (ap.get_password().size() > sizeof(conf.ap.password)) { + ESP_LOGE(TAG, "AP password is too long"); + return false; + } + memcpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), ap.get_password().size()); } // pairwise cipher of SoftAP, group cipher will be derived using this. diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index a18d078967..8e1c2e70d8 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -236,8 +236,16 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { struct station_config conf {}; memset(&conf, 0, sizeof(conf)); - snprintf(reinterpret_cast(conf.ssid), sizeof(conf.ssid), "%s", ap.get_ssid().c_str()); - snprintf(reinterpret_cast(conf.password), sizeof(conf.password), "%s", ap.get_password().c_str()); + if (ap.get_ssid().size() > sizeof(conf.ssid)) { + ESP_LOGE(TAG, "SSID is too long"); + return false; + } + if (ap.get_password().size() > sizeof(conf.password)) { + ESP_LOGE(TAG, "password is too long"); + return false; + } + memcpy(reinterpret_cast(conf.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); + memcpy(reinterpret_cast(conf.password), ap.get_password().c_str(), ap.get_password().size()); if (ap.get_bssid().has_value()) { conf.bssid_set = 1; @@ -775,7 +783,11 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { return false; struct softap_config conf {}; - snprintf(reinterpret_cast(conf.ssid), sizeof(conf.ssid), "%s", ap.get_ssid().c_str()); + if (ap.get_ssid().size() > sizeof(conf.ssid)) { + ESP_LOGE(TAG, "AP SSID is too long"); + return false; + } + memcpy(reinterpret_cast(conf.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); conf.ssid_len = static_cast(ap.get_ssid().size()); conf.channel = ap.get_channel().value_or(1); conf.ssid_hidden = ap.get_hidden(); @@ -787,7 +799,11 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { *conf.password = 0; } else { conf.authmode = AUTH_WPA2_PSK; - snprintf(reinterpret_cast(conf.password), sizeof(conf.password), "%s", ap.get_password().c_str()); + if (ap.get_password().size() > sizeof(conf.password)) { + ESP_LOGE(TAG, "AP password is too long"); + return false; + } + memcpy(reinterpret_cast(conf.password), ap.get_password().c_str(), ap.get_password().size()); } ETS_UART_INTR_DISABLE(); diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 1bf14ff40b..1af271345f 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -289,8 +289,16 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - snprintf(reinterpret_cast(conf.sta.ssid), sizeof(conf.sta.ssid), "%s", ap.get_ssid().c_str()); - snprintf(reinterpret_cast(conf.sta.password), sizeof(conf.sta.password), "%s", ap.get_password().c_str()); + if (ap.get_ssid().size() > sizeof(conf.sta.ssid)) { + ESP_LOGE(TAG, "SSID is too long"); + return false; + } + if (ap.get_password().size() > sizeof(conf.sta.password)) { + ESP_LOGE(TAG, "password is too long"); + return false; + } + memcpy(reinterpret_cast(conf.sta.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); + memcpy(reinterpret_cast(conf.sta.password), ap.get_password().c_str(), ap.get_password().size()); // The weakest authmode to accept in the fast scan mode if (ap.get_password().empty()) { @@ -902,7 +910,11 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { wifi_config_t conf; memset(&conf, 0, sizeof(conf)); - strncpy(reinterpret_cast(conf.ap.ssid), ap.get_ssid().c_str(), sizeof(conf.ap.ssid)); + if (ap.get_ssid().size() > sizeof(conf.ap.ssid)) { + ESP_LOGE(TAG, "AP SSID is too long"); + return false; + } + memcpy(reinterpret_cast(conf.ap.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); conf.ap.channel = ap.get_channel().value_or(1); conf.ap.ssid_hidden = ap.get_ssid().size(); conf.ap.max_connection = 5; @@ -913,7 +925,11 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { *conf.ap.password = 0; } else { conf.ap.authmode = WIFI_AUTH_WPA2_PSK; - strncpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password)); + if (ap.get_password().size() > sizeof(conf.ap.password)) { + ESP_LOGE(TAG, "AP password is too long"); + return false; + } + memcpy(reinterpret_cast(conf.ap.password), ap.get_password().c_str(), ap.get_password().size()); } // pairwise cipher of SoftAP, group cipher will be derived using this. From a70cee1dc1162da1ee5f1f078991aa2c68d421a3 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 25 Nov 2024 14:15:01 -1000 Subject: [PATCH 052/139] fix local time timestamp calculation (#7807) Co-authored-by: Samuel Sieb --- .../components/datetime/datetime_entity.cpp | 4 +-- esphome/core/time.cpp | 34 +++++++++++-------- esphome/core/time.h | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/esphome/components/datetime/datetime_entity.cpp b/esphome/components/datetime/datetime_entity.cpp index f215b7acb5..3d92194efa 100644 --- a/esphome/components/datetime/datetime_entity.cpp +++ b/esphome/components/datetime/datetime_entity.cpp @@ -60,9 +60,7 @@ ESPTime DateTimeEntity::state_as_esptime() const { obj.hour = this->hour_; obj.minute = this->minute_; obj.second = this->second_; - obj.day_of_week = 1; // Required to be valid for recalc_timestamp_local but not used. - obj.day_of_year = 1; // Required to be valid for recalc_timestamp_local but not used. - obj.recalc_timestamp_local(false); + obj.recalc_timestamp_local(); return obj; } diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index f7aa4fdddb..31977d972b 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -5,20 +5,18 @@ namespace esphome { -bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } - uint8_t days_in_month(uint8_t month, uint16_t year) { static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - uint8_t days = DAYS_IN_MONTH[month]; - if (month == 2 && is_leap_year(year)) + if (month == 2 && (year % 4 == 0)) return 29; - return days; + return DAYS_IN_MONTH[month]; } size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { struct tm c_tm = this->to_c_tm(); return ::strftime(buffer, buffer_len, format, &c_tm); } + ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) { ESPTime res{}; res.second = uint8_t(c_tm->tm_sec); @@ -33,6 +31,7 @@ ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) { res.timestamp = c_time; return res; } + struct tm ESPTime::to_c_tm() { struct tm c_tm {}; c_tm.tm_sec = this->second; @@ -46,6 +45,7 @@ struct tm ESPTime::to_c_tm() { c_tm.tm_isdst = this->is_dst; return c_tm; } + std::string ESPTime::strftime(const std::string &format) { std::string timestr; timestr.resize(format.size() * 4); @@ -142,6 +142,7 @@ void ESPTime::increment_second() { this->year++; } } + void ESPTime::increment_day() { this->timestamp += 86400; @@ -159,23 +160,22 @@ void ESPTime::increment_day() { this->year++; } } + void ESPTime::recalc_timestamp_utc(bool use_day_of_year) { time_t res = 0; - if (!this->fields_in_range()) { this->timestamp = -1; return; } for (int i = 1970; i < this->year; i++) - res += is_leap_year(i) ? 366 : 365; + res += (year % 4 == 0) ? 366 : 365; if (use_day_of_year) { res += this->day_of_year - 1; } else { for (int i = 1; i < this->month; i++) res += days_in_month(i, this->year); - res += this->day_of_month - 1; } @@ -188,13 +188,17 @@ void ESPTime::recalc_timestamp_utc(bool use_day_of_year) { this->timestamp = res; } -void ESPTime::recalc_timestamp_local(bool use_day_of_year) { - this->recalc_timestamp_utc(use_day_of_year); - this->timestamp -= ESPTime::timezone_offset(); - ESPTime temp = ESPTime::from_epoch_local(this->timestamp); - if (temp.is_dst) { - this->timestamp -= 3600; - } +void ESPTime::recalc_timestamp_local() { + struct tm tm; + + tm.tm_year = this->year - 1900; + tm.tm_mon = this->month - 1; + tm.tm_mday = this->day_of_month; + tm.tm_hour = this->hour; + tm.tm_min = this->minute; + tm.tm_sec = this->second; + + this->timestamp = mktime(&tm); } int32_t ESPTime::timezone_offset() { diff --git a/esphome/core/time.h b/esphome/core/time.h index bce1108d93..5cbd9369fb 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -9,8 +9,6 @@ namespace esphome { template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end); -bool is_leap_year(uint32_t year); - uint8_t days_in_month(uint8_t month, uint16_t year); /// A more user-friendly version of struct tm from time.h @@ -100,7 +98,7 @@ struct ESPTime { void recalc_timestamp_utc(bool use_day_of_year = true); /// Recalculate the timestamp field from the other fields of this ESPTime instance assuming local fields. - void recalc_timestamp_local(bool use_day_of_year = true); + void recalc_timestamp_local(); /// Convert this ESPTime instance back to a tm struct. struct tm to_c_tm(); From d9d368d38eff2024bf50ab9fc034d19ef91d6799 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Mon, 25 Nov 2024 14:21:47 -1000 Subject: [PATCH 053/139] add on_key trigger to matrix_keypad (#7830) Co-authored-by: Samuel Sieb --- esphome/components/matrix_keypad/__init__.py | 18 +++++++++++++++--- .../components/matrix_keypad/matrix_keypad.cpp | 4 ++++ .../components/matrix_keypad/matrix_keypad.h | 5 +++++ esphome/components/wiegand/__init__.py | 7 +++---- esphome/const.py | 1 + tests/components/matrix_keypad/common.yaml | 8 ++++++++ .../matrix_keypad/test.esp32-ard.yaml | 12 ++++-------- .../matrix_keypad/test.esp32-c3-ard.yaml | 12 ++++-------- .../matrix_keypad/test.esp32-c3-idf.yaml | 12 ++++-------- .../matrix_keypad/test.esp32-idf.yaml | 12 ++++-------- .../matrix_keypad/test.esp32-s3-idf.yaml | 15 +++++++++++++++ .../matrix_keypad/test.esp8266-ard.yaml | 12 ++++-------- .../matrix_keypad/test.rp2040-ard.yaml | 12 ++++-------- 13 files changed, 75 insertions(+), 55 deletions(-) create mode 100644 tests/components/matrix_keypad/common.yaml create mode 100644 tests/components/matrix_keypad/test.esp32-s3-idf.yaml diff --git a/esphome/components/matrix_keypad/__init__.py b/esphome/components/matrix_keypad/__init__.py index 5250a45732..b2bcde98ec 100644 --- a/esphome/components/matrix_keypad/__init__.py +++ b/esphome/components/matrix_keypad/__init__.py @@ -1,8 +1,8 @@ +from esphome import automation, pins import esphome.codegen as cg -import esphome.config_validation as cv -from esphome import pins from esphome.components import key_provider -from esphome.const import CONF_ID, CONF_PIN +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_ON_KEY, CONF_PIN, CONF_TRIGGER_ID CODEOWNERS = ["@ssieb"] @@ -14,6 +14,9 @@ matrix_keypad_ns = cg.esphome_ns.namespace("matrix_keypad") MatrixKeypad = matrix_keypad_ns.class_( "MatrixKeypad", key_provider.KeyProvider, cg.Component ) +MatrixKeyTrigger = matrix_keypad_ns.class_( + "MatrixKeyTrigger", automation.Trigger.template(cg.uint8) +) CONF_KEYPAD_ID = "keypad_id" CONF_ROWS = "rows" @@ -47,6 +50,11 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DEBOUNCE_TIME, default=1): cv.int_range(min=1, max=100), cv.Optional(CONF_HAS_DIODES): cv.boolean, cv.Optional(CONF_HAS_PULLDOWNS): cv.boolean, + cv.Optional(CONF_ON_KEY): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MatrixKeyTrigger), + } + ), } ), check_keys, @@ -73,3 +81,7 @@ async def to_code(config): cg.add(var.set_has_diodes(config[CONF_HAS_DIODES])) if CONF_HAS_PULLDOWNS in config: cg.add(var.set_has_pulldowns(config[CONF_HAS_PULLDOWNS])) + for conf in config.get(CONF_ON_KEY, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) + cg.add(var.register_key_trigger(trigger)) + await automation.build_automation(trigger, [(cg.uint8, "x")], conf) diff --git a/esphome/components/matrix_keypad/matrix_keypad.cpp b/esphome/components/matrix_keypad/matrix_keypad.cpp index f62c75c869..8537997935 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.cpp +++ b/esphome/components/matrix_keypad/matrix_keypad.cpp @@ -86,6 +86,8 @@ void MatrixKeypad::loop() { if (!this->keys_.empty()) { uint8_t keycode = this->keys_[key]; ESP_LOGD(TAG, "key '%c' pressed", keycode); + for (auto &trigger : this->key_triggers_) + trigger->trigger(keycode); for (auto &listener : this->listeners_) listener->key_pressed(keycode); this->send_key_(keycode); @@ -107,5 +109,7 @@ void MatrixKeypad::dump_config() { void MatrixKeypad::register_listener(MatrixKeypadListener *listener) { this->listeners_.push_back(listener); } +void MatrixKeypad::register_key_trigger(MatrixKeyTrigger *trig) { this->key_triggers_.push_back(trig); } + } // namespace matrix_keypad } // namespace esphome diff --git a/esphome/components/matrix_keypad/matrix_keypad.h b/esphome/components/matrix_keypad/matrix_keypad.h index d506040b7c..8b309b42c2 100644 --- a/esphome/components/matrix_keypad/matrix_keypad.h +++ b/esphome/components/matrix_keypad/matrix_keypad.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/components/key_provider/key_provider.h" +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" @@ -18,6 +19,8 @@ class MatrixKeypadListener { virtual void key_released(uint8_t key){}; }; +class MatrixKeyTrigger : public Trigger {}; + class MatrixKeypad : public key_provider::KeyProvider, public Component { public: void setup() override; @@ -31,6 +34,7 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component { void set_has_pulldowns(int has_pulldowns) { has_pulldowns_ = has_pulldowns; }; void register_listener(MatrixKeypadListener *listener); + void register_key_trigger(MatrixKeyTrigger *trig); protected: std::vector rows_; @@ -42,6 +46,7 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component { int pressed_key_ = -1; std::vector listeners_{}; + std::vector key_triggers_; }; } // namespace matrix_keypad diff --git a/esphome/components/wiegand/__init__.py b/esphome/components/wiegand/__init__.py index 7b05c43198..962ac4c373 100644 --- a/esphome/components/wiegand/__init__.py +++ b/esphome/components/wiegand/__init__.py @@ -1,8 +1,8 @@ +from esphome import automation, pins import esphome.codegen as cg -import esphome.config_validation as cv -from esphome import pins, automation from esphome.components import key_provider -from esphome.const import CONF_ID, CONF_ON_TAG, CONF_TRIGGER_ID +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_ON_KEY, CONF_ON_TAG, CONF_TRIGGER_ID CODEOWNERS = ["@ssieb"] @@ -25,7 +25,6 @@ WiegandKeyTrigger = wiegand_ns.class_( CONF_D0 = "d0" CONF_D1 = "d1" -CONF_ON_KEY = "on_key" CONF_ON_RAW = "on_raw" CONFIG_SCHEMA = cv.Schema( diff --git a/esphome/const.py b/esphome/const.py index 50528b7363..d2df83aa43 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -575,6 +575,7 @@ CONF_ON_FINGER_SCAN_UNMATCHED = "on_finger_scan_unmatched" CONF_ON_FINISHED_WRITE = "on_finished_write" CONF_ON_IDLE = "on_idle" CONF_ON_JSON_MESSAGE = "on_json_message" +CONF_ON_KEY = "on_key" CONF_ON_LOCK = "on_lock" CONF_ON_LOOP = "on_loop" CONF_ON_MESSAGE = "on_message" diff --git a/tests/components/matrix_keypad/common.yaml b/tests/components/matrix_keypad/common.yaml new file mode 100644 index 0000000000..32e334d890 --- /dev/null +++ b/tests/components/matrix_keypad/common.yaml @@ -0,0 +1,8 @@ +binary_sensor: + - platform: matrix_keypad + id: key4 + row: 1 + col: 1 + - platform: matrix_keypad + id: key1 + key: 1 diff --git a/tests/components/matrix_keypad/test.esp32-ard.yaml b/tests/components/matrix_keypad/test.esp32-ard.yaml index c8e9b54534..70bb70638d 100644 --- a/tests/components/matrix_keypad/test.esp32-ard.yaml +++ b/tests/components/matrix_keypad/test.esp32-ard.yaml @@ -1,11 +1,5 @@ -binary_sensor: - - platform: matrix_keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 +packages: + common: !include common.yaml matrix_keypad: id: keypad @@ -17,3 +11,5 @@ matrix_keypad: - pin: 15 keys: "1234" has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); diff --git a/tests/components/matrix_keypad/test.esp32-c3-ard.yaml b/tests/components/matrix_keypad/test.esp32-c3-ard.yaml index d15e6af21a..75d9c0b263 100644 --- a/tests/components/matrix_keypad/test.esp32-c3-ard.yaml +++ b/tests/components/matrix_keypad/test.esp32-c3-ard.yaml @@ -1,11 +1,5 @@ -binary_sensor: - - platform: matrix_keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 +packages: + common: !include common.yaml matrix_keypad: id: keypad @@ -17,3 +11,5 @@ matrix_keypad: - pin: 4 keys: "1234" has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); diff --git a/tests/components/matrix_keypad/test.esp32-c3-idf.yaml b/tests/components/matrix_keypad/test.esp32-c3-idf.yaml index d15e6af21a..75d9c0b263 100644 --- a/tests/components/matrix_keypad/test.esp32-c3-idf.yaml +++ b/tests/components/matrix_keypad/test.esp32-c3-idf.yaml @@ -1,11 +1,5 @@ -binary_sensor: - - platform: matrix_keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 +packages: + common: !include common.yaml matrix_keypad: id: keypad @@ -17,3 +11,5 @@ matrix_keypad: - pin: 4 keys: "1234" has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); diff --git a/tests/components/matrix_keypad/test.esp32-idf.yaml b/tests/components/matrix_keypad/test.esp32-idf.yaml index c8e9b54534..70bb70638d 100644 --- a/tests/components/matrix_keypad/test.esp32-idf.yaml +++ b/tests/components/matrix_keypad/test.esp32-idf.yaml @@ -1,11 +1,5 @@ -binary_sensor: - - platform: matrix_keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 +packages: + common: !include common.yaml matrix_keypad: id: keypad @@ -17,3 +11,5 @@ matrix_keypad: - pin: 15 keys: "1234" has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); diff --git a/tests/components/matrix_keypad/test.esp32-s3-idf.yaml b/tests/components/matrix_keypad/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..a491f2ed59 --- /dev/null +++ b/tests/components/matrix_keypad/test.esp32-s3-idf.yaml @@ -0,0 +1,15 @@ +packages: + common: !include common.yaml + +matrix_keypad: + id: keypad + rows: + - pin: 10 + - pin: 11 + columns: + - pin: 12 + - pin: 13 + keys: "1234" + has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); diff --git a/tests/components/matrix_keypad/test.esp8266-ard.yaml b/tests/components/matrix_keypad/test.esp8266-ard.yaml index c8e9b54534..70bb70638d 100644 --- a/tests/components/matrix_keypad/test.esp8266-ard.yaml +++ b/tests/components/matrix_keypad/test.esp8266-ard.yaml @@ -1,11 +1,5 @@ -binary_sensor: - - platform: matrix_keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 +packages: + common: !include common.yaml matrix_keypad: id: keypad @@ -17,3 +11,5 @@ matrix_keypad: - pin: 15 keys: "1234" has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); diff --git a/tests/components/matrix_keypad/test.rp2040-ard.yaml b/tests/components/matrix_keypad/test.rp2040-ard.yaml index d15e6af21a..75d9c0b263 100644 --- a/tests/components/matrix_keypad/test.rp2040-ard.yaml +++ b/tests/components/matrix_keypad/test.rp2040-ard.yaml @@ -1,11 +1,5 @@ -binary_sensor: - - platform: matrix_keypad - id: key4 - row: 1 - col: 1 - - platform: matrix_keypad - id: key1 - key: 1 +packages: + common: !include common.yaml matrix_keypad: id: keypad @@ -17,3 +11,5 @@ matrix_keypad: - pin: 4 keys: "1234" has_pulldowns: true + on_key: + - lambda: ESP_LOGI("KEY", "key %d pressed", x); From c0dcecc465fa8b0d3205880174ca820bc8bfd3d3 Mon Sep 17 00:00:00 2001 From: Citric Lee <37475446+limengdu@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:53:21 +0800 Subject: [PATCH 054/139] Add: Seeed Studio mr60fda2 mmwave sensor (#7576) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Spencer Yan --- CODEOWNERS | 1 + esphome/components/seeed_mr60fda2/__init__.py | 41 ++ .../seeed_mr60fda2/binary_sensor.py | 33 ++ .../seeed_mr60fda2/button/__init__.py | 45 +++ .../button/get_radar_parameters_button.cpp | 9 + .../button/get_radar_parameters_button.h | 18 + .../button/reset_radar_button.cpp | 9 + .../button/reset_radar_button.h | 18 + .../seeed_mr60fda2/seeed_mr60fda2.cpp | 368 ++++++++++++++++++ .../seeed_mr60fda2/seeed_mr60fda2.h | 101 +++++ .../seeed_mr60fda2/select/__init__.py | 59 +++ .../select/height_threshold_select.cpp | 15 + .../select/height_threshold_select.h | 18 + .../select/install_height_select.cpp | 15 + .../select/install_height_select.h | 18 + .../select/sensitivity_select.cpp | 15 + .../select/sensitivity_select.h | 18 + tests/components/seeed_mr60fda2/common.yaml | 34 ++ .../seeed_mr60fda2/test.esp32-c3-ard.yaml | 5 + .../seeed_mr60fda2/test.esp32-c3-idf.yaml | 5 + 20 files changed, 845 insertions(+) create mode 100644 esphome/components/seeed_mr60fda2/__init__.py create mode 100644 esphome/components/seeed_mr60fda2/binary_sensor.py create mode 100644 esphome/components/seeed_mr60fda2/button/__init__.py create mode 100644 esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.cpp create mode 100644 esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.h create mode 100644 esphome/components/seeed_mr60fda2/button/reset_radar_button.cpp create mode 100644 esphome/components/seeed_mr60fda2/button/reset_radar_button.h create mode 100644 esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp create mode 100644 esphome/components/seeed_mr60fda2/seeed_mr60fda2.h create mode 100644 esphome/components/seeed_mr60fda2/select/__init__.py create mode 100644 esphome/components/seeed_mr60fda2/select/height_threshold_select.cpp create mode 100644 esphome/components/seeed_mr60fda2/select/height_threshold_select.h create mode 100644 esphome/components/seeed_mr60fda2/select/install_height_select.cpp create mode 100644 esphome/components/seeed_mr60fda2/select/install_height_select.h create mode 100644 esphome/components/seeed_mr60fda2/select/sensitivity_select.cpp create mode 100644 esphome/components/seeed_mr60fda2/select/sensitivity_select.h create mode 100644 tests/components/seeed_mr60fda2/common.yaml create mode 100644 tests/components/seeed_mr60fda2/test.esp32-c3-ard.yaml create mode 100644 tests/components/seeed_mr60fda2/test.esp32-c3-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index dd3926d283..fb6d11d1fb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -354,6 +354,7 @@ esphome/components/sdl/* @clydebarrow esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sdp3x/* @Azimath esphome/components/seeed_mr24hpc1/* @limengdu +esphome/components/seeed_mr60fda2/* @limengdu esphome/components/selec_meter/* @sourabhjaiswal esphome/components/select/* @esphome/core esphome/components/sen0321/* @notjj diff --git a/esphome/components/seeed_mr60fda2/__init__.py b/esphome/components/seeed_mr60fda2/__init__.py new file mode 100644 index 0000000000..e79134deec --- /dev/null +++ b/esphome/components/seeed_mr60fda2/__init__.py @@ -0,0 +1,41 @@ +import esphome.codegen as cg +from esphome.components import uart +import esphome.config_validation as cv +from esphome.const import CONF_ID + +CODEOWNERS = ["@limengdu"] +DEPENDENCIES = ["uart"] +MULTI_CONF = True + +mr60fda2_ns = cg.esphome_ns.namespace("seeed_mr60fda2") + +MR60FDA2Component = mr60fda2_ns.class_( + "MR60FDA2Component", cg.Component, uart.UARTDevice +) + +CONF_MR60FDA2_ID = "mr60fda2_id" + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(MR60FDA2Component), + } + ) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "seeed_mr60fda2", + require_tx=True, + require_rx=True, + baud_rate=115200, + parity="NONE", + stop_bits=1, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) diff --git a/esphome/components/seeed_mr60fda2/binary_sensor.py b/esphome/components/seeed_mr60fda2/binary_sensor.py new file mode 100644 index 0000000000..2860ac0100 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/binary_sensor.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +from esphome.components import binary_sensor +import esphome.config_validation as cv +from esphome.const import DEVICE_CLASS_OCCUPANCY, DEVICE_CLASS_SAFETY + +from . import CONF_MR60FDA2_ID, MR60FDA2Component + +DEPENDENCIES = ["seeed_mr60fda2"] + +CONF_PEOPLE_EXIST = "people_exist" +CONF_FALL_DETECTED = "fall_detected" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR60FDA2_ID): cv.use_id(MR60FDA2Component), + cv.Optional(CONF_PEOPLE_EXIST): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_OCCUPANCY, icon="mdi:motion-sensor" + ), + cv.Optional(CONF_FALL_DETECTED): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_SAFETY, icon="mdi:emergency" + ), +} + + +async def to_code(config): + mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) + + if people_exist_config := config.get(CONF_PEOPLE_EXIST): + sens = await binary_sensor.new_binary_sensor(people_exist_config) + cg.add(mr60fda2_component.set_people_exist_binary_sensor(sens)) + + if is_fall_config := config.get(CONF_FALL_DETECTED): + sens = await binary_sensor.new_binary_sensor(is_fall_config) + cg.add(mr60fda2_component.set_fall_detected_binary_sensor(sens)) diff --git a/esphome/components/seeed_mr60fda2/button/__init__.py b/esphome/components/seeed_mr60fda2/button/__init__.py new file mode 100644 index 0000000000..1415dc27ca --- /dev/null +++ b/esphome/components/seeed_mr60fda2/button/__init__.py @@ -0,0 +1,45 @@ +import esphome.codegen as cg +from esphome.components import button +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_RESTART, + DEVICE_CLASS_UPDATE, + ENTITY_CATEGORY_DIAGNOSTIC, + ENTITY_CATEGORY_NONE, + CONF_FACTORY_RESET, +) + +from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns + +DEPENDENCIES = ["seeed_mr60fda2"] + +GetRadarParametersButton = mr60fda2_ns.class_("GetRadarParametersButton", button.Button) +ResetRadarButton = mr60fda2_ns.class_("ResetRadarButton", button.Button) + +CONF_GET_RADAR_PARAMETERS = "get_radar_parameters" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR60FDA2_ID): cv.use_id(MR60FDA2Component), + cv.Optional(CONF_GET_RADAR_PARAMETERS): button.button_schema( + GetRadarParametersButton, + device_class=DEVICE_CLASS_UPDATE, + entity_category=ENTITY_CATEGORY_NONE, + ), + cv.Optional(CONF_FACTORY_RESET): button.button_schema( + ResetRadarButton, + device_class=DEVICE_CLASS_RESTART, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), +} + + +async def to_code(config): + mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) + if get_radar_parameters_config := config.get(CONF_GET_RADAR_PARAMETERS): + b = await button.new_button(get_radar_parameters_config) + await cg.register_parented(b, config[CONF_MR60FDA2_ID]) + cg.add(mr60fda2_component.set_get_radar_parameters_button(b)) + if factory_reset_config := config.get(CONF_FACTORY_RESET): + b = await button.new_button(factory_reset_config) + await cg.register_parented(b, config[CONF_MR60FDA2_ID]) + cg.add(mr60fda2_component.set_factory_reset_button(b)) diff --git a/esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.cpp b/esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.cpp new file mode 100644 index 0000000000..88be6dfe7c --- /dev/null +++ b/esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.cpp @@ -0,0 +1,9 @@ +#include "get_radar_parameters_button.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +void GetRadarParametersButton::press_action() { this->parent_->get_radar_parameters(); } + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.h b/esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.h new file mode 100644 index 0000000000..9d6d507383 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../seeed_mr60fda2.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +class GetRadarParametersButton : public button::Button, public Parented { + public: + GetRadarParametersButton() = default; + + protected: + void press_action() override; +}; + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/button/reset_radar_button.cpp b/esphome/components/seeed_mr60fda2/button/reset_radar_button.cpp new file mode 100644 index 0000000000..0a5833a18c --- /dev/null +++ b/esphome/components/seeed_mr60fda2/button/reset_radar_button.cpp @@ -0,0 +1,9 @@ +#include "reset_radar_button.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +void ResetRadarButton::press_action() { this->parent_->factory_reset(); } + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/button/reset_radar_button.h b/esphome/components/seeed_mr60fda2/button/reset_radar_button.h new file mode 100644 index 0000000000..66780fb8af --- /dev/null +++ b/esphome/components/seeed_mr60fda2/button/reset_radar_button.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/button/button.h" +#include "../seeed_mr60fda2.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +class ResetRadarButton : public button::Button, public Parented { + public: + ResetRadarButton() = default; + + protected: + void press_action() override; +}; + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp new file mode 100644 index 0000000000..d183a1f77f --- /dev/null +++ b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp @@ -0,0 +1,368 @@ +#include "seeed_mr60fda2.h" +#include "esphome/core/log.h" + +#include +#include + +namespace esphome { +namespace seeed_mr60fda2 { + +static const char *const TAG = "seeed_mr60fda2"; + +// Prints the component's configuration data. dump_config() prints all of the component's configuration +// items in an easy-to-read format, including the configuration key-value pairs. +void MR60FDA2Component::dump_config() { + ESP_LOGCONFIG(TAG, "MR60FDA2:"); +#ifdef USE_BINARY_SENSOR + LOG_BINARY_SENSOR(" ", "People Exist Binary Sensor", this->people_exist_binary_sensor_); + LOG_BINARY_SENSOR(" ", "Is Fall Binary Sensor", this->fall_detected_binary_sensor_); +#endif +#ifdef USE_BUTTON + LOG_BUTTON(" ", "Get Radar Parameters Button", this->get_radar_parameters_button_); + LOG_BUTTON(" ", "Reset Radar Button", this->factory_reset_button_); +#endif +#ifdef USE_SELECT + LOG_SELECT(" ", "Install Height Select", this->install_height_select_); + LOG_SELECT(" ", "Height Threshold Select", this->height_threshold_select_); + LOG_SELECT(" ", "Sensitivity Select", this->sensitivity_select_); +#endif +} + +// Initialisation functions +void MR60FDA2Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up MR60FDA2..."); + this->check_uart_settings(115200); + + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + this->current_frame_id_ = 0; + this->current_frame_len_ = 0; + this->current_data_frame_len_ = 0; + this->current_frame_type_ = 0; + this->get_radar_parameters(); + + memset(this->current_frame_buf_, 0, FRAME_BUF_MAX_SIZE); + memset(this->current_data_buf_, 0, DATA_BUF_MAX_SIZE); + + ESP_LOGCONFIG(TAG, "Set up MR60FDA2 complete"); +} + +// main loop +void MR60FDA2Component::loop() { + uint8_t byte; + + // Is there data on the serial port + while (this->available()) { + this->read_byte(&byte); + this->split_frame_(byte); // split data frame + } +} + +/** + * @brief Calculate the checksum for a byte array. + * + * This function calculates the checksum for the provided byte array using an + * XOR-based checksum algorithm. + * + * @param data The byte array to calculate the checksum for. + * @param len The length of the byte array. + * @return The calculated checksum. + */ +static uint8_t calculate_checksum(const uint8_t *data, size_t len) { + uint8_t checksum = 0; + for (size_t i = 0; i < len; i++) { + checksum ^= data[i]; + } + checksum = ~checksum; + return checksum; +} + +/** + * @brief Validate the checksum of a byte array. + * + * This function validates the checksum of the provided byte array by comparing + * it to the expected checksum. + * + * @param data The byte array to validate. + * @param len The length of the byte array. + * @param expected_checksum The expected checksum. + * @return True if the checksum is valid, false otherwise. + */ +static bool validate_checksum(const uint8_t *data, size_t len, uint8_t expected_checksum) { + return calculate_checksum(data, len) == expected_checksum; +} + +static uint8_t find_nearest_index(float value, const float *arr, int size) { + int nearest_index = 0; + float min_diff = std::abs(value - arr[0]); + for (int i = 1; i < size; ++i) { + float diff = std::abs(value - arr[i]); + if (diff < min_diff) { + min_diff = diff; + nearest_index = i; + } + } + return nearest_index; +} + +/** + * @brief Convert a float value to a byte array. + * + * This function converts a float value to a byte array. + * + * @param value The float value to convert. + * @param bytes The byte array to store the converted value. + */ +static void float_to_bytes(float value, unsigned char *bytes) { + union { + float float_value; + unsigned char byte_array[4]; + } u; + + u.float_value = value; + memcpy(bytes, u.byte_array, 4); +} + +/** + * @brief Convert a 32-bit unsigned integer to a byte array. + * + * This function converts a 32-bit unsigned integer to a byte array. + * + * @param value The 32-bit unsigned integer to convert. + * @param bytes The byte array to store the converted value. + */ +static void int_to_bytes(uint32_t value, unsigned char *bytes) { + bytes[0] = value & 0xFF; + bytes[1] = (value >> 8) & 0xFF; + bytes[2] = (value >> 16) & 0xFF; + bytes[3] = (value >> 24) & 0xFF; +} + +void MR60FDA2Component::split_frame_(uint8_t buffer) { + switch (this->current_frame_locate_) { + case LOCATE_FRAME_HEADER: // starting buffer + if (buffer == FRAME_HEADER_BUFFER) { + this->current_frame_len_ = 1; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + } + break; + case LOCATE_ID_FRAME1: + this->current_frame_id_ = buffer << 8; + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + break; + case LOCATE_ID_FRAME2: + this->current_frame_id_ += buffer; + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + break; + case LOCATE_LENGTH_FRAME_H: + this->current_data_frame_len_ = buffer << 8; + if (this->current_data_frame_len_ == 0x00) { + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + } else { + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + } + break; + case LOCATE_LENGTH_FRAME_L: + this->current_data_frame_len_ += buffer; + if (this->current_data_frame_len_ > DATA_BUF_MAX_SIZE) { + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + } else { + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + } + break; + case LOCATE_TYPE_FRAME1: + this->current_frame_type_ = buffer << 8; + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + break; + case LOCATE_TYPE_FRAME2: + this->current_frame_type_ += buffer; + if ((this->current_frame_type_ == IS_FALL_TYPE_BUFFER) || + (this->current_frame_type_ == PEOPLE_EXIST_TYPE_BUFFER) || + (this->current_frame_type_ == RESULT_INSTALL_HEIGHT) || (this->current_frame_type_ == RESULT_PARAMETERS) || + (this->current_frame_type_ == RESULT_HEIGHT_THRESHOLD) || (this->current_frame_type_ == RESULT_SENSITIVITY)) { + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + } else { + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + } + break; + case LOCATE_HEAD_CKSUM_FRAME: + if (validate_checksum(this->current_frame_buf_, this->current_frame_len_, buffer)) { + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + } else { + ESP_LOGD(TAG, "HEAD_CKSUM_FRAME ERROR: 0x%02x", buffer); + ESP_LOGV(TAG, "CURRENT_FRAME: %s %s", + format_hex_pretty(this->current_frame_buf_, this->current_frame_len_).c_str(), + format_hex_pretty(&buffer, 1).c_str()); + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + } + break; + case LOCATE_DATA_FRAME: + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_data_buf_[this->current_frame_len_ - LEN_TO_DATA_FRAME] = buffer; + if (this->current_frame_len_ - LEN_TO_HEAD_CKSUM == this->current_data_frame_len_) { + this->current_frame_locate_++; + } + if (this->current_frame_len_ > FRAME_BUF_MAX_SIZE) { + ESP_LOGD(TAG, "PRACTICE_DATA_FRAME_LEN ERROR: %d", this->current_frame_len_ - LEN_TO_HEAD_CKSUM); + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + } + break; + case LOCATE_DATA_CKSUM_FRAME: + if (validate_checksum(this->current_data_buf_, this->current_data_frame_len_, buffer)) { + this->current_frame_len_++; + this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; + this->current_frame_locate_++; + this->process_frame_(); + } else { + ESP_LOGD(TAG, "DATA_CKSUM_FRAME ERROR: 0x%02x", buffer); + ESP_LOGV(TAG, "GET CURRENT_FRAME: %s %s", + format_hex_pretty(this->current_frame_buf_, this->current_frame_len_).c_str(), + format_hex_pretty(&buffer, 1).c_str()); + + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + } + break; + default: + break; + } +} + +void MR60FDA2Component::process_frame_() { + switch (this->current_frame_type_) { + case IS_FALL_TYPE_BUFFER: + if (this->fall_detected_binary_sensor_ != nullptr) { + this->fall_detected_binary_sensor_->publish_state(this->current_frame_buf_[LEN_TO_HEAD_CKSUM]); + } + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + break; + + case PEOPLE_EXIST_TYPE_BUFFER: + if (this->people_exist_binary_sensor_ != nullptr) + this->people_exist_binary_sensor_->publish_state(this->current_frame_buf_[LEN_TO_HEAD_CKSUM]); + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + break; + + case RESULT_INSTALL_HEIGHT: + if (this->current_data_buf_[0]) { + ESP_LOGD(TAG, "Successfully set the mounting height"); + } else { + ESP_LOGD(TAG, "Failed to set the mounting height"); + } + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + break; + + case RESULT_HEIGHT_THRESHOLD: + if (this->current_data_buf_[0]) { + ESP_LOGD(TAG, "Successfully set the height threshold"); + } else { + ESP_LOGD(TAG, "Failed to set the height threshold"); + } + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + break; + + case RESULT_SENSITIVITY: + if (this->current_data_buf_[0]) { + ESP_LOGD(TAG, "Successfully set the sensitivity"); + } else { + ESP_LOGD(TAG, "Failed to set the sensitivity"); + } + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + break; + + case RESULT_PARAMETERS: { + float install_height_float = 0; + float height_threshold_float = 0; + uint32_t current_sensitivity = 0; + if (this->install_height_select_ != nullptr) { + uint32_t current_install_height_int = + encode_uint32(current_data_buf_[3], current_data_buf_[2], current_data_buf_[1], current_data_buf_[0]); + + install_height_float = bit_cast(current_install_height_int); + uint32_t select_index = find_nearest_index(install_height_float, INSTALL_HEIGHT, 7); + this->install_height_select_->publish_state(this->install_height_select_->at(select_index).value()); + } + + if (this->height_threshold_select_ != nullptr) { + uint32_t current_height_threshold_int = + encode_uint32(current_data_buf_[7], current_data_buf_[6], current_data_buf_[5], current_data_buf_[4]); + + height_threshold_float = bit_cast(current_height_threshold_int); + size_t select_index = find_nearest_index(height_threshold_float, HEIGHT_THRESHOLD, 7); + this->height_threshold_select_->publish_state(this->height_threshold_select_->at(select_index).value()); + } + + if (this->sensitivity_select_ != nullptr) { + current_sensitivity = + encode_uint32(current_data_buf_[11], current_data_buf_[10], current_data_buf_[9], current_data_buf_[8]); + + uint32_t select_index = find_nearest_index(current_sensitivity, SENSITIVITY, 3); + this->sensitivity_select_->publish_state(this->sensitivity_select_->at(select_index).value()); + } + + ESP_LOGD(TAG, "Mounting height: %.2f, Height threshold: %.2f, Sensitivity: %" PRIu32, install_height_float, + height_threshold_float, current_sensitivity); + this->current_frame_locate_ = LOCATE_FRAME_HEADER; + break; + } + default: + break; + } +} + +// Send Heartbeat Packet Command +void MR60FDA2Component::set_install_height(uint8_t index) { + uint8_t send_data[13] = {0x01, 0x00, 0x00, 0x00, 0x04, 0x0E, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}; + float_to_bytes(INSTALL_HEIGHT[index], &send_data[8]); + send_data[12] = calculate_checksum(send_data + 8, 4); + this->write_array(send_data, 13); + ESP_LOGV(TAG, "SEND INSTALL HEIGHT FRAME: %s", format_hex_pretty(send_data, 13).c_str()); +} + +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]); + 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()); +} + +void MR60FDA2Component::set_sensitivity(uint8_t index) { + uint8_t send_data[13] = {0x01, 0x00, 0x00, 0x00, 0x04, 0x0E, 0x0A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}; + + int_to_bytes(SENSITIVITY[index], &send_data[8]); + + send_data[12] = calculate_checksum(send_data + 8, 4); + this->write_array(send_data, 13); + ESP_LOGV(TAG, "SEND SET SENSITIVITY: %s", format_hex_pretty(send_data, 13).c_str()); +} + +void MR60FDA2Component::get_radar_parameters() { + uint8_t send_data[8] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x06, 0xF6}; + this->write_array(send_data, 8); + ESP_LOGV(TAG, "SEND GET PARAMETERS: %s", format_hex_pretty(send_data, 8).c_str()); +} + +void MR60FDA2Component::factory_reset() { + uint8_t send_data[8] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x10, 0xCF}; + this->write_array(send_data, 8); + ESP_LOGV(TAG, "SEND RESET: %s", format_hex_pretty(send_data, 8).c_str()); + this->get_radar_parameters(); +} + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h new file mode 100644 index 0000000000..e1ffa4f071 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h @@ -0,0 +1,101 @@ +#pragma once +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif +#ifdef USE_BUTTON +#include "esphome/components/button/button.h" +#endif +#ifdef USE_SELECT +#include "esphome/components/select/select.h" +#endif +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif +#include "esphome/components/uart/uart.h" +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" + +#include + +namespace esphome { +namespace seeed_mr60fda2 { + +static const uint8_t DATA_BUF_MAX_SIZE = 28; +static const uint8_t FRAME_BUF_MAX_SIZE = 37; +static const uint8_t LEN_TO_HEAD_CKSUM = 8; +static const uint8_t LEN_TO_DATA_FRAME = 9; + +static const uint8_t FRAME_HEADER_BUFFER = 0x01; +static const uint16_t IS_FALL_TYPE_BUFFER = 0x0E02; +static const uint16_t PEOPLE_EXIST_TYPE_BUFFER = 0x0F09; +static const uint16_t RESULT_INSTALL_HEIGHT = 0x0E04; +static const uint16_t RESULT_PARAMETERS = 0x0E06; +static const uint16_t RESULT_HEIGHT_THRESHOLD = 0x0E08; +static const uint16_t RESULT_SENSITIVITY = 0x0E0A; + +enum FrameLocation { + LOCATE_FRAME_HEADER, + LOCATE_ID_FRAME1, + LOCATE_ID_FRAME2, + LOCATE_LENGTH_FRAME_H, + LOCATE_LENGTH_FRAME_L, + LOCATE_TYPE_FRAME1, + LOCATE_TYPE_FRAME2, + LOCATE_HEAD_CKSUM_FRAME, // Header checksum: [from the first byte to the previous byte of the HEAD_CKSUM bit] + LOCATE_DATA_FRAME, + LOCATE_DATA_CKSUM_FRAME, // Data checksum: [from the first to the previous byte of the DATA_CKSUM bit] + LOCATE_PROCESS_FRAME, +}; + +static const float INSTALL_HEIGHT[7] = {2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f}; +static const float HEIGHT_THRESHOLD[7] = {0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f}; +static const float SENSITIVITY[3] = {3, 15, 30}; + +static const char *const INSTALL_HEIGHT_STR[7] = {"2.4m", "2.5m", "2.6", "2.7m", "2.8", "2.9m", "3.0m"}; +static const char *const HEIGHT_THRESHOLD_STR[7] = {"0.0m", "0.1m", "0.2m", "0.3m", "0.4m", "0.5m", "0.6m"}; +static const char *const SENSITIVITY_STR[3] = {"1", "2", "3"}; + +class MR60FDA2Component : public Component, + public uart::UARTDevice { // The class name must be the name defined by text_sensor.py +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(people_exist) + SUB_BINARY_SENSOR(fall_detected) +#endif +#ifdef USE_BUTTON + SUB_BUTTON(get_radar_parameters) + SUB_BUTTON(factory_reset) +#endif +#ifdef USE_SELECT + SUB_SELECT(install_height) + SUB_SELECT(height_threshold) + SUB_SELECT(sensitivity) +#endif + + protected: + uint8_t current_frame_locate_; + uint8_t current_frame_buf_[FRAME_BUF_MAX_SIZE]; + uint8_t current_data_buf_[DATA_BUF_MAX_SIZE]; + uint16_t current_frame_id_; + size_t current_frame_len_; + size_t current_data_frame_len_; + uint16_t current_frame_type_; + + void split_frame_(uint8_t buffer); + void process_frame_(); + + public: + float get_setup_priority() const override { return esphome::setup_priority::LATE; } + void setup() override; + void dump_config() override; + void loop() override; + void set_install_height(uint8_t index); + void set_height_threshold(uint8_t index); + void set_sensitivity(uint8_t index); + void get_radar_parameters(); + void factory_reset(); +}; + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/select/__init__.py b/esphome/components/seeed_mr60fda2/select/__init__.py new file mode 100644 index 0000000000..a6f9eeb920 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/__init__.py @@ -0,0 +1,59 @@ +import esphome.codegen as cg +from esphome.components import select +import esphome.config_validation as cv +from esphome.const import CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG, ICON_ACCELERATION_Z + +from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns + + +DEPENDENCIES = ["seeed_mr60fda2"] + +InstallHeightSelect = mr60fda2_ns.class_("InstallHeightSelect", select.Select) +HeightThresholdSelect = mr60fda2_ns.class_("HeightThresholdSelect", select.Select) +SensitivitySelect = mr60fda2_ns.class_("SensitivitySelect", select.Select) + +CONF_INSTALL_HEIGHT = "install_height" +CONF_HEIGHT_THRESHOLD = "height_threshold" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_MR60FDA2_ID): cv.use_id(MR60FDA2Component), + cv.Optional(CONF_INSTALL_HEIGHT): select.select_schema( + InstallHeightSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_ACCELERATION_Z, + ), + cv.Optional(CONF_HEIGHT_THRESHOLD): select.select_schema( + HeightThresholdSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_ACCELERATION_Z, + ), + cv.Optional(CONF_SENSITIVITY): select.select_schema( + SensitivitySelect, + entity_category=ENTITY_CATEGORY_CONFIG, + ), +} + + +async def to_code(config): + mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) + if install_height_config := config.get(CONF_INSTALL_HEIGHT): + s = await select.new_select( + install_height_config, + options=["2.4m", "2.5m", "2.6m", "2.7m", "2.8m", "2.9m", "3.0m"], + ) + await cg.register_parented(s, config[CONF_MR60FDA2_ID]) + cg.add(mr60fda2_component.set_install_height_select(s)) + if height_threshold_config := config.get(CONF_HEIGHT_THRESHOLD): + s = await select.new_select( + height_threshold_config, + options=["0.0m", "0.1m", "0.2m", "0.3m", "0.4m", "0.5m", "0.6m"], + ) + await cg.register_parented(s, config[CONF_MR60FDA2_ID]) + cg.add(mr60fda2_component.set_height_threshold_select(s)) + if sensitivity_config := config.get(CONF_SENSITIVITY): + s = await select.new_select( + sensitivity_config, + options=["1", "2", "3"], + ) + await cg.register_parented(s, config[CONF_MR60FDA2_ID]) + cg.add(mr60fda2_component.set_sensitivity_select(s)) diff --git a/esphome/components/seeed_mr60fda2/select/height_threshold_select.cpp b/esphome/components/seeed_mr60fda2/select/height_threshold_select.cpp new file mode 100644 index 0000000000..037f8c6036 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/height_threshold_select.cpp @@ -0,0 +1,15 @@ +#include "height_threshold_select.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +void HeightThresholdSelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_height_threshold(index.value()); + } +} + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/select/height_threshold_select.h b/esphome/components/seeed_mr60fda2/select/height_threshold_select.h new file mode 100644 index 0000000000..b856dbc89a --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/height_threshold_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr60fda2.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +class HeightThresholdSelect : public select::Select, public Parented { + public: + HeightThresholdSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/select/install_height_select.cpp b/esphome/components/seeed_mr60fda2/select/install_height_select.cpp new file mode 100644 index 0000000000..e791911613 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/install_height_select.cpp @@ -0,0 +1,15 @@ +#include "install_height_select.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +void InstallHeightSelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_install_height(index.value()); + } +} + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/select/install_height_select.h b/esphome/components/seeed_mr60fda2/select/install_height_select.h new file mode 100644 index 0000000000..7430da3493 --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/install_height_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr60fda2.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +class InstallHeightSelect : public select::Select, public Parented { + public: + InstallHeightSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/select/sensitivity_select.cpp b/esphome/components/seeed_mr60fda2/select/sensitivity_select.cpp new file mode 100644 index 0000000000..e2507fb7cc --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/sensitivity_select.cpp @@ -0,0 +1,15 @@ +#include "sensitivity_select.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +void SensitivitySelect::control(const std::string &value) { + this->publish_state(value); + auto index = this->index_of(value); + if (index.has_value()) { + this->parent_->set_sensitivity(index.value()); + } +} + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60fda2/select/sensitivity_select.h b/esphome/components/seeed_mr60fda2/select/sensitivity_select.h new file mode 100644 index 0000000000..d1accc1b5b --- /dev/null +++ b/esphome/components/seeed_mr60fda2/select/sensitivity_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../seeed_mr60fda2.h" + +namespace esphome { +namespace seeed_mr60fda2 { + +class SensitivitySelect : public select::Select, public Parented { + public: + SensitivitySelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace seeed_mr60fda2 +} // namespace esphome diff --git a/tests/components/seeed_mr60fda2/common.yaml b/tests/components/seeed_mr60fda2/common.yaml new file mode 100644 index 0000000000..55a7cc1ab3 --- /dev/null +++ b/tests/components/seeed_mr60fda2/common.yaml @@ -0,0 +1,34 @@ +uart: + - id: seeed_mr60fda2_uart + tx_pin: ${uart_tx_pin} + rx_pin: ${uart_rx_pin} + baud_rate: 115200 + parity: NONE + stop_bits: 1 + +seeed_mr60fda2: + id: my_seeed_mr60fda2 + uart_id: seeed_mr60fda2_uart + +binary_sensor: + - platform: seeed_mr60fda2 + people_exist: + name: "Person Information" + fall_detected: + name: "Falling Information" + +button: + - platform: seeed_mr60fda2 + get_radar_parameters: + name: "Get Radar Parameters" + factory_reset: + name: "Reset" + +select: + - platform: seeed_mr60fda2 + install_height: + name: "Set Install Height" + height_threshold: + name: "Set Height Threshold" + sensitivity: + name: "Set Sensitivity" diff --git a/tests/components/seeed_mr60fda2/test.esp32-c3-ard.yaml b/tests/components/seeed_mr60fda2/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..4fb884abf4 --- /dev/null +++ b/tests/components/seeed_mr60fda2/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO5 + uart_rx_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/seeed_mr60fda2/test.esp32-c3-idf.yaml b/tests/components/seeed_mr60fda2/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4fb884abf4 --- /dev/null +++ b/tests/components/seeed_mr60fda2/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO5 + uart_rx_pin: GPIO4 + +<<: !include common.yaml From ae6736311a47ddc5c63dd36b0d2cb4af29f4dd14 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 25 Nov 2024 22:29:36 -0600 Subject: [PATCH 055/139] [lvgl] clang-tidy fixes for #7822 (#7843) --- esphome/components/lvgl/lvgl_esphome.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 41346bc732..61bdfe9755 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -279,7 +279,7 @@ std::string LvSelectable::get_selected_text() { static std::string join_string(std::vector options) { return std::accumulate( options.begin(), options.end(), std::string(), - [](const std::string &a, const std::string &b) -> std::string { return a + (a.length() > 0 ? "\n" : "") + b; }); + [](const std::string &a, const std::string &b) -> std::string { return a + (!a.empty() ? "\n" : "") + b; }); } void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t anim) { From 72df3d1606aaaf650d49c342439bb2294d9ca76c Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:37:20 -0600 Subject: [PATCH 056/139] [xiaomi_ble] clang-tidy fixes for #7822 (#7860) --- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 85434341cc..04e0724ba7 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -249,7 +249,7 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service } bool decrypt_xiaomi_payload(std::vector &raw, const uint8_t *bindkey, const uint64_t &address) { - if (!((raw.size() == 19) || ((raw.size() >= 22) && (raw.size() <= 24)))) { + if ((raw.size() != 19) && ((raw.size() < 22) || (raw.size() > 24))) { ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): data packet has wrong size (%d)!", raw.size()); ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty(raw.data(), raw.size()).c_str()); return false; From 11076e4614075109ce8cc51d4aae70559fc2394b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:47:24 -0600 Subject: [PATCH 057/139] [wireguard] clang-tidy fixes for #7822 (#7859) --- esphome/components/wireguard/wireguard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/wireguard/wireguard.cpp b/esphome/components/wireguard/wireguard.cpp index 7b4011cb79..431bf52227 100644 --- a/esphome/components/wireguard/wireguard.cpp +++ b/esphome/components/wireguard/wireguard.cpp @@ -37,7 +37,7 @@ void Wireguard::setup() { this->wg_config_.netmask = this->netmask_.c_str(); this->wg_config_.persistent_keepalive = this->keepalive_; - if (this->preshared_key_.length() > 0) + if (!this->preshared_key_.empty()) this->wg_config_.preshared_key = this->preshared_key_.c_str(); this->publish_enabled_state(); @@ -137,7 +137,7 @@ void Wireguard::dump_config() { ESP_LOGCONFIG(TAG, " Peer Port: " LOG_SECRET("%d"), this->peer_port_); ESP_LOGCONFIG(TAG, " Peer Public Key: " LOG_SECRET("%s"), this->peer_public_key_.c_str()); ESP_LOGCONFIG(TAG, " Peer Pre-shared Key: " LOG_SECRET("%s"), - (this->preshared_key_.length() > 0 ? mask_key(this->preshared_key_).c_str() : "NOT IN USE")); + (!this->preshared_key_.empty() ? mask_key(this->preshared_key_).c_str() : "NOT IN USE")); ESP_LOGCONFIG(TAG, " Peer Allowed IPs:"); for (auto &allowed_ip : this->allowed_ips_) { ESP_LOGCONFIG(TAG, " - %s/%s", std::get<0>(allowed_ip).c_str(), std::get<1>(allowed_ip).c_str()); From 841d278224d7a82ff8112cb3ee80dbe31347d84b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:47:57 -0600 Subject: [PATCH 058/139] [dsmr] clang-tidy fixes for #7822 (#7848) --- esphome/components/dsmr/dsmr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/dsmr/dsmr.cpp b/esphome/components/dsmr/dsmr.cpp index 193ea1d4e5..c0a2883d79 100644 --- a/esphome/components/dsmr/dsmr.cpp +++ b/esphome/components/dsmr/dsmr.cpp @@ -296,7 +296,7 @@ void Dsmr::dump_config() { } void Dsmr::set_decryption_key(const std::string &decryption_key) { - if (decryption_key.length() == 0) { + if (decryption_key.empty()) { ESP_LOGI(TAG, "Disabling decryption"); this->decryption_key_.clear(); if (this->crypt_telegram_ != nullptr) { From 6e50e2aa6534c31dbc9e425781c76581178ea68c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:50:16 +1300 Subject: [PATCH 059/139] Fix entity name validation to allow "Off" and "On" (#7821) --- esphome/config_validation.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 98b81ec328..ebfb2631c3 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1839,8 +1839,6 @@ def validate_registry_entry(name, registry): def none(value): if value in ("none", "None"): return None - if boolean(value) is False: - return None raise Invalid("Must be none") @@ -1912,17 +1910,23 @@ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend( } ) + +def _validate_entity_name(value): + value = string(value) + try: + value = none(value) # pylint: disable=assignment-from-none + except Invalid: + pass + else: + requires_friendly_name( + "Name cannot be None when esphome->friendly_name is not set!" + )(value) + return value + + ENTITY_BASE_SCHEMA = Schema( { - Optional(CONF_NAME): Any( - All( - none, - requires_friendly_name( - "Name cannot be None when esphome->friendly_name is not set!" - ), - ), - string, - ), + Optional(CONF_NAME): _validate_entity_name, Optional(CONF_INTERNAL): boolean, Optional(CONF_DISABLED_BY_DEFAULT, default=False): boolean, Optional(CONF_ICON): icon, From 2eac8b6c4643494640aa6889025ba5791c09dc36 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:50:33 -0600 Subject: [PATCH 060/139] [camera_web_server] Use header instead of mock struct (#7823) --- esphome/components/esp32_camera_web_server/camera_web_server.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp32_camera_web_server/camera_web_server.h b/esphome/components/esp32_camera_web_server/camera_web_server.h index f65625554c..3ba8f31dd7 100644 --- a/esphome/components/esp32_camera_web_server/camera_web_server.h +++ b/esphome/components/esp32_camera_web_server/camera_web_server.h @@ -11,7 +11,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" -struct httpd_req; +struct httpd_req; // NOLINT(readability-identifier-naming) namespace esphome { namespace esp32_camera_web_server { From 1c2d2bce5af36527abe758d88f68289b7bccd482 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:52:26 -0600 Subject: [PATCH 061/139] [display_menu_base] clang-tidy fixes for #7822 (#7847) --- esphome/components/display_menu_base/display_menu_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/display_menu_base/display_menu_base.cpp b/esphome/components/display_menu_base/display_menu_base.cpp index 5502623607..2d8e6ae5fc 100644 --- a/esphome/components/display_menu_base/display_menu_base.cpp +++ b/esphome/components/display_menu_base/display_menu_base.cpp @@ -280,7 +280,7 @@ bool DisplayMenuComponent::cursor_down_() { bool DisplayMenuComponent::enter_menu_() { this->displayed_item_->on_leave(); this->displayed_item_ = static_cast(this->get_selected_item_()); - this->selection_stack_.push_front({this->top_index_, this->cursor_index_}); + this->selection_stack_.emplace_front(this->top_index_, this->cursor_index_); this->cursor_index_ = this->top_index_ = 0; this->displayed_item_->on_enter(); From 536bcab5def03c8177cdfc31c6deb3aa01d8ccf3 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:52:57 -0600 Subject: [PATCH 062/139] [nextion] clang-tidy fixes for #7822 (#7852) --- esphome/components/nextion/nextion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 984db09c57..7c41f8dfe2 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -343,7 +343,7 @@ void Nextion::process_serial_() { } // nextion.tech/instruction-set/ void Nextion::process_nextion_commands_() { - if (this->command_data_.length() == 0) { + if (this->command_data_.empty()) { return; } From 2d4688a2061e5734ad136f717ba77a7dc7a9fec7 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:53:23 -0600 Subject: [PATCH 063/139] [shelly_dimmer] clang-tidy fixes for #7822 (#7844) --- esphome/components/shelly_dimmer/shelly_dimmer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index b415840bdc..d4229b2384 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -466,7 +466,7 @@ bool ShellyDimmer::handle_frame_() { } case SHELLY_DIMMER_PROTO_CMD_SWITCH: case SHELLY_DIMMER_PROTO_CMD_SETTINGS: { - return !(payload_len < 1 || payload[0] != 0x01); + return payload_len >= 1 && payload[0] == 0x01; } default: { return false; From e6bd2238ce1fceef7db2cadbae3736a5759e16b2 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:54:16 -0600 Subject: [PATCH 064/139] [sim800l] clang-tidy fixes for #7822 (#7856) --- esphome/components/sim800l/sim800l.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sim800l/sim800l.cpp b/esphome/components/sim800l/sim800l.cpp index 4f7aa228e9..38775b0062 100644 --- a/esphome/components/sim800l/sim800l.cpp +++ b/esphome/components/sim800l/sim800l.cpp @@ -324,7 +324,7 @@ void Sim800LComponent::parse_cmd_(std::string message) { this->sms_received_callback_.call(this->message_, this->sender_); this->state_ = STATE_RECEIVED_SMS; } else { - if (this->message_.length() > 0) + if (!this->message_.empty()) this->message_ += "\n"; this->message_ += message; } From 6b59f55a5097f40c3db18ded853cc27888bd2885 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:58:18 -0600 Subject: [PATCH 065/139] [nfc, pn532, pn7150, pn7160] clang-tidy fixes for #7822 (#7853) --- esphome/components/nfc/ndef_record.cpp | 6 +++--- esphome/components/pn532/pn532_mifare_ultralight.cpp | 4 ++-- esphome/components/pn7150/pn7150_mifare_ultralight.cpp | 4 ++-- esphome/components/pn7160/pn7160_mifare_ultralight.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/esphome/components/nfc/ndef_record.cpp b/esphome/components/nfc/ndef_record.cpp index 8eb0c3b901..540ba62940 100644 --- a/esphome/components/nfc/ndef_record.cpp +++ b/esphome/components/nfc/ndef_record.cpp @@ -30,13 +30,13 @@ std::vector NdefRecord::encode(bool first, bool last) { data.push_back(payload_length & 0xFF); } - if (this->id_.length()) { + if (!this->id_.empty()) { data.push_back(this->id_.length()); } data.insert(data.end(), this->type_.begin(), this->type_.end()); - if (this->id_.length()) { + if (!this->id_.empty()) { data.insert(data.end(), this->id_.begin(), this->id_.end()); } @@ -55,7 +55,7 @@ uint8_t NdefRecord::create_flag_byte(bool first, bool last, size_t payload_size) if (payload_size <= 255) { value = value | 0x10; // Set SR bit } - if (this->id_.length()) { + if (!this->id_.empty()) { value = value | 0x08; // Set IL bit } return value; diff --git a/esphome/components/pn532/pn532_mifare_ultralight.cpp b/esphome/components/pn532/pn532_mifare_ultralight.cpp index b08a7336c7..f823829a6c 100644 --- a/esphome/components/pn532/pn532_mifare_ultralight.cpp +++ b/esphome/components/pn532/pn532_mifare_ultralight.cpp @@ -80,8 +80,8 @@ bool PN532::is_mifare_ultralight_formatted_(const std::vector &page_3_t const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector return (page_3_to_6.size() > p4_offset + 3) && - !((page_3_to_6[p4_offset + 0] == 0xFF) && (page_3_to_6[p4_offset + 1] == 0xFF) && - (page_3_to_6[p4_offset + 2] == 0xFF) && (page_3_to_6[p4_offset + 3] == 0xFF)); + ((page_3_to_6[p4_offset + 0] != 0xFF) || (page_3_to_6[p4_offset + 1] != 0xFF) || + (page_3_to_6[p4_offset + 2] != 0xFF) || (page_3_to_6[p4_offset + 3] != 0xFF)); } uint16_t PN532::read_mifare_ultralight_capacity_() { diff --git a/esphome/components/pn7150/pn7150_mifare_ultralight.cpp b/esphome/components/pn7150/pn7150_mifare_ultralight.cpp index 791b0634d6..b107f6f79e 100644 --- a/esphome/components/pn7150/pn7150_mifare_ultralight.cpp +++ b/esphome/components/pn7150/pn7150_mifare_ultralight.cpp @@ -81,8 +81,8 @@ bool PN7150::is_mifare_ultralight_formatted_(const std::vector &page_3_ const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector return (page_3_to_6.size() > p4_offset + 3) && - !((page_3_to_6[p4_offset + 0] == 0xFF) && (page_3_to_6[p4_offset + 1] == 0xFF) && - (page_3_to_6[p4_offset + 2] == 0xFF) && (page_3_to_6[p4_offset + 3] == 0xFF)); + ((page_3_to_6[p4_offset + 0] != 0xFF) || (page_3_to_6[p4_offset + 1] != 0xFF) || + (page_3_to_6[p4_offset + 2] != 0xFF) || (page_3_to_6[p4_offset + 3] != 0xFF)); } uint16_t PN7150::read_mifare_ultralight_capacity_() { diff --git a/esphome/components/pn7160/pn7160_mifare_ultralight.cpp b/esphome/components/pn7160/pn7160_mifare_ultralight.cpp index a74f23d4f2..65daac494f 100644 --- a/esphome/components/pn7160/pn7160_mifare_ultralight.cpp +++ b/esphome/components/pn7160/pn7160_mifare_ultralight.cpp @@ -81,8 +81,8 @@ bool PN7160::is_mifare_ultralight_formatted_(const std::vector &page_3_ const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector return (page_3_to_6.size() > p4_offset + 3) && - !((page_3_to_6[p4_offset + 0] == 0xFF) && (page_3_to_6[p4_offset + 1] == 0xFF) && - (page_3_to_6[p4_offset + 2] == 0xFF) && (page_3_to_6[p4_offset + 3] == 0xFF)); + ((page_3_to_6[p4_offset + 0] != 0xFF) || (page_3_to_6[p4_offset + 1] != 0xFF) || + (page_3_to_6[p4_offset + 2] != 0xFF) || (page_3_to_6[p4_offset + 3] != 0xFF)); } uint16_t PN7160::read_mifare_ultralight_capacity_() { From 31c13e4c16f18e3ae241b223a529ee5ed2a08fd8 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 03:59:29 -0600 Subject: [PATCH 066/139] [output] clang-tidy fixes for #7822 (#7854) --- esphome/components/output/float_output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/output/float_output.cpp b/esphome/components/output/float_output.cpp index f120f86f1f..e7dba1d81d 100644 --- a/esphome/components/output/float_output.cpp +++ b/esphome/components/output/float_output.cpp @@ -32,7 +32,7 @@ void FloatOutput::set_level(float state) { } #endif - if (!(state == 0.0f && this->zero_means_zero_)) // regardless of min_power_, 0.0 means off + if (state != 0.0f || !this->zero_means_zero_) // regardless of min_power_, 0.0 means off state = (state * (this->max_power_ - this->min_power_)) + this->min_power_; if (this->is_inverted()) From bdc6302ea1b17319d2529d9d5e277ba416e18687 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 04:00:03 -0600 Subject: [PATCH 067/139] [sun_gtil2] clang-tidy fixes for #7822 (#7858) --- esphome/components/sun_gtil2/sun_gtil2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sun_gtil2/sun_gtil2.cpp b/esphome/components/sun_gtil2/sun_gtil2.cpp index 1653f937dd..46b4902654 100644 --- a/esphome/components/sun_gtil2/sun_gtil2.cpp +++ b/esphome/components/sun_gtil2/sun_gtil2.cpp @@ -83,7 +83,7 @@ void SunGTIL2::handle_char_(uint8_t c) { memcpy(&msg, this->rx_message_.data(), MESSAGE_SIZE); this->rx_message_.clear(); - if (!((msg.end[0] == 0) && (msg.end[38] == 0x08))) + if ((msg.end[0] != 0) || (msg.end[38] != 0x08)) return; ESP_LOGVV(TAG, "Frequency raw value: %02x", msg.frequency); From 4c383906c490192a692cc74da82fca5d81fe17fc Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 04:00:40 -0600 Subject: [PATCH 068/139] [pipsolar] clang-tidy fixes for #7822 (#7855) --- esphome/components/pipsolar/pipsolar.cpp | 4 ++-- esphome/components/pipsolar/switch/pipsolar_switch.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index c4bc018b75..03c699e7d4 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -790,7 +790,7 @@ uint8_t Pipsolar::check_incoming_crc_() { // send next command used uint8_t Pipsolar::send_next_command_() { uint16_t crc16; - if (this->command_queue_[this->command_queue_position_].length() != 0) { + if (!this->command_queue_[this->command_queue_position_].empty()) { const char *command = this->command_queue_[this->command_queue_position_].c_str(); uint8_t byte_command[16]; uint8_t length = this->command_queue_[this->command_queue_position_].length(); @@ -846,7 +846,7 @@ void Pipsolar::queue_command_(const char *command, uint8_t length) { uint8_t next_position = command_queue_position_; for (uint8_t i = 0; i < COMMAND_QUEUE_LENGTH; i++) { uint8_t testposition = (next_position + i) % COMMAND_QUEUE_LENGTH; - if (command_queue_[testposition].length() == 0) { + if (command_queue_[testposition].empty()) { command_queue_[testposition] = command; ESP_LOGD(TAG, "Command queued successfully: %s with length %u at position %d", command, command_queue_[testposition].length(), testposition); diff --git a/esphome/components/pipsolar/switch/pipsolar_switch.cpp b/esphome/components/pipsolar/switch/pipsolar_switch.cpp index 7eaeac1c2d..be7763226b 100644 --- a/esphome/components/pipsolar/switch/pipsolar_switch.cpp +++ b/esphome/components/pipsolar/switch/pipsolar_switch.cpp @@ -10,11 +10,11 @@ static const char *const TAG = "pipsolar.switch"; void PipsolarSwitch::dump_config() { LOG_SWITCH("", "Pipsolar Switch", this); } void PipsolarSwitch::write_state(bool state) { if (state) { - if (this->on_command_.length() > 0) { + if (!this->on_command_.empty()) { this->parent_->switch_command(this->on_command_); } } else { - if (this->off_command_.length() > 0) { + if (!this->off_command_.empty()) { this->parent_->switch_command(this->off_command_); } } From 2fa8d907b3506a0db2dc4ed28940bb7d7e30ca4f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 04:01:34 -0600 Subject: [PATCH 069/139] [ltr501] clang-tidy fixes for #7822 (#7850) --- esphome/components/ltr501/ltr501.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/ltr501/ltr501.cpp b/esphome/components/ltr501/ltr501.cpp index 4f4e26f44f..b30e520f2b 100644 --- a/esphome/components/ltr501/ltr501.cpp +++ b/esphome/components/ltr501/ltr501.cpp @@ -23,7 +23,7 @@ bool operator==(const GainTimePair &lhs, const GainTimePair &rhs) { } bool operator!=(const GainTimePair &lhs, const GainTimePair &rhs) { - return !(lhs.gain == rhs.gain && lhs.time == rhs.time); + return lhs.gain != rhs.gain || lhs.time != rhs.time; } template T get_next(const T (&array)[size], const T val) { From cd1ee9660644177c99302d0698cefed6a9802361 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 04:04:50 -0600 Subject: [PATCH 070/139] [cse7766] clang-tidy fixes for #7822 (#7846) --- esphome/components/cse7766/cse7766.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index 48240464b3..3907c195d0 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -43,7 +43,7 @@ bool CSE7766Component::check_byte_() { uint8_t index = this->raw_data_index_; uint8_t byte = this->raw_data_[index]; if (index == 0) { - return !((byte != 0x55) && ((byte & 0xF0) != 0xF0) && (byte != 0xAA)); + return (byte == 0x55) || ((byte & 0xF0) == 0xF0) || (byte == 0xAA); } if (index == 1) { From be7882727448093efd3043364607ad925058606b Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Tue, 26 Nov 2024 00:05:20 -1000 Subject: [PATCH 071/139] [honeywell] use warning instead of failing (#7862) Co-authored-by: Samuel Sieb --- .../components/honeywellabp2_i2c/honeywellabp2.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp b/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp index e2910032cc..d111723669 100644 --- a/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp +++ b/esphome/components/honeywellabp2_i2c/honeywellabp2.cpp @@ -15,7 +15,7 @@ static const char *const TAG = "honeywellabp2"; void HONEYWELLABP2Sensor::read_sensor_data() { if (this->read(raw_data_, 7) != i2c::ERROR_OK) { ESP_LOGE(TAG, "Communication with ABP2 failed!"); - this->mark_failed(); + this->status_set_warning("couldn't read sensor data"); return; } float press_counts = encode_uint24(raw_data_[1], raw_data_[2], raw_data_[3]); // calculate digital pressure counts @@ -25,12 +25,13 @@ void HONEYWELLABP2Sensor::read_sensor_data() { (this->max_pressure_ - this->min_pressure_)) + this->min_pressure_; this->last_temperature_ = (temp_counts * 200 / 16777215) - 50; + this->status_clear_warning(); } void HONEYWELLABP2Sensor::start_measurement() { if (this->write(i2c_cmd_, 3) != i2c::ERROR_OK) { ESP_LOGE(TAG, "Communication with ABP2 failed!"); - this->mark_failed(); + this->status_set_warning("couldn't start measurement"); return; } this->measurement_running_ = true; @@ -39,7 +40,7 @@ void HONEYWELLABP2Sensor::start_measurement() { bool HONEYWELLABP2Sensor::is_measurement_ready() { if (this->read(raw_data_, 1) != i2c::ERROR_OK) { ESP_LOGE(TAG, "Communication with ABP2 failed!"); - this->mark_failed(); + this->status_set_warning("couldn't check measurement"); return false; } if ((raw_data_[0] & (0x1 << STATUS_BIT_BUSY)) > 0) { @@ -52,7 +53,7 @@ bool HONEYWELLABP2Sensor::is_measurement_ready() { void HONEYWELLABP2Sensor::measurement_timeout() { ESP_LOGE(TAG, "Timeout!"); this->measurement_running_ = false; - this->mark_failed(); + this->status_set_warning("measurement timed out"); } float HONEYWELLABP2Sensor::get_pressure() { return this->last_pressure_; } @@ -79,7 +80,7 @@ void HONEYWELLABP2Sensor::update() { ESP_LOGV(TAG, "Update Honeywell ABP2 Sensor"); this->start_measurement(); - this->set_timeout("meas_timeout", 50, [this] { this->measurement_timeout(); }); + this->set_timeout("meas_timeout", 100, [this] { this->measurement_timeout(); }); } void HONEYWELLABP2Sensor::dump_config() { From 2b9013699d841a7878a796f5621adfa3461f597d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 04:05:39 -0600 Subject: [PATCH 072/139] [alarm_control_panel] clang-tidy fixes for #7822 (#7845) --- .../alarm_control_panel/alarm_control_panel_call.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp b/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp index b1d2b2a097..7bb9b9989c 100644 --- a/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp +++ b/esphome/components/alarm_control_panel/alarm_control_panel_call.cpp @@ -72,10 +72,9 @@ void AlarmControlPanelCall::validate_() { this->state_.reset(); return; } - if (state == ACP_STATE_DISARMED && - !(this->parent_->is_state_armed(this->parent_->get_state()) || - this->parent_->get_state() == ACP_STATE_PENDING || this->parent_->get_state() == ACP_STATE_ARMING || - this->parent_->get_state() == ACP_STATE_TRIGGERED)) { + if (state == ACP_STATE_DISARMED && !this->parent_->is_state_armed(this->parent_->get_state()) && + this->parent_->get_state() != ACP_STATE_PENDING && this->parent_->get_state() != ACP_STATE_ARMING && + this->parent_->get_state() != ACP_STATE_TRIGGERED) { ESP_LOGW(TAG, "Cannot disarm when not armed"); this->state_.reset(); return; From 3730b0310b23c989c8c27d5701c3d423b6c749d6 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 12:07:36 -0600 Subject: [PATCH 073/139] [sprinkler] clang-tidy fixes for #7822 (#7857) --- esphome/components/sprinkler/sprinkler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 59565251c3..5384d29871 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -419,7 +419,7 @@ void Sprinkler::add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControll SprinklerValve *new_valve = &this->valve_[new_valve_number]; new_valve->controller_switch = valve_sw; - new_valve->controller_switch->set_state_lambda([=]() -> optional { + new_valve->controller_switch->set_state_lambda([this, new_valve_number]() -> optional { if (this->valve_pump_switch(new_valve_number) != nullptr) { return this->valve_switch(new_valve_number)->state() && this->valve_pump_switch(new_valve_number)->state(); } @@ -445,7 +445,7 @@ void Sprinkler::add_controller(Sprinkler *other_controller) { this->other_contro void Sprinkler::set_controller_main_switch(SprinklerControllerSwitch *controller_switch) { this->controller_sw_ = controller_switch; - controller_switch->set_state_lambda([=]() -> optional { + controller_switch->set_state_lambda([this]() -> optional { for (size_t valve_number = 0; valve_number < this->number_of_valves(); valve_number++) { if (this->valve_[valve_number].controller_switch->state) { return true; From 53691d28a81644b84f82e4441da153b27cbfddd7 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 12:07:42 -0600 Subject: [PATCH 074/139] [haier] clang-tidy fixes for #7822 (#7849) --- esphome/components/haier/hon_climate.cpp | 135 ++++++++++------------- 1 file changed, 60 insertions(+), 75 deletions(-) diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index e7be1fa418..85e9cf37b9 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -1069,19 +1069,17 @@ void HonClimate::fill_control_messages_queue_() { climate_control = this->current_hvac_settings_; // Beeper command { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::BEEPER_STATUS, - this->get_beeper_state() ? ZERO_BUF : ONE_BUF, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::BEEPER_STATUS, + this->get_beeper_state() ? ZERO_BUF : ONE_BUF, 2); } // Health mode { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::HEALTH_MODE, - this->get_health_mode() ? ONE_BUF : ZERO_BUF, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::HEALTH_MODE, + this->get_health_mode() ? ONE_BUF : ZERO_BUF, 2); this->health_mode_ = (SwitchState) ((uint8_t) this->health_mode_ & 0b01); } // Climate mode @@ -1099,51 +1097,46 @@ void HonClimate::fill_control_messages_queue_() { case CLIMATE_MODE_HEAT_COOL: new_power = true; buffer[1] = (uint8_t) hon_protocol::ConditioningMode::AUTO; - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::AC_MODE, - buffer, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::AC_MODE, + buffer, 2); fan_mode_buf[1] = this->other_modes_fan_speed_; break; case CLIMATE_MODE_HEAT: new_power = true; buffer[1] = (uint8_t) hon_protocol::ConditioningMode::HEAT; - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::AC_MODE, - buffer, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::AC_MODE, + buffer, 2); fan_mode_buf[1] = this->other_modes_fan_speed_; break; case CLIMATE_MODE_DRY: new_power = true; buffer[1] = (uint8_t) hon_protocol::ConditioningMode::DRY; - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::AC_MODE, - buffer, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::AC_MODE, + buffer, 2); fan_mode_buf[1] = this->other_modes_fan_speed_; break; case CLIMATE_MODE_FAN_ONLY: new_power = true; buffer[1] = (uint8_t) hon_protocol::ConditioningMode::FAN; - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::AC_MODE, - buffer, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::AC_MODE, + buffer, 2); fan_mode_buf[1] = this->other_modes_fan_speed_; // Auto doesn't work in fan only mode break; case CLIMATE_MODE_COOL: new_power = true; buffer[1] = (uint8_t) hon_protocol::ConditioningMode::COOL; - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::AC_MODE, - buffer, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::AC_MODE, + buffer, 2); fan_mode_buf[1] = this->other_modes_fan_speed_; break; default: @@ -1153,11 +1146,10 @@ void HonClimate::fill_control_messages_queue_() { } // Climate power { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::AC_POWER, - new_power ? ONE_BUF : ZERO_BUF, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::AC_POWER, + new_power ? ONE_BUF : ZERO_BUF, 2); } // CLimate preset { @@ -1199,36 +1191,32 @@ void HonClimate::fill_control_messages_queue_() { } auto presets = this->traits_.get_supported_presets(); if (quiet_mode_buf[1] != 0xFF) { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::QUIET_MODE, - quiet_mode_buf, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::QUIET_MODE, + quiet_mode_buf, 2); } if ((fast_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_BOOST) != presets.end()))) { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::FAST_MODE, - fast_mode_buf, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::FAST_MODE, + fast_mode_buf, 2); } if ((away_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_AWAY) != presets.end()))) { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::TEN_DEGREE, - away_mode_buf, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::TEN_DEGREE, + away_mode_buf, 2); } } // Target temperature if (climate_control.target_temperature.has_value() && (this->mode != ClimateMode::CLIMATE_MODE_FAN_ONLY)) { uint8_t buffer[2] = {0x00, 0x00}; buffer[1] = ((uint8_t) climate_control.target_temperature.value()) - 16; - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::SET_POINT, - buffer, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::SET_POINT, + buffer, 2); } // Vertical swing mode if (climate_control.swing_mode.has_value()) { @@ -1248,16 +1236,14 @@ void HonClimate::fill_control_messages_queue_() { case CLIMATE_SWING_BOTH: break; } - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::HORIZONTAL_SWING_MODE, - horizontal_swing_buf, 2)); - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::VERTICAL_SWING_MODE, - vertical_swing_buf, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::HORIZONTAL_SWING_MODE, + horizontal_swing_buf, 2); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::VERTICAL_SWING_MODE, + vertical_swing_buf, 2); } // Fan mode if (climate_control.fan_mode.has_value()) { @@ -1280,11 +1266,10 @@ void HonClimate::fill_control_messages_queue_() { break; } if (fan_mode_buf[1] != 0xFF) { - this->control_messages_queue_.push( - haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, - (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + - (uint8_t) hon_protocol::DataParameters::FAN_MODE, - fan_mode_buf, 2)); + this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL, + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + + (uint8_t) hon_protocol::DataParameters::FAN_MODE, + fan_mode_buf, 2); } } } From 39f3f795e2b927af404e80286d5af8100fc7c80d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 12:07:53 -0600 Subject: [PATCH 075/139] [mqtt] clang-tidy fixes for #7822 (#7851) --- esphome/components/mqtt/mqtt_backend_esp32.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/mqtt/mqtt_backend_esp32.cpp b/esphome/components/mqtt/mqtt_backend_esp32.cpp index ed500c6d44..2cccb957eb 100644 --- a/esphome/components/mqtt/mqtt_backend_esp32.cpp +++ b/esphome/components/mqtt/mqtt_backend_esp32.cpp @@ -151,11 +151,11 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) { break; case MQTT_EVENT_DATA: { static std::string topic; - if (event.topic.length() > 0) { + if (!event.topic.empty()) { topic = event.topic; } ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str()); - this->on_message_.call(event.topic.length() > 0 ? topic.c_str() : nullptr, event.data.data(), event.data.size(), + this->on_message_.call(!event.topic.empty() ? topic.c_str() : nullptr, event.data.data(), event.data.size(), event.current_data_offset, event.total_data_len); } break; case MQTT_EVENT_ERROR: @@ -184,7 +184,7 @@ void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t b // queue event to decouple processing if (instance) { auto event = *static_cast(event_data); - instance->mqtt_events_.push(Event(event)); + instance->mqtt_events_.emplace(event); } } From e3d673d16c766181c9cda046cca78bc17e0936a6 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 26 Nov 2024 12:08:02 -0600 Subject: [PATCH 076/139] [helpers, optional] clang-tidy fixes for #7822 (#7841) --- esphome/core/helpers.cpp | 2 +- esphome/core/optional.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index befc84516c..103173095b 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -293,7 +293,7 @@ std::string str_sanitize(const std::string &str) { std::replace_if( out.begin(), out.end(), [](const char &c) { - return !(c == '-' || c == '_' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + return c != '-' && c != '_' && (c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z'); }, '_'); return out; diff --git a/esphome/core/optional.h b/esphome/core/optional.h index 1e28ef1354..591bc7aa68 100644 --- a/esphome/core/optional.h +++ b/esphome/core/optional.h @@ -59,7 +59,7 @@ template class optional { // NOLINT return *this; } - void swap(optional &rhs) { + void swap(optional &rhs) noexcept { using std::swap; if (has_value() && rhs.has_value()) { swap(**this, *rhs); @@ -206,7 +206,7 @@ template inline bool operator>=(U const &v, optional // Specialized algorithms -template void swap(optional &x, optional &y) { x.swap(y); } +template void swap(optional &x, optional &y) noexcept { x.swap(y); } // Convenience function to create an optional. From 921be1a17c5b8fdd638518e8c3c92f87ed0cca2d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 27 Nov 2024 07:09:16 +1300 Subject: [PATCH 077/139] Move ``USE_CAPTIVE_PORTAL`` into all define groups it can be used with (#7863) --- esphome/core/defines.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 3798ddba6a..eb3b20d007 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -84,7 +84,6 @@ // Arduino-specific feature flags #ifdef USE_ARDUINO -#define USE_CAPTIVE_PORTAL #define USE_PROMETHEUS #define USE_WIFI_WPA2_EAP #endif @@ -97,6 +96,7 @@ // ESP32-specific feature flags #ifdef USE_ESP32 #define USE_BLUETOOTH_PROXY +#define USE_CAPTIVE_PORTAL #define USE_ESP32_BLE #define USE_ESP32_BLE_CLIENT #define USE_ESP32_BLE_SERVER @@ -135,6 +135,7 @@ #ifdef USE_ESP8266 #define USE_ADC_SENSOR_VCC #define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 1, 2) +#define USE_CAPTIVE_PORTAL #define USE_ESP8266_PREFERENCES_FLASH #define USE_HTTP_REQUEST_ESP8266_HTTPS #define USE_SOCKET_IMPL_LWIP_TCP @@ -159,6 +160,7 @@ #endif #ifdef USE_LIBRETINY +#define USE_CAPTIVE_PORTAL #define USE_SOCKET_IMPL_LWIP_SOCKETS #define USE_WEBSERVER #define USE_WEBSERVER_PORT 80 // NOLINT From 3a8b41daa3297b77175a2303be3036fb93c16954 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:06:56 +0100 Subject: [PATCH 078/139] Bump docker/build-push-action from 6.9.0 to 6.10.0 in /.github/actions/build-image (#7866) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/build-image/action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index 5c686605c3..cc9894a657 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.9.0 + uses: docker/build-push-action@v6.10.0 env: DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_RECORD_UPLOAD: false @@ -72,7 +72,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.9.0 + uses: docker/build-push-action@v6.10.0 env: DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_RECORD_UPLOAD: false From a3ef2ed7fd109fc6885de3dee7245d637d5ae2a9 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Tue, 26 Nov 2024 21:56:43 +0100 Subject: [PATCH 079/139] python lint for platform components (#7864) --- esphome/components/bk72xx/__init__.py | 2 +- esphome/components/esp8266/__init__.py | 12 +++++------- esphome/components/rp2040/__init__.py | 2 +- esphome/components/rtl87xx/__init__.py | 2 +- script/build_language_schema.py | 16 +++++++--------- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/esphome/components/bk72xx/__init__.py b/esphome/components/bk72xx/__init__.py index 6737631ac7..b5122de956 100644 --- a/esphome/components/bk72xx/__init__.py +++ b/esphome/components/bk72xx/__init__.py @@ -15,7 +15,7 @@ from esphome.components.libretiny.const import ( ) from esphome.core import CORE -from .boards import BK72XX_BOARDS, BK72XX_BOARD_PINS +from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS CODEOWNERS = ["@kuba2k2"] AUTO_LOAD = ["libretiny"] diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 64b127bda3..c73027fe1b 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -1,10 +1,13 @@ import logging import os +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_FRAMEWORK, + CONF_PLATFORM_VERSION, CONF_SOURCE, CONF_VERSION, KEY_CORE, @@ -12,27 +15,22 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_ESP8266, - CONF_PLATFORM_VERSION, ) from esphome.core import CORE, coroutine_with_priority -import esphome.config_validation as cv -import esphome.codegen as cg from esphome.helpers import copy_file_if_changed +from .boards import BOARDS, ESP8266_LD_SCRIPTS from .const import ( - CONF_RESTORE_FROM_FLASH, CONF_EARLY_PIN_INIT, + CONF_RESTORE_FROM_FLASH, KEY_BOARD, KEY_ESP8266, KEY_FLASH_SIZE, KEY_PIN_INITIAL_STATES, esp8266_ns, ) -from .boards import BOARDS, ESP8266_LD_SCRIPTS - from .gpio import PinInitialState, add_pin_initial_states_array - CODEOWNERS = ["@esphome/core"] _LOGGER = logging.getLogger(__name__) AUTO_LOAD = ["preferences"] diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index d612631a4c..b04e539182 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -17,7 +17,7 @@ from esphome.const import ( PLATFORM_RP2040, ) from esphome.core import CORE, EsphomeError, coroutine_with_priority -from esphome.helpers import copy_file_if_changed, mkdir_p, write_file, read_file +from esphome.helpers import copy_file_if_changed, mkdir_p, read_file, write_file from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns diff --git a/esphome/components/rtl87xx/__init__.py b/esphome/components/rtl87xx/__init__.py index 9060a7c4a6..4c1956f0f4 100644 --- a/esphome/components/rtl87xx/__init__.py +++ b/esphome/components/rtl87xx/__init__.py @@ -15,7 +15,7 @@ from esphome.components.libretiny.const import ( ) from esphome.core import CORE -from .boards import RTL87XX_BOARDS, RTL87XX_BOARD_PINS +from .boards import RTL87XX_BOARD_PINS, RTL87XX_BOARDS CODEOWNERS = ["@kuba2k2"] AUTO_LOAD = ["libretiny"] diff --git a/script/build_language_schema.py b/script/build_language_schema.py index 8b2c28b06b..2023dc0402 100644 --- a/script/build_language_schema.py +++ b/script/build_language_schema.py @@ -394,9 +394,8 @@ def add_referenced_recursive(referenced_schemas, config_var, path, eat_schema=Fa for k in schema.get(S_EXTENDS, []): if k not in referenced_schemas: referenced_schemas[k] = [path] - else: - if path not in referenced_schemas[k]: - referenced_schemas[k].append(path) + elif path not in referenced_schemas[k]: + referenced_schemas[k].append(path) s1 = get_str_path_schema(k) p = k.split(".") @@ -868,13 +867,12 @@ def convert(schema, config_var, path): config_var[S_TYPE] = "use_id" else: print("TODO deferred?") + elif isinstance(data, str): + # TODO: Figure out why pipsolar does this + config_var["use_id_type"] = data else: - if isinstance(data, str): - # TODO: Figure out why pipsolar does this - config_var["use_id_type"] = data - else: - config_var["use_id_type"] = str(data.base) - config_var[S_TYPE] = "use_id" + config_var["use_id_type"] = str(data.base) + config_var[S_TYPE] = "use_id" else: raise TypeError("Unknown extracted schema type") elif config_var.get("key") == "GeneratedID": From e6c730ab109ee2b896283399c3f7453c1591d1de Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:16:54 -0600 Subject: [PATCH 080/139] [max31865] clang-tidy fixes for #7822 (#7876) --- esphome/components/max31865/max31865.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/max31865/max31865.cpp b/esphome/components/max31865/max31865.cpp index b48aa2fdd3..4749874ac7 100644 --- a/esphome/components/max31865/max31865.cpp +++ b/esphome/components/max31865/max31865.cpp @@ -106,7 +106,8 @@ void MAX31865Sensor::read_data_() { // Check faults const uint8_t faults = this->read_register_(FAULT_STATUS_REG); - if ((has_fault_ = faults & 0b00111100)) { + has_fault_ = faults & 0b00111100; + if (has_fault_) { if (faults & (1 << 2)) { ESP_LOGE(TAG, "Overvoltage/undervoltage fault"); } @@ -125,7 +126,8 @@ void MAX31865Sensor::read_data_() { } else { this->status_clear_error(); } - if ((has_warn_ = faults & 0b11000000)) { + has_warn_ = faults & 0b11000000; + if (has_warn_) { if (faults & (1 << 6)) { ESP_LOGW(TAG, "RTD Low Threshold"); } From 8439232b11ad720c0896fa6bf66ab3594ef91a53 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:18:43 -0600 Subject: [PATCH 081/139] [esp32_ble] clang-tidy fixes for #7822 (#7883) --- esphome/components/esp32_ble/ble_uuid.cpp | 19 +++++++++---------- .../esp32_ble_tracker/esp32_ble_tracker.cpp | 5 ++++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/esphome/components/esp32_ble/ble_uuid.cpp b/esphome/components/esp32_ble/ble_uuid.cpp index 07ac719434..aa1edd96b2 100644 --- a/esphome/components/esp32_ble/ble_uuid.cpp +++ b/esphome/components/esp32_ble/ble_uuid.cpp @@ -34,7 +34,7 @@ ESPBTUUID ESPBTUUID::from_raw(const uint8_t *data) { ESPBTUUID ESPBTUUID::from_raw_reversed(const uint8_t *data) { ESPBTUUID ret; ret.uuid_.len = ESP_UUID_LEN_128; - for (int i = 0; i < ESP_UUID_LEN_128; i++) + for (uint8_t i = 0; i < ESP_UUID_LEN_128; i++) ret.uuid_.uuid.uuid128[ESP_UUID_LEN_128 - 1 - i] = data[i]; return ret; } @@ -43,30 +43,30 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) { if (data.length() == 4) { ret.uuid_.len = ESP_UUID_LEN_16; ret.uuid_.uuid.uuid16 = 0; - for (int i = 0; i < data.length();) { + for (uint i = 0; i < data.length(); i += 2) { uint8_t msb = data.c_str()[i]; uint8_t lsb = data.c_str()[i + 1]; + uint8_t lsb_shift = i <= 2 ? (2 - i) * 4 : 0; if (msb > '9') msb -= 7; if (lsb > '9') lsb -= 7; - ret.uuid_.uuid.uuid16 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << (2 - i) * 4; - i += 2; + ret.uuid_.uuid.uuid16 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << lsb_shift; } } else if (data.length() == 8) { ret.uuid_.len = ESP_UUID_LEN_32; ret.uuid_.uuid.uuid32 = 0; - for (int i = 0; i < data.length();) { + for (uint i = 0; i < data.length(); i += 2) { uint8_t msb = data.c_str()[i]; uint8_t lsb = data.c_str()[i + 1]; + uint8_t lsb_shift = i <= 6 ? (6 - i) * 4 : 0; if (msb > '9') msb -= 7; if (lsb > '9') lsb -= 7; - ret.uuid_.uuid.uuid32 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << (6 - i) * 4; - i += 2; + ret.uuid_.uuid.uuid32 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << lsb_shift; } } else if (data.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be // investigated (lack of time) @@ -77,7 +77,7 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) { // UUID format. ret.uuid_.len = ESP_UUID_LEN_128; int n = 0; - for (int i = 0; i < data.length();) { + for (uint i = 0; i < data.length(); i += 2) { if (data.c_str()[i] == '-') i++; uint8_t msb = data.c_str()[i]; @@ -88,7 +88,6 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) { if (lsb > '9') lsb -= 7; ret.uuid_.uuid.uuid128[15 - n++] = ((msb & 0x0F) << 4) | (lsb & 0x0F); - i += 2; } } else { ESP_LOGE(TAG, "ERROR: UUID value not 2, 4, 16 or 36 bytes - %s", data.c_str()); @@ -155,7 +154,7 @@ bool ESPBTUUID::operator==(const ESPBTUUID &uuid) const { } break; case ESP_UUID_LEN_128: - for (int i = 0; i < ESP_UUID_LEN_128; i++) { + for (uint8_t i = 0; i < ESP_UUID_LEN_128; i++) { if (uuid.uuid_.uuid.uuid128[i] != this->uuid_.uuid.uuid128[i]) { return false; } diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index b86d32ee61..6d051e3d4a 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -432,7 +432,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE ESP_LOGVV(TAG, "Parse Result:"); - const char *address_type = ""; + const char *address_type; switch (this->address_type_) { case BLE_ADDR_TYPE_PUBLIC: address_type = "PUBLIC"; @@ -446,6 +446,9 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e case BLE_ADDR_TYPE_RPA_RANDOM: address_type = "RPA_RANDOM"; break; + default: + address_type = "UNKNOWN"; + break; } ESP_LOGVV(TAG, " Address: %02X:%02X:%02X:%02X:%02X:%02X (%s)", this->address_[0], this->address_[1], this->address_[2], this->address_[3], this->address_[4], this->address_[5], address_type); From f2e8e655ba6476301842f260197e8e52f4ce71eb Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:19:41 -0600 Subject: [PATCH 082/139] [mqtt] clang-tidy fixes for #7822 (#7877) --- .../components/mqtt/mqtt_alarm_control_panel.cpp | 7 ++----- esphome/components/mqtt/mqtt_climate.cpp | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp index 660a030d11..4cc4773bd3 100644 --- a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp +++ b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp @@ -80,8 +80,7 @@ const EntityBase *MQTTAlarmControlPanelComponent::get_entity() const { return th bool MQTTAlarmControlPanelComponent::send_initial_state() { return this->publish_state(); } bool MQTTAlarmControlPanelComponent::publish_state() { - bool success = true; - const char *state_s = ""; + const char *state_s; switch (this->alarm_control_panel_->get_state()) { case ACP_STATE_DISARMED: state_s = "disarmed"; @@ -116,9 +115,7 @@ bool MQTTAlarmControlPanelComponent::publish_state() { default: state_s = "unknown"; } - if (!this->publish(this->get_state_topic_(), state_s)) - success = false; - return success; + return this->publish(this->get_state_topic_(), state_s); } } // namespace mqtt diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp index 773d863835..f06574fa26 100644 --- a/esphome/components/mqtt/mqtt_climate.cpp +++ b/esphome/components/mqtt/mqtt_climate.cpp @@ -257,7 +257,7 @@ const EntityBase *MQTTClimateComponent::get_entity() const { return this->device bool MQTTClimateComponent::publish_state_() { auto traits = this->device_->get_traits(); // mode - const char *mode_s = ""; + const char *mode_s; switch (this->device_->mode) { case CLIMATE_MODE_OFF: mode_s = "off"; @@ -280,6 +280,8 @@ bool MQTTClimateComponent::publish_state_() { case CLIMATE_MODE_HEAT_COOL: mode_s = "heat_cool"; break; + default: + mode_s = "unknown"; } bool success = true; if (!this->publish(this->get_mode_state_topic(), mode_s)) @@ -343,6 +345,8 @@ bool MQTTClimateComponent::publish_state_() { case CLIMATE_PRESET_ACTIVITY: payload = "activity"; break; + default: + payload = "unknown"; } } if (this->device_->custom_preset.has_value()) @@ -352,7 +356,7 @@ bool MQTTClimateComponent::publish_state_() { } if (traits.get_supports_action()) { - const char *payload = "unknown"; + const char *payload; switch (this->device_->action) { case CLIMATE_ACTION_OFF: payload = "off"; @@ -372,6 +376,8 @@ bool MQTTClimateComponent::publish_state_() { case CLIMATE_ACTION_FAN: payload = "fan"; break; + default: + payload = "unknown"; } if (!this->publish(this->get_action_state_topic(), payload)) success = false; @@ -411,6 +417,8 @@ bool MQTTClimateComponent::publish_state_() { case CLIMATE_FAN_QUIET: payload = "quiet"; break; + default: + payload = "unknown"; } } if (this->device_->custom_fan_mode.has_value()) @@ -420,7 +428,7 @@ bool MQTTClimateComponent::publish_state_() { } if (traits.get_supports_swing_modes()) { - const char *payload = ""; + const char *payload; switch (this->device_->swing_mode) { case CLIMATE_SWING_OFF: payload = "off"; @@ -434,6 +442,8 @@ bool MQTTClimateComponent::publish_state_() { case CLIMATE_SWING_HORIZONTAL: payload = "horizontal"; break; + default: + payload = "unknown"; } if (!this->publish(this->get_swing_mode_state_topic(), payload)) success = false; From 4da57c35d0c1b1a3ec413fe8352f71d7d7e12d0e Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:20:51 -0600 Subject: [PATCH 083/139] [uln2003] clang-tidy fixes for #7822 (#7881) --- esphome/components/uln2003/uln2003.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/uln2003/uln2003.cpp b/esphome/components/uln2003/uln2003.cpp index 1af9806906..991fe53487 100644 --- a/esphome/components/uln2003/uln2003.cpp +++ b/esphome/components/uln2003/uln2003.cpp @@ -40,7 +40,7 @@ void ULN2003::dump_config() { LOG_PIN(" Pin C: ", this->pin_c_); LOG_PIN(" Pin D: ", this->pin_d_); ESP_LOGCONFIG(TAG, " Sleep when done: %s", YESNO(this->sleep_when_done_)); - const char *step_mode_s = ""; + const char *step_mode_s; switch (this->step_mode_) { case ULN2003_STEP_MODE_FULL_STEP: step_mode_s = "FULL STEP"; @@ -51,6 +51,9 @@ void ULN2003::dump_config() { case ULN2003_STEP_MODE_WAVE_DRIVE: step_mode_s = "WAVE DRIVE"; break; + default: + step_mode_s = "UNKNOWN"; + break; } ESP_LOGCONFIG(TAG, " Step Mode: %s", step_mode_s); } From 567256bd62cb39ec9706af6b36ca405e584eae5d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:21:10 -0600 Subject: [PATCH 084/139] [rotary_encoder] clang-tidy fixes for #7822 (#7880) --- esphome/components/rotary_encoder/rotary_encoder.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/rotary_encoder/rotary_encoder.cpp b/esphome/components/rotary_encoder/rotary_encoder.cpp index a3631ffe27..e9a0eac3f5 100644 --- a/esphome/components/rotary_encoder/rotary_encoder.cpp +++ b/esphome/components/rotary_encoder/rotary_encoder.cpp @@ -162,7 +162,7 @@ void RotaryEncoderSensor::dump_config() { LOG_PIN(" Pin B: ", this->pin_b_); LOG_PIN(" Pin I: ", this->pin_i_); - const LogString *restore_mode = LOG_STR(""); + const LogString *restore_mode; switch (this->restore_mode_) { case ROTARY_ENCODER_RESTORE_DEFAULT_ZERO: restore_mode = LOG_STR("Restore (Defaults to zero)"); @@ -170,6 +170,8 @@ void RotaryEncoderSensor::dump_config() { case ROTARY_ENCODER_ALWAYS_ZERO: restore_mode = LOG_STR("Always zero"); break; + default: + restore_mode = LOG_STR(""); } ESP_LOGCONFIG(TAG, " Restore Mode: %s", LOG_STR_ARG(restore_mode)); From 65a5216d17b14fddb803906074faa3fb8ef1512f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:22:18 -0600 Subject: [PATCH 085/139] [pca6416a, pca9554] clang-tidy fixes for #7822 (#7879) --- esphome/components/pca6416a/pca6416a.cpp | 8 +++++--- esphome/components/pca9554/pca9554.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/esphome/components/pca6416a/pca6416a.cpp b/esphome/components/pca6416a/pca6416a.cpp index 1f4e315644..53c0dcaf76 100644 --- a/esphome/components/pca6416a/pca6416a.cpp +++ b/esphome/components/pca6416a/pca6416a.cpp @@ -34,7 +34,7 @@ void PCA6416AComponent::setup() { } // Test to see if the device supports pull-up resistors - if (this->read_register(PCAL6416A_PULL_EN0, &value, 1, true) == esphome::i2c::ERROR_OK) { + if (this->read_register(PCAL6416A_PULL_EN0, &value, 1, true) == i2c::ERROR_OK) { this->has_pullup_ = true; } @@ -106,7 +106,8 @@ bool PCA6416AComponent::read_register_(uint8_t reg, uint8_t *value) { return false; } - if ((this->last_error_ = this->read_register(reg, value, 1, true)) != esphome::i2c::ERROR_OK) { + this->last_error_ = this->read_register(reg, value, 1, true); + if (this->last_error_ != i2c::ERROR_OK) { this->status_set_warning(); ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_); return false; @@ -122,7 +123,8 @@ bool PCA6416AComponent::write_register_(uint8_t reg, uint8_t value) { return false; } - if ((this->last_error_ = this->write_register(reg, &value, 1, true)) != esphome::i2c::ERROR_OK) { + this->last_error_ = this->write_register(reg, &value, 1, true); + if (this->last_error_ != i2c::ERROR_OK) { this->status_set_warning(); ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_); return false; diff --git a/esphome/components/pca9554/pca9554.cpp b/esphome/components/pca9554/pca9554.cpp index c5a4bcfb09..78b877072a 100644 --- a/esphome/components/pca9554/pca9554.cpp +++ b/esphome/components/pca9554/pca9554.cpp @@ -95,8 +95,8 @@ bool PCA9554Component::read_inputs_() { return false; } - if ((this->last_error_ = this->read_register(INPUT_REG * this->reg_width_, inputs, this->reg_width_, true)) != - esphome::i2c::ERROR_OK) { + this->last_error_ = this->read_register(INPUT_REG * this->reg_width_, inputs, this->reg_width_, true); + if (this->last_error_ != i2c::ERROR_OK) { this->status_set_warning(); ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_); return false; @@ -113,8 +113,8 @@ bool PCA9554Component::write_register_(uint8_t reg, uint16_t value) { uint8_t outputs[2]; outputs[0] = (uint8_t) value; outputs[1] = (uint8_t) (value >> 8); - if ((this->last_error_ = this->write_register(reg * this->reg_width_, outputs, this->reg_width_, true)) != - esphome::i2c::ERROR_OK) { + this->last_error_ = this->write_register(reg * this->reg_width_, outputs, this->reg_width_, true); + if (this->last_error_ != i2c::ERROR_OK) { this->status_set_warning(); ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_); return false; From a825ef59d47d0550983c733d5730d41ff52eaef7 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:22:37 -0600 Subject: [PATCH 086/139] [nextion] clang-tidy fixes for #7822 (#7878) --- esphome/components/nextion/nextion.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 7c41f8dfe2..50a5834347 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -563,13 +563,10 @@ void Nextion::process_nextion_commands_() { break; } - int dataindex = 0; - int value = 0; for (int i = 0; i < 4; ++i) { value += to_process[i] << (8 * i); - ++dataindex; } NextionQueue *nb = this->nextion_queue_.front(); From 12cdeca48a78169069e462c3dc8785268d9ac90f Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:23:20 -0600 Subject: [PATCH 087/139] [various] clang-tidy fixes for #7822 (#7874) --- .../hitachi_ac344/hitachi_ac344.cpp | 6 ++- .../hitachi_ac424/hitachi_ac424.cpp | 6 ++- .../components/ili9xxx/ili9xxx_display.cpp | 5 +- esphome/components/qspi_dbi/qspi_dbi.cpp | 3 +- esphome/components/st7735/st7735.cpp | 2 +- esphome/components/st7789v/st7789v.cpp | 2 +- esphome/components/udp/udp_component.cpp | 48 ++++++++++++------- esphome/core/component.cpp | 2 +- 8 files changed, 48 insertions(+), 26 deletions(-) diff --git a/esphome/components/hitachi_ac344/hitachi_ac344.cpp b/esphome/components/hitachi_ac344/hitachi_ac344.cpp index 2825e4f04c..2bcb205644 100644 --- a/esphome/components/hitachi_ac344/hitachi_ac344.cpp +++ b/esphome/components/hitachi_ac344/hitachi_ac344.cpp @@ -133,8 +133,10 @@ bool HitachiClimate::get_swing_v_() { } void HitachiClimate::set_swing_h_(uint8_t position) { - if (position > HITACHI_AC344_SWINGH_LEFT_MAX) - return set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE); + if (position > HITACHI_AC344_SWINGH_LEFT_MAX) { + set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE); + return; + } set_bits(&remote_state_[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE, position); set_button_(HITACHI_AC344_BUTTON_SWINGH); } diff --git a/esphome/components/hitachi_ac424/hitachi_ac424.cpp b/esphome/components/hitachi_ac424/hitachi_ac424.cpp index 0bfc3ae564..64f23dfc17 100644 --- a/esphome/components/hitachi_ac424/hitachi_ac424.cpp +++ b/esphome/components/hitachi_ac424/hitachi_ac424.cpp @@ -133,8 +133,10 @@ bool HitachiClimate::get_swing_v_() { } void HitachiClimate::set_swing_h_(uint8_t position) { - if (position > HITACHI_AC424_SWINGH_LEFT_MAX) - return set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE); + if (position > HITACHI_AC424_SWINGH_LEFT_MAX) { + set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE); + return; + } set_bits(&remote_state_[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET, HITACHI_AC424_SWINGH_SIZE, position); set_button_(HITACHI_AC424_BUTTON_SWINGH); } diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 81976dd2c9..b9664067a9 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -313,8 +313,9 @@ void ILI9XXXDisplay::draw_pixels_at(int x_start, int y_start, int w, int h, cons // do color conversion pixel-by-pixel into the buffer and draw it later. If this is happening the user has not // configured the renderer well. if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || !big_endian) { - return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, - x_pad); + display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, + x_pad); + return; } this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1); // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. diff --git a/esphome/components/qspi_dbi/qspi_dbi.cpp b/esphome/components/qspi_dbi/qspi_dbi.cpp index 785885d4ec..f8fd5dd374 100644 --- a/esphome/components/qspi_dbi/qspi_dbi.cpp +++ b/esphome/components/qspi_dbi/qspi_dbi.cpp @@ -146,7 +146,8 @@ void QspiDbi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8 return; if (bitness != display::COLOR_BITNESS_565 || order != this->color_mode_ || big_endian != (this->bit_order_ == spi::BIT_ORDER_MSB_FIRST)) { - return Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad); + Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad); + return; } else if (this->draw_from_origin_) { auto stride = x_offset + w + x_pad; for (int y = 0; y != h; y++) { diff --git a/esphome/components/st7735/st7735.cpp b/esphome/components/st7735/st7735.cpp index a0c2d80d16..5985d8bfb3 100644 --- a/esphome/components/st7735/st7735.cpp +++ b/esphome/components/st7735/st7735.cpp @@ -483,7 +483,7 @@ void ST7735::spi_master_write_color_(uint16_t color, uint16_t size) { } this->dc_pin_->digital_write(true); - return write_array(byte, size * 2); + write_array(byte, size * 2); } } // namespace st7735 diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index 74c7a4e9e3..0d2f35aef5 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -252,7 +252,7 @@ void ST7789V::write_color_(uint16_t color, uint16_t size) { } this->dc_pin_->digital_write(true); - return write_array(byte, size * 2); + write_array(byte, size * 2); } size_t ST7789V::get_buffer_length_() { diff --git a/esphome/components/udp/udp_component.cpp b/esphome/components/udp/udp_component.cpp index a1c8889997..b8727ec423 100644 --- a/esphome/components/udp/udp_component.cpp +++ b/esphome/components/udp/udp_component.cpp @@ -434,7 +434,8 @@ static bool process_rolling_code(Provider &provider, uint8_t *&buf, const uint8_ void UDPComponent::process_(uint8_t *buf, const size_t len) { auto ping_key_seen = !this->ping_pong_enable_; if (len < 8) { - return ESP_LOGV(TAG, "Bad length %zu", len); + ESP_LOGV(TAG, "Bad length %zu", len); + return; } char namebuf[256]{}; uint8_t byte; @@ -442,31 +443,40 @@ void UDPComponent::process_(uint8_t *buf, const size_t len) { const uint8_t *end = buf + len; FuData rdata{}; auto magic = get_uint16(buf); - if (magic != MAGIC_NUMBER && magic != MAGIC_PING) - return ESP_LOGV(TAG, "Bad magic %X", magic); + if (magic != MAGIC_NUMBER && magic != MAGIC_PING) { + ESP_LOGV(TAG, "Bad magic %X", magic); + return; + } auto hlen = *buf++; if (hlen > len - 3) { - return ESP_LOGV(TAG, "Bad hostname length %u > %zu", hlen, len - 3); + ESP_LOGV(TAG, "Bad hostname length %u > %zu", hlen, len - 3); + return; } memcpy(namebuf, buf, hlen); if (strcmp(this->name_, namebuf) == 0) { - return ESP_LOGV(TAG, "Ignoring our own data"); + ESP_LOGV(TAG, "Ignoring our own data"); + return; } buf += hlen; - if (magic == MAGIC_PING) - return this->process_ping_request_(namebuf, buf, end - buf); + if (magic == MAGIC_PING) { + this->process_ping_request_(namebuf, buf, end - buf); + return; + } if (round4(len) != len) { - return ESP_LOGW(TAG, "Bad length %zu", len); + ESP_LOGW(TAG, "Bad length %zu", len); + return; } hlen = round4(hlen + 3); buf = start_ptr + hlen; if (buf == end) { - return ESP_LOGV(TAG, "No data after header"); + ESP_LOGV(TAG, "No data after header"); + return; } if (this->providers_.count(namebuf) == 0) { - return ESP_LOGVV(TAG, "Unknown hostname %s", namebuf); + ESP_LOGVV(TAG, "Unknown hostname %s", namebuf); + return; } auto &provider = this->providers_[namebuf]; // if encryption not used with this host, ping check is pointless since it would be easily spoofed. @@ -489,7 +499,8 @@ void UDPComponent::process_(uint8_t *buf, const size_t len) { if (!process_rolling_code(provider, buf, end)) return; } else if (byte != DATA_KEY) { - return ESP_LOGV(TAG, "Expected rolling_key or data_key, got %X", byte); + ESP_LOGV(TAG, "Expected rolling_key or data_key, got %X", byte); + return; } while (buf < end) { byte = *buf++; @@ -497,7 +508,8 @@ void UDPComponent::process_(uint8_t *buf, const size_t len) { continue; if (byte == PING_KEY) { if (end - buf < 4) { - return ESP_LOGV(TAG, "PING_KEY requires 4 more bytes"); + ESP_LOGV(TAG, "PING_KEY requires 4 more bytes"); + return; } auto key = get_uint32(buf); if (key == this->ping_key_) { @@ -515,21 +527,25 @@ void UDPComponent::process_(uint8_t *buf, const size_t len) { } if (byte == BINARY_SENSOR_KEY) { if (end - buf < 3) { - return ESP_LOGV(TAG, "Binary sensor key requires at least 3 more bytes"); + ESP_LOGV(TAG, "Binary sensor key requires at least 3 more bytes"); + return; } rdata.u32 = *buf++; } else if (byte == SENSOR_KEY) { if (end - buf < 6) { - return ESP_LOGV(TAG, "Sensor key requires at least 6 more bytes"); + ESP_LOGV(TAG, "Sensor key requires at least 6 more bytes"); + return; } rdata.u32 = get_uint32(buf); } else { - return ESP_LOGW(TAG, "Unknown key byte %X", byte); + ESP_LOGW(TAG, "Unknown key byte %X", byte); + return; } hlen = *buf++; if (end - buf < hlen) { - return ESP_LOGV(TAG, "Name length of %u not available", hlen); + ESP_LOGV(TAG, "Name length of %u not available", hlen); + return; } memset(namebuf, 0, sizeof namebuf); memcpy(namebuf, buf, hlen); diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index ae73a451d9..a6224a17c0 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -67,7 +67,7 @@ bool Component::cancel_retry(const std::string &name) { // NOLINT } void Component::set_timeout(const std::string &name, uint32_t timeout, std::function &&f) { // NOLINT - return App.scheduler.set_timeout(this, name, timeout, std::move(f)); + App.scheduler.set_timeout(this, name, timeout, std::move(f)); } bool Component::cancel_timeout(const std::string &name) { // NOLINT From e229ed0da3f7113757907b1b7db1934517390c11 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:23:40 -0600 Subject: [PATCH 088/139] [logger] clang-tidy fixes for #7822 (#7875) --- esphome/components/logger/logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index dac08fbbce..36934c7459 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -47,7 +47,7 @@ void Logger::write_header_(int level, const char *tag, int line) { if (current_task == main_task_) { this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line); } else { - const char *thread_name = ""; + const char *thread_name = ""; // NOLINT(clang-analyzer-deadcode.DeadStores) #if defined(USE_ESP32) thread_name = pcTaskGetName(current_task); #elif defined(USE_LIBRETINY) From e124151e5c4c6ca925baf382e7dca19592a257c9 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:24:43 -0600 Subject: [PATCH 089/139] [ezo] clang-tidy fixes for #7822 (#7873) --- esphome/components/ezo/ezo.cpp | 40 ++++++++++++---------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/esphome/components/ezo/ezo.cpp b/esphome/components/ezo/ezo.cpp index 8e4486dbf2..10f3d530ce 100644 --- a/esphome/components/ezo/ezo.cpp +++ b/esphome/components/ezo/ezo.cpp @@ -111,11 +111,11 @@ void EZOSensor::loop() { if (buf[0] == 1) { std::string payload = reinterpret_cast(&buf[1]); if (!payload.empty()) { + auto start_location = payload.find(','); switch (to_run->command_type) { case EzoCommandType::EZO_READ: { // some sensors return multiple comma-separated values, terminate string after first one - int start_location = 0; - if ((start_location = payload.find(',')) != std::string::npos) { + if (start_location != std::string::npos) { payload.erase(start_location); } auto val = parse_number(payload); @@ -126,49 +126,37 @@ void EZOSensor::loop() { } break; } - case EzoCommandType::EZO_LED: { + case EzoCommandType::EZO_LED: this->led_callback_.call(payload.back() == '1'); break; - } - case EzoCommandType::EZO_DEVICE_INFORMATION: { - int start_location = 0; - if ((start_location = payload.find(',')) != std::string::npos) { + case EzoCommandType::EZO_DEVICE_INFORMATION: + if (start_location != std::string::npos) { this->device_infomation_callback_.call(payload.substr(start_location + 1)); } break; - } - case EzoCommandType::EZO_SLOPE: { - int start_location = 0; - if ((start_location = payload.find(',')) != std::string::npos) { + case EzoCommandType::EZO_SLOPE: + if (start_location != std::string::npos) { this->slope_callback_.call(payload.substr(start_location + 1)); } break; - } - case EzoCommandType::EZO_CALIBRATION: { - int start_location = 0; - if ((start_location = payload.find(',')) != std::string::npos) { + case EzoCommandType::EZO_CALIBRATION: + if (start_location != std::string::npos) { this->calibration_callback_.call(payload.substr(start_location + 1)); } break; - } - case EzoCommandType::EZO_T: { - int start_location = 0; - if ((start_location = payload.find(',')) != std::string::npos) { + case EzoCommandType::EZO_T: + if (start_location != std::string::npos) { this->t_callback_.call(payload.substr(start_location + 1)); } break; - } - case EzoCommandType::EZO_CUSTOM: { + case EzoCommandType::EZO_CUSTOM: this->custom_callback_.call(payload); break; - } - default: { + default: break; - } } } } - this->commands_.pop_front(); } @@ -178,7 +166,7 @@ void EZOSensor::add_command_(const std::string &command, EzoCommandType command_ ezo_command->command_type = command_type; ezo_command->delay_ms = delay_ms; this->commands_.push_back(std::move(ezo_command)); -}; +} void EZOSensor::set_calibration_point_(EzoCalibrationType type, float value) { std::string payload = str_sprintf("Cal,%s,%0.2f", EZO_CALIBRATION_TYPE_STRINGS[type], value); From 7aa3a1a1ccdb8e3cf2df837817e18a7307b90640 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:25:00 -0600 Subject: [PATCH 090/139] [apds9306] clang-tidy fixes for #7822 (#7872) --- esphome/components/apds9306/apds9306.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/apds9306/apds9306.cpp b/esphome/components/apds9306/apds9306.cpp index 7b79b0964c..bbb3ba1910 100644 --- a/esphome/components/apds9306/apds9306.cpp +++ b/esphome/components/apds9306/apds9306.cpp @@ -122,7 +122,8 @@ void APDS9306::update() { this->status_clear_warning(); - if (!(status &= 0b00001000)) { // No new data + status &= 0b00001000; + if (!status) { // No new data return; } From ff5004d7db6514536dfd0e28ec3d114bb14b120c Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:25:15 -0600 Subject: [PATCH 091/139] [dht] clang-tidy fixes for #7822 (#7871) --- esphome/components/dht/dht.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/dht/dht.cpp b/esphome/components/dht/dht.cpp index db1c851d5f..3f9f9c57f4 100644 --- a/esphome/components/dht/dht.cpp +++ b/esphome/components/dht/dht.cpp @@ -135,7 +135,8 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r // Wait for falling edge while (this->pin_->digital_read()) { - if ((end_time = micros()) - start_time > 90) { + end_time = micros(); + if (end_time - start_time > 90) { if (i < 0) { error_code = 3; } else { From d30587028412d80a02ea1fc4ef7cd0085b1508d8 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 27 Nov 2024 16:25:34 -0600 Subject: [PATCH 092/139] [network] clang-tidy fixes for #7822 (#7870) --- esphome/components/network/ip_address.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index 941934cf0a..69d3788ca5 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -116,7 +116,7 @@ struct IPAddress { operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); } #endif - bool is_set() { return !ip_addr_isany(&ip_addr_); } + bool is_set() { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr) bool is_ip4() { return IP_IS_V4(&ip_addr_); } bool is_ip6() { return IP_IS_V6(&ip_addr_); } std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); } From c9b0490305fb402f13f7ee4ee449db9d207c978e Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 28 Nov 2024 14:48:48 +1100 Subject: [PATCH 093/139] [lvgl] Make image update via lambda work (#7886) --- esphome/components/lvgl/defines.py | 8 +++++- esphome/components/lvgl/lv_validation.py | 11 +++++--- esphome/components/lvgl/lvgl_esphome.h | 16 ++++++++++++ esphome/components/lvgl/widgets/animimg.py | 29 +++++++++------------- esphome/components/lvgl/widgets/img.py | 2 -- tests/components/lvgl/lvgl-package.yaml | 12 ++++++--- tests/components/lvgl/test.esp32-ard.yaml | 2 +- 7 files changed, 52 insertions(+), 28 deletions(-) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index ea345fa55c..81984637bd 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -8,7 +8,7 @@ import logging from esphome import codegen as cg, config_validation as cv from esphome.const import CONF_ITEMS -from esphome.core import Lambda +from esphome.core import ID, Lambda from esphome.cpp_generator import LambdaExpression, MockObj from esphome.cpp_types import uint32 from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor @@ -72,6 +72,12 @@ class LValidator: ) if self.retmapper is not None: return self.retmapper(value) + if isinstance(value, ID): + return await cg.get_variable(value) + if isinstance(value, list): + value = [ + await cg.get_variable(x) if isinstance(x, ID) else x for x in value + ] return cg.safe_exp(value) diff --git a/esphome/components/lvgl/lv_validation.py b/esphome/components/lvgl/lv_validation.py index 766c010244..f91ed893f2 100644 --- a/esphome/components/lvgl/lv_validation.py +++ b/esphome/components/lvgl/lv_validation.py @@ -1,6 +1,7 @@ from typing import Union import esphome.codegen as cg +from esphome.components import image from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw from esphome.components.font import Font from esphome.components.image import Image_ @@ -31,7 +32,7 @@ from .defines import ( literal, ) from .helpers import add_lv_use, esphome_fonts_used, lv_fonts_used, requires_component -from .types import lv_font_t, lv_gradient_t, lv_img_t +from .types import lv_font_t, lv_gradient_t opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") @@ -332,8 +333,12 @@ def image_validator(value): lv_image = LValidator( image_validator, - lv_img_t, - retmapper=lambda x: MockObj(x, "->").get_lv_img_dsc(), + image.Image_.operator("ptr"), + requires="image", +) +lv_image_list = LValidator( + cv.ensure_list(image_validator), + cg.std_vector.template(image.Image_.operator("ptr")), requires="image", ) lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal) diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 208cb1cbd5..921b7c109f 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -57,6 +57,22 @@ inline void lv_img_set_src(lv_obj_t *obj, esphome::image::Image *image) { lv_img_set_src(obj, image->get_lv_img_dsc()); } #endif // USE_LVGL_IMAGE +#ifdef USE_LVGL_ANIMIMG +inline void lv_animimg_set_src(lv_obj_t *img, std::vector images) { + auto *dsc = static_cast *>(lv_obj_get_user_data(img)); + if (dsc == nullptr) { + // object will be lazily allocated but never freed. + dsc = new std::vector(images.size()); // NOLINT + lv_obj_set_user_data(img, dsc); + } + dsc->clear(); + for (auto &image : images) { + dsc->push_back(image->get_lv_img_dsc()); + } + lv_animimg_set_src(img, (const void **) dsc->data(), dsc->size()); +} + +#endif // USE_LVGL_ANIMIMG // Parent class for things that wrap an LVGL object class LvCompound { diff --git a/esphome/components/lvgl/widgets/animimg.py b/esphome/components/lvgl/widgets/animimg.py index 8adea72ad3..b824d28fb8 100644 --- a/esphome/components/lvgl/widgets/animimg.py +++ b/esphome/components/lvgl/widgets/animimg.py @@ -1,20 +1,18 @@ from esphome import automation -import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_DURATION, CONF_ID from ..automation import action_to_code from ..defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC from ..helpers import lvgl_components_required -from ..lv_validation import lv_image, lv_milliseconds +from ..lv_validation import lv_image_list, lv_milliseconds from ..lvcode import lv -from ..types import LvType, ObjUpdateAction, void_ptr +from ..types import LvType, ObjUpdateAction from . import Widget, WidgetType, get_widgets from .img import CONF_IMAGE from .label import CONF_LABEL CONF_ANIMIMG = "animimg" -CONF_SRC_LIST_ID = "src_list_id" def lv_repeat_count(value): @@ -32,14 +30,14 @@ ANIMIMG_BASE_SCHEMA = cv.Schema( ANIMIMG_SCHEMA = ANIMIMG_BASE_SCHEMA.extend( { cv.Required(CONF_DURATION): lv_milliseconds, - cv.Required(CONF_SRC): cv.ensure_list(lv_image), - cv.GenerateID(CONF_SRC_LIST_ID): cv.declare_id(void_ptr), + cv.Required(CONF_SRC): lv_image_list, } ) ANIMIMG_MODIFY_SCHEMA = ANIMIMG_BASE_SCHEMA.extend( { cv.Optional(CONF_DURATION): lv_milliseconds, + cv.Optional(CONF_SRC): lv_image_list, } ) @@ -59,17 +57,14 @@ class AnimimgType(WidgetType): async def to_code(self, w: Widget, config): lvgl_components_required.add(CONF_IMAGE) lvgl_components_required.add(CONF_ANIMIMG) - if CONF_SRC in config: - srcs = [ - await lv_image.process(await cg.get_variable(x)) - for x in config[CONF_SRC] - ] - src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs) - count = len(config[CONF_SRC]) - lv.animimg_set_src(w.obj, src_id, count) - lv.animimg_set_repeat_count(w.obj, config[CONF_REPEAT_COUNT]) - lv.animimg_set_duration(w.obj, config[CONF_DURATION]) - if config.get(CONF_AUTO_START): + if srcs := config.get(CONF_SRC): + srcs = await lv_image_list.process(srcs) + lv.animimg_set_src(w.obj, srcs) + if repeat_count := config.get(CONF_REPEAT_COUNT): + lv.animimg_set_repeat_count(w.obj, repeat_count) + if duration := config.get(CONF_DURATION): + lv.animimg_set_duration(w.obj, duration) + if config[CONF_AUTO_START]: lv.animimg_start(w.obj) def get_uses(self): diff --git a/esphome/components/lvgl/widgets/img.py b/esphome/components/lvgl/widgets/img.py index 931d0c0b5b..59b2c97c63 100644 --- a/esphome/components/lvgl/widgets/img.py +++ b/esphome/components/lvgl/widgets/img.py @@ -1,4 +1,3 @@ -import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ANGLE, CONF_MODE @@ -65,7 +64,6 @@ class ImgType(WidgetType): async def to_code(self, w: Widget, config): if src := config.get(CONF_SRC): - src = await cg.get_variable(src) lv.img_set_src(w.obj, await lv_image.process(src)) if (cf_angle := config.get(CONF_ANGLE)) is not None: pivot_x = config[CONF_PIVOT_X] diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index db0443b3bb..81b18c4ff8 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -171,9 +171,13 @@ lvgl: duration: 1s auto_start: true on_all_events: - logger.log: - format: "Event %s" - args: ['lv_event_code_name_for(event->code).c_str()'] + - logger.log: + format: "Event %s" + args: ['lv_event_code_name_for(event->code).c_str()'] + - lvgl.animimg.update: + id: anim_img + src: !lambda "return {dog_image, cat_image};" + duration: 2s - label: id: hello_label text: Hello world @@ -635,7 +639,7 @@ lvgl: - image: grid_cell_row_pos: 0 grid_cell_column_pos: 0 - src: dog_image + src: !lambda return dog_image; on_click: then: - lvgl.tabview.select: diff --git a/tests/components/lvgl/test.esp32-ard.yaml b/tests/components/lvgl/test.esp32-ard.yaml index 80d5ce503f..5b09147de7 100644 --- a/tests/components/lvgl/test.esp32-ard.yaml +++ b/tests/components/lvgl/test.esp32-ard.yaml @@ -55,5 +55,5 @@ lvgl: packages: lvgl: !include lvgl-package.yaml + xvgl: !include common.yaml -<<: !include common.yaml From 7cdf5b55ef637e76d13e31b596d7b7d76a5b4ab8 Mon Sep 17 00:00:00 2001 From: Max Slotov Date: Thu, 28 Nov 2024 05:51:07 +0200 Subject: [PATCH 094/139] [deep_sleep] fix deep_sleep not keeping awake when sleep_duration is defined (#7885) --- esphome/components/deep_sleep/deep_sleep_esp32.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/deep_sleep/deep_sleep_esp32.cpp b/esphome/components/deep_sleep/deep_sleep_esp32.cpp index d54046bc11..d647140865 100644 --- a/esphome/components/deep_sleep/deep_sleep_esp32.cpp +++ b/esphome/components/deep_sleep/deep_sleep_esp32.cpp @@ -52,11 +52,11 @@ void DeepSleepComponent::dump_config_platform_() { bool DeepSleepComponent::prepare_to_sleep_() { if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr && - !this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) { + this->wakeup_pin_->digital_read()) { // Defer deep sleep until inactive if (!this->next_enter_deep_sleep_) { this->status_set_warning(); - ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep..."); + ESP_LOGW(TAG, "Waiting wakeup pin state change to enter deep sleep..."); } this->next_enter_deep_sleep_ = true; return false; From beb8ab50e27f5df45e15af1cf3691309a5eb2e92 Mon Sep 17 00:00:00 2001 From: guillempages Date: Thu, 28 Nov 2024 04:55:20 +0100 Subject: [PATCH 095/139] [online_image]Don't access decoder if not initialized (#7882) --- esphome/components/online_image/png_image.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/online_image/png_image.cpp b/esphome/components/online_image/png_image.cpp index c8e215a91d..4c4c22f9b7 100644 --- a/esphome/components/online_image/png_image.cpp +++ b/esphome/components/online_image/png_image.cpp @@ -49,6 +49,10 @@ void PngDecoder::prepare(uint32_t download_size) { } int HOT PngDecoder::decode(uint8_t *buffer, size_t size) { + if (!this->pngle_) { + ESP_LOGE(TAG, "PNG decoder engine not initialized!"); + return -1; + } if (size < 256 && size < this->download_size_ - this->decoded_bytes_) { ESP_LOGD(TAG, "Waiting for data"); return 0; From 5486b40aab86f6505c62b9077b1d1737548ec554 Mon Sep 17 00:00:00 2001 From: FreeBear-nc <67865163+FreeBear-nc@users.noreply.github.com> Date: Thu, 28 Nov 2024 03:56:37 +0000 Subject: [PATCH 096/139] Add IRAM_ATTR to all functions used during interrupts on esp8266 chips. (#7840) --- esphome/components/opentherm/opentherm.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index e40fc66b7d..62ab1d3860 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -220,7 +220,7 @@ void IRAM_ATTR OpenTherm::bit_read_(uint8_t value) { this->bit_pos_++; } -ProtocolErrorType OpenTherm::verify_stop_bit_(uint8_t value) { +ProtocolErrorType IRAM_ATTR OpenTherm::verify_stop_bit_(uint8_t value) { if (value) { // stop bit detected return check_parity_(this->data_) ? ProtocolErrorType::NO_ERROR : ProtocolErrorType::PARITY_ERROR; } else { // no stop bit detected, error @@ -365,7 +365,7 @@ void IRAM_ATTR OpenTherm::stop_timer_() { #ifdef ESP8266 // 5 kHz timer_ -void OpenTherm::start_read_timer_() { +void IRAM_ATTR OpenTherm::start_read_timer_() { InterruptLock const lock; timer1_attachInterrupt(OpenTherm::esp8266_timer_isr); timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP); // 5MHz (5 ticks/us - 1677721.4 us max) @@ -373,14 +373,14 @@ void OpenTherm::start_read_timer_() { } // 2 kHz timer_ -void OpenTherm::start_write_timer_() { +void IRAM_ATTR OpenTherm::start_write_timer_() { InterruptLock const lock; timer1_attachInterrupt(OpenTherm::esp8266_timer_isr); timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP); // 5MHz (5 ticks/us - 1677721.4 us max) timer1_write(2500); // 2kHz } -void OpenTherm::stop_timer_() { +void IRAM_ATTR OpenTherm::stop_timer_() { InterruptLock const lock; timer1_disable(); timer1_detachInterrupt(); @@ -389,7 +389,7 @@ void OpenTherm::stop_timer_() { #endif // END ESP8266 // https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd -bool OpenTherm::check_parity_(uint32_t val) { +bool IRAM_ATTR OpenTherm::check_parity_(uint32_t val) { val ^= val >> 16; val ^= val >> 8; val ^= val >> 4; From 217a80a1789d235705c47862748ef2c0a8af5a1c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:57:11 +1300 Subject: [PATCH 097/139] [st7920] Remove unnecessary warning when drawing outside display bounds (#7868) --- esphome/components/st7920/st7920.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/esphome/components/st7920/st7920.cpp b/esphome/components/st7920/st7920.cpp index f336d24e24..171e7095dd 100644 --- a/esphome/components/st7920/st7920.cpp +++ b/esphome/components/st7920/st7920.cpp @@ -1,7 +1,7 @@ #include "st7920.h" -#include "esphome/core/log.h" -#include "esphome/core/application.h" #include "esphome/components/display/display_buffer.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" namespace esphome { namespace st7920 { @@ -118,7 +118,6 @@ size_t ST7920::get_buffer_length_() { void HOT ST7920::draw_absolute_pixel_internal(int x, int y, Color color) { if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) { - ESP_LOGW(TAG, "Position out of area: %dx%d", x, y); return; } int width = this->get_width_internal() / 8u; From 30477c764d9353381ef6e8bf186bae703cffbc7f Mon Sep 17 00:00:00 2001 From: Krzysztof Zdulski Date: Fri, 29 Nov 2024 22:05:00 +0100 Subject: [PATCH 098/139] Fix recalc_timestamp_utc (#7894) --- esphome/core/time.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index 31977d972b..66a0e1c0a7 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -169,7 +169,7 @@ void ESPTime::recalc_timestamp_utc(bool use_day_of_year) { } for (int i = 1970; i < this->year; i++) - res += (year % 4 == 0) ? 366 : 365; + res += (i % 4 == 0) ? 366 : 365; if (use_day_of_year) { res += this->day_of_year - 1; From 8f69d070612d9ed7e862fc31c340568dffabf9f7 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 1 Dec 2024 10:08:52 -0600 Subject: [PATCH 099/139] [hx711] clang-tidy fixes for #7822 (#7900) --- esphome/components/hx711/hx711.cpp | 2 +- esphome/components/hx711/hx711.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/hx711/hx711.cpp b/esphome/components/hx711/hx711.cpp index 1a7169eed7..9643d0c411 100644 --- a/esphome/components/hx711/hx711.cpp +++ b/esphome/components/hx711/hx711.cpp @@ -53,7 +53,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) { } // Cycle clock pin for gain setting - for (uint8_t i = 0; i < this->gain_; i++) { + for (uint8_t i = 0; i < static_cast(this->gain_); i++) { this->sck_pin_->digital_write(true); delayMicroseconds(1); this->sck_pin_->digital_write(false); diff --git a/esphome/components/hx711/hx711.h b/esphome/components/hx711/hx711.h index 0cb6868ab5..a92bb9945d 100644 --- a/esphome/components/hx711/hx711.h +++ b/esphome/components/hx711/hx711.h @@ -9,7 +9,7 @@ namespace esphome { namespace hx711 { -enum HX711Gain { +enum HX711Gain : uint8_t { HX711_GAIN_128 = 1, HX711_GAIN_32 = 2, HX711_GAIN_64 = 3, From 83d6834e277e9e9159f12653a2f39bc1113f9104 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Dec 2024 05:10:18 +1300 Subject: [PATCH 100/139] Cast port to int for ota pushing (#7888) --- esphome/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 86d529e1bf..dce041e5ac 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -363,7 +363,7 @@ def upload_program(config, args, host): from esphome import espota2 - remote_port = ota_conf[CONF_PORT] + remote_port = int(ota_conf[CONF_PORT]) password = ota_conf.get(CONF_PASSWORD, "") if ( From edd847ea403c4a0fba05d652b8e30e09fd3e6a85 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sun, 1 Dec 2024 18:27:32 -0600 Subject: [PATCH 101/139] [modbus_controller] Clang fixes (#7899) --- .../modbus_controller/modbus_controller.cpp | 40 ++++++++--------- .../modbus_controller/modbus_controller.h | 44 +++++++++---------- .../number/modbus_number.cpp | 16 +++---- .../modbus_controller/number/modbus_number.h | 8 ++-- .../output/modbus_output.cpp | 13 +++--- .../modbus_controller/output/modbus_output.h | 10 ++--- .../select/modbus_select.cpp | 7 +-- .../modbus_controller/select/modbus_select.h | 8 ++-- .../switch/modbus_switch.cpp | 8 ++-- .../modbus_controller/switch/modbus_switch.h | 4 +- 10 files changed, 80 insertions(+), 78 deletions(-) diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index f8b72af817..641ba68223 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -152,11 +152,11 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t } SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const { - auto reg_it = find_if(begin(register_ranges_), end(register_ranges_), [=](RegisterRange const &r) { + auto reg_it = find_if(begin(this->register_ranges_), end(this->register_ranges_), [=](RegisterRange const &r) { return (r.start_address == start_address && r.register_type == register_type); }); - if (reg_it == register_ranges_.end()) { + if (reg_it == this->register_ranges_.end()) { ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address); } else { return reg_it->sensors; @@ -240,18 +240,18 @@ void ModbusController::update() { // walk through the sensors and determine the register ranges to read size_t ModbusController::create_register_ranges_() { - register_ranges_.clear(); - if (this->parent_->role == modbus::ModbusRole::CLIENT && sensorset_.empty()) { + this->register_ranges_.clear(); + if (this->parent_->role == modbus::ModbusRole::CLIENT && this->sensorset_.empty()) { ESP_LOGW(TAG, "No sensors registered"); return 0; } // iterator is sorted see SensorItemsComparator for details - auto ix = sensorset_.begin(); + auto ix = this->sensorset_.begin(); RegisterRange r = {}; uint8_t buffer_offset = 0; SensorItem *prev = nullptr; - while (ix != sensorset_.end()) { + while (ix != this->sensorset_.end()) { SensorItem *curr = *ix; ESP_LOGV(TAG, "Register: 0x%X %d %d %d offset=%u skip=%u addr=%p", curr->start_address, curr->register_count, @@ -278,12 +278,12 @@ size_t ModbusController::create_register_ranges_() { // this register can re-use the data from the previous register // remove this sensore because start_address is changed (sort-order) - ix = sensorset_.erase(ix); + ix = this->sensorset_.erase(ix); curr->start_address = r.start_address; curr->offset += prev->offset; - sensorset_.insert(curr); + this->sensorset_.insert(curr); // move iterator backwards because it will be incremented later ix--; @@ -293,14 +293,14 @@ size_t ModbusController::create_register_ranges_() { // this register can extend the current range // remove this sensore because start_address is changed (sort-order) - ix = sensorset_.erase(ix); + ix = this->sensorset_.erase(ix); curr->start_address = r.start_address; curr->offset += buffer_offset; buffer_offset += curr->get_register_size(); r.register_count += curr->register_count; - sensorset_.insert(curr); + this->sensorset_.insert(curr); // move iterator backwards because it will be incremented later ix--; @@ -327,7 +327,7 @@ size_t ModbusController::create_register_ranges_() { ix++; } else { ESP_LOGV(TAG, "Add range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates); - register_ranges_.push_back(r); + this->register_ranges_.push_back(r); r = {}; buffer_offset = 0; // do not increment the iterator here because the current sensor has to be re-evaluated @@ -339,10 +339,10 @@ size_t ModbusController::create_register_ranges_() { if (r.register_count > 0) { // Add the last range ESP_LOGV(TAG, "Add last range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates); - register_ranges_.push_back(r); + this->register_ranges_.push_back(r); } - return register_ranges_.size(); + return this->register_ranges_.size(); } void ModbusController::dump_config() { @@ -352,18 +352,18 @@ void ModbusController::dump_config() { ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_); #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE ESP_LOGCONFIG(TAG, "sensormap"); - for (auto &it : sensorset_) { + for (auto &it : this->sensorset_) { ESP_LOGCONFIG(TAG, " Sensor type=%zu start=0x%X offset=0x%X count=%d size=%d", static_cast(it->register_type), it->start_address, it->offset, it->register_count, it->get_register_size()); } ESP_LOGCONFIG(TAG, "ranges"); - for (auto &it : register_ranges_) { + for (auto &it : this->register_ranges_) { ESP_LOGCONFIG(TAG, " Range type=%zu start=0x%X count=%d skip_updates=%d", static_cast(it.register_type), it.start_address, it.register_count, it.skip_updates); } ESP_LOGCONFIG(TAG, "server registers"); - for (auto &r : server_registers_) { + for (auto &r : this->server_registers_) { ESP_LOGCONFIG(TAG, " Address=0x%02X value_type=%zu register_count=%u", r->address, static_cast(r->value_type), r->register_count); } @@ -372,11 +372,11 @@ void ModbusController::dump_config() { void ModbusController::loop() { // Incoming data to process? - if (!incoming_queue_.empty()) { - auto &message = incoming_queue_.front(); + if (!this->incoming_queue_.empty()) { + auto &message = this->incoming_queue_.front(); if (message != nullptr) process_modbus_data_(message.get()); - incoming_queue_.pop(); + this->incoming_queue_.pop(); } else { // all messages processed send pending commands @@ -391,7 +391,7 @@ void ModbusController::on_write_register_response(ModbusRegisterType register_ty void ModbusController::dump_sensors_() { ESP_LOGV(TAG, "sensors"); - for (auto &it : sensorset_) { + for (auto &it : this->sensorset_) { ESP_LOGV(TAG, " Sensor start=0x%X count=%d size=%d offset=%d", it->start_address, it->register_count, it->get_register_size(), it->offset); } diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index 2a0b936bf5..dfd52e44bc 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -240,14 +240,14 @@ class SensorItem { } // Override register size for modbus devices not using 1 register for one dword void set_register_size(uint8_t register_size) { response_bytes = register_size; } - ModbusRegisterType register_type; - SensorValueType sensor_value_type; - uint16_t start_address; - uint32_t bitmask; - uint8_t offset; - uint8_t register_count; + ModbusRegisterType register_type{ModbusRegisterType::CUSTOM}; + SensorValueType sensor_value_type{SensorValueType::RAW}; + uint16_t start_address{0}; + uint32_t bitmask{0}; + uint8_t offset{0}; + uint8_t register_count{0}; uint8_t response_bytes{0}; - uint16_t skip_updates; + uint16_t skip_updates{0}; std::vector custom_data{}; bool force_new_range{false}; }; @@ -261,9 +261,9 @@ class ServerRegister { this->register_count = register_count; this->read_lambda = std::move(read_lambda); } - uint16_t address; - SensorValueType value_type; - uint8_t register_count; + uint16_t address{0}; + SensorValueType value_type{SensorValueType::RAW}; + uint8_t register_count{0}; std::function read_lambda; }; @@ -312,11 +312,11 @@ struct RegisterRange { class ModbusCommandItem { public: static const size_t MAX_PAYLOAD_BYTES = 240; - ModbusController *modbusdevice; - uint16_t register_address; - uint16_t register_count; - ModbusFunctionCode function_code; - ModbusRegisterType register_type; + ModbusController *modbusdevice{nullptr}; + uint16_t register_address{0}; + uint16_t register_count{0}; + ModbusFunctionCode function_code{ModbusFunctionCode::CUSTOM}; + ModbusRegisterType register_type{ModbusRegisterType::CUSTOM}; std::function &data)> on_data_func; std::vector payload = {}; @@ -493,23 +493,23 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { /// Collection of all sensors for this component SensorSet sensorset_; /// Collection of all server registers for this component - std::vector server_registers_; + std::vector server_registers_{}; /// Continuous range of modbus registers - std::vector register_ranges_; + std::vector register_ranges_{}; /// Hold the pending requests to be sent std::list> command_queue_; /// modbus response data waiting to get processed std::queue> incoming_queue_; /// if duplicate commands can be sent - bool allow_duplicate_commands_; + bool allow_duplicate_commands_{false}; /// when was the last send operation - uint32_t last_command_timestamp_; + uint32_t last_command_timestamp_{0}; /// min time in ms between sending modbus commands - uint16_t command_throttle_; + uint16_t command_throttle_{0}; /// if module didn't respond the last command - bool module_offline_; + bool module_offline_{false}; /// how many updates to skip if module is offline - uint16_t offline_skip_updates_; + uint16_t offline_skip_updates_{0}; /// How many times we will retry a command if we get no response uint8_t max_cmd_retries_{4}; /// Command sent callback diff --git a/esphome/components/modbus_controller/number/modbus_number.cpp b/esphome/components/modbus_controller/number/modbus_number.cpp index 001cfb5787..ea8467d5a3 100644 --- a/esphome/components/modbus_controller/number/modbus_number.cpp +++ b/esphome/components/modbus_controller/number/modbus_number.cpp @@ -8,7 +8,7 @@ namespace modbus_controller { static const char *const TAG = "modbus.number"; void ModbusNumber::parse_and_publish(const std::vector &data) { - float result = payload_to_float(data, *this) / multiply_by_; + float result = payload_to_float(data, *this) / this->multiply_by_; // Is there a lambda registered // call it with the pre converted value and the raw data array @@ -43,7 +43,7 @@ void ModbusNumber::control(float value) { return; } } else { - write_value = multiply_by_ * write_value; + write_value = this->multiply_by_ * write_value; } if (!data.empty()) { @@ -63,21 +63,21 @@ void ModbusNumber::control(float value) { // Create and send the write command if (this->register_count == 1 && !this->use_write_multiple_) { // since offset is in bytes and a register is 16 bits we get the start by adding offset/2 - write_cmd = - ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2, data[0]); + write_cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2, + data[0]); } else { - write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2, - this->register_count, data); + write_cmd = ModbusCommandItem::create_write_multiple_command( + this->parent_, this->start_address + this->offset / 2, this->register_count, data); } // publish new value write_cmd.on_data_func = [this, write_cmd, value](ModbusRegisterType register_type, uint16_t start_address, const std::vector &data) { // gets called when the write command is ack'd from the device - parent_->on_write_register_response(write_cmd.register_type, start_address, data); + this->parent_->on_write_register_response(write_cmd.register_type, start_address, data); this->publish_state(value); }; } - parent_->queue_command(write_cmd); + this->parent_->queue_command(write_cmd); this->publish_state(value); } void ModbusNumber::dump_config() { LOG_NUMBER(TAG, "Modbus Number", this); } diff --git a/esphome/components/modbus_controller/number/modbus_number.h b/esphome/components/modbus_controller/number/modbus_number.h index 544d161cbc..8f77b2e014 100644 --- a/esphome/components/modbus_controller/number/modbus_number.h +++ b/esphome/components/modbus_controller/number/modbus_number.h @@ -29,7 +29,7 @@ class ModbusNumber : public number::Number, public Component, public SensorItem void parse_and_publish(const std::vector &data) override; float get_setup_priority() const override { return setup_priority::HARDWARE; } void set_parent(ModbusController *parent) { this->parent_ = parent; } - void set_write_multiply(float factor) { multiply_by_ = factor; } + void set_write_multiply(float factor) { this->multiply_by_ = factor; } using transform_func_t = std::function(ModbusNumber *, float, const std::vector &)>; using write_transform_func_t = std::function(ModbusNumber *, float, std::vector &)>; @@ -39,9 +39,9 @@ class ModbusNumber : public number::Number, public Component, public SensorItem protected: void control(float value) override; - optional transform_func_; - optional write_transform_func_; - ModbusController *parent_; + optional transform_func_{nullopt}; + optional write_transform_func_{nullopt}; + ModbusController *parent_{nullptr}; float multiply_by_{1.0}; bool use_write_multiple_{false}; }; diff --git a/esphome/components/modbus_controller/output/modbus_output.cpp b/esphome/components/modbus_controller/output/modbus_output.cpp index 79cd2d49c2..f0f6e64f10 100644 --- a/esphome/components/modbus_controller/output/modbus_output.cpp +++ b/esphome/components/modbus_controller/output/modbus_output.cpp @@ -27,7 +27,7 @@ void ModbusFloatOutput::write_state(float value) { return; } } else { - value = multiply_by_ * value; + value = this->multiply_by_ * value; } // lambda didn't set payload if (data.empty()) { @@ -40,12 +40,13 @@ void ModbusFloatOutput::write_state(float value) { // Create and send the write command ModbusCommandItem write_cmd; if (this->register_count == 1 && !this->use_write_multiple_) { - write_cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset, data[0]); + write_cmd = + ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset, data[0]); } else { - write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset, + write_cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset, this->register_count, data); } - parent_->queue_command(write_cmd); + this->parent_->queue_command(write_cmd); } void ModbusFloatOutput::dump_config() { @@ -90,9 +91,9 @@ void ModbusBinaryOutput::write_state(bool state) { // offset for coil and discrete inputs is the coil/register number not bytes if (this->use_write_multiple_) { std::vector states{state}; - cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states); + cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states); } else { - cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state); + cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state); } } this->parent_->queue_command(cmd); diff --git a/esphome/components/modbus_controller/output/modbus_output.h b/esphome/components/modbus_controller/output/modbus_output.h index f424671cd1..bceb97affb 100644 --- a/esphome/components/modbus_controller/output/modbus_output.h +++ b/esphome/components/modbus_controller/output/modbus_output.h @@ -25,7 +25,7 @@ class ModbusFloatOutput : public output::FloatOutput, public Component, public S void dump_config() override; void set_parent(ModbusController *parent) { this->parent_ = parent; } - void set_write_multiply(float factor) { multiply_by_ = factor; } + void set_write_multiply(float factor) { this->multiply_by_ = factor; } // Do nothing void parse_and_publish(const std::vector &data) override{}; @@ -37,9 +37,9 @@ class ModbusFloatOutput : public output::FloatOutput, public Component, public S void write_state(float value) override; optional write_transform_func_{nullopt}; - ModbusController *parent_; + ModbusController *parent_{nullptr}; float multiply_by_{1.0}; - bool use_write_multiple_; + bool use_write_multiple_{false}; }; class ModbusBinaryOutput : public output::BinaryOutput, public Component, public SensorItem { @@ -68,8 +68,8 @@ class ModbusBinaryOutput : public output::BinaryOutput, public Component, public void write_state(bool state) override; optional write_transform_func_{nullopt}; - ModbusController *parent_; - bool use_write_multiple_; + ModbusController *parent_{nullptr}; + bool use_write_multiple_{false}; }; } // namespace modbus_controller diff --git a/esphome/components/modbus_controller/select/modbus_select.cpp b/esphome/components/modbus_controller/select/modbus_select.cpp index 33cef39a18..56b8c783ed 100644 --- a/esphome/components/modbus_controller/select/modbus_select.cpp +++ b/esphome/components/modbus_controller/select/modbus_select.cpp @@ -74,12 +74,13 @@ void ModbusSelect::control(const std::string &value) { const uint16_t write_address = this->start_address + this->offset / 2; ModbusCommandItem write_cmd; if ((this->register_count == 1) && (!this->use_write_multiple_)) { - write_cmd = ModbusCommandItem::create_write_single_command(parent_, write_address, data[0]); + write_cmd = ModbusCommandItem::create_write_single_command(this->parent_, write_address, data[0]); } else { - write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, write_address, this->register_count, data); + write_cmd = + ModbusCommandItem::create_write_multiple_command(this->parent_, write_address, this->register_count, data); } - parent_->queue_command(write_cmd); + this->parent_->queue_command(write_cmd); if (this->optimistic_) this->publish_state(value); diff --git a/esphome/components/modbus_controller/select/modbus_select.h b/esphome/components/modbus_controller/select/modbus_select.h index 1c046b11d0..55fb2107dd 100644 --- a/esphome/components/modbus_controller/select/modbus_select.h +++ b/esphome/components/modbus_controller/select/modbus_select.h @@ -42,12 +42,12 @@ class ModbusSelect : public Component, public select::Select, public SensorItem void control(const std::string &value) override; protected: - std::vector mapping_; - ModbusController *parent_; + std::vector mapping_{}; + ModbusController *parent_{nullptr}; bool use_write_multiple_{false}; bool optimistic_{false}; - optional transform_func_; - optional write_transform_func_; + optional transform_func_{nullopt}; + optional write_transform_func_{nullopt}; }; } // namespace modbus_controller diff --git a/esphome/components/modbus_controller/switch/modbus_switch.cpp b/esphome/components/modbus_controller/switch/modbus_switch.cpp index 3a679fbeb8..ec29eca7f8 100644 --- a/esphome/components/modbus_controller/switch/modbus_switch.cpp +++ b/esphome/components/modbus_controller/switch/modbus_switch.cpp @@ -80,18 +80,18 @@ void ModbusSwitch::write_state(bool state) { // offset for coil and discrete inputs is the coil/register number not bytes if (this->use_write_multiple_) { std::vector states{state}; - cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states); + cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states); } else { - cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state); + cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state); } } else { // since offset is in bytes and a register is 16 bits we get the start by adding offset/2 if (this->use_write_multiple_) { std::vector bool_states(1, state ? (0xFFFF & this->bitmask) : 0); - cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2, 1, + cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset / 2, 1, bool_states); } else { - cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2, + cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2, state ? 0xFFFF & this->bitmask : 0u); } } diff --git a/esphome/components/modbus_controller/switch/modbus_switch.h b/esphome/components/modbus_controller/switch/modbus_switch.h index bfe46f3ac8..fe4b7c1ad5 100644 --- a/esphome/components/modbus_controller/switch/modbus_switch.h +++ b/esphome/components/modbus_controller/switch/modbus_switch.h @@ -40,8 +40,8 @@ class ModbusSwitch : public Component, public switch_::Switch, public SensorItem void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; } protected: - ModbusController *parent_; - bool use_write_multiple_; + ModbusController *parent_{nullptr}; + bool use_write_multiple_{false}; optional publish_transform_func_{nullopt}; optional write_transform_func_{nullopt}; }; From fb96e3588d1f771f7430beec570da2d09a83e2f2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 2 Dec 2024 08:16:58 +0000 Subject: [PATCH 102/139] Add H-Bridge switch component (#7421) Co-authored-by: Keith Burzinski --- CODEOWNERS | 1 + esphome/components/hbridge/switch/__init__.py | 44 +++++++++ .../hbridge/switch/hbridge_switch.cpp | 95 +++++++++++++++++++ .../hbridge/switch/hbridge_switch.h | 50 ++++++++++ tests/components/hbridge/common.yaml | 39 ++++++++ tests/components/hbridge/test.esp32-ard.yaml | 46 +++------ .../components/hbridge/test.esp32-c3-ard.yaml | 45 +++------ .../components/hbridge/test.esp32-c3-idf.yaml | 44 +++------ tests/components/hbridge/test.esp32-idf.yaml | 45 +++------ .../components/hbridge/test.esp8266-ard.yaml | 45 +++------ tests/components/hbridge/test.rp2040-ard.yaml | 45 +++------ 11 files changed, 313 insertions(+), 186 deletions(-) create mode 100644 esphome/components/hbridge/switch/__init__.py create mode 100644 esphome/components/hbridge/switch/hbridge_switch.cpp create mode 100644 esphome/components/hbridge/switch/hbridge_switch.h create mode 100644 tests/components/hbridge/common.yaml diff --git a/CODEOWNERS b/CODEOWNERS index fb6d11d1fb..74c205b302 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -179,6 +179,7 @@ esphome/components/haier/text_sensor/* @paveldn esphome/components/havells_solar/* @sourabhjaiswal esphome/components/hbridge/fan/* @WeekendWarrior esphome/components/hbridge/light/* @DotNetDann +esphome/components/hbridge/switch/* @dwmw2 esphome/components/he60r/* @clydebarrow esphome/components/heatpumpir/* @rob-deutsch esphome/components/hitachi_ac424/* @sourabhjaiswal diff --git a/esphome/components/hbridge/switch/__init__.py b/esphome/components/hbridge/switch/__init__.py new file mode 100644 index 0000000000..e26bd6b1d8 --- /dev/null +++ b/esphome/components/hbridge/switch/__init__.py @@ -0,0 +1,44 @@ +from esphome import pins +import esphome.codegen as cg +from esphome.components import switch +import esphome.config_validation as cv +from esphome.const import CONF_OPTIMISTIC, CONF_PULSE_LENGTH, CONF_WAIT_TIME + +from .. import hbridge_ns + +HBridgeSwitch = hbridge_ns.class_("HBridgeSwitch", switch.Switch, cg.Component) + +CODEOWNERS = ["@dwmw2"] + +CONF_OFF_PIN = "off_pin" +CONF_ON_PIN = "on_pin" + +CONFIG_SCHEMA = ( + switch.switch_schema(HBridgeSwitch) + .extend( + { + cv.Required(CONF_ON_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_OFF_PIN): pins.gpio_output_pin_schema, + cv.Optional( + CONF_PULSE_LENGTH, default="100ms" + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_WAIT_TIME): cv.positive_time_period_milliseconds, + cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean, + } + ) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = await switch.new_switch(config) + await cg.register_component(var, config) + + on_pin = await cg.gpio_pin_expression(config[CONF_ON_PIN]) + cg.add(var.set_on_pin(on_pin)) + off_pin = await cg.gpio_pin_expression(config[CONF_OFF_PIN]) + cg.add(var.set_off_pin(off_pin)) + cg.add(var.set_pulse_length(config[CONF_PULSE_LENGTH])) + cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) + if wait_time := config.get(CONF_WAIT_TIME): + cg.add(var.set_wait_time(wait_time)) diff --git a/esphome/components/hbridge/switch/hbridge_switch.cpp b/esphome/components/hbridge/switch/hbridge_switch.cpp new file mode 100644 index 0000000000..12d1c01bca --- /dev/null +++ b/esphome/components/hbridge/switch/hbridge_switch.cpp @@ -0,0 +1,95 @@ +#include "hbridge_switch.h" +#include "esphome/core/log.h" + +#include + +namespace esphome { +namespace hbridge { + +static const char *const TAG = "switch.hbridge"; + +float HBridgeSwitch::get_setup_priority() const { return setup_priority::HARDWARE; } +void HBridgeSwitch::setup() { + ESP_LOGCONFIG(TAG, "Setting up H-Bridge Switch '%s'...", this->name_.c_str()); + + optional initial_state = this->get_initial_state_with_restore_mode().value_or(false); + + // Like GPIOSwitch does, set the pin state both before and after pin setup() + this->on_pin_->digital_write(false); + this->on_pin_->setup(); + this->on_pin_->digital_write(false); + + this->off_pin_->digital_write(false); + this->off_pin_->setup(); + this->off_pin_->digital_write(false); + + if (initial_state.has_value()) + this->write_state(initial_state); +} + +void HBridgeSwitch::dump_config() { + LOG_SWITCH("", "H-Bridge Switch", this); + LOG_PIN(" On Pin: ", this->on_pin_); + LOG_PIN(" Off Pin: ", this->off_pin_); + ESP_LOGCONFIG(TAG, " Pulse length: %" PRId32 " ms", this->pulse_length_); + if (this->wait_time_) + ESP_LOGCONFIG(TAG, " Wait time %" PRId32 " ms", this->wait_time_); +} + +void HBridgeSwitch::write_state(bool state) { + this->desired_state_ = state; + if (!this->timer_running_) + this->timer_fn_(); +} + +void HBridgeSwitch::timer_fn_() { + uint32_t next_timeout = 0; + + while ((uint8_t) this->desired_state_ != this->relay_state_) { + switch (this->relay_state_) { + case RELAY_STATE_ON: + case RELAY_STATE_OFF: + case RELAY_STATE_UNKNOWN: + if (this->desired_state_) { + this->on_pin_->digital_write(true); + this->relay_state_ = RELAY_STATE_SWITCHING_ON; + } else { + this->off_pin_->digital_write(true); + this->relay_state_ = RELAY_STATE_SWITCHING_OFF; + } + next_timeout = this->pulse_length_; + if (!this->optimistic_) + this->publish_state(this->desired_state_); + break; + + case RELAY_STATE_SWITCHING_ON: + this->on_pin_->digital_write(false); + this->relay_state_ = RELAY_STATE_ON; + if (this->optimistic_) + this->publish_state(true); + next_timeout = this->wait_time_; + break; + + case RELAY_STATE_SWITCHING_OFF: + this->off_pin_->digital_write(false); + this->relay_state_ = RELAY_STATE_OFF; + if (this->optimistic_) + this->publish_state(false); + next_timeout = this->wait_time_; + break; + } + + if (next_timeout) { + this->timer_running_ = true; + this->set_timeout(next_timeout, [this]() { this->timer_fn_(); }); + return; + } + + // In the case where ON/OFF state has been reached but we need to + // immediately change back again to reach desired_state_, we loop. + } + this->timer_running_ = false; +} + +} // namespace hbridge +} // namespace esphome diff --git a/esphome/components/hbridge/switch/hbridge_switch.h b/esphome/components/hbridge/switch/hbridge_switch.h new file mode 100644 index 0000000000..ce00c6baa2 --- /dev/null +++ b/esphome/components/hbridge/switch/hbridge_switch.h @@ -0,0 +1,50 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/components/switch/switch.h" + +#include + +namespace esphome { +namespace hbridge { + +enum RelayState : uint8_t { + RELAY_STATE_OFF = 0, + RELAY_STATE_ON = 1, + RELAY_STATE_SWITCHING_ON = 2, + RELAY_STATE_SWITCHING_OFF = 3, + RELAY_STATE_UNKNOWN = 4, +}; + +class HBridgeSwitch : public switch_::Switch, public Component { + public: + void set_on_pin(GPIOPin *pin) { this->on_pin_ = pin; } + void set_off_pin(GPIOPin *pin) { this->off_pin_ = pin; } + void set_pulse_length(uint32_t pulse_length) { this->pulse_length_ = pulse_length; } + void set_wait_time(uint32_t wait_time) { this->wait_time_ = wait_time; } + void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } + + // ========== INTERNAL METHODS ========== + // (In most use cases you won't need these) + float get_setup_priority() const override; + + void setup() override; + void dump_config() override; + + protected: + void write_state(bool state) override; + void timer_fn_(); + + bool timer_running_{false}; + bool desired_state_{false}; + RelayState relay_state_{RELAY_STATE_UNKNOWN}; + GPIOPin *on_pin_{nullptr}; + GPIOPin *off_pin_{nullptr}; + uint32_t pulse_length_{0}; + uint32_t wait_time_{0}; + bool optimistic_{false}; +}; + +} // namespace hbridge +} // namespace esphome diff --git a/tests/components/hbridge/common.yaml b/tests/components/hbridge/common.yaml new file mode 100644 index 0000000000..0504cdea03 --- /dev/null +++ b/tests/components/hbridge/common.yaml @@ -0,0 +1,39 @@ +output: + - platform: ${pwm_platform} + pin: ${output1_pin} + id: gpio_output1 + - platform: ${pwm_platform} + pin: ${output2_pin} + id: gpio_output2 + - platform: ${pwm_platform} + pin: ${output3_pin} + id: gpio_output3 + - platform: ${pwm_platform} + pin: ${output4_pin} + id: gpio_output4 + +light: + - platform: hbridge + name: Icicle Lights + pin_a: gpio_output3 + pin_b: gpio_output4 + +fan: + - platform: hbridge + id: fan_hbridge + speed_count: 4 + name: H-bridge Fan with Presets + pin_a: gpio_output1 + pin_b: gpio_output2 + preset_modes: + - Preset 1 + - Preset 2 + on_preset_set: + then: + - logger.log: Preset mode was changed! + +switch: + - platform: hbridge + id: switch_hbridge + on_pin: ${hbridge_on_pin} + off_pin: ${hbridge_off_pin} diff --git a/tests/components/hbridge/test.esp32-ard.yaml b/tests/components/hbridge/test.esp32-ard.yaml index 6a80aaaf3b..e50d537749 100644 --- a/tests/components/hbridge/test.esp32-ard.yaml +++ b/tests/components/hbridge/test.esp32-ard.yaml @@ -1,33 +1,17 @@ -output: - - platform: ledc - pin: 14 - id: gpio_output1 - - platform: ledc - pin: 15 - id: gpio_output2 - - platform: ledc - pin: 12 - id: gpio_output3 - - platform: ledc - pin: 13 - id: gpio_output4 +substitutions: + pwm_platform: ledc + output1_pin: "14" + output2_pin: "15" + output3_pin: "12" + output4_pin: "13" + hbridge_on_pin: "4" + hbridge_off_pin: "5" -light: - - platform: hbridge - name: Icicle Lights - pin_a: gpio_output3 - pin_b: gpio_output4 +packages: + common: !include common.yaml -fan: - - platform: hbridge - id: fan_hbridge - speed_count: 4 - name: H-bridge Fan with Presets - pin_a: gpio_output1 - pin_b: gpio_output2 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! +switch: + - id: !extend switch_hbridge + pulse_length: 60ms + wait_time: 10ms + optimistic: false diff --git a/tests/components/hbridge/test.esp32-c3-ard.yaml b/tests/components/hbridge/test.esp32-c3-ard.yaml index 70cfd6ab6f..b9e8738442 100644 --- a/tests/components/hbridge/test.esp32-c3-ard.yaml +++ b/tests/components/hbridge/test.esp32-c3-ard.yaml @@ -1,33 +1,16 @@ -output: - - platform: ledc - pin: 4 - id: gpio_output1 - - platform: ledc - pin: 5 - id: gpio_output2 - - platform: ledc - pin: 6 - id: gpio_output3 - - platform: ledc - pin: 7 - id: gpio_output4 +substitutions: + pwm_platform: "ledc" + output1_pin: "4" + output2_pin: "5" + output3_pin: "6" + output4_pin: "7" + hbridge_on_pin: "2" + hbridge_off_pin: "3" -light: - - platform: hbridge - name: Icicle Lights - pin_a: gpio_output3 - pin_b: gpio_output4 +packages: + common: !include common.yaml -fan: - - platform: hbridge - id: fan_hbridge - speed_count: 4 - name: H-bridge Fan with Presets - pin_a: gpio_output1 - pin_b: gpio_output2 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! +switch: + - id: !extend switch_hbridge + wait_time: 10ms + optimistic: true diff --git a/tests/components/hbridge/test.esp32-c3-idf.yaml b/tests/components/hbridge/test.esp32-c3-idf.yaml index 70cfd6ab6f..c73f08b6de 100644 --- a/tests/components/hbridge/test.esp32-c3-idf.yaml +++ b/tests/components/hbridge/test.esp32-c3-idf.yaml @@ -1,33 +1,15 @@ -output: - - platform: ledc - pin: 4 - id: gpio_output1 - - platform: ledc - pin: 5 - id: gpio_output2 - - platform: ledc - pin: 6 - id: gpio_output3 - - platform: ledc - pin: 7 - id: gpio_output4 +substitutions: + pwm_platform: "ledc" + output1_pin: "4" + output2_pin: "5" + output3_pin: "6" + output4_pin: "7" + hbridge_on_pin: "2" + hbridge_off_pin: "3" -light: - - platform: hbridge - name: Icicle Lights - pin_a: gpio_output3 - pin_b: gpio_output4 +packages: + common: !include common.yaml -fan: - - platform: hbridge - id: fan_hbridge - speed_count: 4 - name: H-bridge Fan with Presets - pin_a: gpio_output1 - pin_b: gpio_output2 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! +switch: + - id: !extend switch_hbridge + pulse_length: 60ms diff --git a/tests/components/hbridge/test.esp32-idf.yaml b/tests/components/hbridge/test.esp32-idf.yaml index 6a80aaaf3b..dbbfa738c7 100644 --- a/tests/components/hbridge/test.esp32-idf.yaml +++ b/tests/components/hbridge/test.esp32-idf.yaml @@ -1,33 +1,16 @@ -output: - - platform: ledc - pin: 14 - id: gpio_output1 - - platform: ledc - pin: 15 - id: gpio_output2 - - platform: ledc - pin: 12 - id: gpio_output3 - - platform: ledc - pin: 13 - id: gpio_output4 +substitutions: + pwm_platform: "ledc" + output1_pin: "14" + output2_pin: "15" + output3_pin: "12" + output4_pin: "13" + hbridge_on_pin: "4" + hbridge_off_pin: "5" -light: - - platform: hbridge - name: Icicle Lights - pin_a: gpio_output3 - pin_b: gpio_output4 +packages: + common: !include common.yaml -fan: - - platform: hbridge - id: fan_hbridge - speed_count: 4 - name: H-bridge Fan with Presets - pin_a: gpio_output1 - pin_b: gpio_output2 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! +switch: + - id: !extend switch_hbridge + pulse_length: 60ms + wait_time: 10ms diff --git a/tests/components/hbridge/test.esp8266-ard.yaml b/tests/components/hbridge/test.esp8266-ard.yaml index 4f8915879d..f560da5d38 100644 --- a/tests/components/hbridge/test.esp8266-ard.yaml +++ b/tests/components/hbridge/test.esp8266-ard.yaml @@ -1,33 +1,16 @@ -output: - - platform: esp8266_pwm - pin: 4 - id: gpio_output1 - - platform: esp8266_pwm - pin: 5 - id: gpio_output2 - - platform: esp8266_pwm - pin: 12 - id: gpio_output3 - - platform: esp8266_pwm - pin: 13 - id: gpio_output4 +substitutions: + pwm_platform: "esp8266_pwm" + output1_pin: "4" + output2_pin: "5" + output3_pin: "12" + output4_pin: "13" + hbridge_on_pin: "14" + hbridge_off_pin: "15" -light: - - platform: hbridge - name: Icicle Lights - pin_a: gpio_output3 - pin_b: gpio_output4 +packages: + common: !include common.yaml -fan: - - platform: hbridge - id: fan_hbridge - speed_count: 4 - name: H-bridge Fan with Presets - pin_a: gpio_output1 - pin_b: gpio_output2 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! +switch: + - id: !extend switch_hbridge + pulse_length: 60ms + wait_time: 10ms diff --git a/tests/components/hbridge/test.rp2040-ard.yaml b/tests/components/hbridge/test.rp2040-ard.yaml index e21b55091d..aa6e290cab 100644 --- a/tests/components/hbridge/test.rp2040-ard.yaml +++ b/tests/components/hbridge/test.rp2040-ard.yaml @@ -1,33 +1,16 @@ -output: - - platform: rp2040_pwm - pin: 4 - id: gpio_output1 - - platform: rp2040_pwm - pin: 5 - id: gpio_output2 - - platform: rp2040_pwm - pin: 6 - id: gpio_output3 - - platform: rp2040_pwm - pin: 7 - id: gpio_output4 +substitutions: + pwm_platform: "rp2040_pwm" + output1_pin: "4" + output2_pin: "5" + output3_pin: "6" + output4_pin: "7" + hbridge_on_pin: "2" + hbridge_off_pin: "3" -light: - - platform: hbridge - name: Icicle Lights - pin_a: gpio_output3 - pin_b: gpio_output4 +packages: + common: !include common.yaml -fan: - - platform: hbridge - id: fan_hbridge - speed_count: 4 - name: H-bridge Fan with Presets - pin_a: gpio_output1 - pin_b: gpio_output2 - preset_modes: - - Preset 1 - - Preset 2 - on_preset_set: - then: - - logger.log: Preset mode was changed! +switch: + - id: !extend switch_hbridge + wait_time: 10ms + optimistic: true From b79a3d672782fee909f929da8cb0a516ee52132d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 2 Dec 2024 11:42:44 -0600 Subject: [PATCH 103/139] [CI] Bump GHA runners to ``ubuntu-24.04`` (#7905) --- .github/workflows/ci.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5af3ec9e9..82e823adde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ concurrency: jobs: common: name: Create common environment - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: cache-key: ${{ steps.cache-key.outputs.key }} steps: @@ -62,7 +62,7 @@ jobs: black: name: Check black - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common steps: @@ -83,7 +83,7 @@ jobs: flake8: name: Check flake8 - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common steps: @@ -104,7 +104,7 @@ jobs: pylint: name: Check pylint - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common steps: @@ -125,7 +125,7 @@ jobs: pyupgrade: name: Check pyupgrade - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common steps: @@ -146,7 +146,7 @@ jobs: ci-custom: name: Run script/ci-custom - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common steps: @@ -225,7 +225,7 @@ jobs: clang-format: name: Check clang-format - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common steps: @@ -251,7 +251,7 @@ jobs: clang-tidy: name: ${{ matrix.name }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common - black @@ -345,7 +345,7 @@ jobs: if: always() list-components: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common if: github.event_name == 'pull_request' @@ -387,7 +387,7 @@ jobs: test-build-components: name: Component test ${{ matrix.file }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common - list-components @@ -421,7 +421,7 @@ jobs: test-build-components-splitter: name: Split components for testing into 20 groups maximum - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common - list-components @@ -439,7 +439,7 @@ jobs: test-build-components-split: name: Test split components - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common - list-components @@ -483,7 +483,7 @@ jobs: ci-status: name: CI Status - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - common - black From e08a9cc3a33ab431f6eeef869bdc49c46f17dcf1 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:27:51 +1100 Subject: [PATCH 104/139] [font et. al.] Remove explicit check for pillow installed. (#7891) --- esphome/components/animation/__init__.py | 3 +-- esphome/components/font/__init__.py | 24 ++---------------------- esphome/components/ili9xxx/display.py | 3 +-- esphome/components/image/__init__.py | 3 +-- 4 files changed, 5 insertions(+), 28 deletions(-) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index 5a308855de..21a82649f0 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -2,7 +2,6 @@ import logging from esphome import automation, core import esphome.codegen as cg -from esphome.components import font import esphome.components.image as espImage from esphome.components.image import ( CONF_USE_TRANSPARENCY, @@ -131,7 +130,7 @@ ANIMATION_SCHEMA = cv.Schema( ) ) -CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA) +CONFIG_SCHEMA = ANIMATION_SCHEMA NEXT_FRAME_SCHEMA = automation.maybe_simple_id( { diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 6fd2d7c310..1b4fe4bff0 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -1,4 +1,3 @@ -from collections.abc import Iterable import functools import hashlib import logging @@ -8,7 +7,6 @@ import re import freetype import glyphsets -from packaging import version import requests from esphome import core, external_files @@ -88,7 +86,7 @@ def flatten(lists) -> list: return list(chain.from_iterable(lists)) -def check_missing_glyphs(file, codepoints: Iterable, warning: bool = False): +def check_missing_glyphs(file, codepoints, warning: bool = False): """ Check that the given font file actually contains the requested glyphs :param file: A Truetype font file @@ -177,24 +175,6 @@ def validate_glyphs(config): return config -def validate_pillow_installed(value): - try: - import PIL - except ImportError as err: - raise cv.Invalid( - "Please install the pillow python package to use this feature. " - '(pip install "pillow==10.4.0")' - ) from err - - if version.parse(PIL.__version__) != version.parse("10.4.0"): - raise cv.Invalid( - "Please update your pillow installation to 10.4.0. " - '(pip install "pillow==10.4.0")' - ) - - return value - - FONT_EXTENSIONS = (".ttf", ".woff", ".otf") @@ -421,7 +401,7 @@ FONT_SCHEMA = cv.Schema( }, ) -CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA, validate_glyphs) +CONFIG_SCHEMA = cv.All(FONT_SCHEMA, validate_glyphs) # PIL doesn't provide a consistent interface for both TrueType and bitmap diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 739ad07843..3c9dd2dab9 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -1,6 +1,6 @@ from esphome import core, pins import esphome.codegen as cg -from esphome.components import display, font, spi +from esphome.components import display, spi from esphome.components.display import validate_rotation import esphome.config_validation as cv from esphome.const import ( @@ -147,7 +147,6 @@ def _validate(config): CONFIG_SCHEMA = cv.All( - font.validate_pillow_installed, display.FULL_DISPLAY_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(ILI9XXXDisplay), diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index 8742540067..4669a3418a 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -10,7 +10,6 @@ import puremagic from esphome import core, external_files import esphome.codegen as cg -from esphome.components import font import esphome.config_validation as cv from esphome.const import ( CONF_DITHER, @@ -233,7 +232,7 @@ IMAGE_SCHEMA = cv.Schema( ) ) -CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) +CONFIG_SCHEMA = IMAGE_SCHEMA def load_svg_image(file: bytes, resize: tuple[int, int]): From 9c8976be1328b4c5c1d019aa835f53f129262324 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 2 Dec 2024 16:29:45 -0600 Subject: [PATCH 105/139] [CI] Update clang-tidy to 18.1.3 (#7822) --- .clang-tidy | 29 +++++++++++++++++++++++++++-- .github/workflows/ci.yml | 5 ----- docker/Dockerfile | 8 ++++++-- requirements_dev.txt | 2 +- script/clang-tidy | 8 +++----- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 994416b2f1..8dba033e2d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -7,28 +7,38 @@ Checks: >- -boost-*, -bugprone-easily-swappable-parameters, -bugprone-implicit-widening-of-multiplication-result, + -bugprone-multi-level-implicit-pointer-conversion, -bugprone-narrowing-conversions, -bugprone-signed-char-misuse, + -bugprone-switch-missing-default-case, -cert-dcl50-cpp, -cert-err33-c, -cert-err58-cpp, -cert-oop57-cpp, -cert-str34-c, + -clang-analyzer-optin.core.EnumCastOutOfRange, -clang-analyzer-optin.cplusplus.UninitializedObject, -clang-analyzer-osx.*, -clang-diagnostic-delete-abstract-non-virtual-dtor, -clang-diagnostic-delete-non-abstract-non-virtual-dtor, -clang-diagnostic-ignored-optimization-argument, + -clang-diagnostic-missing-field-initializers, -clang-diagnostic-shadow-field, -clang-diagnostic-unused-const-variable, -clang-diagnostic-unused-parameter, + -clang-diagnostic-vla-cxx-extension, -concurrency-*, -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-const-or-ref-data-members, + -cppcoreguidelines-avoid-do-while, -cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-to-enum, -cppcoreguidelines-macro-usage, + -cppcoreguidelines-missing-std-forward, -cppcoreguidelines-narrowing-conversions, -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, -cppcoreguidelines-prefer-member-initializer, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, @@ -40,7 +50,9 @@ Checks: >- -cppcoreguidelines-pro-type-static-cast-downcast, -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-rvalue-reference-param-not-moved, -cppcoreguidelines-special-member-functions, + -cppcoreguidelines-use-default-member-init, -cppcoreguidelines-virtual-class-destructor, -fuchsia-multiple-inheritance, -fuchsia-overloaded-operator, @@ -60,21 +72,32 @@ Checks: >- -llvm-include-order, -llvm-qualified-auto, -llvmlibc-*, - -misc-non-private-member-variables-in-classes, + -misc-const-correctness, + -misc-include-cleaner, -misc-no-recursion, + -misc-non-private-member-variables-in-classes, -misc-unused-parameters, + -misc-use-anonymous-namespace, -modernize-avoid-bind, -modernize-avoid-c-arrays, -modernize-concat-nested-namespaces, + -modernize-macro-to-enum, -modernize-return-braced-init-list, + -modernize-type-traits, -modernize-use-auto, + -modernize-use-constraints, -modernize-use-default-member-init, -modernize-use-equals-default, -modernize-use-nodiscard, -modernize-use-nullptr, + -modernize-use-nodiscard, + -modernize-use-nullptr, -modernize-use-trailing-return-type, -mpi-*, -objc-*, + -performance-enum-size, + -readability-avoid-nested-conditional-operator, + -readability-container-contains, -readability-container-data-pointer, -readability-convert-member-functions-to-static, -readability-else-after-return, @@ -84,11 +107,13 @@ Checks: >- -readability-magic-numbers, -readability-make-member-function-const, -readability-named-parameter, + -readability-redundant-casting, + -readability-redundant-inline-specifier, + -readability-redundant-member-init, -readability-redundant-string-init, -readability-uppercase-literal-suffix, -readability-use-anyofallof, WarningsAsErrors: '*' -AnalyzeTemporaryDtors: false FormatStyle: google CheckOptions: - key: google-readability-function-size.StatementThreshold diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82e823adde..e4d3934c59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,11 +314,6 @@ jobs: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} - - name: Install clang-tidy - run: | - sudo apt-get update - sudo apt-get install clang-tidy-14 - - name: Register problem matchers run: | echo "::add-matcher::.github/workflows/matchers/gcc.json" diff --git a/docker/Dockerfile b/docker/Dockerfile index c2902a9dd1..c53856d0e8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -209,11 +209,12 @@ ENV \ PLATFORMIO_CORE_DIR=/esphome/.temp/platformio RUN \ - apt-get update \ + curl -L https://apt.llvm.org/llvm-snapshot.gpg.key -o /etc/apt/trusted.gpg.d/apt.llvm.org.asc \ + && echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-18 main" > /etc/apt/sources.list.d/llvm.sources.list \ + && apt-get update \ # Use pinned versions so that we get updates with build caching && apt-get install -y --no-install-recommends \ clang-format-13=1:13.0.1-11+b2 \ - clang-tidy-14=1:14.0.6-12 \ patch=2.7.6-7 \ software-properties-common=0.99.30-4.1~deb12u1 \ nano=7.2-1+deb12u1 \ @@ -227,6 +228,9 @@ RUN \ COPY requirements_test.txt / RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ + else \ + # move this up into RUN above after armv7 is retired + apt-get install -y --no-install-recommends clang-tidy-18=1:18.1.8~++20240731024826+3b5b5c1ec4a3-1~exp1~20240731144843.145 ; \ fi; \ pip3 install \ --break-system-packages --no-cache-dir -r /requirements_test.txt diff --git a/requirements_dev.txt b/requirements_dev.txt index eb749a861d..2ef8330215 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ # Useful stuff when working in a development environment clang-format==13.0.1 # also change in .pre-commit-config.yaml and Dockerfile when updating -clang-tidy==14.0.6 # When updating clang-tidy, also update Dockerfile +clang-tidy==18.1.3 # When updating clang-tidy, also update Dockerfile yamllint==1.35.1 # also change in .pre-commit-config.yaml when updating diff --git a/script/clang-tidy b/script/clang-tidy index 319fab70a2..5c19f81043 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -63,8 +63,6 @@ def clang_options(idedata): "-Ddeprecated(x)=", # allow to condition code on the presence of clang-tidy "-DCLANG_TIDY", - # (esp-idf) Disable this header because they use asm with registers clang-tidy doesn't know - "-D__XTENSA_API_H__", # (esp-idf) Fix __once_callable in some libstdc++ headers "-D_GLIBCXX_HAVE_TLS", ] @@ -238,7 +236,7 @@ def main(): failed_files = [] try: - executable = get_binary("clang-tidy", 14) + executable = get_binary("clang-tidy", 18) task_queue = queue.Queue(args.jobs) lock = threading.Lock() for _ in range(args.jobs): @@ -283,12 +281,12 @@ def main(): print("Applying fixes ...") try: try: - subprocess.call(["clang-apply-replacements-14", tmpdir]) + subprocess.call(["clang-apply-replacements-18", tmpdir]) except FileNotFoundError: subprocess.call(["clang-apply-replacements", tmpdir]) except FileNotFoundError: print( - "Error please install clang-apply-replacements-14 or clang-apply-replacements.\n", + "Error please install clang-apply-replacements-18 or clang-apply-replacements.\n", file=sys.stderr, ) except: From 584dbf2668f888c774be7ad6ce4172d827965e9b Mon Sep 17 00:00:00 2001 From: kbullet Date: Tue, 3 Dec 2024 06:50:05 +0700 Subject: [PATCH 106/139] MQTT sensors handling of publishing NaN values (#7768) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mqtt/__init__.py | 4 ++++ esphome/components/mqtt/mqtt_client.cpp | 4 ++++ esphome/components/mqtt/mqtt_client.h | 6 ++++++ esphome/components/mqtt/mqtt_sensor.cpp | 2 ++ esphome/const.py | 1 + tests/components/mqtt/common.yaml | 1 + 6 files changed, 18 insertions(+) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 86d163e61d..2b0d941220 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -49,6 +49,7 @@ from esphome.const import ( CONF_USE_ABBREVIATIONS, CONF_USERNAME, CONF_WILL_MESSAGE, + CONF_PUBLISH_NAN_AS_NONE, PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, @@ -296,6 +297,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_QOS, default=0): cv.mqtt_qos, } ), + cv.Optional(CONF_PUBLISH_NAN_AS_NONE, default=False): cv.boolean, } ), validate_config, @@ -449,6 +451,8 @@ async def to_code(config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + cg.add(var.set_publish_nan_as_none(config[CONF_PUBLISH_NAN_AS_NONE])) + MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema( { diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 106192c0e3..c7ace505a8 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -608,6 +608,10 @@ void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; } void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix) { this->topic_prefix_ = topic_prefix; } const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; } +void MQTTClientComponent::set_publish_nan_as_none(bool publish_nan_as_none) { + this->publish_nan_as_none_ = publish_nan_as_none; +} +bool MQTTClientComponent::is_publish_nan_as_none() const { return this->publish_nan_as_none_; } void MQTTClientComponent::disable_birth_message() { this->birth_message_.topic = ""; this->recalculate_availability_(); diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 7ae3a6c5e8..34eac29464 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -263,6 +263,10 @@ class MQTTClientComponent : public Component { void set_on_connect(mqtt_on_connect_callback_t &&callback); void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback); + // Publish None state instead of NaN for Home Assistant + void set_publish_nan_as_none(bool publish_nan_as_none); + bool is_publish_nan_as_none() const; + protected: void send_device_info_(); @@ -328,6 +332,8 @@ class MQTTClientComponent : public Component { uint32_t connect_begin_; uint32_t last_connected_{0}; optional disconnect_reason_{}; + + bool publish_nan_as_none_{false}; }; extern MQTTClientComponent *global_mqtt_client; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/components/mqtt/mqtt_sensor.cpp b/esphome/components/mqtt/mqtt_sensor.cpp index fff75a3c00..2cbc291ccf 100644 --- a/esphome/components/mqtt/mqtt_sensor.cpp +++ b/esphome/components/mqtt/mqtt_sensor.cpp @@ -69,6 +69,8 @@ bool MQTTSensorComponent::send_initial_state() { } } bool MQTTSensorComponent::publish_state(float value) { + if (mqtt::global_mqtt_client->is_publish_nan_as_none() && std::isnan(value)) + return this->publish(this->get_state_topic_(), "None"); int8_t accuracy = this->sensor_->get_accuracy_decimals(); return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy)); } diff --git a/esphome/const.py b/esphome/const.py index d2df83aa43..3d3bfcc244 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -692,6 +692,7 @@ CONF_PRIORITY = "priority" CONF_PROJECT = "project" CONF_PROTOCOL = "protocol" CONF_PUBLISH_INITIAL_STATE = "publish_initial_state" +CONF_PUBLISH_NAN_AS_NONE = "publish_nan_as_none" CONF_PULL_MODE = "pull_mode" CONF_PULLDOWN = "pulldown" CONF_PULLUP = "pullup" diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml index d22fe9579f..a4bdf58809 100644 --- a/tests/components/mqtt/common.yaml +++ b/tests/components/mqtt/common.yaml @@ -60,6 +60,7 @@ mqtt: - mqtt.publish: topic: some/topic payload: Good-bye + publish_nan_as_none: false binary_sensor: - platform: template From dc5942a59b521781279ff568057adf1dc01f11c8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:38:44 +1300 Subject: [PATCH 107/139] [ble] Allow setting shorter name for ble advertisements (#7867) Co-authored-by: Keith Burzinski --- esphome/components/esp32_ble/__init__.py | 24 +++++++++++++++++-- esphome/components/esp32_ble/ble.cpp | 18 ++++++++++---- esphome/components/esp32_ble/ble.h | 2 ++ .../components/esp32_ble/ble_advertising.cpp | 2 +- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 75cf9d707d..08e30c9247 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -2,8 +2,10 @@ from esphome import automation import esphome.codegen as cg from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant import esphome.config_validation as cv -from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID +from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ESPHOME, CONF_ID, CONF_NAME from esphome.core import CORE +from esphome.core.config import CONF_NAME_ADD_MAC_SUFFIX +import esphome.final_validate as fv DEPENDENCIES = ["esp32"] CODEOWNERS = ["@jesserockz", "@Rapsssito"] @@ -50,6 +52,7 @@ TX_POWER_LEVELS = { CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32BLE), + cv.Optional(CONF_NAME): cv.All(cv.string, cv.Length(max=20)), cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum( IO_CAPABILITY, lower=True ), @@ -67,7 +70,22 @@ def validate_variant(_): raise cv.Invalid(f"{variant} does not support Bluetooth") -FINAL_VALIDATE_SCHEMA = validate_variant +def final_validation(config): + validate_variant(config) + if (name := config.get(CONF_NAME)) is not None: + full_config = fv.full_config.get() + max_length = 20 + if full_config[CONF_ESPHOME][CONF_NAME_ADD_MAC_SUFFIX]: + max_length -= 7 # "-AABBCC" is appended when add mac suffix option is used + if len(name) > max_length: + raise cv.Invalid( + f"Name '{name}' is too long, maximum length is {max_length} characters" + ) + + return config + + +FINAL_VALIDATE_SCHEMA = final_validation async def to_code(config): @@ -75,6 +93,8 @@ async def to_code(config): cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY])) cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME])) + if (name := config.get(CONF_NAME)) is not None: + cg.add(var.set_name(name)) await cg.register_component(var, config) if CORE.using_esp_idf: diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 5d08b6e973..d7dcf93f86 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -188,12 +188,20 @@ bool ESP32BLE::ble_setup_() { } } - std::string name = App.get_name(); - if (name.length() > 20) { + std::string name; + if (this->name_.has_value()) { + name = this->name_.value(); if (App.is_name_add_mac_suffix_enabled()) { - name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address - } else { - name = name.substr(0, 20); + name += "-" + get_mac_address().substr(6); + } + } else { + name = App.get_name(); + if (name.length() > 20) { + if (App.is_name_add_mac_suffix_enabled()) { + name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address + } else { + name = name.substr(0, 20); + } } } diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index 7c55583852..ed7575f128 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -90,6 +90,7 @@ class ESP32BLE : public Component { void loop() override; void dump_config() override; float get_setup_priority() const override; + void set_name(const std::string &name) { this->name_ = name; } void advertising_start(); void advertising_set_service_data(const std::vector &data); @@ -131,6 +132,7 @@ class ESP32BLE : public Component { esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; uint32_t advertising_cycle_time_; bool enable_on_boot_; + optional name_; }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp index 1d340c76d9..92b7c60368 100644 --- a/esphome/components/esp32_ble/ble_advertising.cpp +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -83,7 +83,7 @@ esp_err_t BLEAdvertising::services_advertisement_() { esp_err_t err; this->advertising_data_.set_scan_rsp = false; - this->advertising_data_.include_name = !this->scan_response_; + this->advertising_data_.include_name = true; this->advertising_data_.include_txpower = !this->scan_response_; err = esp_ble_gap_config_adv_data(&this->advertising_data_); if (err != ESP_OK) { From c95887a14a61c8a5b9cab909ee9f9493eeef8cc3 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:50:11 +1100 Subject: [PATCH 108/139] [lvgl] Bugfixes (#7896) --- esphome/components/lvgl/defines.py | 2 +- esphome/components/lvgl/lvgl_esphome.h | 3 +++ esphome/components/lvgl/widgets/line.py | 6 ++++++ tests/components/lvgl/lvgl-package.yaml | 4 ++-- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 81984637bd..5371f110a6 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -38,7 +38,7 @@ def literal(arg): def call_lambda(lamb: LambdaExpression): expr = lamb.content.strip() if expr.startswith("return") and expr.endswith(";"): - return expr[7:][:-1] + return expr[6:][:-1].strip() return f"{lamb}()" diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 921b7c109f..56413ad77e 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -56,6 +56,9 @@ static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BIT inline void lv_img_set_src(lv_obj_t *obj, esphome::image::Image *image) { lv_img_set_src(obj, image->get_lv_img_dsc()); } +inline void lv_disp_set_bg_image(lv_disp_t *disp, esphome::image::Image *image) { + lv_disp_set_bg_image(disp, image->get_lv_img_dsc()); +} #endif // USE_LVGL_IMAGE #ifdef USE_LVGL_ANIMIMG inline void lv_animimg_set_src(lv_obj_t *img, std::vector images) { diff --git a/esphome/components/lvgl/widgets/line.py b/esphome/components/lvgl/widgets/line.py index 548dfa8452..0156fb1780 100644 --- a/esphome/components/lvgl/widgets/line.py +++ b/esphome/components/lvgl/widgets/line.py @@ -35,6 +35,11 @@ LINE_SCHEMA = { cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t), } +LINE_MODIFY_SCHEMA = { + cv.Optional(CONF_POINTS): cv_point_list, + cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t), +} + class LineType(WidgetType): def __init__(self): @@ -43,6 +48,7 @@ class LineType(WidgetType): LvType("lv_line_t"), (CONF_MAIN,), LINE_SCHEMA, + modify_schema=LINE_MODIFY_SCHEMA, ) async def to_code(self, w: Widget, config): diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 81b18c4ff8..6611209756 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -337,7 +337,7 @@ lvgl: id: button_button width: 20% height: 10% - transform_angle: !lambda return 180*100; + transform_angle: !lambda return(180*100); arc_width: !lambda return 4; border_width: !lambda return 6; shadow_ofs_x: !lambda return 6; @@ -581,7 +581,7 @@ lvgl: - 180, 60 - 240, 10 on_click: - - lvgl.widget.update: + - lvgl.line.update: id: lv_line_id line_color: 0xFFFF - lvgl.page.next: From 00ddb0a427b2cae4a0bda8dfc26066e6857d8e6d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:50:56 +1100 Subject: [PATCH 109/139] [font] Restore correct default glyphs for bitmap fonts (#7907) --- esphome/components/font/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index 1b4fe4bff0..c397ba8306 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -373,7 +373,9 @@ def font_file_schema(value): # Default if no glyphs or glyphsets are provided DEFAULT_GLYPHSET = "GF_Latin_Kernel" # default for bitmap fonts -DEFAULT_GLYPHS = ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz' +DEFAULT_GLYPHS = ( + ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' +) CONF_RAW_GLYPH_ID = "raw_glyph_id" From a37ff2dbd97d17c5b9b522c2a4515fd8311b7003 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:48:50 +1100 Subject: [PATCH 110/139] [lvgl] Fix msgbox content (#7912) --- esphome/components/lvgl/widgets/msgbox.py | 3 ++- tests/components/lvgl/lvgl-package.yaml | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/esphome/components/lvgl/widgets/msgbox.py b/esphome/components/lvgl/widgets/msgbox.py index be0f2100d7..c3393940b6 100644 --- a/esphome/components/lvgl/widgets/msgbox.py +++ b/esphome/components/lvgl/widgets/msgbox.py @@ -29,7 +29,7 @@ from ..lvcode import ( ) from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema, part_schema from ..types import LV_EVENT, char_ptr, lv_obj_t -from . import Widget, set_obj_properties +from . import Widget, add_widgets, set_obj_properties from .button import button_spec from .buttonmatrix import ( BUTTONMATRIX_BUTTON_SCHEMA, @@ -119,6 +119,7 @@ async def msgbox_to_code(top_layer, conf): button_style = {CONF_ITEMS: button_style} await set_obj_properties(buttonmatrix_widget, button_style) await set_obj_properties(msgbox_widget, conf) + await add_widgets(msgbox_widget, conf) async with LambdaContext(EVENT_ARG, where=messagebox_id) as close_action: outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN") if close_button: diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 6611209756..4b7e13db91 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -109,6 +109,10 @@ lvgl: close_button: true title: Messagebox bg_color: 0xffff + widgets: + - label: + text: Hello Msgbox + id: msgbox_label body: text: This is a sample messagebox bg_color: 0x808080 @@ -137,6 +141,9 @@ lvgl: - lvgl.widget.focus: mark - lvgl.widget.redraw: hello_label - lvgl.widget.redraw: + - lvgl.label.update: + id: msgbox_label + text: Unloaded on_all_events: logger.log: format: "Event %s" From d00ec7e544f26b3ec3844f531f4027b9947c8d14 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 3 Dec 2024 17:23:17 -0600 Subject: [PATCH 111/139] [helpers] clang-tidy fix for #7706 (#7909) --- esphome/core/helpers.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 103173095b..4e8caeae99 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -259,10 +259,15 @@ bool random_bytes(uint8_t *data, size_t len) { bool str_equals_case_insensitive(const std::string &a, const std::string &b) { return strcasecmp(a.c_str(), b.c_str()) == 0; } +#if ESP_IDF_VERSION_MAJOR >= 5 +bool str_startswith(const std::string &str, const std::string &start) { return str.starts_with(start); } +bool str_endswith(const std::string &str, const std::string &end) { return str.ends_with(end); } +#else bool str_startswith(const std::string &str, const std::string &start) { return str.rfind(start, 0) == 0; } bool str_endswith(const std::string &str, const std::string &end) { return str.rfind(end) == (str.size() - end.size()); } +#endif std::string str_truncate(const std::string &str, size_t length) { return str.length() > length ? str.substr(0, length) : str; } From dbed74b50d76cb7a6feb903908018aa3b96b9825 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Tue, 3 Dec 2024 17:26:27 -0600 Subject: [PATCH 112/139] [docker] Fix clang-tidy installation (#7910) --- docker/Dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index c53856d0e8..cc05849271 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -220,7 +220,11 @@ RUN \ nano=7.2-1+deb12u1 \ build-essential=12.9 \ python3-dev=3.11.2-1+b1 \ - && rm -rf \ + && if [ "$TARGETARCH$TARGETVARIANT" != "armv7" ]; then \ + # move this up after armv7 is retired + apt-get install -y --no-install-recommends clang-tidy-18=1:18.1.8~++20240731024826+3b5b5c1ec4a3-1~exp1~20240731144843.145 ; \ + fi; \ + rm -rf \ /tmp/* \ /var/{cache,log}/* \ /var/lib/apt/lists/* @@ -228,9 +232,6 @@ RUN \ COPY requirements_test.txt / RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ - else \ - # move this up into RUN above after armv7 is retired - apt-get install -y --no-install-recommends clang-tidy-18=1:18.1.8~++20240731024826+3b5b5c1ec4a3-1~exp1~20240731144843.145 ; \ fi; \ pip3 install \ --break-system-packages --no-cache-dir -r /requirements_test.txt From 79478cdb8a2731c23861da1c607e332117359179 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:13:07 +1100 Subject: [PATCH 113/139] [sntp] Resolve warnings from ESP-IDF 5.x (#7913) --- esphome/components/sntp/sntp_component.cpp | 34 +++++++++------------- esphome/components/sntp/sntp_component.h | 15 ++++------ esphome/components/sntp/time.py | 11 +++---- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/esphome/components/sntp/sntp_component.cpp b/esphome/components/sntp/sntp_component.cpp index 4ded98d483..21add1451d 100644 --- a/esphome/components/sntp/sntp_component.cpp +++ b/esphome/components/sntp/sntp_component.cpp @@ -9,11 +9,6 @@ #include "lwip/apps/sntp.h" #endif -// Yes, the server names are leaked, but that's fine. -#ifdef CLANG_TIDY -#define strdup(x) (const_cast(x)) -#endif - namespace esphome { namespace sntp { @@ -26,30 +21,29 @@ void SNTPComponent::setup() { esp_sntp_stop(); } esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + size_t i = 0; + for (auto &server : this->servers_) { + esp_sntp_setservername(i++, server.c_str()); + } + esp_sntp_set_sync_interval(this->get_update_interval()); + esp_sntp_init(); #else sntp_stop(); sntp_setoperatingmode(SNTP_OPMODE_POLL); -#endif - sntp_setservername(0, strdup(this->server_1_.c_str())); - if (!this->server_2_.empty()) { - sntp_setservername(1, strdup(this->server_2_.c_str())); + size_t i = 0; + for (auto &server : this->servers_) { + sntp_setservername(i++, server.c_str()); } - if (!this->server_3_.empty()) { - sntp_setservername(2, strdup(this->server_3_.c_str())); - } -#ifdef USE_ESP_IDF - esp_sntp_set_sync_interval(this->get_update_interval()); -#endif - sntp_init(); +#endif } void SNTPComponent::dump_config() { ESP_LOGCONFIG(TAG, "SNTP Time:"); - ESP_LOGCONFIG(TAG, " Server 1: '%s'", this->server_1_.c_str()); - ESP_LOGCONFIG(TAG, " Server 2: '%s'", this->server_2_.c_str()); - ESP_LOGCONFIG(TAG, " Server 3: '%s'", this->server_3_.c_str()); - ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str()); + size_t i = 0; + for (auto &server : this->servers_) { + ESP_LOGCONFIG(TAG, " Server %zu: '%s'", i++, server.c_str()); + } } void SNTPComponent::update() { #if !defined(USE_ESP_IDF) diff --git a/esphome/components/sntp/sntp_component.h b/esphome/components/sntp/sntp_component.h index 987dd23a19..a4e8267383 100644 --- a/esphome/components/sntp/sntp_component.h +++ b/esphome/components/sntp/sntp_component.h @@ -14,23 +14,20 @@ namespace sntp { /// \see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html class SNTPComponent : public time::RealTimeClock { public: + SNTPComponent(const std::vector &servers) : servers_(servers) {} + + // Note: set_servers() has been removed and replaced by a constructor - calling set_servers after setup would + // have had no effect anyway, and making the strings immutable avoids the need to strdup their contents. + void setup() override; void dump_config() override; - /// Change the servers used by SNTP for timekeeping - void set_servers(const std::string &server_1, const std::string &server_2, const std::string &server_3) { - this->server_1_ = server_1; - this->server_2_ = server_2; - this->server_3_ = server_3; - } float get_setup_priority() const override { return setup_priority::BEFORE_CONNECTION; } void update() override; void loop() override; protected: - std::string server_1_; - std::string server_2_; - std::string server_3_; + std::vector servers_; bool has_time_{false}; }; diff --git a/esphome/components/sntp/time.py b/esphome/components/sntp/time.py index 7cc82e3dff..6f883d5bed 100644 --- a/esphome/components/sntp/time.py +++ b/esphome/components/sntp/time.py @@ -1,16 +1,16 @@ +import esphome.codegen as cg from esphome.components import time as time_ import esphome.config_validation as cv -import esphome.codegen as cg -from esphome.core import CORE from esphome.const import ( CONF_ID, CONF_SERVERS, + PLATFORM_BK72XX, PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, PLATFORM_RTL87XX, - PLATFORM_BK72XX, ) +from esphome.core import CORE DEPENDENCIES = ["network"] sntp_ns = cg.esphome_ns.namespace("sntp") @@ -40,11 +40,8 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - servers = config[CONF_SERVERS] - servers += [""] * (3 - len(servers)) - cg.add(var.set_servers(*servers)) + var = cg.new_Pvariable(config[CONF_ID], servers) await cg.register_component(var, config) await time_.register_time(var, config) From 016fac249649b475a918eb2c17f9daa0ad399485 Mon Sep 17 00:00:00 2001 From: mikosoft83 <63317931+mikosoft83@users.noreply.github.com> Date: Wed, 4 Dec 2024 01:18:00 +0100 Subject: [PATCH 114/139] Add strftime variant with background color (#7714) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/display/display.cpp | 14 +++++++++----- esphome/components/display/display.h | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 145a4f5278..1d996bd59b 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -662,20 +662,24 @@ void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) this->trigger(from, to); } -void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) { +void Display::strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, + ESPTime time) { char buffer[64]; size_t ret = time.strftime(buffer, sizeof(buffer), format); if (ret > 0) - this->print(x, y, font, color, align, buffer); + this->print(x, y, font, color, align, buffer, background); +} +void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) { + this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time); } void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) { - this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); + this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time); } void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) { - this->strftime(x, y, font, COLOR_ON, align, format, time); + this->strftime(x, y, font, COLOR_ON, COLOR_OFF, align, format, time); } void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) { - this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time); + this->strftime(x, y, font, COLOR_ON, COLOR_OFF, TextAlign::TOP_LEFT, format, time); } void Display::start_clipping(Rect rect) { diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 54e897cdec..43da08f4ac 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -437,6 +437,20 @@ class Display : public PollingComponent { */ void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6))); + /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. + * + * @param x The x coordinate of the text alignment anchor point. + * @param y The y coordinate of the text alignment anchor point. + * @param font The font to draw the text with. + * @param color The color to draw the text with. + * @param background The background color to draw the text with. + * @param align The alignment of the text. + * @param format The format to use. + * @param ... The arguments to use for the text formatting. + */ + void strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, + ESPTime time) __attribute__((format(strftime, 8, 0))); + /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. * * @param x The x coordinate of the text alignment anchor point. From 472402745d2f3821802bbdadf2ebc45d2ee6ccf5 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 4 Dec 2024 16:18:14 -0500 Subject: [PATCH 115/139] [i2s_audio] Bugfix: Follow configured bits per sample (#7916) --- .../i2s_audio/speaker/i2s_audio_speaker.cpp | 123 +++++++++--------- .../i2s_audio/speaker/i2s_audio_speaker.h | 25 ++-- 2 files changed, 70 insertions(+), 78 deletions(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 53b3cc8dc0..194cc06a60 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -33,14 +33,15 @@ enum SpeakerEventGroupBits : uint32_t { STATE_RUNNING = (1 << 11), STATE_STOPPING = (1 << 12), STATE_STOPPED = (1 << 13), - ERR_INVALID_FORMAT = (1 << 14), - ERR_TASK_FAILED_TO_START = (1 << 15), - ERR_ESP_INVALID_STATE = (1 << 16), + ERR_TASK_FAILED_TO_START = (1 << 14), + ERR_ESP_INVALID_STATE = (1 << 15), + ERR_ESP_NOT_SUPPORTED = (1 << 16), ERR_ESP_INVALID_ARG = (1 << 17), ERR_ESP_INVALID_SIZE = (1 << 18), ERR_ESP_NO_MEM = (1 << 19), ERR_ESP_FAIL = (1 << 20), - ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | ERR_ESP_NO_MEM | ERR_ESP_FAIL, + ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_NOT_SUPPORTED | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | + ERR_ESP_NO_MEM | ERR_ESP_FAIL, ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits }; @@ -55,6 +56,8 @@ static esp_err_t err_bit_to_esp_err(uint32_t bit) { return ESP_ERR_INVALID_SIZE; case SpeakerEventGroupBits::ERR_ESP_NO_MEM: return ESP_ERR_NO_MEM; + case SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED: + return ESP_ERR_NOT_SUPPORTED; default: return ESP_FAIL; } @@ -135,19 +138,19 @@ void I2SAudioSpeaker::loop() { xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START); } - if (event_group_bits & SpeakerEventGroupBits::ERR_INVALID_FORMAT) { + if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) { + uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS; + ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits))); + this->status_set_warning(); + } + + if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED) { this->status_set_error("Failed to adjust I2S bus to match the incoming audio"); ESP_LOGE(TAG, "Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8, this->audio_stream_info_.sample_rate, this->audio_stream_info_.channels, this->audio_stream_info_.bits_per_sample); } - - if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) { - uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS; - ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits))); - this->status_set_warning(); - } } void I2SAudioSpeaker::set_volume(float volume) { @@ -236,13 +239,14 @@ void I2SAudioSpeaker::speaker_task(void *params) { xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING); audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_; - const ssize_t bytes_per_sample = audio_stream_info.get_bytes_per_sample(); - const uint8_t number_of_channels = audio_stream_info.channels; - const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * this_speaker->sample_rate_ / 1000 * - bytes_per_sample * number_of_channels; - const size_t ring_buffer_size = - this_speaker->buffer_duration_ms_ * this_speaker->sample_rate_ / 1000 * bytes_per_sample * number_of_channels; + const uint32_t bytes_per_ms = + audio_stream_info.channels * audio_stream_info.get_bytes_per_sample() * audio_stream_info.sample_rate / 1000; + + const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * bytes_per_ms; + + // Ensure ring buffer is at least as large as the total size of the DMA buffers + const size_t ring_buffer_size = std::min(dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms); if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) { // Failed to allocate buffers @@ -250,14 +254,7 @@ void I2SAudioSpeaker::speaker_task(void *params) { this_speaker->delete_task_(dma_buffers_size); } - if (this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_())) { - // Failed to start I2S driver - this_speaker->delete_task_(dma_buffers_size); - } - - if (!this_speaker->send_esp_err_to_event_group_(this_speaker->reconfigure_i2s_stream_info_(audio_stream_info))) { - // Successfully set the I2S stream info, ready to write audio data to the I2S port - + if (!this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_(audio_stream_info))) { xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING); bool stop_gracefully = false; @@ -275,6 +272,12 @@ void I2SAudioSpeaker::speaker_task(void *params) { stop_gracefully = true; } + if (this_speaker->audio_stream_info_ != audio_stream_info) { + // Audio stream info has changed, stop the speaker task so it will restart with the proper settings. + + break; + } + i2s_event_t i2s_event; while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) { if (i2s_event.type == I2S_EVENT_TX_Q_OVF) { @@ -316,17 +319,14 @@ void I2SAudioSpeaker::speaker_task(void *params) { } } } - } else { - // Couldn't configure the I2S port to be compatible with the incoming audio - xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_INVALID_FORMAT); + + xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING); + + i2s_driver_uninstall(this_speaker->parent_->get_port()); + + this_speaker->parent_->unlock(); } - i2s_zero_dma_buffer(this_speaker->parent_->get_port()); - xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING); - - i2s_driver_uninstall(this_speaker->parent_->get_port()); - - this_speaker->parent_->unlock(); this_speaker->delete_task_(dma_buffers_size); } @@ -382,6 +382,9 @@ bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) { case ESP_ERR_NO_MEM: xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM); return true; + case ESP_ERR_NOT_SUPPORTED: + xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED); + return true; default: xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL); return true; @@ -411,18 +414,40 @@ esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t rin return ESP_OK; } -esp_err_t I2SAudioSpeaker::start_i2s_driver_() { +esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info) { + if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.sample_rate)) { // NOLINT + // Can't reconfigure I2S bus, so the sample rate must match the configured value + return ESP_ERR_NOT_SUPPORTED; + } + + if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) { + // Currently can't handle the case when the incoming audio has more bits per sample than the configured value + return ESP_ERR_NOT_SUPPORTED; + } + if (!this->parent_->try_lock()) { return ESP_ERR_INVALID_STATE; } + i2s_channel_fmt_t channel = this->channel_; + + if (audio_stream_info.channels == 1) { + if (this->channel_ == I2S_CHANNEL_FMT_ONLY_LEFT) { + channel = I2S_CHANNEL_FMT_ONLY_LEFT; + } else { + channel = I2S_CHANNEL_FMT_ONLY_RIGHT; + } + } else if (audio_stream_info.channels == 2) { + channel = I2S_CHANNEL_FMT_RIGHT_LEFT; + } + int dma_buffer_length = DMA_BUFFER_DURATION_MS * this->sample_rate_ / 1000; i2s_driver_config_t config = { .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX), - .sample_rate = this->sample_rate_, + .sample_rate = audio_stream_info.sample_rate, .bits_per_sample = this->bits_per_sample_, - .channel_format = this->channel_, + .channel_format = channel, .communication_format = this->i2s_comm_fmt_, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = DMA_BUFFERS_COUNT, @@ -477,30 +502,6 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_() { return err; } -esp_err_t I2SAudioSpeaker::reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info) { - if (this->i2s_mode_ & I2S_MODE_MASTER) { - // ESP controls for the the I2S bus, so adjust the sample rate and bits per sample to match the incoming audio - this->sample_rate_ = audio_stream_info.sample_rate; - this->bits_per_sample_ = (i2s_bits_per_sample_t) audio_stream_info.bits_per_sample; - } else if (this->sample_rate_ != audio_stream_info.sample_rate) { - // Can't reconfigure I2S bus, so the sample rate must match the configured value - return ESP_ERR_INVALID_ARG; - } - - if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) { - // Currently can't handle the case when the incoming audio has more bits per sample than the configured value - return ESP_ERR_INVALID_ARG; - } - - if (audio_stream_info.channels == 1) { - return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_MONO); - } else if (audio_stream_info.channels == 2) { - return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_STEREO); - } - - return ESP_ERR_INVALID_ARG; -} - void I2SAudioSpeaker::delete_task_(size_t buffer_size) { this->audio_ring_buffer_.reset(); // Releases onwership of the shared_ptr diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h index 2b90f39399..d706deb0f4 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.h @@ -91,24 +91,15 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size); /// @brief Starts the ESP32 I2S driver. - /// Attempts to lock the I2S port, starts the I2S driver, and sets the data out pin. If it fails, it will unlock - /// the I2S port and uninstall the driver, if necessary. - /// @return ESP_ERR_INVALID_STATE if the I2S port is already locked. - /// ESP_ERR_INVALID_ARG if installing the driver or setting the data out pin fails due to a parameter error. + /// Attempts to lock the I2S port, starts the I2S driver using the passed in stream information, and sets the data out + /// pin. If it fails, it will unlock the I2S port and uninstall the driver, if necessary. + /// @param audio_stream_info Stream information for the I2S driver. + /// @return ESP_ERR_NOT_ALLOWED if the I2S port can't play the incoming audio stream. + /// ESP_ERR_INVALID_STATE if the I2S port is already locked. + /// ESP_ERR_INVALID_ARG if nstalling the driver or setting the data outpin fails due to a parameter error. /// ESP_ERR_NO_MEM if the driver fails to install due to a memory allocation error. - /// ESP_FAIL if setting the data out pin fails due to an IO error - /// ESP_OK if successful - esp_err_t start_i2s_driver_(); - - /// @brief Adjusts the I2S driver configuration to match the incoming audio stream. - /// Modifies I2S driver's sample rate, bits per sample, and number of channel settings. If the I2S is in secondary - /// mode, it only modifies the number of channels. - /// @param audio_stream_info Describes the incoming audio stream - /// @return ESP_ERR_INVALID_ARG if there is a parameter error, if there is more than 2 channels in the stream, or if - /// the audio settings are incompatible with the configuration. - /// ESP_ERR_NO_MEM if the driver fails to reconfigure due to a memory allocation error. - /// ESP_OK if successful. - esp_err_t reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info); + /// ESP_FAIL if setting the data out pin fails due to an IO error ESP_OK if successful + esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info); /// @brief Deletes the speaker's task. /// Deallocates the data_buffer_ and audio_ring_buffer_, if necessary, and deletes the task. Should only be called by From d429aa8bb8d9c8375996c0ab2335d66132cb3472 Mon Sep 17 00:00:00 2001 From: Pavlo Dudnytskyi Date: Wed, 4 Dec 2024 22:43:00 +0100 Subject: [PATCH 116/139] Haier AC quiet mode switch fix (#7902) --- esphome/components/haier/hon_climate.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/esphome/components/haier/hon_climate.cpp b/esphome/components/haier/hon_climate.cpp index 85e9cf37b9..c95a87223d 100644 --- a/esphome/components/haier/hon_climate.cpp +++ b/esphome/components/haier/hon_climate.cpp @@ -35,7 +35,9 @@ void HonClimate::set_beeper_state(bool state) { if (state != this->settings_.beeper_state) { this->settings_.beeper_state = state; #ifdef USE_SWITCH - this->beeper_switch_->publish_state(state); + if (this->beeper_switch_ != nullptr) { + this->beeper_switch_->publish_state(state); + } #endif this->hon_rtc_.save(&this->settings_); } @@ -45,10 +47,17 @@ bool HonClimate::get_beeper_state() const { return this->settings_.beeper_state; void HonClimate::set_quiet_mode_state(bool state) { if (state != this->get_quiet_mode_state()) { - this->quiet_mode_state_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; + if ((this->mode != ClimateMode::CLIMATE_MODE_OFF) && (this->mode != ClimateMode::CLIMATE_MODE_FAN_ONLY)) { + this->quiet_mode_state_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; + this->force_send_control_ = true; + } else { + this->quiet_mode_state_ = state ? SwitchState::ON : SwitchState::OFF; + } this->settings_.quiet_mode_state = state; #ifdef USE_SWITCH - this->quiet_mode_switch_->publish_state(state); + if (this->quiet_mode_switch_ != nullptr) { + this->quiet_mode_switch_->publish_state(state); + } #endif this->hon_rtc_.save(&this->settings_); } @@ -509,7 +518,7 @@ void HonClimate::initialization() { } this->current_vertical_swing_ = this->settings_.last_vertiacal_swing; this->current_horizontal_swing_ = this->settings_.last_horizontal_swing; - this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF; + this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::ON : SwitchState::OFF; } haier_protocol::HaierMessage HonClimate::get_control_message() { @@ -932,7 +941,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * if (this->mode == CLIMATE_MODE_OFF) { // AC just turned on from remote need to turn off display this->force_send_control_ = true; - } else if ((((uint8_t) this->health_mode_) & 0b10) == 0) { + } else if ((((uint8_t) this->display_status_) & 0b10) == 0) { this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF; } } @@ -1004,6 +1013,11 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t * if (new_quiet_mode != this->get_quiet_mode_state()) { this->quiet_mode_state_ = new_quiet_mode ? SwitchState::ON : SwitchState::OFF; this->settings_.quiet_mode_state = new_quiet_mode; +#ifdef USE_SWITCH + if (this->quiet_mode_switch_ != nullptr) { + this->quiet_mode_switch_->publish_state(new_quiet_mode); + } +#endif // USE_SWITCH this->hon_rtc_.save(&this->settings_); } } From 4e839d42d050f3d6c83e045512fcf5bfab8d27ac Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Wed, 4 Dec 2024 22:44:34 +0100 Subject: [PATCH 117/139] [CI] Update clang-tidy to 18.1.8 (#7915) --- requirements_dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_dev.txt b/requirements_dev.txt index 2ef8330215..1a98a15ab2 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ # Useful stuff when working in a development environment clang-format==13.0.1 # also change in .pre-commit-config.yaml and Dockerfile when updating -clang-tidy==18.1.3 # When updating clang-tidy, also update Dockerfile +clang-tidy==18.1.8 # When updating clang-tidy, also update Dockerfile yamllint==1.35.1 # also change in .pre-commit-config.yaml when updating From ece72c6b189e130bdc8a7dee7920abaa04cb61d9 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 4 Dec 2024 21:03:38 -0600 Subject: [PATCH 118/139] [i2s_audio] Speaker type fix (#7919) --- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp index 194cc06a60..d2a582c2cc 100644 --- a/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +++ b/esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp @@ -246,7 +246,8 @@ void I2SAudioSpeaker::speaker_task(void *params) { const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * bytes_per_ms; // Ensure ring buffer is at least as large as the total size of the DMA buffers - const size_t ring_buffer_size = std::min(dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms); + const size_t ring_buffer_size = + std::min((uint32_t) dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms); if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) { // Failed to allocate buffers From f3cc1e541a904d5ef44b431300e5457e4d782dd5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:44:59 +1300 Subject: [PATCH 119/139] [esp32_rmt_led_strip] Add ``COMPONENT_SCHEMA`` extending (#7918) --- esphome/components/esp32_rmt_led_strip/light.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/esp32_rmt_led_strip/light.py b/esphome/components/esp32_rmt_led_strip/light.py index 79f339e248..976f70e858 100644 --- a/esphome/components/esp32_rmt_led_strip/light.py +++ b/esphome/components/esp32_rmt_led_strip/light.py @@ -1,9 +1,9 @@ from dataclasses import dataclass -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import esp32_rmt, light +import esphome.config_validation as cv from esphome.const import ( CONF_CHIPSET, CONF_IS_RGBW, @@ -103,7 +103,7 @@ CONFIG_SCHEMA = cv.All( default="0 us", ): cv.positive_time_period_nanoseconds, } - ), + ).extend(cv.COMPONENT_SCHEMA), cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH), ) From acc8d24a325b34cd4af035bb2e26b26f1d6e4f83 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 5 Dec 2024 02:39:30 -0600 Subject: [PATCH 120/139] [esp32] Use pioarduino + IDF 5.1.5 as default for IDF builds (#7706) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .clang-tidy | 1 + esphome/components/esp32/__init__.py | 106 ++++++++++++++++-- platformio.ini | 4 +- ...build_components_base.esp32-c3-idf-51.yaml | 19 ---- .../build_components_base.esp32-idf-51.yaml | 19 ---- ...build_components_base.esp32-s2-idf-51.yaml | 20 ---- ...build_components_base.esp32-s3-idf-51.yaml | 20 ---- 7 files changed, 97 insertions(+), 92 deletions(-) delete mode 100644 tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml delete mode 100644 tests/test_build_components/build_components_base.esp32-idf-51.yaml delete mode 100644 tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml delete mode 100644 tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml diff --git a/.clang-tidy b/.clang-tidy index 8dba033e2d..5878028f48 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -21,6 +21,7 @@ Checks: >- -clang-analyzer-osx.*, -clang-diagnostic-delete-abstract-non-virtual-dtor, -clang-diagnostic-delete-non-abstract-non-virtual-dtor, + -clang-diagnostic-deprecated-declarations, -clang-diagnostic-ignored-optimization-argument, -clang-diagnostic-missing-field-initializers, -clang-diagnostic-shadow-field, diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 61fbb53e3a..580c3fc081 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -65,6 +65,8 @@ _LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@esphome/core"] AUTO_LOAD = ["preferences"] +CONF_RELEASE = "release" + def set_core_data(config): CORE.data[KEY_ESP32] = {} @@ -216,11 +218,17 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" -def _format_framework_espidf_version(ver: cv.Version) -> str: +def _format_framework_espidf_version( + ver: cv.Version, release: str, for_platformio: bool +) -> str: # format the given arduino (https://github.com/espressif/esp-idf/releases) version to # a PIO platformio/framework-espidf value # List of package versions: https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf - return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" + if for_platformio: + return f"platformio/framework-espidf@~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0" + if release: + return f"pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v{str(ver)}.{release}/esp-idf-v{str(ver)}.zip" + return f"pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v{str(ver)}/esp-idf-v{str(ver)}.zip" # NOTE: Keep this in mind when updating the recommended version: @@ -241,11 +249,33 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0) # The default/recommended esp-idf framework version # - https://github.com/espressif/esp-idf/releases # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf -RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 8) +RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(5, 1, 5) # The platformio/espressif32 version to use for esp-idf frameworks # - https://github.com/platformio/platform-espressif32/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 -ESP_IDF_PLATFORM_VERSION = cv.Version(5, 4, 0) +ESP_IDF_PLATFORM_VERSION = cv.Version(51, 3, 7) + +# List based on https://registry.platformio.org/tools/platformio/framework-espidf/versions +SUPPORTED_PLATFORMIO_ESP_IDF_5X = [ + cv.Version(5, 3, 1), + cv.Version(5, 3, 0), + cv.Version(5, 2, 2), + cv.Version(5, 2, 1), + cv.Version(5, 1, 2), + cv.Version(5, 1, 1), + cv.Version(5, 1, 0), + cv.Version(5, 0, 2), + cv.Version(5, 0, 1), + cv.Version(5, 0, 0), +] + +# pioarduino versions that don't require a release number +# List based on https://github.com/pioarduino/esp-idf/releases +SUPPORTED_PIOARDUINO_ESP_IDF_5X = [ + cv.Version(5, 3, 1), + cv.Version(5, 3, 0), + cv.Version(5, 1, 5), +] def _arduino_check_versions(value): @@ -286,8 +316,8 @@ def _arduino_check_versions(value): def _esp_idf_check_versions(value): value = value.copy() lookups = { - "dev": (cv.Version(5, 1, 2), "https://github.com/espressif/esp-idf.git"), - "latest": (cv.Version(5, 1, 2), None), + "dev": (cv.Version(5, 1, 5), "https://github.com/espressif/esp-idf.git"), + "latest": (cv.Version(5, 1, 5), None), "recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None), } @@ -305,13 +335,51 @@ def _esp_idf_check_versions(value): if version < cv.Version(4, 0, 0): raise cv.Invalid("Only ESP-IDF 4.0+ is supported.") - value[CONF_VERSION] = str(version) - value[CONF_SOURCE] = source or _format_framework_espidf_version(version) + # flag this for later *before* we set value[CONF_PLATFORM_VERSION] below + has_platform_ver = CONF_PLATFORM_VERSION in value value[CONF_PLATFORM_VERSION] = value.get( CONF_PLATFORM_VERSION, _parse_platform_version(str(ESP_IDF_PLATFORM_VERSION)) ) + if ( + (is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION])) + and version.major >= 5 + and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X + ): + raise cv.Invalid( + f"ESP-IDF {str(version)} not supported by platformio/espressif32" + ) + + if ( + version.major < 5 + or ( + version in SUPPORTED_PLATFORMIO_ESP_IDF_5X + and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X + ) + ) and not has_platform_ver: + raise cv.Invalid( + f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'" + ) + + if ( + not is_platformio + and CONF_RELEASE not in value + and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X + ): + raise cv.Invalid( + f"ESP-IDF {value[CONF_VERSION]} is not available with pioarduino; you may need to specify '{CONF_RELEASE}'" + ) + + value[CONF_VERSION] = str(version) + value[CONF_SOURCE] = source or _format_framework_espidf_version( + version, value.get(CONF_RELEASE, None), is_platformio + ) + + if value[CONF_SOURCE].startswith("http"): + # prefix is necessary or platformio will complain with a cryptic error + value[CONF_SOURCE] = f"framework-espidf@{value[CONF_SOURCE]}" + if version != RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION: _LOGGER.warning( "The selected ESP-IDF framework version is not the recommended one. " @@ -323,6 +391,12 @@ def _esp_idf_check_versions(value): def _parse_platform_version(value): try: + ver = cv.Version.parse(cv.version_number(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}" # if platform version is a valid version constraint, prefix the default package cv.platformio_version_constraint(value) return f"platformio/espressif32@{value}" @@ -330,6 +404,14 @@ def _parse_platform_version(value): return value +def _platform_is_platformio(value): + try: + ver = cv.Version.parse(cv.version_number(value)) + return ver.major < 50 + except cv.Invalid: + return "platformio" in value + + def _detect_variant(value): board = value[CONF_BOARD] if board in BOARDS: @@ -412,6 +494,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All( cv.Schema( { cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict, + cv.Optional(CONF_RELEASE): cv.string_strict, cv.Optional(CONF_SOURCE): cv.string_strict, cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, cv.Optional(CONF_SDKCONFIG_OPTIONS, default={}): { @@ -515,10 +598,9 @@ async def to_code(config): cg.add_build_flag("-DUSE_ESP_IDF") cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ESP_IDF") cg.add_build_flag("-Wno-nonnull-compare") - cg.add_platformio_option( - "platform_packages", - [f"platformio/framework-espidf@{conf[CONF_SOURCE]}"], - ) + + cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]]) + # platformio/toolchain-esp32ulp does not support linux_aarch64 yet and has not been updated for over 2 years # This is espressif's own published version which is more up to date. cg.add_platformio_option( diff --git a/platformio.ini b/platformio.ini index 04afc059af..b9b80e933f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -137,9 +137,9 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script ; This are common settings for the ESP32 (all variants) using IDF. [common:esp32-idf] extends = common:idf -platform = platformio/espressif32@5.4.0 +platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.06/platform-espressif32.zip platform_packages = - platformio/framework-espidf@~3.40408.0 + pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v5.1.5/esp-idf-v5.1.5.zip framework = espidf lib_deps = diff --git a/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml deleted file mode 100644 index eb5b23a4ec..0000000000 --- a/tests/test_build_components/build_components_base.esp32-c3-idf-51.yaml +++ /dev/null @@ -1,19 +0,0 @@ -esphome: - name: componenttestesp32c3idf51 - friendly_name: $component_name - -esp32: - board: lolin_c3_mini - framework: - type: esp-idf - version: 5.1.2 - platform_version: 6.5.0 - -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-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-idf-51.yaml deleted file mode 100644 index b5e3dd6d83..0000000000 --- a/tests/test_build_components/build_components_base.esp32-idf-51.yaml +++ /dev/null @@ -1,19 +0,0 @@ -esphome: - name: componenttestesp32idf51 - friendly_name: $component_name - -esp32: - board: nodemcu-32s - framework: - type: esp-idf - version: 5.1.2 - platform_version: 6.5.0 - -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-s2-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml deleted file mode 100644 index 11b077509e..0000000000 --- a/tests/test_build_components/build_components_base.esp32-s2-idf-51.yaml +++ /dev/null @@ -1,20 +0,0 @@ -esphome: - name: componenttestesp32s2idf51 - friendly_name: $component_name - -esp32: - board: esp32-s2-saola-1 - variant: ESP32S2 - framework: - type: esp-idf - version: 5.1.2 - platform_version: 6.5.0 - -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-s3-idf-51.yaml b/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml deleted file mode 100644 index 4357b3581b..0000000000 --- a/tests/test_build_components/build_components_base.esp32-s3-idf-51.yaml +++ /dev/null @@ -1,20 +0,0 @@ -esphome: - name: componenttestesp32s3idf51 - friendly_name: $component_name - -esp32: - board: esp32s3box - variant: ESP32S3 - framework: - type: esp-idf - version: 5.1.2 - platform_version: 6.5.0 - -logger: - level: VERY_VERBOSE - -packages: - component_under_test: !include - file: $component_test_file - vars: - component_test_file: $component_test_file From 555bdac604147b1f918c6c11609589ac88f5c368 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:11:31 +1300 Subject: [PATCH 121/139] Bump actions/cache from 4.1.2 to 4.2.0 (#7926) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4d3934c59..6ce4159da0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v4.1.2 + uses: actions/cache@v4.2.0 with: path: venv # yamllint disable-line rule:line-length @@ -302,14 +302,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@v4.1.2 + uses: actions/cache@v4.2.0 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@v4.1.2 + uses: actions/cache/restore@v4.2.0 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }} From d3a71a1d45fa3958fee3aac4e1afacb5408e726a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:11:46 +1300 Subject: [PATCH 122/139] Bump actions/cache from 4.1.2 to 4.2.0 in /.github/actions/restore-python (#7925) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/restore-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index 06c54578f5..6b87cf0170 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -22,7 +22,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@v4.1.2 + uses: actions/cache/restore@v4.2.0 with: path: venv # yamllint disable-line rule:line-length From 4e3195b474e5ffeda909e9d8933f8611da758779 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:16:59 +1100 Subject: [PATCH 123/139] [esp32] Fix crash with empty `platformio_options:` value (#7920) --- esphome/components/esp32/__init__.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 580c3fc081..b0bde75451 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -437,24 +437,20 @@ def _detect_variant(value): def final_validate(config): - if CONF_PLATFORMIO_OPTIONS not in fv.full_config.get()[CONF_ESPHOME]: + if not ( + pio_options := fv.full_config.get()[CONF_ESPHOME].get(CONF_PLATFORMIO_OPTIONS) + ): + # Not specified or empty return config pio_flash_size_key = "board_upload.flash_size" pio_partitions_key = "board_build.partitions" - if ( - CONF_PARTITIONS in config - and pio_partitions_key - in fv.full_config.get()[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS] - ): + if CONF_PARTITIONS in config and pio_partitions_key in pio_options: raise cv.Invalid( f"Do not specify '{pio_partitions_key}' in '{CONF_PLATFORMIO_OPTIONS}' with '{CONF_PARTITIONS}' in esp32" ) - if ( - pio_flash_size_key - in fv.full_config.get()[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS] - ): + if pio_flash_size_key in pio_options: raise cv.Invalid( f"Please specify {CONF_FLASH_SIZE} within esp32 configuration only" ) From bfd75d736c3693f7b055e890bf9a36d51543f646 Mon Sep 17 00:00:00 2001 From: alorente Date: Fri, 6 Dec 2024 01:21:14 +0100 Subject: [PATCH 124/139] Add OCI Image Labels (#7924) --- docker/Dockerfile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index cc05849271..1754d951e5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -196,8 +196,16 @@ LABEL \ io.hass.name="ESPHome" \ io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ io.hass.type="addon" \ - io.hass.version="${BUILD_VERSION}" + io.hass.version="${BUILD_VERSION}" \ # io.hass.arch is inherited from addon-debian-base + org.opencontainers.image.authors="The ESPHome Authors" \ + org.opencontainers.image.title="ESPHome" \ + org.opencontainers.image.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ + org.opencontainers.image.url="https://esphome.io/" \ + org.opencontainers.image.documentation="https://esphome.io/" \ + org.opencontainers.image.source="https://github.com/esphome/esphome" \ + org.opencontainers.image.licenses="ESPHome" \ + org.opencontainers.image.version=${BUILD_VERSION} From 58123845ff5f5a61139b9144b266fc1d32136926 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:11:11 +1300 Subject: [PATCH 125/139] Move docker oci labels to correct image (#7927) --- docker/Dockerfile | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 1754d951e5..947e410fe1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -163,6 +163,18 @@ ENTRYPOINT ["/entrypoint.sh"] CMD ["dashboard", "/config"] +ARG BUILD_VERSION=dev + +# Labels +LABEL \ + org.opencontainers.image.authors="The ESPHome Authors" \ + org.opencontainers.image.title="ESPHome" \ + org.opencontainers.image.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ + org.opencontainers.image.url="https://esphome.io/" \ + org.opencontainers.image.documentation="https://esphome.io/" \ + org.opencontainers.image.source="https://github.com/esphome/esphome" \ + org.opencontainers.image.licenses="ESPHome" \ + org.opencontainers.image.version=${BUILD_VERSION} # ======================= hassio-type image ======================= @@ -196,16 +208,8 @@ LABEL \ io.hass.name="ESPHome" \ io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ io.hass.type="addon" \ - io.hass.version="${BUILD_VERSION}" \ + io.hass.version="${BUILD_VERSION}" # io.hass.arch is inherited from addon-debian-base - org.opencontainers.image.authors="The ESPHome Authors" \ - org.opencontainers.image.title="ESPHome" \ - org.opencontainers.image.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ - org.opencontainers.image.url="https://esphome.io/" \ - org.opencontainers.image.documentation="https://esphome.io/" \ - org.opencontainers.image.source="https://github.com/esphome/esphome" \ - org.opencontainers.image.licenses="ESPHome" \ - org.opencontainers.image.version=${BUILD_VERSION} From b0e3ac01e83258329244ca0efc557c2225c7d790 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:24:20 +1300 Subject: [PATCH 126/139] Update project description (#7928) --- docker/Dockerfile | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 947e410fe1..0bb558d35e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -169,7 +169,7 @@ ARG BUILD_VERSION=dev LABEL \ org.opencontainers.image.authors="The ESPHome Authors" \ org.opencontainers.image.title="ESPHome" \ - org.opencontainers.image.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ + org.opencontainers.image.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \ org.opencontainers.image.url="https://esphome.io/" \ org.opencontainers.image.documentation="https://esphome.io/" \ org.opencontainers.image.source="https://github.com/esphome/esphome" \ @@ -206,7 +206,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ # Labels LABEL \ io.hass.name="ESPHome" \ - io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \ + io.hass.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \ io.hass.type="addon" \ io.hass.version="${BUILD_VERSION}" # io.hass.arch is inherited from addon-debian-base diff --git a/pyproject.toml b/pyproject.toml index cfc279845f..7789f6d645 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "esphome" license = {text = "MIT"} -description = "Make creating custom firmwares for ESP32/ESP8266 super easy." +description = "ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems." readme = "README.md" authors = [ {name = "The ESPHome Authors", email = "esphome@nabucasa.com"} From 749a5e3348e5da84b8a199ef49ea5122d993d6c1 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Thu, 5 Dec 2024 20:41:53 -0600 Subject: [PATCH 127/139] [modbus] More clean-up (#7921) --- .../components/modbus_controller/modbus_controller.cpp | 10 +++++----- .../modbus_controller/switch/modbus_switch.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 641ba68223..3f487abc94 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -152,9 +152,9 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t } SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const { - auto reg_it = find_if(begin(this->register_ranges_), end(this->register_ranges_), [=](RegisterRange const &r) { - return (r.start_address == start_address && r.register_type == register_type); - }); + auto reg_it = std::find_if( + std::begin(this->register_ranges_), std::end(this->register_ranges_), + [=](RegisterRange const &r) { return (r.start_address == start_address && r.register_type == register_type); }); if (reg_it == this->register_ranges_.end()) { ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address); @@ -375,12 +375,12 @@ void ModbusController::loop() { if (!this->incoming_queue_.empty()) { auto &message = this->incoming_queue_.front(); if (message != nullptr) - process_modbus_data_(message.get()); + this->process_modbus_data_(message.get()); this->incoming_queue_.pop(); } else { // all messages processed send pending commands - send_next_command_(); + this->send_next_command_(); } } diff --git a/esphome/components/modbus_controller/switch/modbus_switch.cpp b/esphome/components/modbus_controller/switch/modbus_switch.cpp index ec29eca7f8..b729e2659f 100644 --- a/esphome/components/modbus_controller/switch/modbus_switch.cpp +++ b/esphome/components/modbus_controller/switch/modbus_switch.cpp @@ -97,7 +97,7 @@ void ModbusSwitch::write_state(bool state) { } } this->parent_->queue_command(cmd); - publish_state(state); + this->publish_state(state); } // ModbusSwitch end } // namespace modbus_controller From 9d000e9abf3832497e8a6640e66c0eb4c8568060 Mon Sep 17 00:00:00 2001 From: Citric Lee <37475446+limengdu@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:28:41 +0800 Subject: [PATCH 128/139] Add: Seeed Studio MR60BHA2 mmWave Sensor (#7589) Co-authored-by: Spencer Yan Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/seeed_mr60bha2/__init__.py | 41 +++++ .../seeed_mr60bha2/seeed_mr60bha2.cpp | 173 ++++++++++++++++++ .../seeed_mr60bha2/seeed_mr60bha2.h | 61 ++++++ esphome/components/seeed_mr60bha2/sensor.py | 57 ++++++ esphome/const.py | 2 + tests/components/seeed_mr60bha2/common.yaml | 19 ++ .../seeed_mr60bha2/test.esp32-c3-ard.yaml | 5 + .../seeed_mr60bha2/test.esp32-c3-idf.yaml | 5 + 9 files changed, 364 insertions(+) create mode 100644 esphome/components/seeed_mr60bha2/__init__.py create mode 100644 esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp create mode 100644 esphome/components/seeed_mr60bha2/seeed_mr60bha2.h create mode 100644 esphome/components/seeed_mr60bha2/sensor.py create mode 100644 tests/components/seeed_mr60bha2/common.yaml create mode 100644 tests/components/seeed_mr60bha2/test.esp32-c3-ard.yaml create mode 100644 tests/components/seeed_mr60bha2/test.esp32-c3-idf.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 74c205b302..404ad35efc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -355,6 +355,7 @@ esphome/components/sdl/* @clydebarrow esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sdp3x/* @Azimath esphome/components/seeed_mr24hpc1/* @limengdu +esphome/components/seeed_mr60bha2/* @limengdu esphome/components/seeed_mr60fda2/* @limengdu esphome/components/selec_meter/* @sourabhjaiswal esphome/components/select/* @esphome/core diff --git a/esphome/components/seeed_mr60bha2/__init__.py b/esphome/components/seeed_mr60bha2/__init__.py new file mode 100644 index 0000000000..87bdbbd003 --- /dev/null +++ b/esphome/components/seeed_mr60bha2/__init__.py @@ -0,0 +1,41 @@ +import esphome.codegen as cg +from esphome.components import uart +import esphome.config_validation as cv +from esphome.const import CONF_ID + +CODEOWNERS = ["@limengdu"] +DEPENDENCIES = ["uart"] +MULTI_CONF = True + +mr60bha2_ns = cg.esphome_ns.namespace("seeed_mr60bha2") + +MR60BHA2Component = mr60bha2_ns.class_( + "MR60BHA2Component", cg.Component, uart.UARTDevice +) + +CONF_MR60BHA2_ID = "mr60bha2_id" + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(MR60BHA2Component), + } + ) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "seeed_mr60bha2", + require_tx=True, + require_rx=True, + baud_rate=115200, + parity="NONE", + stop_bits=1, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) diff --git a/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp b/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp new file mode 100644 index 0000000000..50d709c3b0 --- /dev/null +++ b/esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp @@ -0,0 +1,173 @@ +#include "seeed_mr60bha2.h" +#include "esphome/core/log.h" + +#include + +namespace esphome { +namespace seeed_mr60bha2 { + +static const char *const TAG = "seeed_mr60bha2"; + +// Prints the component's configuration data. dump_config() prints all of the component's configuration +// items in an easy-to-read format, including the configuration key-value pairs. +void MR60BHA2Component::dump_config() { + ESP_LOGCONFIG(TAG, "MR60BHA2:"); +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Breath Rate Sensor", this->breath_rate_sensor_); + LOG_SENSOR(" ", "Heart Rate Sensor", this->heart_rate_sensor_); + LOG_SENSOR(" ", "Distance Sensor", this->distance_sensor_); +#endif +} + +// main loop +void MR60BHA2Component::loop() { + uint8_t byte; + + // Is there data on the serial port + while (this->available()) { + this->read_byte(&byte); + this->rx_message_.push_back(byte); + if (!this->validate_message_()) { + this->rx_message_.clear(); + } + } +} + +/** + * @brief Calculate the checksum for a byte array. + * + * This function calculates the checksum for the provided byte array using an + * XOR-based checksum algorithm. + * + * @param data The byte array to calculate the checksum for. + * @param len The length of the byte array. + * @return The calculated checksum. + */ +static uint8_t calculate_checksum(const uint8_t *data, size_t len) { + uint8_t checksum = 0; + for (size_t i = 0; i < len; i++) { + checksum ^= data[i]; + } + checksum = ~checksum; + return checksum; +} + +/** + * @brief Validate the checksum of a byte array. + * + * This function validates the checksum of the provided byte array by comparing + * it to the expected checksum. + * + * @param data The byte array to validate. + * @param len The length of the byte array. + * @param expected_checksum The expected checksum. + * @return True if the checksum is valid, false otherwise. + */ +static bool validate_checksum(const uint8_t *data, size_t len, uint8_t expected_checksum) { + return calculate_checksum(data, len) == expected_checksum; +} + +bool MR60BHA2Component::validate_message_() { + size_t at = this->rx_message_.size() - 1; + auto *data = &this->rx_message_[0]; + uint8_t new_byte = data[at]; + + if (at == 0) { + return new_byte == FRAME_HEADER_BUFFER; + } + + if (at <= 2) { + return true; + } + uint16_t frame_id = encode_uint16(data[1], data[2]); + + if (at <= 4) { + return true; + } + + uint16_t length = encode_uint16(data[3], data[4]); + + if (at <= 6) { + return true; + } + + uint16_t frame_type = encode_uint16(data[5], data[6]); + + if (frame_type != BREATH_RATE_TYPE_BUFFER && frame_type != HEART_RATE_TYPE_BUFFER && + frame_type != DISTANCE_TYPE_BUFFER) { + return false; + } + + uint8_t header_checksum = new_byte; + + if (at == 7) { + if (!validate_checksum(data, 7, header_checksum)) { + ESP_LOGE(TAG, "HEAD_CKSUM_FRAME ERROR: 0x%02x", header_checksum); + ESP_LOGV(TAG, "GET FRAME: %s", format_hex_pretty(data, 8).c_str()); + return false; + } + return true; + } + + // Wait until all data is read + if (at - 8 < length) { + return true; + } + + uint8_t data_checksum = new_byte; + if (at == 8 + length) { + if (!validate_checksum(data + 8, length, data_checksum)) { + ESP_LOGE(TAG, "DATA_CKSUM_FRAME ERROR: 0x%02x", data_checksum); + ESP_LOGV(TAG, "GET FRAME: %s", format_hex_pretty(data, 8 + length).c_str()); + return false; + } + } + + const uint8_t *frame_data = data + 8; + ESP_LOGV(TAG, "Received Frame: ID: 0x%04x, Type: 0x%04x, Data: [%s] Raw Data: [%s]", frame_id, frame_type, + format_hex_pretty(frame_data, length).c_str(), format_hex_pretty(this->rx_message_).c_str()); + this->process_frame_(frame_id, frame_type, data + 8, length); + + // Return false to reset rx buffer + return false; +} + +void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, const uint8_t *data, size_t length) { + switch (frame_type) { + case BREATH_RATE_TYPE_BUFFER: + if (this->breath_rate_sensor_ != nullptr && length >= 4) { + uint32_t current_breath_rate_int = encode_uint32(data[3], data[2], data[1], data[0]); + if (current_breath_rate_int != 0) { + float breath_rate_float; + memcpy(&breath_rate_float, ¤t_breath_rate_int, sizeof(float)); + this->breath_rate_sensor_->publish_state(breath_rate_float); + } + } + break; + case HEART_RATE_TYPE_BUFFER: + if (this->heart_rate_sensor_ != nullptr && length >= 4) { + uint32_t current_heart_rate_int = encode_uint32(data[3], data[2], data[1], data[0]); + if (current_heart_rate_int != 0) { + float heart_rate_float; + memcpy(&heart_rate_float, ¤t_heart_rate_int, sizeof(float)); + this->heart_rate_sensor_->publish_state(heart_rate_float); + } + } + break; + case DISTANCE_TYPE_BUFFER: + if (!data[0]) { + if (this->distance_sensor_ != nullptr && length >= 8) { + uint32_t current_distance_int = encode_uint32(data[7], data[6], data[5], data[4]); + float distance_float; + memcpy(&distance_float, ¤t_distance_int, sizeof(float)); + this->distance_sensor_->publish_state(distance_float); + } + } + break; + default: + break; + } +} + +} // namespace seeed_mr60bha2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60bha2/seeed_mr60bha2.h b/esphome/components/seeed_mr60bha2/seeed_mr60bha2.h new file mode 100644 index 0000000000..0a4f21f1ad --- /dev/null +++ b/esphome/components/seeed_mr60bha2/seeed_mr60bha2.h @@ -0,0 +1,61 @@ +#pragma once +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif +#include "esphome/components/uart/uart.h" +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" + +#include + +namespace esphome { +namespace seeed_mr60bha2 { + +static const uint8_t DATA_BUF_MAX_SIZE = 12; +static const uint8_t FRAME_BUF_MAX_SIZE = 21; +static const uint8_t LEN_TO_HEAD_CKSUM = 8; +static const uint8_t LEN_TO_DATA_FRAME = 9; + +static const uint8_t FRAME_HEADER_BUFFER = 0x01; +static const uint16_t BREATH_RATE_TYPE_BUFFER = 0x0A14; +static const uint16_t HEART_RATE_TYPE_BUFFER = 0x0A15; +static const uint16_t DISTANCE_TYPE_BUFFER = 0x0A16; + +enum FrameLocation { + LOCATE_FRAME_HEADER, + LOCATE_ID_FRAME1, + LOCATE_ID_FRAME2, + LOCATE_LENGTH_FRAME_H, + LOCATE_LENGTH_FRAME_L, + LOCATE_TYPE_FRAME1, + LOCATE_TYPE_FRAME2, + LOCATE_HEAD_CKSUM_FRAME, // Header checksum: [from the first byte to the previous byte of the HEAD_CKSUM bit] + LOCATE_DATA_FRAME, + LOCATE_DATA_CKSUM_FRAME, // Data checksum: [from the first to the previous byte of the DATA_CKSUM bit] + LOCATE_PROCESS_FRAME, +}; + +class MR60BHA2Component : public Component, + public uart::UARTDevice { // The class name must be the name defined by text_sensor.py +#ifdef USE_SENSOR + SUB_SENSOR(breath_rate); + SUB_SENSOR(heart_rate); + SUB_SENSOR(distance); +#endif + + public: + float get_setup_priority() const override { return esphome::setup_priority::LATE; } + void dump_config() override; + void loop() override; + + protected: + bool validate_message_(); + void process_frame_(uint16_t frame_id, uint16_t frame_type, const uint8_t *data, size_t length); + + std::vector rx_message_; +}; + +} // namespace seeed_mr60bha2 +} // namespace esphome diff --git a/esphome/components/seeed_mr60bha2/sensor.py b/esphome/components/seeed_mr60bha2/sensor.py new file mode 100644 index 0000000000..5f30b363bf --- /dev/null +++ b/esphome/components/seeed_mr60bha2/sensor.py @@ -0,0 +1,57 @@ +import esphome.codegen as cg +from esphome.components import sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_DISTANCE, + DEVICE_CLASS_DISTANCE, + ICON_HEART_PULSE, + ICON_PULSE, + ICON_SIGNAL, + STATE_CLASS_MEASUREMENT, + UNIT_BEATS_PER_MINUTE, + UNIT_CENTIMETER, +) + +from . import CONF_MR60BHA2_ID, MR60BHA2Component + +DEPENDENCIES = ["seeed_mr60bha2"] + +CONF_BREATH_RATE = "breath_rate" +CONF_HEART_RATE = "heart_rate" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_MR60BHA2_ID): cv.use_id(MR60BHA2Component), + cv.Optional(CONF_BREATH_RATE): sensor.sensor_schema( + accuracy_decimals=2, + state_class=STATE_CLASS_MEASUREMENT, + icon=ICON_PULSE, + ), + cv.Optional(CONF_HEART_RATE): sensor.sensor_schema( + accuracy_decimals=0, + icon=ICON_HEART_PULSE, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_BEATS_PER_MINUTE, + ), + cv.Optional(CONF_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, + state_class=STATE_CLASS_MEASUREMENT, + unit_of_measurement=UNIT_CENTIMETER, + accuracy_decimals=2, + icon=ICON_SIGNAL, + ), + } +) + + +async def to_code(config): + mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID]) + if breath_rate_config := config.get(CONF_BREATH_RATE): + sens = await sensor.new_sensor(breath_rate_config) + cg.add(mr60bha2_component.set_breath_rate_sensor(sens)) + if heart_rate_config := config.get(CONF_HEART_RATE): + sens = await sensor.new_sensor(heart_rate_config) + cg.add(mr60bha2_component.set_heart_rate_sensor(sens)) + if distance_config := config.get(CONF_DISTANCE): + sens = await sensor.new_sensor(distance_config) + cg.add(mr60bha2_component.set_distance_sensor(sens)) diff --git a/esphome/const.py b/esphome/const.py index 3d3bfcc244..b9397aa1bd 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1001,6 +1001,7 @@ ICON_GRAIN = "mdi:grain" ICON_GYROSCOPE_X = "mdi:axis-x-rotate-clockwise" ICON_GYROSCOPE_Y = "mdi:axis-y-rotate-clockwise" ICON_GYROSCOPE_Z = "mdi:axis-z-rotate-clockwise" +ICON_HEART_PULSE = "mdi:heart-pulse" ICON_HEATING_COIL = "mdi:heating-coil" ICON_KEY_PLUS = "mdi:key-plus" ICON_LIGHTBULB = "mdi:lightbulb" @@ -1040,6 +1041,7 @@ ICON_WEATHER_WINDY = "mdi:weather-windy" ICON_WIFI = "mdi:wifi" UNIT_AMPERE = "A" +UNIT_BEATS_PER_MINUTE = "bpm" UNIT_BECQUEREL_PER_CUBIC_METER = "Bq/m³" UNIT_BYTES = "B" UNIT_CELSIUS = "°C" diff --git a/tests/components/seeed_mr60bha2/common.yaml b/tests/components/seeed_mr60bha2/common.yaml new file mode 100644 index 0000000000..e9d0c735af --- /dev/null +++ b/tests/components/seeed_mr60bha2/common.yaml @@ -0,0 +1,19 @@ +uart: + - id: seeed_mr60fda2_uart + tx_pin: ${uart_tx_pin} + rx_pin: ${uart_rx_pin} + baud_rate: 115200 + parity: NONE + stop_bits: 1 + +seeed_mr60bha2: + id: my_seeed_mr60bha2 + +sensor: + - platform: seeed_mr60bha2 + breath_rate: + name: "Real-time respiratory rate" + heart_rate: + name: "Real-time heart rate" + distance: + name: "Distance to detection object" diff --git a/tests/components/seeed_mr60bha2/test.esp32-c3-ard.yaml b/tests/components/seeed_mr60bha2/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..4fb884abf4 --- /dev/null +++ b/tests/components/seeed_mr60bha2/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO5 + uart_rx_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/seeed_mr60bha2/test.esp32-c3-idf.yaml b/tests/components/seeed_mr60bha2/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..4fb884abf4 --- /dev/null +++ b/tests/components/seeed_mr60bha2/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + uart_tx_pin: GPIO5 + uart_rx_pin: GPIO4 + +<<: !include common.yaml From f15e3cfb9b9cc26b402d1098549a79e87c00d9bc Mon Sep 17 00:00:00 2001 From: David Schneider Date: Sun, 8 Dec 2024 18:51:37 -0800 Subject: [PATCH 129/139] Optimize QMC5883L reads (#7889) --- esphome/components/qmc5883l/qmc5883l.cpp | 62 +++++++++++++++++------- esphome/components/qmc5883l/qmc5883l.h | 2 +- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index 49a67d4e09..36286244fb 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -81,16 +81,39 @@ void QMC5883LComponent::dump_config() { } float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; } void QMC5883LComponent::update() { + i2c::ErrorCode err; uint8_t status = false; - this->read_byte(QMC5883L_REGISTER_STATUS, &status); + // Status byte gets cleared when data is read, so we have to read this first. + // If status and two axes are desired, it's possible to save one byte of traffic by enabling + // ROL_PNT in setup and reading 7 bytes starting at the status register. + // If status and all three axes are desired, using ROL_PNT saves you 3 bytes. + // But simply not reading status saves you 4 bytes always and is much simpler. + if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG) { + err = this->read_register(QMC5883L_REGISTER_STATUS, &status, 1); + if (err != i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("status read failed (%d)", err).c_str()); + return; + } + } - // Always request X,Y,Z regardless if there are sensors for them - // to avoid https://github.com/esphome/issues/issues/5731 - uint16_t raw_x, raw_y, raw_z; - if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x) || - !this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y) || - !this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) { - this->status_set_warning(); + uint16_t raw[3] = {0}; + // Z must always be requested, otherwise the data registers will remain locked against updates. + // Skipping the Y axis if X and Z are needed actually requires an additional byte of comms. + // Starting partway through the axes does save you traffic. + uint8_t start, dest; + if (this->heading_sensor_ != nullptr || this->x_sensor_ != nullptr) { + start = QMC5883L_REGISTER_DATA_X_LSB; + dest = 0; + } else if (this->y_sensor_ != nullptr) { + start = QMC5883L_REGISTER_DATA_Y_LSB; + dest = 1; + } else { + start = QMC5883L_REGISTER_DATA_Z_LSB; + dest = 2; + } + err = this->read_bytes_16_le_(start, &raw[dest], 3 - dest); + if (err != i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("mag read failed (%d)", err).c_str()); return; } @@ -107,17 +130,18 @@ void QMC5883LComponent::update() { } // in µT - const float x = int16_t(raw_x) * mg_per_bit * 0.1f; - const float y = int16_t(raw_y) * mg_per_bit * 0.1f; - const float z = int16_t(raw_z) * mg_per_bit * 0.1f; + const float x = int16_t(raw[0]) * mg_per_bit * 0.1f; + const float y = int16_t(raw[1]) * mg_per_bit * 0.1f; + const float z = int16_t(raw[2]) * mg_per_bit * 0.1f; float heading = atan2f(0.0f - x, y) * 180.0f / M_PI; float temp = NAN; if (this->temperature_sensor_ != nullptr) { uint16_t raw_temp; - if (!this->read_byte_16_(QMC5883L_REGISTER_TEMPERATURE_LSB, &raw_temp)) { - this->status_set_warning(); + err = this->read_bytes_16_le_(QMC5883L_REGISTER_TEMPERATURE_LSB, &raw_temp); + if (err != i2c::ERROR_OK) { + this->status_set_warning(str_sprintf("temp read failed (%d)", err).c_str()); return; } temp = int16_t(raw_temp) * 0.01f; @@ -138,11 +162,13 @@ void QMC5883LComponent::update() { this->temperature_sensor_->publish_state(temp); } -bool QMC5883LComponent::read_byte_16_(uint8_t a_register, uint16_t *data) { - if (!this->read_byte_16(a_register, data)) - return false; - *data = (*data & 0x00FF) << 8 | (*data & 0xFF00) >> 8; // Flip Byte order, LSB first; - return true; +i2c::ErrorCode QMC5883LComponent::read_bytes_16_le_(uint8_t a_register, uint16_t *data, uint8_t len) { + i2c::ErrorCode err = this->read_register(a_register, reinterpret_cast(data), len * 2); + if (err != i2c::ERROR_OK) + return err; + for (size_t i = 0; i < len; i++) + data[i] = convert_little_endian(data[i]); + return err; } } // namespace qmc5883l diff --git a/esphome/components/qmc5883l/qmc5883l.h b/esphome/components/qmc5883l/qmc5883l.h index dd2008d453..3202e37780 100644 --- a/esphome/components/qmc5883l/qmc5883l.h +++ b/esphome/components/qmc5883l/qmc5883l.h @@ -55,7 +55,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice { NONE = 0, COMMUNICATION_FAILED, } error_code_; - bool read_byte_16_(uint8_t a_register, uint16_t *data); + i2c::ErrorCode read_bytes_16_le_(uint8_t a_register, uint16_t *data, uint8_t len = 1); HighFrequencyLoopRequester high_freq_; }; From 440080a753ffeed63616f3c3601acd911f239e56 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 9 Dec 2024 17:09:29 +1300 Subject: [PATCH 130/139] [display] Fix strftime overload ignoring alignment (#7937) --- esphome/components/display/display.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 1d996bd59b..f00c2936a8 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -1,6 +1,6 @@ #include "display.h" -#include "display_color_utils.h" #include +#include "display_color_utils.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" @@ -670,7 +670,7 @@ void Display::strftime(int x, int y, BaseFont *font, Color color, Color backgrou this->print(x, y, font, color, align, buffer, background); } void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) { - this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time); + this->strftime(x, y, font, color, COLOR_OFF, align, format, time); } void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) { this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time); From 132a096ae75c39e6d882b616b79bffd0cc50ea69 Mon Sep 17 00:00:00 2001 From: Yoonji Park Date: Mon, 9 Dec 2024 20:13:21 +0900 Subject: [PATCH 131/139] Add font anti-aliasing for grayscale display (#7934) --- esphome/components/font/font.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/components/font/font.cpp b/esphome/components/font/font.cpp index aeca0f5cc0..8c4cba34b3 100644 --- a/esphome/components/font/font.cpp +++ b/esphome/components/font/font.cpp @@ -133,9 +133,11 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo auto diff_r = (float) color.r - (float) background.r; auto diff_g = (float) color.g - (float) background.g; auto diff_b = (float) color.b - (float) background.b; + auto diff_w = (float) color.w - (float) background.w; auto b_r = (float) background.r; auto b_g = (float) background.g; - auto b_b = (float) background.g; + auto b_b = (float) background.b; + auto b_w = (float) background.w; for (int glyph_y = y_start + scan_y1; glyph_y != max_y; glyph_y++) { for (int glyph_x = x_at + scan_x1; glyph_x != max_x; glyph_x++) { uint8_t pixel = 0; @@ -153,8 +155,8 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo display->draw_pixel_at(glyph_x, glyph_y, color); } else if (pixel != 0) { auto on = (float) pixel / (float) bpp_max; - auto blended = - Color((uint8_t) (diff_r * on + b_r), (uint8_t) (diff_g * on + b_g), (uint8_t) (diff_b * on + b_b)); + auto blended = Color((uint8_t) (diff_r * on + b_r), (uint8_t) (diff_g * on + b_g), + (uint8_t) (diff_b * on + b_b), (uint8_t) (diff_w * on + b_w)); display->draw_pixel_at(glyph_x, glyph_y, blended); } } From 14eac3dbce15acf6857c68db1e931130ae6bd462 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 23:44:39 +0100 Subject: [PATCH 132/139] Bump pypa/gh-action-pypi-publish from 1.12.2 to 1.12.3 (#7941) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 096b00f0f1..a4e4305207 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: pip3 install build python3 -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.12.2 + uses: pypa/gh-action-pypi-publish@v1.12.3 deploy-docker: name: Build ESPHome ${{ matrix.platform }} From 437b236a4d5b7e2eb39a66b828b8dcfc1d51d162 Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Tue, 10 Dec 2024 01:38:45 +0100 Subject: [PATCH 133/139] [adc] Split files by platform (#7940) --- esphome/components/adc/adc_sensor.h | 15 +- esphome/components/adc/adc_sensor_common.cpp | 24 +++ .../{adc_sensor.cpp => adc_sensor_esp32.cpp} | 189 +----------------- esphome/components/adc/adc_sensor_esp8266.cpp | 58 ++++++ esphome/components/adc/adc_sensor_rp2040.cpp | 93 +++++++++ 5 files changed, 192 insertions(+), 187 deletions(-) create mode 100644 esphome/components/adc/adc_sensor_common.cpp rename esphome/components/adc/{adc_sensor.cpp => adc_sensor_esp32.cpp} (53%) create mode 100644 esphome/components/adc/adc_sensor_esp8266.cpp create mode 100644 esphome/components/adc/adc_sensor_rp2040.cpp diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index b697d6dd7e..7a3e1c8da7 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -3,13 +3,12 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/voltage_sampler/voltage_sampler.h" #include "esphome/core/component.h" -#include "esphome/core/defines.h" #include "esphome/core/hal.h" #ifdef USE_ESP32 #include #include "driver/adc.h" -#endif +#endif // USE_ESP32 namespace esphome { namespace adc { @@ -43,7 +42,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage this->channel1_ = ADC1_CHANNEL_MAX; } void set_autorange(bool autorange) { this->autorange_ = autorange; } -#endif +#endif // USE_ESP32 /// Update ADC values void update() override; @@ -59,11 +58,11 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #ifdef USE_ESP8266 std::string unique_id() override; -#endif +#endif // USE_ESP8266 #ifdef USE_RP2040 void set_is_temperature() { this->is_temperature_ = true; } -#endif +#endif // USE_RP2040 protected: InternalGPIOPin *pin_; @@ -72,7 +71,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage #ifdef USE_RP2040 bool is_temperature_{false}; -#endif +#endif // USE_RP2040 #ifdef USE_ESP32 adc_atten_t attenuation_{ADC_ATTEN_DB_0}; @@ -83,8 +82,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {}; #else esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {}; -#endif -#endif +#endif // ESP_IDF_VERSION_MAJOR +#endif // USE_ESP32 }; } // namespace adc diff --git a/esphome/components/adc/adc_sensor_common.cpp b/esphome/components/adc/adc_sensor_common.cpp new file mode 100644 index 0000000000..2dccd55fcd --- /dev/null +++ b/esphome/components/adc/adc_sensor_common.cpp @@ -0,0 +1,24 @@ +#include "adc_sensor.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace adc { + +static const char *const TAG = "adc.common"; + +void ADCSensor::update() { + float value_v = this->sample(); + ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v); + this->publish_state(value_v); +} + +void ADCSensor::set_sample_count(uint8_t sample_count) { + if (sample_count != 0) { + this->sample_count_ = sample_count; + } +} + +float ADCSensor::get_setup_priority() const { return setup_priority::DATA; } + +} // namespace adc +} // namespace esphome diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor_esp32.cpp similarity index 53% rename from esphome/components/adc/adc_sensor.cpp rename to esphome/components/adc/adc_sensor_esp32.cpp index 7257793016..24e3750091 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor_esp32.cpp @@ -1,30 +1,13 @@ +#ifdef USE_ESP32 + #include "adc_sensor.h" -#include "esphome/core/helpers.h" #include "esphome/core/log.h" -#ifdef USE_ESP8266 -#ifdef USE_ADC_SENSOR_VCC -#include -ADC_MODE(ADC_VCC) -#else -#include -#endif -#endif - -#ifdef USE_RP2040 -#ifdef CYW43_USES_VSYS_PIN -#include "pico/cyw43_arch.h" -#endif -#include -#endif - namespace esphome { namespace adc { -static const char *const TAG = "adc"; +static const char *const TAG = "adc.esp32"; -// 13-bit for S2, 12-bit for all other ESP32 variants -#ifdef USE_ESP32 static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast(ADC_WIDTH_MAX - 1); #ifndef SOC_ADC_RTC_MAX_BITWIDTH @@ -32,24 +15,15 @@ static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast> 1; // 2048 (12 bit) or 4096 (13 bit) -#endif +static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; +static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; -#ifdef USE_RP2040 -extern "C" -#endif - void - ADCSensor::setup() { +void ADCSensor::setup() { ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); -#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040) - this->pin_->setup(); -#endif -#ifdef USE_ESP32 if (this->channel1_ != ADC1_CHANNEL_MAX) { adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); if (!this->autorange_) { @@ -61,7 +35,6 @@ extern "C" } } - // load characteristics for each attenuation for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) { auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, @@ -79,31 +52,10 @@ extern "C" break; } } - -#endif // USE_ESP32 - -#ifdef USE_RP2040 - static bool initialized = false; - if (!initialized) { - adc_init(); - initialized = true; - } -#endif - - ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str()); } void ADCSensor::dump_config() { LOG_SENSOR("", "ADC Sensor", this); -#if defined(USE_ESP8266) || defined(USE_LIBRETINY) -#ifdef USE_ADC_SENSOR_VCC - ESP_LOGCONFIG(TAG, " Pin: VCC"); -#else - LOG_PIN(" Pin: ", this->pin_); -#endif -#endif // USE_ESP8266 || USE_LIBRETINY - -#ifdef USE_ESP32 LOG_PIN(" Pin: ", this->pin_); if (this->autorange_) { ESP_LOGCONFIG(TAG, " Attenuation: auto"); @@ -125,55 +77,10 @@ void ADCSensor::dump_config() { break; } } -#endif // USE_ESP32 - -#ifdef USE_RP2040 - if (this->is_temperature_) { - ESP_LOGCONFIG(TAG, " Pin: Temperature"); - } else { -#ifdef USE_ADC_SENSOR_VCC - ESP_LOGCONFIG(TAG, " Pin: VCC"); -#else - LOG_PIN(" Pin: ", this->pin_); -#endif // USE_ADC_SENSOR_VCC - } -#endif // USE_RP2040 ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); LOG_UPDATE_INTERVAL(this); } -float ADCSensor::get_setup_priority() const { return setup_priority::DATA; } -void ADCSensor::update() { - float value_v = this->sample(); - ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v); - this->publish_state(value_v); -} - -void ADCSensor::set_sample_count(uint8_t sample_count) { - if (sample_count != 0) { - this->sample_count_ = sample_count; - } -} - -#ifdef USE_ESP8266 -float ADCSensor::sample() { - uint32_t raw = 0; - for (uint8_t sample = 0; sample < this->sample_count_; sample++) { -#ifdef USE_ADC_SENSOR_VCC - raw += ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) -#else - raw += analogRead(this->pin_->get_pin()); // NOLINT -#endif - } - raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) - if (this->output_raw_) { - return raw; - } - return raw / 1024.0f; -} -#endif - -#ifdef USE_ESP32 float ADCSensor::sample() { if (!this->autorange_) { uint32_t sum = 0; @@ -240,93 +147,17 @@ float ADCSensor::sample() { uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); - // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) uint32_t c12 = std::min(raw12, ADC_HALF); uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF); uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF); uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF); - // max theoretical csum value is 4096*4 = 16384 uint32_t csum = c12 + c6 + c2 + c0; - // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32 uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0); return mv_scaled / (float) (csum * 1000U); } -#endif // USE_ESP32 - -#ifdef USE_RP2040 -float ADCSensor::sample() { - if (this->is_temperature_) { - adc_set_temp_sensor_enabled(true); - delay(1); - adc_select_input(4); - uint32_t raw = 0; - for (uint8_t sample = 0; sample < this->sample_count_; sample++) { - raw += adc_read(); - } - raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) - adc_set_temp_sensor_enabled(false); - if (this->output_raw_) { - return raw; - } - return raw * 3.3f / 4096.0f; - } else { - uint8_t pin = this->pin_->get_pin(); -#ifdef CYW43_USES_VSYS_PIN - if (pin == PICO_VSYS_PIN) { - // Measuring VSYS on Raspberry Pico W needs to be wrapped with - // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in - // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and - // VSYS ADC both share GPIO29 - cyw43_thread_enter(); - } -#endif // CYW43_USES_VSYS_PIN - - adc_gpio_init(pin); - adc_select_input(pin - 26); - - uint32_t raw = 0; - for (uint8_t sample = 0; sample < this->sample_count_; sample++) { - raw += adc_read(); - } - raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) - -#ifdef CYW43_USES_VSYS_PIN - if (pin == PICO_VSYS_PIN) { - cyw43_thread_exit(); - } -#endif // CYW43_USES_VSYS_PIN - - if (this->output_raw_) { - return raw; - } - float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0; - return raw * 3.3f / 4096.0f * coeff; - } -} -#endif - -#ifdef USE_LIBRETINY -float ADCSensor::sample() { - uint32_t raw = 0; - if (this->output_raw_) { - for (uint8_t sample = 0; sample < this->sample_count_; sample++) { - raw += analogRead(this->pin_->get_pin()); // NOLINT - } - raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) - return raw; - } - for (uint8_t sample = 0; sample < this->sample_count_; sample++) { - raw += analogReadVoltage(this->pin_->get_pin()); // NOLINT - } - raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) - return raw / 1000.0f; -} -#endif // USE_LIBRETINY - -#ifdef USE_ESP8266 -std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; } -#endif } // namespace adc } // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/adc/adc_sensor_esp8266.cpp b/esphome/components/adc/adc_sensor_esp8266.cpp new file mode 100644 index 0000000000..c9b6f8b652 --- /dev/null +++ b/esphome/components/adc/adc_sensor_esp8266.cpp @@ -0,0 +1,58 @@ +#ifdef USE_ESP8266 + +#include "adc_sensor.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +#ifdef USE_ADC_SENSOR_VCC +#include +ADC_MODE(ADC_VCC) +#else +#include +#endif // USE_ADC_SENSOR_VCC + +namespace esphome { +namespace adc { + +static const char *const TAG = "adc.esp8266"; + +void ADCSensor::setup() { + ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); +#ifndef USE_ADC_SENSOR_VCC + this->pin_->setup(); +#endif +} + +void ADCSensor::dump_config() { + LOG_SENSOR("", "ADC Sensor", this); +#ifdef USE_ADC_SENSOR_VCC + ESP_LOGCONFIG(TAG, " Pin: VCC"); +#else + LOG_PIN(" Pin: ", this->pin_); +#endif // USE_ADC_SENSOR_VCC + ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); + LOG_UPDATE_INTERVAL(this); +} + +float ADCSensor::sample() { + uint32_t raw = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { +#ifdef USE_ADC_SENSOR_VCC + raw += ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) +#else + raw += analogRead(this->pin_->get_pin()); // NOLINT +#endif // USE_ADC_SENSOR_VCC + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + if (this->output_raw_) { + return raw; + } + return raw / 1024.0f; +} + +std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; } + +} // namespace adc +} // namespace esphome + +#endif // USE_ESP8266 diff --git a/esphome/components/adc/adc_sensor_rp2040.cpp b/esphome/components/adc/adc_sensor_rp2040.cpp new file mode 100644 index 0000000000..520ff3bacc --- /dev/null +++ b/esphome/components/adc/adc_sensor_rp2040.cpp @@ -0,0 +1,93 @@ +#ifdef USE_RP2040 + +#include "adc_sensor.h" +#include "esphome/core/log.h" + +#ifdef CYW43_USES_VSYS_PIN +#include "pico/cyw43_arch.h" +#endif // CYW43_USES_VSYS_PIN +#include + +namespace esphome { +namespace adc { + +static const char *const TAG = "adc.rp2040"; + +void ADCSensor::setup() { + ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); + static bool initialized = false; + if (!initialized) { + adc_init(); + initialized = true; + } +} + +void ADCSensor::dump_config() { + LOG_SENSOR("", "ADC Sensor", this); + if (this->is_temperature_) { + ESP_LOGCONFIG(TAG, " Pin: Temperature"); + } else { +#ifdef USE_ADC_SENSOR_VCC + ESP_LOGCONFIG(TAG, " Pin: VCC"); +#else + LOG_PIN(" Pin: ", this->pin_); +#endif // USE_ADC_SENSOR_VCC + } + ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_); + LOG_UPDATE_INTERVAL(this); +} + +float ADCSensor::sample() { + if (this->is_temperature_) { + adc_set_temp_sensor_enabled(true); + delay(1); + adc_select_input(4); + uint32_t raw = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + raw += adc_read(); + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + adc_set_temp_sensor_enabled(false); + if (this->output_raw_) { + return raw; + } + return raw * 3.3f / 4096.0f; + } + + uint8_t pin = this->pin_->get_pin(); +#ifdef CYW43_USES_VSYS_PIN + if (pin == PICO_VSYS_PIN) { + // Measuring VSYS on Raspberry Pico W needs to be wrapped with + // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in + // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and + // VSYS ADC both share GPIO29 + cyw43_thread_enter(); + } +#endif // CYW43_USES_VSYS_PIN + + adc_gpio_init(pin); + adc_select_input(pin - 26); + + uint32_t raw = 0; + for (uint8_t sample = 0; sample < this->sample_count_; sample++) { + raw += adc_read(); + } + raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero) + +#ifdef CYW43_USES_VSYS_PIN + if (pin == PICO_VSYS_PIN) { + cyw43_thread_exit(); + } +#endif // CYW43_USES_VSYS_PIN + + if (this->output_raw_) { + return raw; + } + float coeff = pin == PICO_VSYS_PIN ? 3.0f : 1.0f; + return raw * 3.3f / 4096.0f * coeff; +} + +} // namespace adc +} // namespace esphome + +#endif // USE_RP2040 From 5a92e2466238fa2627e9a16a1e29ec8d41375c92 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:22:30 +1300 Subject: [PATCH 134/139] [const] Move ``CONF_TEMPERATURE_COMPENSATION`` to common const.py (#7943) --- esphome/components/sen5x/sensor.py | 11 +++++------ esphome/components/ufire_ec/sensor.py | 8 ++++---- esphome/const.py | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/esphome/components/sen5x/sensor.py b/esphome/components/sen5x/sensor.py index 67bd627f7f..a8a796853e 100644 --- a/esphome/components/sen5x/sensor.py +++ b/esphome/components/sen5x/sensor.py @@ -1,19 +1,19 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import i2c, sensor, sensirion_common from esphome import automation from esphome.automation import maybe_simple_id - +import esphome.codegen as cg +from esphome.components import i2c, sensirion_common, sensor +import esphome.config_validation as cv from esphome.const import ( CONF_HUMIDITY, CONF_ID, CONF_OFFSET, CONF_PM_1_0, - CONF_PM_10_0, CONF_PM_2_5, CONF_PM_4_0, + CONF_PM_10_0, CONF_STORE_BASELINE, CONF_TEMPERATURE, + CONF_TEMPERATURE_COMPENSATION, DEVICE_CLASS_AQI, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_PM1, @@ -51,7 +51,6 @@ CONF_LEARNING_TIME_OFFSET_HOURS = "learning_time_offset_hours" CONF_NORMALIZED_OFFSET_SLOPE = "normalized_offset_slope" CONF_NOX = "nox" CONF_STD_INITIAL = "std_initial" -CONF_TEMPERATURE_COMPENSATION = "temperature_compensation" CONF_TIME_CONSTANT = "time_constant" CONF_VOC = "voc" CONF_VOC_BASELINE = "voc_baseline" diff --git a/esphome/components/ufire_ec/sensor.py b/esphome/components/ufire_ec/sensor.py index 9602d0c2d0..944fdfdee9 100644 --- a/esphome/components/ufire_ec/sensor.py +++ b/esphome/components/ufire_ec/sensor.py @@ -1,11 +1,12 @@ -import esphome.codegen as cg from esphome import automation -import esphome.config_validation as cv +import esphome.codegen as cg from esphome.components import i2c, sensor +import esphome.config_validation as cv from esphome.const import ( - CONF_ID, CONF_EC, + CONF_ID, CONF_TEMPERATURE, + CONF_TEMPERATURE_COMPENSATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, @@ -18,7 +19,6 @@ DEPENDENCIES = ["i2c"] CONF_SOLUTION = "solution" CONF_TEMPERATURE_SENSOR = "temperature_sensor" -CONF_TEMPERATURE_COMPENSATION = "temperature_compensation" CONF_TEMPERATURE_COEFFICIENT = "temperature_coefficient" ufire_ec_ns = cg.esphome_ns.namespace("ufire_ec") diff --git a/esphome/const.py b/esphome/const.py index b9397aa1bd..4d3818cb23 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -864,6 +864,7 @@ CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC = "target_temperature_low_command_topi CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC = "target_temperature_low_state_topic" CONF_TARGET_TEMPERATURE_STATE_TOPIC = "target_temperature_state_topic" CONF_TEMPERATURE = "temperature" +CONF_TEMPERATURE_COMPENSATION = "temperature_compensation" CONF_TEMPERATURE_OFFSET = "temperature_offset" CONF_TEMPERATURE_SOURCE = "temperature_source" CONF_TEMPERATURE_STEP = "temperature_step" From 517f659da86e111e5c203564aa91f54471e3ceca Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:23:30 +1100 Subject: [PATCH 135/139] [lvgl] Fix image `mode` property (Bugfix) (#7938) --- esphome/components/lvgl/widgets/img.py | 2 +- tests/components/lvgl/lvgl-package.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/lvgl/widgets/img.py b/esphome/components/lvgl/widgets/img.py index 59b2c97c63..46077190d0 100644 --- a/esphome/components/lvgl/widgets/img.py +++ b/esphome/components/lvgl/widgets/img.py @@ -79,7 +79,7 @@ class ImgType(WidgetType): if CONF_ANTIALIAS in config: lv.img_set_antialias(w.obj, config[CONF_ANTIALIAS]) if mode := config.get(CONF_MODE): - lv.img_set_mode(w.obj, mode) + await w.set_property("size_mode", mode) img_spec = ImgType() diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 4b7e13db91..556ce105ee 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -451,6 +451,7 @@ lvgl: src: cat_image align: top_left y: "50" + mode: real - tileview: id: tileview_id scrollbar_mode: active @@ -647,6 +648,7 @@ lvgl: grid_cell_row_pos: 0 grid_cell_column_pos: 0 src: !lambda return dog_image; + mode: virtual on_click: then: - lvgl.tabview.select: From bb27eaaf1e58316c6124f2d16a1fba6b0a033141 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:25:29 +1100 Subject: [PATCH 136/139] [lvgl] Add `on_change` event (#7939) --- esphome/components/lvgl/defines.py | 1 + tests/components/lvgl/lvgl-package.yaml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 5371f110a6..02323f9655 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -168,6 +168,7 @@ LV_EVENT_MAP = { "READY": "READY", "CANCEL": "CANCEL", "ALL_EVENTS": "ALL", + "CHANGE": "VALUE_CHANGED", } LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 556ce105ee..b1b89adfe0 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -165,6 +165,11 @@ lvgl: - Nov - Dec selected_index: 1 + on_change: + then: + - logger.log: + format: "Roller changed = %d: %s" + args: [x, text.c_str()] on_value: then: - logger.log: From 444e162c92c3148a14493f66d3de256679a6eedf Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:39:00 +1300 Subject: [PATCH 137/139] Synchronise esp32 boards with platform version 51.03.07 (#7945) --- esphome/components/esp32/boards.py | 236 +++++++++++++++++++++++++++-- 1 file changed, 222 insertions(+), 14 deletions(-) diff --git a/esphome/components/esp32/boards.py b/esphome/components/esp32/boards.py index 02744ecb6f..81400eb9c3 100644 --- a/esphome/components/esp32/boards.py +++ b/esphome/components/esp32/boards.py @@ -1,4 +1,12 @@ -from .const import VARIANT_ESP32, VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3 +from .const import ( + VARIANT_ESP32, + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C6, + VARIANT_ESP32H2, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) ESP32_BASE_PINS = { "TX": 1, @@ -1344,6 +1352,26 @@ done | sort """ BOARDS = { + "4d_systems_esp32s3_gen4_r8n16": { + "name": "4D Systems GEN4-ESP32 16MB (ESP32S3-R8N16)", + "variant": VARIANT_ESP32S3, + }, + "adafruit_camera_esp32s3": { + "name": "Adafruit pyCamera S3", + "variant": VARIANT_ESP32S3, + }, + "adafruit_feather_esp32c6": { + "name": "Adafruit Feather ESP32-C6", + "variant": VARIANT_ESP32C6, + }, + "adafruit_feather_esp32s2": { + "name": "Adafruit Feather ESP32-S2", + "variant": VARIANT_ESP32S2, + }, + "adafruit_feather_esp32s2_reversetft": { + "name": "Adafruit Feather ESP32-S2 Reverse TFT", + "variant": VARIANT_ESP32S2, + }, "adafruit_feather_esp32s2_tft": { "name": "Adafruit Feather ESP32-S2 TFT", "variant": VARIANT_ESP32S2, @@ -1356,6 +1384,10 @@ BOARDS = { "name": "Adafruit Feather ESP32-S3 No PSRAM", "variant": VARIANT_ESP32S3, }, + "adafruit_feather_esp32s3_reversetft": { + "name": "Adafruit Feather ESP32-S3 Reverse TFT", + "variant": VARIANT_ESP32S3, + }, "adafruit_feather_esp32s3_tft": { "name": "Adafruit Feather ESP32-S3 TFT", "variant": VARIANT_ESP32S3, @@ -1376,10 +1408,18 @@ BOARDS = { "name": "Adafruit MagTag 2.9", "variant": VARIANT_ESP32S2, }, + "adafruit_matrixportal_esp32s3": { + "name": "Adafruit MatrixPortal ESP32-S3", + "variant": VARIANT_ESP32S3, + }, "adafruit_metro_esp32s2": { "name": "Adafruit Metro ESP32-S2", "variant": VARIANT_ESP32S2, }, + "adafruit_metro_esp32s3": { + "name": "Adafruit Metro ESP32-S3", + "variant": VARIANT_ESP32S3, + }, "adafruit_qtpy_esp32c3": { "name": "Adafruit QT Py ESP32-C3", "variant": VARIANT_ESP32C3, @@ -1392,10 +1432,18 @@ BOARDS = { "name": "Adafruit QT Py ESP32-S2", "variant": VARIANT_ESP32S2, }, + "adafruit_qtpy_esp32s3_n4r2": { + "name": "Adafruit QT Py ESP32-S3 (4M Flash 2M PSRAM)", + "variant": VARIANT_ESP32S3, + }, "adafruit_qtpy_esp32s3_nopsram": { "name": "Adafruit QT Py ESP32-S3 No PSRAM", "variant": VARIANT_ESP32S3, }, + "adafruit_qualia_s3_rgb666": { + "name": "Adafruit Qualia ESP32-S3 RGB666", + "variant": VARIANT_ESP32S3, + }, "airm2m_core_esp32c3": { "name": "AirM2M CORE ESP32C3", "variant": VARIANT_ESP32C3, @@ -1404,14 +1452,30 @@ BOARDS = { "name": "ALKS ESP32", "variant": VARIANT_ESP32, }, + "arduino_nano_esp32": { + "name": "Arduino Nano ESP32", + "variant": VARIANT_ESP32S3, + }, + "atd147_s3": { + "name": "ArtronShop ATD1.47-S3", + "variant": VARIANT_ESP32S3, + }, "atmegazero_esp32s2": { "name": "EspinalLab ATMegaZero ESP32-S2", "variant": VARIANT_ESP32S2, }, + "aventen_s3_sync": { + "name": "Aventen S3 Sync", + "variant": VARIANT_ESP32S3, + }, "az-delivery-devkit-v4": { "name": "AZ-Delivery ESP-32 Dev Kit C V4", "variant": VARIANT_ESP32, }, + "bee_data_logger": { + "name": "Smart Bee Data Logger", + "variant": VARIANT_ESP32S3, + }, "bee_motion_mini": { "name": "Smart Bee Motion Mini", "variant": VARIANT_ESP32C3, @@ -1436,14 +1500,6 @@ BOARDS = { "name": "BPI-Leaf-S3", "variant": VARIANT_ESP32S3, }, - "briki_abc_esp32": { - "name": "Briki ABC (MBC-WB) - ESP32", - "variant": VARIANT_ESP32, - }, - "briki_mbc-wb_esp32": { - "name": "Briki MBC-WB - ESP32", - "variant": VARIANT_ESP32, - }, "cnrs_aw2eth": { "name": "CNRS AW2ETH", "variant": VARIANT_ESP32, @@ -1496,18 +1552,38 @@ BOARDS = { "name": "DFRobot Beetle ESP32-C3", "variant": VARIANT_ESP32C3, }, + "dfrobot_firebeetle2_esp32e": { + "name": "DFRobot Firebeetle 2 ESP32-E", + "variant": VARIANT_ESP32, + }, "dfrobot_firebeetle2_esp32s3": { "name": "DFRobot Firebeetle 2 ESP32-S3", "variant": VARIANT_ESP32S3, }, + "dfrobot_romeo_esp32s3": { + "name": "DFRobot Romeo ESP32-S3", + "variant": VARIANT_ESP32S3, + }, "dpu_esp32": { "name": "TAMC DPU ESP32", "variant": VARIANT_ESP32, }, + "edgebox-esp-100": { + "name": "Seeed Studio Edgebox-ESP-100", + "variant": VARIANT_ESP32S3, + }, "esp320": { "name": "Electronic SweetPeas ESP320", "variant": VARIANT_ESP32, }, + "esp32-c2-devkitm-1": { + "name": "Espressif ESP32-C2-DevKitM-1", + "variant": VARIANT_ESP32C2, + }, + "esp32-c3-devkitc-02": { + "name": "Espressif ESP32-C3-DevKitC-02", + "variant": VARIANT_ESP32C3, + }, "esp32-c3-devkitm-1": { "name": "Espressif ESP32-C3-DevKitM-1", "variant": VARIANT_ESP32C3, @@ -1516,6 +1592,14 @@ BOARDS = { "name": "Ai-Thinker ESP-C3-M1-I-Kit", "variant": VARIANT_ESP32C3, }, + "esp32-c6-devkitc-1": { + "name": "Espressif ESP32-C6-DevKitC-1", + "variant": VARIANT_ESP32C6, + }, + "esp32-c6-devkitm-1": { + "name": "Espressif ESP32-C6-DevKitM-1", + "variant": VARIANT_ESP32C6, + }, "esp32cam": { "name": "AI Thinker ESP32-CAM", "variant": VARIANT_ESP32, @@ -1544,6 +1628,14 @@ BOARDS = { "name": "OLIMEX ESP32-GATEWAY", "variant": VARIANT_ESP32, }, + "esp32-h2-devkitm-1": { + "name": "Espressif ESP32-H2-DevKit", + "variant": VARIANT_ESP32H2, + }, + "esp32-pico-devkitm-2": { + "name": "Espressif ESP32-PICO-DevKitM-2", + "variant": VARIANT_ESP32, + }, "esp32-poe-iso": { "name": "OLIMEX ESP32-PoE-ISO", "variant": VARIANT_ESP32, @@ -1580,10 +1672,22 @@ BOARDS = { "name": "Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)", "variant": VARIANT_ESP32S3, }, - "esp32-s3-korvo-2": { - "name": "Espressif ESP32-S3-Korvo-2", + "esp32-s3-devkitm-1": { + "name": "Espressif ESP32-S3-DevKitM-1", "variant": VARIANT_ESP32S3, }, + "esp32s3_powerfeather": { + "name": "ESP32-S3 PowerFeather", + "variant": VARIANT_ESP32S3, + }, + "esp32s3usbotg": { + "name": "Espressif ESP32-S3-USB-OTG", + "variant": VARIANT_ESP32S3, + }, + "esp32-solo1": { + "name": "Espressif Generic ESP32-solo1 4M Flash", + "variant": VARIANT_ESP32, + }, "esp32thing": { "name": "SparkFun ESP32 Thing", "variant": VARIANT_ESP32, @@ -1652,9 +1756,9 @@ BOARDS = { "name": "Heltec WiFi Kit 32", "variant": VARIANT_ESP32, }, - "heltec_wifi_kit_32_v2": { - "name": "Heltec WiFi Kit 32 (V2)", - "variant": VARIANT_ESP32, + "heltec_wifi_kit_32_V3": { + "name": "Heltec WiFi Kit 32 (V3)", + "variant": VARIANT_ESP32S3, }, "heltec_wifi_lora_32": { "name": "Heltec WiFi LoRa 32", @@ -1664,6 +1768,10 @@ BOARDS = { "name": "Heltec WiFi LoRa 32 (V2)", "variant": VARIANT_ESP32, }, + "heltec_wifi_lora_32_V3": { + "name": "Heltec WiFi LoRa 32 (V3)", + "variant": VARIANT_ESP32S3, + }, "heltec_wireless_stick_lite": { "name": "Heltec Wireless Stick Lite", "variant": VARIANT_ESP32, @@ -1708,6 +1816,14 @@ BOARDS = { "name": "oddWires IoT-Bus Proteus", "variant": VARIANT_ESP32, }, + "ioxesp32": { + "name": "ArtronShop IOXESP32", + "variant": VARIANT_ESP32, + }, + "ioxesp32ps": { + "name": "ArtronShop IOXESP32PS", + "variant": VARIANT_ESP32, + }, "kb32-ft": { "name": "MakerAsia KB32-FT", "variant": VARIANT_ESP32, @@ -1720,10 +1836,26 @@ BOARDS = { "name": "Labplus mPython", "variant": VARIANT_ESP32, }, + "lilka_v2": { + "name": "Lilka v2", + "variant": VARIANT_ESP32S3, + }, + "lilygo-t-display": { + "name": "LilyGo T-Display", + "variant": VARIANT_ESP32, + }, + "lilygo-t-display-s3": { + "name": "LilyGo T-Display-S3", + "variant": VARIANT_ESP32S3, + }, "lionbit": { "name": "Lion:Bit Dev Board", "variant": VARIANT_ESP32, }, + "lionbits3": { + "name": "Lion:Bit S3 STEM Dev Board", + "variant": VARIANT_ESP32S3, + }, "lolin32_lite": { "name": "WEMOS LOLIN32 Lite", "variant": VARIANT_ESP32, @@ -1752,10 +1884,18 @@ BOARDS = { "name": "WEMOS LOLIN S2 PICO", "variant": VARIANT_ESP32S2, }, + "lolin_s3_mini": { + "name": "WEMOS LOLIN S3 Mini", + "variant": VARIANT_ESP32S3, + }, "lolin_s3": { "name": "WEMOS LOLIN S3", "variant": VARIANT_ESP32S3, }, + "lolin_s3_pro": { + "name": "WEMOS LOLIN S3 PRO", + "variant": VARIANT_ESP32S3, + }, "lopy4": { "name": "Pycom LoPy4", "variant": VARIANT_ESP32, @@ -1768,10 +1908,18 @@ BOARDS = { "name": "M5Stack-ATOM", "variant": VARIANT_ESP32, }, + "m5stack-atoms3": { + "name": "M5Stack AtomS3", + "variant": VARIANT_ESP32S3, + }, "m5stack-core2": { "name": "M5Stack Core2", "variant": VARIANT_ESP32, }, + "m5stack-core-esp32-16M": { + "name": "M5Stack Core ESP32 16M", + "variant": VARIANT_ESP32, + }, "m5stack-core-esp32": { "name": "M5Stack Core ESP32", "variant": VARIANT_ESP32, @@ -1780,6 +1928,10 @@ BOARDS = { "name": "M5Stack-Core Ink", "variant": VARIANT_ESP32, }, + "m5stack-cores3": { + "name": "M5Stack CoreS3", + "variant": VARIANT_ESP32S3, + }, "m5stack-fire": { "name": "M5Stack FIRE", "variant": VARIANT_ESP32, @@ -1788,6 +1940,14 @@ BOARDS = { "name": "M5Stack GREY ESP32", "variant": VARIANT_ESP32, }, + "m5stack_paper": { + "name": "M5Stack Paper", + "variant": VARIANT_ESP32, + }, + "m5stack-stamps3": { + "name": "M5Stack StampS3", + "variant": VARIANT_ESP32S3, + }, "m5stack-station": { "name": "M5Stack Station", "variant": VARIANT_ESP32, @@ -1796,6 +1956,10 @@ BOARDS = { "name": "M5Stack Timer CAM", "variant": VARIANT_ESP32, }, + "m5stamp-pico": { + "name": "M5Stamp-Pico", + "variant": VARIANT_ESP32, + }, "m5stick-c": { "name": "M5Stick-C", "variant": VARIANT_ESP32, @@ -1832,10 +1996,26 @@ BOARDS = { "name": "Deparment of Alchemy MiniMain ESP32-S2", "variant": VARIANT_ESP32S2, }, + "motorgo_mini_1": { + "name": "MotorGo Mini 1 (ESP32-S3)", + "variant": VARIANT_ESP32S3, + }, + "namino_arancio": { + "name": "Namino Arancio", + "variant": VARIANT_ESP32S3, + }, + "namino_rosso": { + "name": "Namino Rosso", + "variant": VARIANT_ESP32S3, + }, "nano32": { "name": "MakerAsia Nano32", "variant": VARIANT_ESP32, }, + "nebulas3": { + "name": "Kinetic Dynamics Nebula S3", + "variant": VARIANT_ESP32S3, + }, "nina_w10": { "name": "u-blox NINA-W10 series", "variant": VARIANT_ESP32, @@ -1896,10 +2076,22 @@ BOARDS = { "name": "Munich Labs RedPill ESP32-S3", "variant": VARIANT_ESP32S3, }, + "roboheart_hercules": { + "name": "RoboHeart Hercules", + "variant": VARIANT_ESP32, + }, "seeed_xiao_esp32c3": { "name": "Seeed Studio XIAO ESP32C3", "variant": VARIANT_ESP32C3, }, + "seeed_xiao_esp32s3": { + "name": "Seeed Studio XIAO ESP32S3", + "variant": VARIANT_ESP32S3, + }, + "sensebox_mcu_esp32s2": { + "name": "senseBox MCU-S2 ESP32-S2", + "variant": VARIANT_ESP32S2, + }, "sensesiot_weizen": { "name": "LOGISENSES Senses Weizen", "variant": VARIANT_ESP32, @@ -1912,6 +2104,10 @@ BOARDS = { "name": "S.ODI Ultra v1", "variant": VARIANT_ESP32, }, + "sparkfun_esp32c6_thing_plus": { + "name": "Sparkfun ESP32-C6 Thing Plus", + "variant": VARIANT_ESP32C6, + }, "sparkfun_esp32_iot_redboard": { "name": "SparkFun ESP32 IoT RedBoard", "variant": VARIANT_ESP32, @@ -2004,6 +2200,10 @@ BOARDS = { "name": "Unexpected Maker FeatherS3", "variant": VARIANT_ESP32S3, }, + "um_nanos3": { + "name": "Unexpected Maker NanoS3", + "variant": VARIANT_ESP32S3, + }, "um_pros3": { "name": "Unexpected Maker PROS3", "variant": VARIANT_ESP32S3, @@ -2040,6 +2240,14 @@ BOARDS = { "name": "uPesy ESP32 Wrover DevKit", "variant": VARIANT_ESP32, }, + "valtrack_v4_mfw_esp32_c3": { + "name": "Valetron Systems VALTRACK-V4MVF", + "variant": VARIANT_ESP32C3, + }, + "valtrack_v4_vts_esp32_c3": { + "name": "Valetron Systems VALTRACK-V4VTS", + "variant": VARIANT_ESP32C3, + }, "vintlabs-devkit-v1": { "name": "VintLabs ESP32 Devkit", "variant": VARIANT_ESP32, From 7aa54b6879ceb7bdec3d8b7d6ce8d143a394c1ff Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:24:06 +1300 Subject: [PATCH 138/139] [i2c] Use correct macro to determine number of i2c peripherals for idf (#7947) --- esphome/components/i2c/i2c_bus_esp_idf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index 3a9c229778..ac3a754024 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -17,14 +17,14 @@ void IDFI2CBus::setup() { ESP_LOGCONFIG(TAG, "Setting up I2C bus..."); static i2c_port_t next_port = I2C_NUM_0; port_ = next_port; -#if I2C_NUM_MAX > 1 +#if SOC_I2C_NUM > 1 next_port = (next_port == I2C_NUM_0) ? I2C_NUM_1 : I2C_NUM_MAX; #else next_port = I2C_NUM_MAX; #endif if (port_ == I2C_NUM_MAX) { - ESP_LOGE(TAG, "Too many I2C buses configured"); + ESP_LOGE(TAG, "Too many I2C buses configured. Max %u supported.", SOC_I2C_NUM); this->mark_failed(); return; } From 5dcaf1241f12df31582546488fe70df78add11e7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:55:29 +1300 Subject: [PATCH 139/139] Bump version to 2024.12.0b1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4d3818cb23..4d8d550fd1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.12.0-dev" +__version__ = "2024.12.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = (