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,6 +5,7 @@
5
5
  #include <vector>
6
6
  #include "esphome/core/component.h"
7
7
  #include "esphome/core/helpers.h"
8
+ #include "esphome/core/automation.h"
8
9
 
9
10
  namespace esphome {
10
11
  namespace sensor {
@@ -273,34 +274,33 @@ class LambdaFilter : public Filter {
273
274
  /// A simple filter that adds `offset` to each value it receives.
274
275
  class OffsetFilter : public Filter {
275
276
  public:
276
- explicit OffsetFilter(float offset);
277
+ explicit OffsetFilter(TemplatableValue<float> offset);
277
278
 
278
279
  optional<float> new_value(float value) override;
279
280
 
280
281
  protected:
281
- float offset_;
282
+ TemplatableValue<float> offset_;
282
283
  };
283
284
 
284
285
  /// A simple filter that multiplies to each value it receives by `multiplier`.
285
286
  class MultiplyFilter : public Filter {
286
287
  public:
287
- explicit MultiplyFilter(float multiplier);
288
-
288
+ explicit MultiplyFilter(TemplatableValue<float> multiplier);
289
289
  optional<float> new_value(float value) override;
290
290
 
291
291
  protected:
292
- float multiplier_;
292
+ TemplatableValue<float> multiplier_;
293
293
  };
294
294
 
295
295
  /// A simple filter that only forwards the filter chain if it doesn't receive `value_to_filter_out`.
296
296
  class FilterOutValueFilter : public Filter {
297
297
  public:
298
- explicit FilterOutValueFilter(float value_to_filter_out);
298
+ explicit FilterOutValueFilter(std::vector<TemplatableValue<float>> values_to_filter_out);
299
299
 
300
300
  optional<float> new_value(float value) override;
301
301
 
302
302
  protected:
303
- float value_to_filter_out_;
303
+ std::vector<TemplatableValue<float>> values_to_filter_out_;
304
304
  };
305
305
 
306
306
  class ThrottleFilter : public Filter {
@@ -316,8 +316,7 @@ class ThrottleFilter : public Filter {
316
316
 
317
317
  class TimeoutFilter : public Filter, public Component {
318
318
  public:
319
- explicit TimeoutFilter(uint32_t time_period, float new_value);
320
- void set_value(float new_value) { this->value_ = new_value; }
319
+ explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value);
321
320
 
322
321
  optional<float> new_value(float value) override;
323
322
 
@@ -325,7 +324,7 @@ class TimeoutFilter : public Filter, public Component {
325
324
 
326
325
  protected:
327
326
  uint32_t time_period_;
328
- float value_;
327
+ TemplatableValue<float> value_;
329
328
  };
330
329
 
331
330
  class DebounceFilter : public Filter, public Component {
@@ -111,7 +111,7 @@ void SGP4xComponent::setup() {
111
111
  number of records reported from being overwhelming.
112
112
  */
113
113
  ESP_LOGD(TAG, "Component requires sampling of 1Hz, setting up background sampler");
114
- this->set_interval(1000, [this]() { this->update_gas_indices(); });
114
+ this->set_interval(1000, [this]() { this->take_sample(); });
115
115
  }
116
116
 
117
117
  void SGP4xComponent::self_test_() {
@@ -146,31 +146,15 @@ void SGP4xComponent::self_test_() {
146
146
  });
147
147
  }
148
148
 
149
- /**
150
- * @brief Combined the measured gasses, temperature, and humidity
151
- * to calculate the VOC Index
152
- *
153
- * @param temperature The measured temperature in degrees C
154
- * @param humidity The measured relative humidity in % rH
155
- * @return int32_t The VOC Index
156
- */
157
- bool SGP4xComponent::measure_gas_indices_(int32_t &voc, int32_t &nox) {
158
- uint16_t voc_sraw;
159
- uint16_t nox_sraw;
160
- if (!measure_raw_(voc_sraw, nox_sraw))
161
- return false;
162
-
163
- this->status_clear_warning();
164
-
165
- voc = voc_algorithm_.process(voc_sraw);
166
- if (nox_sensor_) {
167
- nox = nox_algorithm_.process(nox_sraw);
168
- }
169
- ESP_LOGV(TAG, "VOC = %" PRId32 ", NOx = %" PRId32, voc, nox);
149
+ void SGP4xComponent::update_gas_indices_() {
150
+ this->voc_index_ = this->voc_algorithm_.process(this->voc_sraw_);
151
+ if (this->nox_sensor_ != nullptr)
152
+ this->nox_index_ = this->nox_algorithm_.process(this->nox_sraw_);
153
+ ESP_LOGV(TAG, "VOC = %" PRId32 ", NOx = %" PRId32, this->voc_index_, this->nox_index_);
170
154
  // Store baselines after defined interval or if the difference between current and stored baseline becomes too
171
155
  // much
172
156
  if (this->store_baseline_ && this->seconds_since_last_store_ > SHORTEST_BASELINE_STORE_INTERVAL) {
173
- voc_algorithm_.get_states(this->voc_state0_, this->voc_state1_);
157
+ this->voc_algorithm_.get_states(this->voc_state0_, this->voc_state1_);
174
158
  if (std::abs(this->voc_baselines_storage_.state0 - this->voc_state0_) > MAXIMUM_STORAGE_DIFF ||
175
159
  std::abs(this->voc_baselines_storage_.state1 - this->voc_state1_) > MAXIMUM_STORAGE_DIFF) {
176
160
  this->seconds_since_last_store_ = 0;
@@ -179,29 +163,27 @@ bool SGP4xComponent::measure_gas_indices_(int32_t &voc, int32_t &nox) {
179
163
 
180
164
  if (this->pref_.save(&this->voc_baselines_storage_)) {
181
165
  ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 " ,state1: 0x%04" PRIX32,
182
- this->voc_baselines_storage_.state0, voc_baselines_storage_.state1);
166
+ this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
183
167
  } else {
184
168
  ESP_LOGW(TAG, "Could not store VOC baselines");
185
169
  }
186
170
  }
187
171
  }
188
172
 
189
- return true;
173
+ if (this->samples_read_ < this->samples_to_stabilize_) {
174
+ this->samples_read_++;
175
+ ESP_LOGD(TAG, "Sensor has not collected enough samples yet. (%d/%d) VOC index is: %" PRIu32, this->samples_read_,
176
+ this->samples_to_stabilize_, this->voc_index_);
177
+ }
190
178
  }
191
- /**
192
- * @brief Return the raw gas measurement
193
- *
194
- * @param temperature The measured temperature in degrees C
195
- * @param humidity The measured relative humidity in % rH
196
- * @return uint16_t The current raw gas measurement
197
- */
198
- bool SGP4xComponent::measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw) {
179
+
180
+ void SGP4xComponent::measure_raw_() {
199
181
  float humidity = NAN;
200
182
  static uint32_t nox_conditioning_start = millis();
201
183
 
202
184
  if (!this->self_test_complete_) {
203
185
  ESP_LOGD(TAG, "Self-test not yet complete");
204
- return false;
186
+ return;
205
187
  }
206
188
  if (this->humidity_sensor_ != nullptr) {
207
189
  humidity = this->humidity_sensor_->state;
@@ -243,61 +225,45 @@ bool SGP4xComponent::measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw) {
243
225
  data[1] = tempticks;
244
226
 
245
227
  if (!this->write_command(command, data, 2)) {
246
- this->status_set_warning();
247
228
  ESP_LOGD(TAG, "write error (%d)", this->last_error_);
248
- return false;
249
- }
250
- delay(measure_time_);
251
- uint16_t raw_data[2];
252
- raw_data[1] = 0;
253
- if (!this->read_data(raw_data, response_words)) {
254
- this->status_set_warning();
255
- ESP_LOGD(TAG, "read error (%d)", this->last_error_);
256
- return false;
229
+ this->status_set_warning("measurement request failed");
230
+ return;
257
231
  }
258
- voc_raw = raw_data[0];
259
- nox_raw = raw_data[1]; // either 0 or the measured NOx ticks
260
- return true;
232
+
233
+ this->set_timeout(this->measure_time_, [this, response_words]() {
234
+ uint16_t raw_data[2];
235
+ raw_data[1] = 0;
236
+ if (!this->read_data(raw_data, response_words)) {
237
+ ESP_LOGD(TAG, "read error (%d)", this->last_error_);
238
+ this->status_set_warning("measurement read failed");
239
+ this->voc_index_ = this->nox_index_ = UINT16_MAX;
240
+ return;
241
+ }
242
+ this->voc_sraw_ = raw_data[0];
243
+ this->nox_sraw_ = raw_data[1]; // either 0 or the measured NOx ticks
244
+ this->status_clear_warning();
245
+ this->update_gas_indices_();
246
+ });
261
247
  }
262
248
 
263
- void SGP4xComponent::update_gas_indices() {
249
+ void SGP4xComponent::take_sample() {
264
250
  if (!this->self_test_complete_)
265
251
  return;
266
-
267
252
  this->seconds_since_last_store_ += 1;
268
- if (!this->measure_gas_indices_(this->voc_index_, this->nox_index_)) {
269
- // Set values to UINT16_MAX to indicate failure
270
- this->voc_index_ = this->nox_index_ = UINT16_MAX;
271
- ESP_LOGE(TAG, "measure gas indices failed");
272
- return;
273
- }
274
- if (this->samples_read_ < this->samples_to_stabilize_) {
275
- this->samples_read_++;
276
- ESP_LOGD(TAG, "Sensor has not collected enough samples yet. (%d/%d) VOC index is: %" PRIu32, this->samples_read_,
277
- this->samples_to_stabilize_, this->voc_index_);
278
- return;
279
- }
253
+ this->measure_raw_();
280
254
  }
281
255
 
282
256
  void SGP4xComponent::update() {
283
257
  if (this->samples_read_ < this->samples_to_stabilize_) {
284
258
  return;
285
259
  }
286
- if (this->voc_sensor_) {
287
- if (this->voc_index_ != UINT16_MAX) {
288
- this->status_clear_warning();
260
+ if (this->voc_sensor_ != nullptr) {
261
+ if (this->voc_index_ != UINT16_MAX)
289
262
  this->voc_sensor_->publish_state(this->voc_index_);
290
- } else {
291
- this->status_set_warning();
292
- }
293
263
  }
294
- if (this->nox_sensor_) {
295
- if (this->nox_index_ != UINT16_MAX) {
296
- this->status_clear_warning();
264
+ if (this->nox_sensor_ != nullptr) {
265
+ if (this->nox_index_ != UINT16_MAX)
297
266
  this->nox_sensor_->publish_state(this->nox_index_);
298
- } else {
299
- this->status_set_warning();
300
- }
301
267
  }
302
268
  }
303
269
 
@@ -329,7 +295,7 @@ void SGP4xComponent::dump_config() {
329
295
  }
330
296
  LOG_UPDATE_INTERVAL(this);
331
297
 
332
- if (this->humidity_sensor_ != nullptr && this->temperature_sensor_ != nullptr) {
298
+ if (this->humidity_sensor_ != nullptr || this->temperature_sensor_ != nullptr) {
333
299
  ESP_LOGCONFIG(TAG, " Compensation:");
334
300
  LOG_SENSOR(" ", "Temperature Source:", this->temperature_sensor_);
335
301
  LOG_SENSOR(" ", "Humidity Source:", this->humidity_sensor_);
@@ -73,7 +73,7 @@ class SGP4xComponent : public PollingComponent, public sensor::Sensor, public se
73
73
 
74
74
  void setup() override;
75
75
  void update() override;
76
- void update_gas_indices();
76
+ void take_sample();
77
77
  void dump_config() override;
78
78
  float get_setup_priority() const override { return setup_priority::DATA; }
79
79
  void set_store_baseline(bool store_baseline) { store_baseline_ = store_baseline; }
@@ -108,8 +108,10 @@ class SGP4xComponent : public PollingComponent, public sensor::Sensor, public se
108
108
  sensor::Sensor *temperature_sensor_{nullptr};
109
109
  int16_t sensirion_init_sensors_();
110
110
 
111
- bool measure_gas_indices_(int32_t &voc, int32_t &nox);
112
- bool measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw);
111
+ void update_gas_indices_();
112
+ void measure_raw_();
113
+ uint16_t voc_sraw_;
114
+ uint16_t nox_sraw_;
113
115
 
114
116
  SgpType sgp_type_{SGP40};
115
117
  uint64_t serial_number_;
@@ -1,15 +1,18 @@
1
1
  from esphome import automation
2
2
  from esphome.automation import maybe_simple_id
3
3
  import esphome.codegen as cg
4
+ from esphome.components import audio_dac
4
5
  import esphome.config_validation as cv
5
- from esphome.const import CONF_DATA, CONF_ID
6
+ from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME
6
7
  from esphome.core import CORE
7
8
  from esphome.coroutine import coroutine_with_priority
8
9
 
9
- CODEOWNERS = ["@jesserockz"]
10
+ CODEOWNERS = ["@jesserockz", "@kahrendt"]
10
11
 
11
12
  IS_PLATFORM_COMPONENT = True
12
13
 
14
+ CONF_AUDIO_DAC = "audio_dac"
15
+
13
16
  speaker_ns = cg.esphome_ns.namespace("speaker")
14
17
 
15
18
  Speaker = speaker_ns.class_("Speaker")
@@ -23,13 +26,25 @@ StopAction = speaker_ns.class_(
23
26
  FinishAction = speaker_ns.class_(
24
27
  "FinishAction", automation.Action, cg.Parented.template(Speaker)
25
28
  )
29
+ VolumeSetAction = speaker_ns.class_(
30
+ "VolumeSetAction", automation.Action, cg.Parented.template(Speaker)
31
+ )
32
+ MuteOnAction = speaker_ns.class_(
33
+ "MuteOnAction", automation.Action, cg.Parented.template(Speaker)
34
+ )
35
+ MuteOffAction = speaker_ns.class_(
36
+ "MuteOffAction", automation.Action, cg.Parented.template(Speaker)
37
+ )
38
+
26
39
 
27
40
  IsPlayingCondition = speaker_ns.class_("IsPlayingCondition", automation.Condition)
28
41
  IsStoppedCondition = speaker_ns.class_("IsStoppedCondition", automation.Condition)
29
42
 
30
43
 
31
44
  async def setup_speaker_core_(var, config):
32
- pass
45
+ if audio_dac_config := config.get(CONF_AUDIO_DAC):
46
+ aud_dac = await cg.get_variable(audio_dac_config)
47
+ cg.add(var.set_audio_dac(aud_dac))
33
48
 
34
49
 
35
50
  async def register_speaker(var, config):
@@ -38,8 +53,11 @@ async def register_speaker(var, config):
38
53
  await setup_speaker_core_(var, config)
39
54
 
40
55
 
41
- SPEAKER_SCHEMA = cv.Schema({})
42
-
56
+ SPEAKER_SCHEMA = cv.Schema(
57
+ {
58
+ cv.Optional(CONF_AUDIO_DAC): cv.use_id(audio_dac.AudioDac),
59
+ }
60
+ )
43
61
 
44
62
  SPEAKER_AUTOMATION_SCHEMA = maybe_simple_id({cv.GenerateID(): cv.use_id(Speaker)})
45
63
 
@@ -90,6 +108,34 @@ automation.register_condition(
90
108
  )(speaker_action)
91
109
 
92
110
 
111
+ @automation.register_action(
112
+ "speaker.volume_set",
113
+ VolumeSetAction,
114
+ cv.maybe_simple_value(
115
+ {
116
+ cv.GenerateID(): cv.use_id(Speaker),
117
+ cv.Required(CONF_VOLUME): cv.templatable(cv.percentage),
118
+ },
119
+ key=CONF_VOLUME,
120
+ ),
121
+ )
122
+ async def speaker_volume_set_action(config, action_id, template_arg, args):
123
+ var = cg.new_Pvariable(action_id, template_arg)
124
+ await cg.register_parented(var, config[CONF_ID])
125
+ volume = await cg.templatable(config[CONF_VOLUME], args, float)
126
+ cg.add(var.set_volume(volume))
127
+ return var
128
+
129
+
130
+ @automation.register_action(
131
+ "speaker.mute_off", MuteOffAction, SPEAKER_AUTOMATION_SCHEMA
132
+ )
133
+ @automation.register_action("speaker.mute_on", MuteOnAction, SPEAKER_AUTOMATION_SCHEMA)
134
+ async def speaker_mute_action_to_code(config, action_id, template_arg, args):
135
+ paren = await cg.get_variable(config[CONF_ID])
136
+ return cg.new_Pvariable(action_id, template_arg, paren)
137
+
138
+
93
139
  @coroutine_with_priority(100.0)
94
140
  async def to_code(config):
95
141
  cg.add_global(speaker_ns.using)
@@ -34,6 +34,31 @@ template<typename... Ts> class PlayAction : public Action<Ts...>, public Parente
34
34
  std::vector<uint8_t> data_static_{};
35
35
  };
36
36
 
37
+ template<typename... Ts> class VolumeSetAction : public Action<Ts...>, public Parented<Speaker> {
38
+ TEMPLATABLE_VALUE(float, volume)
39
+ void play(Ts... x) override { this->parent_->set_volume(this->volume_.value(x...)); }
40
+ };
41
+
42
+ template<typename... Ts> class MuteOnAction : public Action<Ts...> {
43
+ public:
44
+ explicit MuteOnAction(Speaker *speaker) : speaker_(speaker) {}
45
+
46
+ void play(Ts... x) override { this->speaker_->set_mute_state(true); }
47
+
48
+ protected:
49
+ Speaker *speaker_;
50
+ };
51
+
52
+ template<typename... Ts> class MuteOffAction : public Action<Ts...> {
53
+ public:
54
+ explicit MuteOffAction(Speaker *speaker) : speaker_(speaker) {}
55
+
56
+ void play(Ts... x) override { this->speaker_->set_mute_state(false); }
57
+
58
+ protected:
59
+ Speaker *speaker_;
60
+ };
61
+
37
62
  template<typename... Ts> class StopAction : public Action<Ts...>, public Parented<Speaker> {
38
63
  public:
39
64
  void play(Ts... x) override { this->parent_->stop(); }
@@ -4,6 +4,17 @@
4
4
  #include <cstdint>
5
5
  #include <vector>
6
6
 
7
+ #ifdef USE_ESP32
8
+ #include <freertos/FreeRTOS.h>
9
+ #endif
10
+
11
+ #include "esphome/core/defines.h"
12
+
13
+ #include "esphome/components/audio/audio.h"
14
+ #ifdef USE_AUDIO_DAC
15
+ #include "esphome/components/audio_dac/audio_dac.h"
16
+ #endif
17
+
7
18
  namespace esphome {
8
19
  namespace speaker {
9
20
 
@@ -16,14 +27,33 @@ enum State : uint8_t {
16
27
 
17
28
  class Speaker {
18
29
  public:
30
+ #ifdef USE_ESP32
31
+ /// @brief Plays the provided audio data.
32
+ /// If the speaker component doesn't implement this method, it falls back to the play method without this parameter.
33
+ /// @param data Audio data in the format specified by ``set_audio_stream_info`` method.
34
+ /// @param length The length of the audio data in bytes.
35
+ /// @param ticks_to_wait The FreeRTOS ticks to wait before writing as much data as possible to the ring buffer.
36
+ /// @return The number of bytes that were actually written to the speaker's internal buffer.
37
+ virtual size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
38
+ return this->play(data, length);
39
+ };
40
+ #endif
41
+
42
+ /// @brief Plays the provided audio data.
43
+ /// If the audio stream is not the default defined in "esphome/core/audio.h" and the speaker component implements it,
44
+ /// then this should be called after calling ``set_audio_stream_info``.
45
+ /// @param data Audio data in the format specified by ``set_audio_stream_info`` method.
46
+ /// @param length The length of the audio data in bytes.
47
+ /// @return The number of bytes that were actually written to the speaker's internal buffer.
19
48
  virtual size_t play(const uint8_t *data, size_t length) = 0;
49
+
20
50
  size_t play(const std::vector<uint8_t> &data) { return this->play(data.data(), data.size()); }
21
51
 
22
52
  virtual void start() = 0;
23
53
  virtual void stop() = 0;
24
54
  // In compare between *STOP()* and *FINISH()*; *FINISH()* will stop after emptying the play buffer,
25
55
  // while *STOP()* will break directly.
26
- // When finish() is not implemented on the plateform component it should just do a normal stop.
56
+ // When finish() is not implemented on the platform component it should just do a normal stop.
27
57
  virtual void finish() { this->stop(); }
28
58
 
29
59
  virtual bool has_buffered_data() const = 0;
@@ -31,8 +61,49 @@ class Speaker {
31
61
  bool is_running() const { return this->state_ == STATE_RUNNING; }
32
62
  bool is_stopped() const { return this->state_ == STATE_STOPPED; }
33
63
 
64
+ // Volume control is handled by a configured audio dac component. Individual speaker components can
65
+ // override and implement in software if an audio dac isn't available.
66
+ virtual void set_volume(float volume) {
67
+ this->volume_ = volume;
68
+ #ifdef USE_AUDIO_DAC
69
+ if (this->audio_dac_ != nullptr) {
70
+ this->audio_dac_->set_volume(volume);
71
+ }
72
+ #endif
73
+ };
74
+ float get_volume() { return this->volume_; }
75
+
76
+ virtual void set_mute_state(bool mute_state) {
77
+ this->mute_state_ = mute_state;
78
+ #ifdef USE_AUDIO_DAC
79
+ if (this->audio_dac_) {
80
+ if (mute_state) {
81
+ this->audio_dac_->set_mute_on();
82
+ } else {
83
+ this->audio_dac_->set_mute_off();
84
+ }
85
+ }
86
+ #endif
87
+ }
88
+ bool get_mute_state() { return this->mute_state_; }
89
+
90
+ #ifdef USE_AUDIO_DAC
91
+ void set_audio_dac(audio_dac::AudioDac *audio_dac) { this->audio_dac_ = audio_dac; }
92
+ #endif
93
+
94
+ void set_audio_stream_info(const audio::AudioStreamInfo &audio_stream_info) {
95
+ this->audio_stream_info_ = audio_stream_info;
96
+ }
97
+
34
98
  protected:
35
99
  State state_{STATE_STOPPED};
100
+ audio::AudioStreamInfo audio_stream_info_;
101
+ float volume_{1.0f};
102
+ bool mute_state_{false};
103
+
104
+ #ifdef USE_AUDIO_DAC
105
+ audio_dac::AudioDac *audio_dac_{nullptr};
106
+ #endif
36
107
  };
37
108
 
38
109
  } // namespace speaker
@@ -1,40 +1,37 @@
1
1
  import re
2
2
 
3
+ from esphome import pins
3
4
  import esphome.codegen as cg
4
- import esphome.config_validation as cv
5
- import esphome.final_validate as fv
6
5
  from esphome.components.esp32.const import (
7
6
  KEY_ESP32,
8
- VARIANT_ESP32S2,
9
- VARIANT_ESP32S3,
10
7
  VARIANT_ESP32C2,
11
8
  VARIANT_ESP32C3,
12
9
  VARIANT_ESP32C6,
13
10
  VARIANT_ESP32H2,
11
+ VARIANT_ESP32S2,
12
+ VARIANT_ESP32S3,
14
13
  )
15
- from esphome import pins
14
+ import esphome.config_validation as cv
16
15
  from esphome.const import (
17
16
  CONF_CLK_PIN,
17
+ CONF_CS_PIN,
18
+ CONF_DATA_PINS,
19
+ CONF_DATA_RATE,
18
20
  CONF_ID,
21
+ CONF_INVERTED,
19
22
  CONF_MISO_PIN,
20
23
  CONF_MOSI_PIN,
21
- CONF_SPI_ID,
22
- CONF_CS_PIN,
23
24
  CONF_NUMBER,
24
- CONF_INVERTED,
25
+ CONF_SPI_ID,
25
26
  KEY_CORE,
26
27
  KEY_TARGET_PLATFORM,
27
28
  KEY_VARIANT,
28
- CONF_DATA_RATE,
29
29
  PLATFORM_ESP32,
30
30
  PLATFORM_ESP8266,
31
31
  PLATFORM_RP2040,
32
- CONF_DATA_PINS,
33
- )
34
- from esphome.core import (
35
- coroutine_with_priority,
36
- CORE,
37
32
  )
33
+ from esphome.core import CORE, coroutine_with_priority
34
+ import esphome.final_validate as fv
38
35
 
39
36
  CODEOWNERS = ["@esphome/core", "@clydebarrow"]
40
37
  spi_ns = cg.esphome_ns.namespace("spi")
@@ -69,6 +66,10 @@ SPI_MODE_OPTIONS = {
69
66
  1: SPIMode.MODE1,
70
67
  2: SPIMode.MODE2,
71
68
  3: SPIMode.MODE3,
69
+ "0": SPIMode.MODE0,
70
+ "1": SPIMode.MODE1,
71
+ "2": SPIMode.MODE2,
72
+ "3": SPIMode.MODE3,
72
73
  }
73
74
 
74
75
  CONF_SPI_MODE = "spi_mode"
@@ -1,6 +1,6 @@
1
1
  import esphome.codegen as cg
2
- import esphome.config_validation as cv
3
2
  from esphome.components import spi
3
+ import esphome.config_validation as cv
4
4
  from esphome.const import CONF_ID, CONF_MODE
5
5
 
6
6
  DEPENDENCIES = ["spi"]
@@ -11,18 +11,6 @@ spi_device_ns = cg.esphome_ns.namespace("spi_device")
11
11
 
12
12
  spi_device = spi_device_ns.class_("SPIDeviceComponent", cg.Component, spi.SPIDevice)
13
13
 
14
- Mode = spi.spi_ns.enum("SPIMode")
15
- MODES = {
16
- "0": Mode.MODE0,
17
- "1": Mode.MODE1,
18
- "2": Mode.MODE2,
19
- "3": Mode.MODE3,
20
- "MODE0": Mode.MODE0,
21
- "MODE1": Mode.MODE1,
22
- "MODE2": Mode.MODE2,
23
- "MODE3": Mode.MODE3,
24
- }
25
-
26
14
  BitOrder = spi.spi_ns.enum("SPIBitOrder")
27
15
  ORDERS = {
28
16
  "msb_first": BitOrder.BIT_ORDER_MSB_FIRST,
@@ -34,7 +22,9 @@ CONFIG_SCHEMA = cv.Schema(
34
22
  {
35
23
  cv.GenerateID(CONF_ID): cv.declare_id(spi_device),
36
24
  cv.Optional(CONF_BIT_ORDER, default="msb_first"): cv.enum(ORDERS, lower=True),
37
- cv.Optional(CONF_MODE, default="0"): cv.enum(MODES, upper=True),
25
+ cv.Optional(CONF_MODE): cv.invalid(
26
+ "The 'mode' option has been renamed to 'spi_mode'."
27
+ ),
38
28
  }
39
29
  ).extend(spi.spi_device_schema(False, "1MHz"))
40
30
 
@@ -42,6 +32,5 @@ CONFIG_SCHEMA = cv.Schema(
42
32
  async def to_code(config):
43
33
  var = cg.new_Pvariable(config[CONF_ID])
44
34
  await cg.register_component(var, config)
45
- cg.add(var.set_mode(config[CONF_MODE]))
46
35
  cg.add(var.set_bit_order(config[CONF_BIT_ORDER]))
47
36
  await spi.register_spi_device(var, config)
@@ -1,8 +1,8 @@
1
- import esphome.codegen as cg
2
- import esphome.config_validation as cv
3
1
  from esphome import pins
2
+ import esphome.codegen as cg
4
3
  from esphome.components import spi, ssd1306_base
5
4
  from esphome.components.ssd1306_base import _validate
5
+ import esphome.config_validation as cv
6
6
  from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES
7
7
 
8
8
  AUTO_LOAD = ["ssd1306_base"]
@@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All(
24
24
  _validate,
25
25
  )
26
26
 
27
+ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema(
28
+ "ssd1306_spi", require_miso=False, require_mosi=True
29
+ )
30
+
27
31
 
28
32
  async def to_code(config):
29
33
  var = cg.new_Pvariable(config[CONF_ID])
@@ -1,7 +1,7 @@
1
- import esphome.codegen as cg
2
- import esphome.config_validation as cv
3
1
  from esphome import pins
2
+ import esphome.codegen as cg
4
3
  from esphome.components import spi, ssd1322_base
4
+ import esphome.config_validation as cv
5
5
  from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES
6
6
 
7
7
  CODEOWNERS = ["@kbx81"]
@@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All(
24
24
  cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
25
25
  )
26
26
 
27
+ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema(
28
+ "ssd1322_spi", require_miso=False, require_mosi=True
29
+ )
30
+
27
31
 
28
32
  async def to_code(config):
29
33
  var = cg.new_Pvariable(config[CONF_ID])
@@ -1,7 +1,7 @@
1
- import esphome.codegen as cg
2
- import esphome.config_validation as cv
3
1
  from esphome import pins
2
+ import esphome.codegen as cg
4
3
  from esphome.components import spi, ssd1325_base
4
+ import esphome.config_validation as cv
5
5
  from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES
6
6
 
7
7
  CODEOWNERS = ["@kbx81"]
@@ -24,6 +24,10 @@ CONFIG_SCHEMA = cv.All(
24
24
  cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
25
25
  )
26
26
 
27
+ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema(
28
+ "ssd1325_spi", require_miso=False, require_mosi=True
29
+ )
30
+
27
31
 
28
32
  async def to_code(config):
29
33
  var = cg.new_Pvariable(config[CONF_ID])