From c69cdec0521147ec3d1a594c9c5121cab9710c33 Mon Sep 17 00:00:00 2001
From: Keith Burzinski <kbx81x@gmail.com>
Date: Tue, 30 Apr 2024 23:49:20 -0500
Subject: [PATCH 1/7] Extend MQTT tests (#6648)

---
 esphome/components/mqtt/__init__.py          |   7 +-
 tests/components/mqtt/common.yaml            | 428 +++++++++++++++++++
 tests/components/mqtt/test.bk72xx.yaml       |   2 +
 tests/components/mqtt/test.esp32-c3-idf.yaml |  18 +-
 tests/components/mqtt/test.esp32-c3.yaml     |  17 +-
 tests/components/mqtt/test.esp32-idf.yaml    |  18 +-
 tests/components/mqtt/test.esp32.yaml        |  17 +-
 tests/components/mqtt/test.esp8266.yaml      |  17 +-
 8 files changed, 446 insertions(+), 78 deletions(-)
 create mode 100644 tests/components/mqtt/common.yaml
 create mode 100644 tests/components/mqtt/test.bk72xx.yaml

diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py
index 064362c619..31cbb2cf97 100644
--- a/esphome/components/mqtt/__init__.py
+++ b/esphome/components/mqtt/__init__.py
@@ -54,7 +54,12 @@ from esphome.components.esp32 import add_idf_sdkconfig_option
 
 DEPENDENCIES = ["network"]
 
-AUTO_LOAD = ["json"]
+
+def AUTO_LOAD():
+    if CORE.is_esp8266 or CORE.is_libretiny:
+        return ["async_tcp", "json"]
+    return ["json"]
+
 
 CONF_IDF_SEND_ASYNC = "idf_send_async"
 CONF_SKIP_CERT_CN_CHECK = "skip_cert_cn_check"
diff --git a/tests/components/mqtt/common.yaml b/tests/components/mqtt/common.yaml
new file mode 100644
index 0000000000..a2a751df63
--- /dev/null
+++ b/tests/components/mqtt/common.yaml
@@ -0,0 +1,428 @@
+wifi:
+  ssid: MySSID
+  password: password1
+
+time:
+  - platform: sntp
+
+mqtt:
+  broker: "192.168.178.84"
+  port: 1883
+  username: debug
+  password: debug
+  client_id: someclient
+  use_abbreviations: false
+  discovery: true
+  discovery_retain: false
+  discovery_prefix: discovery
+  discovery_unique_id_generator: legacy
+  topic_prefix: helloworld
+  log_topic:
+    topic: helloworld/hi
+    level: INFO
+  birth_message:
+  will_message:
+  shutdown_message:
+    topic: topic/to/send/to
+    payload: hi
+    qos: 2
+    retain: true
+  keepalive: 60s
+  reboot_timeout: 60s
+  on_message:
+    - topic: my/custom/topic
+      qos: 0
+      then:
+        - lambda: >-
+            ESP_LOGD("main", "Got message %s", x.c_str());
+    - topic: bedroom/ota_mode
+      then:
+        - logger.log: Got bedroom/ota_mode
+    - topic: livingroom/ota_mode
+      then:
+        - logger.log: Got livingroom/ota_mode
+  on_json_message:
+    topic: the/topic
+    then:
+      - if:
+          condition:
+            - wifi.connected:
+            - mqtt.connected:
+          then:
+            - logger.log: on_json_message
+  on_connect:
+    - mqtt.publish:
+        topic: some/topic
+        payload: Hello
+  on_disconnect:
+    - mqtt.publish:
+        topic: some/topic
+        payload: Good-bye
+
+binary_sensor:
+  - platform: template
+    id: some_binary_sensor
+    name: Garage Door Open
+    state_topic: some/topic/binary_sensor
+    qos: 2
+    lambda: |-
+      if (id(template_sens).state > 30) {
+        // Garage Door is open.
+        return true;
+      } else {
+        // Garage Door is closed.
+        return false;
+      }
+    on_state:
+      - mqtt.publish:
+          topic: some/topic/binary_sensor
+          payload: Hello
+          qos: 2
+          retain: true
+
+button:
+  - platform: template
+    name: "Template Button"
+    state_topic: some/topic/button
+    qos: 2
+    on_press:
+      - mqtt.publish:
+          topic: some/topic/button
+          payload: Hello
+          qos: 2
+          retain: true
+
+climate:
+  - platform: thermostat
+    name: Test Thermostat
+    sensor: template_sens
+    humidity_sensor: template_sens
+    action_state_topic: some/topicaction_state
+    current_temperature_state_topic: some/topiccurrent_temperature_state
+    current_humidity_state_topic: some/topiccurrent_humidity_state
+    fan_mode_state_topic: some/topicfan_mode_state
+    fan_mode_command_topic: some/topicfan_mode_command
+    mode_state_topic: some/topicmode_state
+    mode_command_topic: some/topicmode_command
+    preset_state_topic: some/topicpreset_state
+    preset_command_topic: some/topicpreset_command
+    swing_mode_state_topic: some/topicswing_mode_state
+    swing_mode_command_topic: some/topicswing_mode_command
+    target_temperature_state_topic: some/topictarget_temperature_state
+    target_temperature_command_topic: some/topictarget_temperature_command
+    target_temperature_high_state_topic: some/topictarget_temperature_high_state
+    target_temperature_high_command_topic: some/topictarget_temperature_high_command
+    target_temperature_low_state_topic: some/topictarget_temperature_low_state
+    target_temperature_low_command_topic: some/topictarget_temperature_low_command
+    target_humidity_state_topic: some/topictarget_humidity_state
+    target_humidity_command_topic: some/topictarget_humidity_command
+    preset:
+      - name: Default Preset
+        default_target_temperature_low: 18°C
+        default_target_temperature_high: 24°C
+      - name: Away
+        default_target_temperature_low: 16°C
+        default_target_temperature_high: 20°C
+    idle_action:
+      - logger.log: idle_action
+    cool_action:
+      - logger.log: cool_action
+    supplemental_cooling_action:
+      - logger.log: supplemental_cooling_action
+    heat_action:
+      - logger.log: heat_action
+    supplemental_heating_action:
+      - logger.log: supplemental_heating_action
+    dry_action:
+      - logger.log: dry_action
+    fan_only_action:
+      - logger.log: fan_only_action
+    auto_mode:
+      - logger.log: auto_mode
+    off_mode:
+      - logger.log: off_mode
+    heat_mode:
+      - logger.log: heat_mode
+    cool_mode:
+      - logger.log: cool_mode
+    dry_mode:
+      - logger.log: dry_mode
+    fan_only_mode:
+      - logger.log: fan_only_mode
+    fan_mode_auto_action:
+      - logger.log: fan_mode_auto_action
+    fan_mode_on_action:
+      - logger.log: fan_mode_on_action
+    fan_mode_off_action:
+      - logger.log: fan_mode_off_action
+    fan_mode_low_action:
+      - logger.log: fan_mode_low_action
+    fan_mode_medium_action:
+      - logger.log: fan_mode_medium_action
+    fan_mode_high_action:
+      - logger.log: fan_mode_high_action
+    fan_mode_middle_action:
+      - logger.log: fan_mode_middle_action
+    fan_mode_focus_action:
+      - logger.log: fan_mode_focus_action
+    fan_mode_diffuse_action:
+      - logger.log: fan_mode_diffuse_action
+    fan_mode_quiet_action:
+      - logger.log: fan_mode_quiet_action
+    swing_off_action:
+      - logger.log: swing_off_action
+    swing_horizontal_action:
+      - logger.log: swing_horizontal_action
+    swing_vertical_action:
+      - logger.log: swing_vertical_action
+    swing_both_action:
+      - logger.log: swing_both_action
+    startup_delay: true
+    supplemental_cooling_delta: 2.0
+    cool_deadband: 0.5
+    cool_overrun: 0.5
+    min_cooling_off_time: 300s
+    min_cooling_run_time: 300s
+    max_cooling_run_time: 600s
+    supplemental_heating_delta: 2.0
+    heat_deadband: 0.5
+    heat_overrun: 0.5
+    min_heating_off_time: 300s
+    min_heating_run_time: 300s
+    max_heating_run_time: 600s
+    min_fanning_off_time: 30s
+    min_fanning_run_time: 30s
+    min_fan_mode_switching_time: 15s
+    min_idle_time: 30s
+    set_point_minimum_differential: 0.5
+    fan_only_action_uses_fan_mode_timer: true
+    fan_only_cooling: true
+    fan_with_cooling: true
+    fan_with_heating: true
+
+cover:
+  - platform: template
+    name: Template Cover
+    state_topic: some/topic/cover
+    qos: 2
+    lambda: |-
+      if (id(some_binary_sensor).state) {
+        return COVER_OPEN;
+      } else {
+        return COVER_CLOSED;
+      }
+    open_action:
+      - logger.log: open_action
+    close_action:
+      - logger.log: close_action
+    stop_action:
+      - logger.log: stop_action
+    optimistic: true
+
+datetime:
+  - platform: template
+    name: Date
+    id: test_date
+    type: date
+    state_topic: some/topic/date
+    qos: 2
+    set_action:
+      - logger.log: "set_value"
+    on_value:
+      - logger.log:
+          format: "Date: %04d-%02d-%02d"
+          args:
+            - x.year
+            - x.month
+            - x.day_of_month
+  - platform: template
+    name: Time
+    id: test_time
+    type: time
+    state_topic: some/topic/time
+    qos: 2
+    set_action:
+      - logger.log: "set_value"
+    on_value:
+      - logger.log:
+          format: "Time: %02d:%02d:%02d"
+          args:
+            - x.hour
+            - x.minute
+            - x.second
+  - platform: template
+    name: DateTime
+    id: test_datetime
+    type: datetime
+    state_topic: some/topic/datetime
+    qos: 2
+    set_action:
+      - logger.log: set_value
+    on_value:
+      - logger.log:
+          format: "DateTime: %04d-%02d-%02d %02d:%02d:%02d"
+          args:
+            - x.year
+            - x.month
+            - x.day_of_month
+            - x.hour
+            - x.minute
+            - x.second
+
+event:
+  - platform: template
+    name: Template Event
+    state_topic: some/topic/event
+    qos: 2
+    event_types:
+      - "custom_event_1"
+      - "custom_event_2"
+
+fan:
+  - platform: template
+    name: Template Fan
+    state_topic: some/topic/fan
+    qos: 2
+    on_state:
+      - logger.log: on_state
+    on_speed_set:
+      - logger.log: on_speed_set
+
+light:
+  - platform: binary
+    name: Desk Lamp
+    output: light_output
+    state_topic: some/topic/light
+    qos: 2
+
+output:
+  - id: light_output
+    platform: gpio
+    pin: 0
+
+lock:
+  - platform: template
+    name: "Template Lock"
+    state_topic: some/topic/lock
+    qos: 2
+    lambda: |-
+      if (id(some_binary_sensor).state) {
+        return LOCK_STATE_LOCKED;
+      } else {
+        return LOCK_STATE_UNLOCKED;
+      }
+    lock_action:
+      - logger.log: lock_action
+    unlock_action:
+      - logger.log: unlock_action
+    open_action:
+      - logger.log: open_action
+
+number:
+  - platform: template
+    name: "Template number"
+    state_topic: some/topic/number
+    qos: 2
+    optimistic: true
+    min_value: 0
+    max_value: 100
+    step: 1
+
+select:
+  - platform: template
+    name: "Template select"
+    state_topic: some/topic/select
+    qos: 2
+    optimistic: true
+    options:
+      - one
+      - two
+      - three
+    initial_option: two
+
+sensor:
+  - platform: template
+    name: Template Sensor
+    id: template_sens
+    lambda: |-
+      if (id(some_binary_sensor).state) {
+        return 42.0;
+      } else {
+        return 0.0;
+      }
+    update_interval: 60s
+    on_value:
+      - mqtt.publish:
+          topic: some/topic/sensor
+          payload: Hello
+          qos: 2
+          retain: true
+  - platform: mqtt_subscribe
+    name: MQTT Subscribe Sensor
+    topic: mqtt/topic
+    id: the_sensor
+    qos: 2
+    on_value:
+      - mqtt.publish_json:
+          topic: the/topic
+          payload: |-
+            root["key"] = id(template_sens).state;
+            root["greeting"] = "Hello World";
+
+switch:
+  - platform: template
+    name: Template Switch
+    state_topic: some/topic/switch
+    qos: 2
+    lambda: |-
+      if (id(some_binary_sensor).state) {
+        return true;
+      } else {
+        return false;
+      }
+    turn_on_action:
+      - logger.log: turn_on_action
+    turn_off_action:
+      - logger.log: turn_off_action
+
+text_sensor:
+  - platform: template
+    name: Template Text Sensor
+    id: tts_text
+    state_topic: some/topic/text_sensor
+    qos: 2
+  - platform: mqtt_subscribe
+    name: MQTT Subscribe Text
+    topic: some/topic/text_sensor
+    qos: 2
+    on_value:
+      - text_sensor.template.publish:
+          id: tts_text
+          state: Hello World
+      - text_sensor.template.publish:
+          id: tts_text
+          state: |-
+            return "Hello World2";
+
+text:
+  - platform: template
+    name: Template Text
+    optimistic: true
+    min_length: 0
+    max_length: 100
+    mode: text
+    state_topic: some/topic/text
+    qos: 2
+
+valve:
+  - platform: template
+    name: Template Valve
+    state_topic: some/topic/valve
+    qos: 2
+    optimistic: true
+    lambda: |-
+      if (id(some_binary_sensor).state) {
+        return VALVE_OPEN;
+      } else {
+        return VALVE_CLOSED;
+      }
diff --git a/tests/components/mqtt/test.bk72xx.yaml b/tests/components/mqtt/test.bk72xx.yaml
new file mode 100644
index 0000000000..25cb37a0b4
--- /dev/null
+++ b/tests/components/mqtt/test.bk72xx.yaml
@@ -0,0 +1,2 @@
+packages:
+  common: !include common.yaml
diff --git a/tests/components/mqtt/test.esp32-c3-idf.yaml b/tests/components/mqtt/test.esp32-c3-idf.yaml
index 7702ed5610..25cb37a0b4 100644
--- a/tests/components/mqtt/test.esp32-c3-idf.yaml
+++ b/tests/components/mqtt/test.esp32-c3-idf.yaml
@@ -1,16 +1,2 @@
-wifi:
-  ssid: MySSID
-  password: password1
-
-mqtt:
-  broker: test.mosquitto.org
-  port: 1883
-  discovery: true
-  discovery_prefix: homeassistant
-  idf_send_async: false
-  log_topic:
-  on_message:
-    topic: testing/sensor/testing_sensor/state
-    qos: 0
-    then:
-      - logger.log: Mqtt Test
+packages:
+  common: !include common.yaml
diff --git a/tests/components/mqtt/test.esp32-c3.yaml b/tests/components/mqtt/test.esp32-c3.yaml
index 692d504d6d..25cb37a0b4 100644
--- a/tests/components/mqtt/test.esp32-c3.yaml
+++ b/tests/components/mqtt/test.esp32-c3.yaml
@@ -1,15 +1,2 @@
-wifi:
-  ssid: MySSID
-  password: password1
-
-mqtt:
-  broker: test.mosquitto.org
-  port: 1883
-  discovery: true
-  discovery_prefix: homeassistant
-  log_topic:
-  on_message:
-    topic: testing/sensor/testing_sensor/state
-    qos: 0
-    then:
-      - logger.log: Mqtt Test
+packages:
+  common: !include common.yaml
diff --git a/tests/components/mqtt/test.esp32-idf.yaml b/tests/components/mqtt/test.esp32-idf.yaml
index 7702ed5610..25cb37a0b4 100644
--- a/tests/components/mqtt/test.esp32-idf.yaml
+++ b/tests/components/mqtt/test.esp32-idf.yaml
@@ -1,16 +1,2 @@
-wifi:
-  ssid: MySSID
-  password: password1
-
-mqtt:
-  broker: test.mosquitto.org
-  port: 1883
-  discovery: true
-  discovery_prefix: homeassistant
-  idf_send_async: false
-  log_topic:
-  on_message:
-    topic: testing/sensor/testing_sensor/state
-    qos: 0
-    then:
-      - logger.log: Mqtt Test
+packages:
+  common: !include common.yaml
diff --git a/tests/components/mqtt/test.esp32.yaml b/tests/components/mqtt/test.esp32.yaml
index 692d504d6d..25cb37a0b4 100644
--- a/tests/components/mqtt/test.esp32.yaml
+++ b/tests/components/mqtt/test.esp32.yaml
@@ -1,15 +1,2 @@
-wifi:
-  ssid: MySSID
-  password: password1
-
-mqtt:
-  broker: test.mosquitto.org
-  port: 1883
-  discovery: true
-  discovery_prefix: homeassistant
-  log_topic:
-  on_message:
-    topic: testing/sensor/testing_sensor/state
-    qos: 0
-    then:
-      - logger.log: Mqtt Test
+packages:
+  common: !include common.yaml
diff --git a/tests/components/mqtt/test.esp8266.yaml b/tests/components/mqtt/test.esp8266.yaml
index 692d504d6d..25cb37a0b4 100644
--- a/tests/components/mqtt/test.esp8266.yaml
+++ b/tests/components/mqtt/test.esp8266.yaml
@@ -1,15 +1,2 @@
-wifi:
-  ssid: MySSID
-  password: password1
-
-mqtt:
-  broker: test.mosquitto.org
-  port: 1883
-  discovery: true
-  discovery_prefix: homeassistant
-  log_topic:
-  on_message:
-    topic: testing/sensor/testing_sensor/state
-    qos: 0
-    then:
-      - logger.log: Mqtt Test
+packages:
+  common: !include common.yaml

From 5ddad2647605b28da208029e7959aa12701904bd Mon Sep 17 00:00:00 2001
From: Keith Burzinski <kbx81x@gmail.com>
Date: Wed, 1 May 2024 14:17:11 -0500
Subject: [PATCH 2/7] Extend and consolidate `script` tests (#6663)

---
 tests/components/script/common.yaml           | 55 +++++++++++++++++++
 tests/components/script/test.bk72xx.yaml      |  1 +
 .../components/script/test.esp32-c3-idf.yaml  | 27 +--------
 tests/components/script/test.esp32-c3.yaml    | 27 +--------
 tests/components/script/test.esp32-idf.yaml   | 27 +--------
 tests/components/script/test.esp32.yaml       | 27 +--------
 tests/components/script/test.esp8266.yaml     | 27 +--------
 tests/components/script/test.rp2040.yaml      | 27 +--------
 8 files changed, 62 insertions(+), 156 deletions(-)
 create mode 100644 tests/components/script/common.yaml
 create mode 100644 tests/components/script/test.bk72xx.yaml

diff --git a/tests/components/script/common.yaml b/tests/components/script/common.yaml
new file mode 100644
index 0000000000..bfd5d0e7ff
--- /dev/null
+++ b/tests/components/script/common.yaml
@@ -0,0 +1,55 @@
+esphome:
+  on_boot:
+    then:
+      - script.execute: my_script
+      - script.execute:
+          id: my_script_with_params
+          prefix: "Test"
+          param2: 0
+          param3: true
+      - script.wait: my_script
+      - script.stop: my_script
+      - if:
+          condition:
+            - script.is_running: my_script
+          then:
+            - logger.log: my_script is running
+
+script:
+  - id: my_script
+    mode: single
+    then:
+      - lambda: 'ESP_LOGD("main", "Hello World!");'
+  - id: my_script_queued
+    mode: queued
+    max_runs: 2
+    then:
+      - lambda: 'ESP_LOGD("main", "Hello World!");'
+  - id: my_script_parallel
+    mode: parallel
+    max_runs: 2
+    then:
+      - lambda: 'ESP_LOGD("main", "Hello World!");'
+  - id: my_script_restart
+    mode: restart
+    then:
+      - lambda: 'ESP_LOGD("main", "Hello World!");'
+  - id: my_script_with_params
+    parameters:
+      prefix: string
+      param2: uint8_t
+      param3: bool
+    then:
+      - lambda: 'ESP_LOGD(prefix.c_str(), "Hello World! %u %u", param2, param3);'
+      - if:
+          condition:
+            for:
+              time: !lambda "return param2;"
+              condition:
+                script.is_running: my_script
+          then:
+            - lambda: 'ESP_LOGD("main", "API has stayed connected for at least %u minutes", param2);'
+      - repeat:
+          count: 5
+          then:
+            - logger.log: looping!
diff --git a/tests/components/script/test.bk72xx.yaml b/tests/components/script/test.bk72xx.yaml
new file mode 100644
index 0000000000..dade44d145
--- /dev/null
+++ b/tests/components/script/test.bk72xx.yaml
@@ -0,0 +1 @@
+<<: !include common.yaml
diff --git a/tests/components/script/test.esp32-c3-idf.yaml b/tests/components/script/test.esp32-c3-idf.yaml
index 3872c690ff..dade44d145 100644
--- a/tests/components/script/test.esp32-c3-idf.yaml
+++ b/tests/components/script/test.esp32-c3-idf.yaml
@@ -1,26 +1 @@
-script:
-  - id: my_script
-    mode: single
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_queued
-    mode: queued
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_parallel
-    mode: parallel
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_restart
-    mode: restart
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_with_params
-    parameters:
-      prefix: string
-      param2: int
-      param3: bool
-    then:
-      - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());'
+<<: !include common.yaml
diff --git a/tests/components/script/test.esp32-c3.yaml b/tests/components/script/test.esp32-c3.yaml
index 3872c690ff..dade44d145 100644
--- a/tests/components/script/test.esp32-c3.yaml
+++ b/tests/components/script/test.esp32-c3.yaml
@@ -1,26 +1 @@
-script:
-  - id: my_script
-    mode: single
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_queued
-    mode: queued
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_parallel
-    mode: parallel
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_restart
-    mode: restart
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_with_params
-    parameters:
-      prefix: string
-      param2: int
-      param3: bool
-    then:
-      - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());'
+<<: !include common.yaml
diff --git a/tests/components/script/test.esp32-idf.yaml b/tests/components/script/test.esp32-idf.yaml
index 3872c690ff..dade44d145 100644
--- a/tests/components/script/test.esp32-idf.yaml
+++ b/tests/components/script/test.esp32-idf.yaml
@@ -1,26 +1 @@
-script:
-  - id: my_script
-    mode: single
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_queued
-    mode: queued
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_parallel
-    mode: parallel
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_restart
-    mode: restart
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_with_params
-    parameters:
-      prefix: string
-      param2: int
-      param3: bool
-    then:
-      - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());'
+<<: !include common.yaml
diff --git a/tests/components/script/test.esp32.yaml b/tests/components/script/test.esp32.yaml
index 3872c690ff..dade44d145 100644
--- a/tests/components/script/test.esp32.yaml
+++ b/tests/components/script/test.esp32.yaml
@@ -1,26 +1 @@
-script:
-  - id: my_script
-    mode: single
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_queued
-    mode: queued
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_parallel
-    mode: parallel
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_restart
-    mode: restart
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_with_params
-    parameters:
-      prefix: string
-      param2: int
-      param3: bool
-    then:
-      - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());'
+<<: !include common.yaml
diff --git a/tests/components/script/test.esp8266.yaml b/tests/components/script/test.esp8266.yaml
index ce0e40e7ee..dade44d145 100644
--- a/tests/components/script/test.esp8266.yaml
+++ b/tests/components/script/test.esp8266.yaml
@@ -1,26 +1 @@
-script:
-  - id: my_script
-    mode: single
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_queued
-    mode: queued
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_parallel
-    mode: parallel
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_restart
-    mode: restart
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_with_params
-    parameters:
-      prefix: string
-      param2: int
-      param3: bool
-    then:
-      - lambda: 'ESP_LOGD(prefix.c_str(), "Hello World! %i %i", param2, param3);'
+<<: !include common.yaml
diff --git a/tests/components/script/test.rp2040.yaml b/tests/components/script/test.rp2040.yaml
index 3872c690ff..dade44d145 100644
--- a/tests/components/script/test.rp2040.yaml
+++ b/tests/components/script/test.rp2040.yaml
@@ -1,26 +1 @@
-script:
-  - id: my_script
-    mode: single
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_queued
-    mode: queued
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_parallel
-    mode: parallel
-    max_runs: 2
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_restart
-    mode: restart
-    then:
-      - lambda: 'ESP_LOGD("main", "Hello World!");'
-  - id: my_script_with_params
-    parameters:
-      prefix: string
-      param2: int
-      param3: bool
-    then:
-      - lambda: 'ESP_LOGD("main", (prefix + " Hello World!" + to_string(param2) + " " + to_string(param3)).c_str());'
+<<: !include common.yaml

