esphome 2024.11.2__py3-none-any.whl → 2024.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. esphome/__main__.py +1 -1
  2. esphome/components/adc/adc_sensor.h +7 -8
  3. esphome/components/adc/adc_sensor_common.cpp +24 -0
  4. esphome/components/adc/{adc_sensor.cpp → adc_sensor_esp32.cpp} +10 -179
  5. esphome/components/adc/adc_sensor_esp8266.cpp +58 -0
  6. esphome/components/adc/adc_sensor_libretiny.cpp +48 -0
  7. esphome/components/adc/adc_sensor_rp2040.cpp +93 -0
  8. esphome/components/alarm_control_panel/alarm_control_panel_call.cpp +3 -4
  9. esphome/components/animation/__init__.py +1 -2
  10. esphome/components/apds9306/apds9306.cpp +2 -1
  11. esphome/components/audio/audio.h +1 -1
  12. esphome/components/bk72xx/__init__.py +1 -1
  13. esphome/components/cse7766/cse7766.cpp +1 -1
  14. esphome/components/datetime/datetime_entity.cpp +1 -3
  15. esphome/components/deep_sleep/deep_sleep_esp32.cpp +2 -2
  16. esphome/components/dht/dht.cpp +2 -1
  17. esphome/components/display/display.cpp +10 -6
  18. esphome/components/display/display.h +14 -0
  19. esphome/components/display_menu_base/__init__.py +0 -2
  20. esphome/components/display_menu_base/display_menu_base.cpp +1 -1
  21. esphome/components/dsmr/dsmr.cpp +1 -1
  22. esphome/components/esp32/__init__.py +100 -22
  23. esphome/components/esp32/boards.py +222 -14
  24. esphome/components/esp32_ble/__init__.py +22 -2
  25. esphome/components/esp32_ble/ble.cpp +39 -12
  26. esphome/components/esp32_ble/ble.h +2 -0
  27. esphome/components/esp32_ble/ble_advertising.cpp +1 -1
  28. esphome/components/esp32_ble/ble_uuid.cpp +9 -10
  29. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +4 -1
  30. esphome/components/esp32_camera_web_server/camera_web_server.h +1 -1
  31. esphome/components/esp32_rmt_led_strip/light.py +3 -3
  32. esphome/components/esp8266/__init__.py +5 -7
  33. esphome/components/ezo/ezo.cpp +14 -26
  34. esphome/components/font/__init__.py +10 -25
  35. esphome/components/font/font.cpp +5 -3
  36. esphome/components/graphical_display_menu/__init__.py +2 -0
  37. esphome/components/haier/hon_climate.cpp +79 -80
  38. esphome/components/hbridge/switch/__init__.py +44 -0
  39. esphome/components/hbridge/switch/hbridge_switch.cpp +95 -0
  40. esphome/components/hbridge/switch/hbridge_switch.h +50 -0
  41. esphome/components/hitachi_ac344/hitachi_ac344.cpp +4 -2
  42. esphome/components/hitachi_ac424/hitachi_ac424.cpp +4 -2
  43. esphome/components/homeassistant/number/homeassistant_number.cpp +3 -0
  44. esphome/components/hx711/hx711.cpp +1 -1
  45. esphome/components/hx711/hx711.h +1 -1
  46. esphome/components/i2c/i2c_bus_esp_idf.cpp +2 -2
  47. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +61 -59
  48. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -17
  49. esphome/components/ili9xxx/display.py +1 -2
  50. esphome/components/ili9xxx/ili9xxx_display.cpp +3 -2
  51. esphome/components/image/__init__.py +1 -2
  52. esphome/components/logger/logger.cpp +1 -1
  53. esphome/components/ltr501/ltr501.cpp +1 -1
  54. esphome/components/lvgl/defines.py +9 -2
  55. esphome/components/lvgl/lv_validation.py +8 -3
  56. esphome/components/lvgl/lvgl_esphome.cpp +1 -1
  57. esphome/components/lvgl/lvgl_esphome.h +19 -0
  58. esphome/components/lvgl/widgets/animimg.py +12 -17
  59. esphome/components/lvgl/widgets/img.py +1 -3
  60. esphome/components/lvgl/widgets/line.py +6 -0
  61. esphome/components/lvgl/widgets/msgbox.py +2 -1
  62. esphome/components/matrix_keypad/__init__.py +15 -3
  63. esphome/components/matrix_keypad/matrix_keypad.cpp +4 -0
  64. esphome/components/matrix_keypad/matrix_keypad.h +5 -0
  65. esphome/components/max31865/max31865.cpp +4 -2
  66. esphome/components/modbus_controller/modbus_controller.cpp +24 -24
  67. esphome/components/modbus_controller/modbus_controller.h +22 -22
  68. esphome/components/modbus_controller/number/modbus_number.cpp +8 -8
  69. esphome/components/modbus_controller/number/modbus_number.h +4 -4
  70. esphome/components/modbus_controller/output/modbus_output.cpp +7 -6
  71. esphome/components/modbus_controller/output/modbus_output.h +5 -5
  72. esphome/components/modbus_controller/select/modbus_select.cpp +4 -3
  73. esphome/components/modbus_controller/select/modbus_select.h +4 -4
  74. esphome/components/modbus_controller/switch/modbus_switch.cpp +5 -5
  75. esphome/components/modbus_controller/switch/modbus_switch.h +2 -2
  76. esphome/components/mqtt/__init__.py +4 -0
  77. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -5
  78. esphome/components/mqtt/mqtt_backend_esp32.cpp +3 -3
  79. esphome/components/mqtt/mqtt_client.cpp +4 -0
  80. esphome/components/mqtt/mqtt_client.h +6 -0
  81. esphome/components/mqtt/mqtt_climate.cpp +13 -3
  82. esphome/components/mqtt/mqtt_sensor.cpp +2 -0
  83. esphome/components/network/ip_address.h +1 -1
  84. esphome/components/nextion/__init__.py +2 -0
  85. esphome/components/nextion/automation.h +76 -0
  86. esphome/components/nextion/base_component.py +1 -0
  87. esphome/components/nextion/binary_sensor/__init__.py +43 -2
  88. esphome/components/nextion/display.py +15 -0
  89. esphome/components/nextion/nextion.cpp +8 -5
  90. esphome/components/nextion/nextion.h +7 -0
  91. esphome/components/nextion/nextion_upload_idf.cpp +2 -2
  92. esphome/components/nextion/sensor/__init__.py +38 -5
  93. esphome/components/nextion/switch/__init__.py +38 -2
  94. esphome/components/nextion/text_sensor/__init__.py +37 -2
  95. esphome/components/nfc/ndef_record.cpp +3 -3
  96. esphome/components/online_image/__init__.py +1 -0
  97. esphome/components/online_image/png_image.cpp +4 -0
  98. esphome/components/opentherm/hub.cpp +6 -7
  99. esphome/components/opentherm/opentherm.cpp +18 -34
  100. esphome/components/opentherm/opentherm.h +4 -5
  101. esphome/components/ota/automation.h +1 -1
  102. esphome/components/output/float_output.cpp +1 -1
  103. esphome/components/pca6416a/pca6416a.cpp +5 -3
  104. esphome/components/pca9554/pca9554.cpp +4 -4
  105. esphome/components/pipsolar/pipsolar.cpp +2 -2
  106. esphome/components/pipsolar/switch/pipsolar_switch.cpp +2 -2
  107. esphome/components/pn532/pn532_mifare_ultralight.cpp +2 -2
  108. esphome/components/pn7150/pn7150_mifare_ultralight.cpp +2 -2
  109. esphome/components/pn7160/pn7160_mifare_ultralight.cpp +2 -2
  110. esphome/components/qmc5883l/qmc5883l.cpp +45 -19
  111. esphome/components/qmc5883l/qmc5883l.h +1 -1
  112. esphome/components/qspi_dbi/qspi_dbi.cpp +2 -1
  113. esphome/components/remote_base/raw_protocol.cpp +1 -1
  114. esphome/components/remote_receiver/__init__.py +5 -6
  115. esphome/components/rotary_encoder/rotary_encoder.cpp +3 -1
  116. esphome/components/rp2040/__init__.py +1 -1
  117. esphome/components/rtl87xx/__init__.py +1 -1
  118. esphome/components/safe_mode/automation.h +1 -1
  119. esphome/components/seeed_mr60bha2/__init__.py +41 -0
  120. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +173 -0
  121. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +61 -0
  122. esphome/components/seeed_mr60bha2/sensor.py +57 -0
  123. esphome/components/seeed_mr60fda2/__init__.py +41 -0
  124. esphome/components/seeed_mr60fda2/binary_sensor.py +33 -0
  125. esphome/components/seeed_mr60fda2/button/__init__.py +45 -0
  126. esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.cpp +9 -0
  127. esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.h +18 -0
  128. esphome/components/seeed_mr60fda2/button/reset_radar_button.cpp +9 -0
  129. esphome/components/seeed_mr60fda2/button/reset_radar_button.h +18 -0
  130. esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +368 -0
  131. esphome/components/seeed_mr60fda2/seeed_mr60fda2.h +101 -0
  132. esphome/components/seeed_mr60fda2/select/__init__.py +59 -0
  133. esphome/components/seeed_mr60fda2/select/height_threshold_select.cpp +15 -0
  134. esphome/components/seeed_mr60fda2/select/height_threshold_select.h +18 -0
  135. esphome/components/seeed_mr60fda2/select/install_height_select.cpp +15 -0
  136. esphome/components/seeed_mr60fda2/select/install_height_select.h +18 -0
  137. esphome/components/seeed_mr60fda2/select/sensitivity_select.cpp +15 -0
  138. esphome/components/seeed_mr60fda2/select/sensitivity_select.h +18 -0
  139. esphome/components/sen5x/sensor.py +5 -6
  140. esphome/components/sgp30/sensor.py +8 -9
  141. esphome/components/sgp30/sgp30.cpp +2 -6
  142. esphome/components/shelly_dimmer/shelly_dimmer.cpp +1 -1
  143. esphome/components/sim800l/sim800l.cpp +1 -1
  144. esphome/components/sntp/sntp_component.cpp +14 -20
  145. esphome/components/sntp/sntp_component.h +6 -9
  146. esphome/components/sntp/time.py +4 -7
  147. esphome/components/sprinkler/sprinkler.cpp +2 -2
  148. esphome/components/st7735/st7735.cpp +1 -1
  149. esphome/components/st7789v/st7789v.cpp +1 -1
  150. esphome/components/st7920/st7920.cpp +2 -3
  151. esphome/components/stepper/stepper.h +0 -1
  152. esphome/components/sun_gtil2/sun_gtil2.cpp +1 -1
  153. esphome/components/switch/binary_sensor/__init__.py +31 -0
  154. esphome/components/switch/binary_sensor/switch_binary_sensor.cpp +17 -0
  155. esphome/components/switch/binary_sensor/switch_binary_sensor.h +22 -0
  156. esphome/components/sx1509/sx1509_gpio_pin.cpp +2 -1
  157. esphome/components/sx1509/sx1509_gpio_pin.h +5 -5
  158. esphome/components/uart/uart.h +1 -1
  159. esphome/components/udp/udp_component.cpp +32 -16
  160. esphome/components/ufire_ec/sensor.py +4 -4
  161. esphome/components/uln2003/uln2003.cpp +4 -1
  162. esphome/components/waveshare_epaper/display.py +8 -0
  163. esphome/components/waveshare_epaper/waveshare_epaper.cpp +191 -0
  164. esphome/components/waveshare_epaper/waveshare_epaper.h +56 -0
  165. esphome/components/wiegand/__init__.py +3 -4
  166. esphome/components/wifi/__init__.py +42 -0
  167. esphome/components/wifi/wifi_component.cpp +2 -2
  168. esphome/components/wifi/wifi_component.h +82 -1
  169. esphome/components/wifi/wifi_component_esp32_arduino.cpp +1 -1
  170. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  171. esphome/components/wifi/wifi_component_esp_idf.cpp +1 -1
  172. esphome/components/wifi/wifi_component_libretiny.cpp +1 -1
  173. esphome/components/wifi/wifi_component_pico_w.cpp +1 -1
  174. esphome/components/wireguard/wireguard.cpp +2 -2
  175. esphome/components/xiaomi_ble/xiaomi_ble.cpp +1 -1
  176. esphome/config_validation.py +15 -11
  177. esphome/const.py +11 -1
  178. esphome/core/component.cpp +1 -1
  179. esphome/core/config.py +1 -2
  180. esphome/core/defines.h +3 -1
  181. esphome/core/helpers.cpp +20 -2
  182. esphome/core/helpers.h +10 -1
  183. esphome/core/optional.h +2 -2
  184. esphome/core/time.cpp +19 -15
  185. esphome/core/time.h +1 -3
  186. esphome/dashboard/web_server.py +6 -0
  187. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/METADATA +4 -4
  188. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/RECORD +192 -162
  189. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/LICENSE +0 -0
  190. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/WHEEL +0 -0
  191. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/entry_points.txt +0 -0
  192. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,44 @@
