esphome 2024.10.3__py3-none-any.whl → 2024.11.0b1__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 (228) hide show
  1. esphome/__main__.py +22 -4
  2. esphome/automation.py +29 -2
  3. esphome/components/animation/__init__.py +5 -8
  4. esphome/components/animation/animation.cpp +1 -1
  5. esphome/components/audio/__init__.py +9 -0
  6. esphome/components/audio/audio.h +21 -0
  7. esphome/components/axs15231/__init__.py +6 -0
  8. esphome/components/axs15231/touchscreen/__init__.py +36 -0
  9. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +64 -0
  10. esphome/components/axs15231/touchscreen/axs15231_touchscreen.h +27 -0
  11. esphome/components/bme68x_bsec2/__init__.py +1 -1
  12. esphome/components/bytebuffer/__init__.py +5 -0
  13. esphome/components/bytebuffer/bytebuffer.h +421 -0
  14. esphome/components/climate/__init__.py +14 -13
  15. esphome/components/datetime/__init__.py +3 -3
  16. esphome/components/debug/debug_esp32.cpp +16 -8
  17. esphome/components/dfplayer/dfplayer.cpp +132 -6
  18. esphome/components/dfplayer/dfplayer.h +19 -53
  19. esphome/components/display/display.cpp +142 -0
  20. esphome/components/display/display.h +7 -0
  21. esphome/components/es8311/__init__.py +0 -0
  22. esphome/components/es8311/audio_dac.py +70 -0
  23. esphome/components/es8311/es8311.cpp +227 -0
  24. esphome/components/es8311/es8311.h +135 -0
  25. esphome/components/es8311/es8311_const.h +195 -0
  26. esphome/components/esp32/boards.py +199 -1
  27. esphome/components/esp32/gpio.py +3 -1
  28. esphome/components/esp32_ble/const_esp32c6.h +7 -0
  29. esphome/components/esp32_ble_client/ble_client_base.h +1 -1
  30. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -1
  31. esphome/components/esp32_rmt_led_strip/led_strip.cpp +2 -2
  32. esphome/components/esp32_rmt_led_strip/led_strip.h +2 -0
  33. esphome/components/esp32_rmt_led_strip/light.py +3 -1
  34. esphome/components/esp8266/gpio.py +7 -5
  35. esphome/components/ethernet/__init__.py +55 -1
  36. esphome/components/ethernet/ethernet_component.cpp +14 -1
  37. esphome/components/ethernet/ethernet_component.h +7 -1
  38. esphome/components/font/__init__.py +213 -108
  39. esphome/components/gp8403/output/__init__.py +1 -1
  40. esphome/components/host/gpio.py +6 -4
  41. esphome/components/http_request/__init__.py +12 -0
  42. esphome/components/http_request/http_request.h +65 -3
  43. esphome/components/http_request/http_request_arduino.cpp +2 -3
  44. esphome/components/http_request/http_request_idf.cpp +6 -14
  45. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  46. esphome/components/http_request/update/http_request_update.cpp +1 -1
  47. esphome/components/i2c_device/__init__.py +26 -0
  48. esphome/components/i2c_device/i2c_device.cpp +17 -0
  49. esphome/components/i2c_device/i2c_device.h +18 -0
  50. esphome/components/i2s_audio/__init__.py +1 -3
  51. esphome/components/i2s_audio/speaker/__init__.py +12 -4
  52. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +432 -197
  53. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +91 -32
  54. esphome/components/ili9xxx/display.py +5 -1
  55. esphome/components/image/__init__.py +5 -8
  56. esphome/components/image/image.cpp +14 -14
  57. esphome/components/image/image.h +20 -24
  58. esphome/components/internal_temperature/internal_temperature.cpp +51 -2
  59. esphome/components/internal_temperature/internal_temperature.h +1 -0
  60. esphome/components/libretiny/gpio.py +4 -2
  61. esphome/components/light/__init__.py +32 -1
  62. esphome/components/light/automation.py +39 -32
  63. esphome/components/light/effects.py +36 -36
  64. esphome/components/light/light_state.cpp +6 -16
  65. esphome/components/light/light_state.h +34 -0
  66. esphome/components/light/types.py +3 -1
  67. esphome/components/logger/logger_esp32.cpp +15 -0
  68. esphome/components/lvgl/__init__.py +202 -95
  69. esphome/components/lvgl/automation.py +42 -40
  70. esphome/components/lvgl/binary_sensor/__init__.py +8 -15
  71. esphome/components/lvgl/defines.py +14 -8
  72. esphome/components/lvgl/encoders.py +11 -8
  73. esphome/components/lvgl/keypads.py +77 -0
  74. esphome/components/lvgl/light/__init__.py +6 -8
  75. esphome/components/lvgl/lv_validation.py +2 -4
  76. esphome/components/lvgl/lvcode.py +3 -9
  77. esphome/components/lvgl/lvgl_esphome.cpp +210 -89
  78. esphome/components/lvgl/lvgl_esphome.h +113 -30
  79. esphome/components/lvgl/lvgl_proxy.h +17 -0
  80. esphome/components/lvgl/number/__init__.py +10 -15
  81. esphome/components/lvgl/schemas.py +4 -2
  82. esphome/components/lvgl/select/__init__.py +12 -37
  83. esphome/components/lvgl/select/lvgl_select.h +27 -33
  84. esphome/components/lvgl/sensor/__init__.py +8 -14
  85. esphome/components/lvgl/styles.py +3 -4
  86. esphome/components/lvgl/switch/__init__.py +8 -13
  87. esphome/components/lvgl/text/__init__.py +5 -6
  88. esphome/components/lvgl/text_sensor/__init__.py +15 -15
  89. esphome/components/lvgl/touchscreens.py +2 -3
  90. esphome/components/lvgl/trigger.py +7 -9
  91. esphome/components/lvgl/types.py +9 -3
  92. esphome/components/lvgl/widgets/__init__.py +32 -21
  93. esphome/components/lvgl/widgets/dropdown.py +22 -10
  94. esphome/components/lvgl/widgets/msgbox.py +6 -5
  95. esphome/components/lvgl/widgets/obj.py +4 -2
  96. esphome/components/lvgl/widgets/page.py +3 -2
  97. esphome/components/lvgl/widgets/qrcode.py +54 -0
  98. esphome/components/lvgl/widgets/roller.py +21 -14
  99. esphome/components/lvgl/widgets/tileview.py +2 -1
  100. esphome/components/max17043/__init__.py +1 -0
  101. esphome/components/max17043/automation.h +20 -0
  102. esphome/components/max17043/max17043.cpp +98 -0
  103. esphome/components/max17043/max17043.h +29 -0
  104. esphome/components/max17043/sensor.py +77 -0
  105. esphome/components/media_player/__init__.py +11 -0
  106. esphome/components/media_player/automation.h +10 -0
  107. esphome/components/media_player/media_player.cpp +4 -0
  108. esphome/components/midea/air_conditioner.cpp +17 -1
  109. esphome/components/mlx90393/sensor.py +1 -1
  110. esphome/components/modbus_controller/__init__.py +31 -1
  111. esphome/components/modbus_controller/automation.h +16 -0
  112. esphome/components/modbus_controller/const.py +2 -0
  113. esphome/components/modbus_controller/modbus_controller.cpp +14 -2
  114. esphome/components/modbus_controller/modbus_controller.h +9 -0
  115. esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +40 -21
  116. esphome/components/mopeka_pro_check/mopeka_pro_check.h +9 -2
  117. esphome/components/mopeka_pro_check/sensor.py +41 -0
  118. esphome/components/mqtt/__init__.py +36 -0
  119. esphome/components/mqtt/mqtt_client.cpp +27 -3
  120. esphome/components/mqtt/mqtt_client.h +27 -2
  121. esphome/components/mqtt/mqtt_climate.cpp +4 -2
  122. esphome/components/mqtt/mqtt_component.cpp +6 -0
  123. esphome/components/mqtt/mqtt_component.h +4 -0
  124. esphome/components/mqtt/mqtt_const.h +6 -0
  125. esphome/components/online_image/online_image.cpp +2 -8
  126. esphome/components/online_image/online_image.h +2 -6
  127. esphome/components/opentherm/__init__.py +35 -9
  128. esphome/components/opentherm/binary_sensor/__init__.py +33 -0
  129. esphome/components/opentherm/const.py +11 -0
  130. esphome/components/opentherm/generate.py +142 -0
  131. esphome/components/opentherm/hub.cpp +130 -24
  132. esphome/components/opentherm/hub.h +62 -9
  133. esphome/components/opentherm/input.h +18 -0
  134. esphome/components/opentherm/input.py +51 -0
  135. esphome/components/opentherm/number/__init__.py +74 -0
  136. esphome/components/opentherm/number/number.cpp +40 -0
  137. esphome/components/opentherm/number/number.h +31 -0
  138. esphome/components/opentherm/opentherm.cpp +30 -0
  139. esphome/components/opentherm/opentherm.h +34 -2
  140. esphome/components/opentherm/opentherm_macros.h +151 -0
  141. esphome/components/opentherm/output/__init__.py +47 -0
  142. esphome/components/opentherm/output/output.cpp +18 -0
  143. esphome/components/opentherm/output/output.h +33 -0
  144. esphome/components/opentherm/schema.py +814 -0
  145. esphome/components/opentherm/sensor/__init__.py +51 -0
  146. esphome/components/opentherm/switch/__init__.py +43 -0
  147. esphome/components/opentherm/switch/switch.cpp +28 -0
  148. esphome/components/opentherm/switch/switch.h +20 -0
  149. esphome/components/opentherm/validate.py +31 -0
  150. esphome/components/pcd8544/display.py +8 -4
  151. esphome/components/prometheus/prometheus_handler.cpp +176 -14
  152. esphome/components/prometheus/prometheus_handler.h +25 -7
  153. esphome/components/qspi_amoled/display.py +1 -141
  154. esphome/components/qspi_dbi/display.py +185 -0
  155. esphome/components/qspi_dbi/models.py +64 -0
  156. esphome/components/{qspi_amoled/qspi_amoled.cpp → qspi_dbi/qspi_dbi.cpp} +95 -46
  157. esphome/components/{qspi_amoled/qspi_amoled.h → qspi_dbi/qspi_dbi.h} +26 -15
  158. esphome/components/rp2040/__init__.py +6 -3
  159. esphome/components/rp2040/gpio.py +5 -3
  160. esphome/components/rtttl/rtttl.cpp +4 -1
  161. esphome/components/rtttl/rtttl.h +1 -0
  162. esphome/components/sdl/sdl_esphome.cpp +22 -5
  163. esphome/components/sdl/sdl_esphome.h +1 -0
  164. esphome/components/sensor/__init__.py +18 -8
  165. esphome/components/sensor/filter.cpp +19 -18
  166. esphome/components/sensor/filter.h +9 -10
  167. esphome/components/sgp4x/sgp4x.cpp +40 -74
  168. esphome/components/sgp4x/sgp4x.h +5 -3
  169. esphome/components/speaker/__init__.py +51 -5
  170. esphome/components/speaker/automation.h +25 -0
  171. esphome/components/speaker/speaker.h +72 -1
  172. esphome/components/spi/__init__.py +15 -14
  173. esphome/components/spi_device/__init__.py +4 -15
  174. esphome/components/ssd1306_spi/display.py +6 -2
  175. esphome/components/ssd1322_spi/display.py +6 -2
  176. esphome/components/ssd1325_spi/display.py +6 -2
  177. esphome/components/ssd1327_spi/display.py +6 -2
  178. esphome/components/ssd1331_spi/display.py +6 -2
  179. esphome/components/ssd1351_spi/display.py +6 -2
  180. esphome/components/st7567_spi/display.py +6 -2
  181. esphome/components/st7701s/display.py +5 -1
  182. esphome/components/st7735/display.py +10 -5
  183. esphome/components/st7789v/display.py +12 -7
  184. esphome/components/statsd/statsd.cpp +2 -0
  185. esphome/components/statsd/statsd.h +2 -0
  186. esphome/components/sun/sun.h +3 -0
  187. esphome/components/tc74/__init__.py +1 -0
  188. esphome/components/tc74/sensor.py +32 -0
  189. esphome/components/tc74/tc74.cpp +68 -0
  190. esphome/components/tc74/tc74.h +28 -0
  191. esphome/components/touchscreen/__init__.py +41 -50
  192. esphome/components/touchscreen/touchscreen.h +4 -8
  193. esphome/components/udp/udp_component.cpp +6 -3
  194. esphome/components/udp/udp_component.h +4 -2
  195. esphome/components/waveshare_epaper/display.py +6 -2
  196. esphome/components/web_server/web_server.cpp +22 -0
  197. esphome/components/web_server/web_server.h +3 -0
  198. esphome/components/weikai/weikai.h +2 -2
  199. esphome/components/wifi/wifi_component.cpp +2 -2
  200. esphome/components/wifi/wifi_component_esp32_arduino.cpp +4 -4
  201. esphome/components/wifi/wifi_component_esp8266.cpp +4 -4
  202. esphome/components/wifi/wifi_component_esp_idf.cpp +2 -2
  203. esphome/components/xpt2046/touchscreen/__init__.py +7 -32
  204. esphome/config_validation.py +3 -1
  205. esphome/const.py +8 -1
  206. esphome/core/defines.h +8 -2
  207. esphome/core/helpers.cpp +32 -17
  208. esphome/core/helpers.h +32 -16
  209. esphome/core/ring_buffer.cpp +2 -2
  210. esphome/core/ring_buffer.h +2 -2
  211. esphome/dashboard/core.py +25 -0
  212. esphome/dashboard/status/mdns.py +3 -4
  213. esphome/dashboard/web_server.py +54 -19
  214. esphome/espota2.py +36 -35
  215. esphome/helpers.py +68 -16
  216. esphome/mqtt.py +9 -2
  217. esphome/storage_json.py +4 -0
  218. esphome/writer.py +7 -18
  219. esphome/zeroconf.py +8 -6
  220. {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/METADATA +7 -5
  221. {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/RECORD +226 -180
  222. esphome/core/bytebuffer.cpp +0 -167
  223. esphome/core/bytebuffer.h +0 -144
  224. /esphome/components/{qspi_amoled → qspi_dbi}/__init__.py +0 -0
  225. {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/LICENSE +0 -0
  226. {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/WHEEL +0 -0
  227. {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/entry_points.txt +0 -0
  228. {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,12 @@
1
1
  #ifdef USE_ESP_IDF
2
- #include "qspi_amoled.h"
2
+ #include "qspi_dbi.h"
3
3
  #include "esphome/core/log.h"
4
4
 
5
5
  namespace esphome {
6
- namespace qspi_amoled {
6
+ namespace qspi_dbi {
7
7
 
8
- void QspiAmoLed::setup() {
9
- esph_log_config(TAG, "Setting up QSPI_AMOLED");
8
+ void QspiDbi::setup() {
9
+ ESP_LOGCONFIG(TAG, "Setting up QSPI_DBI");
10
10
  this->spi_setup();
11
11
  if (this->enable_pin_ != nullptr) {
12
12
  this->enable_pin_->setup();
@@ -22,13 +22,17 @@ void QspiAmoLed::setup() {
22
22
  }
23
23
  this->set_timeout(120, [this] { this->write_command_(SLEEP_OUT); });
24
24
  this->set_timeout(240, [this] { this->write_init_sequence_(); });
25
+ if (this->draw_from_origin_)
26
+ check_buffer_();
25
27
  }
26
28
 
27
- void QspiAmoLed::update() {
29
+ void QspiDbi::update() {
28
30
  if (!this->setup_complete_) {
29
31
  return;
30
32
  }
31
33
  this->do_update_();
34
+ if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
35
+ return;
32
36
  // Start addresses and widths/heights must be divisible by 2 (CASET/RASET restriction in datasheet)
33
37
  if (this->x_low_ % 2 == 1) {
34
38
  this->x_low_--;
@@ -42,10 +46,15 @@ void QspiAmoLed::update() {
42
46
  if (this->y_high_ % 2 == 0) {
43
47
  this->y_high_++;
44
48
  }
49
+ if (this->draw_from_origin_) {
50
+ this->x_low_ = 0;
51
+ this->y_low_ = 0;
52
+ this->x_high_ = this->width_ - 1;
53
+ }
45
54
  int w = this->x_high_ - this->x_low_ + 1;
46
55
  int h = this->y_high_ - this->y_low_ + 1;
47
- this->draw_pixels_at(this->x_low_, this->y_low_, w, h, this->buffer_, this->color_mode_, display::COLOR_BITNESS_565,
48
- true, this->x_low_, this->y_low_, this->get_width_internal() - w - this->x_low_);
56
+ this->write_to_display_(this->x_low_, this->y_low_, w, h, this->buffer_, this->x_low_, this->y_low_,
57
+ this->width_ - w - this->x_low_);
49
58
  // invalidate watermarks
50
59
  this->x_low_ = this->width_;
51
60
  this->y_low_ = this->height_;
@@ -53,21 +62,19 @@ void QspiAmoLed::update() {
53
62
  this->y_high_ = 0;
54
63
  }
55
64
 
56
- void QspiAmoLed::draw_absolute_pixel_internal(int x, int y, Color color) {
65
+ void QspiDbi::draw_absolute_pixel_internal(int x, int y, Color color) {
57
66
  if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) {
58
67
  return;
59
68
  }
60
- if (this->buffer_ == nullptr)
61
- this->init_internal_(this->width_ * this->height_ * 2);
62
69
  if (this->is_failed())
63
70
  return;
71
+ check_buffer_();
64
72
  uint32_t pos = (y * this->width_) + x;
65
- uint16_t new_color;
66
73
  bool updated = false;
67
74
  pos = pos * 2;
68
- new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB);
69
- if (this->buffer_[pos] != (uint8_t) (new_color >> 8)) {
70
- this->buffer_[pos] = (uint8_t) (new_color >> 8);
75
+ uint16_t new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB);
76
+ if (this->buffer_[pos] != static_cast<uint8_t>(new_color >> 8)) {
77
+ this->buffer_[pos] = static_cast<uint8_t>(new_color >> 8);
71
78
  updated = true;
72
79
  }
73
80
  pos = pos + 1;
@@ -90,7 +97,7 @@ void QspiAmoLed::draw_absolute_pixel_internal(int x, int y, Color color) {
90
97
  }
91
98
  }
92
99
 
93
- void QspiAmoLed::reset_params_(bool ready) {
100
+ void QspiDbi::reset_params_(bool ready) {
94
101
  if (!ready && !this->is_ready())
95
102
  return;
96
103
  this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF);
@@ -102,55 +109,64 @@ void QspiAmoLed::reset_params_(bool ready) {
102
109
  mad |= MADCTL_MX;
103
110
  if (this->mirror_y_)
104
111
  mad |= MADCTL_MY;
105
- this->write_command_(MADCTL_CMD, &mad, 1);
106
- this->write_command_(BRIGHTNESS, &this->brightness_, 1);
112
+ this->write_command_(MADCTL_CMD, mad);
113
+ this->write_command_(BRIGHTNESS, this->brightness_);
114
+ this->write_command_(NORON);
115
+ this->write_command_(DISPLAY_ON);
107
116
  }
108
117
 
109
- void QspiAmoLed::write_init_sequence_() {
110
- if (this->model_ == RM690B0) {
111
- this->write_command_(PAGESEL, 0x20);
112
- this->write_command_(MIPI, 0x0A);
113
- this->write_command_(WRAM, 0x80);
114
- this->write_command_(SWIRE1, 0x51);
115
- this->write_command_(SWIRE2, 0x2E);
116
- this->write_command_(PAGESEL, 0x00);
117
- this->write_command_(0xC2, 0x00);
118
- delay(10);
119
- this->write_command_(TEON, 0x00);
120
- }
121
- this->write_command_(PIXFMT, 0x55);
122
- this->write_command_(BRIGHTNESS, 0);
123
- this->write_command_(DISPLAY_ON);
118
+ void QspiDbi::write_init_sequence_() {
119
+ for (const auto &seq : this->init_sequences_) {
120
+ this->write_sequence_(seq);
121
+ }
124
122
  this->reset_params_(true);
125
123
  this->setup_complete_ = true;
126
- esph_log_config(TAG, "QSPI_AMOLED setup complete");
124
+ ESP_LOGCONFIG(TAG, "QSPI_DBI setup complete");
127
125
  }
128
126
 
129
- void QspiAmoLed::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
127
+ void QspiDbi::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
128
+ ESP_LOGVV(TAG, "Set addr %d/%d, %d/%d", x1, y1, x2, y2);
130
129
  uint8_t buf[4];
131
130
  x1 += this->offset_x_;
132
131
  x2 += this->offset_x_;
133
132
  y1 += this->offset_y_;
134
133
  y2 += this->offset_y_;
135
- put16_be(buf, x1);
136
- put16_be(buf + 2, x2);
137
- this->write_command_(CASET, buf, sizeof buf);
138
134
  put16_be(buf, y1);
139
135
  put16_be(buf + 2, y2);
140
136
  this->write_command_(RASET, buf, sizeof buf);
137
+ put16_be(buf, x1);
138
+ put16_be(buf + 2, x2);
139
+ this->write_command_(CASET, buf, sizeof buf);
141
140
  }
142
141
 
143
- void QspiAmoLed::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
144
- display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
142
+ void QspiDbi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
143
+ display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
145
144
  if (!this->setup_complete_ || this->is_failed())
146
145
  return;
147
146
  if (w <= 0 || h <= 0)
148
147
  return;
149
148
  if (bitness != display::COLOR_BITNESS_565 || order != this->color_mode_ ||
150
149
  big_endian != (this->bit_order_ == spi::BIT_ORDER_MSB_FIRST)) {
151
- return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
152
- x_pad);
150
+ return Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
151
+ } else if (this->draw_from_origin_) {
152
+ auto stride = x_offset + w + x_pad;
153
+ for (int y = 0; y != h; y++) {
154
+ memcpy(this->buffer_ + ((y + y_start) * this->width_ + x_start) * 2,
155
+ ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2);
156
+ }
157
+ ptr = this->buffer_;
158
+ w = this->width_;
159
+ h += y_start;
160
+ x_start = 0;
161
+ y_start = 0;
162
+ x_offset = 0;
163
+ y_offset = 0;
153
164
  }
165
+ this->write_to_display_(x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
166
+ }
167
+
168
+ void QspiDbi::write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset,
169
+ int x_pad) {
154
170
  this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1);
155
171
  this->enable();
156
172
  // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display.
@@ -158,17 +174,50 @@ void QspiAmoLed::draw_pixels_at(int x_start, int y_start, int w, int h, const ui
158
174
  // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother
159
175
  this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, ptr, w * h * 2, 4);
160
176
  } else {
161
- this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, nullptr, 0, 4);
162
177
  auto stride = x_offset + w + x_pad;
178
+ uint16_t cmd = 0x2C00;
163
179
  for (int y = 0; y != h; y++) {
164
- this->write_cmd_addr_data(0, 0, 0, 0, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4);
180
+ this->write_cmd_addr_data(8, 0x32, 24, cmd, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4);
181
+ cmd = 0x3C00;
165
182
  }
166
183
  }
167
184
  this->disable();
168
185
  }
186
+ void QspiDbi::write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) {
187
+ ESP_LOGV(TAG, "Command %02X, length %d, bytes %s", cmd, len, format_hex_pretty(bytes, len).c_str());
188
+ this->enable();
189
+ this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len);
190
+ this->disable();
191
+ }
192
+
193
+ void QspiDbi::write_sequence_(const std::vector<uint8_t> &vec) {
194
+ size_t index = 0;
195
+ while (index != vec.size()) {
196
+ if (vec.size() - index < 2) {
197
+ ESP_LOGE(TAG, "Malformed init sequence");
198
+ return;
199
+ }
200
+ uint8_t cmd = vec[index++];
201
+ uint8_t x = vec[index++];
202
+ if (x == DELAY_FLAG) {
203
+ ESP_LOGV(TAG, "Delay %dms", cmd);
204
+ delay(cmd);
205
+ } else {
206
+ uint8_t num_args = x & 0x7F;
207
+ if (vec.size() - index < num_args) {
208
+ ESP_LOGE(TAG, "Malformed init sequence");
209
+ return;
210
+ }
211
+ const auto *ptr = vec.data() + index;
212
+ this->write_command_(cmd, ptr, num_args);
213
+ index += num_args;
214
+ }
215
+ }
216
+ }
169
217
 
170
- void QspiAmoLed::dump_config() {
171
- ESP_LOGCONFIG("", "QSPI AMOLED");
218
+ void QspiDbi::dump_config() {
219
+ ESP_LOGCONFIG("", "QSPI_DBI Display");
220
+ ESP_LOGCONFIG("", "Model: %s", this->model_);
172
221
  ESP_LOGCONFIG(TAG, " Height: %u", this->height_);
173
222
  ESP_LOGCONFIG(TAG, " Width: %u", this->width_);
174
223
  LOG_PIN(" CS Pin: ", this->cs_);
@@ -176,6 +225,6 @@ void QspiAmoLed::dump_config() {
176
225
  ESP_LOGCONFIG(TAG, " SPI Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000));
177
226
  }
178
227
 
179
- } // namespace qspi_amoled
228
+ } // namespace qspi_dbi
180
229
  } // namespace esphome
181
230
  #endif
@@ -14,11 +14,12 @@
14
14
  #include "esp_lcd_panel_rgb.h"
15
15
 
16
16
  namespace esphome {
17
- namespace qspi_amoled {
17
+ namespace qspi_dbi {
18
18
 
19
- constexpr static const char *const TAG = "display.qspi_amoled";
19
+ constexpr static const char *const TAG = "display.qspi_dbi";
20
20
  static const uint8_t SW_RESET_CMD = 0x01;
21
21
  static const uint8_t SLEEP_OUT = 0x11;
22
+ static const uint8_t NORON = 0x13;
22
23
  static const uint8_t INVERT_OFF = 0x20;
23
24
  static const uint8_t INVERT_ON = 0x21;
24
25
  static const uint8_t ALL_ON = 0x23;
@@ -42,6 +43,7 @@ static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode
42
43
  static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order
43
44
  static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order
44
45
 
46
+ static const uint8_t DELAY_FLAG = 0xFF;
45
47
  // store a 16 bit value in a buffer, big endian.
46
48
  static inline void put16_be(uint8_t *buf, uint16_t value) {
47
49
  buf[0] = value >> 8;
@@ -49,15 +51,16 @@ static inline void put16_be(uint8_t *buf, uint16_t value) {
49
51
  }
50
52
 
51
53
  enum Model {
54
+ CUSTOM,
52
55
  RM690B0,
53
56
  RM67162,
54
57
  };
55
58
 
56
- class QspiAmoLed : public display::DisplayBuffer,
57
- public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
58
- spi::DATA_RATE_1MHZ> {
59
+ class QspiDbi : public display::DisplayBuffer,
60
+ public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
61
+ spi::DATA_RATE_1MHZ> {
59
62
  public:
60
- void set_model(Model model) { this->model_ = model; }
63
+ void set_model(const char *model) { this->model_ = model; }
61
64
  void update() override;
62
65
  void setup() override;
63
66
  display::ColorOrder get_color_mode() { return this->color_mode_; }
@@ -93,17 +96,27 @@ class QspiAmoLed : public display::DisplayBuffer,
93
96
  this->offset_x_ = offset_x;
94
97
  this->offset_y_ = offset_y;
95
98
  }
99
+
100
+ void set_draw_from_origin(bool draw_from_origin) { this->draw_from_origin_ = draw_from_origin; }
96
101
  display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; }
97
102
  void dump_config() override;
98
103
 
99
104
  int get_width_internal() override { return this->width_; }
100
105
  int get_height_internal() override { return this->height_; }
101
106
  bool can_proceed() override { return this->setup_complete_; }
107
+ void add_init_sequence(const std::vector<uint8_t> &sequence) { this->init_sequences_.push_back(sequence); }
102
108
 
103
109
  protected:
110
+ void check_buffer_() {
111
+ if (this->buffer_ == nullptr)
112
+ this->init_internal_(this->width_ * this->height_ * 2);
113
+ }
114
+ void write_sequence_(const std::vector<uint8_t> &vec);
104
115
  void draw_absolute_pixel_internal(int x, int y, Color color) override;
105
116
  void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
106
117
  display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override;
118
+ void write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset,
119
+ int x_pad);
107
120
  /**
108
121
  * the RM67162 in quad SPI mode seems to work like this (not in the datasheet, this is deduced from the
109
122
  * sample code.)
@@ -122,11 +135,7 @@ class QspiAmoLed : public display::DisplayBuffer,
122
135
  * @param bytes
123
136
  * @param len
124
137
  */
125
- void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) {
126
- this->enable();
127
- this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len);
128
- this->disable();
129
- }
138
+ void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len);
130
139
 
131
140
  void write_command_(uint8_t cmd, uint8_t data) { this->write_command_(cmd, &data, 1); }
132
141
  void write_command_(uint8_t cmd) { this->write_command_(cmd, &cmd, 0); }
@@ -136,8 +145,8 @@ class QspiAmoLed : public display::DisplayBuffer,
136
145
 
137
146
  GPIOPin *reset_pin_{nullptr};
138
147
  GPIOPin *enable_pin_{nullptr};
139
- uint16_t x_low_{0};
140
- uint16_t y_low_{0};
148
+ uint16_t x_low_{1};
149
+ uint16_t y_low_{1};
141
150
  uint16_t x_high_{0};
142
151
  uint16_t y_high_{0};
143
152
  bool setup_complete_{};
@@ -151,12 +160,14 @@ class QspiAmoLed : public display::DisplayBuffer,
151
160
  bool swap_xy_{};
152
161
  bool mirror_x_{};
153
162
  bool mirror_y_{};
163
+ bool draw_from_origin_{false};
154
164
  uint8_t brightness_{0xD0};
155
- Model model_{RM690B0};
165
+ const char *model_{"Unknown"};
166
+ std::vector<std::vector<uint8_t>> init_sequences_{};
156
167
 
157
168
  esp_lcd_panel_handle_t handle_{};
158
169
  };
159
170
 
160
- } // namespace qspi_amoled
171
+ } // namespace qspi_dbi
161
172
  } // namespace esphome
162
173
  #endif
@@ -17,7 +17,7 @@ from esphome.const import (
17
17
  PLATFORM_RP2040,
18
18
  )
19
19
  from esphome.core import CORE, EsphomeError, coroutine_with_priority
20
- from esphome.helpers import copy_file_if_changed, mkdir_p, write_file
20
+ from esphome.helpers import copy_file_if_changed, mkdir_p, write_file, read_file
21
21
 
22
22
  from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns
23
23
 
@@ -230,11 +230,14 @@ def generate_pio_files() -> bool:
230
230
 
231
231
 
232
232
  # Called by writer.py
233
- def copy_files() -> bool:
233
+ def copy_files():
234
234
  dir = os.path.dirname(__file__)
235
235
  post_build_file = os.path.join(dir, "post_build.py.script")
236
236
  copy_file_if_changed(
237
237
  post_build_file,
238
238
  CORE.relative_build_path("post_build.py"),
239
239
  )
240
- return generate_pio_files()
240
+ if generate_pio_files():
241
+ path = CORE.relative_src_path("esphome.h")
242
+ content = read_file(path).rstrip("\n")
243
+ write_file(path, content + '\n#include "pio_includes.h"\n')
@@ -1,6 +1,8 @@
1
+ from esphome import pins
1
2
  import esphome.codegen as cg
2
3
  import esphome.config_validation as cv
3
4
  from esphome.const import (
5
+ CONF_ANALOG,
4
6
  CONF_ID,
5
7
  CONF_INPUT,
6
8
  CONF_INVERTED,
@@ -10,10 +12,8 @@ from esphome.const import (
10
12
  CONF_OUTPUT,
11
13
  CONF_PULLDOWN,
12
14
  CONF_PULLUP,
13
- CONF_ANALOG,
14
15
  )
15
16
  from esphome.core import CORE
16
- from esphome import pins
17
17
 
18
18
  from . import boards
19
19
  from .const import KEY_BOARD, KEY_RP2040, rp2040_ns
@@ -41,8 +41,10 @@ def _translate_pin(value):
41
41
  "This variable only supports pin numbers, not full pin schemas "
42
42
  "(with inverted and mode)."
43
43
  )
44
- if isinstance(value, int):
44
+ if isinstance(value, int) and not isinstance(value, bool):
45
45
  return value
46
+ if not isinstance(value, str):
47
+ raise cv.Invalid(f"Invalid pin number: {value}")
46
48
  try:
47
49
  return int(value)
48
50
  except ValueError:
@@ -26,7 +26,10 @@ inline double deg2rad(double degrees) {
26
26
  return degrees * PI_ON_180;
27
27
  }
28
28
 
29
- void Rtttl::dump_config() { ESP_LOGCONFIG(TAG, "Rtttl"); }
29
+ void Rtttl::dump_config() {
30
+ ESP_LOGCONFIG(TAG, "Rtttl:");
31
+ ESP_LOGCONFIG(TAG, " Gain: %f", gain_);
32
+ }
30
33
 
31
34
  void Rtttl::play(std::string rtttl) {
32
35
  if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) {
@@ -39,6 +39,7 @@ class Rtttl : public Component {
39
39
  #ifdef USE_SPEAKER
40
40
  void set_speaker(speaker::Speaker *speaker) { this->speaker_ = speaker; }
41
41
  #endif
42
+ float get_gain() { return gain_; }
42
43
  void set_gain(float gain) {
43
44
  if (gain < 0.1f)
44
45
  gain = 0.1f;
@@ -9,8 +9,9 @@ void Sdl::setup() {
9
9
  ESP_LOGD(TAG, "Starting setup");
10
10
  SDL_Init(SDL_INIT_VIDEO);
11
11
  this->window_ = SDL_CreateWindow(App.get_name().c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
12
- this->width_, this->height_, 0);
12
+ this->width_, this->height_, SDL_WINDOW_RESIZABLE);
13
13
  this->renderer_ = SDL_CreateRenderer(this->window_, -1, SDL_RENDERER_SOFTWARE);
14
+ SDL_RenderSetLogicalSize(this->renderer_, this->width_, this->height_);
14
15
  this->texture_ =
15
16
  SDL_CreateTexture(this->renderer_, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STATIC, this->width_, this->height_);
16
17
  SDL_SetTextureBlendMode(this->texture_, SDL_BLENDMODE_BLEND);
@@ -25,6 +26,10 @@ void Sdl::update() {
25
26
  this->y_low_ = this->height_;
26
27
  this->x_high_ = 0;
27
28
  this->y_high_ = 0;
29
+ this->redraw_(rect);
30
+ }
31
+
32
+ void Sdl::redraw_(SDL_Rect &rect) {
28
33
  SDL_RenderCopy(this->renderer_, this->texture_, &rect, &rect);
29
34
  SDL_RenderPresent(this->renderer_);
30
35
  }
@@ -33,15 +38,13 @@ void Sdl::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *
33
38
  display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
34
39
  SDL_Rect rect{x_start, y_start, w, h};
35
40
  if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || big_endian) {
36
- display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
37
- x_pad);
41
+ Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
38
42
  } else {
39
43
  auto stride = x_offset + w + x_pad;
40
44
  auto data = ptr + (stride * y_offset + x_offset) * 2;
41
45
  SDL_UpdateTexture(this->texture_, &rect, data, stride * 2);
42
46
  }
43
- SDL_RenderCopy(this->renderer_, this->texture_, &rect, &rect);
44
- SDL_RenderPresent(this->renderer_);
47
+ this->redraw_(rect);
45
48
  }
46
49
 
47
50
  void Sdl::draw_pixel_at(int x, int y, Color color) {
@@ -84,6 +87,20 @@ void Sdl::loop() {
84
87
  }
85
88
  break;
86
89
 
90
+ case SDL_WINDOWEVENT:
91
+ switch (e.window.event) {
92
+ case SDL_WINDOWEVENT_SIZE_CHANGED:
93
+ case SDL_WINDOWEVENT_EXPOSED:
94
+ case SDL_WINDOWEVENT_RESIZED: {
95
+ SDL_Rect rect{0, 0, this->width_, this->height_};
96
+ this->redraw_(rect);
97
+ break;
98
+ }
99
+ default:
100
+ break;
101
+ }
102
+ break;
103
+
87
104
  default:
88
105
  ESP_LOGV(TAG, "Event %d", e.type);
89
106
  break;
@@ -38,6 +38,7 @@ class Sdl : public display::Display {
38
38
  protected:
39
39
  int get_width_internal() override { return this->width_; }
40
40
  int get_height_internal() override { return this->height_; }
41
+ void redraw_(SDL_Rect &rect);
41
42
  int width_{};
42
43
  int height_{};
43
44
  SDL_Renderer *renderer_{};
@@ -335,19 +335,28 @@ def sensor_schema(
335
335
  return SENSOR_SCHEMA.extend(schema)
336
336
 
337
337
 
338
- @FILTER_REGISTRY.register("offset", OffsetFilter, cv.float_)
338
+ @FILTER_REGISTRY.register("offset", OffsetFilter, cv.templatable(cv.float_))
339
339
  async def offset_filter_to_code(config, filter_id):
340
- return cg.new_Pvariable(filter_id, config)
340
+ template_ = await cg.templatable(config, [], float)
341
+ return cg.new_Pvariable(filter_id, template_)
341
342
 
342
343
 
343
- @FILTER_REGISTRY.register("multiply", MultiplyFilter, cv.float_)
344
+ @FILTER_REGISTRY.register("multiply", MultiplyFilter, cv.templatable(cv.float_))
344
345
  async def multiply_filter_to_code(config, filter_id):
345
- return cg.new_Pvariable(filter_id, config)
346
+ template_ = await cg.templatable(config, [], float)
347
+ return cg.new_Pvariable(filter_id, template_)
346
348
 
347
349
 
348
- @FILTER_REGISTRY.register("filter_out", FilterOutValueFilter, cv.float_)
350
+ @FILTER_REGISTRY.register(
351
+ "filter_out",
352
+ FilterOutValueFilter,
353
+ cv.Any(cv.templatable(cv.float_), [cv.templatable(cv.float_)]),
354
+ )
349
355
  async def filter_out_filter_to_code(config, filter_id):
350
- return cg.new_Pvariable(filter_id, config)
356
+ if not isinstance(config, list):
357
+ config = [config]
358
+ template_ = [await cg.templatable(x, [], float) for x in config]
359
+ return cg.new_Pvariable(filter_id, template_)
351
360
 
352
361
 
353
362
  QUANTILE_SCHEMA = cv.All(
@@ -573,7 +582,7 @@ async def heartbeat_filter_to_code(config, filter_id):
573
582
  TIMEOUT_SCHEMA = cv.maybe_simple_value(
574
583
  {
575
584
  cv.Required(CONF_TIMEOUT): cv.positive_time_period_milliseconds,
576
- cv.Optional(CONF_VALUE, default="nan"): cv.float_,
585
+ cv.Optional(CONF_VALUE, default="nan"): cv.templatable(cv.float_),
577
586
  },
578
587
  key=CONF_TIMEOUT,
579
588
  )
@@ -581,7 +590,8 @@ TIMEOUT_SCHEMA = cv.maybe_simple_value(
581
590
 
582
591
  @FILTER_REGISTRY.register("timeout", TimeoutFilter, TIMEOUT_SCHEMA)
583
592
  async def timeout_filter_to_code(config, filter_id):
584
- var = cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], config[CONF_VALUE])
593
+ template_ = await cg.templatable(config[CONF_VALUE], [], float)
594
+ var = cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], template_)
585
595
  await cg.register_component(var, {})
586
596
  return var
587
597
 
@@ -288,36 +288,36 @@ optional<float> LambdaFilter::new_value(float value) {
288
288
  }
289
289
 
290
290
  // OffsetFilter
291
- OffsetFilter::OffsetFilter(float offset) : offset_(offset) {}
291
+ OffsetFilter::OffsetFilter(TemplatableValue<float> offset) : offset_(std::move(offset)) {}
292
292
 
293
- optional<float> OffsetFilter::new_value(float value) { return value + this->offset_; }
293
+ optional<float> OffsetFilter::new_value(float value) { return value + this->offset_.value(); }
294
294
 
295
295
  // MultiplyFilter
296
- MultiplyFilter::MultiplyFilter(float multiplier) : multiplier_(multiplier) {}
296
+ MultiplyFilter::MultiplyFilter(TemplatableValue<float> multiplier) : multiplier_(std::move(multiplier)) {}
297
297
 
298
- optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_; }
298
+ optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_.value(); }
299
299
 
300
300
  // FilterOutValueFilter
301
- FilterOutValueFilter::FilterOutValueFilter(float value_to_filter_out) : value_to_filter_out_(value_to_filter_out) {}
301
+ FilterOutValueFilter::FilterOutValueFilter(std::vector<TemplatableValue<float>> values_to_filter_out)
302
+ : values_to_filter_out_(std::move(values_to_filter_out)) {}
302
303
 
303
304
  optional<float> FilterOutValueFilter::new_value(float value) {
304
- if (std::isnan(this->value_to_filter_out_)) {
305
- if (std::isnan(value)) {
306
- return {};
307
- } else {
308
- return value;
305
+ int8_t accuracy = this->parent_->get_accuracy_decimals();
306
+ float accuracy_mult = powf(10.0f, accuracy);
307
+ for (auto filter_value : this->values_to_filter_out_) {
308
+ if (std::isnan(filter_value.value())) {
309
+ if (std::isnan(value)) {
310
+ return {};
311
+ }
312
+ continue;
309
313
  }
310
- } else {
311
- int8_t accuracy = this->parent_->get_accuracy_decimals();
312
- float accuracy_mult = powf(10.0f, accuracy);
313
- float rounded_filter_out = roundf(accuracy_mult * this->value_to_filter_out_);
314
+ float rounded_filter_out = roundf(accuracy_mult * filter_value.value());
314
315
  float rounded_value = roundf(accuracy_mult * value);
315
316
  if (rounded_filter_out == rounded_value) {
316
317
  return {};
317
- } else {
318
- return value;
319
318
  }
320
319
  }
320
+ return value;
321
321
  }
322
322
 
323
323
  // ThrottleFilter
@@ -383,11 +383,12 @@ void OrFilter::initialize(Sensor *parent, Filter *next) {
383
383
 
384
384
  // TimeoutFilter
385
385
  optional<float> TimeoutFilter::new_value(float value) {
386
- this->set_timeout("timeout", this->time_period_, [this]() { this->output(this->value_); });
386
+ this->set_timeout("timeout", this->time_period_, [this]() { this->output(this->value_.value()); });
387
387
  return value;
388
388
  }
389
389
 
390
- TimeoutFilter::TimeoutFilter(uint32_t time_period, float new_value) : time_period_(time_period), value_(new_value) {}
390
+ TimeoutFilter::TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value)
391
+ : time_period_(time_period), value_(std::move(new_value)) {}
391
392
  float TimeoutFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
392
393
 
393
394
  // DebounceFilter