esphome 2024.10.3__py3-none-any.whl → 2024.11.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 (234) 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/bme68x_bsec2/bme68x_bsec2.cpp +50 -47
  13. esphome/components/bme68x_bsec2/bme68x_bsec2.h +0 -2
  14. esphome/components/bytebuffer/__init__.py +5 -0
  15. esphome/components/bytebuffer/bytebuffer.h +421 -0
  16. esphome/components/climate/__init__.py +14 -13
  17. esphome/components/datetime/__init__.py +3 -3
  18. esphome/components/debug/debug_esp32.cpp +16 -8
  19. esphome/components/dfplayer/dfplayer.cpp +132 -6
  20. esphome/components/dfplayer/dfplayer.h +19 -53
  21. esphome/components/display/display.cpp +142 -0
  22. esphome/components/display/display.h +7 -0
  23. esphome/components/es8311/__init__.py +0 -0
  24. esphome/components/es8311/audio_dac.py +70 -0
  25. esphome/components/es8311/es8311.cpp +227 -0
  26. esphome/components/es8311/es8311.h +135 -0
  27. esphome/components/es8311/es8311_const.h +195 -0
  28. esphome/components/esp32/boards.py +199 -1
  29. esphome/components/esp32/gpio.py +3 -1
  30. esphome/components/esp32_ble/const_esp32c6.h +7 -0
  31. esphome/components/esp32_ble_client/ble_client_base.h +1 -1
  32. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +3 -0
  33. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -1
  34. esphome/components/esp32_rmt_led_strip/led_strip.cpp +2 -2
  35. esphome/components/esp32_rmt_led_strip/led_strip.h +2 -0
  36. esphome/components/esp32_rmt_led_strip/light.py +3 -1
  37. esphome/components/esp8266/gpio.py +7 -5
  38. esphome/components/ethernet/__init__.py +55 -1
  39. esphome/components/ethernet/ethernet_component.cpp +14 -1
  40. esphome/components/ethernet/ethernet_component.h +7 -1
  41. esphome/components/font/__init__.py +213 -108
  42. esphome/components/gp8403/output/__init__.py +1 -1
  43. esphome/components/host/gpio.py +6 -4
  44. esphome/components/http_request/__init__.py +12 -0
  45. esphome/components/http_request/http_request.h +65 -3
  46. esphome/components/http_request/http_request_arduino.cpp +4 -3
  47. esphome/components/http_request/http_request_idf.cpp +12 -14
  48. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  49. esphome/components/http_request/update/http_request_update.cpp +1 -1
  50. esphome/components/i2c_device/__init__.py +26 -0
  51. esphome/components/i2c_device/i2c_device.cpp +17 -0
  52. esphome/components/i2c_device/i2c_device.h +18 -0
  53. esphome/components/i2s_audio/__init__.py +1 -3
  54. esphome/components/i2s_audio/speaker/__init__.py +12 -4
  55. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +426 -200
  56. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +92 -33
  57. esphome/components/ili9xxx/display.py +5 -1
  58. esphome/components/image/__init__.py +5 -8
  59. esphome/components/image/image.cpp +14 -14
  60. esphome/components/image/image.h +20 -24
  61. esphome/components/internal_temperature/internal_temperature.cpp +51 -2
  62. esphome/components/internal_temperature/internal_temperature.h +1 -0
  63. esphome/components/ld2420/ld2420.cpp +1 -1
  64. esphome/components/libretiny/gpio.py +4 -2
  65. esphome/components/light/__init__.py +32 -1
  66. esphome/components/light/automation.py +39 -32
  67. esphome/components/light/effects.py +36 -36
  68. esphome/components/light/light_state.cpp +6 -16
  69. esphome/components/light/light_state.h +34 -0
  70. esphome/components/light/types.py +3 -1
  71. esphome/components/logger/logger_esp32.cpp +15 -0
  72. esphome/components/lvgl/__init__.py +202 -95
  73. esphome/components/lvgl/automation.py +42 -40
  74. esphome/components/lvgl/binary_sensor/__init__.py +8 -15
  75. esphome/components/lvgl/defines.py +14 -8
  76. esphome/components/lvgl/encoders.py +11 -8
  77. esphome/components/lvgl/keypads.py +77 -0
  78. esphome/components/lvgl/light/__init__.py +6 -8
  79. esphome/components/lvgl/lv_validation.py +2 -4
  80. esphome/components/lvgl/lvcode.py +3 -9
  81. esphome/components/lvgl/lvgl_esphome.cpp +210 -89
  82. esphome/components/lvgl/lvgl_esphome.h +113 -30
  83. esphome/components/lvgl/lvgl_proxy.h +17 -0
  84. esphome/components/lvgl/number/__init__.py +10 -15
  85. esphome/components/lvgl/schemas.py +4 -2
  86. esphome/components/lvgl/select/__init__.py +12 -37
  87. esphome/components/lvgl/select/lvgl_select.h +27 -33
  88. esphome/components/lvgl/sensor/__init__.py +8 -14
  89. esphome/components/lvgl/styles.py +3 -4
  90. esphome/components/lvgl/switch/__init__.py +8 -13
  91. esphome/components/lvgl/text/__init__.py +5 -6
  92. esphome/components/lvgl/text_sensor/__init__.py +15 -15
  93. esphome/components/lvgl/touchscreens.py +2 -3
  94. esphome/components/lvgl/trigger.py +7 -9
  95. esphome/components/lvgl/types.py +9 -3
  96. esphome/components/lvgl/widgets/__init__.py +32 -21
  97. esphome/components/lvgl/widgets/dropdown.py +22 -10
  98. esphome/components/lvgl/widgets/msgbox.py +6 -5
  99. esphome/components/lvgl/widgets/obj.py +4 -2
  100. esphome/components/lvgl/widgets/page.py +3 -2
  101. esphome/components/lvgl/widgets/qrcode.py +54 -0
  102. esphome/components/lvgl/widgets/roller.py +21 -14
  103. esphome/components/lvgl/widgets/tileview.py +2 -1
  104. esphome/components/max17043/__init__.py +1 -0
  105. esphome/components/max17043/automation.h +20 -0
  106. esphome/components/max17043/max17043.cpp +98 -0
  107. esphome/components/max17043/max17043.h +29 -0
  108. esphome/components/max17043/sensor.py +77 -0
  109. esphome/components/media_player/__init__.py +11 -0
  110. esphome/components/media_player/automation.h +10 -0
  111. esphome/components/media_player/media_player.cpp +4 -0
  112. esphome/components/midea/air_conditioner.cpp +17 -1
  113. esphome/components/mlx90393/sensor.py +1 -1
  114. esphome/components/modbus_controller/__init__.py +31 -1
  115. esphome/components/modbus_controller/automation.h +16 -0
  116. esphome/components/modbus_controller/const.py +2 -0
  117. esphome/components/modbus_controller/modbus_controller.cpp +14 -2
  118. esphome/components/modbus_controller/modbus_controller.h +9 -0
  119. esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +40 -21
  120. esphome/components/mopeka_pro_check/mopeka_pro_check.h +9 -2
  121. esphome/components/mopeka_pro_check/sensor.py +41 -0
  122. esphome/components/mqtt/__init__.py +36 -0
  123. esphome/components/mqtt/mqtt_client.cpp +27 -3
  124. esphome/components/mqtt/mqtt_client.h +27 -2
  125. esphome/components/mqtt/mqtt_climate.cpp +4 -2
  126. esphome/components/mqtt/mqtt_component.cpp +6 -0
  127. esphome/components/mqtt/mqtt_component.h +4 -0
  128. esphome/components/mqtt/mqtt_const.h +6 -0
  129. esphome/components/online_image/online_image.cpp +2 -8
  130. esphome/components/online_image/online_image.h +2 -6
  131. esphome/components/opentherm/__init__.py +35 -9
  132. esphome/components/opentherm/binary_sensor/__init__.py +33 -0
  133. esphome/components/opentherm/const.py +11 -0
  134. esphome/components/opentherm/generate.py +142 -0
  135. esphome/components/opentherm/hub.cpp +130 -24
  136. esphome/components/opentherm/hub.h +62 -9
  137. esphome/components/opentherm/input.h +18 -0
  138. esphome/components/opentherm/input.py +51 -0
  139. esphome/components/opentherm/number/__init__.py +74 -0
  140. esphome/components/opentherm/number/number.cpp +40 -0
  141. esphome/components/opentherm/number/number.h +31 -0
  142. esphome/components/opentherm/opentherm.cpp +30 -0
  143. esphome/components/opentherm/opentherm.h +34 -2
  144. esphome/components/opentherm/opentherm_macros.h +151 -0
  145. esphome/components/opentherm/output/__init__.py +47 -0
  146. esphome/components/opentherm/output/output.cpp +18 -0
  147. esphome/components/opentherm/output/output.h +33 -0
  148. esphome/components/opentherm/schema.py +814 -0
  149. esphome/components/opentherm/sensor/__init__.py +51 -0
  150. esphome/components/opentherm/switch/__init__.py +43 -0
  151. esphome/components/opentherm/switch/switch.cpp +28 -0
  152. esphome/components/opentherm/switch/switch.h +20 -0
  153. esphome/components/opentherm/validate.py +31 -0
  154. esphome/components/pcd8544/display.py +8 -4
  155. esphome/components/prometheus/prometheus_handler.cpp +176 -14
  156. esphome/components/prometheus/prometheus_handler.h +25 -7
  157. esphome/components/qspi_amoled/display.py +1 -141
  158. esphome/components/qspi_dbi/display.py +185 -0
  159. esphome/components/qspi_dbi/models.py +64 -0
  160. esphome/components/{qspi_amoled/qspi_amoled.cpp → qspi_dbi/qspi_dbi.cpp} +95 -46
  161. esphome/components/{qspi_amoled/qspi_amoled.h → qspi_dbi/qspi_dbi.h} +26 -15
  162. esphome/components/rp2040/__init__.py +6 -3
  163. esphome/components/rp2040/gpio.py +5 -3
  164. esphome/components/rtttl/rtttl.cpp +4 -1
  165. esphome/components/rtttl/rtttl.h +1 -0
  166. esphome/components/sdl/sdl_esphome.cpp +22 -5
  167. esphome/components/sdl/sdl_esphome.h +1 -0
  168. esphome/components/sdm_meter/sdm_meter.cpp +1 -1
  169. esphome/components/sensor/__init__.py +18 -8
  170. esphome/components/sensor/filter.cpp +19 -18
  171. esphome/components/sensor/filter.h +9 -10
  172. esphome/components/sgp4x/sgp4x.cpp +40 -74
  173. esphome/components/sgp4x/sgp4x.h +5 -3
  174. esphome/components/speaker/__init__.py +51 -5
  175. esphome/components/speaker/automation.h +25 -0
  176. esphome/components/speaker/speaker.h +72 -1
  177. esphome/components/spi/__init__.py +15 -14
  178. esphome/components/spi_device/__init__.py +4 -15
  179. esphome/components/ssd1306_spi/display.py +6 -2
  180. esphome/components/ssd1322_spi/display.py +6 -2
  181. esphome/components/ssd1325_spi/display.py +6 -2
  182. esphome/components/ssd1327_spi/display.py +6 -2
  183. esphome/components/ssd1331_spi/display.py +6 -2
  184. esphome/components/ssd1351_spi/display.py +6 -2
  185. esphome/components/st7567_spi/display.py +6 -2
  186. esphome/components/st7701s/display.py +5 -1
  187. esphome/components/st7735/display.py +10 -5
  188. esphome/components/st7789v/display.py +12 -7
  189. esphome/components/statsd/statsd.cpp +2 -0
  190. esphome/components/statsd/statsd.h +2 -0
  191. esphome/components/sun/sun.h +3 -0
  192. esphome/components/tc74/__init__.py +1 -0
  193. esphome/components/tc74/sensor.py +32 -0
  194. esphome/components/tc74/tc74.cpp +68 -0
  195. esphome/components/tc74/tc74.h +28 -0
  196. esphome/components/touchscreen/__init__.py +41 -50
  197. esphome/components/touchscreen/touchscreen.h +4 -8
  198. esphome/components/tuya/fan/tuya_fan.cpp +1 -1
  199. esphome/components/udp/udp_component.cpp +6 -3
  200. esphome/components/udp/udp_component.h +4 -2
  201. esphome/components/waveshare_epaper/display.py +6 -2
  202. esphome/components/web_server/web_server.cpp +22 -0
  203. esphome/components/web_server/web_server.h +3 -0
  204. esphome/components/weikai/weikai.h +2 -2
  205. esphome/components/wifi/wifi_component.cpp +2 -2
  206. esphome/components/wifi/wifi_component_esp32_arduino.cpp +4 -4
  207. esphome/components/wifi/wifi_component_esp8266.cpp +4 -4
  208. esphome/components/wifi/wifi_component_esp_idf.cpp +2 -2
  209. esphome/components/xpt2046/touchscreen/__init__.py +7 -32
  210. esphome/config_validation.py +3 -1
  211. esphome/const.py +9 -2
  212. esphome/core/defines.h +8 -2
  213. esphome/core/helpers.cpp +32 -17
  214. esphome/core/helpers.h +32 -16
  215. esphome/core/ring_buffer.cpp +2 -2
  216. esphome/core/ring_buffer.h +2 -2
  217. esphome/dashboard/core.py +25 -0
  218. esphome/dashboard/status/mdns.py +3 -4
  219. esphome/dashboard/web_server.py +54 -19
  220. esphome/espota2.py +36 -35
  221. esphome/helpers.py +68 -16
  222. esphome/mqtt.py +9 -2
  223. esphome/storage_json.py +4 -0
  224. esphome/writer.py +7 -18
  225. esphome/zeroconf.py +8 -6
  226. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/METADATA +7 -5
  227. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/RECORD +232 -186
  228. esphome/core/bytebuffer.cpp +0 -167
  229. esphome/core/bytebuffer.h +0 -144
  230. /esphome/components/{qspi_amoled → qspi_dbi}/__init__.py +0 -0
  231. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/LICENSE +0 -0
  232. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/WHEEL +0 -0
  233. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/entry_points.txt +0 -0
  234. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/top_level.txt +0 -0