1
+ from esphome import pins
2
+ import esphome.codegen as cg
3
+ from esphome.components import switch
4
+ import esphome.config_validation as cv
5
+ from esphome.const import CONF_OPTIMISTIC, CONF_PULSE_LENGTH, CONF_WAIT_TIME
6
+
7
+ from .. import hbridge_ns
8
+
9
+ HBridgeSwitch = hbridge_ns.class_("HBridgeSwitch", switch.Switch, cg.Component)
10
+
11
+ CODEOWNERS = ["@dwmw2"]
12
+
13
+ CONF_OFF_PIN = "off_pin"
14
+ CONF_ON_PIN = "on_pin"
15
+
16
+ CONFIG_SCHEMA = (
17
+ switch.switch_schema(HBridgeSwitch)
18
+ .extend(
19
+ {
20
+ cv.Required(CONF_ON_PIN): pins.gpio_output_pin_schema,
21
+ cv.Required(CONF_OFF_PIN): pins.gpio_output_pin_schema,
22
+ cv.Optional(
23
+ CONF_PULSE_LENGTH, default="100ms"
24
+ ): cv.positive_time_period_milliseconds,
25
+ cv.Optional(CONF_WAIT_TIME): cv.positive_time_period_milliseconds,
26
+ cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
27
+ }
28
+ )
29
+ .extend(cv.COMPONENT_SCHEMA)
30
+ )
31
+
32
+
33
+ async def to_code(config):
34
+ var = await switch.new_switch(config)
35
+ await cg.register_component(var, config)
36
+
37
+ on_pin = await cg.gpio_pin_expression(config[CONF_ON_PIN])
38
+ cg.add(var.set_on_pin(on_pin))
39
+ off_pin = await cg.gpio_pin_expression(config[CONF_OFF_PIN])
40
+ cg.add(var.set_off_pin(off_pin))
41
+ cg.add(var.set_pulse_length(config[CONF_PULSE_LENGTH]))
42
+ cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
43
+ if wait_time := config.get(CONF_WAIT_TIME):
44
+ cg.add(var.set_wait_time(wait_time))
@@ -0,0 +1,95 @@
1
+ #include "hbridge_switch.h"
2
+ #include "esphome/core/log.h"
3
+
4
+ #include <cinttypes>
5
+
6
+ namespace esphome {
7
+ namespace hbridge {
8
+
9
+ static const char *const TAG = "switch.hbridge";
10
+
11
+ float HBridgeSwitch::get_setup_priority() const { return setup_priority::HARDWARE; }
12
+ void HBridgeSwitch::setup() {
13
+ ESP_LOGCONFIG(TAG, "Setting up H-Bridge Switch '%s'...", this->name_.c_str());
14
+
15
+ optional<bool> initial_state = this->get_initial_state_with_restore_mode().value_or(false);
16
+
17
+ // Like GPIOSwitch does, set the pin state both before and after pin setup()
18
+ this->on_pin_->digital_write(false);
19
+ this->on_pin_->setup();
20
+ this->on_pin_->digital_write(false);
21
+
22
+ this->off_pin_->digital_write(false);
23
+ this->off_pin_->setup();
24
+ this->off_pin_->digital_write(false);
25
+
26
+ if (initial_state.has_value())
27
+ this->write_state(initial_state);
28
+ }
29
+
30
+ void HBridgeSwitch::dump_config() {
31
+ LOG_SWITCH("", "H-Bridge Switch", this);
32
+ LOG_PIN(" On Pin: ", this->on_pin_);
33
+ LOG_PIN(" Off Pin: ", this->off_pin_);
34
+ ESP_LOGCONFIG(TAG, " Pulse length: %" PRId32 " ms", this->pulse_length_);
35
+ if (this->wait_time_)
36
+ ESP_LOGCONFIG(TAG, " Wait time %" PRId32 " ms", this->wait_time_);
37
+ }
38
+
39
+ void HBridgeSwitch::write_state(bool state) {
40
+ this->desired_state_ = state;
41
+ if (!this->timer_running_)
42
+ this->timer_fn_();
43
+ }
44
+
45
+ void HBridgeSwitch::timer_fn_() {
46
+ uint32_t next_timeout = 0;
47
+
48
+ while ((uint8_t) this->desired_state_ != this->relay_state_) {
49
+ switch (this->relay_state_) {
50
+ case RELAY_STATE_ON:
51
+ case RELAY_STATE_OFF:
52
+ case RELAY_STATE_UNKNOWN:
53
+ if (this->desired_state_) {
54
+ this->on_pin_->digital_write(true);
55
+ this->relay_state_ = RELAY_STATE_SWITCHING_ON;
56
+ } else {
57
+ this->off_pin_->digital_write(true);
58
+ this->relay_state_ = RELAY_STATE_SWITCHING_OFF;
59
+ }
60
+ next_timeout = this->pulse_length_;
61
+ if (!this->optimistic_)
62
+ this->publish_state(this->desired_state_);
63
+ break;
64
+
65
+ case RELAY_STATE_SWITCHING_ON:
66
+ this->on_pin_->digital_write(false);
67
+ this->relay_state_ = RELAY_STATE_ON;
68
+ if (this->optimistic_)
69
+ this->publish_state(true);
70
+ next_timeout = this->wait_time_;
71
+ break;
72
+
73
+ case RELAY_STATE_SWITCHING_OFF:
74
+ this->off_pin_->digital_write(false);
75
+ this->relay_state_ = RELAY_STATE_OFF;
76
+ if (this->optimistic_)
77
+ this->publish_state(false);
78
+ next_timeout = this->wait_time_;
79
+ break;
80
+ }
81
+
82
+ if (next_timeout) {
83
+ this->timer_running_ = true;
84
+ this->set_timeout(next_timeout, [this]() { this->timer_fn_(); });
85
+ return;
86
+ }
87
+
88
+ // In the case where ON/OFF state has been reached but we need to
89
+ // immediately change back again to reach desired_state_, we loop.
90
+ }
91
+ this->timer_running_ = false;
92
+ }
93
+
94
+ } // namespace hbridge
95
+ } // namespace esphome
@@ -0,0 +1,50 @@
1
+ #pragma once
2
+
3
+ #include "esphome/core/component.h"
4
+ #include "esphome/core/hal.h"
5
+ #include "esphome/components/switch/switch.h"
6
+
7
+ #include <vector>
8
+
9
+ namespace esphome {
10
+ namespace hbridge {
11
+
12
+ enum RelayState : uint8_t {
13
+ RELAY_STATE_OFF = 0,
14
+ RELAY_STATE_ON = 1,
15
+ RELAY_STATE_SWITCHING_ON = 2,
16
+ RELAY_STATE_SWITCHING_OFF = 3,
17
+ RELAY_STATE_UNKNOWN = 4,
18
+ };
19
+
20
+ class HBridgeSwitch : public switch_::Switch, public Component {
21
+ public:
22
+ void set_on_pin(GPIOPin *pin) { this->on_pin_ = pin; }
23
+ void set_off_pin(GPIOPin *pin) { this->off_pin_ = pin; }
24
+ void set_pulse_length(uint32_t pulse_length) { this->pulse_length_ = pulse_length; }
25
+ void set_wait_time(uint32_t wait_time) { this->wait_time_ = wait_time; }
26
+ void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
27
+
28
+ // ========== INTERNAL METHODS ==========
29
+ // (In most use cases you won't need these)
30
+ float get_setup_priority() const override;
31
+
32
+ void setup() override;
33
+ void dump_config() override;
34
+
35
+ protected:
36
+ void write_state(bool state) override;
37
+ void timer_fn_();
38
+
39
+ bool timer_running_{false};
40
+ bool desired_state_{false};
41
+ RelayState relay_state_{RELAY_STATE_UNKNOWN};
42
+ GPIOPin *on_pin_{nullptr};
43
+ GPIOPin *off_pin_{nullptr};
44
+ uint32_t pulse_length_{0};
45
+ uint32_t wait_time_{0};
46
+ bool optimistic_{false};
47
+ };
48
+
49
+ } // namespace hbridge
50
+ } // namespace esphome
@@ -133,8 +133,10 @@ bool HitachiClimate::get_swing_v_() {
133
133
  }
