esphome 2024.7.3__py3-none-any.whl → 2024.8.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 (350) hide show
  1. esphome/__main__.py +15 -81
  2. esphome/automation.py +1 -1
  3. esphome/codegen.py +53 -53
  4. esphome/components/ade7953/sensor.py +1 -1
  5. esphome/components/ade7953_spi/ade7953_spi.cpp +1 -1
  6. esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +5 -2
  7. esphome/components/airthings_wave_plus/airthings_wave_plus.h +2 -0
  8. esphome/components/airthings_wave_plus/sensor.py +12 -0
  9. esphome/components/alarm_control_panel/__init__.py +75 -66
  10. esphome/components/apds9306/__init__.py +4 -0
  11. esphome/components/apds9306/apds9306.cpp +151 -0
  12. esphome/components/apds9306/apds9306.h +66 -0
  13. esphome/components/apds9306/sensor.py +95 -0
  14. esphome/components/api/__init__.py +80 -52
  15. esphome/components/api/api_connection.cpp +14 -1
  16. esphome/components/api/api_pb2.cpp +33 -4
  17. esphome/components/api/api_pb2.h +8 -1
  18. esphome/components/api/api_server.cpp +10 -0
  19. esphome/components/api/api_server.h +3 -0
  20. esphome/components/atm90e32/__init__.py +7 -0
  21. esphome/components/atm90e32/atm90e32.cpp +68 -16
  22. esphome/components/atm90e32/atm90e32.h +20 -7
  23. esphome/components/atm90e32/atm90e32_reg.h +2 -0
  24. esphome/components/atm90e32/button/__init__.py +43 -0
  25. esphome/components/atm90e32/button/atm90e32_button.cpp +20 -0
  26. esphome/components/atm90e32/button/atm90e32_button.h +27 -0
  27. esphome/components/atm90e32/sensor.py +15 -11
  28. esphome/components/bedjet/bedjet_codec.h +1 -1
  29. esphome/components/binary/light/binary_light_output.h +3 -2
  30. esphome/components/binary_sensor/__init__.py +5 -5
  31. esphome/components/ble_client/__init__.py +3 -3
  32. esphome/components/ble_client/output/__init__.py +1 -1
  33. esphome/components/ble_client/sensor/__init__.py +4 -3
  34. esphome/components/ble_client/switch/__init__.py +2 -1
  35. esphome/components/ble_client/text_sensor/__init__.py +4 -3
  36. esphome/components/ble_presence/binary_sensor.py +3 -3
  37. esphome/components/ble_rssi/sensor.py +2 -2
  38. esphome/components/ble_scanner/text_sensor.py +1 -1
  39. esphome/components/bluetooth_proxy/__init__.py +3 -3
  40. esphome/components/bme68x_bsec2/__init__.py +196 -0
  41. esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +523 -0
  42. esphome/components/bme68x_bsec2/bme68x_bsec2.h +163 -0
  43. esphome/components/bme68x_bsec2/sensor.py +130 -0
  44. esphome/components/bme68x_bsec2/text_sensor.py +33 -0
  45. esphome/components/bme68x_bsec2_i2c/__init__.py +28 -0
  46. esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp +53 -0
  47. esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h +28 -0
  48. esphome/components/bmp3xx/sensor.py +1 -1
  49. esphome/components/button/__init__.py +4 -4
  50. esphome/components/climate/__init__.py +5 -5
  51. esphome/components/climate/climate.h +1 -1
  52. esphome/components/cover/__init__.py +8 -8
  53. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +11 -7
  54. esphome/components/cst226/touchscreen/cst226_touchscreen.h +1 -1
  55. esphome/components/datetime/__init__.py +11 -13
  56. esphome/components/demo/demo_sensor.h +3 -2
  57. esphome/components/display/display.cpp +31 -0
  58. esphome/components/display/display.h +3 -0
  59. esphome/components/display_menu_base/__init__.py +14 -13
  60. esphome/components/ens160/sensor.py +1 -1
  61. esphome/components/esp32/__init__.py +22 -10
  62. esphome/components/esp32/boards.py +1 -1
  63. esphome/components/esp32/gpio.py +12 -13
  64. esphome/components/esp32/gpio_esp32.py +1 -2
  65. esphome/components/esp32/gpio_esp32_c2.py +1 -2
  66. esphome/components/esp32/gpio_esp32_c3.py +1 -5
  67. esphome/components/esp32/gpio_esp32_c6.py +1 -2
  68. esphome/components/esp32/gpio_esp32_h2.py +1 -2
  69. esphome/components/esp32/gpio_esp32_s2.py +1 -2
  70. esphome/components/esp32/gpio_esp32_s3.py +1 -6
  71. esphome/components/esp32_ble/__init__.py +20 -3
  72. esphome/components/esp32_ble/ble.cpp +9 -1
  73. esphome/components/esp32_ble/ble.h +9 -0
  74. esphome/components/esp32_ble/ble_advertising.cpp +42 -9
  75. esphome/components/esp32_ble/ble_advertising.h +21 -1
  76. esphome/components/esp32_ble_beacon/__init__.py +17 -7
  77. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +45 -113
  78. esphome/components/esp32_ble_beacon/esp32_ble_beacon.h +17 -19
  79. esphome/components/esp32_ble_client/__init__.py +0 -1
  80. esphome/components/esp32_ble_server/__init__.py +2 -3
  81. esphome/components/esp32_ble_tracker/__init__.py +2 -2
  82. esphome/components/esp32_improv/__init__.py +2 -4
  83. esphome/components/ethernet/__init__.py +17 -17
  84. esphome/components/ethernet_info/text_sensor.py +2 -2
  85. esphome/components/event/__init__.py +5 -5
  86. esphome/components/fan/__init__.py +14 -14
  87. esphome/components/fan/fan.cpp +2 -2
  88. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  89. esphome/components/fingerprint_grow/fingerprint_grow.h +1 -1
  90. esphome/components/graphical_display_menu/__init__.py +11 -8
  91. esphome/components/haier/haier_base.h +2 -2
  92. esphome/components/homeassistant/__init__.py +8 -1
  93. esphome/components/homeassistant/number/__init__.py +33 -0
  94. esphome/components/homeassistant/number/homeassistant_number.cpp +100 -0
  95. esphome/components/homeassistant/number/homeassistant_number.h +31 -0
  96. esphome/components/homeassistant/switch/__init__.py +30 -0
  97. esphome/components/homeassistant/switch/homeassistant_switch.cpp +59 -0
  98. esphome/components/homeassistant/switch/homeassistant_switch.h +22 -0
  99. esphome/components/host/__init__.py +3 -7
  100. esphome/components/http_request/__init__.py +12 -1
  101. esphome/components/http_request/http_request_arduino.cpp +2 -2
  102. esphome/components/http_request/http_request_idf.cpp +11 -2
  103. esphome/components/http_request/http_request_idf.h +10 -0
  104. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  105. esphome/components/http_request/update/http_request_update.cpp +2 -2
  106. esphome/components/http_request/update/http_request_update.h +2 -1
  107. esphome/components/hx711/hx711.cpp +10 -1
  108. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +1 -1
  109. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +11 -2
  110. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
  111. esphome/components/ili9xxx/ili9xxx_defines.h +3 -1
  112. esphome/components/ili9xxx/ili9xxx_display.cpp +9 -22
  113. esphome/components/ili9xxx/ili9xxx_display.h +5 -7
  114. esphome/components/ili9xxx/ili9xxx_init.h +4 -4
  115. esphome/components/improv_base/__init__.py +2 -3
  116. esphome/components/improv_serial/__init__.py +4 -10
  117. esphome/components/improv_serial/improv_serial_component.cpp +4 -0
  118. esphome/components/jsn_sr04t/jsn_sr04t.cpp +18 -1
  119. esphome/components/jsn_sr04t/jsn_sr04t.h +7 -1
  120. esphome/components/jsn_sr04t/sensor.py +13 -0
  121. esphome/components/kalman_combinator/sensor.py +1 -1
  122. esphome/components/light/__init__.py +16 -15
  123. esphome/components/light/addressable_light_effect.h +12 -8
  124. esphome/components/light/automation.h +16 -1
  125. esphome/components/light/automation.py +21 -0
  126. esphome/components/light/base_light_effects.h +5 -5
  127. esphome/components/light/esp_color_correction.h +8 -8
  128. esphome/components/light/types.py +7 -0
  129. esphome/components/lock/__init__.py +3 -3
  130. esphome/components/logger/__init__.py +15 -18
  131. esphome/components/lvgl/__init__.py +346 -0
  132. esphome/components/lvgl/automation.py +226 -0
  133. esphome/components/lvgl/binary_sensor/__init__.py +43 -0
  134. esphome/components/lvgl/defines.py +508 -0
  135. esphome/components/lvgl/encoders.py +77 -0
  136. esphome/components/lvgl/font.cpp +76 -0
  137. esphome/components/lvgl/helpers.py +49 -0
  138. esphome/components/lvgl/light/__init__.py +32 -0
  139. esphome/components/lvgl/light/lvgl_light.h +48 -0
  140. esphome/components/lvgl/lv_validation.py +303 -0
  141. esphome/components/lvgl/lvcode.py +349 -0
  142. esphome/components/lvgl/lvgl_esphome.cpp +407 -0
  143. esphome/components/lvgl/lvgl_esphome.h +274 -0
  144. esphome/components/lvgl/lvgl_hal.h +21 -0
  145. esphome/components/lvgl/number/__init__.py +66 -0
  146. esphome/components/lvgl/number/lvgl_number.h +34 -0
  147. esphome/components/lvgl/schemas.py +436 -0
  148. esphome/components/lvgl/select/__init__.py +55 -0
  149. esphome/components/lvgl/select/lvgl_select.h +62 -0
  150. esphome/components/lvgl/sensor/__init__.py +47 -0
  151. esphome/components/lvgl/styles.py +58 -0
  152. esphome/components/lvgl/switch/__init__.py +56 -0
  153. esphome/components/lvgl/switch/lvgl_switch.h +34 -0
  154. esphome/components/lvgl/text/__init__.py +50 -0
  155. esphome/components/lvgl/text/lvgl_text.h +34 -0
  156. esphome/components/lvgl/text_sensor/__init__.py +42 -0
  157. esphome/components/lvgl/touchscreens.py +45 -0
  158. esphome/components/lvgl/trigger.py +74 -0
  159. esphome/components/lvgl/types.py +191 -0
  160. esphome/components/lvgl/widgets/__init__.py +419 -0
  161. esphome/components/lvgl/widgets/animimg.py +117 -0
  162. esphome/components/lvgl/widgets/arc.py +78 -0
  163. esphome/components/lvgl/widgets/button.py +20 -0
  164. esphome/components/lvgl/widgets/buttonmatrix.py +275 -0
  165. esphome/components/lvgl/widgets/checkbox.py +27 -0
  166. esphome/components/lvgl/widgets/dropdown.py +76 -0
  167. esphome/components/lvgl/widgets/img.py +85 -0
  168. esphome/components/lvgl/widgets/keyboard.py +49 -0
  169. esphome/components/lvgl/widgets/label.py +42 -0
  170. esphome/components/lvgl/widgets/led.py +29 -0
  171. esphome/components/lvgl/widgets/line.py +50 -0
  172. esphome/components/lvgl/widgets/lv_bar.py +55 -0
  173. esphome/components/lvgl/widgets/meter.py +302 -0
  174. esphome/components/lvgl/widgets/msgbox.py +134 -0
  175. esphome/components/lvgl/widgets/obj.py +28 -0
  176. esphome/components/lvgl/widgets/page.py +113 -0
  177. esphome/components/lvgl/widgets/roller.py +77 -0
  178. esphome/components/lvgl/widgets/slider.py +63 -0
  179. esphome/components/lvgl/widgets/spinbox.py +178 -0
  180. esphome/components/lvgl/widgets/spinner.py +43 -0
  181. esphome/components/lvgl/widgets/switch.py +20 -0
  182. esphome/components/lvgl/widgets/tabview.py +114 -0
  183. esphome/components/lvgl/widgets/textarea.py +66 -0
  184. esphome/components/lvgl/widgets/tileview.py +128 -0
  185. esphome/components/m5stack_8angle/__init__.py +33 -0
  186. esphome/components/m5stack_8angle/binary_sensor/__init__.py +30 -0
  187. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +17 -0
  188. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h +19 -0
  189. esphome/components/m5stack_8angle/light/__init__.py +31 -0
  190. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +45 -0
  191. esphome/components/m5stack_8angle/light/m5stack_8angle_light.h +37 -0
  192. esphome/components/m5stack_8angle/m5stack_8angle.cpp +74 -0
  193. esphome/components/m5stack_8angle/m5stack_8angle.h +34 -0
  194. esphome/components/m5stack_8angle/sensor/__init__.py +66 -0
  195. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +24 -0
  196. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h +27 -0
  197. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -0
  198. esphome/components/max31856/sensor.py +5 -5
  199. esphome/components/media_player/__init__.py +3 -5
  200. esphome/components/media_player/automation.h +31 -27
  201. esphome/components/micro_wake_word/__init__.py +20 -25
  202. esphome/components/microphone/microphone.h +4 -1
  203. esphome/components/modbus_controller/__init__.py +26 -2
  204. esphome/components/modbus_controller/automation.h +19 -0
  205. esphome/components/modbus_controller/const.py +1 -0
  206. esphome/components/modbus_controller/modbus_controller.cpp +8 -0
  207. esphome/components/modbus_controller/modbus_controller.h +3 -0
  208. esphome/components/mqtt/__init__.py +20 -9
  209. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +128 -0
  210. esphome/components/mqtt/mqtt_alarm_control_panel.h +39 -0
  211. esphome/components/mqtt/mqtt_backend.h +3 -1
  212. esphome/components/mqtt/mqtt_backend_esp32.cpp +4 -1
  213. esphome/components/mqtt/mqtt_backend_esp32.h +3 -1
  214. esphome/components/mqtt/mqtt_backend_esp8266.h +3 -1
  215. esphome/components/mqtt/mqtt_backend_libretiny.h +3 -1
  216. esphome/components/mqtt/mqtt_client.cpp +16 -3
  217. esphome/components/mqtt/mqtt_client.h +5 -1
  218. esphome/components/mqtt/mqtt_component.cpp +32 -4
  219. esphome/components/mqtt/mqtt_const.h +2 -0
  220. esphome/components/network/__init__.py +15 -12
  221. esphome/components/network/ip_address.h +3 -0
  222. esphome/components/network/util.cpp +2 -1
  223. esphome/components/network/util.h +3 -1
  224. esphome/components/nextion/base_component.py +5 -8
  225. esphome/components/number/__init__.py +7 -8
  226. esphome/components/online_image/__init__.py +167 -0
  227. esphome/components/online_image/image_decoder.cpp +44 -0
  228. esphome/components/online_image/image_decoder.h +112 -0
  229. esphome/components/online_image/online_image.cpp +283 -0
  230. esphome/components/online_image/online_image.h +195 -0
  231. esphome/components/online_image/png_image.cpp +68 -0
  232. esphome/components/online_image/png_image.h +33 -0
  233. esphome/components/ota/__init__.py +8 -4
  234. esphome/components/pid/pid_climate.h +2 -0
  235. esphome/components/remote_base/pronto_protocol.cpp +0 -3
  236. esphome/components/remote_transmitter/remote_transmitter.h +1 -1
  237. esphome/components/rgbct/rgbct_light_output.h +3 -2
  238. esphome/components/rgbw/rgbw_light_output.h +3 -2
  239. esphome/components/rgbww/rgbww_light_output.h +3 -2
  240. esphome/components/rp2040_pio_led_strip/led_strip.cpp +31 -5
  241. esphome/components/rp2040_pio_led_strip/led_strip.h +5 -0
  242. esphome/components/rtttl/rtttl.cpp +108 -21
  243. esphome/components/rtttl/rtttl.h +15 -6
  244. esphome/components/select/__init__.py +7 -7
  245. esphome/components/sensor/__init__.py +29 -10
  246. esphome/components/sensor/filter.cpp +8 -0
  247. esphome/components/sensor/filter.h +9 -0
  248. esphome/components/sml/sml_parser.cpp +48 -22
  249. esphome/components/socket/socket.cpp +11 -14
  250. esphome/components/speaker/__init__.py +14 -5
  251. esphome/components/speaker/automation.h +10 -0
  252. esphome/components/speaker/speaker.h +9 -0
  253. esphome/components/spi/spi.cpp +0 -6
  254. esphome/components/spi/spi.h +2 -19
  255. esphome/components/spi_led_strip/spi_led_strip.h +5 -4
  256. esphome/components/sprinkler/sprinkler.cpp +2 -2
  257. esphome/components/sprinkler/sprinkler.h +1 -1
  258. esphome/components/switch/__init__.py +3 -3
  259. esphome/components/text/__init__.py +5 -5
  260. esphome/components/text_sensor/__init__.py +7 -7
  261. esphome/components/time/__init__.py +8 -8
  262. esphome/components/touchscreen/binary_sensor/__init__.py +24 -10
  263. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +3 -2
  264. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +4 -2
  265. esphome/components/uart/uart_component_host.cpp +6 -2
  266. esphome/components/update/__init__.py +33 -15
  267. esphome/components/update/automation.h +23 -0
  268. esphome/components/update/update_entity.h +3 -1
  269. esphome/components/valve/__init__.py +3 -3
  270. esphome/components/voice_assistant/__init__.py +7 -8
  271. esphome/components/wake_on_lan/wake_on_lan.cpp +2 -0
  272. esphome/components/wake_on_lan/wake_on_lan.h +3 -1
  273. esphome/components/watchdog/__init__.py +1 -0
  274. esphome/components/{http_request → watchdog}/watchdog.cpp +0 -2
  275. esphome/components/{http_request → watchdog}/watchdog.h +0 -2
  276. esphome/components/waveshare_epaper/waveshare_epaper.cpp +5 -5
  277. esphome/components/web_server/server_index_v3.h +3615 -3603
  278. esphome/components/web_server/web_server.cpp +0 -209
  279. esphome/components/web_server/web_server.h +1 -1
  280. esphome/components/web_server/web_server_v1.cpp +217 -0
  281. esphome/components/web_server_base/web_server_base.h +1 -0
  282. esphome/components/wifi/__init__.py +15 -14
  283. esphome/components/wifi/wifi_component.cpp +2 -0
  284. esphome/components/wifi/wifi_component.h +7 -1
  285. esphome/components/wifi/wifi_component_esp32_arduino.cpp +5 -2
  286. esphome/components/wifi/wifi_component_esp8266.cpp +2 -0
  287. esphome/components/wifi/wifi_component_esp_idf.cpp +43 -7
  288. esphome/components/wifi/wifi_component_libretiny.cpp +2 -0
  289. esphome/components/wifi/wifi_component_pico_w.cpp +2 -0
  290. esphome/components/wifi/wpa2_eap.py +6 -7
  291. esphome/components/wifi_info/text_sensor.py +3 -3
  292. esphome/components/wifi_info/wifi_info_text_sensor.cpp +2 -0
  293. esphome/components/wifi_info/wifi_info_text_sensor.h +2 -0
  294. esphome/components/wifi_signal/sensor.py +1 -1
  295. esphome/components/wifi_signal/wifi_signal_sensor.cpp +2 -0
  296. esphome/components/wifi_signal/wifi_signal_sensor.h +2 -1
  297. esphome/components/xiaomi_ble/xiaomi_ble.cpp +20 -3
  298. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  299. esphome/components/xiaomi_lywsd02mmc/__init__.py +0 -0
  300. esphome/components/xiaomi_lywsd02mmc/sensor.py +77 -0
  301. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp +73 -0
  302. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +37 -0
  303. esphome/config.py +17 -19
  304. esphome/config_validation.py +55 -23
  305. esphome/const.py +25 -9
  306. esphome/core/__init__.py +17 -14
  307. esphome/core/application.h +42 -21
  308. esphome/core/automation.h +5 -3
  309. esphome/core/base_automation.h +3 -2
  310. esphome/core/bytebuffer.cpp +134 -0
  311. esphome/core/bytebuffer.h +96 -0
  312. esphome/core/color.h +24 -16
  313. esphome/core/config.py +3 -3
  314. esphome/core/defines.h +14 -1
  315. esphome/core/entity_base.h +2 -2
  316. esphome/core/entity_helpers.py +1 -2
  317. esphome/core/gpio.h +0 -18
  318. esphome/core/helpers.h +1 -1
  319. esphome/core/optional.h +15 -16
  320. esphome/coroutine.py +1 -1
  321. esphome/cpp_generator.py +1 -1
  322. esphome/cpp_helpers.py +3 -5
  323. esphome/dashboard/core.py +3 -3
  324. esphome/dashboard/dashboard.py +3 -3
  325. esphome/dashboard/entries.py +1 -1
  326. esphome/dashboard/util/file.py +1 -1
  327. esphome/dashboard/web_server.py +3 -3
  328. esphome/external_files.py +5 -3
  329. esphome/final_validate.py +2 -2
  330. esphome/git.py +4 -4
  331. esphome/helpers.py +5 -5
  332. esphome/loader.py +15 -10
  333. esphome/mqtt.py +4 -8
  334. esphome/pins.py +6 -6
  335. esphome/platformio_api.py +5 -5
  336. esphome/storage_json.py +2 -1
  337. esphome/types.py +1 -1
  338. esphome/util.py +2 -3
  339. esphome/voluptuous_schema.py +1 -0
  340. esphome/vscode.py +5 -4
  341. esphome/wizard.py +1 -1
  342. esphome/writer.py +7 -7
  343. esphome/yaml_util.py +3 -3
  344. esphome/zeroconf.py +1 -1
  345. {esphome-2024.7.3.dist-info → esphome-2024.8.0.dist-info}/METADATA +3 -3
  346. {esphome-2024.7.3.dist-info → esphome-2024.8.0.dist-info}/RECORD +350 -244
  347. {esphome-2024.7.3.dist-info → esphome-2024.8.0.dist-info}/LICENSE +0 -0
  348. {esphome-2024.7.3.dist-info → esphome-2024.8.0.dist-info}/WHEEL +0 -0
  349. {esphome-2024.7.3.dist-info → esphome-2024.8.0.dist-info}/entry_points.txt +0 -0
  350. {esphome-2024.7.3.dist-info → esphome-2024.8.0.dist-info}/top_level.txt +0 -0