@@ -5,45 +5,30 @@
5
5
  #include "../i2s_audio.h"
6
6
 
7
7
  #include <driver/i2s.h>
8
- #include <freertos/FreeRTOS.h>
8
+
9
+ #include <freertos/event_groups.h>
9
10
  #include <freertos/queue.h>
11
+ #include <freertos/FreeRTOS.h>
10
12
 
13
+ #include "esphome/components/audio/audio.h"
11
14
  #include "esphome/components/speaker/speaker.h"
15
+
12
16
  #include "esphome/core/component.h"
13
17
  #include "esphome/core/gpio.h"
14
18
  #include "esphome/core/helpers.h"
19
+ #include "esphome/core/ring_buffer.h"
15
20
 
16
21
  namespace esphome {
17
22
  namespace i2s_audio {
18
23
 
19
- static const size_t BUFFER_SIZE = 1024;
20
-
21
- enum class TaskEventType : uint8_t {
22
- STARTING = 0,
23
- STARTED,
24
- STOPPING,
25
- STOPPED,
26
- WARNING = 255,
27
- };
28
-
29
- struct TaskEvent {
30
- TaskEventType type;
31
- esp_err_t err;
32
- };
33
-
34
- struct DataEvent {
35
- bool stop;
36
- size_t len;
37
- uint8_t data[BUFFER_SIZE];
38
- };
39
-
40
24
  class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Component {
41
25
  public:
42
- float get_setup_priority() const override { return esphome::setup_priority::LATE; }
26
+ float get_setup_priority() const override { return esphome::setup_priority::PROCESSOR; }
43
27
 
44
28
  void setup() override;
45
29
  void loop() override;
46
30
 
31
+ void set_buffer_duration(uint32_t buffer_duration_ms) { this->buffer_duration_ms_ = buffer_duration_ms; }
47
32
  void set_timeout(uint32_t ms) { this->timeout_ = ms; }
48
33
  void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; }
49
34
  #if SOC_I2S_SUPPORTS_DAC
@@ -55,25 +40,99 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
55
40
  void stop() override;
56
41
  void finish() override;
57
42
 
58
- size_t play(const uint8_t *data, size_t length) override;
43
+ /// @brief Plays the provided audio data.
44
+ /// Starts the speaker task, if necessary. Writes the audio data to the ring buffer.
45
+ /// @param data Audio data in the format set by the parent speaker classes ``set_audio_stream_info`` method.
46
+ /// @param length The length of the audio data in bytes.
47
+ /// @param ticks_to_wait The FreeRTOS ticks to wait before writing as much data as possible to the ring buffer.
48
+ /// @return The number of bytes that were actually written to the ring buffer.
49
+ size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) override;
50
+ size_t play(const uint8_t *data, size_t length) override { return play(data, length, 0); }
59
51
 
60
52
  bool has_buffered_data() const override;
61
53
 
54
+ /// @brief Sets the volume of the speaker. Uses the speaker's configured audio dac component. If unavailble, it is
55
+ /// implemented as a software volume control. Overrides the default setter to convert the floating point volume to a
56
+ /// Q15 fixed-point factor.
57
+ /// @param volume between 0.0 and 1.0
58
+ void set_volume(float volume) override;
59
+
60
+ /// @brief Mutes or unmute the speaker. Uses the speaker's configured audio dac component. If unavailble, it is
61
+ /// implemented as a software volume control. Overrides the default setter to convert the floating point volume to a
62
+ /// Q15 fixed-point factor.
63
+ /// @param mute_state true for muting, false for unmuting
64
+ void set_mute_state(bool mute_state) override;
65
+
62
66
  protected:
63
- void start_();
67
+ /// @brief Function for the FreeRTOS task handling audio output.
68
+ /// After receiving the COMMAND_START signal, allocates space for the buffers, starts the I2S driver, and reads
69
+ /// audio from the ring buffer and writes audio to the I2S port. Stops immmiately after receiving the COMMAND_STOP
70
+ /// signal and stops only after the ring buffer is empty after receiving the COMMAND_STOP_GRACEFULLY signal. Stops if
71
+ /// the ring buffer hasn't read data for more than timeout_ milliseconds. When stopping, it deallocates the buffers,
72
+ /// stops the I2S driver, unlocks the I2S port, and deletes the task. It communicates the state and any errors via
73
+ /// event_group_.
74
+ /// @param params I2SAudioSpeaker component
75
+ static void speaker_task(void *params);
76
+
77
+ /// @brief Sends a stop command to the speaker task via event_group_.
78
+ /// @param wait_on_empty If false, sends the COMMAND_STOP signal. If true, sends the COMMAND_STOP_GRACEFULLY signal.
64
79
  void stop_(bool wait_on_empty);
65
- void watch_();
66
-
67
- static void player_task(void *params);
68
80
 
69
- TaskHandle_t player_task_handle_{nullptr};
70
- QueueHandle_t buffer_queue_;
71
- QueueHandle_t event_queue_;
81
+ /// @brief Sets the corresponding ERR_ESP event group bits.
82
+ /// @param err esp_err_t error code.
83
+ /// @return True if an ERR_ESP bit is set and false if err == ESP_OK
84
+ bool send_esp_err_to_event_group_(esp_err_t err);
85
+
86
+ /// @brief Allocates the data buffer and ring buffer
87
+ /// @param data_buffer_size Number of bytes to allocate for the data buffer.
88
+ /// @param ring_buffer_size Number of bytes to allocate for the ring buffer.
89
+ /// @return ESP_ERR_NO_MEM if either buffer fails to allocate
90
+ /// ESP_OK if successful
91
+ esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size);
92
+
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.
98
+ /// 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);
112
+
113
+ /// @brief Deletes the speaker's task.
114
+ /// Deallocates the data_buffer_ and audio_ring_buffer_, if necessary, and deletes the task. Should only be called by
115
+ /// the speaker_task itself.
116
+ /// @param buffer_size The allocated size of the data_buffer_.
117
+ void delete_task_(size_t buffer_size);
118
+
119
+ TaskHandle_t speaker_task_handle_{nullptr};
120
+ EventGroupHandle_t event_group_{nullptr};
121
+
122
+ QueueHandle_t i2s_event_queue_;
123
+
124
+ uint8_t *data_buffer_;
125
+ std::shared_ptr<RingBuffer> audio_ring_buffer_;
126
+
127
+ uint32_t buffer_duration_ms_;
128
+
129
+ optional<uint32_t> timeout_;
130
+ uint8_t dout_pin_;
72
131
 