134
134
 
135
135
  void HitachiClimate::set_swing_h_(uint8_t position) {
136
- if (position > HITACHI_AC344_SWINGH_LEFT_MAX)
137
- return set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
136
+ if (position > HITACHI_AC344_SWINGH_LEFT_MAX) {
137
+ set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
138
+ return;
139
+ }
138
140
  set_bits(&remote_state_[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE, position);
139
141
  set_button_(HITACHI_AC344_BUTTON_SWINGH);
140
142
  }
@@ -133,8 +133,10 @@ bool HitachiClimate::get_swing_v_() {
133
133
  }
134
134
 
135
135
  void HitachiClimate::set_swing_h_(uint8_t position) {
136
- if (position > HITACHI_AC424_SWINGH_LEFT_MAX)
137
- return set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
136
+ if (position > HITACHI_AC424_SWINGH_LEFT_MAX) {
137
+ set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
138
+ return;
139
+ }
138
140
  set_bits(&remote_state_[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET, HITACHI_AC424_SWINGH_SIZE, position);
139
141
  set_button_(HITACHI_AC424_BUTTON_SWINGH);
140
142
  }
@@ -27,6 +27,7 @@ void HomeassistantNumber::min_retrieved_(const std::string &min) {
27
27
  auto min_value = parse_number<float>(min);
28
28
  if (!min_value.has_value()) {
29
29
  ESP_LOGE(TAG, "'%s': Can't convert 'min' value '%s' to number!", this->entity_id_.c_str(), min.c_str());
30
+ return;
30
31
  }
31
32
  ESP_LOGD(TAG, "'%s': Min retrieved: %s", get_name().c_str(), min.c_str());
32
33
  this->traits.set_min_value(min_value.value());
@@ -36,6 +37,7 @@ void HomeassistantNumber::max_retrieved_(const std::string &max) {
36
37
  auto max_value = parse_number<float>(max);
37
38
  if (!max_value.has_value()) {
38
39
  ESP_LOGE(TAG, "'%s': Can't convert 'max' value '%s' to number!", this->entity_id_.c_str(), max.c_str());
40
+ return;
39
41
  }
40
42
  ESP_LOGD(TAG, "'%s': Max retrieved: %s", get_name().c_str(), max.c_str());
41
43
  this->traits.set_max_value(max_value.value());
@@ -45,6 +47,7 @@ void HomeassistantNumber::step_retrieved_(const std::string &step) {
45
47
  auto step_value = parse_number<float>(step);
46
48
  if (!step_value.has_value()) {
47
49
  ESP_LOGE(TAG, "'%s': Can't convert 'step' value '%s' to number!", this->entity_id_.c_str(), step.c_str());
50
+ return;
48
51
  }
49
52
  ESP_LOGD(TAG, "'%s': Step Retrieved %s", get_name().c_str(), step.c_str());
50
53
  this->traits.set_step(step_value.value());
@@ -53,7 +53,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
53
53
  }
54
54
 
55
55
  // Cycle clock pin for gain setting
56
- for (uint8_t i = 0; i < this->gain_; i++) {
56
+ for (uint8_t i = 0; i < static_cast<uint8_t>(this->gain_); i++) {
57
57
  this->sck_pin_->digital_write(true);
58
58
  delayMicroseconds(1);
59
59
  this->sck_pin_->digital_write(false);
@@ -9,7 +9,7 @@
9
9
  namespace esphome {
10
10
  namespace hx711 {
11
11
 
12
- enum HX711Gain {
12
+ enum HX711Gain : uint8_t {
13
13
  HX711_GAIN_128 = 1,
14
14
  HX711_GAIN_32 = 2,
15
15
  HX711_GAIN_64 = 3,
@@ -17,14 +17,14 @@ void IDFI2CBus::setup() {
17
17
  ESP_LOGCONFIG(TAG, "Setting up I2C bus...");
18
18
  static i2c_port_t next_port = I2C_NUM_0;
19
19
  port_ = next_port;
20
- #if I2C_NUM_MAX > 1
20
+ #if SOC_I2C_NUM > 1
21
21
  next_port = (next_port == I2C_NUM_0) ? I2C_NUM_1 : I2C_NUM_MAX;
22
22
  #else
23
23
  next_port = I2C_NUM_MAX;
24
24
  #endif
25
25
 
26
26
  if (port_ == I2C_NUM_MAX) {
27
- ESP_LOGE(TAG, "Too many I2C buses configured");
27
+ ESP_LOGE(TAG, "Too many I2C buses configured. Max %u supported.", SOC_I2C_NUM);
28
28
  this->mark_failed();
29
29
  return;
30
30
  }
@@ -33,14 +33,15 @@ enum SpeakerEventGroupBits : uint32_t {
33
33
  STATE_RUNNING = (1 << 11),
34
34
  STATE_STOPPING = (1 << 12),
35
35
  STATE_STOPPED = (1 << 13),
36
- ERR_INVALID_FORMAT = (1 << 14),
37
- ERR_TASK_FAILED_TO_START = (1 << 15),
38
- ERR_ESP_INVALID_STATE = (1 << 16),
36
+ ERR_TASK_FAILED_TO_START = (1 << 14),
37
+ ERR_ESP_INVALID_STATE = (1 << 15),
38
+ ERR_ESP_NOT_SUPPORTED = (1 << 16),
39
39
  ERR_ESP_INVALID_ARG = (1 << 17),
40
40
  ERR_ESP_INVALID_SIZE = (1 << 18),
41
41
  ERR_ESP_NO_MEM = (1 << 19),
42
42
  ERR_ESP_FAIL = (1 << 20),
43
- ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | ERR_ESP_NO_MEM | ERR_ESP_FAIL,
43
+ ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_NOT_SUPPORTED | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE |
44
+ ERR_ESP_NO_MEM | ERR_ESP_FAIL,
44
45
  ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
45
46
  };
46
47
 
@@ -55,6 +56,8 @@ static esp_err_t err_bit_to_esp_err(uint32_t bit) {
55
56
  return ESP_ERR_INVALID_SIZE;
56
57
  case SpeakerEventGroupBits::ERR_ESP_NO_MEM:
57
58
  return ESP_ERR_NO_MEM;
59
+ case SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED:
60
+ return ESP_ERR_NOT_SUPPORTED;
58
61
  default:
59
62
  return ESP_FAIL;
60
63
  }
@@ -135,19 +138,19 @@ void I2SAudioSpeaker::loop() {
135
138
  xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
136
139
  }
137
140
 
138
- if (event_group_bits & SpeakerEventGroupBits::ERR_INVALID_FORMAT) {
141
+ if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
142
+ uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
143
+ ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
144
+ this->status_set_warning();
145
+ }
146
+
147
+ if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED) {
139
148
  this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
140
149
  ESP_LOGE(TAG,
141
150
  "Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
142
151
  this->audio_stream_info_.sample_rate, this->audio_stream_info_.channels,
143
152
  this->audio_stream_info_.bits_per_sample);
144
153
  }
145
-
146
- if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
147
- uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
148
- ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
149
- this->status_set_warning();
150
- }
151
154
  }
152
155
 
153
156
  void I2SAudioSpeaker::set_volume(float volume) {
@@ -236,13 +239,15 @@ void I2SAudioSpeaker::speaker_task(void *params) {
236
239
  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
237
240
 
238
241
  audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_;
239
- const ssize_t bytes_per_sample = audio_stream_info.get_bytes_per_sample();
240
- const uint8_t number_of_channels = audio_stream_info.channels;
241
242
 
242
- const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * this_speaker->sample_rate_ / 1000 *
243
- bytes_per_sample * number_of_channels;
243
+ const uint32_t bytes_per_ms =
244
+ audio_stream_info.channels * audio_stream_info.get_bytes_per_sample() * audio_stream_info.sample_rate / 1000;
245
+
246
+ const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * bytes_per_ms;
247
+
248
+ // Ensure ring buffer is at least as large as the total size of the DMA buffers
244
249
  const size_t ring_buffer_size =
245
- this_speaker->buffer_duration_ms_ * this_speaker->sample_rate_ / 1000 * bytes_per_sample * number_of_channels;
250
+ std::max((uint32_t) dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms);
246
251
 
247
252
  if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) {
248
253
  // Failed to allocate buffers
@@ -250,14 +255,7 @@ void I2SAudioSpeaker::speaker_task(void *params) {
250
255
  this_speaker->delete_task_(dma_buffers_size);
251
256
  }
252
257
 
253
- if (this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_())) {
254
- // Failed to start I2S driver
255
- this_speaker->delete_task_(dma_buffers_size);
256
- }
257
-
258
- if (!this_speaker->send_esp_err_to_event_group_(this_speaker->reconfigure_i2s_stream_info_(audio_stream_info))) {
259
- // Successfully set the I2S stream info, ready to write audio data to the I2S port
260
-
258
+ if (!this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_(audio_stream_info))) {
261
259
  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
262
260
 
263
261
  bool stop_gracefully = false;
@@ -275,6 +273,12 @@ void I2SAudioSpeaker::speaker_task(void *params) {
275
273
  stop_gracefully = true;
276
274
  }
277
275
 
276
+ if (this_speaker->audio_stream_info_ != audio_stream_info) {
277
+ // Audio stream info has changed, stop the speaker task so it will restart with the proper settings.
278
+
279
+ break;
280
+ }
281
+
278
282
  i2s_event_t i2s_event;
279
283
  while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
280
284
  if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
@@ -316,17 +320,14 @@ void I2SAudioSpeaker::speaker_task(void *params) {
316
320
  }
317
321
  }
318
322
  }
319
- } else {
320
- // Couldn't configure the I2S port to be compatible with the incoming audio
321
- xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_INVALID_FORMAT);
322
- }
323
- i2s_zero_dma_buffer(this_speaker->parent_->get_port());
324
323
 
325
- xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
324
+ xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
325
+
326
+ i2s_driver_uninstall(this_speaker->parent_->get_port());
326
327
 
327
- i2s_driver_uninstall(this_speaker->parent_->get_port());
328
+ this_speaker->parent_->unlock();
329
+ }
328
330
 
329
- this_speaker->parent_->unlock();
330
331
  this_speaker->delete_task_(dma_buffers_size);
331
332
  }
332
333
 
@@ -382,6 +383,9 @@ bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) {
382
383
  case ESP_ERR_NO_MEM:
383
384
  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
384
385
  return true;
386
+ case ESP_ERR_NOT_SUPPORTED:
387
+ xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED);
388
+ return true;
385
389
  default:
386
390
  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
387
391
  return true;
@@ -411,18 +415,40 @@ esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t rin
411
415
  return ESP_OK;
412
416
  }
413
417
 
414
- esp_err_t I2SAudioSpeaker::start_i2s_driver_() {
418
+ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info) {
419
+ if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.sample_rate)) { // NOLINT
420
+ // Can't reconfigure I2S bus, so the sample rate must match the configured value
421
+ return ESP_ERR_NOT_SUPPORTED;
422
+ }
423
+
424
+ if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) {
425
+ // Currently can't handle the case when the incoming audio has more bits per sample than the configured value
426
+ return ESP_ERR_NOT_SUPPORTED;
427
+ }
428
+
415
429
  if (!this->parent_->try_lock()) {
416
430
  return ESP_ERR_INVALID_STATE;
417
431
  }