From a4a23d73b32b0b485ccfbd8209b787a6785d5dd9 Mon Sep 17 00:00:00 2001
From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com>
Date: Thu, 2 May 2024 00:05:37 +0200
Subject: [PATCH 3/7] [nextion] Use persistent http connection for TFT upload
 (ESP-IDF) (#6576)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
---
 CODEOWNERS                                    |   2 +-
 esphome/components/nextion/display.py         |   2 +-
 esphome/components/nextion/nextion.h          |  37 +-
 .../components/nextion/nextion_upload_idf.cpp | 395 +++++++++---------
 esphome/core/defines.h                        |   2 +-
 5 files changed, 225 insertions(+), 213 deletions(-)

diff --git a/CODEOWNERS b/CODEOWNERS
index a60a5c3099..d0e920fe1d 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -242,7 +242,7 @@ esphome/components/mpl3115a2/* @kbickar
 esphome/components/mpu6886/* @fabaff
 esphome/components/ms8607/* @e28eta
 esphome/components/network/* @esphome/core
-esphome/components/nextion/* @senexcrenshaw
+esphome/components/nextion/* @edwardtfn @senexcrenshaw
 esphome/components/nextion/binary_sensor/* @senexcrenshaw
 esphome/components/nextion/sensor/* @senexcrenshaw
 esphome/components/nextion/switch/* @senexcrenshaw
diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py
index 6487c12f36..ce45d25e7b 100644
--- a/esphome/components/nextion/display.py
+++ b/esphome/components/nextion/display.py
@@ -25,7 +25,7 @@ from .base_component import (
     CONF_EXIT_REPARSE_ON_START,
 )
 
-CODEOWNERS = ["@senexcrenshaw"]
+CODEOWNERS = ["@senexcrenshaw", "@edwardtfn"]
 
 DEPENDENCIES = ["uart"]
 AUTO_LOAD = ["binary_sensor", "switch", "sensor", "text_sensor"]
diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h
index 7938af0ea5..6435e2b4e2 100644
--- a/esphome/components/nextion/nextion.h
+++ b/esphome/components/nextion/nextion.h
@@ -1013,7 +1013,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
    */
   bool upload_tft(uint32_t baud_rate = 0, bool exit_reparse = true);
 
-#endif
+#endif  // USE_NEXTION_TFT_UPLOAD
 
   void dump_config() override;
 
@@ -1142,6 +1142,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
    * Sends commands ignoring of the Nextion has been setup.
    */
   bool ignore_is_setup_ = false;
+
   bool nextion_reports_is_setup_ = false;
   uint8_t nextion_event_;
 
@@ -1182,7 +1183,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
   WiFiClient *wifi_client_{nullptr};
   BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr};
   WiFiClient *get_wifi_client_();