@@ -29,6 +29,13 @@ inline double deg2rad(double degrees) {
29
29
  void Rtttl::dump_config() { ESP_LOGCONFIG(TAG, "Rtttl"); }
30
30
 
31
31
  void Rtttl::play(std::string rtttl) {
32
+ if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) {
33
+ int pos = this->rtttl_.find(':');
34
+ auto name = this->rtttl_.substr(0, pos);
35
+ ESP_LOGW(TAG, "RTTTL Component is already playing: %s", name.c_str());
36
+ return;
37
+ }
38
+
32
39
  this->rtttl_ = std::move(rtttl);
33
40
 
34
41
  this->default_duration_ = 4;
@@ -98,16 +105,24 @@ void Rtttl::play(std::string rtttl) {
98
105
  this->note_duration_ = 1;
99
106
 
100
107
  #ifdef USE_SPEAKER
101
- this->samples_sent_ = 0;
102
- this->samples_count_ = 0;
108
+ if (this->speaker_ != nullptr) {
109
+ this->set_state_(State::STATE_INIT);
110
+ this->samples_sent_ = 0;
111
+ this->samples_count_ = 0;
112
+ }
113
+ #endif
114
+ #ifdef USE_OUTPUT
115
+ if (this->output_ != nullptr) {
116
+ this->set_state_(State::STATE_RUNNING);
117
+ }
103
118
  #endif
104
119
  }
105
120
 
106
121
  void Rtttl::stop() {
107
- this->note_duration_ = 0;
108
122
  #ifdef USE_OUTPUT
109
123
  if (this->output_ != nullptr) {
110
124
  this->output_->set_level(0.0);
125
+ this->set_state_(STATE_STOPPED);
111
126
  }
112
127
  #endif
113
128
  #ifdef USE_SPEAKER
@@ -115,18 +130,37 @@ void Rtttl::stop() {
115
130
  if (this->speaker_->is_running()) {
116
131
  this->speaker_->stop();
117
132
  }
133
+ this->set_state_(STATE_STOPPING);
118
134
  }
119
135
  #endif
136
+ this->note_duration_ = 0;
120
137
  }
121
138
 
122
139
  void Rtttl::loop() {
123
- if (this->note_duration_ == 0)
140
+ if (this->note_duration_ == 0 || this->state_ == State::STATE_STOPPED)
124
141
  return;
125
142
 
126
143
  #ifdef USE_SPEAKER
127
144
  if (this->speaker_ != nullptr) {
145
+ if (this->state_ == State::STATE_STOPPING) {
146
+ if (this->speaker_->is_stopped()) {
147
+ this->set_state_(State::STATE_STOPPED);
148
+ }
149
+ } else if (this->state_ == State::STATE_INIT) {
150
+ if (this->speaker_->is_stopped()) {
151
+ this->speaker_->start();
152
+ this->set_state_(State::STATE_STARTING);
153
+ }
154
+ } else if (this->state_ == State::STATE_STARTING) {
155
+ if (this->speaker_->is_running()) {
156
+ this->set_state_(State::STATE_RUNNING);
157
+ }
158
+ }
159
+ if (!this->speaker_->is_running()) {
160
+ return;
161
+ }
128
162
  if (this->samples_sent_ != this->samples_count_) {
129
- SpeakerSample sample[SAMPLE_BUFFER_SIZE + 1];
163
+ SpeakerSample sample[SAMPLE_BUFFER_SIZE + 2];
130
164
  int x = 0;
131
165
  double rem = 0.0;
132
166
 
@@ -136,7 +170,7 @@ void Rtttl::loop() {
136
170
  if (this->samples_per_wave_ != 0 && this->samples_sent_ >= this->samples_gap_) { // Play note//
137
171
  rem = ((this->samples_sent_ << 10) % this->samples_per_wave_) * (360.0 / this->samples_per_wave_);
138
172
 
139
- int16_t val = (49152 * this->gain_) * sin(deg2rad(rem));
173
+ int16_t val = (127 * this->gain_) * sin(deg2rad(rem)); // 16bit = 49152
140
174
 
141
175
  sample[x].left = val;
142
176
  sample[x].right = val;
@@ -153,9 +187,9 @@ void Rtttl::loop() {
153
187
  x++;
154
188
  }
155
189
  if (x > 0) {
156
- int send = this->speaker_->play((uint8_t *) (&sample), x * 4);
190
+ int send = this->speaker_->play((uint8_t *) (&sample), x * 2);
157
191
  if (send != x * 4) {
158
- this->samples_sent_ -= (x - (send / 4));
192
+ this->samples_sent_ -= (x - (send / 2));
159
193
  }
160
194
  return;
161
195
  }
@@ -167,14 +201,7 @@ void Rtttl::loop() {
167
201
  return;
168
202
  #endif
169
203
  if (!this->rtttl_[position_]) {
170
- this->note_duration_ = 0;
171
- #ifdef USE_OUTPUT
172
- if (this->output_ != nullptr) {
173
- this->output_->set_level(0.0);
174
- }
175
- #endif
176
- ESP_LOGD(TAG, "Playback finished");
177
- this->on_finished_playback_callback_.call();
204
+ this->finish_();
178
205
  return;
179
206
  }
180
207
 
@@ -213,6 +240,7 @@ void Rtttl::loop() {
213
240
  case 'a':
214
241
  note = 10;
215
242
  break;
243
+ case 'h':
216
244
  case 'b':
217
245
  note = 12;
218
246
  break;
@@ -238,14 +266,21 @@ void Rtttl::loop() {
238
266
  uint8_t scale = get_integer_();
239
267
  if (scale == 0)
240
268
  scale = this->default_octave_;
269
+
270
+ if (scale < 4 || scale > 7) {
271
+ ESP_LOGE(TAG, "Octave out of valid range. Should be between 4 and 7. (Octave: %d)", scale);
272
+ this->finish_();
273
+ return;
274
+ }
241
275
  bool need_note_gap = false;
242
276
 
243
277
  // Now play the note
244
278
  if (note) {
245
279
  auto note_index = (scale - 4) * 12 + note;
246
280
  if (note_index < 0 || note_index >= (int) sizeof(NOTES)) {
247
- ESP_LOGE(TAG, "Note out of valid range");
248
- this->note_duration_ = 0;
281
+ ESP_LOGE(TAG, "Note out of valid range (note: %d, scale: %d, index: %d, max: %d)", note, scale, note_index,
282
+ (int) sizeof(NOTES));
283
+ this->finish_();
249
284
  return;
250
285
  }
251
286
  auto freq = NOTES[note_index];
@@ -285,14 +320,17 @@ void Rtttl::loop() {
285
320
  this->samples_gap_ = (this->sample_rate_ * DOUBLE_NOTE_GAP_MS) / 1600; //(ms);
286
321
  }
287
322
  if (this->output_freq_ != 0) {
323
+ // make sure there is enough samples to add a full last sinus.
324
+
325
+ uint16_t samples_wish = this->samples_count_;
288
326
  this->samples_per_wave_ = (this->sample_rate_ << 10) / this->output_freq_;
289
327
 
290
- // make sure there is enough samples to add a full last sinus.
291
328
  uint16_t division = ((this->samples_count_ << 10) / this->samples_per_wave_) + 1;
292
- uint16_t x = this->samples_count_;
329
+
293
330
  this->samples_count_ = (division * this->samples_per_wave_);
294
- ESP_LOGD(TAG, "play time old: %d div: %d new: %d %d", x, division, this->samples_count_, this->samples_per_wave_);
295
331
  this->samples_count_ = this->samples_count_ >> 10;
332
+ ESP_LOGVV(TAG, "- Calc play time: wish: %d gets: %d (div: %d spw: %d)", samples_wish, this->samples_count_,
333
+ division, this->samples_per_wave_);
296
334
  }
297
335
  // Convert from frequency in Hz to high and low samples in fixed point
298
336
  }
@@ -301,5 +339,54 @@ void Rtttl::loop() {
301
339
  this->last_note_ = millis();
302
340
  }
303
341
 
342
+ void Rtttl::finish_() {
343
+ #ifdef USE_OUTPUT
344
+ if (this->output_ != nullptr) {
345
+ this->output_->set_level(0.0);
346
+ this->set_state_(State::STATE_STOPPED);
347
+ }
348
+ #endif
349
+ #ifdef USE_SPEAKER
350
+ if (this->speaker_ != nullptr) {
351
+ SpeakerSample sample[2];
352
+ sample[0].left = 0;
353
+ sample[0].right = 0;
354
+ sample[1].left = 0;
355
+ sample[1].right = 0;
356
+ this->speaker_->play((uint8_t *) (&sample), 8);
357
+
358
+ this->speaker_->finish();
359
+ this->set_state_(State::STATE_STOPPING);
360
+ }
361
+ #endif
362
+ this->note_duration_ = 0;
363
+ this->on_finished_playback_callback_.call();
364
+ ESP_LOGD(TAG, "Playback finished");
365
+ }
366
+
367
+ static const LogString *state_to_string(State state) {
368
+ switch (state) {
369
+ case STATE_STOPPED:
370
+ return LOG_STR("STATE_STOPPED");
371
+ case STATE_STARTING:
372
+ return LOG_STR("STATE_STARTING");
373
+ case STATE_RUNNING:
374
+ return LOG_STR("STATE_RUNNING");
375
+ case STATE_STOPPING:
376
+ return LOG_STR("STATE_STOPPING");
377
+ case STATE_INIT:
378
+ return LOG_STR("STATE_INIT");
379
+ default:
380
+ return LOG_STR("UNKNOWN");
381
+ }
382
+ };
383
+
384
+ void Rtttl::set_state_(State state) {
385
+ State old_state = this->state_;
386
+ this->state_ = state;
387
+ ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(state_to_string(old_state)),
388
+ LOG_STR_ARG(state_to_string(state)));
389
+ }
390
+
304
391
  } // namespace rtttl
305
392
  } // namespace esphome
@@ -14,12 +14,20 @@
14
14
  namespace esphome {
15
15
  namespace rtttl {
16
16
 
17
+ enum State : uint8_t {
18
+ STATE_STOPPED = 0,
19
+ STATE_INIT,
20
+ STATE_STARTING,
21
+ STATE_RUNNING,
22
+ STATE_STOPPING,
23
+ };
24
+
17
25
  #ifdef USE_SPEAKER
18
- static const size_t SAMPLE_BUFFER_SIZE = 512;
26
+ static const size_t SAMPLE_BUFFER_SIZE = 2048;
19
27
 
20
28
  struct SpeakerSample {
21
- int16_t left{0};
22
- int16_t right{0};
29
+ int8_t left{0};
30
+ int8_t right{0};
23
31
  };
24
32
  #endif
25
33
 
@@ -42,7 +50,7 @@ class Rtttl : public Component {
42
50
  void stop();
43
51
  void dump_config() override;
44
52
 
45
- bool is_playing() { return this->note_duration_ != 0; }
53
+ bool is_playing() { return this->state_ != State::STATE_STOPPED; }
46
54
  void loop() override;
47
55
 
48
56
  void add_on_finished_playback_callback(std::function<void()> callback) {
@@ -57,6 +65,8 @@ class Rtttl : public Component {
57
65
  }
58
66
  return ret;
59
67
  }
68
+ void finish_();
69
+ void set_state_(State state);
60
70
 
61
71
  std::string rtttl_{""};
62
72
  size_t position_{0};
@@ -68,13 +78,12 @@ class Rtttl : public Component {
68
78
 
69
79
  uint32_t output_freq_;
70
80
  float gain_{0.6f};
81
+ State state_{State::STATE_STOPPED};
71
82
 
72
83
  #ifdef USE_OUTPUT
73
84
  output::FloatOutput *output_;
74
85
  #endif
75
86
 
76
- void play_output_();
77
-
78
87
  #ifdef USE_SPEAKER
79
88
  speaker::Speaker *speaker_{nullptr};
80
89
  int sample_rate_{16000};
@@ -1,20 +1,20 @@
1
- import esphome.codegen as cg
2
- import esphome.config_validation as cv
3
1
  from esphome import automation
2
+ import esphome.codegen as cg
4
3
  from esphome.components import mqtt, web_server
4
+ import esphome.config_validation as cv
5
5
  from esphome.const import (
6
+ CONF_CYCLE,
6
7
  CONF_ENTITY_CATEGORY,
7
8
  CONF_ICON,
8
9
  CONF_ID,
10
+ CONF_INDEX,
11
+ CONF_MODE,
12
+ CONF_MQTT_ID,
9
13
  CONF_ON_VALUE,
14
+ CONF_OPERATION,
10
15
  CONF_OPTION,
11
16
  CONF_TRIGGER_ID,
12
- CONF_MQTT_ID,
13
17
  CONF_WEB_SERVER_ID,
14
- CONF_CYCLE,
15
- CONF_MODE,
16
- CONF_OPERATION,
17
- CONF_INDEX,
18
18
  )
19
19
  from esphome.core import CORE, coroutine_with_priority
20
20
  from esphome.cpp_generator import MockObjClass
@@ -1,22 +1,28 @@
1
1
  import math
2
2
 
3
- import esphome.codegen as cg
4
- import esphome.config_validation as cv
5
3
  from esphome import automation
4
+ import esphome.codegen as cg
6
5
  from esphome.components import mqtt, web_server
6
+ import esphome.config_validation as cv
7
7
  from esphome.const import (
8
- CONF_DEVICE_CLASS,
9
8
  CONF_ABOVE,
10
9
  CONF_ACCURACY_DECIMALS,
11
10
  CONF_ALPHA,
12
11
  CONF_BELOW,
12
+ CONF_DEVICE_CLASS,
13
13
  CONF_ENTITY_CATEGORY,
14
14
  CONF_EXPIRE_AFTER,
15
15
  CONF_FILTERS,
16
+ CONF_FORCE_UPDATE,
16
17
  CONF_FROM,
17
18
  CONF_ICON,
18
19
  CONF_ID,
19
20
  CONF_IGNORE_OUT_OF_RANGE,
21
+ CONF_MAX_VALUE,
22
+ CONF_METHOD,
23
+ CONF_MIN_VALUE,
24
+ CONF_MQTT_ID,
25
+ CONF_MULTIPLE,
20
26
  CONF_ON_RAW_VALUE,
21
27
  CONF_ON_VALUE,
22
28
  CONF_ON_VALUE_RANGE,
@@ -29,14 +35,9 @@ from esphome.const import (
29
35
  CONF_TRIGGER_ID,
30
36
  CONF_TYPE,
31
37
  CONF_UNIT_OF_MEASUREMENT,
32
- CONF_WINDOW_SIZE,
33
- CONF_MQTT_ID,
34
- CONF_WEB_SERVER_ID,
35
- CONF_FORCE_UPDATE,
36
38
  CONF_VALUE,
37
- CONF_MIN_VALUE,
38
- CONF_MAX_VALUE,
39
- CONF_METHOD,
39
+ CONF_WEB_SERVER_ID,
40
+ CONF_WINDOW_SIZE,
40
41
  DEVICE_CLASS_APPARENT_POWER,
41
42
  DEVICE_CLASS_AQI,
42
43
  DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
@@ -249,6 +250,7 @@ CalibratePolynomialFilter = sensor_ns.class_("CalibratePolynomialFilter", Filter
249
250
  SensorInRangeCondition = sensor_ns.class_("SensorInRangeCondition", Filter)
250
251
  ClampFilter = sensor_ns.class_("ClampFilter", Filter)
251
252
  RoundFilter = sensor_ns.class_("RoundFilter", Filter)
253
+ RoundMultipleFilter = sensor_ns.class_("RoundMultipleFilter", Filter)
252
254
 
253
255
  validate_unit_of_measurement = cv.string_strict
254
256
  validate_accuracy_decimals = cv.int_
@@ -734,6 +736,23 @@ async def round_filter_to_code(config, filter_id):
734
736
  )
735
737
 
736
738
 
739
+ @FILTER_REGISTRY.register(
740
+ "round_to_multiple_of",
741
+ RoundMultipleFilter,
742
+ cv.maybe_simple_value(
743
+ {
744
+ cv.Required(CONF_MULTIPLE): cv.positive_not_null_float,
745
+ },
746
+ key=CONF_MULTIPLE,
747
+ ),
748
+ )
749
+ async def round_multiple_filter_to_code(config, filter_id):
750
+ return cg.new_Pvariable(
751
+ filter_id,
752
+ config[CONF_MULTIPLE],
753
+ )
754
+
755
+
737
756
  async def build_filters(config):
738
757
  return await cg.build_registry_list(FILTER_REGISTRY, config)
739
758
 
@@ -472,5 +472,13 @@ optional<float> RoundFilter::new_value(float value) {
472
472
  return value;
473
473
  }
474
474
 
475
+ RoundMultipleFilter::RoundMultipleFilter(float multiple) : multiple_(multiple) {}
476
+ optional<float> RoundMultipleFilter::new_value(float value) {
477
+ if (std::isfinite(value)) {
478
+ return value - remainderf(value, this->multiple_);
479
+ }
480
+ return value;
481
+ }
482
+
475
483
  } // namespace sensor
476
484
  } // namespace esphome
@@ -431,5 +431,14 @@ class RoundFilter : public Filter {
431
431
  uint8_t precision_;
432
432
  };
433
433
 
434
+ class RoundMultipleFilter : public Filter {
435
+ public:
436
+ explicit RoundMultipleFilter(float multiple);
437
+ optional<float> new_value(float value) override;
438
+
439
+ protected:
440
+ float multiple_;
441
+ };
442
+
434
443
  } // namespace sensor
435
444
  } // namespace esphome
@@ -10,7 +10,7 @@ SmlFile::SmlFile(bytes buffer) : buffer_(std::move(buffer)) {
10
10
  this->pos_ = 0;
11
11
  while (this->pos_ < this->buffer_.size()) {
12
12
  if (this->buffer_[this->pos_] == 0x00)
13
- break; // fill byte detected -> no more messages
13
+ break; // EndOfSmlMsg
14
14
 
15
15
  SmlNode message = SmlNode();
16
16
  if (!this->setup_node(&message))
@@ -20,40 +20,66 @@ SmlFile::SmlFile(bytes buffer) : buffer_(std::move(buffer)) {
20
20
  }
21
21
 
22
22
  bool SmlFile::setup_node(SmlNode *node) {
23
- uint8_t type = this->buffer_[this->pos_] >> 4; // type including overlength info
24
- uint8_t length = this->buffer_[this->pos_] & 0x0f; // length including TL bytes
25
- bool is_list = (type & 0x07) == SML_LIST;
26
- bool has_extended_length = type & 0x08; // we have a long list/value (>15 entries)
27
- uint8_t parse_length = length;
28
- if (has_extended_length) {
23
+ // If the TL field is 0x00, this is the end of the message
24
+ // (see 6.3.1 of SML protocol definition)
25
+ if (this->buffer_[this->pos_] == 0x00) {
26
+ // Increment past this byte and signal that the message is done
27
+ this->pos_ += 1;
28
+ return true;
29
+ }
30
+
31
+ // Extract data from initial TL field
32
+ uint8_t type = (this->buffer_[this->pos_] >> 4) & 0x07; // type without overlength info
33
+ bool overlength = (this->buffer_[this->pos_] >> 4) & 0x08; // overlength information
34
+ uint8_t length = this->buffer_[this->pos_] & 0x0f; // length (including TL bytes)
35
+
36
+ // Check if we need additional length bytes
37
+ if (overlength) {
38
+ // Shift the current length to the higher nibble
39
+ // and add the lower nibble of the next byte to the length
29
40
  length = (length << 4) + (this->buffer_[this->pos_ + 1] & 0x0f);
30
- parse_length = length;
41
+ // We are basically done with the first TL field now,
42
+ // so increment past that, we now point to the second TL field
31
43
  this->pos_ += 1;
44
+ // Decrement the length for value fields (not lists),
45
+ // since the byte we just handled is counted as part of the field
46
+ // in case of values but not for lists
47
+ if (type != SML_LIST)
48
+ length -= 1;
49
+
50
+ // Technically, this is not enough, the standard allows for more than two length fields.
51
+ // However I don't think it is very common to have more than 255 entries in a list
32
52
  }
33
53
 
34
- if (this->pos_ + parse_length >= this->buffer_.size())
54
+ // We are done with the last TL field(s), so advance the position
55
+ this->pos_ += 1;
56
+ // and decrement the length for non-list fields
57
+ if (type != SML_LIST)
58
+ length -= 1;
59
+
60
+ // Check if the buffer length is long enough
61
+ if (this->pos_ + length > this->buffer_.size())
35
62
  return false;
36
63
 
37
- node->type = type & 0x07;
64
+ node->type = type;
38
65
  node->nodes.clear();
39
66
  node->value_bytes.clear();
40
67
 
41
- // if the list is a has_extended_length list with e.g. 16 elements this is a 0x00 byte but not the end of message
42
- if (!has_extended_length && this->buffer_[this->pos_] == 0x00) { // end of message
43
- this->pos_ += 1;
44
- } else if (is_list) { // list
45
- this->pos_ += 1;
46
- node->nodes.reserve(parse_length);
47
- for (size_t i = 0; i != parse_length; i++) {
68
+ if (type == SML_LIST) {
69
+ node->nodes.reserve(length);
70
+ for (size_t i = 0; i != length; i++) {
48
71
  SmlNode child_node = SmlNode();
49
72
  if (!this->setup_node(&child_node))
50
73
  return false;
51
74
  node->nodes.emplace_back(child_node);
52
75
  }
53
- } else { // value
54
- node->value_bytes =
55
- bytes(this->buffer_.begin() + this->pos_ + 1, this->buffer_.begin() + this->pos_ + parse_length);
56
- this->pos_ += parse_length;
76
+ } else {
77
+ // Value starts at the current position
78
+ // Value ends "length" bytes later,
79
+ // (since the TL field is counted but already subtracted from length)
80
+ node->value_bytes = bytes(this->buffer_.begin() + this->pos_, this->buffer_.begin() + this->pos_ + length);
81
+ // Increment the pointer past all consumed bytes
82
+ this->pos_ += length;
57
83
  }
58
84
  return true;
59
85
  }
@@ -101,7 +127,7 @@ int64_t bytes_to_int(const bytes &buffer) {
101
127
  // see https://stackoverflow.com/questions/42534749/signed-extension-from-24-bit-to-32-bit-in-c
102
128
  if (buffer.size() < 8) {
103
129
  const int bits = buffer.size() * 8;
104
- const uint64_t m = 1u << (bits - 1);
130
+ const uint64_t m = 1ull << (bits - 1);
105
131
  tmp = (tmp ^ m) - m;
106
132
  }
107
133
 
@@ -19,24 +19,22 @@ std::unique_ptr<Socket> socket_ip(int type, int protocol) {
19
19
 
20
20
  socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) {
21
21
  #if USE_NETWORK_IPV6
22
- if (addrlen < sizeof(sockaddr_in6)) {
23
- errno = EINVAL;
24
- return 0;
25
- }
26
- auto *server = reinterpret_cast<sockaddr_in6 *>(addr);
27
- memset(server, 0, sizeof(sockaddr_in6));
28
- server->sin6_family = AF_INET6;
29
- server->sin6_port = htons(port);
22
+ if (ip_address.find(':') != std::string::npos) {
23
+ if (addrlen < sizeof(sockaddr_in6)) {
24
+ errno = EINVAL;
25
+ return 0;
26
+ }
27
+ auto *server = reinterpret_cast<sockaddr_in6 *>(addr);
28
+ memset(server, 0, sizeof(sockaddr_in6));
29
+ server->sin6_family = AF_INET6;
30
+ server->sin6_port = htons(port);
30
31
 
31
- if (ip_address.find('.') != std::string::npos) {
32
- server->sin6_addr.un.u32_addr[3] = inet_addr(ip_address.c_str());
33
- } else {
34
32
  ip6_addr_t ip6;
35
33
  inet6_aton(ip_address.c_str(), &ip6);
36
34
  memcpy(server->sin6_addr.un.u32_addr, ip6.addr, sizeof(ip6.addr));
35
+ return sizeof(sockaddr_in6);
37
36
  }
38
- return sizeof(sockaddr_in6);
39
- #else
37
+ #endif /* USE_NETWORK_IPV6 */
40
38
  if (addrlen < sizeof(sockaddr_in)) {
41
39
  errno = EINVAL;
42
40
  return 0;
@@ -47,7 +45,6 @@ socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::stri
47
45
  server->sin_addr.s_addr = inet_addr(ip_address.c_str());
48
46
  server->sin_port = htons(port);
49
47
  return sizeof(sockaddr_in);
50
- #endif /* USE_NETWORK_IPV6 */
51
48
  }
52
49
 
53
50
  socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) {
@@ -1,13 +1,11 @@
1
1
  from esphome import automation
2
- import esphome.config_validation as cv
3
- import esphome.codegen as cg
4
-
5
2
  from esphome.automation import maybe_simple_id
6
- from esphome.const import CONF_ID, CONF_DATA
3
+ import esphome.codegen as cg
4
+ import esphome.config_validation as cv
5
+ from esphome.const import CONF_DATA, CONF_ID
7
6
  from esphome.core import CORE
8
7
  from esphome.coroutine import coroutine_with_priority
9
8
 
10
-
11
9
  CODEOWNERS = ["@jesserockz"]
12
10
 
13
11
  IS_PLATFORM_COMPONENT = True
@@ -22,8 +20,12 @@ PlayAction = speaker_ns.class_(
22
20
  StopAction = speaker_ns.class_(
23
21
  "StopAction", automation.Action, cg.Parented.template(Speaker)
24
22
  )
23
+ FinishAction = speaker_ns.class_(
24
+ "FinishAction", automation.Action, cg.Parented.template(Speaker)
25
+ )
25
26
 
26
27
  IsPlayingCondition = speaker_ns.class_("IsPlayingCondition", automation.Condition)
28
+ IsStoppedCondition = speaker_ns.class_("IsStoppedCondition", automation.Condition)
27
29
 
28
30
 
29
31
  async def setup_speaker_core_(var, config):
@@ -75,11 +77,18 @@ async def speaker_play_action(config, action_id, template_arg, args):
75
77
  automation.register_action("speaker.stop", StopAction, SPEAKER_AUTOMATION_SCHEMA)(
76
78
  speaker_action
77
79
  )
80
+ automation.register_action("speaker.finish", FinishAction, SPEAKER_AUTOMATION_SCHEMA)(
81
+ speaker_action
82
+ )
78
83
 
79
84
  automation.register_condition(
80
85
  "speaker.is_playing", IsPlayingCondition, SPEAKER_AUTOMATION_SCHEMA
81
86
  )(speaker_action)
82
87
 
88
+ automation.register_condition(
89
+ "speaker.is_stopped", IsStoppedCondition, SPEAKER_AUTOMATION_SCHEMA
90
+ )(speaker_action)
91
+
83
92
 
84
93
  @coroutine_with_priority(100.0)
85
94
  async def to_code(config):
@@ -39,10 +39,20 @@ template<typename... Ts> class StopAction : public Action<Ts...>, public Parente
39
39
  void play(Ts... x) override { this->parent_->stop(); }
40
40
  };
41
41
 
42
+ template<typename... Ts> class FinishAction : public Action<Ts...>, public Parented<Speaker> {
43
+ public:
44
+ void play(Ts... x) override { this->parent_->finish(); }
45
+ };
46
+
42
47
  template<typename... Ts> class IsPlayingCondition : public Condition<Ts...>, public Parented<Speaker> {
43
48
  public:
44
49
  bool check(Ts... x) override { return this->parent_->is_running(); }
45
50
  };
46
51
 
52
+ template<typename... Ts> class IsStoppedCondition : public Condition<Ts...>, public Parented<Speaker> {
53
+ public:
54
+ bool check(Ts... x) override { return this->parent_->is_stopped(); }
55
+ };
56
+
47
57
  } // namespace speaker
48
58
  } // namespace esphome
@@ -1,5 +1,9 @@
1
1
  #pragma once
2
2
 
3
+ #include <stddef.h>
4
+ #include <cstdint>
5
+ #include <vector>
6
+
3
7
  namespace esphome {
4
8
  namespace speaker {
5
9
 
@@ -17,10 +21,15 @@ class Speaker {
17
21
 
18
22
  virtual void start() = 0;
19
23
  virtual void stop() = 0;
24
+ // In compare between *STOP()* and *FINISH()*; *FINISH()* will stop after emptying the play buffer,
25
+ // while *STOP()* will break directly.
26
+ // When finish() is not implemented on the plateform component it should just do a normal stop.
27
+ virtual void finish() { this->stop(); }
20
28
 
21
29
  virtual bool has_buffered_data() const = 0;
22
30
 
23
31
  bool is_running() const { return this->state_ == STATE_RUNNING; }
32
+ bool is_stopped() const { return this->state_ == STATE_STOPPED; }
24
33
 
25
34
  protected:
26
35
  State state_{STATE_STOPPED};
@@ -7,10 +7,6 @@ namespace spi {
7
7
 
8
8
  const char *const TAG = "spi";
9
9
 
10
- SPIDelegate *const SPIDelegate::NULL_DELEGATE = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
11
- new SPIDelegateDummy();
12
- // https://bugs.llvm.org/show_bug.cgi?id=48040
13
-
14
10
  bool SPIDelegate::is_ready() { return true; }
15
11
 
16
12
  GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
@@ -79,8 +75,6 @@ void SPIComponent::dump_config() {
79
75
  }
80
76
  }
81
77
 
82
- void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); }
83
-
84
78
  uint8_t SPIDelegateBitBash::transfer(uint8_t data) { return this->transfer_(data, 8); }
85
79
 
86
80
  void SPIDelegateBitBash::write(uint16_t data, size_t num_bits) { this->transfer_(data, num_bits); }