418
432
 
433
+ i2s_channel_fmt_t channel = this->channel_;
434
+
435
+ if (audio_stream_info.channels == 1) {
436
+ if (this->channel_ == I2S_CHANNEL_FMT_ONLY_LEFT) {
437
+ channel = I2S_CHANNEL_FMT_ONLY_LEFT;
438
+ } else {
439
+ channel = I2S_CHANNEL_FMT_ONLY_RIGHT;
440
+ }
441
+ } else if (audio_stream_info.channels == 2) {
442
+ channel = I2S_CHANNEL_FMT_RIGHT_LEFT;
443
+ }
444
+
419
445
  int dma_buffer_length = DMA_BUFFER_DURATION_MS * this->sample_rate_ / 1000;
420
446
 
421
447
  i2s_driver_config_t config = {
422
448
  .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
423
- .sample_rate = this->sample_rate_,
449
+ .sample_rate = audio_stream_info.sample_rate,
424
450
  .bits_per_sample = this->bits_per_sample_,
425
- .channel_format = this->channel_,
451
+ .channel_format = channel,
426
452
  .communication_format = this->i2s_comm_fmt_,
427
453
  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
428
454
  .dma_buf_count = DMA_BUFFERS_COUNT,
@@ -477,30 +503,6 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_() {
477
503
  return err;
478
504
  }
479
505
 
480
- esp_err_t I2SAudioSpeaker::reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info) {
481
- if (this->i2s_mode_ & I2S_MODE_MASTER) {
482
- // ESP controls for the the I2S bus, so adjust the sample rate and bits per sample to match the incoming audio
483
- this->sample_rate_ = audio_stream_info.sample_rate;
484
- this->bits_per_sample_ = (i2s_bits_per_sample_t) audio_stream_info.bits_per_sample;
485
- } else if (this->sample_rate_ != audio_stream_info.sample_rate) {
486
- // Can't reconfigure I2S bus, so the sample rate must match the configured value
487
- return ESP_ERR_INVALID_ARG;
488
- }
489
-
490
- if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) {
491
- // Currently can't handle the case when the incoming audio has more bits per sample than the configured value
492
- return ESP_ERR_INVALID_ARG;
493
- }
494
-
495
- if (audio_stream_info.channels == 1) {
496
- return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_MONO);
497
- } else if (audio_stream_info.channels == 2) {
498
- return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_STEREO);
499
- }
500
-
501
- return ESP_ERR_INVALID_ARG;
502
- }
503
-
504
506
  void I2SAudioSpeaker::delete_task_(size_t buffer_size) {
505
507
  this->audio_ring_buffer_.reset(); // Releases onwership of the shared_ptr
506
508
 
@@ -91,24 +91,15 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
91
91
  esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size);