73
- uint32_t timeout_{0};
74
- uint8_t dout_pin_{0};
75
132
  bool task_created_{false};
76
133
 
134
+ int16_t q15_volume_factor_{INT16_MAX};
135
+
77
136
  #if SOC_I2S_SUPPORTS_DAC
78
137
  i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE};
79
138
  #endif
@@ -10,6 +10,7 @@ from esphome.const import (
10
10
  CONF_DIMENSIONS,
11
11
  CONF_HEIGHT,
12
12
  CONF_ID,
13
+ CONF_INIT_SEQUENCE,
13
14
  CONF_INVERT_COLORS,
14
15
  CONF_LAMBDA,
15
16
  CONF_MIRROR_X,
@@ -89,7 +90,6 @@ CONF_LED_PIN = "led_pin"
89
90
  CONF_COLOR_PALETTE_IMAGES = "color_palette_images"
90
91
  CONF_INVERT_DISPLAY = "invert_display"
91
92
  CONF_PIXEL_MODE = "pixel_mode"
92
- CONF_INIT_SEQUENCE = "init_sequence"
93
93
 
94
94
 
95
95
  def cmd(c, *args):
@@ -196,6 +196,10 @@ CONFIG_SCHEMA = cv.All(
196
196
  _validate,
197
197
  )
198
198
 
199
+ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema(
200
+ "ili9xxx", require_miso=False, require_mosi=True
201
+ )
202
+
199
203
 
200
204
  async def to_code(config):
201
205
  rhs = MODELS[config[CONF_MODEL]].new()
@@ -361,24 +361,21 @@ async def to_code(config):
361
361
  elif config[CONF_TYPE] in ["RGB565"]:
362
362
  image = image.convert("RGBA")
363
363
  pixels = list(image.getdata())
364
- data = [0 for _ in range(height * width * 2)]
364
+ bytes_per_pixel = 3 if transparent else 2
365
+ data = [0 for _ in range(height * width * bytes_per_pixel)]
365
366
  pos = 0
366
367
  for r, g, b, a in pixels:
367
368
  R = r >> 3
368
369
  G = g >> 2
369
370
  B = b >> 3
370
371
  rgb = (R << 11) | (G << 5) | B
371
-
372
- if transparent:
373
- if rgb == 0x0020:
374
- rgb = 0
375
- if a < 0x80:
376
- rgb = 0x0020
377
-
378
372
  data[pos] = rgb >> 8
379
373
  pos += 1
380
374
  data[pos] = rgb & 0xFF
381
375
  pos += 1
376
+ if transparent:
377
+ data[pos] = a
378
+ pos += 1
382
379
 
383
380
  elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
384
381
  if transparent:
@@ -88,7 +88,7 @@ lv_img_dsc_t *Image::get_lv_img_dsc() {
88
88
  this->dsc_.header.reserved = 0;
89
89
  this->dsc_.header.w = this->width_;
90
90
  this->dsc_.header.h = this->height_;
91
- this->dsc_.data_size = image_type_to_width_stride(this->dsc_.header.w * this->dsc_.header.h, this->get_type());
91
+ this->dsc_.data_size = this->get_width_stride() * this->get_height();
92
92
  switch (this->get_type()) {
93
93
  case IMAGE_TYPE_BINARY:
94
94
  this->dsc_.header.cf = LV_IMG_CF_ALPHA_1BIT;
@@ -104,17 +104,17 @@ lv_img_dsc_t *Image::get_lv_img_dsc() {
104
104
 
105
105
  case IMAGE_TYPE_RGB565:
106
106
  #if LV_COLOR_DEPTH == 16
107
- this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED : LV_IMG_CF_TRUE_COLOR;
107
+ this->dsc_.header.cf = this->has_transparency() ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR;
108
108
  #else
109
109
  this->dsc_.header.cf = LV_IMG_CF_RGB565;
110
110
  #endif
111
111
  break;
112
112
 
113
- case image::IMAGE_TYPE_RGBA:
113
+ case IMAGE_TYPE_RGBA:
114
114
  #if LV_COLOR_DEPTH == 32
115
115
  this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR;
116
116
  #else
117
- this->dsc_.header.cf = LV_IMG_CF_RGBA8888;
117
+ this->dsc_.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
118
118
  #endif
119
119
  break;
120
120
  }
@@ -147,21 +147,21 @@ Color Image::get_rgb24_pixel_(int x, int y) const {
147
147
  return color;
148
148
  }
149
149
  Color Image::get_rgb565_pixel_(int x, int y) const {
150
- const uint32_t pos = (x + y * this->width_) * 2;
151
- uint16_t rgb565 =
152
- progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1);
150
+ const uint8_t *pos = this->data_start_;
151
+ if (this->transparent_) {
152
+ pos += (x + y * this->width_) * 3;
153
+ } else {
154
+ pos += (x + y * this->width_) * 2;
155
+ }
156
+ uint16_t rgb565 = encode_uint16(progmem_read_byte(pos), progmem_read_byte(pos + 1));
153
157
  auto r = (rgb565 & 0xF800) >> 11;
154
158
  auto g = (rgb565 & 0x07E0) >> 5;
155
159
  auto b = rgb565 & 0x001F;
156
- Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2));
157
- if (rgb565 == 0x0020 && transparent_) {
158
- // darkest green has been defined as transparent color for transparent RGB565 images.
159
- color.w = 0;
160
- } else {
161
- color.w = 0xFF;
162
- }
160
+ auto a = this->transparent_ ? progmem_read_byte(pos + 2) : 0xFF;
161
+ Color color = Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2), a);
163
162
  return color;