-#endif
+#endif  // USE_ESP8266
   std::string tft_url_;
   uint32_t content_length_ = 0;
   int tft_size_ = 0;
@@ -1193,11 +1194,21 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
   /**
    * will request chunk_size chunks from the web server
    * and send each to the nextion
-   * @param HTTPClient http HTTP client handler.
+   * @param HTTPClient http_client HTTP client handler.
    * @param int range_start Position of next byte to transfer.
    * @return position of last byte transferred, -1 for failure.
    */
   int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start);
+#elif defined(USE_ESP_IDF)
+  /**
+   * will request 4096 bytes chunks from the web server
+   * and send each to Nextion
+   * @param esp_http_client_handle_t http_client HTTP client handler.
+   * @param int range_start Position of next byte to transfer.
+   * @return position of last byte transferred, -1 for failure.
+   */
+  int upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start);
+#endif  // ARDUINO vs USE_ESP_IDF
 
   /**
    * Ends the upload process, restart Nextion and, if successful,
@@ -1207,24 +1218,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
    */
   bool upload_end_(bool successful);
 
-#elif defined(USE_ESP_IDF)
-  /**
-   * will request 4096 bytes chunks from the web server
-   * and send each to Nextion
-   * @param std::string url Full url for download.
-   * @param int range_start Position of next byte to transfer.
-   * @return position of last byte transferred, -1 for failure.
-   */
-  int upload_range(const std::string &url, int range_start);
-
-  /**
-   * Ends the upload process, restart Nextion and, if successful,
-   * restarts ESP
-   * @param bool url successful True: Transfer completed successfuly, False: Transfer failed.
-   * @return bool True: Transfer completed successfuly, False: Transfer failed.
-   */
-  bool upload_end(bool successful);
-#endif  // ARDUINO vs USE_ESP_IDF
   /**
    * Returns the ESP Free Heap memory. This is framework independent.
    * @return Free Heap in bytes.
@@ -1260,7 +1253,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
 
 #ifdef NEXTION_PROTOCOL_LOG
   void print_queue_members_();
-#endif
+#endif  // NEXTION_PROTOCOL_LOG
   void reset_(bool reset_nextion = true);
 
   std::string command_data_;
diff --git a/esphome/components/nextion/nextion_upload_idf.cpp b/esphome/components/nextion/nextion_upload_idf.cpp
index 163b497d3b..448b6fc0ff 100644
--- a/esphome/components/nextion/nextion_upload_idf.cpp
+++ b/esphome/components/nextion/nextion_upload_idf.cpp
@@ -1,17 +1,16 @@
 #include "nextion.h"
 
-#ifdef USE_ESP_IDF
 #ifdef USE_NEXTION_TFT_UPLOAD
+#ifdef USE_ESP_IDF
 
 #include "esphome/core/application.h"
 #include "esphome/core/defines.h"
 #include "esphome/core/util.h"
 #include "esphome/core/log.h"
 #include "esphome/components/network/util.h"
-
+#include <cinttypes>
 #include <esp_heap_caps.h>
 #include <esp_http_client.h>
-#include <cinttypes>
 
 namespace esphome {
 namespace nextion {
@@ -20,153 +19,147 @@ static const char *const TAG = "nextion.upload.idf";
 // Followed guide
 // https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2
 
-int Nextion::upload_range(const std::string &url, int range_start) {
-  ESP_LOGVV(TAG, "url: %s", url.c_str());
-  uint range_size = this->tft_size_ - range_start;
-  ESP_LOGVV(TAG, "tft_size_: %i", this->tft_size_);
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  int range_end = (range_start == 0) ? std::min(this->tft_size_, 16383) : this->tft_size_;
+int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start) {
+  uint32_t range_size = this->tft_size_ - range_start;
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
+  uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1;
+  ESP_LOGD(TAG, "Range start: %" PRIu32, range_start);
   if (range_size <= 0 or range_end <= range_start) {
+    ESP_LOGD(TAG, "Range end: %" PRIu32, range_end);
+    ESP_LOGD(TAG, "Range size: %" PRIu32, range_size);
     ESP_LOGE(TAG, "Invalid range");
-    ESP_LOGD(TAG, "Range start: %i", range_start);
-    ESP_LOGD(TAG, "Range end: %i", range_end);
-    ESP_LOGD(TAG, "Range size: %i", range_size);
     return -1;
   }
 
-  esp_http_client_config_t config = {
-      .url = url.c_str(),
-      .cert_pem = nullptr,
-      .disable_auto_redirect = false,
-      .max_redirection_count = 10,
-  };
-  esp_http_client_handle_t client = esp_http_client_init(&config);
-
-  char range_header[64];
-  sprintf(range_header, "bytes=%d-%d", range_start, range_end);
+  char range_header[32];
+  sprintf(range_header, "bytes=%" PRIu32 "-%" PRIu32, range_start, range_end);
   ESP_LOGV(TAG, "Requesting range: %s", range_header);
-  esp_http_client_set_header(client, "Range", range_header);
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-
-  ESP_LOGV(TAG, "Opening http connetion");
+  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(client, 0)) != ESP_OK) {
+  if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) {
     ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
-    esp_http_client_cleanup(client);
     return -1;
   }
 
   ESP_LOGV(TAG, "Fetch content length");
-  int content_length = esp_http_client_fetch_headers(client);
-  ESP_LOGV(TAG, "content_length = %d", content_length);
-  if (content_length <= 0) {
-    ESP_LOGE(TAG, "Failed to get content length: %d", content_length);
-    esp_http_client_cleanup(client);
+  const int chunk_size = esp_http_client_fetch_headers(http_client);
+  ESP_LOGV(TAG, "content_length = %d", chunk_size);
+  if (chunk_size <= 0) {
+    ESP_LOGE(TAG, "Failed to get chunk's content length: %d", chunk_size);
     return -1;
   }
 
-  int total_read_len = 0, read_len;
-
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  ESP_LOGV(TAG, "Allocate buffer");
-  uint8_t *buffer = new uint8_t[4096];
-  std::string recv_string;
-  if (buffer == nullptr) {
-    ESP_LOGE(TAG, "Failed to allocate memory for buffer");
-    ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  } else {
-    ESP_LOGV(TAG, "Memory for buffer allocated successfully");
-
-    while (true) {
-      App.feed_wdt();
-      ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-      int read_len = esp_http_client_read(client, reinterpret_cast<char *>(buffer), 4096);
-      ESP_LOGVV(TAG, "Read %d bytes from HTTP client, writing to UART", read_len);
-      if (read_len > 0) {
-        this->write_array(buffer, read_len);
-        ESP_LOGVV(TAG, "Write to UART successful");
-        this->recv_ret_string_(recv_string, 5000, true);
-        this->content_length_ -= read_len;
-        ESP_LOGD(TAG, "Uploaded %0.2f %%, remaining %d bytes, heap is %" PRIu32 " bytes",
-                 100.0 * (this->tft_size_ - this->content_length_) / this->tft_size_, this->content_length_,
-                 esp_get_free_heap_size());
-
-        if (recv_string[0] == 0x08 && recv_string.size() == 5) {  // handle partial upload request
-          ESP_LOGD(
-              TAG, "recv_string [%s]",
-              format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
-          uint32_t result = 0;
-          for (int j = 0; j < 4; ++j) {
-            result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
-          }
-          if (result > 0) {
-            ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result);
-            this->content_length_ = this->tft_size_ - result;
-            // Deallocate the buffer when done
-            ESP_LOGV(TAG, "Deallocate buffer");
-            ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-            delete[] buffer;
-            ESP_LOGVV(TAG, "Memory for buffer deallocated");
-            ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-            ESP_LOGV(TAG, "Close http client");
-            ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-            esp_http_client_close(client);
-            esp_http_client_cleanup(client);
-            ESP_LOGVV(TAG, "Client closed");
-            ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-            return result;
-          }
-        } else if (recv_string[0] != 0x05) {  // 0x05 == "ok"
-          ESP_LOGE(
-              TAG, "Invalid response from Nextion: [%s]",
-              format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
-          ESP_LOGV(TAG, "Deallocate buffer");
-          ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-          delete[] buffer;
-          ESP_LOGVV(TAG, "Memory for buffer deallocated");
-          ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-          ESP_LOGV(TAG, "Close http client");
-          ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-          esp_http_client_close(client);
-          esp_http_client_cleanup(client);
-          ESP_LOGVV(TAG, "Client closed");
-          ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-          return -1;
-        }
-
-        recv_string.clear();
-      } else if (read_len == 0) {
-        ESP_LOGV(TAG, "End of HTTP response reached");
-        break;  // Exit the loop if there is no more data to read
-      } else {
-        ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %d", read_len);
-        break;  // Exit the loop on error
-      }
-    }
-
-    // Deallocate the buffer when done
-    ESP_LOGV(TAG, "Deallocate buffer");
-    ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-    delete[] buffer;
-    ESP_LOGVV(TAG, "Memory for buffer deallocated");
-    ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+  // Allocate the buffer dynamically
+  ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
+  uint8_t *buffer = allocator.allocate(4096);
+  if (!buffer) {
+    ESP_LOGE(TAG, "Failed to allocate upload buffer");
+    return -1;
   }
-  ESP_LOGV(TAG, "Close http client");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  esp_http_client_close(client);
-  esp_http_client_cleanup(client);
-  ESP_LOGVV(TAG, "Client closed");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+
+  std::string recv_string;
+  while (true) {
+    App.feed_wdt();
+    const uint16_t buffer_size =
+        this->content_length_ < 4096 ? this->content_length_ : 4096;  // Limits buffer to the remaining data
+    ESP_LOGV(TAG, "Fetching %" PRIu16 " bytes from HTTP", buffer_size);
+    uint16_t read_len = 0;
+    int partial_read_len = 0;
+    uint8_t retries = 0;
+    // Attempt to read the chunk with retries.
+    while (retries < 5 && read_len < buffer_size) {
+      partial_read_len =
+          esp_http_client_read(http_client, reinterpret_cast<char *>(buffer) + read_len, buffer_size - read_len);
+      if (partial_read_len > 0) {
+        read_len += partial_read_len;  // Accumulate the total read length.
+        // Reset retries on successful read.
+        retries = 0;
+      } else {
+        // If no data was read, increment retries.
+        retries++;
+        vTaskDelay(pdMS_TO_TICKS(2));  // NOLINT
+      }
+      App.feed_wdt();  // Feed the watchdog timer.
+    }
+    if (read_len != buffer_size) {
+      // Did not receive the full package within the timeout period
+      ESP_LOGE(TAG, "Failed to read full package, received only %" PRIu16 " of %" PRIu16 " bytes", read_len,
+               buffer_size);
+      // Deallocate buffer
+      allocator.deallocate(buffer, 4096);
+      buffer = nullptr;
+      return -1;
+    }
+    ESP_LOGV(TAG, "%d bytes fetched, writing it to UART", read_len);
+    if (read_len > 0) {
+      recv_string.clear();
+      this->write_array(buffer, buffer_size);
+      App.feed_wdt();
+      this->recv_ret_string_(recv_string, upload_first_chunk_sent_ ? 500 : 5000, true);
+      this->content_length_ -= read_len;
+      const float upload_percentage = 100.0f * (this->tft_size_ - this->content_length_) / this->tft_size_;
+#ifdef USE_PSRAM
+      ESP_LOGD(
+          TAG,
+          "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " (DRAM) + %" PRIu32 " (PSRAM) bytes",
+          upload_percentage, this->content_length_, static_cast<uint32_t>(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)),
+          static_cast<uint32_t>(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)));
+#else
+      ESP_LOGD(TAG, "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " bytes", upload_percentage,
+               this->content_length_, static_cast<uint32_t>(esp_get_free_heap_size()));
+#endif
+      upload_first_chunk_sent_ = true;
+      if (recv_string[0] == 0x08 && recv_string.size() == 5) {  // handle partial upload request
+        ESP_LOGD(TAG, "recv_string [%s]",
+                 format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
+        uint32_t result = 0;
+        for (int j = 0; j < 4; ++j) {
+          result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
+        }
+        if (result > 0) {
+          ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result);
+          this->content_length_ = this->tft_size_ - result;
+          range_start = result;
+        } else {
+          range_start = range_end + 1;
+        }
+        // Deallocate buffer
+        allocator.deallocate(buffer, 4096);
+        buffer = nullptr;
+        return range_end + 1;
+      } else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) {  // 0x05 == "ok"
+        ESP_LOGE(TAG, "Invalid response from Nextion: [%s]",
+                 format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
+        // Deallocate buffer
+        allocator.deallocate(buffer, 4096);
+        buffer = nullptr;
+        return -1;
+      }
+
+      recv_string.clear();
+    } else if (read_len == 0) {
+      ESP_LOGV(TAG, "End of HTTP response reached");
+      break;  // Exit the loop if there is no more data to read
+    } else {
+      ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %" PRIu16, read_len);
+      break;  // Exit the loop on error
+    }
+  }
+  range_start = range_end + 1;
+  // Deallocate buffer
+  allocator.deallocate(buffer, 4096);
+  buffer = nullptr;
   return range_end + 1;
 }
 
 bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
   ESP_LOGD(TAG, "Nextion TFT upload requested");
   ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse));
-  ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str());
+  ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str());
 
   if (this->is_updating_) {
-    ESP_LOGW(TAG, "Currently updating");
+    ESP_LOGW(TAG, "Currently uploading");
     return false;
   }
 
@@ -195,8 +188,8 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
   ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate);
 
   // Define the configuration for the HTTP client
-  ESP_LOGV(TAG, "Establishing connection to HTTP server");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+  ESP_LOGV(TAG, "Initializing HTTP client");
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
   esp_http_client_config_t config = {
       .url = this->tft_url_.c_str(),
       .cert_pem = nullptr,
@@ -205,58 +198,62 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
       .disable_auto_redirect = false,
       .max_redirection_count = 10,
   };
-
   // Initialize the HTTP client with the configuration
-  ESP_LOGV(TAG, "Initializing HTTP client");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  esp_http_client_handle_t http = esp_http_client_init(&config);
-  if (!http) {
+  esp_http_client_handle_t http_client = esp_http_client_init(&config);
+  if (!http_client) {
     ESP_LOGE(TAG, "Failed to initialize HTTP client.");
-    return this->upload_end(false);
+    return this->upload_end_(false);
+  }
+
+  esp_err_t err = esp_http_client_set_header(http_client, "Connection", "keep-alive");
+  if (err != ESP_OK) {
+    ESP_LOGE(TAG, "HTTP set header failed: %s", esp_err_to_name(err));
+    esp_http_client_cleanup(http_client);
+    return this->upload_end_(false);
   }
 
   // Perform the HTTP request
   ESP_LOGV(TAG, "Check if the client could connect");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  esp_err_t err = esp_http_client_perform(http);
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
+  err = esp_http_client_perform(http_client);
   if (err != ESP_OK) {
     ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
-    esp_http_client_cleanup(http);
-    return this->upload_end(false);
+    esp_http_client_cleanup(http_client);
+    return this->upload_end_(false);
   }
 
   // Check the HTTP Status Code
   ESP_LOGV(TAG, "Check the HTTP Status Code");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  int status_code = esp_http_client_get_status_code(http);
-  ESP_LOGV(TAG, "HTTP Status Code: %d", status_code);
-  size_t tft_file_size = esp_http_client_get_content_length(http);
-  ESP_LOGD(TAG, "TFT file size: %zu", tft_file_size);
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
+  int status_code = esp_http_client_get_status_code(http_client);
+  if (status_code != 200 && status_code != 206) {
+    return this->upload_end_(false);
+  }
 
-  ESP_LOGD(TAG, "Close HTTP connection");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  esp_http_client_close(http);
-  esp_http_client_cleanup(http);
-  ESP_LOGVV(TAG, "Connection closed");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+  this->tft_size_ = esp_http_client_get_content_length(http_client);
 
-  if (tft_file_size < 4096) {
-    ESP_LOGE(TAG, "File size check failed. Size: %zu", tft_file_size);
-    return this->upload_end(false);
+  ESP_LOGD(TAG, "TFT file size: %zu bytes", this->tft_size_);
+  if (this->tft_size_ < 4096 || this->tft_size_ > 134217728) {
+    ESP_LOGE(TAG, "File size check failed.");
+    ESP_LOGD(TAG, "Close HTTP connection");
+    esp_http_client_close(http_client);
+    esp_http_client_cleanup(http_client);
+    ESP_LOGV(TAG, "Connection closed");
+    return this->upload_end_(false);
   } else {
     ESP_LOGV(TAG, "File size check passed. Proceeding...");
   }
-  this->content_length_ = tft_file_size;
-  this->tft_size_ = tft_file_size;
+  this->content_length_ = this->tft_size_;
 
-  ESP_LOGD(TAG, "Updating Nextion");
+  ESP_LOGD(TAG, "Uploading Nextion");
 
-  // The Nextion will ignore the update command if it is sleeping
+  // The Nextion will ignore the upload command if it is sleeping
   ESP_LOGV(TAG, "Wake-up Nextion");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+  this->ignore_is_setup_ = true;
   this->send_command_("sleep=0");
-  this->set_backlight_brightness(1.0);
+  this->send_command_("dim=100");
   vTaskDelay(pdMS_TO_TICKS(250));  // NOLINT
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
 
   App.feed_wdt();
   char command[128];
@@ -267,14 +264,11 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
 
   // Clear serial receive buffer
   ESP_LOGV(TAG, "Clear serial receive buffer");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  uint8_t d;
-  while (this->available()) {
-    this->read_byte(&d);
-  };
+  this->reset_(false);
+  vTaskDelay(pdMS_TO_TICKS(250));  // NOLINT
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
 
-  ESP_LOGV(TAG, "Send update instruction: %s", command);
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+  ESP_LOGV(TAG, "Send upload instruction: %s", command);
   this->send_command_(command);
 
   if (baud_rate != this->original_baud_rate_) {
@@ -288,41 +282,66 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
   this->recv_ret_string_(response, 5000, true);  // This can take some time to return
 
   // The Nextion display will, if it's ready to accept data, send a 0x05 byte.
-  ESP_LOGD(TAG, "Upgrade response is [%s] - %zu bytes",
+  ESP_LOGD(TAG, "Upgrade response is [%s] - %zu byte(s)",
            format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str(),
            response.length());
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
+  ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
 
   if (response.find(0x05) != std::string::npos) {
-    ESP_LOGV(TAG, "Preparation for tft update done");
+    ESP_LOGV(TAG, "Preparation for TFT upload done");
   } else {
-    ESP_LOGE(TAG, "Preparation for tft update failed %d \"%s\"", response[0], response.c_str());
-    return this->upload_end(false);
+    ESP_LOGE(TAG, "Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str());
+    ESP_LOGD(TAG, "Close HTTP connection");
+    esp_http_client_close(http_client);
+    esp_http_client_cleanup(http_client);
+    ESP_LOGV(TAG, "Connection closed");
+    return this->upload_end_(false);
   }
 
-  ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d, Heap Size %" PRIu32, this->tft_url_.c_str(),
-           content_length_, esp_get_free_heap_size());
+  ESP_LOGV(TAG, "Change the method to GET before starting the download");
+  esp_err_t set_method_result = esp_http_client_set_method(http_client, HTTP_METHOD_GET);
+  if (set_method_result != ESP_OK) {
+    ESP_LOGE(TAG, "Failed to set HTTP method to GET: %s", esp_err_to_name(set_method_result));
+    return this->upload_end_(false);
+  }
+
+  ESP_LOGD(TAG, "Uploading TFT to Nextion:");
+  ESP_LOGD(TAG, "  URL: %s", this->tft_url_.c_str());
+  ESP_LOGD(TAG, "  File size: %" PRIu32 " bytes", this->content_length_);
+  ESP_LOGD(TAG, "  Free heap: %" PRIu32, esp_get_free_heap_size());
+
+  // Proceed with the content download as before
 
   ESP_LOGV(TAG, "Starting transfer by chunks loop");
-  ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
-  int result = 0;
-  while (content_length_ > 0) {
-    result = upload_range(this->tft_url_.c_str(), result);
-    if (result < 0) {
-      ESP_LOGE(TAG, "Error updating Nextion!");
-      return this->upload_end(false);
+
+  uint32_t position = 0;
+  while (this->content_length_ > 0) {
+    int upload_result = upload_by_chunks_(http_client, position);
+    if (upload_result < 0) {
+      ESP_LOGE(TAG, "Error uploading TFT to Nextion!");
+      ESP_LOGD(TAG, "Close HTTP connection");
+      esp_http_client_close(http_client);
+      esp_http_client_cleanup(http_client);
+      ESP_LOGV(TAG, "Connection closed");
+      return this->upload_end_(false);
     }
     App.feed_wdt();
-    ESP_LOGV(TAG, "Heap Size %" PRIu32 ", Bytes left %d", esp_get_free_heap_size(), content_length_);
+    ESP_LOGV(TAG, "Free heap: %" PRIu32 ", Bytes left: %" PRIu32, esp_get_free_heap_size(), this->content_length_);
   }
 
-  ESP_LOGD(TAG, "Successfully updated Nextion!");
+  ESP_LOGD(TAG, "Successfully uploaded TFT to Nextion!");
 
-  return upload_end(true);
+  ESP_LOGD(TAG, "Close HTTP connection");
+  esp_http_client_close(http_client);
+  esp_http_client_cleanup(http_client);
+  ESP_LOGV(TAG, "Connection closed");
+  return this->upload_end_(true);
 }
 
-bool Nextion::upload_end(bool successful) {
+bool Nextion::upload_end_(bool successful) {
+  ESP_LOGD(TAG, "Nextion TFT upload finished: %s", YESNO(successful));
   this->is_updating_ = false;
+  this->ignore_is_setup_ = false;
 
   uint32_t baud_rate = this->parent_->get_baud_rate();
   if (baud_rate != this->original_baud_rate_) {
@@ -331,12 +350,12 @@ bool Nextion::upload_end(bool successful) {
     this->parent_->load_settings();
   }
 
-  ESP_LOGD(TAG, "Restarting Nextion");
-  this->soft_reset();
-  vTaskDelay(pdMS_TO_TICKS(1500));  // NOLINT
   if (successful) {
     ESP_LOGD(TAG, "Restarting ESPHome");
-    esp_restart();  // NOLINT(readability-static-accessed-through-instance)
+    delay(1500);  // NOLINT
+    arch_restart();
+  } else {
+    ESP_LOGE(TAG, "Nextion TFT upload failed");
   }
   return successful;
 }
@@ -344,5 +363,5 @@ bool Nextion::upload_end(bool successful) {
 }  // namespace nextion
 }  // namespace esphome
 
-#endif  // USE_NEXTION_TFT_UPLOAD
 #endif  // USE_ESP_IDF
+#endif  // USE_NEXTION_TFT_UPLOAD
diff --git a/esphome/core/defines.h b/esphome/core/defines.h
index 619a956071..b09373bcde 100644
--- a/esphome/core/defines.h
+++ b/esphome/core/defines.h
@@ -35,6 +35,7 @@
 #define USE_MDNS
 #define USE_MEDIA_PLAYER
 #define USE_MQTT
+#define USE_NEXTION_TFT_UPLOAD
 #define USE_NUMBER
 #define USE_DATETIME
 #define USE_DATETIME_DATE
@@ -64,7 +65,6 @@
 // Arduino-specific feature flags
 #ifdef USE_ARDUINO
 #define USE_CAPTIVE_PORTAL
-#define USE_NEXTION_TFT_UPLOAD
 #define USE_PROMETHEUS
 #define USE_WEBSERVER
 #define USE_WEBSERVER_PORT 80  // NOLINT

From 539c369eea0c07a89d0b0fbc877d3b14fe17fbdc Mon Sep 17 00:00:00 2001
From: tronikos <tronikos@users.noreply.github.com>
Date: Wed, 1 May 2024 17:39:15 -0700
Subject: [PATCH 4/7] Add a function to return the loop_interval (#6666)

---
 esphome/core/application.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/esphome/core/application.h b/esphome/core/application.h
index 7487780412..c4c745b687 100644
--- a/esphome/core/application.h
+++ b/esphome/core/application.h
@@ -222,6 +222,8 @@ class Application {
    */
   void set_loop_interval(uint32_t loop_interval) { this->loop_interval_ = loop_interval; }
 