92
92
 
93
93
  /// @brief Starts the ESP32 I2S driver.
94
- /// Attempts to lock the I2S port, starts the I2S driver, and sets the data out pin. If it fails, it will unlock
95
- /// the I2S port and uninstall the driver, if necessary.
96
- /// @return ESP_ERR_INVALID_STATE if the I2S port is already locked.
97
- /// ESP_ERR_INVALID_ARG if installing the driver or setting the data out pin fails due to a parameter error.
94
+ /// Attempts to lock the I2S port, starts the I2S driver using the passed in stream information, and sets the data out
95
+ /// pin. If it fails, it will unlock the I2S port and uninstall the driver, if necessary.
96
+ /// @param audio_stream_info Stream information for the I2S driver.
97
+ /// @return ESP_ERR_NOT_ALLOWED if the I2S port can't play the incoming audio stream.
98
+ /// ESP_ERR_INVALID_STATE if the I2S port is already locked.
99
+ /// ESP_ERR_INVALID_ARG if nstalling the driver or setting the data outpin fails due to a parameter error.
98
100
  /// ESP_ERR_NO_MEM if the driver fails to install due to a memory allocation error.
99
- /// ESP_FAIL if setting the data out pin fails due to an IO error
100
- /// ESP_OK if successful
101
- esp_err_t start_i2s_driver_();
102
-
103
- /// @brief Adjusts the I2S driver configuration to match the incoming audio stream.
104
- /// Modifies I2S driver's sample rate, bits per sample, and number of channel settings. If the I2S is in secondary
105
- /// mode, it only modifies the number of channels.
106
- /// @param audio_stream_info Describes the incoming audio stream
107
- /// @return ESP_ERR_INVALID_ARG if there is a parameter error, if there is more than 2 channels in the stream, or if
108
- /// the audio settings are incompatible with the configuration.
109
- /// ESP_ERR_NO_MEM if the driver fails to reconfigure due to a memory allocation error.
110
- /// ESP_OK if successful.
111
- esp_err_t reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info);
101
+ /// ESP_FAIL if setting the data out pin fails due to an IO error ESP_OK if successful
102
+ esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info);
112
103
 