164
163
  }
164
+
165
165
  Color Image::get_grayscale_pixel_(int x, int y) const {
166
166
  const uint32_t pos = (x + y * this->width_);
167
167
  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
@@ -3,12 +3,7 @@
3
3
  #include "esphome/components/display/display.h"
4
4
 
5
5
  #ifdef USE_LVGL
6
- // required for clang-tidy
7
- #ifndef LV_CONF_H
8
- #define LV_CONF_SKIP 1 // NOLINT
9
- #endif // LV_CONF_H
10
-
11
- #include <lvgl.h>
6
+ #include "esphome/components/lvgl/lvgl_proxy.h"
12
7
  #endif // USE_LVGL
13
8
 
14
9
  namespace esphome {
@@ -22,24 +17,6 @@ enum ImageType {
22
17
  IMAGE_TYPE_RGBA = 4,
23
18
  };
24
19
 
25
- inline int image_type_to_bpp(ImageType type) {
26
- switch (type) {
27
- case IMAGE_TYPE_BINARY:
28
- return 1;
29
- case IMAGE_TYPE_GRAYSCALE:
30
- return 8;
31
- case IMAGE_TYPE_RGB565:
32
- return 16;
33
- case IMAGE_TYPE_RGB24:
34
- return 24;
35
- case IMAGE_TYPE_RGBA:
36
- return 32;
37
- }
38
- return 0;
39
- }
40
-
41
- inline int image_type_to_width_stride(int width, ImageType type) { return (width * image_type_to_bpp(type) + 7u) / 8u; }
42
-
43
20
  class Image : public display::BaseImage {
44
21
  public:
45
22
  Image(const uint8_t *data_start, int width, int height, ImageType type);
@@ -49,6 +26,25 @@ class Image : public display::BaseImage {
49
26
  const uint8_t *get_data_start() const { return this->data_start_; }
50
27
  ImageType get_type() const;
51
28
 
29
+ int get_bpp() const {
30
+ switch (this->type_) {
31
+ case IMAGE_TYPE_BINARY:
32
+ return 1;
33
+ case IMAGE_TYPE_GRAYSCALE:
34
+ return 8;
35
+ case IMAGE_TYPE_RGB565:
36
+ return this->transparent_ ? 24 : 16;
37
+ case IMAGE_TYPE_RGB24:
38
+ return 24;
39
+ case IMAGE_TYPE_RGBA:
40
+ return 32;
41
+ }
42
+ return 0;
43
+ }
44
+
45
+ /// Return the stride of the image in bytes, that is, the distance in bytes
46
+ /// between two consecutive rows of pixels.
47
+ uint32_t get_width_stride() const { return (this->width_ * this->get_bpp() + 7u) / 8u; }
52
48
  void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
53
49
 
54
50
  void set_transparency(bool transparent) { transparent_ = transparent; }
@@ -7,8 +7,14 @@
7
7
  extern "C" {
8
8
  uint8_t temprature_sens_read();
9
9
  }
10
- #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
10
+ #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
11
+ defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \
12
+ defined(USE_ESP32_VARIANT_ESP32C2)
13
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
11
14
  #include "driver/temp_sensor.h"
15
+ #else
16
+ #include "driver/temperature_sensor.h"
17
+ #endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
12
18
  #endif // USE_ESP32_VARIANT
13
19
  #endif // USE_ESP32
14
20
  #ifdef USE_RP2040
@@ -24,6 +30,13 @@ namespace esphome {
24
30
  namespace internal_temperature {
25
31
 
26
32
  static const char *const TAG = "internal_temperature";
33
+ #ifdef USE_ESP32
34
+ #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \
35
+ (defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
36
+ defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2))
37
+ static temperature_sensor_handle_t tsensNew = NULL;
38
+ #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT
39
+ #endif // USE_ESP32
27
40
 
28
41
  void InternalTemperatureSensor::update() {
29
42
  float temperature = NAN;
@@ -34,7 +47,10 @@ void InternalTemperatureSensor::update() {
34
47
  ESP_LOGV(TAG, "Raw temperature value: %d", raw);
35
48
  temperature = (raw - 32) / 1.8f;
36
49
  success = (raw != 128);
37
- #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
50
+ #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
51
+ defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \
52
+ defined(USE_ESP32_VARIANT_ESP32C2)
53
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
38
54
  temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT();
39
55
  temp_sensor_set_config(tsens);
40
56
  temp_sensor_start();
@@ -45,6 +61,13 @@ void InternalTemperatureSensor::update() {
45
61
  esp_err_t result = temp_sensor_read_celsius(&temperature);
46
62
  temp_sensor_stop();
47
63
  success = (result == ESP_OK);
64
+ #else
65
+ esp_err_t result = temperature_sensor_get_celsius(tsensNew, &temperature);
66
+ success = (result == ESP_OK);
67
+ if (!success) {
68
+ ESP_LOGE(TAG, "Failed to get temperature: %d", result);
69
+ }
70
+ #endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
48
71
  #endif // USE_ESP32_VARIANT
49
72
  #endif // USE_ESP32
50
73
  #ifdef USE_RP2040
@@ -73,6 +96,32 @@ void InternalTemperatureSensor::update() {
73
96
  }
74
97
  }
75
98
 
99
+ void InternalTemperatureSensor::setup() {
100
+ #ifdef USE_ESP32
101
+ #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \
102
+ (defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
103
+ defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2))
104
+ ESP_LOGCONFIG(TAG, "Setting up temperature sensor...");
105
+
106
+ temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
107
+
108
+ esp_err_t result = temperature_sensor_install(&tsens_config, &tsensNew);
109
+ if (result != ESP_OK) {
110
+ ESP_LOGE(TAG, "Failed to install temperature sensor: %d", result);
111
+ this->mark_failed();
112
+ return;
113
+ }
114
+
115
+ result = temperature_sensor_enable(tsensNew);
116
+ if (result != ESP_OK) {
117
+ ESP_LOGE(TAG, "Failed to enable temperature sensor: %d", result);
118
+ this->mark_failed();
119
+ return;
120
+ }
121
+ #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT
122
+ #endif // USE_ESP32
123
+ }
124
+
76
125
  void InternalTemperatureSensor::dump_config() { LOG_SENSOR("", "Internal Temperature Sensor", this); }
77
126
 
78
127
  } // namespace internal_temperature
@@ -8,6 +8,7 @@ namespace internal_temperature {
8
8
 
9
9
  class InternalTemperatureSensor : public sensor::Sensor, public PollingComponent {
10
10
  public:
11
+ void setup() override;
11
12
  void dump_config() override;
12
13
 
13
14
  void update() override;
@@ -180,7 +180,7 @@ void LD2420Component::apply_config_action() {
180
180
  }
181
181
 
182
182
  void LD2420Component::factory_reset_action() {
183
- ESP_LOGCONFIG(TAG, "Setiing factory defaults...");
183
+ ESP_LOGCONFIG(TAG, "Setting factory defaults...");
184
184
  if (this->set_config_mode(true) == LD2420_ERROR_TIMEOUT) {
185
185
  ESP_LOGE(TAG, "LD2420 module has failed to respond, check baud rate and serial connections.");
186
186
  this->mark_failed();
@@ -1,8 +1,8 @@
1
1
  import logging
2
2
 
3
+ from esphome import pins
3
4
  import esphome.codegen as cg
4
5
  import esphome.config_validation as cv
5
- from esphome import pins
6
6
  from esphome.const import (
7
7
  CONF_ANALOG,
8
8
  CONF_ID,
@@ -103,8 +103,10 @@ def _translate_pin(value):
103
103
  "This variable only supports pin numbers, not full pin schemas "
104
104
  "(with inverted and mode)."
105
105
  )
106
- if isinstance(value, int):
106
+ if isinstance(value, int) and not isinstance(value, bool):
107
107
  return value
108
+ if not isinstance(value, str):
109
+ raise cv.Invalid(f"Invalid pin number: {value}")
108
110
  try:
109
111
  return int(value)
110
112
  except ValueError:
@@ -3,27 +3,39 @@ import esphome.codegen as cg
3
3
  from esphome.components import mqtt, power_supply, web_server
4
4
  import esphome.config_validation as cv
5
5
  from esphome.const import (
6
+ CONF_BLUE,
7
+ CONF_BRIGHTNESS,
8
+ CONF_COLD_WHITE,
6
9
  CONF_COLD_WHITE_COLOR_TEMPERATURE,
10
+ CONF_COLOR_BRIGHTNESS,
7
11
  CONF_COLOR_CORRECT,
12
+ CONF_COLOR_MODE,
13
+ CONF_COLOR_TEMPERATURE,
8
14
  CONF_DEFAULT_TRANSITION_LENGTH,
9
15
  CONF_EFFECTS,
10
16
  CONF_FLASH_TRANSITION_LENGTH,
11
17
  CONF_GAMMA_CORRECT,
18
+ CONF_GREEN,
12
19
  CONF_ID,
20
+ CONF_INITIAL_STATE,
13
21
  CONF_MQTT_ID,
14
22
  CONF_ON_STATE,
15
23
  CONF_ON_TURN_OFF,
16
24
  CONF_ON_TURN_ON,
17
25
  CONF_POWER_SUPPLY,
26
+ CONF_RED,
18
27
  CONF_RESTORE_MODE,
28
+ CONF_STATE,
19
29
  CONF_TRIGGER_ID,
30
+ CONF_WARM_WHITE,
20
31
  CONF_WARM_WHITE_COLOR_TEMPERATURE,
21
32
  CONF_WEB_SERVER,
33
+ CONF_WHITE,
22
34
  )
23
35
  from esphome.core import coroutine_with_priority
24
36
  from esphome.cpp_helpers import setup_entity
25
37
 
26
- from .automation import light_control_to_code # noqa
38
+ from .automation import LIGHT_STATE_SCHEMA
27
39
  from .effects import (
28
40
  ADDRESSABLE_EFFECTS,
29
41
  BINARY_EFFECTS,
@@ -35,8 +47,10 @@ from .effects import (
35
47
  from .types import ( # noqa
36
48
  AddressableLight,
37
49
  AddressableLightState,
50
+ ColorMode,
38
51
  LightOutput,
39
52
  LightState,
53
+ LightStateRTCState,
40
54
  LightStateTrigger,
41
55
  LightTurnOffTrigger,
42
56
  LightTurnOnTrigger,
@@ -85,6 +99,7 @@ LIGHT_SCHEMA = (
85
99
  cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightStateTrigger),
86
100
  }
87
101
  ),
102
+ cv.Optional(CONF_INITIAL_STATE): LIGHT_STATE_SCHEMA,
88
103
  }
89
104
  )
90
105
  )
@@ -145,6 +160,22 @@ async def setup_light_core_(light_var, output_var, config):
145
160
 
146
161
  cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))
147
162
 
163
+ if (initial_state_config := config.get(CONF_INITIAL_STATE)) is not None:
164
+ initial_state = LightStateRTCState(
165
+ initial_state_config.get(CONF_COLOR_MODE, ColorMode.UNKNOWN),
166
+ initial_state_config.get(CONF_STATE, False),
167
+ initial_state_config.get(CONF_BRIGHTNESS, 1.0),
168
+ initial_state_config.get(CONF_COLOR_BRIGHTNESS, 1.0),
169
+ initial_state_config.get(CONF_RED, 1.0),
170
+ initial_state_config.get(CONF_GREEN, 1.0),
171
+ initial_state_config.get(CONF_BLUE, 1.0),
172
+ initial_state_config.get(CONF_WHITE, 1.0),
173
+ initial_state_config.get(CONF_COLOR_TEMPERATURE, 1.0),
174
+ initial_state_config.get(CONF_COLD_WHITE, 1.0),
175
+ initial_state_config.get(CONF_WARM_WHITE, 1.0),
176
+ )
177
+ cg.add(light_var.set_initial_state(initial_state))
178
+
148
179
  if (
149
180
  default_transition_length := config.get(CONF_DEFAULT_TRANSITION_LENGTH)
150
181
  ) is not None:
@@ -1,41 +1,42 @@
1
+ from esphome import automation
1
2
  import esphome.codegen as cg
2
3
  import esphome.config_validation as cv
3
- from esphome import automation
4
4
  from esphome.const import (
5
- CONF_ID,
6
- CONF_COLOR_MODE,
7
- CONF_TRANSITION_LENGTH,
8
- CONF_STATE,
9
- CONF_FLASH_LENGTH,
10
- CONF_EFFECT,
5
+ CONF_BLUE,
11
6
  CONF_BRIGHTNESS,
7
+ CONF_BRIGHTNESS_LIMITS,
8
+ CONF_COLD_WHITE,
12
9
  CONF_COLOR_BRIGHTNESS,
13
- CONF_RED,
14
- CONF_GREEN,
15
- CONF_BLUE,
16
- CONF_WHITE,
10
+ CONF_COLOR_MODE,
17
11
  CONF_COLOR_TEMPERATURE,
18
- CONF_COLD_WHITE,
19
- CONF_WARM_WHITE,
20
- CONF_RANGE_FROM,
21
- CONF_RANGE_TO,
22
- CONF_BRIGHTNESS_LIMITS,
12
+ CONF_EFFECT,
13
+ CONF_FLASH_LENGTH,
14
+ CONF_GREEN,
15
+ CONF_ID,
23
16
  CONF_LIMIT_MODE,
24
- CONF_MIN_BRIGHTNESS,
25
17
  CONF_MAX_BRIGHTNESS,
18
+ CONF_MIN_BRIGHTNESS,
19
+ CONF_RANGE_FROM,
20
+ CONF_RANGE_TO,
21
+ CONF_RED,
22
+ CONF_STATE,
23
+ CONF_TRANSITION_LENGTH,
24
+ CONF_WARM_WHITE,
25
+ CONF_WHITE,
26
26
  )
27
+
27
28
  from .types import (
28
- ColorMode,
29
29
  COLOR_MODES,
30
30
  LIMIT_MODES,
31
- DimRelativeAction,
32
- ToggleAction,
33
- LightState,
34
- LightControlAction,
35
31
  AddressableLightState,
36
32
  AddressableSet,
37
- LightIsOnCondition,
33
+ ColorMode,
34
+ DimRelativeAction,
35
+ LightControlAction,
38
36
  LightIsOffCondition,
37
+ LightIsOnCondition,
38
+ LightState,
39
+ ToggleAction,
39
40
  )
40
41
 
41
42
 
@@ -62,18 +63,10 @@ async def light_toggle_to_code(config, action_id, template_arg, args):
62
63
  return var
63
64
 
64
65
 
65
- LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema(
66
+ LIGHT_STATE_SCHEMA = cv.Schema(
66
67
  {
67
- cv.Required(CONF_ID): cv.use_id(LightState),
68
68
  cv.Optional(CONF_COLOR_MODE): cv.enum(COLOR_MODES, upper=True, space="_"),
69
69
  cv.Optional(CONF_STATE): cv.templatable(cv.boolean),
70
- cv.Exclusive(CONF_TRANSITION_LENGTH, "transformer"): cv.templatable(
71
- cv.positive_time_period_milliseconds
72
- ),
73
- cv.Exclusive(CONF_FLASH_LENGTH, "transformer"): cv.templatable(
74
- cv.positive_time_period_milliseconds
75
- ),
76
- cv.Exclusive(CONF_EFFECT, "transformer"): cv.templatable(cv.string),
77
70
  cv.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage),
78
71
  cv.Optional(CONF_COLOR_BRIGHTNESS): cv.templatable(cv.percentage),
79
72
  cv.Optional(CONF_RED): cv.templatable(cv.percentage),
@@ -85,6 +78,20 @@ LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema(
85
78
  cv.Optional(CONF_WARM_WHITE): cv.templatable(cv.percentage),
86
79
  }
87
80
  )
81
+
82
+ LIGHT_CONTROL_ACTION_SCHEMA = LIGHT_STATE_SCHEMA.extend(
83
+ {
84
+ cv.Required(CONF_ID): cv.use_id(LightState),
85
+ cv.Exclusive(CONF_TRANSITION_LENGTH, "transformer"): cv.templatable(
86
+ cv.positive_time_period_milliseconds
87
+ ),
88
+ cv.Exclusive(CONF_FLASH_LENGTH, "transformer"): cv.templatable(
89
+ cv.positive_time_period_milliseconds
90
+ ),
91
+ cv.Exclusive(CONF_EFFECT, "transformer"): cv.templatable(cv.string),
92
+ }
93
+ )
94
+
88
95
  LIGHT_TURN_OFF_ACTION_SCHEMA = automation.maybe_simple_id(
89
96
  {
90
97
  cv.Required(CONF_ID): cv.use_id(LightState),