+  uint32_t get_loop_interval() const { return this->loop_interval_; }
+
   void schedule_dump_config() { this->dump_config_at_ = 0; }
 
   void feed_wdt();

From 1b9a30e921f129f5c9aa3dd1032387722a7babc9 Mon Sep 17 00:00:00 2001
From: Mat931 <49403702+Mat931@users.noreply.github.com>
Date: Thu, 2 May 2024 01:21:57 +0000
Subject: [PATCH 5/7] Remote receiver improvements (#4642)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
---
 .../components/remote_base/remote_base.cpp    |  6 +-
 esphome/components/remote_base/remote_base.h  | 45 +++++++++--
 .../components/remote_receiver/__init__.py    | 75 +++++++++++++++++--
 .../remote_receiver/remote_receiver.h         |  6 +-
 .../remote_receiver/remote_receiver_esp32.cpp | 16 ++--
 .../remote_receiver_esp8266.cpp               |  3 +-
 .../remote_receiver_libretiny.cpp             |  3 +-
 7 files changed, 125 insertions(+), 29 deletions(-)

diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp
index 0e9cef8cca..fdfd0b43cc 100644
--- a/esphome/components/remote_base/remote_base.cpp
+++ b/esphome/components/remote_base/remote_base.cpp
@@ -108,18 +108,18 @@ void RemoteReceiverBase::register_dumper(RemoteReceiverDumperBase *dumper) {
 
 void RemoteReceiverBase::call_listeners_() {
   for (auto *listener : this->listeners_)
-    listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_));
+    listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_));
 }
 
 void RemoteReceiverBase::call_dumpers_() {
   bool success = false;
   for (auto *dumper : this->dumpers_) {
-    if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_)))
+    if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_)))
       success = true;
   }
   if (!success) {
     for (auto *dumper : this->secondary_dumpers_)
-      dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_));
+      dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_));
   }
 }
 
diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h
index b2a4b543ea..c31127735a 100644
--- a/esphome/components/remote_base/remote_base.h
+++ b/esphome/components/remote_base/remote_base.h
@@ -15,6 +15,11 @@
 namespace esphome {
 namespace remote_base {
 
+enum ToleranceMode : uint8_t {
+  TOLERANCE_MODE_PERCENTAGE = 0,
+  TOLERANCE_MODE_TIME = 1,
+};
+
 using RawTimings = std::vector<int32_t>;
 
 class RemoteTransmitData {
@@ -42,8 +47,8 @@ class RemoteTransmitData {
 
 class RemoteReceiveData {
  public:
-  explicit RemoteReceiveData(const RawTimings &data, uint8_t tolerance)
-      : data_(data), index_(0), tolerance_(tolerance) {}
+  explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
+      : data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {}
 
   const RawTimings &get_raw_data() const { return this->data_; }
   uint32_t get_index() const { return index_; }
@@ -65,13 +70,35 @@ class RemoteReceiveData {
   void advance(uint32_t amount = 1) { this->index_ += amount; }
   void reset() { this->index_ = 0; }
 
+  void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
+    this->tolerance_ = tolerance;
+    this->tolerance_mode_ = tolerance_mode;
+  }
+  uint32_t get_tolerance() { return tolerance_; }
+  ToleranceMode get_tolerance_mode() { return this->tolerance_mode_; }
+
  protected:
-  int32_t lower_bound_(uint32_t length) const { return int32_t(100 - this->tolerance_) * length / 100U; }
-  int32_t upper_bound_(uint32_t length) const { return int32_t(100 + this->tolerance_) * length / 100U; }
+  int32_t lower_bound_(uint32_t length) const {
+    if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) {
+      return int32_t(length - this->tolerance_);
+    } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
+      return int32_t(100 - this->tolerance_) * length / 100U;
+    }
+    return 0;
+  }
+  int32_t upper_bound_(uint32_t length) const {
+    if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) {
+      return int32_t(length + this->tolerance_);
+    } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
+      return int32_t(100 + this->tolerance_) * length / 100U;
+    }
+    return 0;
+  }
 
   const RawTimings &data_;
   uint32_t index_;
-  uint8_t tolerance_;
+  uint32_t tolerance_;
+  ToleranceMode tolerance_mode_;
 };
 
 class RemoteComponentBase {
@@ -162,7 +189,10 @@ class RemoteReceiverBase : public RemoteComponentBase {
   RemoteReceiverBase(InternalGPIOPin *pin) : RemoteComponentBase(pin) {}
   void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
   void register_dumper(RemoteReceiverDumperBase *dumper);
-  void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; }
+  void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
+    this->tolerance_ = tolerance;
+    this->tolerance_mode_ = tolerance_mode;
+  }
 
  protected:
   void call_listeners_();
@@ -176,7 +206,8 @@ class RemoteReceiverBase : public RemoteComponentBase {
   std::vector<RemoteReceiverDumperBase *> dumpers_;
   std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
   RawTimings temp_;
-  uint8_t tolerance_;
+  uint32_t tolerance_{25};
+  ToleranceMode tolerance_mode_{TOLERANCE_MODE_PERCENTAGE};
 };
 
 class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitiallyOff,
diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py
index 6a68c8b254..6fe20153f4 100644
--- a/esphome/components/remote_receiver/__init__.py
+++ b/esphome/components/remote_receiver/__init__.py
@@ -10,17 +10,69 @@ from esphome.const import (
     CONF_IDLE,
     CONF_PIN,
     CONF_TOLERANCE,
+    CONF_TYPE,
     CONF_MEMORY_BLOCKS,
     CONF_RMT_CHANNEL,
+    CONF_VALUE,
 )
 from esphome.core import CORE, TimePeriod
 
+CONF_CLOCK_DIVIDER = "clock_divider"
+
 AUTO_LOAD = ["remote_base"]
 remote_receiver_ns = cg.esphome_ns.namespace("remote_receiver")
+remote_base_ns = cg.esphome_ns.namespace("remote_base")
+
+ToleranceMode = remote_base_ns.enum("ToleranceMode")
+
+TYPE_PERCENTAGE = "percentage"
+TYPE_TIME = "time"
+
+TOLERANCE_MODE = {
+    TYPE_PERCENTAGE: ToleranceMode.TOLERANCE_MODE_PERCENTAGE,
+    TYPE_TIME: ToleranceMode.TOLERANCE_MODE_TIME,
+}
+
+TOLERANCE_SCHEMA = cv.typed_schema(
+    {
+        TYPE_PERCENTAGE: cv.Schema(
+            {cv.Required(CONF_VALUE): cv.All(cv.percentage_int, cv.uint32_t)}
+        ),
+        TYPE_TIME: cv.Schema(
+            {
+                cv.Required(CONF_VALUE): cv.All(
+                    cv.positive_time_period_microseconds,
+                    cv.Range(max=TimePeriod(microseconds=4294967295)),
+                )
+            }
+        ),
+    },
+    lower=True,
+    enum=TOLERANCE_MODE,
+)
+
 RemoteReceiverComponent = remote_receiver_ns.class_(
     "RemoteReceiverComponent", remote_base.RemoteReceiverBase, cg.Component
 )
 
+
+def validate_tolerance(value):
+    if isinstance(value, dict):
+        return TOLERANCE_SCHEMA(value)
+
+    if "%" in str(value):
+        type_ = TYPE_PERCENTAGE
+    else:
+        type_ = TYPE_TIME
+
+    return TOLERANCE_SCHEMA(
+        {
+            CONF_VALUE: value,
+            CONF_TYPE: type_,
+        }
+    )
+
+
 MULTI_CONF = True
 CONFIG_SCHEMA = remote_base.validate_triggers(
     cv.Schema(
@@ -28,9 +80,7 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
             cv.GenerateID(): cv.declare_id(RemoteReceiverComponent),
             cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema),
             cv.Optional(CONF_DUMP, default=[]): remote_base.validate_dumpers,
-            cv.Optional(CONF_TOLERANCE, default=25): cv.All(
-                cv.percentage_int, cv.Range(min=0)
-            ),
+            cv.Optional(CONF_TOLERANCE, default="25%"): validate_tolerance,
             cv.SplitDefault(
                 CONF_BUFFER_SIZE,
                 esp32="10000b",
@@ -40,11 +90,15 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
             ): cv.validate_bytes,
             cv.Optional(CONF_FILTER, default="50us"): cv.All(
                 cv.positive_time_period_microseconds,
-                cv.Range(max=TimePeriod(microseconds=255)),
+                cv.Range(max=TimePeriod(microseconds=4294967295)),
+            ),
+            cv.SplitDefault(CONF_CLOCK_DIVIDER, esp32=80): cv.All(
+                cv.only_on_esp32, cv.Range(min=1, max=255)
+            ),
+            cv.Optional(CONF_IDLE, default="10ms"): cv.All(
+                cv.positive_time_period_microseconds,
+                cv.Range(max=TimePeriod(microseconds=4294967295)),
             ),
-            cv.Optional(
-                CONF_IDLE, default="10ms"
-            ): cv.positive_time_period_microseconds,
             cv.Optional(CONF_MEMORY_BLOCKS, default=3): cv.Range(min=1, max=8),
             cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=False),
         }
@@ -61,6 +115,7 @@ async def to_code(config):
             )
         else:
             var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS])
+        cg.add(var.set_clock_divider(config[CONF_CLOCK_DIVIDER]))
     else:
         var = cg.new_Pvariable(config[CONF_ID], pin)
 
@@ -73,7 +128,11 @@ async def to_code(config):
         cg.add(var.register_listener(trigger))
     await cg.register_component(var, config)
 
-    cg.add(var.set_tolerance(config[CONF_TOLERANCE]))
+    cg.add(
+        var.set_tolerance(
+            config[CONF_TOLERANCE][CONF_VALUE], config[CONF_TOLERANCE][CONF_TYPE]
+        )
+    )
     cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE]))
     cg.add(var.set_filter_us(config[CONF_FILTER]))
     cg.add(var.set_idle_us(config[CONF_IDLE]))
diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h
index f29145a59e..a1db671e5c 100644
--- a/esphome/components/remote_receiver/remote_receiver.h
+++ b/esphome/components/remote_receiver/remote_receiver.h
@@ -22,7 +22,7 @@ struct RemoteReceiverComponentStore {
   uint32_t buffer_read_at{0};
   bool overflow{false};
   uint32_t buffer_size{1000};
-  uint8_t filter_us{10};
+  uint32_t filter_us{10};
   ISRInternalGPIOPin pin;
 };
 #endif
@@ -50,7 +50,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase,
   float get_setup_priority() const override { return setup_priority::DATA; }
 
   void set_buffer_size(uint32_t buffer_size) { this->buffer_size_ = buffer_size; }
-  void set_filter_us(uint8_t filter_us) { this->filter_us_ = filter_us; }
+  void set_filter_us(uint32_t filter_us) { this->filter_us_ = filter_us; }
   void set_idle_us(uint32_t idle_us) { this->idle_us_ = idle_us; }
 
  protected:
@@ -66,7 +66,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase,
 #endif
 
   uint32_t buffer_size_{};
-  uint8_t filter_us_{10};
+  uint32_t filter_us_{10};
   uint32_t idle_us_{10000};
 };
 
diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp
index d19ab695e1..c0bfb0222f 100644
--- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp
+++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp
@@ -20,9 +20,11 @@ void RemoteReceiverComponent::setup() {
     rmt.rx_config.filter_en = false;
   } else {
     rmt.rx_config.filter_en = true;
-    rmt.rx_config.filter_ticks_thresh = this->from_microseconds_(this->filter_us_);
+    rmt.rx_config.filter_ticks_thresh = static_cast<uint8_t>(
+        std::min(this->from_microseconds_(this->filter_us_) * this->clock_divider_, (uint32_t) 255));
   }
-  rmt.rx_config.idle_threshold = this->from_microseconds_(this->idle_us_);
+  rmt.rx_config.idle_threshold =
+      static_cast<uint16_t>(std::min(this->from_microseconds_(this->idle_us_), (uint32_t) 65535));
 
   esp_err_t error = rmt_config(&rmt);
   if (error != ESP_OK) {
@@ -60,8 +62,9 @@ void RemoteReceiverComponent::dump_config() {
   ESP_LOGCONFIG(TAG, "  Channel: %d", this->channel_);
   ESP_LOGCONFIG(TAG, "  RMT memory blocks: %d", this->mem_block_num_);
   ESP_LOGCONFIG(TAG, "  Clock divider: %u", this->clock_divider_);
-  ESP_LOGCONFIG(TAG, "  Tolerance: %u%%", this->tolerance_);
-  ESP_LOGCONFIG(TAG, "  Filter out pulses shorter than: %u us", this->filter_us_);
+  ESP_LOGCONFIG(TAG, "  Tolerance: %" PRIu32 "%s", this->tolerance_,
+                (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
+  ESP_LOGCONFIG(TAG, "  Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_);
   ESP_LOGCONFIG(TAG, "  Signal is done after %" PRIu32 " us of no changes", this->idle_us_);
   if (this->is_failed()) {
     ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_));
@@ -88,6 +91,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
   this->temp_.clear();
   int32_t multiplier = this->pin_->is_inverted() ? -1 : 1;
   size_t item_count = len / sizeof(rmt_item32_t);
+  uint32_t filter_ticks = this->from_microseconds_(this->filter_us_);
 
   ESP_LOGVV(TAG, "START:");
   for (size_t i = 0; i < item_count; i++) {
@@ -112,7 +116,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
   for (size_t i = 0; i < item_count; i++) {
     if (item[i].duration0 == 0u) {
       // Do nothing
-    } else if (bool(item[i].level0) == prev_level) {
+    } else if ((bool(item[i].level0) == prev_level) || (item[i].duration0 < filter_ticks)) {
       prev_length += item[i].duration0;
     } else {
       if (prev_length > 0) {
@@ -128,7 +132,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
 
     if (item[i].duration1 == 0u) {
       // Do nothing
-    } else if (bool(item[i].level1) == prev_level) {
+    } else if ((bool(item[i].level1) == prev_level) || (item[i].duration1 < filter_ticks)) {
       prev_length += item[i].duration1;
     } else {
       if (prev_length > 0) {
diff --git a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp
index 8700fcf0bb..c92a134bd8 100644
--- a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp
+++ b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp
@@ -64,7 +64,8 @@ void RemoteReceiverComponent::dump_config() {
                   "invert the signal using 'inverted: True' in the pin schema!");
   }
   ESP_LOGCONFIG(TAG, "  Buffer Size: %u", this->buffer_size_);
-  ESP_LOGCONFIG(TAG, "  Tolerance: %u%%", this->tolerance_);
+  ESP_LOGCONFIG(TAG, "  Tolerance: %u%s", this->tolerance_,
+                (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
   ESP_LOGCONFIG(TAG, "  Filter out pulses shorter than: %u us", this->filter_us_);
   ESP_LOGCONFIG(TAG, "  Signal is done after %u us of no changes", this->idle_us_);
 }
diff --git a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp
index ac85b6b520..bfc29b4211 100644
--- a/esphome/components/remote_receiver/remote_receiver_libretiny.cpp
+++ b/esphome/components/remote_receiver/remote_receiver_libretiny.cpp
@@ -64,7 +64,8 @@ void RemoteReceiverComponent::dump_config() {
                   "invert the signal using 'inverted: True' in the pin schema!");
   }
   ESP_LOGCONFIG(TAG, "  Buffer Size: %u", this->buffer_size_);
-  ESP_LOGCONFIG(TAG, "  Tolerance: %u%%", this->tolerance_);
+  ESP_LOGCONFIG(TAG, "  Tolerance: %u%s", this->tolerance_,
+                (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
   ESP_LOGCONFIG(TAG, "  Filter out pulses shorter than: %u us", this->filter_us_);
   ESP_LOGCONFIG(TAG, "  Signal is done after %u us of no changes", this->idle_us_);
 }

From bc65e6e914ea29da8bbb02ca5f5f3d948823dbd7 Mon Sep 17 00:00:00 2001
From: tronikos <tronikos@users.noreply.github.com>
Date: Wed, 1 May 2024 18:24:18 -0700
Subject: [PATCH 6/7] Make fast update intervals in qmc5883l work (#6647)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
---
 esphome/components/qmc5883l/qmc5883l.cpp | 5 +++++
 esphome/components/qmc5883l/qmc5883l.h   | 1 +
 2 files changed, 6 insertions(+)

diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp
index 8541b41ff7..49a67d4e09 100644
--- a/esphome/components/qmc5883l/qmc5883l.cpp
+++ b/esphome/components/qmc5883l/qmc5883l.cpp
@@ -1,4 +1,5 @@
 #include "qmc5883l.h"
+#include "esphome/core/application.h"
 #include "esphome/core/log.h"
 #include "esphome/core/hal.h"
 #include <cmath>
@@ -59,6 +60,10 @@ void QMC5883LComponent::setup() {
     this->mark_failed();
     return;
   }
+
+  if (this->get_update_interval() < App.get_loop_interval()) {
+    high_freq_.start();
+  }
 }
 void QMC5883LComponent::dump_config() {
   ESP_LOGCONFIG(TAG, "QMC5883L:");
diff --git a/esphome/components/qmc5883l/qmc5883l.h b/esphome/components/qmc5883l/qmc5883l.h
index b0c0af40d2..dd2008d453 100644
--- a/esphome/components/qmc5883l/qmc5883l.h
+++ b/esphome/components/qmc5883l/qmc5883l.h
@@ -56,6 +56,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
     COMMUNICATION_FAILED,
   } error_code_;
   bool read_byte_16_(uint8_t a_register, uint16_t *data);
+  HighFrequencyLoopRequester high_freq_;
 };
 
 }  // namespace qmc5883l

From c7c0d97a5ecbaa235636ba9e527f8c9ff7b4c4b0 Mon Sep 17 00:00:00 2001
From: Anton Viktorov <anton.viktorov@live.com>
Date: Thu, 2 May 2024 03:49:01 +0200
Subject: [PATCH 7/7] SPI and I2C for BMP390 and BMP380 (#6652)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
---
 CODEOWNERS                                    |   5 +-
 esphome/components/bmp3xx/sensor.py           | 105 +-----------------
 esphome/components/bmp3xx_base/__init__.py    |  95 ++++++++++++++++
 .../bmp3xx_base.cpp}                          |   7 +-
 .../bmp3xx.h => bmp3xx_base/bmp3xx_base.h}    |  15 ++-
 esphome/components/bmp3xx_i2c/__init__.py     |   0
 esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp  |  29 +++++
 esphome/components/bmp3xx_i2c/bmp3xx_i2c.h    |  17 +++
 esphome/components/bmp3xx_i2c/sensor.py       |  22 ++++
 esphome/components/bmp3xx_spi/__init__.py     |   0
 esphome/components/bmp3xx_spi/bmp3xx_spi.cpp  |  57 ++++++++++
 esphome/components/bmp3xx_spi/bmp3xx_spi.h    |  19 ++++
 esphome/components/bmp3xx_spi/sensor.py       |  22 ++++
 .../components/bmp3xx/test.esp32-c3-idf.yaml  |  14 ---
 tests/components/bmp3xx/test.esp32-c3.yaml    |  14 ---
 tests/components/bmp3xx/test.esp32.yaml       |  14 ---
 tests/components/bmp3xx/test.esp8266.yaml     |  14 ---
 tests/components/bmp3xx/test.rp2040.yaml      |  14 ---
 .../common.yaml}                              |   7 +-
 .../bmp3xx_i2c/test.esp32-c3-idf.yaml         |   5 +
 .../components/bmp3xx_i2c/test.esp32-c3.yaml  |   5 +
 .../components/bmp3xx_i2c/test.esp32-idf.yaml |   5 +
 tests/components/bmp3xx_i2c/test.esp32.yaml   |   5 +
 tests/components/bmp3xx_i2c/test.esp8266.yaml |   5 +
 tests/components/bmp3xx_i2c/test.rp2040.yaml  |   5 +
 tests/components/bmp3xx_spi/common.yaml       |  16 +++
 .../bmp3xx_spi/test.esp32-c3-idf.yaml         |   7 ++
 .../components/bmp3xx_spi/test.esp32-c3.yaml  |   7 ++
 .../components/bmp3xx_spi/test.esp32-idf.yaml |   7 ++
 tests/components/bmp3xx_spi/test.esp32.yaml   |   7 ++
 tests/components/bmp3xx_spi/test.esp8266.yaml |   7 ++
 tests/components/bmp3xx_spi/test.rp2040.yaml  |   7 ++
 tests/test11.5.yaml                           |   9 --
 tests/test5.yaml                              |   9 --
 34 files changed, 375 insertions(+), 201 deletions(-)
 create mode 100644 esphome/components/bmp3xx_base/__init__.py
 rename esphome/components/{bmp3xx/bmp3xx.cpp => bmp3xx_base/bmp3xx_base.cpp} (99%)
 rename esphome/components/{bmp3xx/bmp3xx.h => bmp3xx_base/bmp3xx_base.h} (94%)
 create mode 100644 esphome/components/bmp3xx_i2c/__init__.py
 create mode 100644 esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp
 create mode 100644 esphome/components/bmp3xx_i2c/bmp3xx_i2c.h
 create mode 100644 esphome/components/bmp3xx_i2c/sensor.py
 create mode 100644 esphome/components/bmp3xx_spi/__init__.py
 create mode 100644 esphome/components/bmp3xx_spi/bmp3xx_spi.cpp
 create mode 100644 esphome/components/bmp3xx_spi/bmp3xx_spi.h
 create mode 100644 esphome/components/bmp3xx_spi/sensor.py
 delete mode 100644 tests/components/bmp3xx/test.esp32-c3-idf.yaml
 delete mode 100644 tests/components/bmp3xx/test.esp32-c3.yaml
 delete mode 100644 tests/components/bmp3xx/test.esp32.yaml
 delete mode 100644 tests/components/bmp3xx/test.esp8266.yaml
 delete mode 100644 tests/components/bmp3xx/test.rp2040.yaml
 rename tests/components/{bmp3xx/test.esp32-idf.yaml => bmp3xx_i2c/common.yaml} (66%)
 create mode 100644 tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml
 create mode 100644 tests/components/bmp3xx_i2c/test.esp32-c3.yaml
 create mode 100644 tests/components/bmp3xx_i2c/test.esp32-idf.yaml
 create mode 100644 tests/components/bmp3xx_i2c/test.esp32.yaml
 create mode 100644 tests/components/bmp3xx_i2c/test.esp8266.yaml
 create mode 100644 tests/components/bmp3xx_i2c/test.rp2040.yaml
 create mode 100644 tests/components/bmp3xx_spi/common.yaml
 create mode 100644 tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml
 create mode 100644 tests/components/bmp3xx_spi/test.esp32-c3.yaml
 create mode 100644 tests/components/bmp3xx_spi/test.esp32-idf.yaml
 create mode 100644 tests/components/bmp3xx_spi/test.esp32.yaml
 create mode 100644 tests/components/bmp3xx_spi/test.esp8266.yaml
 create mode 100644 tests/components/bmp3xx_spi/test.rp2040.yaml

diff --git a/CODEOWNERS b/CODEOWNERS
index d0e920fe1d..c630db7948 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -63,7 +63,10 @@ esphome/components/bme280_base/* @esphome/core
 esphome/components/bme280_spi/* @apbodrov
 esphome/components/bme680_bsec/* @trvrnrth
 esphome/components/bmi160/* @flaviut
-esphome/components/bmp3xx/* @martgras
+esphome/components/bmp3xx/* @latonita
+esphome/components/bmp3xx_base/* @latonita @martgras
+esphome/components/bmp3xx_i2c/* @latonita
+esphome/components/bmp3xx_spi/* @latonita
 esphome/components/bmp581/* @kahrendt
 esphome/components/bp1658cj/* @Cossid
 esphome/components/bp5758d/* @Cossid
diff --git a/esphome/components/bmp3xx/sensor.py b/esphome/components/bmp3xx/sensor.py
index 6f90173c7b..89753768c3 100644
--- a/esphome/components/bmp3xx/sensor.py
+++ b/esphome/components/bmp3xx/sensor.py
@@ -1,102 +1,7 @@
-import esphome.codegen as cg
 import esphome.config_validation as cv
-from esphome.components import i2c, sensor
-from esphome.const import (
-    CONF_ID,
-    CONF_IIR_FILTER,
-    CONF_OVERSAMPLING,
-    CONF_PRESSURE,
-    CONF_TEMPERATURE,
-    DEVICE_CLASS_PRESSURE,
-    DEVICE_CLASS_TEMPERATURE,
-    STATE_CLASS_MEASUREMENT,
-    UNIT_CELSIUS,
-    UNIT_HECTOPASCAL,
+
+CODEOWNERS = ["@latonita"]
+
+CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid(
+    "The bmp3xx sensor component has been renamed to bmp3xx_i2c."
 )
-
-CODEOWNERS = ["@martgras"]
-DEPENDENCIES = ["i2c"]
-
-bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx")
-Oversampling = bmp3xx_ns.enum("Oversampling")
-OVERSAMPLING_OPTIONS = {
-    "NONE": Oversampling.OVERSAMPLING_NONE,
-    "2X": Oversampling.OVERSAMPLING_X2,
-    "4X": Oversampling.OVERSAMPLING_X4,
-    "8X": Oversampling.OVERSAMPLING_X8,
-    "16X": Oversampling.OVERSAMPLING_X16,
-    "32X": Oversampling.OVERSAMPLING_X32,
-}
-
-IIRFilter = bmp3xx_ns.enum("IIRFilter")
-IIR_FILTER_OPTIONS = {
-    "OFF": IIRFilter.IIR_FILTER_OFF,
-    "2X": IIRFilter.IIR_FILTER_2,
-    "4X": IIRFilter.IIR_FILTER_4,
-    "8X": IIRFilter.IIR_FILTER_8,
-    "16X": IIRFilter.IIR_FILTER_16,
-    "32X": IIRFilter.IIR_FILTER_32,
-    "64X": IIRFilter.IIR_FILTER_64,
-    "128X": IIRFilter.IIR_FILTER_128,
-}
-
-BMP3XXComponent = bmp3xx_ns.class_(
-    "BMP3XXComponent", cg.PollingComponent, i2c.I2CDevice
-)
-
-CONFIG_SCHEMA = (
-    cv.Schema(
-        {
-            cv.GenerateID(): cv.declare_id(BMP3XXComponent),
-            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
-                unit_of_measurement=UNIT_CELSIUS,
-                accuracy_decimals=1,
-                device_class=DEVICE_CLASS_TEMPERATURE,
-                state_class=STATE_CLASS_MEASUREMENT,
-            ).extend(
-                {
-                    cv.Optional(CONF_OVERSAMPLING, default="2X"): cv.enum(
-                        OVERSAMPLING_OPTIONS, upper=True
-                    ),
-                }
-            ),
-            cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
-                unit_of_measurement=UNIT_HECTOPASCAL,
-                accuracy_decimals=1,
-                device_class=DEVICE_CLASS_PRESSURE,
-                state_class=STATE_CLASS_MEASUREMENT,
-            ).extend(
-                {
-                    cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
-                        OVERSAMPLING_OPTIONS, upper=True
-                    ),
-                }
-            ),
-            cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
-                IIR_FILTER_OPTIONS, upper=True
-            ),
-        }
-    )
-    .extend(cv.polling_component_schema("60s"))
-    .extend(i2c.i2c_device_schema(0x77))
-)
-
-
-async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await cg.register_component(var, config)
-    await i2c.register_i2c_device(var, config)
-    cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER]))
-    if temperature_config := config.get(CONF_TEMPERATURE):
-        sens = await sensor.new_sensor(temperature_config)
-        cg.add(var.set_temperature_sensor(sens))
-        cg.add(
-            var.set_temperature_oversampling_config(
-                temperature_config[CONF_OVERSAMPLING]
-            )
-        )
-
-    if pressure_config := config.get(CONF_PRESSURE):
-        sens = await sensor.new_sensor(pressure_config)
-        cg.add(var.set_pressure_sensor(sens))
-        cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING]))
diff --git a/esphome/components/bmp3xx_base/__init__.py b/esphome/components/bmp3xx_base/__init__.py
new file mode 100644
index 0000000000..589d170907
--- /dev/null
+++ b/esphome/components/bmp3xx_base/__init__.py
@@ -0,0 +1,95 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import sensor
+from esphome.const import (
+    CONF_ID,
+    CONF_IIR_FILTER,
+    CONF_OVERSAMPLING,
+    CONF_PRESSURE,
+    CONF_TEMPERATURE,
+    DEVICE_CLASS_PRESSURE,
+    DEVICE_CLASS_TEMPERATURE,
+    STATE_CLASS_MEASUREMENT,
+    UNIT_CELSIUS,
+    UNIT_HECTOPASCAL,
+)
+
+CODEOWNERS = ["@martgras", "@latonita"]
+
+bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx_base")
+Oversampling = bmp3xx_ns.enum("Oversampling")
+OVERSAMPLING_OPTIONS = {
+    "NONE": Oversampling.OVERSAMPLING_NONE,
+    "2X": Oversampling.OVERSAMPLING_X2,
+    "4X": Oversampling.OVERSAMPLING_X4,
+    "8X": Oversampling.OVERSAMPLING_X8,
+    "16X": Oversampling.OVERSAMPLING_X16,
+    "32X": Oversampling.OVERSAMPLING_X32,
+}
+
+IIRFilter = bmp3xx_ns.enum("IIRFilter")
+IIR_FILTER_OPTIONS = {
+    "OFF": IIRFilter.IIR_FILTER_OFF,
+    "2X": IIRFilter.IIR_FILTER_2,
+    "4X": IIRFilter.IIR_FILTER_4,
+    "8X": IIRFilter.IIR_FILTER_8,
+    "16X": IIRFilter.IIR_FILTER_16,
+    "32X": IIRFilter.IIR_FILTER_32,
+    "64X": IIRFilter.IIR_FILTER_64,
+    "128X": IIRFilter.IIR_FILTER_128,
+}
+
+
+CONFIG_SCHEMA_BASE = cv.Schema(
+    {
+        cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
+            unit_of_measurement=UNIT_CELSIUS,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_TEMPERATURE,
+            state_class=STATE_CLASS_MEASUREMENT,
+        ).extend(
+            {
+                cv.Optional(CONF_OVERSAMPLING, default="2X"): cv.enum(
+                    OVERSAMPLING_OPTIONS, upper=True
+                ),
+            }
+        ),
+        cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
+            unit_of_measurement=UNIT_HECTOPASCAL,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_PRESSURE,
+            state_class=STATE_CLASS_MEASUREMENT,
+        ).extend(
+            {
+                cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
+                    OVERSAMPLING_OPTIONS, upper=True
+                ),
+            }
+        ),
+        cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
+            IIR_FILTER_OPTIONS, upper=True
+        ),
+    }
+).extend(cv.polling_component_schema("60s"))
+
+
+async def to_code_base(config):
+    var = cg.new_Pvariable(config[CONF_ID])
+    await cg.register_component(var, config)
+
+    cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER]))
+    if temperature_config := config.get(CONF_TEMPERATURE):
+        sens = await sensor.new_sensor(temperature_config)
+        cg.add(var.set_temperature_sensor(sens))
+        cg.add(
+            var.set_temperature_oversampling_config(
+                temperature_config[CONF_OVERSAMPLING]
+            )
+        )
+
+    if pressure_config := config.get(CONF_PRESSURE):
+        sens = await sensor.new_sensor(pressure_config)
+        cg.add(var.set_pressure_sensor(sens))
+        cg.add(var.set_pressure_oversampling_config(pressure_config[CONF_OVERSAMPLING]))
+
+    return var
diff --git a/esphome/components/bmp3xx/bmp3xx.cpp b/esphome/components/bmp3xx_base/bmp3xx_base.cpp
similarity index 99%
rename from esphome/components/bmp3xx/bmp3xx.cpp
rename to esphome/components/bmp3xx_base/bmp3xx_base.cpp
index de28fd76ff..75b6812f81 100644
--- a/esphome/components/bmp3xx/bmp3xx.cpp
+++ b/esphome/components/bmp3xx_base/bmp3xx_base.cpp
@@ -5,13 +5,13 @@
   http://github.com/MartinL1/BMP388_DEV
 */
 
-#include "bmp3xx.h"
+#include "bmp3xx_base.h"
 #include "esphome/core/log.h"
 #include "esphome/core/hal.h"
 #include <cinttypes>
 
 namespace esphome {
-namespace bmp3xx {
+namespace bmp3xx_base {
 
 static const char *const TAG = "bmp3xx.sensor";
 
@@ -150,7 +150,6 @@ void BMP3XXComponent::setup() {
 void BMP3XXComponent::dump_config() {
   ESP_LOGCONFIG(TAG, "BMP3XX:");
   ESP_LOGCONFIG(TAG, "  Type: %s (0x%X)", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
-  LOG_I2C_DEVICE(this);
   switch (this->error_code_) {
     case NONE:
       break;
@@ -386,5 +385,5 @@ float BMP3XXComponent::bmp388_compensate_pressure_(float uncomp_press, float t_l
   return partial_out1 + partial_out2 + partial_data4;
 }
 
-}  // namespace bmp3xx
+}  // namespace bmp3xx_base
 }  // namespace esphome
diff --git a/esphome/components/bmp3xx/bmp3xx.h b/esphome/components/bmp3xx_base/bmp3xx_base.h
similarity index 94%
rename from esphome/components/bmp3xx/bmp3xx.h
rename to esphome/components/bmp3xx_base/bmp3xx_base.h
index d3b15f601d..50f92e04c1 100644
--- a/esphome/components/bmp3xx/bmp3xx.h
+++ b/esphome/components/bmp3xx_base/bmp3xx_base.h
@@ -9,10 +9,9 @@
 
 #include "esphome/core/component.h"
 #include "esphome/components/sensor/sensor.h"
-#include "esphome/components/i2c/i2c.h"
 
 namespace esphome {
-namespace bmp3xx {
+namespace bmp3xx_base {
 
 static const uint8_t BMP388_ID = 0x50;   // The BMP388 device ID
 static const uint8_t BMP390_ID = 0x60;   // The BMP390 device ID
@@ -69,8 +68,8 @@ enum IIRFilter {
   IIR_FILTER_128 = 0x07
 };
 
-/// This class implements support for the BMP3XX Temperature+Pressure i2c sensor.
-class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice {
+/// This class implements support for the BMP3XX Temperature+Pressure sensor.
+class BMP3XXComponent : public PollingComponent {
  public:
   void setup() override;
   void dump_config() override;
@@ -231,7 +230,13 @@ class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice {
   float bmp388_compensate_temperature_(float uncomp_temp);
   // Bosch pressure compensation function
   float bmp388_compensate_pressure_(float uncomp_press, float t_lin);
+
+  // interface specific functions
+  virtual bool read_byte(uint8_t a_register, uint8_t *data) = 0;
+  virtual bool write_byte(uint8_t a_register, uint8_t data) = 0;
+  virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0;
+  virtual bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0;
 };
 
-}  // namespace bmp3xx
+}  // namespace bmp3xx_base
 }  // namespace esphome
diff --git a/esphome/components/bmp3xx_i2c/__init__.py b/esphome/components/bmp3xx_i2c/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp
new file mode 100644
index 0000000000..7531090185
--- /dev/null
+++ b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.cpp
@@ -0,0 +1,29 @@
+#include "esphome/components/i2c/i2c.h"
+#include "bmp3xx_i2c.h"
+#include <cinttypes>
+
+namespace esphome {
+namespace bmp3xx_i2c {
+
+static const char *const TAG = "bmp3xx_i2c.sensor";
+
+bool BMP3XXI2CComponent::read_byte(uint8_t a_register, uint8_t *data) {
+  return I2CDevice::read_byte(a_register, data);
+};
+bool BMP3XXI2CComponent::write_byte(uint8_t a_register, uint8_t data) {
+  return I2CDevice::write_byte(a_register, data);
+};
+bool BMP3XXI2CComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
+  return I2CDevice::read_bytes(a_register, data, len);
+};
+bool BMP3XXI2CComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) {
+  return I2CDevice::write_bytes(a_register, data, len);
+};
+
+void BMP3XXI2CComponent::dump_config() {
+  LOG_I2C_DEVICE(this);
+  BMP3XXComponent::dump_config();
+}
+
+}  // namespace bmp3xx_i2c
+}  // namespace esphome
diff --git a/esphome/components/bmp3xx_i2c/bmp3xx_i2c.h b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.h
new file mode 100644
index 0000000000..d8b95cf843
--- /dev/null
+++ b/esphome/components/bmp3xx_i2c/bmp3xx_i2c.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "esphome/components/i2c/i2c.h"
+#include "esphome/components/bmp3xx_base/bmp3xx_base.h"
+
+namespace esphome {
+namespace bmp3xx_i2c {
+
+class BMP3XXI2CComponent : public bmp3xx_base::BMP3XXComponent, public i2c::I2CDevice {
+  bool read_byte(uint8_t a_register, uint8_t *data) override;
+  bool write_byte(uint8_t a_register, uint8_t data) override;
+  bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
+  bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
+  void dump_config() override;
+};
+
+}  // namespace bmp3xx_i2c
+}  // namespace esphome
diff --git a/esphome/components/bmp3xx_i2c/sensor.py b/esphome/components/bmp3xx_i2c/sensor.py
new file mode 100644
index 0000000000..ae59d29e89
--- /dev/null
+++ b/esphome/components/bmp3xx_i2c/sensor.py
@@ -0,0 +1,22 @@
+import esphome.codegen as cg
+from esphome.components import i2c
+from ..bmp3xx_base import to_code_base, cv, CONFIG_SCHEMA_BASE
+
+AUTO_LOAD = ["bmp3xx_base"]
+CODEOWNERS = ["@latonita"]
+DEPENDENCIES = ["i2c"]
+
+bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx_i2c")
+
+BMP3XXI2CComponent = bmp3xx_ns.class_(
+    "BMP3XXI2CComponent", cg.PollingComponent, i2c.I2CDevice
+)
+
+CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(
+    i2c.i2c_device_schema(default_address=0x77)
+).extend({cv.GenerateID(): cv.declare_id(BMP3XXI2CComponent)})
+
+
+async def to_code(config):
+    var = await to_code_base(config)
+    await i2c.register_i2c_device(var, config)
diff --git a/esphome/components/bmp3xx_spi/__init__.py b/esphome/components/bmp3xx_spi/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/esphome/components/bmp3xx_spi/bmp3xx_spi.cpp b/esphome/components/bmp3xx_spi/bmp3xx_spi.cpp
new file mode 100644
index 0000000000..2084530125
--- /dev/null
+++ b/esphome/components/bmp3xx_spi/bmp3xx_spi.cpp
@@ -0,0 +1,57 @@
+#include "bmp3xx_spi.h"
+#include <cinttypes>
+
+namespace esphome {
+namespace bmp3xx_spi {
+
+static const char *const TAG = "bmp3xx_spi.sensor";
+
+uint8_t set_bit(uint8_t num, int position) {
+  int mask = 1 << position;
+  return num | mask;
+}
+
+uint8_t clear_bit(uint8_t num, int position) {
+  int mask = 1 << position;
+  return num & ~mask;
+}
+
+void BMP3XXSPIComponent::setup() {
+  this->spi_setup();
+  BMP3XXComponent::setup();
+}
+
+bool BMP3XXSPIComponent::read_byte(uint8_t a_register, uint8_t *data) {
+  this->enable();
+  this->transfer_byte(set_bit(a_register, 7));
+  *data = this->transfer_byte(0);
+  this->disable();
+  return true;
+}
+
+bool BMP3XXSPIComponent::write_byte(uint8_t a_register, uint8_t data) {
+  this->enable();
+  this->transfer_byte(clear_bit(a_register, 7));
+  this->transfer_byte(data);
+  this->disable();
+  return true;
+}
+
+bool BMP3XXSPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
+  this->enable();
+  this->transfer_byte(set_bit(a_register, 7));
+  this->read_array(data, len);
+  this->disable();
+  return true;
+}
+
+bool BMP3XXSPIComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) {
+  this->enable();
+  this->transfer_byte(clear_bit(a_register, 7));
+  this->transfer_array(data, len);
+  this->disable();
+  return true;
+}
+
+}  // namespace bmp3xx_spi
+}  // namespace esphome
diff --git a/esphome/components/bmp3xx_spi/bmp3xx_spi.h b/esphome/components/bmp3xx_spi/bmp3xx_spi.h
new file mode 100644
index 0000000000..2183994abe
--- /dev/null
+++ b/esphome/components/bmp3xx_spi/bmp3xx_spi.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "esphome/components/bmp3xx_base/bmp3xx_base.h"
+#include "esphome/components/spi/spi.h"
+
+namespace esphome {
+namespace bmp3xx_spi {
+
+class BMP3XXSPIComponent : public bmp3xx_base::BMP3XXComponent,
+                           public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
+                                                 spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1MHZ> {
+  void setup() override;
+  bool read_byte(uint8_t a_register, uint8_t *data) override;
+  bool write_byte(uint8_t a_register, uint8_t data) override;
+  bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
+  bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
+};
+
+}  // namespace bmp3xx_spi
+}  // namespace esphome
diff --git a/esphome/components/bmp3xx_spi/sensor.py b/esphome/components/bmp3xx_spi/sensor.py
new file mode 100644
index 0000000000..3d1acd3c1b
--- /dev/null
+++ b/esphome/components/bmp3xx_spi/sensor.py
@@ -0,0 +1,22 @@
+import esphome.codegen as cg
+from esphome.components import spi
+from ..bmp3xx_base import to_code_base, cv, CONFIG_SCHEMA_BASE
+
+AUTO_LOAD = ["bmp3xx_base"]
+CODEOWNERS = ["@latonita"]
+DEPENDENCIES = ["spi"]
+
+bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx_spi")
+
+BMP3XXSPIComponent = bmp3xx_ns.class_(
+    "BMP3XXSPIComponent", cg.PollingComponent, spi.SPIDevice
+)
+
+CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend(
+    {cv.GenerateID(): cv.declare_id(BMP3XXSPIComponent)}
+)
+
+
+async def to_code(config):
+    var = await to_code_base(config)
+    await spi.register_spi_device(var, config)
diff --git a/tests/components/bmp3xx/test.esp32-c3-idf.yaml b/tests/components/bmp3xx/test.esp32-c3-idf.yaml
deleted file mode 100644
index 3b244eccf9..0000000000
--- a/tests/components/bmp3xx/test.esp32-c3-idf.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-i2c:
-  - id: i2c_bmp3xx
-    scl: 5
-    sda: 4
-
-sensor:
-  - platform: bmp3xx
-    address: 0x77
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    iir_filter: 2X
diff --git a/tests/components/bmp3xx/test.esp32-c3.yaml b/tests/components/bmp3xx/test.esp32-c3.yaml
deleted file mode 100644
index 3b244eccf9..0000000000
--- a/tests/components/bmp3xx/test.esp32-c3.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-i2c:
-  - id: i2c_bmp3xx
-    scl: 5
-    sda: 4
-
-sensor:
-  - platform: bmp3xx
-    address: 0x77
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    iir_filter: 2X
diff --git a/tests/components/bmp3xx/test.esp32.yaml b/tests/components/bmp3xx/test.esp32.yaml
deleted file mode 100644
index 677ed8a22d..0000000000
--- a/tests/components/bmp3xx/test.esp32.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-i2c:
-  - id: i2c_bmp3xx
-    scl: 16
-    sda: 17
-
-sensor:
-  - platform: bmp3xx
-    address: 0x77
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    iir_filter: 2X
diff --git a/tests/components/bmp3xx/test.esp8266.yaml b/tests/components/bmp3xx/test.esp8266.yaml
deleted file mode 100644
index 3b244eccf9..0000000000
--- a/tests/components/bmp3xx/test.esp8266.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-i2c:
-  - id: i2c_bmp3xx
-    scl: 5
-    sda: 4
-
-sensor:
-  - platform: bmp3xx
-    address: 0x77
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    iir_filter: 2X
diff --git a/tests/components/bmp3xx/test.rp2040.yaml b/tests/components/bmp3xx/test.rp2040.yaml
deleted file mode 100644
index 3b244eccf9..0000000000
--- a/tests/components/bmp3xx/test.rp2040.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-i2c:
-  - id: i2c_bmp3xx
-    scl: 5
-    sda: 4
-
-sensor:
-  - platform: bmp3xx
-    address: 0x77
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    iir_filter: 2X
diff --git a/tests/components/bmp3xx/test.esp32-idf.yaml b/tests/components/bmp3xx_i2c/common.yaml
similarity index 66%
rename from tests/components/bmp3xx/test.esp32-idf.yaml
rename to tests/components/bmp3xx_i2c/common.yaml
index 677ed8a22d..6641b7a1b8 100644
--- a/tests/components/bmp3xx/test.esp32-idf.yaml
+++ b/tests/components/bmp3xx_i2c/common.yaml
@@ -1,10 +1,11 @@
 i2c:
   - id: i2c_bmp3xx
-    scl: 16
-    sda: 17
+    scl: ${scl_pin}
+    sda: ${sda_pin}
 
 sensor:
-  - platform: bmp3xx
+  - platform: bmp3xx_i2c
+    i2c_id: i2c_bmp3xx
     address: 0x77
     temperature:
       name: BMP Temperature
diff --git a/tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml b/tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/bmp3xx_i2c/test.esp32-c3-idf.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_i2c/test.esp32-c3.yaml b/tests/components/bmp3xx_i2c/test.esp32-c3.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/bmp3xx_i2c/test.esp32-c3.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_i2c/test.esp32-idf.yaml b/tests/components/bmp3xx_i2c/test.esp32-idf.yaml
new file mode 100644
index 0000000000..63c3bd6afd
--- /dev/null
+++ b/tests/components/bmp3xx_i2c/test.esp32-idf.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO16
+  sda_pin: GPIO17
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_i2c/test.esp32.yaml b/tests/components/bmp3xx_i2c/test.esp32.yaml
new file mode 100644
index 0000000000..63c3bd6afd
--- /dev/null
+++ b/tests/components/bmp3xx_i2c/test.esp32.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO16
+  sda_pin: GPIO17
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_i2c/test.esp8266.yaml b/tests/components/bmp3xx_i2c/test.esp8266.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/bmp3xx_i2c/test.esp8266.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_i2c/test.rp2040.yaml b/tests/components/bmp3xx_i2c/test.rp2040.yaml
new file mode 100644
index 0000000000..ee2c29ca4e
--- /dev/null
+++ b/tests/components/bmp3xx_i2c/test.rp2040.yaml
@@ -0,0 +1,5 @@
+substitutions:
+  scl_pin: GPIO5
+  sda_pin: GPIO4
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_spi/common.yaml b/tests/components/bmp3xx_spi/common.yaml
new file mode 100644
index 0000000000..8d5f897661
--- /dev/null
+++ b/tests/components/bmp3xx_spi/common.yaml
@@ -0,0 +1,16 @@
+spi:
+  - id: spi_bmp3xx
+    clk_pin: ${clk_pin}
+    mosi_pin: ${mosi_pin}
+    miso_pin: ${miso_pin}
+
+sensor:
+  - platform: bmp3xx_spi
+    spi_id: spi_bmp3xx
+    cs_pin: ${cs_pin}
+    temperature:
+      name: BMP Temperature
+      oversampling: 16x
+    pressure:
+      name: BMP Pressure
+    iir_filter: 2X
diff --git a/tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml b/tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml
new file mode 100644
index 0000000000..2415ba5dc6
--- /dev/null
+++ b/tests/components/bmp3xx_spi/test.esp32-c3-idf.yaml
@@ -0,0 +1,7 @@
+substitutions:
+  clk_pin: GPIO6
+  mosi_pin: GPIO7
+  miso_pin: GPIO5
+  cs_pin: GPIO8
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_spi/test.esp32-c3.yaml b/tests/components/bmp3xx_spi/test.esp32-c3.yaml
new file mode 100644
index 0000000000..2415ba5dc6
--- /dev/null
+++ b/tests/components/bmp3xx_spi/test.esp32-c3.yaml
@@ -0,0 +1,7 @@
+substitutions:
+  clk_pin: GPIO6
+  mosi_pin: GPIO7
+  miso_pin: GPIO5
+  cs_pin: GPIO8
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_spi/test.esp32-idf.yaml b/tests/components/bmp3xx_spi/test.esp32-idf.yaml
new file mode 100644
index 0000000000..54e027a614
--- /dev/null
+++ b/tests/components/bmp3xx_spi/test.esp32-idf.yaml
@@ -0,0 +1,7 @@
+substitutions:
+  clk_pin: GPIO16
+  mosi_pin: GPIO17
+  miso_pin: GPIO15
+  cs_pin: GPIO5
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_spi/test.esp32.yaml b/tests/components/bmp3xx_spi/test.esp32.yaml
new file mode 100644
index 0000000000..54e027a614
--- /dev/null
+++ b/tests/components/bmp3xx_spi/test.esp32.yaml
@@ -0,0 +1,7 @@
+substitutions:
+  clk_pin: GPIO16
+  mosi_pin: GPIO17
+  miso_pin: GPIO15
+  cs_pin: GPIO5
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_spi/test.esp8266.yaml b/tests/components/bmp3xx_spi/test.esp8266.yaml
new file mode 100644
index 0000000000..dbd158d030
--- /dev/null
+++ b/tests/components/bmp3xx_spi/test.esp8266.yaml
@@ -0,0 +1,7 @@
+substitutions:
+  clk_pin: GPIO14
+  mosi_pin: GPIO13
+  miso_pin: GPIO12
+  cs_pin: GPIO15
+
+<<: !include common.yaml
diff --git a/tests/components/bmp3xx_spi/test.rp2040.yaml b/tests/components/bmp3xx_spi/test.rp2040.yaml
new file mode 100644
index 0000000000..f6c3f1eeca
--- /dev/null
+++ b/tests/components/bmp3xx_spi/test.rp2040.yaml
@@ -0,0 +1,7 @@
+substitutions:
+  clk_pin: GPIO2
+  mosi_pin: GPIO3
+  miso_pin: GPIO4
+  cs_pin: GPIO5
+
+<<: !include common.yaml
diff --git a/tests/test11.5.yaml b/tests/test11.5.yaml
index ef260d79c0..13de7f1929 100644
--- a/tests/test11.5.yaml
+++ b/tests/test11.5.yaml
@@ -498,15 +498,6 @@ sensor:
     co2:
       name: CO2 Sensor
 
-  - platform: bmp3xx
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    address: 0x77
-    iir_filter: 2X
-
   - platform: sen5x
     id: sen54
     temperature:
diff --git a/tests/test5.yaml b/tests/test5.yaml
index 81615b24b0..afd3359098 100644
--- a/tests/test5.yaml
+++ b/tests/test5.yaml
@@ -474,15 +474,6 @@ sensor:
     co2:
       name: CO2 Sensor
 
-  - platform: bmp3xx
-    temperature:
-      name: BMP Temperature
-      oversampling: 16x
-    pressure:
-      name: BMP Pressure
-    address: 0x77
-    iir_filter: 2X
-
   - platform: ms8607
     temperature:
       name: Temperature