113
104
  /// @brief Deletes the speaker's task.
114
105
  /// Deallocates the data_buffer_ and audio_ring_buffer_, if necessary, and deletes the task. Should only be called by
@@ -1,6 +1,6 @@
1
1
  from esphome import core, pins
2
2
  import esphome.codegen as cg
3
- from esphome.components import display, font, spi
3
+ from esphome.components import display, spi
4
4
  from esphome.components.display import validate_rotation
5
5
  import esphome.config_validation as cv
6
6
  from esphome.const import (
@@ -147,7 +147,6 @@ def _validate(config):
147
147
 
148
148
 
149
149
  CONFIG_SCHEMA = cv.All(
150
- font.validate_pillow_installed,
151
150
  display.FULL_DISPLAY_SCHEMA.extend(
152
151
  {
153
152
  cv.GenerateID(): cv.declare_id(ILI9XXXDisplay),
@@ -313,8 +313,9 @@ void ILI9XXXDisplay::draw_pixels_at(int x_start, int y_start, int w, int h, cons
313
313
  // do color conversion pixel-by-pixel into the buffer and draw it later. If this is happening the user has not
314
314
  // configured the renderer well.
315
315
  if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || !big_endian) {
316
- return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
317
- x_pad);
316
+ display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
317
+ x_pad);
318
+ return;
318
319
  }
319
320
  this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1);
320
321
  // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display.
@@ -10,7 +10,6 @@ import puremagic
10
10
 
11
11
  from esphome import core, external_files
12
12
  import esphome.codegen as cg
13
- from esphome.components import font
14
13
  import esphome.config_validation as cv
15
14
  from esphome.const import (
16
15
  CONF_DITHER,
@@ -233,7 +232,7 @@ IMAGE_SCHEMA = cv.Schema(
233
232
  )
234
233
  )
235
234
 
236
- CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA)
235
+ CONFIG_SCHEMA = IMAGE_SCHEMA
237
236
 
238
237
 
239
238
  def load_svg_image(file: bytes, resize: tuple[int, int]):
@@ -47,7 +47,7 @@ void Logger::write_header_(int level, const char *tag, int line) {
47
47
  if (current_task == main_task_) {
48
48
  this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line);
49
49
  } else {
50
- const char *thread_name = "";
50
+ const char *thread_name = ""; // NOLINT(clang-analyzer-deadcode.DeadStores)
51
51
  #if defined(USE_ESP32)
52
52
  thread_name = pcTaskGetName(current_task);
53
53
  #elif defined(USE_LIBRETINY)
@@ -23,7 +23,7 @@ bool operator==(const GainTimePair &lhs, const GainTimePair &rhs) {
23
23
  }
24
24
 
25
25
  bool operator!=(const GainTimePair &lhs, const GainTimePair &rhs) {
26
- return !(lhs.gain == rhs.gain && lhs.time == rhs.time);
26
+ return lhs.gain != rhs.gain || lhs.time != rhs.time;
27
27
  }
28
28
 
29
29
  template<typename T, size_t size> T get_next(const T (&array)[size], const T val) {
@@ -8,7 +8,7 @@ import logging
8
8
 
9
9
  from esphome import codegen as cg, config_validation as cv
10
10
  from esphome.const import CONF_ITEMS
11
- from esphome.core import Lambda
11
+ from esphome.core import ID, Lambda
12
12
  from esphome.cpp_generator import LambdaExpression, MockObj
13
13
  from esphome.cpp_types import uint32
14
14
  from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
@@ -38,7 +38,7 @@ def literal(arg):
38
38
  def call_lambda(lamb: LambdaExpression):
39
39
  expr = lamb.content.strip()
40
40
  if expr.startswith("return") and expr.endswith(";"):
41
- return expr[7:][:-1]
41
+ return expr[6:][:-1].strip()
42
42
  return f"{lamb}()"
43
43
 
44
44
 
@@ -72,6 +72,12 @@ class LValidator:
72
72
  )
73
73
  if self.retmapper is not None:
74
74
  return self.retmapper(value)
75
+ if isinstance(value, ID):
76
+ return await cg.get_variable(value)
77
+ if isinstance(value, list):
78
+ value = [
79
+ await cg.get_variable(x) if isinstance(x, ID) else x for x in value
80
+ ]
75
81
  return cg.safe_exp(value)
76
82
 
77
83
 
@@ -162,6 +168,7 @@ LV_EVENT_MAP = {
162
168
  "READY": "READY",
163
169
  "CANCEL": "CANCEL",
164
170
  "ALL_EVENTS": "ALL",
171
+ "CHANGE": "VALUE_CHANGED",
165
172
  }
166
173
 
167
174
  LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP)
@@ -1,6 +1,7 @@
1
1
  from typing import Union
2
2
 
3
3
  import esphome.codegen as cg
4
+ from esphome.components import image
4
5
  from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw
5
6
  from esphome.components.font import Font
6
7
  from esphome.components.image import Image_
@@ -31,7 +32,7 @@ from .defines import (
31
32
  literal,
32
33
  )
33
34
  from .helpers import add_lv_use, esphome_fonts_used, lv_fonts_used, requires_component
34
- from .types import lv_font_t, lv_gradient_t, lv_img_t
35
+ from .types import lv_font_t, lv_gradient_t
35
36
 
36
37
  opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
37
38
 
@@ -332,8 +333,12 @@ def image_validator(value):
332
333
 
333
334
  lv_image = LValidator(
334
335
  image_validator,
335
- lv_img_t,
336
- retmapper=lambda x: MockObj(x, "->").get_lv_img_dsc(),
336
+ image.Image_.operator("ptr"),
337
+ requires="image",
338
+ )
339
+ lv_image_list = LValidator(
340
+ cv.ensure_list(image_validator),
341
+ cg.std_vector.template(image.Image_.operator("ptr")),
337
342
  requires="image",
338
343
  )
339
344
  lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal)