1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-03 08:31:47 +00:00

Compare commits

..

530 Commits

Author SHA1 Message Date
Jesse Hills
e8f3eefd49 Discard changes to .github/workflows/ci.yml 2024-09-11 07:59:47 +12:00
Jesse Hills
679f8140c6 Merge branch 'dev' into jesserockz-2023-284 2024-09-11 07:59:26 +12:00
David Woodhouse
7b90bfaec6 Bump LibreTiny recommended version to 1.7.0 (#7432) 2024-09-11 07:43:19 +12:00
David Woodhouse
7abbb0fb97 Pull in new AsyncTCP for IPv6 on BK72xx (#7431) 2024-09-11 07:42:46 +12:00
marcovaneck
de7d2c33e1 [dsmr] Add internal 'telegram' text_sensor to support bridging (#6841)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-09-10 20:22:58 +12:00
Clyde Stubbs
c8aed15157 [LVGL] Add color gradients (#7427) 2024-09-10 13:24:18 +12:00
Clyde Stubbs
dcfad31770 [rpi_dpi_rgb] Add bounce_buffer config for ESP-IDF 5.x (#7423) 2024-09-10 13:15:56 +12:00
David Woodhouse
f5c2921b85 [bl0942] Improve energy reporting (#7428) 2024-09-10 13:11:26 +12:00
David Woodhouse
b5e5741ffd Switch IPv6 platform check to use require_framework_version() (#7410) 2024-09-10 11:59:46 +12:00
David Woodhouse
d10feafa9b Add BK72xx support to require_framework_version() (#7409) 2024-09-10 11:58:57 +12:00
Jesse Hills
9f42b76de3 [gh-actions] Don't produce docker build summaries (#7430) 2024-09-10 11:57:42 +12:00
Jesse Hills
198bd3b41a Bump libssl-dev to 3.0.14-1~deb12u2 (#7426) 2024-09-10 10:35:39 +12:00
Anton Viktorov
c90dcfc0ca LTR-501, LTR-301, LTR-558 Series of Lite-On Light (ALS) and Proximity(PS) sensors (#6262)
Co-authored-by: root <root@LAOX1>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-09-09 12:25:37 -05:00
David Woodhouse
7a93dde5d4 [libretiny] Report version 1.7.0 for 'dev' and 'latest' (#7415) 2024-09-09 17:05:19 +12:00
David Woodhouse
32995a352b libretiny: Allow specifying version of explicitly imported sources (#7408) 2024-09-09 17:05:09 +12:00
Clyde Stubbs
9722876ef6 [lvgl] Msgbox fixes and enhancements (#7380) 2024-09-09 15:59:09 +12:00
Michael Hansen
8bd46a43b9 Add voice assistant announce (#7377) 2024-09-09 12:54:20 +12:00
Adam DeMuri
18a1191e03 Add support for using BMP280 with SPI (#7053)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-09-05 17:08:02 +12:00
Jesse Hills
1548fa0811 [homeassistant-switch] Support different entity domains (#7331) 2024-09-04 20:09:49 -05:00
Markus
b496233425 Add StatsD component (#6642)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-09-05 12:57:44 +12:00
Jesse Hills
dc4e60526c [micro_wake_word] Remove duplicated download code (#7401) 2024-09-05 12:49:01 +12:00
David Woodhouse
71a7f6383f Support BL0942 calibration (#7299)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-09-05 12:08:39 +12:00
Jeff Cooper
e882cea47e Voice assist improvement - configurable conversation_id timeout (#7385) 2024-09-04 15:48:13 +12:00
dependabot[bot]
a7fd3b34aa Bump pypa/gh-action-pypi-publish from 1.10.0 to 1.10.1 (#7404)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 15:47:59 +12:00
dependabot[bot]
a96de54d46 Bump peter-evans/create-pull-request from 6.1.0 to 7.0.0 (#7405)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 15:45:40 +12:00
David Woodhouse
188faa6530 [bl0942] loop and overflow cleanup (#7358) 2024-09-04 15:38:47 +12:00
Sebastian Muszynski
1a71cc3047 Drop max BLE client connections limitation (#7088) 2024-09-04 12:02:33 +10:00
Jesse Hills
10ccc5f125 [api] Remove id from `MediaPlayerSupportedFormat` (#7406) 2024-09-04 12:55:41 +12:00
dependabot[bot]
c6e64a9ed3 Bump pypa/gh-action-pypi-publish from 1.9.0 to 1.10.0 (#7395)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 19:22:56 +12:00
Jesse Hills
565835cb59 Merge branch 'release' into dev 2024-09-03 16:38:57 +12:00
Jesse Hills
f2d8ab62dd Merge pull request #7400 from esphome/bump-2024.8.3
2024.8.3
2024-09-03 16:38:10 +12:00
Jesse Hills
cb4bede6d8 Bump version to 2024.8.3 2024-09-03 16:06:54 +12:00
Jesse Hills
39b2f30b16 Bump Dockerfile dependencies (#7386) 2024-09-03 16:06:54 +12:00
Jesse Hills
e18ae84031 Merge branch 'release' into dev 2024-09-03 13:38:01 +12:00
Jesse Hills
5cb1d18574 Merge pull request #7399 from esphome/bump-2024.8.2
2024.8.2
2024-09-03 13:37:13 +12:00
Kevin Ahrendt
f8ec5242c9 Better support for task blocking ring buffer reads and writes (#7390) 2024-09-03 12:47:54 +12:00
Tercio Filho
d6eeac0619 [modbus_controller] Allow duplicate command config (#7311) 2024-09-03 11:56:19 +12:00
Dan Greco
3b14b0efce [gree] Add support for YX1FF remote (#7298) 2024-09-03 10:35:54 +12:00
Jimmy Hedman
29f0b504b9 Bump rp2040 Arduino platform and framework (#7134) 2024-09-03 10:28:18 +12:00
Jimmy Hedman
01c50432c9 Bump mDNS and follow ruff's suggestions (#7308) 2024-09-03 10:16:59 +12:00
Jesse Hills
e5e06a12ef Bump version to 2024.8.2 2024-09-03 09:57:28 +12:00
Jesse Hills
c9c5ca28d2 [core] Only clean build files with esp-idf (#7388) 2024-09-03 09:57:28 +12:00
Jimmy Hedman
04ec6c5677 Enable IPv6 when manual IPv4 is enabled (#7381) 2024-09-03 09:57:28 +12:00
Jesse Hills
816b060edc [datetime] Fix templated args (#7368) 2024-09-03 09:57:28 +12:00
Mathieu Rene
91c7c43682 Fix build for esp32h2 using esp-idf 5.3 (#7393) 2024-09-03 09:26:10 +12:00
Jesse Hills
ca8e45cf4c [core] Only clean build files with esp-idf (#7388) 2024-09-02 19:11:21 +12:00
dependabot[bot]
854bafbd4a Bump actions/upload-artifact from 4.3.4 to 4.4.0 (#7379)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-02 14:33:58 +12:00
Jimmy Hedman
094c867fba Enable IPv6 when manual IPv4 is enabled (#7381) 2024-09-02 14:32:34 +12:00
Ludovic BOUÉ
fc930327b4 [rpi_dpi_rgb] Add enable_pin and reset_display method to driver (#7383)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-09-02 12:30:13 +10:00
Andrzej Skowroński
6490fc9c62 CH422G support (#7356) 2024-09-02 11:56:35 +10:00
Jesse Hills
3a7aabb2eb Bump Dockerfile dependencies (#7386) 2024-09-02 10:36:18 +12:00
Clyde Stubbs
61223a3cc9 [font] Make display an auto-load, not a dependency (#7366)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-09-02 08:45:40 +12:00
tomaszduda23
ca2f25e73b update logs for bluetooth proxy (#7382) 2024-09-01 21:20:31 +10:00
Clyde Stubbs
ba6963cf72 [udp] Implement UDP sensor broadcast (#6865)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: clydebarrow <366188+clydebarrow@users.noreply.github.com>
2024-08-30 20:59:55 +12:00
Piotr Szulc
721b532d71 Tuya Number: allow restoring value of hidden datapoints (#7346) 2024-08-30 12:53:34 +12:00
Trevor Schirmer
a5d46ae9e5 Update MiCS Values (#7173)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-30 12:36:32 +12:00
tomaszduda23
f8e8bd2c24 [code-quality] fix clang-tidy web_server and web_server_base (#7286) 2024-08-30 12:03:44 +12:00
Mariusz Kryński
69f98e0f87 esp32_can: make queue lengths configurable (#7361) 2024-08-30 11:43:47 +12:00
Clyde Stubbs
87d801721b Add now required invert_colors option to test files referencing ili9xxx (#7367) 2024-08-30 11:20:01 +12:00
Clyde Stubbs
d754bdde1b [st7701s] Add delay feature in init sequences (#7343) 2024-08-30 08:27:35 +12:00
Clyde Stubbs
725e50348b [gt911] Add reset pin config (#7373) 2024-08-30 08:20:12 +12:00
dependabot[bot]
acb00c9c59 Bump actions/setup-python from 5.1.1 to 5.2.0 in /.github/actions/restore-python (#7376)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 08:17:34 +12:00
dependabot[bot]
bb6693a255 Bump actions/setup-python from 5.1.0 to 5.2.0 (#7375)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 08:17:28 +12:00
Clyde Stubbs
c09df3c05d [bytebuffer] Use existing bit_cast operations. (#7374) 2024-08-30 08:16:16 +12:00
Clyde Stubbs
f28418d0b4 [lvgl] Bug fixes (#7370) 2024-08-29 13:34:41 +12:00
Clyde Stubbs
1922f2bbee [platformio] Add environments for ESP-IDF 5.3 for development (#7371) 2024-08-29 12:55:37 +12:00
Aiden
0375072bdf Add support for BL0906 energy meter (#7339)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-29 12:52:49 +12:00
Mariusz Kryński
b3f03c07c6 esp32_can: suppress compiler warning (#7372) 2024-08-29 12:52:13 +12:00
Jesse Hills
4b2032a98e [datetime] Fix templated args (#7368) 2024-08-28 10:07:31 -07:00
Clyde Stubbs
d6df466237 [lvgl] Add lvgl.widget.focus action and related triggers. (#7315) 2024-08-28 16:29:41 +12:00
Jesse Hills
458a8970b6 Merge branch 'release' into dev 2024-08-28 13:38:38 +12:00
Jesse Hills
8b6c95f723 Merge pull request #7363 from esphome/bump-2024.8.1
2024.8.1
2024-08-28 13:37:48 +12:00
Jesse Hills
28eda4b220 Bump version to 2024.8.1 2024-08-28 12:54:31 +12:00
Jesse Hills
9975e8b544 [api] Fix sending the `once` flag on ha entity subscription (#7357) 2024-08-28 12:54:31 +12:00
Clyde Stubbs
c1774c42c2 [lvgl] Fix race condition involving numbers, switches etc. (#7345) 2024-08-28 12:54:31 +12:00
Clyde Stubbs
8677763492 [core] Clean build if the loaded integrations changed (#7344) 2024-08-28 12:54:31 +12:00
Clyde Stubbs
388abaf09f [lvgl] Bug fixes (#7338) 2024-08-28 12:54:31 +12:00
Angel Nunez Mencias
92ae506ffb Add WS2811 to esp32_rmt_led_strip (#7353) 2024-08-28 11:40:21 +12:00
Gilles van den Hoven
34cce0e920 [ili9xxx] Make invert_colors required (#7292)
Co-authored-by: Gilles van den Hoven <gilles0181@gmail.com>
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
2024-08-27 22:07:32 +10:00
Angel Nunez Mencias
7e18a5c44f Add reset to esp32_rmt_led_strip (#7354) 2024-08-27 13:26:01 +12:00
Michael Hansen
5a707b558d Add supported formats to media player (#7318)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-27 11:38:49 +12:00
David Woodhouse
e10f8128c8 bl0942: Fix init sequence, add address and line_frequency options (#7250) 2024-08-27 10:41:09 +12:00
Jesse Hills
0f2064193f [api] Fix sending the `once` flag on ha entity subscription (#7357) 2024-08-27 10:20:26 +12:00
Jesse Hills
dc9c001056 [const] Move `CONF_LINE_FREQUENCY` to const.py (#7351) 2024-08-26 13:07:18 +12:00
Clyde Stubbs
60fced53c2 [lvgl] Bug fixes: (#7341) 2024-08-26 10:08:30 +12:00
Clyde Stubbs
71d6bbc7e6 [lvgl] Fix race condition involving numbers, switches etc. (#7345) 2024-08-26 10:03:25 +12:00
Clyde Stubbs
caaae59ea9 [ledc] Fix maximum brightness on ESP-IDF 5.1 (#7342)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-08-24 09:56:13 +00:00
Keith Burzinski
a01fea54a0 [ledc] Tweak fix in #6997 (#7336) 2024-08-24 02:32:08 -05:00
Clyde Stubbs
43f8f2fd2e [core] Clean build if the loaded integrations changed (#7344) 2024-08-23 20:09:40 +12:00
Rodrigo Martín
3c65cabe1d feat: Expand ByteBuffer (#7316)
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-23 07:30:22 +10:00
Clyde Stubbs
5cc8dbace4 [lvgl] Bug fixes (#7338) 2024-08-23 06:56:53 +12:00
Piotr Szulc
ab620acd4f Tuya Number: allow to set hidden datapoints (#7024)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-22 12:59:31 +12:00
Pieter Viljoen
11e155d866 Enable verbose mode from env ESPHOME_VERBOSE or --verbose (#6987) 2024-08-22 12:58:43 +12:00
Sebastian Muszynski
68272c39c0 Add output source priority "hybrid" (#7322) 2024-08-22 12:58:11 +12:00
Jesse Hills
da72bae94a Merge branch 'release' into dev 2024-08-21 17:32:54 +12:00
Jesse Hills
1f21e419aa Merge pull request #7329 from esphome/bump-2024.8.0
2024.8.0
2024-08-21 17:32:03 +12:00
Jesse Hills
5d4bf5f8e5 Bump version to 2024.8.0 2024-08-21 14:20:29 +12:00
Jesse Hills
b5a6d3aa9d Merge branch 'beta' into dev 2024-08-21 13:26:14 +12:00
Jesse Hills
813d517076 Merge pull request #7328 from esphome/bump-2024.8.0b4
2024.8.0b4
2024-08-21 13:25:37 +12:00
Jesse Hills
4ed6a64869 Bump version to 2024.8.0b4 2024-08-21 11:46:56 +12:00
NewoPL
aaae8f4a87 [rtttl] fix STOPPED state (#7323) 2024-08-21 11:46:56 +12:00
Sung-jin Brian Hong
436c6282da Fix waveshare 2.13" epaper stride calculation error (#7303)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-21 11:46:56 +12:00
NP v/d Spek
c043bbe598 add the ability to add more idf components to an existing setup (#7302)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-21 11:46:56 +12:00
Ali Jafri
8fae609316 Fix RP2040 Neopixel flickering issue (#7307) 2024-08-21 11:46:56 +12:00
NewoPL
848fd0442d [rtttl] fix STOPPED state (#7323) 2024-08-21 11:46:15 +12:00
Sung-jin Brian Hong
bd3d065a23 Fix waveshare 2.13" epaper stride calculation error (#7303)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-21 11:44:21 +12:00
tomaszduda23
fa497d06b0 [code-quality] fix clang-tidy cstddef (#7324) 2024-08-21 10:01:50 +12:00
tomaszduda23
3cbdf63f56 [code-quality] fix clang-tidy socket (#7285) 2024-08-20 10:53:15 +12:00
NP v/d Spek
30414667d0 add the ability to add more idf components to an existing setup (#7302)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-20 10:22:19 +12:00
Ali Jafri
1ffee9c4d2 Fix RP2040 Neopixel flickering issue (#7307) 2024-08-20 09:42:41 +12:00
Roving Ronin
b425912a80 Update const.py - Add missing UNIT_LITRE (#7317) 2024-08-20 09:18:06 +12:00
Jesse Hills
10147d8e0e Merge branch 'beta' into dev 2024-08-19 15:21:09 +12:00
Jesse Hills
c4d225a6f2 Merge pull request #7313 from esphome/bump-2024.8.0b3
2024.8.0b3
2024-08-19 15:20:32 +12:00
Jesse Hills
409e84090e Bump version to 2024.8.0b3 2024-08-19 13:09:59 +12:00
Jesse Hills
c96784f591 [microphone] Fix header includes (#7310) 2024-08-19 13:09:59 +12:00
NP v/d Spek
0f82114e64 [speaker] Fix header includes (#7304) 2024-08-19 13:09:59 +12:00
Clyde Stubbs
5c7d070307 [lvgl] Bug fixes (#7300) 2024-08-19 13:09:59 +12:00
Jesse Hills
7464b440c0 Revert "[validation] Allow `maybe_simple_value` to not have default key in complex value" (#7305) 2024-08-19 13:09:59 +12:00
Jesse Hills
baedd74c7a [microphone] Fix header includes (#7310) 2024-08-19 10:45:22 +12:00
NP v/d Spek
8b6d6fe661 [speaker] Fix header includes (#7304) 2024-08-19 10:45:10 +12:00
Clyde Stubbs
ac9417d469 [lvgl] Bug fixes (#7300) 2024-08-19 10:43:23 +12:00
Jesse Hills
56aa58780d Revert "[validation] Allow `maybe_simple_value` to not have default key in complex value" (#7305) 2024-08-18 03:27:03 -05:00
Jesse Hills
75899162b3 Merge branch 'beta' into dev 2024-08-17 08:08:42 +12:00
Jesse Hills
28bb0ddfeb Merge pull request #7297 from esphome/bump-2024.8.0b2
2024.8.0b2
2024-08-17 08:07:54 +12:00
Jesse Hills
e779a09586 Bump version to 2024.8.0b2 2024-08-16 13:38:06 +12:00
David Woodhouse
343650e37d [network] Always allow `enable_ipv6: false` (#7291)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-16 13:38:06 +12:00
Jesse Hills
2c47eb62a7 [validation] Allow `maybe_simple_value` to not have default key in complex value (#7294) 2024-08-16 13:38:06 +12:00
Gábor Kiss
033ab55206 Fix overflow in ESPColorCorrection object (#7268) 2024-08-16 13:38:06 +12:00
NP v/d Spek
e17c7124f4 fix some small rtttl issues (#6817)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-16 13:38:06 +12:00
Clyde Stubbs
e3bfbebb8f [api] Bump noise-c library version (#7288) 2024-08-16 13:38:06 +12:00
Samuel Sieb
bc20fd57fe remove extra number from pronto (#7263) 2024-08-16 13:38:05 +12:00
David Woodhouse
a7167ec3bf [network] Always allow `enable_ipv6: false` (#7291)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-16 13:32:00 +12:00
David Woodhouse
a0c54504cd Add HMAC-MD5 support for authenticating OTA updates (#7200)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-16 11:27:23 +12:00
Jesse Hills
c3668b9a4d [validation] Allow `maybe_simple_value` to not have default key in complex value (#7294) 2024-08-15 18:05:26 -05:00
Gábor Kiss
9001d1c0d4 Fix overflow in ESPColorCorrection object (#7268) 2024-08-16 10:35:00 +12:00
tomaszduda23
abb2669f0f [code-quality] fix clang-tidy captive_portal (#7280) 2024-08-16 09:16:06 +12:00
tomaszduda23
9713458368 [code-quality] fix clang-tidy improv_serial (#7283) 2024-08-15 17:17:38 +12:00
NP v/d Spek
5c31ab4060 fix some small rtttl issues (#6817)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-15 04:51:44 +00:00
tomaszduda23
965141fad7 [code-quality] fix clang-tidy wireguard (#7287) 2024-08-15 16:38:49 +12:00
Clyde Stubbs
ecd3d838c9 [api] Bump noise-c library version (#7288) 2024-08-15 15:35:03 +12:00
tomaszduda23
ce7adbae99 [code-quality] fix clang-tidy e131 (#7281) 2024-08-15 10:31:19 +12:00
tomaszduda23
1bc3ccd969 [code-quality] fix clang-tidy ota (#7282) 2024-08-15 10:30:29 +12:00
tomaszduda23
5646ec7f9c [code-quality] fix clang-tidy prometheus (#7284) 2024-08-15 09:41:29 +12:00
tomaszduda23
80a0f13722 [code-quality] fix performance-unnecessary-value-param (#7274) 2024-08-15 07:05:16 +10:00
Jesse Hills
fef592b6c6 Merge branch 'beta' into dev 2024-08-15 07:51:18 +12:00
Jesse Hills
b654dea55e Merge pull request #7278 from esphome/bump-2024.8.0b1
2024.8.0b1
2024-08-15 07:50:36 +12:00
Samuel Sieb
7133e08755 remove extra number from pronto (#7263) 2024-08-14 02:55:23 -05:00
Jesse Hills
7b233d6871 Bump version to 2024.8.0b1 2024-08-14 16:56:53 +12:00
Jesse Hills
350f17e48f Bump version to 2024.9.0-dev 2024-08-14 16:56:53 +12:00
Mike La Spina
ccf57488c5 Correct offset calibration (#7228)
Co-authored-by: descipher <mike.laspina@gelidus.ca>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-14 16:43:35 +12:00
NP v/d Spek
cf6ea7cb2c Implement the finish() method and action. implement the is_stopped condition (#7255) 2024-08-14 15:42:43 +12:00
Kevin Ahrendt
d6f130e35a [micro_wake_word] Bump ESPMicroSpeechFeatures version to 1.1.0 (#7249) 2024-08-14 15:40:07 +12:00
Philippe Wechsler
8f09382367 support illuminance for airthings wave plus device (#5203)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-14 14:25:45 +12:00
tomaszduda23
b2b23f2a4f [code-quality] fix readability-named-parameter (#7272) 2024-08-14 14:21:19 +12:00
Olivier ARCHER
8756b41b63 [mqtt] fix missing initializer in MQTTClientComponent::disable_discovery (#7271) 2024-08-14 14:19:46 +12:00
tomaszduda23
4cb174585c [code-quality] fix readability-braces-around-statements (#7273) 2024-08-14 14:14:29 +12:00
tomaszduda23
56e05998ef [code-quality] fix clang-tidy wake_on_lan (#7275) 2024-08-14 14:08:10 +12:00
Clyde Stubbs
bec2d42c79 Add color_filter_opa style property (#7276) 2024-08-14 14:06:13 +12:00
Clyde Stubbs
a0eff08f39 [lvgl] Rework events to avoid feedback loops (#7262) 2024-08-14 14:05:25 +12:00
Landon Rohatensky
a5fdcb31fc [homeassistant] Native number entity import and control (#6455)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-14 14:04:12 +12:00
Markus
1d25db491c [homeassistant] Native switch entity import and control (#7018)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-14 14:03:12 +12:00
PaoloTK
c5b1a8eb81 Add min and max brightness parameters for Light dim_relative Action (#6971) 2024-08-14 09:29:55 +12:00
Clyde Stubbs
68c56b3e03 Implement ByteBuffer (#6878) 2024-08-14 09:29:31 +12:00
Jesse Hills
0c567adf63 [CI] Dont run full CI on `build-image` action changes (#7270) 2024-08-14 08:13:09 +12:00
dependabot[bot]
9ec61cbff3 Bump docker/build-push-action from 6.6.1 to 6.7.0 in /.github/actions/build-image (#7269)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-14 08:12:56 +12:00
tomaszduda23
2e58297a16 [code-quality] fix clang-tidy wifi related (#7254) 2024-08-14 07:58:30 +12:00
tomaszduda23
f81ce2c707 [code-quality] fix clang-tidy mqtt (#7253) 2024-08-14 07:56:09 +12:00
tomaszduda23
4bd7ba0d30 [code-quality] Fix variable naming in base_light_effects (#7237) 2024-08-14 07:54:37 +12:00
tomaszduda23
9663b7d67c [code-quality] fix clang-tidy core optional (#7265) 2024-08-14 07:53:42 +12:00
tomaszduda23
b082a64d32 [code-quality] fix clang-tidy network (#7266) 2024-08-14 07:48:27 +12:00
tomaszduda23
c9979ad90c [code-quality] fix order in esphome/const.py (#7267) 2024-08-14 07:46:23 +12:00
Clyde Stubbs
3598560472 [lvgl] Add initial_focus for encoders (#7256) 2024-08-13 20:06:01 +12:00
guillempages
506e69addf [online_image] add option to show placeholder while downloading (#7083)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-13 19:44:43 +12:00
nkinnan
2a70ef05d1 [const] Add some units for future use and adjust case (#7260) 2024-08-13 18:48:12 +12:00
Jesse Hills
8696f922d1 [homeassistant] Add `HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA` (#7259) 2024-08-13 17:33:16 +12:00
Jesse Hills
2b25daa199 [api] Add new flag to request state/attribute once from HA only (#7258) 2024-08-13 17:12:06 +12:00
Olivier ARCHER
ab51bbd8f7 [api] Error log when NONE Update command is sent (#7247)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-13 13:52:31 +12:00
RFDarter
390d5f2f93 [test][web_server] Rejig test for v3 (#7110) 2024-08-13 13:26:39 +12:00
tomaszduda23
8d106e97a2 [code-quality] fix clang-tidy web server (#7230)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-13 01:14:25 +00:00
juanluss31
fc146dabed Add support for LYWSD02MMC Xiaomi device (#7080) 2024-08-13 13:12:48 +12:00
tomaszduda23
8d5be27746 [code-quality] Apply ruff linting suggestions (#7239)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-13 12:47:18 +12:00
tomaszduda23
f24fd34d86 fix name conflict with zephyr macro (#7252) 2024-08-13 11:38:13 +12:00
tomaszduda23
64ee40d370 [code-quality] clang-tidy bedjet (#7251) 2024-08-13 11:33:51 +12:00
tomaszduda23
5f3f106283 [code-quality] add NOLINT haier_base (#7236) 2024-08-13 11:29:09 +12:00
NP v/d Spek
8148eae134 add windows script/setup.bat (#7140)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-08-13 11:16:42 +12:00
tomaszduda23
f13cf1f7a0 adjust to new python pre-commit hooks (#7178)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-12 16:52:09 +12:00
tomaszduda23
8a076cc906 fix build error (#7229) 2024-08-12 16:49:35 +12:00
dependabot[bot]
82c5cd18de Bump docker/build-push-action from 6.5.0 to 6.6.1 in /.github/actions/build-image (#7232)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-12 16:30:27 +12:00
tomaszduda23
e769804fe6 [code-quality] clang-tidy media_player (#7238) 2024-08-12 16:27:22 +12:00
David K.
f2e99fa319 [bme68x_bsec2_i2c] BME68X Temperature+Pressure+Humidity+Gas Sensor via BSEC2 (#4585)
* Added initial bme68x component

* Initialize all child sensors to nullptr

This was added to all other sensors in #3808

* Update BSEC2 and BME68x Libraries

Current versions from Bosch Sensortec

* Add myself to codeowners for bme68x_bsec

* Move constants to const.py, according to ci-custom checks

Move constants to const.py, according to ci-custom checks

* Update library dependencies

We'll stick with 1.4.2200 for now. 1.4.2200 is not on platform.io registry, use tag instead.

Update to 1.5.2400 needs some work due to multi instance support.

* Update BSEC2 to 1.6.2400

* Add consts to bme680x_bsec

Enable inclusion with external_components

* Update device class for pressure

* Update to use multisensor API

* Tidy up some constants

* Add tests

* Remove scd30 changes

* Import CONF_SAMPLE_RATE

* Pull BSEC config blob from repo based on config

* Rename component to `bme68x_bsec_i2c`

* Fix tests + codeowners

* Cleanup for review

* Rename using `bsec2`

* Apply suggestions from code review

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>

* Download file during validation stage, instead

* Make `dump_config()` only dump stuff

* Compile safely without sensor and text sensor headers

* Use `intf_ptr`

* Save state if measuring static IAQ, too

* Update CODEOWNERS

* Simplify esphome/components/bme68x_bsec2_i2c/__init__.py

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>

* Remove extraneous colon & imports

* Track & save the maximum accuracy value

* Polish up accuracy sensor handling

* Log static sensor, update `defines.h`

* Walruses make it better

* Add some logging of setup failures

* Update esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp

Co-authored-by: Trevor North <trevor@freedisc.co.uk>

* Break out some things

* Update CODEOWNERS

* Update CODEOWNERS take 2

* Use `add_extra` in base schema

* Another walrus in the sensor

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Trevor North <trevor@freedisc.co.uk>
2024-08-11 23:14:58 -05:00
Clyde Stubbs
34d435c996 [lvgl] Implement default group for encoders (#7242)
Co-authored-by: clydeps <U5yx99dok9>
2024-08-12 15:56:54 +12:00
Flo
d04e706295 Allow project name and version as improv_serial identity (#7248)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-12 14:20:51 +12:00
Nis Wechselberg
442e765187 [sml] Fixed crashing sml parser (#7235) 2024-08-12 14:18:11 +12:00
Michael Davidson
15602b0664 Add text_align_to_string (#7243) 2024-08-12 08:06:29 +12:00
tomaszduda23
b43c5b851a add missing overrides (#7231) 2024-08-09 21:15:25 +10:00
Clyde Stubbs
a47a17d7e7 [lvgl] Fix set state on updates (#7227) 2024-08-08 20:24:10 +12:00
tomaszduda23
b71c03424e [code-quality] Organise time imports (#7219) 2024-08-08 17:02:55 +12:00
tomaszduda23
a3d5b69a9c [code-quality] NOLINT readability-identifier-naming (#7220) 2024-08-08 17:02:41 +12:00
dentra
3f1d2c0caf [mqtt] Add extended device info (#7194)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-08 16:49:37 +12:00
David Woodhouse
7fd65987d3 hx711: Check for DOUT going high after a reading (#7214) 2024-08-08 14:29:49 +12:00
tomaszduda23
24b6c1d3eb [code-quality] __attribute__((packed)) (#7221) 2024-08-07 19:30:49 -05:00
tomaszduda23
9a9757ddeb [code-quality] fix clang-tidy sprinkler (#7222)
* fix clang-tidy

* fix build error

* clang-tidy

* clang-tidy
2024-08-07 19:29:32 -05:00
tomaszduda23
4b91ef5123 [code-quality] Apply ruff linting suggestions to core (#7207) 2024-08-07 19:33:41 +12:00
tomaszduda23
2a8424a7f2 [code-quality] Organise logger imports (#7205) 2024-08-07 19:32:06 +12:00
tomaszduda23
132269c5b8 [code-quality] Apply ruff linting suggestions (#7206) 2024-08-07 19:31:44 +12:00
Jesse Hills
ddd8027238 [spi] Remove `SPIDelegateDummy` (#7215) 2024-08-07 06:33:12 +00:00
tomaszduda23
c348efa401 [code-quality] Organise base entities imports (#7208) 2024-08-07 15:49:51 +12:00
Jesse Hills
9b0c2234d8 [max31856] Use cv.frequency as validator (#7212) 2024-08-06 22:47:46 -05:00
Jesse Hills
73f786c606 [code-quality] Organise script imports (#7198) 2024-08-06 22:46:37 -05:00
iannisimo
1e63fddf36 [remote_transmitter] Change default carrier_frequency to valid value (#7176)
set current_carrier_frequency_ default value to esp-idf's default (38000)
2024-08-06 18:02:30 -05:00
Jesse Hills
da0dbe8753 Revert "Add null GPIO pin " (#6621) 2024-08-07 07:29:05 +12:00
Clyde Stubbs
eccc5a3ea3 [lvgl] Fix compile error when using encoder with buttons only. (#7203) 2024-08-07 07:15:28 +12:00
Jesse Hills
8667f51cf0 Move CONF_ITEMS/CONF_FONT/CONF_TEXT to const.py (#7204) 2024-08-07 07:15:15 +12:00
Mimoja
455df35e50 Update i2s_audio_speaker.cppi2s_audio/speaker: Fix fallthrough compiler warning (#7167) 2024-08-06 23:17:02 +12:00
guillempages
9188836f70 Add runtime online image support (#4710) 2024-08-06 23:08:06 +12:00
Jesse Hills
b0d9800817 [helpers] Set default flags of ExternalRAMAllocator to ALLOW_FAILURE (#7201) 2024-08-06 05:02:08 -05:00
Jesse Hills
e6b1780a31 Move `CONF_BACKGROUND_COLOR and CONF_FOREGROUND_COLOR` to const.py (#7202) 2024-08-06 04:39:47 -05:00
Clyde Stubbs
71ea2cec1f [lvgl] Final stage (#7184)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-06 03:56:48 +00:00
Nate Clark
7074fa06ae Adds MQTT component to Alarm Control panel component (#7188) 2024-08-06 15:53:52 +12:00
David Woodhouse
3ba9caa118 socket: socket::set_sockaddr() for IPv4 addresses in IPv6 builds (#7196) 2024-08-06 13:50:36 +12:00
Clyde Stubbs
6b141102d6 [lvgl] Stage 5 (#7191)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-06 13:17:29 +12:00
tomaszduda23
acaec41bb7 Remove outdated version block (#7177) 2024-08-06 11:40:34 +12:00
Daniel Kraft
f737ca6e28 hydreon_rgxx: Fix parsing of data line (#7192) 2024-08-06 09:17:02 +12:00
Kevin Ahrendt
e02319dcff [esp32_improv] Update Improv library to reference new repo/version (#7195) 2024-08-05 11:09:54 -05:00
Clyde Stubbs
d18bb34f87 [lvgl] Stage 4 (#7166) 2024-08-05 17:07:05 +12:00
Jesse Hills
87944f0c1b Add support for doing update entity refresh/check via API. (#7190) 2024-08-04 23:58:20 -05:00
Jesse Hills
38c25dec93 [code-quality] More portable shebangs (#7189)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-08-05 04:15:19 +00:00
Clyde Stubbs
81ac9391d1 [core] Eliminate nuisance messages from build_codeowners (#7185) 2024-08-05 14:04:06 +12:00
Olivier ARCHER
61c6581123 git ignore managed_components (#7180) 2024-08-02 23:00:18 +00:00
Björn Ebbinghaus
4a7570770b Implement 'round to nearest multiple' filter (#7142) 2024-08-01 18:58:59 -05:00
Jesse Hills
aedfb32482 Bump improv library to 1.2.4 (#7174) 2024-08-01 22:01:21 +00:00
SimoPk
a5f18dfe7f ade7953_spi wrong size specified in read_array call (#7172) 2024-08-01 22:39:54 +12:00
Jesse Hills
cb9906b921 [api] `homeassistant.action replaces homeassistant.service` (#7171) 2024-08-01 22:38:36 +12:00
Jesse Hills
144f1d3663 Merge branch 'release' into dev 2024-08-01 11:15:24 +12:00
Jesse Hills
546bfe6db5 Merge pull request #7168 from esphome/bump-2024.7.3
2024.7.3
2024-08-01 11:14:35 +12:00
Jesse Hills
0af10c58f5 Bump version to 2024.7.3 2024-08-01 07:51:23 +12:00
Kevin Ahrendt
5ac9d301ea [micro_wake_word] Fix VAD detection and modify detection computation (#7164) 2024-08-01 07:51:23 +12:00
RubyBailey
a70f926971 Fix for Mitsubishi units that only support cooling (#7143) 2024-08-01 07:51:23 +12:00
thevogoncoder
dfacf1bbfe Add delay after sending REG_READ_START (#7130)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-08-01 07:51:23 +12:00
Clyde Stubbs
3920029aff [lvgl] PR stage 3 (#7160)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-31 16:31:15 +12:00
Jesse Hills
8849443bf6 [update] Implement `update.perform action and update.is_available` condition (#7165)
* [update] Fix unimplemented yaml action/condition

* Add/update tests

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-07-31 04:08:11 +00:00
Adam Allport
dd3dd7a136 fix: Add pin->setup(); to matrix_keypad.cpp (#7163) 2024-07-30 14:30:15 -07:00
Kevin Ahrendt
dff6884bed [micro_wake_word] Fix VAD detection and modify detection computation (#7164) 2024-07-31 08:57:51 +12:00
Jesse Hills
d7231fadb1 [touchscreen] Allow binary sensor to have multiple pages in config (#7112)
* [touchscreen] Allow binary sensor to have multiple pages in config

* Sort imports
2024-07-29 23:50:12 -05:00
Olivier ARCHER
caa2ea64e3 http_request watchdog as a component (#7161) 2024-07-30 13:45:19 +12:00
Jesse Hills
83bb7d0266 [code-quality] Organise bluetooth related imports (#7155) 2024-07-30 13:23:30 +12:00
FreeBear-nc
6e21d79bde [pid] Add get_min_integral() and get_max_integral() (#7162) 2024-07-30 13:15:27 +12:00
Clyde Stubbs
7c1aa771aa LVGL stage 2 (#7129)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-29 23:41:34 +00:00
dependabot[bot]
12e840ee88 Bump docker/setup-buildx-action from 3.5.0 to 3.6.1 in the docker-actions group (#7159)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-30 11:36:09 +12:00
RubyBailey
25c8676d80 Fix for Mitsubishi units that only support cooling (#7143) 2024-07-30 11:20:29 +12:00
FreeBear-nc
341fc65958 Add microAmp and milliAmp to defined units (#7157) 2024-07-30 08:05:25 +12:00
Jesse Hills
5b6b7c0d15 [code-quality] Organise esp32 imports (#7154) 2024-07-29 03:25:53 -05:00
Jesse Hills
24515546fd Move `CONF_ON_ERROR` to const.py (#7156) 2024-07-29 03:22:30 -05:00
Jesse Hills
b3728697cc Remove deprecated argument parser (#7151)
* Remove deprecated argument parser

* Add back removed argcomplete line
2024-07-29 03:13:57 -05:00
Jesse Hills
e64709c37e [code-quality] Organise core imports (#7149) 2024-07-29 14:07:44 +12:00
Jesse Hills
20c2246533 [code-quality] Organise wifi related imports (#7153) 2024-07-29 14:06:08 +12:00
Jesse Hills
acf690c87d [code-quality] Organise ethernet related imports (#7152) 2024-07-29 14:05:41 +12:00
Jesse Hills
adfec578cf Add `--version` handler to cli (#7150) 2024-07-28 20:13:09 -05:00
thevogoncoder
39c0019534 Add delay after sending REG_READ_START (#7130)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-25 14:06:23 +12:00
Jesse Hills
f61582f826 [dependabot] Group docker action bumps into single PR (#7133) 2024-07-25 13:19:33 +12:00
Jesse Hills
e343aca9bc Merge branch 'release' into dev 2024-07-25 12:48:28 +12:00
Jesse Hills
038f24fcea Merge pull request #7132 from esphome/bump-2024.7.2
2024.7.2
2024-07-25 12:47:33 +12:00
J. Nick Koston
d3f2434c57 Bump aioesphomeapi to 24.6.2 and cryptography to 43.0.0 (#7131) 2024-07-25 12:45:42 +12:00
Clyde Stubbs
23ffc3ddfb [lvgl] base implementation (#7116)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-25 11:12:04 +12:00
Jesse Hills
ad0118dd4a Bump version to 2024.7.2 2024-07-25 09:13:05 +12:00
dentra
7c24f1ba6d [http_request] Fix ESP-IDF follow redirect (#7101) 2024-07-25 09:13:05 +12:00
Jesse Hills
6e863305aa [http_request] Change default timeout to 4.5s (#7123) 2024-07-25 09:13:05 +12:00
Clyde Stubbs
75635956cd Give more info on import errors. (#7128) 2024-07-25 07:30:39 +12:00
dentra
1f3754684a [http_request] Allow configure buffer size on ESP-IDF (#7125)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-24 15:50:59 +12:00
esphomebot
da10de9ea8 Update webserver local assets to 20240724-013115 (#7126) 2024-07-24 01:57:02 +00:00
dentra
39de179e21 [http_request] Fix ESP-IDF follow redirect (#7101) 2024-07-24 12:12:59 +12:00
Clyde Stubbs
2cc14055cf Added ruff to pre-commit hooks (#7124) 2024-07-23 16:12:23 +12:00
Daniel
19a787c235 [fan] fix initial FanCall to properly set speed (#7113)
Speed settings were ignored for the first FanCall, if no speed has been restored before. This commit changes the behaviour to: set speed to 100%, iff current speed AND new speed are not set.
2024-07-22 21:53:31 -05:00
dependabot[bot]
e88e32bf23 Bump docker/setup-buildx-action from 3.4.0 to 3.5.0 (#7122)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-23 14:21:03 +12:00
dependabot[bot]
f0d4b5f740 Bump docker/login-action from 3.2.0 to 3.3.0 (#7121)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-23 14:20:54 +12:00
dependabot[bot]
2b2a83273f Bump docker/setup-qemu-action from 3.1.0 to 3.2.0 (#7120)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-23 14:20:44 +12:00
Jesse Hills
ae476bb400 [http_request] Change default timeout to 4.5s (#7123) 2024-07-22 20:51:32 -05:00
dependabot[bot]
dc24eefe08 Bump docker/build-push-action from 6.4.1 to 6.5.0 in /.github/actions/build-image (#7119)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-23 13:01:45 +12:00
Aodren Auffrédou-Heinicke
f1aa254e48 APDS9306 Ambient Light Sensor (#6709)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Mat931 <49403702+Mat931@users.noreply.github.com>
2024-07-22 17:29:54 +12:00
Jan-Philipp Benecke
5d5f3276e9 Inherit esp32_ble_beacon from esp32_ble (#6908)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-22 16:20:09 +12:00
Jesse Hills
172a358d01 Merge branch 'release' into dev 2024-07-22 14:09:49 +12:00
Jesse Hills
0ac549d208 Merge pull request #7114 from esphome/bump-2024.7.1
2024.7.1
2024-07-22 14:09:00 +12:00
Clyde Stubbs
8fc42694f6 [ili9xxx] Rework delay handling (#7115) 2024-07-22 13:42:25 +12:00
leejoow
0a7d883633 [modbus_controller] Add on_command_sent trigger (#7078)
Co-authored-by: Leo Schelvis <leo.schelvis@gmail.com>
2024-07-22 13:33:11 +12:00
Jesse Hills
41813b0a1f Bump version to 2024.7.1 2024-07-22 12:35:06 +12:00
irgendwienet
4690e227b8 Fixes sml parser to process extended length lists with a number of items that is dividable by 16 (#6148) 2024-07-22 12:35:06 +12:00
Olivier ARCHER
5bec0a6534 [http_request] allow basic auth for idf (#7086) 2024-07-22 12:35:06 +12:00
Lucio Tarantino
626ed815fb [heatpumpir] Fix BK72XX Compile error with IRremoteESP8266 (#6955) 2024-07-22 12:35:06 +12:00
Kevin Ahrendt
74aee1d453 revert bit shift to match previous behavior (#7109) 2024-07-22 12:35:06 +12:00
Alex Cortelyou
d187340fc4 Prevent rename from deleting new config (#7104) 2024-07-22 12:35:06 +12:00
irgendwienet
a464e46d4d Fixes sml parser to process extended length lists with a number of items that is dividable by 16 (#6148) 2024-07-22 11:42:09 +12:00
tomaszduda23
f322ec8f3d use cache to build tests for compoenents (#7059) 2024-07-22 11:33:26 +12:00
Olivier ARCHER
1f4829598a [http_request] allow basic auth for idf (#7086) 2024-07-22 11:29:09 +12:00
rnauber
40e79299d5 Feature/m5angle8: Add support for m5angle8 input device (#6799)
Co-authored-by: Richard Nauber <richard@nauber.dev>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-22 09:57:59 +12:00
Markus
368662969e Move MQTT ip discovery to deticated config option. (#6673) 2024-07-22 09:36:46 +12:00
Lucio Tarantino
fbc830176f [heatpumpir] Fix BK72XX Compile error with IRremoteESP8266 (#6955) 2024-07-22 09:16:51 +12:00
Jesse Hills
cfb20abb9f [code-quality] Tidy up some duplicate CONFIG_SCHEMA assignments (#7106) 2024-07-21 20:09:06 +00:00
Jesse Hills
43b818f2b1 [validation] Add `host to require_framework_version` (#7107) 2024-07-22 07:54:16 +12:00
Kevin Ahrendt
32b927de7e revert bit shift to match previous behavior (#7109) 2024-07-20 07:15:11 +12:00
tomaszduda23
c5b77f4590 [web_server] move v1 code to separate file (#7091) 2024-07-19 16:35:41 +12:00
Jesse Hills
0fb89d1869 [code-quality] Add some ruff configuration (#7103) 2024-07-18 18:26:21 -05:00
Alex Cortelyou
b32078a5fe Prevent rename from deleting new config (#7104) 2024-07-19 10:04:11 +12:00
dependabot[bot]
dd20c5eab0 Bump docker/build-push-action from 6.4.0 to 6.4.1 in /.github/actions/build-image (#7102)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-18 15:33:30 +12:00
Jesse Hills
0ef73c6dd6 Merge branch 'release' into dev 2024-07-17 16:19:42 +12:00
Jesse Hills
de0e549187 Merge pull request #7100 from esphome/bump-2024.7.0
2024.7.0
2024-07-17 16:18:45 +12:00
Jesse Hills
e15d0ee150 Bump version to 2024.7.0 2024-07-17 14:54:44 +12:00
Jesse Hills
331d556799 Merge branch 'beta' into dev 2024-07-17 11:52:14 +12:00
Jesse Hills
93e0c71c2f Merge pull request #7099 from esphome/bump-2024.7.0b4
2024.7.0b4
2024-07-17 11:51:22 +12:00
Jesse Hills
c512d5ebb6 Bump version to 2024.7.0b4 2024-07-17 11:15:19 +12:00
Jesse Hills
f153a7b0fd [ota] Print Arduino update errors (#7096) 2024-07-17 11:15:19 +12:00
Clyde Stubbs
10205e06cb Add host uart support for MacOS (#7095) 2024-07-16 09:06:27 +00:00
Jesse Hills
aa490e3726 Merge branch 'beta' into dev 2024-07-16 19:49:21 +12:00
Jesse Hills
de43c4e6ab Merge pull request #7097 from esphome/bump-2024.7.0b3
2024.7.0b3
2024-07-16 19:48:37 +12:00
Jesse Hills
193db50668 [ota] Print Arduino update errors (#7096) 2024-07-16 02:18:43 -05:00
NewoPL
659fdefccb [wifi] Hostname may not be set as expected on Arduino platform (#7050)
* bug #6014: workaround for not setting hostname on arduino plarform

* moving handle initailisation to ESPHOME_EVENT_ID_WIFI_STA_START callback
2024-07-16 01:28:23 -05:00
tomaszduda23
8980996b1a [CI] add web_server v1 test (#7090) 2024-07-16 17:14:33 +12:00
dependabot[bot]
0b3fe73b74 Bump docker/build-push-action from 6.3.0 to 6.4.0 in /.github/actions/build-image (#7089)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-16 17:13:02 +12:00
Jesse Hills
4af8230b4f Bump version to 2024.7.0b3 2024-07-16 16:51:13 +12:00
Jesse Hills
0bbefb5b2a [micro_wake_word] Allow simpler model config (#7094) 2024-07-16 16:51:13 +12:00
Jesse Hills
41baf70660 [i2s_audio] Allow config for primary/secondary i2s mode (#7092) 2024-07-16 16:51:13 +12:00
Keith Burzinski
eaf2bb70d9 [improv_serial] Fix linker error created in #6998 (#7082) 2024-07-16 16:51:13 +12:00
Jesse Hills
c910fdf7e5 [micro_wake_word] Allow simpler model config (#7094) 2024-07-15 23:29:45 -05:00
Jesse Hills
f1d19416be [i2s_audio] Allow config for primary/secondary i2s mode (#7092) 2024-07-15 23:28:41 -05:00
Keith Burzinski
07b78fea76 [CI] Add more `improv_serial` tests (#7081)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-14 20:32:10 +00:00
Keith Burzinski
896af84acc [improv_serial] Fix linker error created in #6998 (#7082) 2024-07-15 08:06:10 +12:00
tomaszduda23
44d609b205 [CI] compile entire web_server during tests (#7084) 2024-07-15 08:05:02 +12:00
Jesse Hills
72cbfd8fea Merge branch 'beta' into dev 2024-07-13 15:24:43 +12:00
Jesse Hills
71236b170d Merge pull request #7079 from esphome/bump-2024.7.0b2
2024.7.0b2
2024-07-13 15:24:07 +12:00
Jesse Hills
bb92ab01d7 Bump version to 2024.7.0b2 2024-07-13 09:46:08 +12:00
Anton Viktorov
316a0e1c96 LTR390 separate ALS and UV gain and resolution (#7026)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-13 09:46:08 +12:00
H. Árkosi Róbert
0c2f9b9dbb Bump HeatpumpIR, add protocols, remove IRremoteESP8266 (#6996) 2024-07-13 09:46:08 +12:00
kevdliu
c6c1d3a3ad Fix voice assistant crash when no speaker configured (#7075) 2024-07-13 09:46:08 +12:00
Eugen
fbab0aceb0 add ESP32-C6 support to esp32_can (#7063) 2024-07-13 09:46:08 +12:00
Tomi Junnila
54b77a1174 Add support for the Gree YAC1FB9 in climate_ir (#7056) 2024-07-13 09:46:08 +12:00
leejoow
a34cec217e Add default icon to restart button (#7076)
Co-authored-by: Leo Schelvis <leo.schelvis@gmail.com>
2024-07-13 09:46:08 +12:00
Sergey Dudanov
91bb38553d [climate-traits] improved performance (#7006) 2024-07-13 09:46:08 +12:00
Sergey Dudanov
531f33a158 [climate] fix dump output of unsupported features (#7005) 2024-07-13 09:46:08 +12:00
ttaborda
2d826768b0 Update mitsubishi.cpp (#6909)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-13 09:46:07 +12:00
Colm
d7f6d4436e Add braces to if statement to avoid compiler warning. (#7036) 2024-07-13 09:46:07 +12:00
esphomebot
bdd0a36aa3 Update webserver local assets to 20240704-081526 (#7041) 2024-07-13 09:46:07 +12:00
Jimmy Hedman
8a89dac5d5 [ethernet] Fix compile warning for IPv6 (#7048) 2024-07-13 09:46:07 +12:00
guillempages
8d28c53fd3 [http_request] Fix follow_redirects on arduino (#7054) 2024-07-13 09:46:07 +12:00
Z3LIFF
114476d8b1 Fix pmsa003i cold boot marked as failed on ESP32 et al (#7064) 2024-07-13 09:46:07 +12:00
Christian Ferbar
d1bfad9890 helpers.cpp: Fix GLIBCXX_RELEASE check < 8 (#7062) 2024-07-13 09:46:07 +12:00
Anton Viktorov
feae794787 LTR390 separate ALS and UV gain and resolution (#7026)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-13 09:42:41 +12:00
H. Árkosi Róbert
8a3f0e3b93 Bump HeatpumpIR, add protocols, remove IRremoteESP8266 (#6996) 2024-07-13 09:19:33 +12:00
kevdliu
4a80a09db3 Fix voice assistant crash when no speaker configured (#7075) 2024-07-12 09:32:31 +12:00
soeffi
7f83bcfdd9 jsn_sr04t component: AJ_SR04M compatibility mode in checksum calculation (#7044)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-12 09:30:45 +12:00
Eugen
99cba0ae7f add ESP32-C6 support to esp32_can (#7063) 2024-07-12 09:26:04 +12:00
Tomi Junnila
2e8a2fdbd4 Add support for the Gree YAC1FB9 in climate_ir (#7056) 2024-07-12 08:32:38 +12:00
leejoow
d209a2b45a Add default icon to restart button (#7076)
Co-authored-by: Leo Schelvis <leo.schelvis@gmail.com>
2024-07-12 08:20:58 +12:00
Sergey Dudanov
d071b05249 [climate-traits] improved performance (#7006) 2024-07-11 17:24:36 +12:00
Sergey Dudanov
66b36afe90 [climate] fix dump output of unsupported features (#7005) 2024-07-11 17:23:29 +12:00
Jesse Hills
c6b81eff9a Merge branch 'beta' into dev 2024-07-11 16:31:47 +12:00
Jesse Hills
04b268e319 Merge pull request #7073 from esphome/bump-2024.7.0b1
2024.7.0b1
2024-07-11 16:31:07 +12:00
ttaborda
5ac875545f Update mitsubishi.cpp (#6909)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-07-11 16:26:37 +12:00
Keith Burzinski
6e624ff797 [wifi] Fix EAP for IDF 5.1+, add test (#7061) 2024-07-11 16:21:24 +12:00
Colm
08b8ab837a Add braces to if statement to avoid compiler warning. (#7036) 2024-07-11 16:10:58 +12:00
esphomebot
1b57d8511b Update webserver local assets to 20240704-081526 (#7041) 2024-07-11 16:10:18 +12:00
Jimmy Hedman
ee4d5178d6 [ethernet] Fix compile warning for IPv6 (#7048) 2024-07-11 16:09:51 +12:00
guillempages
dea1e9a1e0 [http_request] Fix follow_redirects on arduino (#7054) 2024-07-11 16:08:51 +12:00
Z3LIFF
fa4fbf9d73 Fix pmsa003i cold boot marked as failed on ESP32 et al (#7064) 2024-07-11 16:01:14 +12:00
Christian Ferbar
fb6c2aef59 helpers.cpp: Fix GLIBCXX_RELEASE check < 8 (#7062) 2024-07-11 15:58:54 +12:00
Jesse Hills
6417f1f907 Bump version to 2024.7.0b1 2024-07-11 15:41:48 +12:00
Jesse Hills
d1b0e6b5fe Bump version to 2024.8.0-dev 2024-07-11 15:41:48 +12:00
Jimmy Hedman
2f669c99f8 Configure ap ip for RP2040 (#7065) 2024-07-11 13:32:17 +12:00
Pavlo Dudnytskyi
aa8c963c50 UART component support added for host platform (#6912)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Pavlo Dudnytskyi <pdudnytskyi@astrata.eu>
2024-07-11 13:30:55 +12:00
Kevin Ahrendt
2873c6bbaf [micro_wake_word] Version 2 (#7032) 2024-07-11 13:21:04 +12:00
MichD
2da939c81c Fix RC Switch protocol not transmitting correctly via IR (#5411) 2024-07-11 10:37:50 +12:00
dependabot[bot]
ee398441b6 Bump actions/setup-python from 5.1.0 to 5.1.1 in /.github/actions/restore-python (#7071)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 23:21:11 +02:00
tomaszduda23
894d81c577 [CI] Allow running specific target test(s) only (#7051) 2024-07-08 21:07:54 -05:00
Colm
4c6a17e304 Don't test for IPv6 addresses when min_ipv6_addr_count is 0 (#7037) 2024-07-06 19:02:41 +12:00
Pavlo Dudnytskyi
ddaa84683b Haier component update to support more protocol variations (#7040)
Co-authored-by: Pavlo Dudnytskyi <pdudnytskyi@astrata.eu>
2024-07-06 19:00:44 +12:00
leejoow
dd1e480142 Fix display of update state in webinterfae (#7045)
Co-authored-by: Leo Schelvis <leo.schelvis@gmail.com>
2024-07-06 16:57:30 +12:00
dependabot[bot]
6ca7b30f75 Bump actions/download-artifact from 4.1.7 to 4.1.8 (#7046)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-06 16:23:47 +12:00
dependabot[bot]
b0a3b5e080 Bump actions/upload-artifact from 4.3.3 to 4.3.4 (#7047)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-06 16:23:37 +12:00
dependabot[bot]
5fa54b0885 Bump docker/setup-qemu-action from 3.0.0 to 3.1.0 (#7039)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-05 13:27:46 +12:00
dependabot[bot]
803f3f2e13 Bump docker/build-push-action from 6.2.0 to 6.3.0 in /.github/actions/build-image (#7038)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-05 11:31:50 +12:00
dependabot[bot]
de19588d10 Bump docker/setup-buildx-action from 3.3.0 to 3.4.0 (#7043)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-05 11:22:06 +12:00
Jesse Hills
bc2bc13eb1 Merge branch 'release' into dev 2024-07-03 21:04:14 +12:00
Jesse Hills
6c96281a1d Merge pull request #7035 from esphome/bump-2024.6.6
2024.6.6
2024-07-03 21:03:25 +12:00
Jesse Hills
3727342bce Bump version to 2024.6.6 2024-07-03 20:14:27 +12:00
Jesse Hills
fc3f806555 [docker] Fix docker build error fall through (#7021) 2024-07-03 20:14:27 +12:00
Jesse Hills
c013c3bf61 [docker] Bump versions inside armv7 block (#7022) 2024-07-03 20:14:27 +12:00
Jesse Hills
849a98d5b4 Bump dockerfile dependencies (#7017) 2024-07-03 20:14:27 +12:00
Jesse Hills
dd1a72e4d9 Merge branch 'release' into dev 2024-07-03 20:05:10 +12:00
Jesse Hills
e4e404d54f Merge pull request #7034 from esphome/bump-2024.6.5
2024.6.5
2024-07-03 20:04:18 +12:00
lhy
ee6f2bfecb Fix compile errors on ESP32-C6 with W5500 SPI ethernet (#7030) 2024-07-03 20:03:54 +12:00
Jesse Hills
995db1d0e1 Bump version to 2024.6.5 2024-07-03 15:45:30 +12:00
Jesse Hills
5cb80619dd [wifi] Only set default ttls phase 2 on esp-idf (#7033)
* [wifi] Only set default ttls phase 2 on esp-idf

* Add eap arduino test
2024-07-03 15:45:30 +12:00
Keith Burzinski
0914dc7198 Move some consts for #4585 (#7023) 2024-07-03 15:45:30 +12:00
Jesse Hills
12f00a9d3d [mpr121] await register parented (#7014)
fixes https://github.com/esphome/issues/issues/5913
2024-07-03 15:45:30 +12:00
Jesse Hills
3fb9c93a24 [wifi] Only set default ttls phase 2 on esp-idf (#7033)
* [wifi] Only set default ttls phase 2 on esp-idf

* Add eap arduino test
2024-07-03 02:21:41 +00:00
Jesse Hills
d8f0dce08f [uptime] Add new timestamp type for uptime sensor (#7029)
* [uptime] Add new timestamp type for uptime sensor

* Remove debug logs
2024-07-01 21:29:49 -05:00
Keith Burzinski
5e6c69b930 [CI] Update tests to run against IDF 5.1 (#7011) 2024-07-02 14:07:36 +12:00
Keith Burzinski
83f9664efb [CI] Run all tests when a base test changes (#7010) 2024-07-02 14:06:33 +12:00
Andreas Fritiofson
582386d3a2 Make crc8 const-correct (#7027) 2024-07-02 13:47:56 +12:00
Keith Burzinski
7aaa5ce9c8 Move some consts for #4585 (#7023) 2024-07-01 06:20:59 +00:00
Kevin P. Fleming
5278ae4b5e 'uart' and 'improv_serial' need to understand non-UART logger configurations (#6998) 2024-07-01 11:52:05 +12:00
Jesse Hills
b89dea97d9 [docker] Fix docker build error fall through (#7021) 2024-07-01 11:51:51 +12:00
Jesse Hills
715184070d [docker] Bump versions inside armv7 block (#7022) 2024-07-01 11:17:44 +12:00
orland0m
6294c3b913 Enable devcontainer linters (#7019) 2024-07-01 11:06:59 +12:00
Jesse Hills
e9cf3623d1 Bump dockerfile dependencies (#7017) 2024-07-01 08:54:04 +12:00
Jesse Hills
d0ab2a16a6 [mpr121] await register parented (#7014)
fixes https://github.com/esphome/issues/issues/5913
2024-06-28 21:12:59 -05:00
Jesse Hills
1f5442f1ba Merge branch 'release' into dev 2024-06-27 18:40:44 +12:00
Jesse Hills
dc4a93f5d0 Revert "[CI] Update tests to run against IDF 5.1" (#7003) 2024-06-27 17:15:02 +12:00
Keith Burzinski
e23153d090 [CI] Remove old test yaml files (#7002) 2024-06-27 02:34:39 +00:00
Sergey Dudanov
9a26cdb336 [modbus_text_sensor] new default ANSI encoding type (#6975) 2024-06-27 13:50:25 +12:00
Markus
decf50ed49 Fix LEDC 100% is not 100% duty with ESP32 IDF (#6997) 2024-06-27 13:48:01 +12:00
Simone Rossetto
bfdf63055f Allow wireguard to bind to PPP interface (#6989)
Co-authored-by: Tim Lunn <tl@smlight.tech>
2024-06-27 13:42:16 +12:00
Keith Burzinski
cd7894ae8f [ota-esphome] Merge configurations by port (#7001) 2024-06-27 13:07:07 +12:00
Christiaan de Ridder
10504c4d68 Tuya invalid command 0x22 (#6980) 2024-06-27 11:03:55 +12:00
dependabot[bot]
192718fee6 Bump docker/build-push-action from 6.1.0 to 6.2.0 in /.github/actions/build-image (#6999)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-27 10:55:42 +12:00
Keith Burzinski
855d154439 [CI] Update tests to run against IDF 5.1 (#6992) 2024-06-27 10:55:05 +12:00
Keith Burzinski
300d48a55e [CI] Remove old test yamls (#6991) 2024-06-27 10:54:17 +12:00
Keith Burzinski
7174cf35dd [CI] Add more mdns and safe_mode tests (#6990) 2024-06-27 10:53:29 +12:00
Jesse Hills
0b3145a6df Merge branch 'release' into dev 2024-06-26 23:26:58 +12:00
Sergey Dudanov
01bcf5fb97 [modbus-text-sensor] fix potential buffer overflow (#6993) 2024-06-26 22:38:11 +12:00
Samuel Sieb
91766afb64 [dallas_temp] fix ds18s20 temp calc (#6988) 2024-06-26 19:27:07 +12:00
Jesse Hills
5f1a08c922 Fix key 2024-06-26 13:31:38 +12:00
Jesse Hills
9567b45b30 Add more components 2024-06-26 13:29:59 +12:00
Jesse Hills
6d8afce3cd Disable all other CI flows 2024-06-26 13:20:56 +12:00
Jesse Hills
e0485894ca Try without changing component folder name 2024-06-26 13:20:46 +12:00
Petapton
cc4f1c667e Fix float encoding in modbus server (#6986) 2024-06-26 12:08:16 +12:00
Pieter Viljoen
bc26de2d68 [ds1307] Initialize uninitialized struct members (#6985) 2024-06-26 11:54:02 +12:00
Kevin P. Fleming
0179358f9c Improve 'body' handling in http_request on_response triggers (#6968) 2024-06-26 11:50:54 +12:00
Keith Burzinski
d8a5c1ea0c [ota-esphome] Validate for multiple esphome ota instances (#6984) 2024-06-25 20:57:15 +00:00
H. Árkosi Róbert
fb9844463b Bump HeatpumpIR and IRremoteESP8266 (#6948) 2024-06-25 21:08:57 +12:00
Jesse Hills
481cf7384a [safe_mode] Set safe mode core data in disabled cases (#6983) 2024-06-25 09:07:19 +00:00
Markus
c9a0daf4b6 Do not build mDNS when mDNS is disabled via yaml (#6979) 2024-06-25 20:05:37 +12:00
Jesse Hills
8a25bedaf9 [external_files] Move common `download_content function to external_files.py` (#6982) 2024-06-25 00:42:55 -05:00
Jesse Hills
11b8e2e1af [core] Add script to extract actions, conditions, and pin_providers (#6929) 2024-06-24 23:43:30 -05:00
Keith Burzinski
d5c008c027 Add audio_sal 2024-06-24 23:06:39 -05:00
Keith Burzinski
f72151ac9b Be more specific in idf_component.yml 2024-06-24 22:35:46 -05:00
Keith Burzinski
aa72db9db6 Be more specific in idf_component.yml 2024-06-24 21:22:27 -05:00
Jesse Hills
53cfa8d3a1 Merge branch 'release' into dev 2024-06-25 13:58:30 +12:00
Keith Burzinski
3773aa6f41 Add esp-adf to idf_component.yml 2024-06-24 20:38:01 -05:00
Keith Burzinski
abb812b9e1 Merge branch 'dev' into jesserockz-2023-284 2024-06-24 20:34:42 -05:00
Sergey Dudanov
78450da6f3 [midea] fix fan speed compatibility with some models (#6978) 2024-06-25 08:04:58 +12:00
Samuel Sieb
b1868123db fix potential hang (#6976)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-06-24 11:21:28 +00:00
Sergey Dudanov
f7af51b92c [haier] climate ID auto generation (#6949) 2024-06-24 18:22:07 +12:00
Brian Kaufman
7ee1406f64 Await cg.get_variable in Update component (#6974) 2024-06-24 04:54:30 +00:00
Gábor Poczkodi
0f49b58e0a [http_request] memory leak fix (#6973) 2024-06-24 16:32:20 +12:00
Samuel Sieb
17204baac0 allow template parameters (#6972) 2024-06-24 10:22:08 +12:00
Manuel Kasper
1e05bcaa61 [qspi_amoled] Fix clear/fill with rotation (#6960) 2024-06-23 01:10:22 +10:00
esphomebot
18690d51f5 Synchronise Device Classes from Home Assistant (#6966) 2024-06-22 13:27:47 +00:00
Samuel Sieb
2aacf14e96 Onewire (#6967)
* retry scan

* setup pin and log retries

* fix retries

* remove retries

---------

Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-06-22 11:57:27 +00:00
dependabot[bot]
9c5507ab46 Bump docker/build-push-action from 6.0.1 to 6.1.0 in /.github/actions/build-image (#6962)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-22 12:50:21 +02:00
Kevin P. Fleming
0a9703bff9 ESP-IDF 4.x expects seconds for esp_task_wdt_init(), not milliseconds. (#6964) 2024-06-21 21:28:11 +00:00
Kevin P. Fleming
67bd5db6d6 Fix infinite loop in http_request for ESP-IDF. (#6963) 2024-06-22 09:18:43 +12:00
Manuel Kasper
6c11f0bd51 [qspi_amoled] Fix display remaining blank after update() before setup completion (#6958) 2024-06-22 00:46:06 +10:00
Jesse Hills
e7556271e7 [update] Set entity_category to config & Publish state to logs (#6954) 2024-06-21 02:59:52 +00:00
Jesse Hills
8045b889d3 [core] Fix package merging with lists of primitives (#6952) 2024-06-20 20:09:00 -05:00
Jesse Hills
6f074d3692 [dooya] Flip bit timings (#6947) 2024-06-21 12:49:26 +12:00
Jesse Hills
b09781afa5 Merge branch 'release' into dev 2024-06-20 17:06:28 +12:00
Keith Burzinski
96f1a146a6 [CI] Add debug component test for LibreTiny (#6945) 2024-06-19 21:32:29 -05:00
Jesse Hills
775e03cfd9 Bump esphome-dashboard to 20240620.0 (#6944) 2024-06-20 02:12:38 +00:00
Cossid
80e5e19956 debug_libretiny - Fix typo (#6942) 2024-06-19 19:59:37 -05:00
Jesse Hills
8f16268572 Merge branch 'release' into dev 2024-06-20 08:27:35 +12:00
Jesse Hills
ba11f2ab0c Merge branch 'beta' into dev 2024-06-19 18:22:52 +12:00
Jesse Hills
8567877f07 [network] Default ipv6 to false to always set the flags (#6937)
* [network] Default ipv6 to false to always set the flags

* Separate tests for ipv6 disabled and enabled

* Forgot other platforms wouldnt have the variable in config
2024-06-18 22:09:16 -05:00
peter--s
310f850ee4 Update cover.h for open() and close() compiler warnings (#6936) 2024-06-19 13:28:03 +12:00
Manuel Kasper
896cdab22d Fix garbled graphics on LILYGO T4-S3 display (#6910) 2024-06-19 05:53:01 +10:00
dependabot[bot]
ed6462fa00 Bump docker/build-push-action from 6.0.0 to 6.0.1 in /.github/actions/build-image (#6934)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 07:38:50 +12:00
dependabot[bot]
65b05af014 Bump peter-evans/create-pull-request from 6.0.5 to 6.1.0 (#6935)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 07:38:31 +12:00
dependabot[bot]
c18056bdda Bump docker/build-push-action from 5.4.0 to 6.0.0 in /.github/actions/build-image (#6927)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 19:16:10 +12:00
dependabot[bot]
65a79acfb9 Bump pypa/gh-action-pypi-publish from 1.8.14 to 1.9.0 (#6926)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 16:44:20 +12:00
Jesse Hills
18d331d284 Merge branch 'beta' into dev 2024-06-18 16:14:38 +12:00
Faidon Liambotis
7d642147c1 uart: allow setting the UART id in final_validate_device_schema (#6923) 2024-06-18 14:22:50 +12:00
Jesse Hills
4c313bc198 Rename legacy/modern to ota/factory (#6922)
* Rename legacy/modern to ota/factory

* Add modern/legacy in brackets
2024-06-17 21:12:55 -05:00
Jesse Hills
a78b2d0128 [wifi] Fix some access point bugs related to esp-idf 4.4.7 (#6928)
* Set dhcp server range to only 10 IPs

* Change log level to errors to make it clearer

* We want to stop the dhcp server, not client
2024-06-17 20:07:43 -05:00
Keith Burzinski
f6848fe24d [CI] Introduce testing for IDF 5 (and other arbitrary framework versions) (#6802)
* Initial changes to support testing of additional framework versions

* Rename Arduino test files
2024-06-17 16:32:11 -05:00
Keith Burzinski
a59c9b4f77 [CI-esp32_hall] Remove IDF test (#6921) 2024-06-17 07:30:54 +00:00
Keith Burzinski
c30913ccde [CI-wireguard] Test file consolidation (#6920) 2024-06-17 07:23:24 +00:00
Keith Burzinski
41f810f828 [CI-http_request] Test fix for IDF 5+ (#6919) 2024-06-17 19:21:15 +12:00
Keith Burzinski
d604c8ae64 [CI-api] Test fix for IDF 5+ (#6918) 2024-06-17 07:18:04 +00:00
Keith Burzinski
67d8c7c691 [CI-a01nyub] Consolidate test files (#6917) 2024-06-17 07:14:19 +00:00
Keith Burzinski
015cd42a2e [CI-ethernet] Add/fix/organize/clean up ethernet component tests (#6916) 2024-06-17 07:06:25 +00:00
Giel van Schijndel
51c5d1714c fix(dallas): make recovery time for 1-bit equal to that of 0-bit (#6763) 2024-06-16 22:48:56 -07:00
Jesse Hills
1ff302b341 Merge branch 'beta' into dev 2024-06-17 16:29:58 +12:00
Jesse Hills
6b89763ad6 [mqtt] Fix datetime copy pasta (#6914) 2024-06-17 13:20:04 +12:00
Jesse Hills
253303f3a9 [ili9xxx] Fix init for GC9A01A (#6913) 2024-06-17 13:01:07 +12:00
Keith Burzinski
d49f2cbec8 IDF 5 fixes for #6802 (#6911) 2024-06-16 20:02:15 +12:00
Anton Viktorov
290816be11 VEML7700 Fix GCC build warnings (#6881) 2024-06-16 02:50:00 -05:00
Keith Burzinski
2fc43fa9c7 [micro_wake_word] Pin to esp-tflite-micro v1.3.1 (#6906) 2024-06-14 12:38:35 +12:00
Keith Burzinski
5adadeaa07 [esp32_camera] Use newer library version (for #6802) (#6809) 2024-06-13 10:42:08 +00:00
Keith Burzinski
761aae6f89 [CI] Allow clang-tidy to see IDF components (#6903)
* Allow clang-tidy to see IDF components

* Remove camera, add tflite-micro
2024-06-13 05:15:38 -05:00
esphomebot
b29e1acab8 Synchronise Device Classes from Home Assistant (#6904) 2024-06-13 19:24:36 +12:00
Jesse Hills
49d4260cfe Merge branch 'beta' into dev 2024-06-13 11:41:24 +12:00
Jesse Hills
c4c46c206f Bump esphome-dashboard to 20240613.0 (#6901) 2024-06-13 10:12:36 +12:00
dependabot[bot]
8453d9a70d Bump actions/checkout from 4.1.6 to 4.1.7 (#6900)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-13 09:27:15 +12:00
Oliver Hihn
68dbf35b09 X9C step delay with units (#6898) 2024-06-12 11:14:03 -07:00
Jesse Hills
1a242f94db [host] Execute host program when using run command (#6897) 2024-06-12 09:20:46 +00:00
Oliver Hihn
df52bc3493 Add step_delay option to X9C component (#6890) 2024-06-12 09:09:26 +00:00
Jesse Hills
2044c7e4d4 [CI] Fix for sdl (#6892) 2024-06-12 19:58:56 +12:00
Jesse Hills
b401b5eca8 [CI] Update device class sync script for update entities (#6895) 2024-06-12 19:36:57 +12:00
Jesse Hills
67f41a0c72 Merge branch 'beta' into dev 2024-06-12 19:34:22 +12:00
Jesse Hills
bd7e8fbf86 Bump version to 2024.7.0-dev 2024-06-12 14:16:43 +12:00
Jesse Hills
85a3789fb9 Fix i2s channel 2024-06-05 13:41:18 +12:00
Jesse Hills
b6f69cef56 Add min version requirement 2024-01-17 11:03:48 +09:00
Jesse Hills
219d704ce4 Use unique_ptr 2024-01-17 11:02:44 +09:00
Jesse Hills
14bc9b64bd Allocate speaker buffer in psram 2024-01-16 14:16:17 +09:00
Jesse Hills
dd7f56e502 Use RingBuffer class 2024-01-16 14:14:30 +09:00
Jesse Hills
c018ea0848 Fail if memory not allocated 2024-01-15 13:31:51 +09:00
Jesse Hills
317ee53188 Fix microphone read empty check 2024-01-11 09:51:06 +09:00
Jesse Hills
6e09f4b4d7 Send actual buffered byte count 2024-01-11 09:50:34 +09:00
Jesse Hills
709a92649c Remove unused algorithm stream code 2023-12-07 13:03:55 +09:00
Jesse Hills
78a8271797 Update esphome/components/esp_adf/__init__.py
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2023-11-29 12:00:01 +13:00
Jesse Hills
970680b1b2 Add has_buffered_data() function to ESPADFSpeaker class 2023-11-24 21:19:36 +13:00
Jesse Hills
f500bd5e6f Extend timeout to 500ms 2023-11-24 21:19:36 +13:00
Jesse Hills
e2bb81e233 Update esphome/components/esp_adf/microphone/esp_adf_microphone.cpp
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
2023-11-24 12:01:28 +13:00
Jesse Hills
26a1d14ee0 Add s3-box-3 board 2023-11-16 15:04:49 +13:00
Jesse Hills
97f07f8d13 Merge branch 'dev' into jesserockz-2023-284 2023-11-16 13:10:34 +13:00
Jesse Hills
ff9bffc363 Dont include when not using a supported board 2023-10-11 17:33:16 +13:00
Jesse Hills
89b3af8be4 Merge remote-tracking branch 'origin/dev' into jesserockz-2023-284 2023-10-11 16:32:26 +13:00
Jesse Hills
c9b2e54c1a Fix esp-adf init 2023-10-10 11:43:17 +13:00
Jesse Hills
6dd92053b5 Fix adf version 2023-10-05 12:18:46 +13:00
Jesse Hills
33346c0b6a Add back esp-dsp component.
Without this, esp-idf will auto download a version and may be incompatible
2023-10-04 13:37:21 +13:00
Jesse Hills
161fbecfe1 Allow esp-adf libraries to be used by any board 2023-09-29 09:57:05 +13:00
Jesse Hills
fce2eafda0 Allow manual overriding of esp-adf board 2023-09-13 11:49:27 +12:00
Jesse Hills
c19f0cf6bc Remove unused esp-dsp component 2023-09-11 16:07:19 +12:00
Jesse Hills
b05e7bfe0a Update flags 2023-09-11 16:07:09 +12:00
Jesse Hills
3e58ee2130 Allow patching esp-idf with esp-adf files 2023-09-01 10:13:00 +12:00
Jesse Hills
bab9c7c70e Remove afe and try to use algorithm stream 2023-08-31 17:38:49 +12:00
Jesse Hills
0b60a1d9eb Move microphone to use rtos task to read
Use afe_fr for noise suppression (not working)
2023-08-29 11:19:09 +12:00
Jesse Hills
f7455ad76a Fix ifdef 2023-08-24 17:18:52 +12:00
Jesse Hills
3190e86ba8 Dont warn when buffer is just empty 2023-08-24 17:02:50 +12:00
Jesse Hills
a34569d314 Merge branch 'dev' into jesserockz-2023-284 2023-08-23 14:31:19 +12:00
Jesse Hills
6c1c200cf9 Codeowners 2023-08-23 14:31:04 +12:00
Jesse Hills
3635179564 ESP-ADF microphone and speaker board support for s3-box 2023-08-11 07:53:34 +12:00
2522 changed files with 28483 additions and 19298 deletions

View File

@@ -1,7 +1,9 @@
{ {
"name": "ESPHome Dev", "name": "ESPHome Dev",
"image": "ghcr.io/esphome/esphome-lint:dev", "image": "ghcr.io/esphome/esphome-lint:dev",
"postCreateCommand": ["script/devcontainer-post-create"], "postCreateCommand": [
"script/devcontainer-post-create"
],
"containerEnv": { "containerEnv": {
"DEVCONTAINER": "1", "DEVCONTAINER": "1",
"PIP_BREAK_SYSTEM_PACKAGES": "1", "PIP_BREAK_SYSTEM_PACKAGES": "1",
@@ -27,6 +29,9 @@
"extensions": [ "extensions": [
// python // python
"ms-python.python", "ms-python.python",
"ms-python.pylint",
"ms-python.flake8",
"ms-python.black-formatter",
"visualstudioexptteam.vscodeintellicode", "visualstudioexptteam.vscodeintellicode",
// yaml // yaml
"redhat.vscode-yaml", "redhat.vscode-yaml",
@@ -38,9 +43,21 @@
"settings": { "settings": {
"python.languageServer": "Pylance", "python.languageServer": "Pylance",
"python.pythonPath": "/usr/bin/python3", "python.pythonPath": "/usr/bin/python3",
"python.linting.pylintEnabled": true, "pylint.args": [
"python.linting.enabled": true, "--rcfile=${workspaceFolder}/pyproject.toml"
"python.formatting.provider": "black", ],
"flake8.args": [
"--config=${workspaceFolder}/.flake8"
],
"black-formatter.args": [
"--config",
"${workspaceFolder}/pyproject.toml"
],
"[python]": {
// VS will say "Value is not accepted" before building the devcontainer, but the warning
// should go away after build is completed.
"editor.defaultFormatter": "ms-python.black-formatter"
},
"editor.formatOnPaste": false, "editor.formatOnPaste": false,
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.formatOnType": true, "editor.formatOnType": true,

View File

@@ -46,7 +46,10 @@ runs:
- name: Build and push to ghcr by digest - name: Build and push to ghcr by digest
id: build-ghcr id: build-ghcr
uses: docker/build-push-action@v6.0.1 uses: docker/build-push-action@v6.7.0
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
with: with:
context: . context: .
file: ./docker/Dockerfile file: ./docker/Dockerfile
@@ -69,7 +72,10 @@ runs:
- name: Build and push to dockerhub by digest - name: Build and push to dockerhub by digest
id: build-dockerhub id: build-dockerhub
uses: docker/build-push-action@v6.0.1 uses: docker/build-push-action@v6.7.0
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
with: with:
context: . context: .
file: ./docker/Dockerfile file: ./docker/Dockerfile

View File

@@ -17,7 +17,7 @@ runs:
steps: steps:
- name: Set up Python ${{ inputs.python-version }} - name: Set up Python ${{ inputs.python-version }}
id: python id: python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: ${{ inputs.python-version }} python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment - name: Restore Python virtual environment

View File

@@ -13,6 +13,13 @@ updates:
schedule: schedule:
interval: daily interval: daily
open-pull-requests-limit: 10 open-pull-requests-limit: 10
groups:
docker-actions:
applies-to: version-updates
patterns:
- "docker/setup-qemu-action"
- "docker/login-action"
- "docker/setup-buildx-action"
- package-ecosystem: github-actions - package-ecosystem: github-actions
directory: "/.github/actions/build-image" directory: "/.github/actions/build-image"
schedule: schedule:

View File

@@ -21,9 +21,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.11" python-version: "3.11"

View File

@@ -40,15 +40,15 @@ jobs:
arch: [amd64, armv7, aarch64] arch: [amd64, armv7, aarch64]
build_type: ["ha-addon", "docker", "lint"] build_type: ["ha-addon", "docker", "lint"]
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.9" python-version: "3.9"
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.3.0 uses: docker/setup-buildx-action@v3.6.1
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3.0.0 uses: docker/setup-qemu-action@v3.2.0
- name: Set TAG - name: Set TAG
run: | run: |

View File

@@ -9,6 +9,7 @@ on:
paths: paths:
- "**" - "**"
- "!.github/workflows/*.yml" - "!.github/workflows/*.yml"
- "!.github/actions/build-image/*"
- ".github/workflows/ci.yml" - ".github/workflows/ci.yml"
- "!.yamllint" - "!.yamllint"
- "!.github/dependabot.yml" - "!.github/dependabot.yml"
@@ -34,13 +35,13 @@ jobs:
cache-key: ${{ steps.cache-key.outputs.key }} cache-key: ${{ steps.cache-key.outputs.key }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Generate cache-key - name: Generate cache-key
id: cache-key id: cache-key
run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
- name: Set up Python ${{ env.DEFAULT_PYTHON }} - name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python id: python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment - name: Restore Python virtual environment
@@ -66,7 +67,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -87,7 +88,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -108,7 +109,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -129,7 +130,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -150,7 +151,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -199,7 +200,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -229,7 +230,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -248,72 +249,6 @@ jobs:
run: script/ci-suggest-changes run: script/ci-suggest-changes
if: always() if: always()
compile-tests-list:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Find all YAML test files
id: set-matrix
run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
validate-tests:
name: Validate YAML test ${{ matrix.file }}
runs-on: ubuntu-latest
needs:
- common
- compile-tests-list
strategy:
fail-fast: false
matrix:
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Run esphome config ${{ matrix.file }}
run: |
. venv/bin/activate
esphome config ${{ matrix.file }}
compile-tests:
name: Run YAML test ${{ matrix.file }}
runs-on: ubuntu-latest
needs:
- common
- black
- ci-custom
- clang-format
- flake8
- pylint
- pytest
- pyupgrade
- compile-tests-list
- validate-tests
strategy:
fail-fast: false
max-parallel: 2
matrix:
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Run esphome compile ${{ matrix.file }}
run: |
. venv/bin/activate
esphome compile ${{ matrix.file }}
clang-tidy: clang-tidy:
name: ${{ matrix.name }} name: ${{ matrix.name }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -358,7 +293,7 @@ jobs:
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -387,6 +322,13 @@ jobs:
echo "::add-matcher::.github/workflows/matchers/gcc.json" echo "::add-matcher::.github/workflows/matchers/gcc.json"
echo "::add-matcher::.github/workflows/matchers/clang-tidy.json" echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
- name: Run 'pio run --list-targets -e esp32-idf-tidy'
if: matrix.name == 'Run script/clang-tidy for ESP32 IDF'
run: |
. venv/bin/activate
mkdir -p .temp
pio run --list-targets -e esp32-idf-tidy
- name: Run clang-tidy - name: Run clang-tidy
run: | run: |
. venv/bin/activate . venv/bin/activate
@@ -410,7 +352,7 @@ jobs:
count: ${{ steps.list-components.outputs.count }} count: ${{ steps.list-components.outputs.count }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
with: with:
# Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works. # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
fetch-depth: 500 fetch-depth: 500
@@ -455,10 +397,10 @@ jobs:
file: ${{ fromJson(needs.list-components.outputs.components) }} file: ${{ fromJson(needs.list-components.outputs.components) }}
steps: steps:
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install libsodium-dev libsdl2-dev run: sudo apt-get install libsdl2-dev
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -484,7 +426,7 @@ jobs:
matrix: ${{ steps.split.outputs.components }} matrix: ${{ steps.split.outputs.components }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Split components into 20 groups - name: Split components into 20 groups
id: split id: split
run: | run: |
@@ -509,10 +451,10 @@ jobs:
run: echo ${{ matrix.components }} run: echo ${{ matrix.components }}
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install libsodium-dev libsdl2-dev run: sudo apt-get install libsdl2-dev
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -527,6 +469,8 @@ jobs:
- name: Compile config - name: Compile config
run: | run: |
. venv/bin/activate . venv/bin/activate
mkdir build_cache
export PLATFORMIO_BUILD_CACHE_DIR=$PWD/build_cache
for component in ${{ matrix.components }}; do for component in ${{ matrix.components }}; do
./script/test_build_components -e compile -c $component ./script/test_build_components -e compile -c $component
done done
@@ -543,7 +487,6 @@ jobs:
- pylint - pylint
- pytest - pytest
- pyupgrade - pyupgrade
- compile-tests
- clang-tidy - clang-tidy
- list-components - list-components
- test-build-components - test-build-components

View File

@@ -19,7 +19,7 @@ jobs:
tag: ${{ steps.tag.outputs.tag }} tag: ${{ steps.tag.outputs.tag }}
branch_build: ${{ steps.tag.outputs.branch_build }} branch_build: ${{ steps.tag.outputs.branch_build }}
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Get tag - name: Get tag
id: tag id: tag
# yamllint disable rule:line-length # yamllint disable rule:line-length
@@ -51,9 +51,9 @@ jobs:
contents: read contents: read
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- name: Set up python environment - name: Set up python environment
@@ -65,7 +65,7 @@ jobs:
pip3 install build pip3 install build
python3 -m build python3 -m build
- name: Publish - name: Publish
uses: pypa/gh-action-pypi-publish@v1.9.0 uses: pypa/gh-action-pypi-publish@v1.10.1
deploy-docker: deploy-docker:
name: Build ESPHome ${{ matrix.platform }} name: Build ESPHome ${{ matrix.platform }}
@@ -83,25 +83,25 @@ jobs:
- linux/arm/v7 - linux/arm/v7
- linux/arm64 - linux/arm64
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.9" python-version: "3.9"
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.3.0 uses: docker/setup-buildx-action@v3.6.1
- name: Set up QEMU - name: Set up QEMU
if: matrix.platform != 'linux/amd64' if: matrix.platform != 'linux/amd64'
uses: docker/setup-qemu-action@v3.0.0 uses: docker/setup-qemu-action@v3.2.0
- name: Log in to docker hub - name: Log in to docker hub
uses: docker/login-action@v3.2.0 uses: docker/login-action@v3.3.0
with: with:
username: ${{ secrets.DOCKER_USER }} username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry - name: Log in to the GitHub container registry
uses: docker/login-action@v3.2.0 uses: docker/login-action@v3.3.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
@@ -141,7 +141,7 @@ jobs:
echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT
- name: Upload digests - name: Upload digests
uses: actions/upload-artifact@v4.3.3 uses: actions/upload-artifact@v4.4.0
with: with:
name: digests-${{ steps.sanitize.outputs.name }} name: digests-${{ steps.sanitize.outputs.name }}
path: /tmp/digests path: /tmp/digests
@@ -174,27 +174,27 @@ jobs:
- ghcr - ghcr
- dockerhub - dockerhub
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Download digests - name: Download digests
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v4.1.8
with: with:
pattern: digests-* pattern: digests-*
path: /tmp/digests path: /tmp/digests
merge-multiple: true merge-multiple: true
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.3.0 uses: docker/setup-buildx-action@v3.6.1
- name: Log in to docker hub - name: Log in to docker hub
if: matrix.registry == 'dockerhub' if: matrix.registry == 'dockerhub'
uses: docker/login-action@v3.2.0 uses: docker/login-action@v3.3.0
with: with:
username: ${{ secrets.DOCKER_USER }} username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry - name: Log in to the GitHub container registry
if: matrix.registry == 'ghcr' if: matrix.registry == 'ghcr'
uses: docker/login-action@v3.2.0 uses: docker/login-action@v3.3.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}

View File

@@ -13,16 +13,16 @@ jobs:
if: github.repository == 'esphome/esphome' if: github.repository == 'esphome/esphome'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Checkout Home Assistant - name: Checkout Home Assistant
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
with: with:
repository: home-assistant/core repository: home-assistant/core
path: lib/home-assistant path: lib/home-assistant
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: 3.12 python-version: 3.12
@@ -36,7 +36,7 @@ jobs:
python ./script/sync-device_class.py python ./script/sync-device_class.py
- name: Commit changes - name: Commit changes
uses: peter-evans/create-pull-request@v6.0.5 uses: peter-evans/create-pull-request@v7.0.0
with: with:
commit-message: "Synchronise Device Classes from Home Assistant" commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@nabucasa.com> committer: esphomebot <esphome@nabucasa.com>

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- name: Run yamllint - name: Run yamllint
uses: frenck/action-yamllint@v1.5.0 uses: frenck/action-yamllint@v1.5.0
with: with:

2
.gitignore vendored
View File

@@ -138,3 +138,5 @@ sdkconfig.*
.tests/ .tests/
/components /components
/managed_components

View File

@@ -2,6 +2,15 @@
# See https://pre-commit.com for more information # See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks # See https://pre-commit.com/hooks.html for more hooks
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.5.4
hooks:
# Run the linter.
- id: ruff
args: [--fix]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2 rev: 24.4.2
hooks: hooks:

View File

@@ -37,6 +37,7 @@ esphome/components/am43/sensor/* @buxtronix
esphome/components/analog_threshold/* @ianchi esphome/components/analog_threshold/* @ianchi
esphome/components/animation/* @syndlex esphome/components/animation/* @syndlex
esphome/components/anova/* @buxtronix esphome/components/anova/* @buxtronix
esphome/components/apds9306/* @aodrenah
esphome/components/api/* @OttoWinter esphome/components/api/* @OttoWinter
esphome/components/as5600/* @ammmze esphome/components/as5600/* @ammmze
esphome/components/as5600/sensor/* @ammmze esphome/components/as5600/sensor/* @ammmze
@@ -45,6 +46,7 @@ esphome/components/async_tcp/* @OttoWinter
esphome/components/at581x/* @X-Ryl669 esphome/components/at581x/* @X-Ryl669
esphome/components/atc_mithermometer/* @ahpohl esphome/components/atc_mithermometer/* @ahpohl
esphome/components/atm90e26/* @danieltwagner esphome/components/atm90e26/* @danieltwagner
esphome/components/atm90e32/* @circuitsetup @descipher
esphome/components/b_parasite/* @rbaron esphome/components/b_parasite/* @rbaron
esphome/components/ballu/* @bazuchan esphome/components/ballu/* @bazuchan
esphome/components/bang_bang/* @OttoWinter esphome/components/bang_bang/* @OttoWinter
@@ -56,15 +58,21 @@ esphome/components/beken_spi_led_strip/* @Mat931
esphome/components/bh1750/* @OttoWinter esphome/components/bh1750/* @OttoWinter
esphome/components/binary_sensor/* @esphome/core esphome/components/binary_sensor/* @esphome/core
esphome/components/bk72xx/* @kuba2k2 esphome/components/bk72xx/* @kuba2k2
esphome/components/bl0906/* @athom-tech @jesserockz @tarontop
esphome/components/bl0939/* @ziceva esphome/components/bl0939/* @ziceva
esphome/components/bl0940/* @tobias- esphome/components/bl0940/* @tobias-
esphome/components/bl0942/* @dbuezas esphome/components/bl0942/* @dbuezas @dwmw2
esphome/components/ble_client/* @buxtronix @clydebarrow esphome/components/ble_client/* @buxtronix @clydebarrow
esphome/components/bluetooth_proxy/* @jesserockz esphome/components/bluetooth_proxy/* @jesserockz
esphome/components/bme280_base/* @esphome/core esphome/components/bme280_base/* @esphome/core
esphome/components/bme280_spi/* @apbodrov esphome/components/bme280_spi/* @apbodrov
esphome/components/bme680_bsec/* @trvrnrth esphome/components/bme680_bsec/* @trvrnrth
esphome/components/bme68x_bsec2/* @kbx81 @neffs
esphome/components/bme68x_bsec2_i2c/* @kbx81 @neffs
esphome/components/bmi160/* @flaviut esphome/components/bmi160/* @flaviut
esphome/components/bmp280_base/* @ademuri
esphome/components/bmp280_i2c/* @ademuri
esphome/components/bmp280_spi/* @ademuri
esphome/components/bmp3xx/* @latonita esphome/components/bmp3xx/* @latonita
esphome/components/bmp3xx_base/* @latonita @martgras esphome/components/bmp3xx_base/* @latonita @martgras
esphome/components/bmp3xx_i2c/* @latonita esphome/components/bmp3xx_i2c/* @latonita
@@ -78,6 +86,7 @@ esphome/components/cap1188/* @mreditor97
esphome/components/captive_portal/* @OttoWinter esphome/components/captive_portal/* @OttoWinter
esphome/components/ccs811/* @habbie esphome/components/ccs811/* @habbie
esphome/components/cd74hc4067/* @asoehlke esphome/components/cd74hc4067/* @asoehlke
esphome/components/ch422g/* @jesterret
esphome/components/climate/* @esphome/core esphome/components/climate/* @esphome/core
esphome/components/climate_ir/* @glmnet esphome/components/climate_ir/* @glmnet
esphome/components/color_temperature/* @jesserockz esphome/components/color_temperature/* @jesserockz
@@ -127,6 +136,7 @@ esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz esphome/components/esp32_rmt_led_strip/* @jesserockz
esphome/components/esp8266/* @esphome/core esphome/components/esp8266/* @esphome/core
esphome/components/esp_adf/* @jesserockz
esphome/components/ethernet_info/* @gtjadsonsantos esphome/components/ethernet_info/* @gtjadsonsantos
esphome/components/event/* @nohat esphome/components/event/* @nohat
esphome/components/exposure_notifications/* @OttoWinter esphome/components/exposure_notifications/* @OttoWinter
@@ -165,7 +175,10 @@ esphome/components/he60r/* @clydebarrow
esphome/components/heatpumpir/* @rob-deutsch esphome/components/heatpumpir/* @rob-deutsch
esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/hm3301/* @freekode esphome/components/hm3301/* @freekode
esphome/components/homeassistant/* @OttoWinter esphome/components/hmac_md5/* @dwmw2
esphome/components/homeassistant/* @OttoWinter @esphome/core
esphome/components/homeassistant/number/* @landonr
esphome/components/homeassistant/switch/* @Links2004
esphome/components/honeywell_hih_i2c/* @Benichou34 esphome/components/honeywell_hih_i2c/* @Benichou34
esphome/components/honeywellabp/* @RubyBailey esphome/components/honeywellabp/* @RubyBailey
esphome/components/honeywellabp2_i2c/* @jpfaff esphome/components/honeywellabp2_i2c/* @jpfaff
@@ -214,8 +227,11 @@ esphome/components/lightwaverf/* @max246
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
esphome/components/lock/* @esphome/core esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core esphome/components/logger/* @esphome/core
esphome/components/ltr390/* @sjtrny esphome/components/ltr390/* @latonita @sjtrny
esphome/components/ltr501/* @latonita
esphome/components/ltr_als_ps/* @latonita esphome/components/ltr_als_ps/* @latonita
esphome/components/lvgl/* @clydebarrow
esphome/components/m5stack_8angle/* @rnauber
esphome/components/matrix_keypad/* @ssieb esphome/components/matrix_keypad/* @ssieb
esphome/components/max31865/* @DAVe3283 esphome/components/max31865/* @DAVe3283
esphome/components/max44009/* @berfenger esphome/components/max44009/* @berfenger
@@ -273,6 +289,7 @@ esphome/components/nfc/* @jesserockz @kbx81
esphome/components/noblex/* @AGalfra esphome/components/noblex/* @AGalfra
esphome/components/number/* @esphome/core esphome/components/number/* @esphome/core
esphome/components/one_wire/* @ssieb esphome/components/one_wire/* @ssieb
esphome/components/online_image/* @guillempages
esphome/components/ota/* @esphome/core esphome/components/ota/* @esphome/core
esphome/components/output/* @esphome/core esphome/components/output/* @esphome/core
esphome/components/pca6416a/* @Mat931 esphome/components/pca6416a/* @Mat931
@@ -373,6 +390,7 @@ esphome/components/st7701s/* @clydebarrow
esphome/components/st7735/* @SenexCrenshaw esphome/components/st7735/* @SenexCrenshaw
esphome/components/st7789v/* @kbx81 esphome/components/st7789v/* @kbx81
esphome/components/st7920/* @marsjan155 esphome/components/st7920/* @marsjan155
esphome/components/statsd/* @Links2004
esphome/components/substitutions/* @esphome/core esphome/components/substitutions/* @esphome/core
esphome/components/sun/* @OttoWinter esphome/components/sun/* @OttoWinter
esphome/components/sun_gtil2/* @Mat931 esphome/components/sun_gtil2/* @Mat931
@@ -412,6 +430,7 @@ esphome/components/tuya/switch/* @jesserockz
esphome/components/tuya/text_sensor/* @dentra esphome/components/tuya/text_sensor/* @dentra
esphome/components/uart/* @esphome/core esphome/components/uart/* @esphome/core
esphome/components/uart/button/* @ssieb esphome/components/uart/button/* @ssieb
esphome/components/udp/* @clydebarrow
esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ec/* @pvizeli
esphome/components/ufire_ise/* @pvizeli esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter esphome/components/ultrasonic/* @OttoWinter
@@ -424,6 +443,7 @@ esphome/components/veml7700/* @latonita
esphome/components/version/* @esphome/core esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz esphome/components/voice_assistant/* @jesserockz
esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
esphome/components/watchdog/* @oarcher
esphome/components/waveshare_epaper/* @clydebarrow esphome/components/waveshare_epaper/* @clydebarrow
esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_base/* @OttoWinter
esphome/components/web_server_idf/* @dentra esphome/components/web_server_idf/* @dentra
@@ -446,6 +466,7 @@ esphome/components/wl_134/* @hobbypunk90
esphome/components/x9c/* @EtienneMD esphome/components/x9c/* @EtienneMD
esphome/components/xgzp68xx/* @gcormier esphome/components/xgzp68xx/* @gcormier
esphome/components/xiaomi_hhccjcy10/* @fariouche esphome/components/xiaomi_hhccjcy10/* @fariouche
esphome/components/xiaomi_lywsd02mmc/* @juanluss31
esphome/components/xiaomi_lywsd03mmc/* @ahpohl esphome/components/xiaomi_lywsd03mmc/* @ahpohl
esphome/components/xiaomi_mhoc303/* @drug123 esphome/components/xiaomi_mhoc303/* @drug123
esphome/components/xiaomi_mhoc401/* @vevsvevs esphome/components/xiaomi_mhoc401/* @vevsvevs

View File

@@ -34,28 +34,32 @@ RUN \
python3-wheel=0.38.4-2 \ python3-wheel=0.38.4-2 \
iputils-ping=3:20221126-1 \ iputils-ping=3:20221126-1 \
git=1:2.39.2-1.1 \ git=1:2.39.2-1.1 \
curl=7.88.1-10+deb12u5 \ curl=7.88.1-10+deb12u7 \
openssh-client=1:9.2p1-2+deb12u2 \ openssh-client=1:9.2p1-2+deb12u3 \
python3-cffi=1.15.1-5 \ python3-cffi=1.15.1-5 \
libcairo2=1.16.0-7 \ libcairo2=1.16.0-7 \
libmagic1=1:5.44-3 \ libmagic1=1:5.44-3 \
patch=2.7.6-7; \ patch=2.7.6-7 \
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ && ( \
apt-get install -y --no-install-recommends \ ( \
build-essential=12.9 \ [ "$TARGETARCH$TARGETVARIANT" = "armv7" ] && \
python3-dev=3.11.2-1+b1 \ apt-get install -y --no-install-recommends \
zlib1g-dev=1:1.2.13.dfsg-1 \ build-essential=12.9 \
libjpeg-dev=1:2.1.5-2 \ python3-dev=3.11.2-1+b1 \
libfreetype-dev=2.12.1+dfsg-5 \ zlib1g-dev=1:1.2.13.dfsg-1 \
libssl-dev=3.0.11-1~deb12u2 \ libjpeg-dev=1:2.1.5-2 \
libffi-dev=3.4.4-1 \ libfreetype-dev=2.12.1+dfsg-5+deb12u3 \
libopenjp2-7=2.5.0-2 \ libssl-dev=3.0.14-1~deb12u2 \
libtiff6=4.5.0-6+deb12u1 \ libffi-dev=3.4.4-1 \
cargo=0.66.0+ds1-1 \ libopenjp2-7=2.5.0-2 \
pkg-config=1.8.1-1 \ libtiff6=4.5.0-6+deb12u1 \
gcc-arm-linux-gnueabihf=4:12.2.0-3; \ cargo=0.66.0+ds1-1 \
fi; \ pkg-config=1.8.1-1 \
rm -rf \ gcc-arm-linux-gnueabihf=4:12.2.0-3 \
) \
|| [ "$TARGETARCH$TARGETVARIANT" != "armv7" ] \
) \
&& rm -rf \
/tmp/* \ /tmp/* \
/var/{cache,log}/* \ /var/{cache,log}/* \
/var/lib/apt/lists/* /var/lib/apt/lists/*
@@ -92,14 +96,19 @@ RUN \
# First install requirements to leverage caching when requirements don't change # First install requirements to leverage caching when requirements don't change
# tmpfs is for https://github.com/rust-lang/cargo/issues/8719 # tmpfs is for https://github.com/rust-lang/cargo/issues/8719
COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini / COPY requirements.txt requirements_optional.txt /
RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ curl -L https://www.piwheels.org/cp311/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl -o /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
&& pip3 install --break-system-packages --no-cache-dir /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
&& rm /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
&& export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \ fi; \
CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \ CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \
pip3 install \ pip3 install \
--break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt
&& /platformio_install_deps.py /platformio.ini --libraries
COPY script/platformio_install_deps.py platformio.ini /
RUN /platformio_install_deps.py /platformio.ini --libraries
# Avoid unsafe git error when container user and file config volume permissions don't match # Avoid unsafe git error when container user and file config volume permissions don't match
RUN git config --system --add safe.directory '*' RUN git config --system --add safe.directory '*'
@@ -190,8 +199,8 @@ RUN \
clang-format-13=1:13.0.1-11+b2 \ clang-format-13=1:13.0.1-11+b2 \
clang-tidy-14=1:14.0.6-12 \ clang-tidy-14=1:14.0.6-12 \
patch=2.7.6-7 \ patch=2.7.6-7 \
software-properties-common=0.99.30-4 \ software-properties-common=0.99.30-4.1~deb12u1 \
nano=7.2-1 \ nano=7.2-1+deb12u1 \
build-essential=12.9 \ build-essential=12.9 \
python3-dev=3.11.2-1+b1 \ python3-dev=3.11.2-1+b1 \
&& rm -rf \ && rm -rf \

View File

@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# If /cache is mounted, use that as PIO's coredir # If /cache is mounted, use that as PIO's coredir
# otherwise use path in /config (so that PIO packages aren't downloaded on each compile) # otherwise use path in /config (so that PIO packages aren't downloaded on each compile)

View File

@@ -1,12 +1,12 @@
# PYTHON_ARGCOMPLETE_OK # PYTHON_ARGCOMPLETE_OK
import argparse import argparse
from datetime import datetime
import functools import functools
import logging import logging
import os import os
import re import re
import sys import sys
import time import time
from datetime import datetime
import argcomplete import argcomplete
@@ -38,15 +38,15 @@ from esphome.const import (
SECRETS_FILES, SECRETS_FILES,
) )
from esphome.core import CORE, EsphomeError, coroutine from esphome.core import CORE, EsphomeError, coroutine
from esphome.helpers import indent, is_ip_address from esphome.helpers import indent, is_ip_address, get_bool_env
from esphome.log import Fore, color, setup_log
from esphome.util import ( from esphome.util import (
get_serial_ports,
list_yaml_files,
run_external_command, run_external_command,
run_external_process, run_external_process,
safe_print, safe_print,
list_yaml_files,
get_serial_ports,
) )
from esphome.log import color, setup_log, Fore
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -116,6 +116,7 @@ def get_port_type(port):
def run_miniterm(config, port): def run_miniterm(config, port):
import serial import serial
from esphome import platformio_api from esphome import platformio_api
if CONF_LOGGER not in config: if CONF_LOGGER not in config:
@@ -596,9 +597,10 @@ def command_update_all(args):
def command_idedata(args, config): def command_idedata(args, config):
from esphome import platformio_api
import json import json
from esphome import platformio_api
logging.disable(logging.INFO) logging.disable(logging.INFO)
logging.disable(logging.WARNING) logging.disable(logging.WARNING)
@@ -695,7 +697,8 @@ def command_rename(args, config):
os.remove(new_path) os.remove(new_path)
return 1 return 1
os.remove(CORE.config_path) if CORE.config_path != new_path:
os.remove(CORE.config_path)
print(color(Fore.BOLD_GREEN, "SUCCESS")) print(color(Fore.BOLD_GREEN, "SUCCESS"))
print() print()
@@ -728,7 +731,11 @@ POST_CONFIG_ACTIONS = {
def parse_args(argv): def parse_args(argv):
options_parser = argparse.ArgumentParser(add_help=False) options_parser = argparse.ArgumentParser(add_help=False)
options_parser.add_argument( options_parser.add_argument(
"-v", "--verbose", help="Enable verbose ESPHome logs.", action="store_true" "-v",
"--verbose",
help="Enable verbose ESPHome logs.",
action="store_true",
default=get_bool_env("ESPHOME_VERBOSE"),
) )
options_parser.add_argument( options_parser.add_argument(
"-q", "--quiet", help="Disable all ESPHome logs.", action="store_true" "-q", "--quiet", help="Disable all ESPHome logs.", action="store_true"
@@ -746,7 +753,14 @@ def parse_args(argv):
) )
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=f"ESPHome v{const.__version__}", parents=[options_parser] description=f"ESPHome {const.__version__}", parents=[options_parser]
)
parser.add_argument(
"--version",
action="version",
version=f"Version: {const.__version__}",
help="Print the ESPHome version and exit.",
) )
mqtt_options = argparse.ArgumentParser(add_help=False) mqtt_options = argparse.ArgumentParser(add_help=False)
@@ -947,67 +961,6 @@ def parse_args(argv):
# a deprecation warning). # a deprecation warning).
arguments = argv[1:] arguments = argv[1:]
# On Python 3.9+ we can simply set exit_on_error=False in the constructor
def _raise(x):
raise argparse.ArgumentError(None, x)
# First, try new-style parsing, but don't exit in case of failure
try:
# duplicate parser so that we can use the original one to raise errors later on
current_parser = argparse.ArgumentParser(add_help=False, parents=[parser])
current_parser.set_defaults(deprecated_argv_suggestion=None)
current_parser.error = _raise
return current_parser.parse_args(arguments)
except argparse.ArgumentError:
pass
# Second, try compat parsing and rearrange the command-line if it succeeds
# Disable argparse's built-in help option and add it manually to prevent this
# parser from printing the help messagefor the old format when invoked with -h.
compat_parser = argparse.ArgumentParser(parents=[options_parser], add_help=False)
compat_parser.add_argument("-h", "--help", action="store_true")
compat_parser.add_argument("configuration", nargs="*")
compat_parser.add_argument(
"command",
choices=[
"config",
"compile",
"upload",
"logs",
"run",
"clean-mqtt",
"wizard",
"mqtt-fingerprint",
"version",
"clean",
"dashboard",
"vscode",
"update-all",
],
)
try:
compat_parser.error = _raise
result, unparsed = compat_parser.parse_known_args(argv[1:])
last_option = len(arguments) - len(unparsed) - 1 - len(result.configuration)
unparsed = [
"--device" if arg in ("--upload-port", "--serial-port") else arg
for arg in unparsed
]
arguments = (
arguments[0:last_option]
+ [result.command]
+ result.configuration
+ unparsed
)
deprecated_argv_suggestion = arguments
except argparse.ArgumentError:
# old-style parsing failed, don't suggest any argument
deprecated_argv_suggestion = None
# Finally, run the new-style parser again with the possibly swapped arguments,
# and let it error out if the command is unparsable.
parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion)
argcomplete.autocomplete(parser) argcomplete.autocomplete(parser)
return parser.parse_args(arguments) return parser.parse_args(arguments)
@@ -1022,20 +975,6 @@ def run_esphome(argv):
# Show timestamp for dashboard access logs # Show timestamp for dashboard access logs
args.command == "dashboard", args.command == "dashboard",
) )
if args.deprecated_argv_suggestion is not None and args.command != "vscode":
_LOGGER.warning(
"Calling ESPHome with the configuration before the command is deprecated "
"and will be removed in the future. "
)
_LOGGER.warning("Please instead use:")
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
if sys.version_info < (3, 8, 0):
_LOGGER.error(
"You're running ESPHome with Python <3.8. ESPHome is no longer compatible "
"with this Python version. Please reinstall ESPHome with Python 3.8+"
)
return 1
if args.command in PRE_CONFIG_ACTIONS: if args.command in PRE_CONFIG_ACTIONS:
try: try:

View File

@@ -7,10 +7,10 @@ from esphome.const import (
CONF_ELSE, CONF_ELSE,
CONF_ID, CONF_ID,
CONF_THEN, CONF_THEN,
CONF_TIME,
CONF_TIMEOUT, CONF_TIMEOUT,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_TYPE_ID, CONF_TYPE_ID,
CONF_TIME,
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
) )
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor

View File

@@ -8,55 +8,78 @@
# want to break suddenly due to a rename (this file will get backports for features). # want to break suddenly due to a rename (this file will get backports for features).
# pylint: disable=unused-import # pylint: disable=unused-import
from esphome.cpp_generator import ( # noqa from esphome.cpp_generator import ( # noqa: F401
ArrayInitializer,
Expression, Expression,
LineComment,
MockObj,
MockObjClass,
Pvariable,
RawExpression, RawExpression,
RawStatement, RawStatement,
TemplateArguments,
StructInitializer,
ArrayInitializer,
safe_exp,
Statement, Statement,
LineComment, StructInitializer,
progmem_array, TemplateArguments,
static_const_array,
statement,
variable,
with_local_variable,
new_variable,
Pvariable,
new_Pvariable,
add, add,
add_global,
add_library,
add_build_flag, add_build_flag,
add_define, add_define,
add_global,
add_library,
add_platformio_option, add_platformio_option,
get_variable, get_variable,
get_variable_with_full_id, get_variable_with_full_id,
process_lambda,
is_template, is_template,
new_Pvariable,
new_variable,
process_lambda,
progmem_array,
safe_exp,
statement,
static_const_array,
templatable, templatable,
MockObj, variable,
MockObjClass, with_local_variable,
) )
from esphome.cpp_helpers import ( # noqa from esphome.cpp_helpers import ( # noqa: F401
gpio_pin_expression,
register_component,
build_registry_entry, build_registry_entry,
build_registry_list, build_registry_list,
extract_registry_entry_config, extract_registry_entry_config,
register_parented, gpio_pin_expression,
past_safe_mode, past_safe_mode,
register_component,
register_parented,
) )
from esphome.cpp_types import ( # noqa from esphome.cpp_types import ( # noqa: F401
global_ns, NAN,
void, App,
nullptr, Application,
float_, Component,
double, ComponentPtr,
Controller,
EntityBase,
EntityCategory,
ESPTime,
GPIOPin,
InternalGPIOPin,
JsonObject,
JsonObjectConst,
Parented,
PollingComponent,
arduino_json_ns,
bool_, bool_,
const_char_ptr,
double,
esphome_ns,
float_,
global_ns,
gpio_Flags,
int16,
int32,
int64,
int_, int_,
nullptr,
optional,
size_t,
std_ns, std_ns,
std_shared_ptr, std_shared_ptr,
std_string, std_string,
@@ -66,28 +89,5 @@ from esphome.cpp_types import ( # noqa
uint16, uint16,
uint32, uint32,
uint64, uint64,
int16, void,
int32,
int64,
size_t,
const_char_ptr,
NAN,
esphome_ns,
App,
EntityBase,
Component,
ComponentPtr,
PollingComponent,
Application,
optional,
arduino_json_ns,
JsonObject,
JsonObjectConst,
Controller,
GPIOPin,
InternalGPIOPin,
gpio_Flags,
EntityCategory,
Parented,
ESPTime,
) )

View File

@@ -1,5 +1,5 @@
import esphome.config_validation as cv import esphome.config_validation as cv
CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( CONFIG_SCHEMA = cv.invalid(
"The ade7953 sensor component has been renamed to ade7953_i2c." "The ade7953 sensor component has been renamed to ade7953_i2c."
) )

View File

@@ -60,7 +60,7 @@ bool AdE7953Spi::ade_read_16(uint16_t reg, uint16_t *value) {
this->write_byte16(reg); this->write_byte16(reg);
this->transfer_byte(0x80); this->transfer_byte(0x80);
uint8_t recv[2]; uint8_t recv[2];
this->read_array(recv, 4); this->read_array(recv, 2);
*value = encode_uint16(recv[0], recv[1]); *value = encode_uint16(recv[0], recv[1]);
this->disable(); this->disable();
return false; return false;

View File

@@ -93,8 +93,9 @@ void AHT10Component::restart_read_() {
void AHT10Component::read_data_() { void AHT10Component::read_data_() {
uint8_t data[6]; uint8_t data[6];
if (this->read_count_ > 1) if (this->read_count_ > 1) {
ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_)); ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_));
}
if (this->read(data, 6) != i2c::ERROR_OK) { if (this->read(data, 6) != i2c::ERROR_OK) {
this->status_set_warning("AHT10 read failed, retrying soon"); this->status_set_warning("AHT10 read failed, retrying soon");
this->restart_read_(); this->restart_read_();
@@ -119,8 +120,9 @@ void AHT10Component::read_data_() {
return; return;
} }
} }
if (this->read_count_ > 1) if (this->read_count_ > 1) {
ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_)); ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_));
}
uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4;

View File

@@ -14,8 +14,6 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) {
ESP_LOGD(TAG, "version = %d", value->version); ESP_LOGD(TAG, "version = %d", value->version);
if (value->version == 1) { if (value->version == 1) {
ESP_LOGD(TAG, "ambient light = %d", value->ambientLight);
if (this->humidity_sensor_ != nullptr) { if (this->humidity_sensor_ != nullptr) {
this->humidity_sensor_->publish_state(value->humidity / 2.0f); this->humidity_sensor_->publish_state(value->humidity / 2.0f);
} }
@@ -43,6 +41,10 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) {
if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) {
this->tvoc_sensor_->publish_state(value->voc); this->tvoc_sensor_->publish_state(value->voc);
} }
if (this->illuminance_sensor_ != nullptr) {
this->illuminance_sensor_->publish_state(value->ambientLight);
}
} else { } else {
ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version);
} }
@@ -68,6 +70,7 @@ void AirthingsWavePlus::dump_config() {
LOG_SENSOR(" ", "Radon", this->radon_sensor_); LOG_SENSOR(" ", "Radon", this->radon_sensor_);
LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_); LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_);
LOG_SENSOR(" ", "CO2", this->co2_sensor_); LOG_SENSOR(" ", "CO2", this->co2_sensor_);
LOG_SENSOR(" ", "Illuminance", this->illuminance_sensor_);
} }
AirthingsWavePlus::AirthingsWavePlus() { AirthingsWavePlus::AirthingsWavePlus() {

View File

@@ -22,6 +22,7 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; } void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; }
void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; }
void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; }
void set_illuminance(sensor::Sensor *illuminance) { illuminance_sensor_ = illuminance; }
protected: protected:
bool is_valid_radon_value_(uint16_t radon); bool is_valid_radon_value_(uint16_t radon);
@@ -32,6 +33,7 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
sensor::Sensor *radon_sensor_{nullptr}; sensor::Sensor *radon_sensor_{nullptr};
sensor::Sensor *radon_long_term_sensor_{nullptr}; sensor::Sensor *radon_long_term_sensor_{nullptr};
sensor::Sensor *co2_sensor_{nullptr}; sensor::Sensor *co2_sensor_{nullptr};
sensor::Sensor *illuminance_sensor_{nullptr};
struct WavePlusReadings { struct WavePlusReadings {
uint8_t version; uint8_t version;

View File

@@ -12,6 +12,9 @@ from esphome.const import (
CONF_CO2, CONF_CO2,
UNIT_BECQUEREL_PER_CUBIC_METER, UNIT_BECQUEREL_PER_CUBIC_METER,
UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_MILLION,
CONF_ILLUMINANCE,
UNIT_LUX,
DEVICE_CLASS_ILLUMINANCE,
) )
DEPENDENCIES = airthings_wave_base.DEPENDENCIES DEPENDENCIES = airthings_wave_base.DEPENDENCIES
@@ -45,6 +48,12 @@ CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend(
device_class=DEVICE_CLASS_CARBON_DIOXIDE, device_class=DEVICE_CLASS_CARBON_DIOXIDE,
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
), ),
cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema(
unit_of_measurement=UNIT_LUX,
accuracy_decimals=0,
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
),
} }
) )
@@ -62,3 +71,6 @@ async def to_code(config):
if config_co2 := config.get(CONF_CO2): if config_co2 := config.get(CONF_CO2):
sens = await sensor.new_sensor(config_co2) sens = await sensor.new_sensor(config_co2)
cg.add(var.set_co2(sens)) cg.add(var.set_co2(sens))
if config_illuminance := config.get(CONF_ILLUMINANCE):
sens = await sensor.new_sensor(config_illuminance)
cg.add(var.set_illuminance(sens))

View File

@@ -1,16 +1,17 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import web_server
from esphome import automation from esphome import automation
from esphome.automation import maybe_simple_id from esphome.automation import maybe_simple_id
from esphome.core import CORE, coroutine_with_priority import esphome.codegen as cg
from esphome.components import mqtt, web_server
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_CODE,
CONF_ID, CONF_ID,
CONF_MQTT_ID,
CONF_ON_STATE, CONF_ON_STATE,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_CODE,
CONF_WEB_SERVER_ID, CONF_WEB_SERVER_ID,
) )
from esphome.core import CORE, coroutine_with_priority
from esphome.cpp_helpers import setup_entity from esphome.cpp_helpers import setup_entity
CODEOWNERS = ["@grahambrown11", "@hwstar"] CODEOWNERS = ["@grahambrown11", "@hwstar"]
@@ -77,67 +78,72 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
"AlarmControlPanelCondition", automation.Condition "AlarmControlPanelCondition", automation.Condition
) )
ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( ALARM_CONTROL_PANEL_SCHEMA = (
web_server.WEBSERVER_SORTING_SCHEMA cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
).extend( .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
{ .extend(
cv.GenerateID(): cv.declare_id(AlarmControlPanel), {
cv.Optional(CONF_ON_STATE): automation.validate_automation( cv.GenerateID(): cv.declare_id(AlarmControlPanel),
{ cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), mqtt.MQTTAlarmControlPanelComponent
} ),
), cv.Optional(CONF_ON_STATE): automation.validate_automation(
cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger), }
} ),
), cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation(
cv.Optional(CONF_ON_ARMING): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger), }
} ),
), cv.Optional(CONF_ON_ARMING): automation.validate_automation(
cv.Optional(CONF_ON_PENDING): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger), }
} ),
), cv.Optional(CONF_ON_PENDING): automation.validate_automation(
cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger), }
} ),
), cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation(
cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger), }
} ),
), cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation(
cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger), }
} ),
), cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation(
cv.Optional(CONF_ON_DISARMED): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger), }
} ),
), cv.Optional(CONF_ON_DISARMED): automation.validate_automation(
cv.Optional(CONF_ON_CLEARED): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger), }
} ),
), cv.Optional(CONF_ON_CLEARED): automation.validate_automation(
cv.Optional(CONF_ON_CHIME): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChimeTrigger), }
} ),
), cv.Optional(CONF_ON_CHIME): automation.validate_automation(
cv.Optional(CONF_ON_READY): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChimeTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReadyTrigger), }
} ),
), cv.Optional(CONF_ON_READY): automation.validate_automation(
} {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReadyTrigger),
}
),
}
)
) )
ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id( ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id(
@@ -192,6 +198,9 @@ async def setup_alarm_control_panel_core_(var, config):
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None: if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id) web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config) web_server.add_entity_to_sorting_list(web_server_, var, config)
if mqtt_id := config.get(CONF_MQTT_ID):
mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config)
async def register_alarm_control_panel(var, config): async def register_alarm_control_panel(var, config):

View File

@@ -0,0 +1,4 @@
# Based on this datasheet:
# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
CODEOWNERS = ["@aodrenah"]

View File

@@ -0,0 +1,151 @@
// Based on this datasheet:
// https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
#include "apds9306.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace apds9306 {
static const char *const TAG = "apds9306";
enum { // APDS9306 registers
APDS9306_MAIN_CTRL = 0x00,
APDS9306_ALS_MEAS_RATE = 0x04,
APDS9306_ALS_GAIN = 0x05,
APDS9306_PART_ID = 0x06,
APDS9306_MAIN_STATUS = 0x07,
APDS9306_CLEAR_DATA_0 = 0x0A, // LSB
APDS9306_CLEAR_DATA_1 = 0x0B,
APDS9306_CLEAR_DATA_2 = 0x0C, // MSB
APDS9306_ALS_DATA_0 = 0x0D, // LSB
APDS9306_ALS_DATA_1 = 0x0E,
APDS9306_ALS_DATA_2 = 0x0F, // MSB
APDS9306_INT_CFG = 0x19,
APDS9306_INT_PERSISTENCE = 0x1A,
APDS9306_ALS_THRES_UP_0 = 0x21, // LSB
APDS9306_ALS_THRES_UP_1 = 0x22,
APDS9306_ALS_THRES_UP_2 = 0x23, // MSB
APDS9306_ALS_THRES_LOW_0 = 0x24, // LSB
APDS9306_ALS_THRES_LOW_1 = 0x25,
APDS9306_ALS_THRES_LOW_2 = 0x26, // MSB
APDS9306_ALS_THRES_VAR = 0x27
};
#define APDS9306_ERROR_CHECK(func, error) \
if (!(func)) { \
ESP_LOGE(TAG, error); \
this->mark_failed(); \
return; \
}
#define APDS9306_WARNING_CHECK(func, warning) \
if (!(func)) { \
ESP_LOGW(TAG, warning); \
this->status_set_warning(); \
return; \
}
#define APDS9306_WRITE_BYTE(reg, value) \
ESP_LOGV(TAG, "Writing 0x%02x to 0x%02x", value, reg); \
if (!this->write_byte(reg, value)) { \
ESP_LOGE(TAG, "Failed writing 0x%02x to 0x%02x", value, reg); \
this->mark_failed(); \
return; \
}
void APDS9306::setup() {
ESP_LOGCONFIG(TAG, "Setting up APDS9306...");
uint8_t id;
if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (id != 0xB1 && id != 0xB3) { // 0xB1 for APDS9306 0xB3 for APDS9306-065
this->error_code_ = WRONG_ID;
this->mark_failed();
return;
}
// ALS resolution and measurement, see datasheet or init.py for options
uint8_t als_meas_rate = ((this->bit_width_ & 0x07) << 4) | (this->measurement_rate_ & 0x07);
APDS9306_WRITE_BYTE(APDS9306_ALS_MEAS_RATE, als_meas_rate);
// ALS gain, see datasheet or init.py for options
uint8_t als_gain = (this->gain_ & 0x07);
APDS9306_WRITE_BYTE(APDS9306_ALS_GAIN, als_gain);
// Set to standby mode
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00);
// Check for data, clear main status
uint8_t status;
APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
// Set to active mode
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
ESP_LOGCONFIG(TAG, "APDS9306 setup complete");
}
void APDS9306::dump_config() {
LOG_SENSOR("", "APDS9306", this);
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Communication with APDS9306 failed!");
break;
case WRONG_ID:
ESP_LOGE(TAG, "APDS9306 has invalid id!");
break;
default:
ESP_LOGE(TAG, "Setting up APDS9306 registers failed!");
break;
}
}
ESP_LOGCONFIG(TAG, " Gain: %u", AMBIENT_LIGHT_GAIN_VALUES[this->gain_]);
ESP_LOGCONFIG(TAG, " Measurement rate: %u", MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
ESP_LOGCONFIG(TAG, " Measurement Resolution/Bit width: %d", MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]);
LOG_UPDATE_INTERVAL(this);
}
void APDS9306::update() {
// Check for new data
uint8_t status;
APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
this->status_clear_warning();
if (!(status &= 0b00001000)) { // No new data
return;
}
// Set to standby mode
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00);
// Clear MAIN STATUS
APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
uint8_t als_data[3];
APDS9306_WARNING_CHECK(this->read_bytes(APDS9306_ALS_DATA_0, als_data, 3), "Reading ALS data has failed.");
// Set to active mode
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
uint32_t light_level = 0x00 | encode_uint24(als_data[2], als_data[1], als_data[0]);
float lux = ((float) light_level / AMBIENT_LIGHT_GAIN_VALUES[this->gain_]) *
(100.0f / MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
ESP_LOGD(TAG, "Got illuminance=%.1flx from", lux);
this->publish_state(lux);
}
} // namespace apds9306
} // namespace esphome

View File

@@ -0,0 +1,66 @@
// Based on this datasheet:
// https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
#pragma once
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
namespace esphome {
namespace apds9306 {
enum MeasurementBitWidth : uint8_t {
MEASUREMENT_BIT_WIDTH_20 = 0,
MEASUREMENT_BIT_WIDTH_19 = 1,
MEASUREMENT_BIT_WIDTH_18 = 2,
MEASUREMENT_BIT_WIDTH_17 = 3,
MEASUREMENT_BIT_WIDTH_16 = 4,
MEASUREMENT_BIT_WIDTH_13 = 5,
};
static const uint8_t MEASUREMENT_BIT_WIDTH_VALUES[] = {20, 19, 18, 17, 16, 13};
enum MeasurementRate : uint8_t {
MEASUREMENT_RATE_25 = 0,
MEASUREMENT_RATE_50 = 1,
MEASUREMENT_RATE_100 = 2,
MEASUREMENT_RATE_200 = 3,
MEASUREMENT_RATE_500 = 4,
MEASUREMENT_RATE_1000 = 5,
MEASUREMENT_RATE_2000 = 6,
};
static const uint16_t MEASUREMENT_RATE_VALUES[] = {25, 50, 100, 200, 500, 1000, 2000};
enum AmbientLightGain : uint8_t {
AMBIENT_LIGHT_GAIN_1 = 0,
AMBIENT_LIGHT_GAIN_3 = 1,
AMBIENT_LIGHT_GAIN_6 = 2,
AMBIENT_LIGHT_GAIN_9 = 3,
AMBIENT_LIGHT_GAIN_18 = 4,
};
static const uint8_t AMBIENT_LIGHT_GAIN_VALUES[] = {1, 3, 6, 9, 18};
class APDS9306 : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
float get_setup_priority() const override { return setup_priority::BUS; }
void dump_config() override;
void update() override;
void set_bit_width(MeasurementBitWidth bit_width) { this->bit_width_ = bit_width; }
void set_measurement_rate(MeasurementRate measurement_rate) { this->measurement_rate_ = measurement_rate; }
void set_ambient_light_gain(AmbientLightGain gain) { this->gain_ = gain; }
protected:
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
WRONG_ID,
} error_code_{NONE};
MeasurementBitWidth bit_width_;
MeasurementRate measurement_rate_;
AmbientLightGain gain_;
};
} // namespace apds9306
} // namespace esphome

View File

@@ -0,0 +1,95 @@
# Based on this datasheet:
# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_GAIN,
DEVICE_CLASS_ILLUMINANCE,
ICON_LIGHTBULB,
STATE_CLASS_MEASUREMENT,
UNIT_LUX,
)
DEPENDENCIES = ["i2c"]
CONF_APDS9306_ID = "apds9306_id"
CONF_BIT_WIDTH = "bit_width"
CONF_MEASUREMENT_RATE = "measurement_rate"
apds9306_ns = cg.esphome_ns.namespace("apds9306")
APDS9306 = apds9306_ns.class_(
"APDS9306", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
)
MeasurementBitWidth = apds9306_ns.enum("MeasurementBitWidth")
MeasurementRate = apds9306_ns.enum("MeasurementRate")
AmbientLightGain = apds9306_ns.enum("AmbientLightGain")
MEASUREMENT_BIT_WIDTHS = {
20: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_20,
19: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_19,
18: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_18,
17: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_17,
16: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_16,
13: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_13,
}
MEASUREMENT_RATES = {
25: MeasurementRate.MEASUREMENT_RATE_25,
50: MeasurementRate.MEASUREMENT_RATE_50,
100: MeasurementRate.MEASUREMENT_RATE_100,
200: MeasurementRate.MEASUREMENT_RATE_200,
500: MeasurementRate.MEASUREMENT_RATE_500,
1000: MeasurementRate.MEASUREMENT_RATE_1000,
2000: MeasurementRate.MEASUREMENT_RATE_2000,
}
AMBIENT_LIGHT_GAINS = {
1: AmbientLightGain.AMBIENT_LIGHT_GAIN_1,
3: AmbientLightGain.AMBIENT_LIGHT_GAIN_3,
6: AmbientLightGain.AMBIENT_LIGHT_GAIN_6,
9: AmbientLightGain.AMBIENT_LIGHT_GAIN_9,
18: AmbientLightGain.AMBIENT_LIGHT_GAIN_18,
}
def _validate_measurement_rate(value):
value = cv.positive_time_period_milliseconds(value)
return cv.enum(MEASUREMENT_RATES, int=True)(value.total_milliseconds)
CONFIG_SCHEMA = (
sensor.sensor_schema(
APDS9306,
unit_of_measurement=UNIT_LUX,
accuracy_decimals=1,
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICON_LIGHTBULB,
)
.extend(
{
cv.Optional(CONF_GAIN, default="1"): cv.enum(AMBIENT_LIGHT_GAINS, int=True),
cv.Optional(CONF_BIT_WIDTH, default="18"): cv.enum(
MEASUREMENT_BIT_WIDTHS, int=True
),
cv.Optional(
CONF_MEASUREMENT_RATE, default="100ms"
): _validate_measurement_rate,
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x52))
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
cg.add(var.set_bit_width(config[CONF_BIT_WIDTH]))
cg.add(var.set_measurement_rate(config[CONF_MEASUREMENT_RATE]))
cg.add(var.set_ambient_light_gain(config[CONF_GAIN]))

View File

@@ -1,25 +1,27 @@
import base64 import base64
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation from esphome import automation
from esphome.automation import Condition from esphome.automation import Condition
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ACTION,
CONF_ACTIONS,
CONF_DATA, CONF_DATA,
CONF_DATA_TEMPLATE, CONF_DATA_TEMPLATE,
CONF_EVENT,
CONF_ID, CONF_ID,
CONF_KEY, CONF_KEY,
CONF_ON_CLIENT_CONNECTED,
CONF_ON_CLIENT_DISCONNECTED,
CONF_PASSWORD, CONF_PASSWORD,
CONF_PORT, CONF_PORT,
CONF_REBOOT_TIMEOUT, CONF_REBOOT_TIMEOUT,
CONF_SERVICE, CONF_SERVICE,
CONF_VARIABLES,
CONF_SERVICES, CONF_SERVICES,
CONF_TRIGGER_ID,
CONF_EVENT,
CONF_TAG, CONF_TAG,
CONF_ON_CLIENT_CONNECTED, CONF_TRIGGER_ID,
CONF_ON_CLIENT_DISCONNECTED, CONF_VARIABLES,
) )
from esphome.core import coroutine_with_priority from esphome.core import coroutine_with_priority
@@ -63,40 +65,51 @@ def validate_encryption_key(value):
return value return value
CONFIG_SCHEMA = cv.Schema( ACTIONS_SCHEMA = automation.validate_automation(
{ {
cv.GenerateID(): cv.declare_id(APIServer), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger),
cv.Optional(CONF_PORT, default=6053): cv.port, cv.Exclusive(CONF_SERVICE, group_of_exclusion=CONF_ACTION): cv.valid_name,
cv.Optional(CONF_PASSWORD, default=""): cv.string_strict, cv.Exclusive(CONF_ACTION, group_of_exclusion=CONF_ACTION): cv.valid_name,
cv.Optional( cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
CONF_REBOOT_TIMEOUT, default="15min"
): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SERVICES): automation.validate_automation(
{ {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger), cv.validate_id_name: cv.one_of(*SERVICE_ARG_NATIVE_TYPES, lower=True),
cv.Required(CONF_SERVICE): cv.valid_name,
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
{
cv.validate_id_name: cv.one_of(
*SERVICE_ARG_NATIVE_TYPES, lower=True
),
}
),
} }
), ),
cv.Optional(CONF_ENCRYPTION): cv.Schema( },
{ cv.All(
cv.Required(CONF_KEY): validate_encryption_key, cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION),
} cv.rename_key(CONF_SERVICE, CONF_ACTION),
), ),
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( )
single=True
), CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation( cv.Schema(
single=True {
), cv.GenerateID(): cv.declare_id(APIServer),
} cv.Optional(CONF_PORT, default=6053): cv.port,
).extend(cv.COMPONENT_SCHEMA) cv.Optional(CONF_PASSWORD, default=""): cv.string_strict,
cv.Optional(
CONF_REBOOT_TIMEOUT, default="15min"
): cv.positive_time_period_milliseconds,
cv.Exclusive(
CONF_SERVICES, group_of_exclusion=CONF_ACTIONS
): ACTIONS_SCHEMA,
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
cv.Optional(CONF_ENCRYPTION): cv.Schema(
{
cv.Required(CONF_KEY): validate_encryption_key,
}
),
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
single=True
),
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation(
single=True
),
}
).extend(cv.COMPONENT_SCHEMA),
cv.rename_key(CONF_SERVICES, CONF_ACTIONS),
)
@coroutine_with_priority(40.0) @coroutine_with_priority(40.0)
@@ -108,7 +121,7 @@ async def to_code(config):
cg.add(var.set_password(config[CONF_PASSWORD])) cg.add(var.set_password(config[CONF_PASSWORD]))
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
for conf in config.get(CONF_SERVICES, []): for conf in config.get(CONF_ACTIONS, []):
template_args = [] template_args = []
func_args = [] func_args = []
service_arg_names = [] service_arg_names = []
@@ -119,7 +132,7 @@ async def to_code(config):
service_arg_names.append(name) service_arg_names.append(name)
templ = cg.TemplateArguments(*template_args) templ = cg.TemplateArguments(*template_args)
trigger = cg.new_Pvariable( trigger = cg.new_Pvariable(
conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names
) )
cg.add(var.register_user_service(trigger)) cg.add(var.register_user_service(trigger))
await automation.build_automation(trigger, func_args, conf) await automation.build_automation(trigger, func_args, conf)
@@ -142,7 +155,7 @@ async def to_code(config):
decoded = base64.b64decode(encryption_config[CONF_KEY]) decoded = base64.b64decode(encryption_config[CONF_KEY])
cg.add(var.set_noise_psk(list(decoded))) cg.add(var.set_noise_psk(list(decoded)))
cg.add_define("USE_API_NOISE") cg.add_define("USE_API_NOISE")
cg.add_library("esphome/noise-c", "0.1.4") cg.add_library("esphome/noise-c", "0.1.6")
else: else:
cg.add_define("USE_API_PLAINTEXT") cg.add_define("USE_API_PLAINTEXT")
@@ -152,28 +165,43 @@ async def to_code(config):
KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string_strict)}) KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string_strict)})
HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema(
{ HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
cv.GenerateID(): cv.use_id(APIServer), cv.Schema(
cv.Required(CONF_SERVICE): cv.templatable(cv.string), {
cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA, cv.GenerateID(): cv.use_id(APIServer),
cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA, cv.Exclusive(CONF_SERVICE, group_of_exclusion=CONF_ACTION): cv.templatable(
cv.Optional(CONF_VARIABLES, default={}): cv.Schema( cv.string
{cv.string: cv.returning_lambda} ),
), cv.Exclusive(CONF_ACTION, group_of_exclusion=CONF_ACTION): cv.templatable(
} cv.string
),
cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA,
cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA,
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
{cv.string: cv.returning_lambda}
),
}
),
cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION),
cv.rename_key(CONF_SERVICE, CONF_ACTION),
) )
@automation.register_action(
"homeassistant.action",
HomeAssistantServiceCallAction,
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
)
@automation.register_action( @automation.register_action(
"homeassistant.service", "homeassistant.service",
HomeAssistantServiceCallAction, HomeAssistantServiceCallAction,
HOMEASSISTANT_SERVICE_ACTION_SCHEMA, HOMEASSISTANT_ACTION_ACTION_SCHEMA,
) )
async def homeassistant_service_to_code(config, action_id, template_arg, args): async def homeassistant_service_to_code(config, action_id, template_arg, args):
serv = await cg.get_variable(config[CONF_ID]) serv = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv, False) var = cg.new_Pvariable(action_id, template_arg, serv, False)
templ = await cg.templatable(config[CONF_SERVICE], args, None) templ = await cg.templatable(config[CONF_ACTION], args, None)
cg.add(var.set_service(templ)) cg.add(var.set_service(templ))
for key, value in config[CONF_DATA].items(): for key, value in config[CONF_DATA].items():
templ = await cg.templatable(value, args, None) templ = await cg.templatable(value, args, None)

View File

@@ -686,6 +686,7 @@ message SubscribeHomeAssistantStateResponse {
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
string entity_id = 1; string entity_id = 1;
string attribute = 2; string attribute = 2;
bool once = 3;
} }
message HomeAssistantStateResponse { message HomeAssistantStateResponse {
@@ -1106,6 +1107,18 @@ enum MediaPlayerCommand {
MEDIA_PLAYER_COMMAND_MUTE = 3; MEDIA_PLAYER_COMMAND_MUTE = 3;
MEDIA_PLAYER_COMMAND_UNMUTE = 4; MEDIA_PLAYER_COMMAND_UNMUTE = 4;
} }
enum MediaPlayerFormatPurpose {
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0;
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1;
}
message MediaPlayerSupportedFormat {
option (ifdef) = "USE_MEDIA_PLAYER";
string format = 1;
uint32 sample_rate = 2;
uint32 num_channels = 3;
MediaPlayerFormatPurpose purpose = 4;
}
message ListEntitiesMediaPlayerResponse { message ListEntitiesMediaPlayerResponse {
option (id) = 63; option (id) = 63;
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
@@ -1121,6 +1134,8 @@ message ListEntitiesMediaPlayerResponse {
EntityCategory entity_category = 7; EntityCategory entity_category = 7;
bool supports_pause = 8; bool supports_pause = 8;
repeated MediaPlayerSupportedFormat supported_formats = 9;
} }
message MediaPlayerStateResponse { message MediaPlayerStateResponse {
option (id) = 64; option (id) = 64;
@@ -1538,6 +1553,23 @@ message VoiceAssistantTimerEventResponse {
bool is_active = 6; bool is_active = 6;
} }
message VoiceAssistantAnnounceRequest {
option (id) = 119;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
string media_id = 1;
string text = 2;
}
message VoiceAssistantAnnounceFinished {
option (id) = 120;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_VOICE_ASSISTANT";
bool success = 1;
}
// ==================== ALARM CONTROL PANEL ==================== // ==================== ALARM CONTROL PANEL ====================
enum AlarmControlPanelState { enum AlarmControlPanelState {
ALARM_STATE_DISARMED = 0; ALARM_STATE_DISARMED = 0;
@@ -1872,6 +1904,11 @@ message UpdateStateResponse {
string release_summary = 9; string release_summary = 9;
string release_url = 10; string release_url = 10;
} }
enum UpdateCommand {
UPDATE_COMMAND_NONE = 0;
UPDATE_COMMAND_UPDATE = 1;
UPDATE_COMMAND_CHECK = 2;
}
message UpdateCommandRequest { message UpdateCommandRequest {
option (id) = 118; option (id) = 118;
option (source) = SOURCE_CLIENT; option (source) = SOURCE_CLIENT;
@@ -1879,5 +1916,5 @@ message UpdateCommandRequest {
option (no_delay) = true; option (no_delay) = true;
fixed32 key = 1; fixed32 key = 1;
bool install = 2; UpdateCommand command = 2;
} }

View File

@@ -179,6 +179,7 @@ void APIConnection::loop() {
SubscribeHomeAssistantStateResponse resp; SubscribeHomeAssistantStateResponse resp;
resp.entity_id = it.entity_id; resp.entity_id = it.entity_id;
resp.attribute = it.attribute.value(); resp.attribute = it.attribute.value();
resp.once = it.once;
if (this->send_subscribe_home_assistant_state_response(resp)) { if (this->send_subscribe_home_assistant_state_response(resp)) {
state_subs_at_++; state_subs_at_++;
} }
@@ -1025,6 +1026,15 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
auto traits = media_player->get_traits(); auto traits = media_player->get_traits();
msg.supports_pause = traits.get_supports_pause(); msg.supports_pause = traits.get_supports_pause();
for (auto &supported_format : traits.get_supported_formats()) {
MediaPlayerSupportedFormat media_format;
media_format.format = supported_format.format;
media_format.sample_rate = supported_format.sample_rate;
media_format.num_channels = supported_format.num_channels;
media_format.purpose = static_cast<enums::MediaPlayerFormatPurpose>(supported_format.purpose);
msg.supported_formats.push_back(media_format);
}
return this->send_list_entities_media_player_response(msg); return this->send_list_entities_media_player_response(msg);
} }
void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) { void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
@@ -1203,6 +1213,16 @@ void APIConnection::on_voice_assistant_timer_event_response(const VoiceAssistant
} }
}; };
void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) {
if (voice_assistant::global_voice_assistant != nullptr) {
if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
return;
}
voice_assistant::global_voice_assistant->on_announce(msg);
}
}
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
@@ -1328,7 +1348,20 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) {
if (update == nullptr) if (update == nullptr)
return; return;
update->perform(); switch (msg.command) {
case enums::UPDATE_COMMAND_UPDATE:
update->perform();
break;
case enums::UPDATE_COMMAND_CHECK:
update->check();
break;
case enums::UPDATE_COMMAND_NONE:
ESP_LOGE(TAG, "UPDATE_COMMAND_NONE not handled. Check client is sending the correct command");
break;
default:
ESP_LOGW(TAG, "Unknown update command: %" PRIu32, msg.command);
break;
}
} }
#endif #endif

View File

@@ -151,6 +151,7 @@ class APIConnection : public APIServerConnection {
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override;
void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override; void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override;
void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) override;
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL

View File

@@ -387,6 +387,18 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
} }
#endif #endif
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::MediaPlayerFormatPurpose>(enums::MediaPlayerFormatPurpose value) {
switch (value) {
case enums::MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT:
return "MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT";
case enums::MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT:
return "MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT";
default:
return "UNKNOWN";
}
}
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> template<>
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) { const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
switch (value) { switch (value) {
@@ -567,6 +579,20 @@ template<> const char *proto_enum_to_string<enums::ValveOperation>(enums::ValveO
} }
} }
#endif #endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::UpdateCommand>(enums::UpdateCommand value) {
switch (value) {
case enums::UPDATE_COMMAND_NONE:
return "UPDATE_COMMAND_NONE";
case enums::UPDATE_COMMAND_UPDATE:
return "UPDATE_COMMAND_UPDATE";
case enums::UPDATE_COMMAND_CHECK:
return "UPDATE_COMMAND_CHECK";
default:
return "UNKNOWN";
}
}
#endif
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 2: { case 2: {
@@ -3095,6 +3121,16 @@ void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const {
out.append("SubscribeHomeAssistantStatesRequest {}"); out.append("SubscribeHomeAssistantStatesRequest {}");
} }
#endif #endif
bool SubscribeHomeAssistantStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 3: {
this->once = value.as_bool();
return true;
}
default:
return false;
}
}
bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) { switch (field_id) {
case 1: { case 1: {
@@ -3112,6 +3148,7 @@ bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, Proto
void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const { void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->entity_id); buffer.encode_string(1, this->entity_id);
buffer.encode_string(2, this->attribute); buffer.encode_string(2, this->attribute);
buffer.encode_bool(3, this->once);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
@@ -3124,6 +3161,10 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
out.append(" attribute: "); out.append(" attribute: ");
out.append("'").append(this->attribute).append("'"); out.append("'").append(this->attribute).append("'");
out.append("\n"); out.append("\n");
out.append(" once: ");
out.append(YESNO(this->once));
out.append("\n");
out.append("}"); out.append("}");
} }
#endif #endif
@@ -5094,6 +5135,64 @@ void ButtonCommandRequest::dump_to(std::string &out) const {
out.append("}"); out.append("}");
} }
#endif #endif
bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->sample_rate = value.as_uint32();
return true;
}
case 3: {
this->num_channels = value.as_uint32();
return true;
}
case 4: {
this->purpose = value.as_enum<enums::MediaPlayerFormatPurpose>();
return true;
}
default:
return false;
}
}
bool MediaPlayerSupportedFormat::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->format = value.as_string();
return true;
}
default:
return false;
}
}
void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->format);
buffer.encode_uint32(2, this->sample_rate);
buffer.encode_uint32(3, this->num_channels);
buffer.encode_enum<enums::MediaPlayerFormatPurpose>(4, this->purpose);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void MediaPlayerSupportedFormat::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("MediaPlayerSupportedFormat {\n");
out.append(" format: ");
out.append("'").append(this->format).append("'");
out.append("\n");
out.append(" sample_rate: ");
sprintf(buffer, "%" PRIu32, this->sample_rate);
out.append(buffer);
out.append("\n");
out.append(" num_channels: ");
sprintf(buffer, "%" PRIu32, this->num_channels);
out.append(buffer);
out.append("\n");
out.append(" purpose: ");
out.append(proto_enum_to_string<enums::MediaPlayerFormatPurpose>(this->purpose));
out.append("\n");
out.append("}");
}
#endif
bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 6: { case 6: {
@@ -5130,6 +5229,10 @@ bool ListEntitiesMediaPlayerResponse::decode_length(uint32_t field_id, ProtoLeng
this->icon = value.as_string(); this->icon = value.as_string();
return true; return true;
} }
case 9: {
this->supported_formats.push_back(value.as_message<MediaPlayerSupportedFormat>());
return true;
}
default: default:
return false; return false;
} }
@@ -5153,6 +5256,9 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(6, this->disabled_by_default); buffer.encode_bool(6, this->disabled_by_default);
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category); buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
buffer.encode_bool(8, this->supports_pause); buffer.encode_bool(8, this->supports_pause);
for (auto &it : this->supported_formats) {
buffer.encode_message<MediaPlayerSupportedFormat>(9, it, true);
}
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
@@ -5190,6 +5296,12 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
out.append(" supports_pause: "); out.append(" supports_pause: ");
out.append(YESNO(this->supports_pause)); out.append(YESNO(this->supports_pause));
out.append("\n"); out.append("\n");
for (const auto &it : this->supported_formats) {
out.append(" supported_formats: ");
it.dump_to(out);
out.append("\n");
}
out.append("}"); out.append("}");
} }
#endif #endif
@@ -6949,6 +7061,59 @@ void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
out.append("}"); out.append("}");
} }
#endif #endif
bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->media_id = value.as_string();
return true;
}
case 2: {
this->text = value.as_string();
return true;
}
default:
return false;
}
}
void VoiceAssistantAnnounceRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->media_id);
buffer.encode_string(2, this->text);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantAnnounceRequest {\n");
out.append(" media_id: ");
out.append("'").append(this->media_id).append("'");
out.append("\n");
out.append(" text: ");
out.append("'").append(this->text).append("'");
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantAnnounceFinished::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->success = value.as_bool();
return true;
}
default:
return false;
}
}
void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->success); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantAnnounceFinished {\n");
out.append(" success: ");
out.append(YESNO(this->success));
out.append("\n");
out.append("}");
}
#endif
bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 6: { case 6: {
@@ -8596,7 +8761,7 @@ void UpdateStateResponse::dump_to(std::string &out) const {
bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 2: { case 2: {
this->install = value.as_bool(); this->command = value.as_enum<enums::UpdateCommand>();
return true; return true;
} }
default: default:
@@ -8615,7 +8780,7 @@ bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
} }
void UpdateCommandRequest::encode(ProtoWriteBuffer buffer) const { void UpdateCommandRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key); buffer.encode_fixed32(1, this->key);
buffer.encode_bool(2, this->install); buffer.encode_enum<enums::UpdateCommand>(2, this->command);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void UpdateCommandRequest::dump_to(std::string &out) const { void UpdateCommandRequest::dump_to(std::string &out) const {
@@ -8626,8 +8791,8 @@ void UpdateCommandRequest::dump_to(std::string &out) const {
out.append(buffer); out.append(buffer);
out.append("\n"); out.append("\n");
out.append(" install: "); out.append(" command: ");
out.append(YESNO(this->install)); out.append(proto_enum_to_string<enums::UpdateCommand>(this->command));
out.append("\n"); out.append("\n");
out.append("}"); out.append("}");
} }

View File

@@ -156,6 +156,10 @@ enum MediaPlayerCommand : uint32_t {
MEDIA_PLAYER_COMMAND_MUTE = 3, MEDIA_PLAYER_COMMAND_MUTE = 3,
MEDIA_PLAYER_COMMAND_UNMUTE = 4, MEDIA_PLAYER_COMMAND_UNMUTE = 4,
}; };
enum MediaPlayerFormatPurpose : uint32_t {
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0,
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1,
};
enum BluetoothDeviceRequestType : uint32_t { enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1, BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
@@ -227,6 +231,11 @@ enum ValveOperation : uint32_t {
VALVE_OPERATION_IS_OPENING = 1, VALVE_OPERATION_IS_OPENING = 1,
VALVE_OPERATION_IS_CLOSING = 2, VALVE_OPERATION_IS_CLOSING = 2,
}; };
enum UpdateCommand : uint32_t {
UPDATE_COMMAND_NONE = 0,
UPDATE_COMMAND_UPDATE = 1,
UPDATE_COMMAND_CHECK = 2,
};
} // namespace enums } // namespace enums
@@ -831,6 +840,7 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage {
public: public:
std::string entity_id{}; std::string entity_id{};
std::string attribute{}; std::string attribute{};
bool once{false};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
@@ -838,6 +848,7 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage {
protected: protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
class HomeAssistantStateResponse : public ProtoMessage { class HomeAssistantStateResponse : public ProtoMessage {
public: public:
@@ -1260,6 +1271,21 @@ class ButtonCommandRequest : public ProtoMessage {
protected: protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
}; };
class MediaPlayerSupportedFormat : public ProtoMessage {
public:
std::string format{};
uint32_t sample_rate{0};
uint32_t num_channels{0};
enums::MediaPlayerFormatPurpose purpose{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class ListEntitiesMediaPlayerResponse : public ProtoMessage { class ListEntitiesMediaPlayerResponse : public ProtoMessage {
public: public:
std::string object_id{}; std::string object_id{};
@@ -1270,6 +1296,7 @@ class ListEntitiesMediaPlayerResponse : public ProtoMessage {
bool disabled_by_default{false}; bool disabled_by_default{false};
enums::EntityCategory entity_category{}; enums::EntityCategory entity_category{};
bool supports_pause{false}; bool supports_pause{false};
std::vector<MediaPlayerSupportedFormat> supported_formats{};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
@@ -1798,6 +1825,29 @@ class VoiceAssistantTimerEventResponse : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
class VoiceAssistantAnnounceRequest : public ProtoMessage {
public:
std::string media_id{};
std::string text{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class VoiceAssistantAnnounceFinished : public ProtoMessage {
public:
bool success{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class ListEntitiesAlarmControlPanelResponse : public ProtoMessage { class ListEntitiesAlarmControlPanelResponse : public ProtoMessage {
public: public:
std::string object_id{}; std::string object_id{};
@@ -2175,7 +2225,7 @@ class UpdateStateResponse : public ProtoMessage {
class UpdateCommandRequest : public ProtoMessage { class UpdateCommandRequest : public ProtoMessage {
public: public:
uint32_t key{0}; uint32_t key{0};
bool install{false}; enums::UpdateCommand command{};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;

View File

@@ -486,6 +486,16 @@ bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAud
#endif #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
#endif #endif
#ifdef USE_VOICE_ASSISTANT
#endif
#ifdef USE_VOICE_ASSISTANT
bool APIServerConnectionBase::send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_voice_assistant_announce_finished: %s", msg.dump().c_str());
#endif
return this->send_message_<VoiceAssistantAnnounceFinished>(msg, 120);
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response( bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response(
const ListEntitiesAlarmControlPanelResponse &msg) { const ListEntitiesAlarmControlPanelResponse &msg) {
@@ -1135,6 +1145,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_update_command_request(msg); this->on_update_command_request(msg);
#endif
break;
}
case 119: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantAnnounceRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_announce_request(msg);
#endif #endif
break; break;
} }

View File

@@ -247,6 +247,12 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){}; virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){};
#endif #endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &value){};
#endif
#ifdef USE_VOICE_ASSISTANT
bool send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg);
#endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg); bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg);
#endif #endif

View File

@@ -359,8 +359,18 @@ void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<s
.entity_id = std::move(entity_id), .entity_id = std::move(entity_id),
.attribute = std::move(attribute), .attribute = std::move(attribute),
.callback = std::move(f), .callback = std::move(f),
.once = false,
}); });
} }
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f) {
this->state_subs_.push_back(HomeAssistantStateSubscription{
.entity_id = std::move(entity_id),
.attribute = std::move(attribute),
.callback = std::move(f),
.once = true,
});
};
const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const { const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
return this->state_subs_; return this->state_subs_;
} }

View File

@@ -112,10 +112,13 @@ class APIServer : public Component, public Controller {
std::string entity_id; std::string entity_id;
optional<std::string> attribute; optional<std::string> attribute;
std::function<void(std::string)> callback; std::function<void(std::string)> callback;
bool once;
}; };
void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute, void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f); std::function<void(std::string)> f);
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f);
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const; const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; } const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }

View File

@@ -1,13 +1,13 @@
# Dummy integration to allow relying on AsyncTCP # Dummy integration to allow relying on AsyncTCP
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import CORE, coroutine_with_priority
from esphome.const import ( from esphome.const import (
PLATFORM_BK72XX,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
) )
from esphome.core import CORE, coroutine_with_priority
CODEOWNERS = ["@OttoWinter"] CODEOWNERS = ["@OttoWinter"]
@@ -22,7 +22,7 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config): async def to_code(config):
if CORE.is_esp32 or CORE.is_libretiny: if CORE.is_esp32 or CORE.is_libretiny:
# https://github.com/esphome/AsyncTCP/blob/master/library.json # https://github.com/esphome/AsyncTCP/blob/master/library.json
cg.add_library("esphome/AsyncTCP-esphome", "2.1.3") cg.add_library("esphome/AsyncTCP-esphome", "2.1.4")
elif CORE.is_esp8266: elif CORE.is_esp8266:
# https://github.com/esphome/ESPAsyncTCP # https://github.com/esphome/ESPAsyncTCP
cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0") cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0")

View File

@@ -1,34 +1,34 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, spi from esphome.components import sensor, spi
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ID,
CONF_REACTIVE_POWER,
CONF_VOLTAGE,
CONF_CURRENT, CONF_CURRENT,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_FREQUENCY,
CONF_ID,
CONF_LINE_FREQUENCY,
CONF_POWER, CONF_POWER,
CONF_POWER_FACTOR, CONF_POWER_FACTOR,
CONF_FREQUENCY, CONF_REACTIVE_POWER,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_REVERSE_ACTIVE_ENERGY, CONF_REVERSE_ACTIVE_ENERGY,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT, DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER, DEVICE_CLASS_POWER,
DEVICE_CLASS_POWER_FACTOR, DEVICE_CLASS_POWER_FACTOR,
DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLTAGE,
ICON_LIGHTBULB,
ICON_CURRENT_AC, ICON_CURRENT_AC,
ICON_LIGHTBULB,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING, STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_HERTZ, UNIT_HERTZ,
UNIT_VOLT, UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
UNIT_VOLT_AMPS_REACTIVE, UNIT_VOLT_AMPS_REACTIVE,
UNIT_WATT,
UNIT_WATT_HOURS, UNIT_WATT_HOURS,
) )
CONF_LINE_FREQUENCY = "line_frequency"
CONF_METER_CONSTANT = "meter_constant" CONF_METER_CONSTANT = "meter_constant"
CONF_PL_CONST = "pl_const" CONF_PL_CONST = "pl_const"
CONF_GAIN_PGA = "gain_pga" CONF_GAIN_PGA = "gain_pga"

View File

@@ -0,0 +1,7 @@
import esphome.codegen as cg
CODEOWNERS = ["@circuitsetup", "@descipher"]
atm90e32_ns = cg.esphome_ns.namespace("atm90e32")
CONF_ATM90E32_ID = "atm90e32_id"

View File

@@ -132,10 +132,77 @@ void ATM90E32Component::update() {
this->status_clear_warning(); this->status_clear_warning();
} }
void ATM90E32Component::restore_calibrations_() {
if (enable_offset_calibration_) {
this->pref_.load(&this->offset_phase_);
}
};
void ATM90E32Component::run_offset_calibrations() {
// Run the calibrations and
// Setup voltage and current calibration offsets for PHASE A
this->offset_phase_[PHASEA].voltage_offset_ = calibrate_voltage_offset_phase(PHASEA);
this->phase_[PHASEA].voltage_offset_ = this->offset_phase_[PHASEA].voltage_offset_;
this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // C Voltage offset
this->offset_phase_[PHASEA].current_offset_ = calibrate_current_offset_phase(PHASEA);
this->phase_[PHASEA].current_offset_ = this->offset_phase_[PHASEA].current_offset_;
this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // C Current offset
// Setup voltage and current calibration offsets for PHASE B
this->offset_phase_[PHASEB].voltage_offset_ = calibrate_voltage_offset_phase(PHASEB);
this->phase_[PHASEB].voltage_offset_ = this->offset_phase_[PHASEB].voltage_offset_;
this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // C Voltage offset
this->offset_phase_[PHASEB].current_offset_ = calibrate_current_offset_phase(PHASEB);
this->phase_[PHASEB].current_offset_ = this->offset_phase_[PHASEB].current_offset_;
this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // C Current offset
// Setup voltage and current calibration offsets for PHASE C
this->offset_phase_[PHASEC].voltage_offset_ = calibrate_voltage_offset_phase(PHASEC);
this->phase_[PHASEC].voltage_offset_ = this->offset_phase_[PHASEC].voltage_offset_;
this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
this->offset_phase_[PHASEC].current_offset_ = calibrate_current_offset_phase(PHASEC);
this->phase_[PHASEC].current_offset_ = this->offset_phase_[PHASEC].current_offset_;
this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
this->pref_.save(&this->offset_phase_);
ESP_LOGI(TAG, "PhaseA Vo=%5d PhaseB Vo=%5d PhaseC Vo=%5d", this->offset_phase_[PHASEA].voltage_offset_,
this->offset_phase_[PHASEB].voltage_offset_, this->offset_phase_[PHASEC].voltage_offset_);
ESP_LOGI(TAG, "PhaseA Io=%5d PhaseB Io=%5d PhaseC Io=%5d", this->offset_phase_[PHASEA].current_offset_,
this->offset_phase_[PHASEB].current_offset_, this->offset_phase_[PHASEC].current_offset_);
}
void ATM90E32Component::clear_offset_calibrations() {
// Clear the calibrations and
this->offset_phase_[PHASEA].voltage_offset_ = 0;
this->phase_[PHASEA].voltage_offset_ = this->offset_phase_[PHASEA].voltage_offset_;
this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // C Voltage offset
this->offset_phase_[PHASEA].current_offset_ = 0;
this->phase_[PHASEA].current_offset_ = this->offset_phase_[PHASEA].current_offset_;
this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // C Current offset
this->offset_phase_[PHASEB].voltage_offset_ = 0;
this->phase_[PHASEB].voltage_offset_ = this->offset_phase_[PHASEB].voltage_offset_;
this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // C Voltage offset
this->offset_phase_[PHASEB].current_offset_ = 0;
this->phase_[PHASEB].current_offset_ = this->offset_phase_[PHASEB].current_offset_;
this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // C Current offset
this->offset_phase_[PHASEC].voltage_offset_ = 0;
this->phase_[PHASEC].voltage_offset_ = this->offset_phase_[PHASEC].voltage_offset_;
this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
this->offset_phase_[PHASEC].current_offset_ = 0;
this->phase_[PHASEC].current_offset_ = this->offset_phase_[PHASEC].current_offset_;
this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
this->pref_.save(&this->offset_phase_);
ESP_LOGI(TAG, "PhaseA Vo=%5d PhaseB Vo=%5d PhaseC Vo=%5d", this->offset_phase_[PHASEA].voltage_offset_,
this->offset_phase_[PHASEB].voltage_offset_, this->offset_phase_[PHASEC].voltage_offset_);
ESP_LOGI(TAG, "PhaseA Io=%5d PhaseB Io=%5d PhaseC Io=%5d", this->offset_phase_[PHASEA].current_offset_,
this->offset_phase_[PHASEB].current_offset_, this->offset_phase_[PHASEC].current_offset_);
}
void ATM90E32Component::setup() { void ATM90E32Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up ATM90E32 Component..."); ESP_LOGCONFIG(TAG, "Setting up ATM90E32 Component...");
this->spi_setup(); this->spi_setup();
if (this->enable_offset_calibration_) {
uint32_t hash = fnv1_hash(App.get_friendly_name());
this->pref_ = global_preferences->make_preference<Calibration[3]>(hash, true);
this->restore_calibrations_();
}
uint16_t mmode0 = 0x87; // 3P4W 50Hz uint16_t mmode0 = 0x87; // 3P4W 50Hz
if (line_freq_ == 60) { if (line_freq_ == 60) {
mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz
@@ -167,27 +234,12 @@ void ATM90E32Component::setup() {
this->write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50% this->write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750 this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10% this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10%
// Setup voltage and current calibration offsets for PHASE A
this->phase_[PHASEA].voltage_offset_ = calibrate_voltage_offset_phase(PHASEA);
this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // A Voltage offset
this->phase_[PHASEA].current_offset_ = calibrate_current_offset_phase(PHASEA);
this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // A Current offset
// Setup voltage and current gain for PHASE A // Setup voltage and current gain for PHASE A
this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[PHASEA].voltage_gain_); // A Voltage rms gain this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[PHASEA].voltage_gain_); // A Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[PHASEA].ct_gain_); // A line current gain this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[PHASEA].ct_gain_); // A line current gain
// Setup voltage and current calibration offsets for PHASE B
this->phase_[PHASEB].voltage_offset_ = calibrate_voltage_offset_phase(PHASEB);
this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // B Voltage offset
this->phase_[PHASEB].current_offset_ = calibrate_current_offset_phase(PHASEB);
this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // B Current offset
// Setup voltage and current gain for PHASE B // Setup voltage and current gain for PHASE B
this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[PHASEB].voltage_gain_); // B Voltage rms gain this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[PHASEB].voltage_gain_); // B Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[PHASEB].ct_gain_); // B line current gain this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[PHASEB].ct_gain_); // B line current gain
// Setup voltage and current calibration offsets for PHASE C
this->phase_[PHASEC].voltage_offset_ = calibrate_voltage_offset_phase(PHASEC);
this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
this->phase_[PHASEC].current_offset_ = calibrate_current_offset_phase(PHASEC);
this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
// Setup voltage and current gain for PHASE C // Setup voltage and current gain for PHASE C
this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[PHASEC].voltage_gain_); // C Voltage rms gain this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[PHASEC].voltage_gain_); // C Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[PHASEC].ct_gain_); // C line current gain this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[PHASEC].ct_gain_); // C line current gain

View File

@@ -1,9 +1,12 @@
#pragma once #pragma once
#include "esphome/core/component.h" #include "atm90e32_reg.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/spi/spi.h" #include "esphome/components/spi/spi.h"
#include "atm90e32_reg.h" #include "esphome/core/application.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
namespace esphome { namespace esphome {
namespace atm90e32 { namespace atm90e32 {
@@ -20,7 +23,6 @@ class ATM90E32Component : public PollingComponent,
void dump_config() override; void dump_config() override;
float get_setup_priority() const override; float get_setup_priority() const override;
void update() override; void update() override;
void set_voltage_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].voltage_sensor_ = obj; } void set_voltage_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].voltage_sensor_ = obj; }
void set_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].current_sensor_ = obj; } void set_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].current_sensor_ = obj; }
void set_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_sensor_ = obj; } void set_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_sensor_ = obj; }
@@ -48,9 +50,11 @@ class ATM90E32Component : public PollingComponent,
void set_line_freq(int freq) { line_freq_ = freq; } void set_line_freq(int freq) { line_freq_ = freq; }
void set_current_phases(int phases) { current_phases_ = phases; } void set_current_phases(int phases) { current_phases_ = phases; }
void set_pga_gain(uint16_t gain) { pga_gain_ = gain; } void set_pga_gain(uint16_t gain) { pga_gain_ = gain; }
void run_offset_calibrations();
void clear_offset_calibrations();
void set_enable_offset_calibration(bool flag) { enable_offset_calibration_ = flag; }
uint16_t calibrate_voltage_offset_phase(uint8_t /*phase*/); uint16_t calibrate_voltage_offset_phase(uint8_t /*phase*/);
uint16_t calibrate_current_offset_phase(uint8_t /*phase*/); uint16_t calibrate_current_offset_phase(uint8_t /*phase*/);
int32_t last_periodic_millis = millis(); int32_t last_periodic_millis = millis();
protected: protected:
@@ -83,10 +87,11 @@ class ATM90E32Component : public PollingComponent,
float get_chip_temperature_(); float get_chip_temperature_();
bool get_publish_interval_flag_() { return publish_interval_flag_; }; bool get_publish_interval_flag_() { return publish_interval_flag_; };
void set_publish_interval_flag_(bool flag) { publish_interval_flag_ = flag; }; void set_publish_interval_flag_(bool flag) { publish_interval_flag_ = flag; };
void restore_calibrations_();
struct ATM90E32Phase { struct ATM90E32Phase {
uint16_t voltage_gain_{7305}; uint16_t voltage_gain_{0};
uint16_t ct_gain_{27961}; uint16_t ct_gain_{0};
uint16_t voltage_offset_{0}; uint16_t voltage_offset_{0};
uint16_t current_offset_{0}; uint16_t current_offset_{0};
float voltage_{0}; float voltage_{0};
@@ -114,13 +119,21 @@ class ATM90E32Component : public PollingComponent,
uint32_t cumulative_reverse_active_energy_{0}; uint32_t cumulative_reverse_active_energy_{0};
} phase_[3]; } phase_[3];
struct Calibration {
uint16_t voltage_offset_{0};
uint16_t current_offset_{0};
} offset_phase_[3];
ESPPreferenceObject pref_;
sensor::Sensor *freq_sensor_{nullptr}; sensor::Sensor *freq_sensor_{nullptr};
sensor::Sensor *chip_temperature_sensor_{nullptr}; sensor::Sensor *chip_temperature_sensor_{nullptr};
uint16_t pga_gain_{0x15}; uint16_t pga_gain_{0x15};
int line_freq_{60}; int line_freq_{60};
int current_phases_{3}; int current_phases_{3};
bool publish_interval_flag_{true}; bool publish_interval_flag_{false};
bool peak_current_signed_{false}; bool peak_current_signed_{false};
bool enable_offset_calibration_{false};
}; };
} // namespace atm90e32 } // namespace atm90e32

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <cinttypes>
namespace esphome { namespace esphome {
namespace atm90e32 { namespace atm90e32 {

View File

@@ -0,0 +1,43 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import CONF_ID, ENTITY_CATEGORY_CONFIG, ICON_CHIP, ICON_SCALE
from .. import atm90e32_ns
from ..sensor import ATM90E32Component
CONF_RUN_OFFSET_CALIBRATION = "run_offset_calibration"
CONF_CLEAR_OFFSET_CALIBRATION = "clear_offset_calibration"
ATM90E32CalibrationButton = atm90e32_ns.class_(
"ATM90E32CalibrationButton",
button.Button,
)
ATM90E32ClearCalibrationButton = atm90e32_ns.class_(
"ATM90E32ClearCalibrationButton",
button.Button,
)
CONFIG_SCHEMA = {
cv.GenerateID(CONF_ID): cv.use_id(ATM90E32Component),
cv.Optional(CONF_RUN_OFFSET_CALIBRATION): button.button_schema(
ATM90E32CalibrationButton,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SCALE,
),
cv.Optional(CONF_CLEAR_OFFSET_CALIBRATION): button.button_schema(
ATM90E32ClearCalibrationButton,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_CHIP,
),
}
async def to_code(config):
parent = await cg.get_variable(config[CONF_ID])
if run_offset := config.get(CONF_RUN_OFFSET_CALIBRATION):
b = await button.new_button(run_offset)
await cg.register_parented(b, parent)
if clear_offset := config.get(CONF_CLEAR_OFFSET_CALIBRATION):
b = await button.new_button(clear_offset)
await cg.register_parented(b, parent)

View File

@@ -0,0 +1,20 @@
#include "atm90e32_button.h"
#include "esphome/core/log.h"
namespace esphome {
namespace atm90e32 {
static const char *const TAG = "atm90e32.button";
void ATM90E32CalibrationButton::press_action() {
ESP_LOGI(TAG, "Running offset calibrations, Note: CTs and ACVs must be 0 during this process...");
this->parent_->run_offset_calibrations();
}
void ATM90E32ClearCalibrationButton::press_action() {
ESP_LOGI(TAG, "Offset calibrations cleared.");
this->parent_->clear_offset_calibrations();
}
} // namespace atm90e32
} // namespace esphome

View File

@@ -0,0 +1,27 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/atm90e32/atm90e32.h"
#include "esphome/components/button/button.h"
namespace esphome {
namespace atm90e32 {
class ATM90E32CalibrationButton : public button::Button, public Parented<ATM90E32Component> {
public:
ATM90E32CalibrationButton() = default;
protected:
void press_action() override;
};
class ATM90E32ClearCalibrationButton : public button::Button, public Parented<ATM90E32Component> {
public:
ATM90E32ClearCalibrationButton() = default;
protected:
void press_action() override;
};
} // namespace atm90e32
} // namespace esphome

View File

@@ -1,21 +1,22 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, spi from esphome.components import sensor, spi
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_APPARENT_POWER,
CONF_REACTIVE_POWER,
CONF_VOLTAGE,
CONF_CURRENT, CONF_CURRENT,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_FREQUENCY,
CONF_ID,
CONF_LINE_FREQUENCY,
CONF_PHASE_A, CONF_PHASE_A,
CONF_PHASE_ANGLE,
CONF_PHASE_B, CONF_PHASE_B,
CONF_PHASE_C, CONF_PHASE_C,
CONF_PHASE_ANGLE,
CONF_POWER, CONF_POWER,
CONF_POWER_FACTOR, CONF_POWER_FACTOR,
CONF_APPARENT_POWER, CONF_REACTIVE_POWER,
CONF_FREQUENCY,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_REVERSE_ACTIVE_ENERGY, CONF_REVERSE_ACTIVE_ENERGY,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT, DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER, DEVICE_CLASS_POWER,
@@ -23,13 +24,13 @@ from esphome.const import (
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLTAGE,
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
ICON_LIGHTBULB,
ICON_CURRENT_AC, ICON_CURRENT_AC,
ICON_LIGHTBULB,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING, STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE, UNIT_AMPERE,
UNIT_DEGREES,
UNIT_CELSIUS, UNIT_CELSIUS,
UNIT_DEGREES,
UNIT_HERTZ, UNIT_HERTZ,
UNIT_VOLT, UNIT_VOLT,
UNIT_VOLT_AMPS_REACTIVE, UNIT_VOLT_AMPS_REACTIVE,
@@ -37,7 +38,8 @@ from esphome.const import (
UNIT_WATT_HOURS, UNIT_WATT_HOURS,
) )
CONF_LINE_FREQUENCY = "line_frequency" from . import atm90e32_ns
CONF_CHIP_TEMPERATURE = "chip_temperature" CONF_CHIP_TEMPERATURE = "chip_temperature"
CONF_GAIN_PGA = "gain_pga" CONF_GAIN_PGA = "gain_pga"
CONF_CURRENT_PHASES = "current_phases" CONF_CURRENT_PHASES = "current_phases"
@@ -46,6 +48,7 @@ CONF_GAIN_CT = "gain_ct"
CONF_HARMONIC_POWER = "harmonic_power" CONF_HARMONIC_POWER = "harmonic_power"
CONF_PEAK_CURRENT = "peak_current" CONF_PEAK_CURRENT = "peak_current"
CONF_PEAK_CURRENT_SIGNED = "peak_current_signed" CONF_PEAK_CURRENT_SIGNED = "peak_current_signed"
CONF_ENABLE_OFFSET_CALIBRATION = "enable_offset_calibration"
UNIT_DEG = "degrees" UNIT_DEG = "degrees"
LINE_FREQS = { LINE_FREQS = {
"50HZ": 50, "50HZ": 50,
@@ -61,7 +64,6 @@ PGA_GAINS = {
"4X": 0x2A, "4X": 0x2A,
} }
atm90e32_ns = cg.esphome_ns.namespace("atm90e32")
ATM90E32Component = atm90e32_ns.class_( ATM90E32Component = atm90e32_ns.class_(
"ATM90E32Component", cg.PollingComponent, spi.SPIDevice "ATM90E32Component", cg.PollingComponent, spi.SPIDevice
) )
@@ -164,6 +166,7 @@ CONFIG_SCHEMA = (
), ),
cv.Optional(CONF_GAIN_PGA, default="2X"): cv.enum(PGA_GAINS, upper=True), cv.Optional(CONF_GAIN_PGA, default="2X"): cv.enum(PGA_GAINS, upper=True),
cv.Optional(CONF_PEAK_CURRENT_SIGNED, default=False): cv.boolean, cv.Optional(CONF_PEAK_CURRENT_SIGNED, default=False): cv.boolean,
cv.Optional(CONF_ENABLE_OFFSET_CALIBRATION, default=False): cv.boolean,
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
@@ -227,3 +230,4 @@ async def to_code(config):
cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES])) cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES]))
cg.add(var.set_pga_gain(config[CONF_GAIN_PGA])) cg.add(var.set_pga_gain(config[CONF_GAIN_PGA]))
cg.add(var.set_peak_current_signed(config[CONF_PEAK_CURRENT_SIGNED])) cg.add(var.set_peak_current_signed(config[CONF_PEAK_CURRENT_SIGNED]))
cg.add(var.set_enable_offset_calibration(config[CONF_ENABLE_OFFSET_CALIBRATION]))

View File

@@ -90,7 +90,7 @@ struct BedjetStatusPacket {
int unused_6 : 1; // 0x4 int unused_6 : 1; // 0x4
bool is_dual_zone : 1; /// Is part of a Dual Zone configuration bool is_dual_zone : 1; /// Is part of a Dual Zone configuration
int unused_7 : 1; // 0x1 int unused_7 : 1; // 0x1
} dual_zone_flags; } dual_zone_flags; // NOLINT(clang-diagnostic-unaligned-access)
uint8_t unused_4 : 8; // Unknown 23-24 = 0x1310 uint8_t unused_4 : 8; // Unknown 23-24 = 0x1310
uint8_t unused_5 : 8; // Unknown 23-24 = 0x1310 uint8_t unused_5 : 8; // Unknown 23-24 = 0x1310

View File

@@ -18,10 +18,11 @@ class BinaryLightOutput : public light::LightOutput {
void write_state(light::LightState *state) override { void write_state(light::LightState *state) override {
bool binary; bool binary;
state->current_values_as_binary(&binary); state->current_values_as_binary(&binary);
if (binary) if (binary) {
this->output_->turn_on(); this->output_->turn_on();
else } else {
this->output_->turn_off(); this->output_->turn_off();
}
} }
protected: protected:

View File

@@ -1,10 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.cpp_generator import MockObjClass
from esphome.cpp_helpers import setup_entity
from esphome import automation, core from esphome import automation, core
from esphome.automation import Condition, maybe_simple_id from esphome.automation import Condition, maybe_simple_id
import esphome.codegen as cg
from esphome.components import mqtt, web_server from esphome.components import mqtt, web_server
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_DELAY, CONF_DELAY,
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
@@ -16,6 +14,7 @@ from esphome.const import (
CONF_INVERTED, CONF_INVERTED,
CONF_MAX_LENGTH, CONF_MAX_LENGTH,
CONF_MIN_LENGTH, CONF_MIN_LENGTH,
CONF_MQTT_ID,
CONF_ON_CLICK, CONF_ON_CLICK,
CONF_ON_DOUBLE_CLICK, CONF_ON_DOUBLE_CLICK,
CONF_ON_MULTI_CLICK, CONF_ON_MULTI_CLICK,
@@ -26,7 +25,6 @@ from esphome.const import (
CONF_STATE, CONF_STATE,
CONF_TIMING, CONF_TIMING,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_MQTT_ID,
CONF_WEB_SERVER_ID, CONF_WEB_SERVER_ID,
DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY,
DEVICE_CLASS_BATTERY_CHARGING, DEVICE_CLASS_BATTERY_CHARGING,
@@ -59,6 +57,8 @@ from esphome.const import (
DEVICE_CLASS_WINDOW, DEVICE_CLASS_WINDOW,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
from esphome.cpp_generator import MockObjClass
from esphome.cpp_helpers import setup_entity
from esphome.util import Registry from esphome.util import Registry
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]

View File

@@ -0,0 +1 @@
CODEOWNERS = ["@athom-tech", "@tarontop", "@jesserockz"]

View File

@@ -0,0 +1,238 @@
#include "bl0906.h"
#include "constants.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bl0906 {
static const char *const TAG = "bl0906";
constexpr uint32_t to_uint32_t(ube24_t input) { return input.h << 16 | input.m << 8 | input.l; }
constexpr int32_t to_int32_t(sbe24_t input) { return input.h << 16 | input.m << 8 | input.l; }
// The SUM byte is (Addr+Data_L+Data_M+Data_H)&0xFF negated;
constexpr uint8_t bl0906_checksum(const uint8_t address, const DataPacket *data) {
return (address + data->l + data->m + data->h) ^ 0xFF;
}
void BL0906::loop() {
if (this->current_channel_ == UINT8_MAX) {
return;
}
while (this->available())
this->flush();
if (this->current_channel_ == 0) {
// Temperature
this->read_data_(BL0906_TEMPERATURE, BL0906_TREF, this->temperature_sensor_);
} else if (this->current_channel_ == 1) {
this->read_data_(BL0906_I_1_RMS, BL0906_IREF, this->current_1_sensor_);
this->read_data_(BL0906_WATT_1, BL0906_PREF, this->power_1_sensor_);
this->read_data_(BL0906_CF_1_CNT, BL0906_EREF, this->energy_1_sensor_);
} else if (this->current_channel_ == 2) {
this->read_data_(BL0906_I_2_RMS, BL0906_IREF, this->current_2_sensor_);
this->read_data_(BL0906_WATT_2, BL0906_PREF, this->power_2_sensor_);
this->read_data_(BL0906_CF_2_CNT, BL0906_EREF, this->energy_2_sensor_);
} else if (this->current_channel_ == 3) {
this->read_data_(BL0906_I_3_RMS, BL0906_IREF, this->current_3_sensor_);
this->read_data_(BL0906_WATT_3, BL0906_PREF, this->power_3_sensor_);
this->read_data_(BL0906_CF_3_CNT, BL0906_EREF, this->energy_3_sensor_);
} else if (this->current_channel_ == 4) {
this->read_data_(BL0906_I_4_RMS, BL0906_IREF, this->current_4_sensor_);
this->read_data_(BL0906_WATT_4, BL0906_PREF, this->power_4_sensor_);
this->read_data_(BL0906_CF_4_CNT, BL0906_EREF, this->energy_4_sensor_);
} else if (this->current_channel_ == 5) {
this->read_data_(BL0906_I_5_RMS, BL0906_IREF, this->current_5_sensor_);
this->read_data_(BL0906_WATT_5, BL0906_PREF, this->power_5_sensor_);
this->read_data_(BL0906_CF_5_CNT, BL0906_EREF, this->energy_5_sensor_);
} else if (this->current_channel_ == 6) {
this->read_data_(BL0906_I_6_RMS, BL0906_IREF, this->current_6_sensor_);
this->read_data_(BL0906_WATT_6, BL0906_PREF, this->power_6_sensor_);
this->read_data_(BL0906_CF_6_CNT, BL0906_EREF, this->energy_6_sensor_);
} else if (this->current_channel_ == UINT8_MAX - 2) {
// Frequency
this->read_data_(BL0906_FREQUENCY, BL0906_FREF, frequency_sensor_);
// Voltage
this->read_data_(BL0906_V_RMS, BL0906_UREF, voltage_sensor_);
} else if (this->current_channel_ == UINT8_MAX - 1) {
// Total power
this->read_data_(BL0906_WATT_SUM, BL0906_WATT, this->total_power_sensor_);
// Total Energy
this->read_data_(BL0906_CF_SUM_CNT, BL0906_CF, this->total_energy_sensor_);
} else {
this->current_channel_ = UINT8_MAX - 2; // Go to frequency and voltage
return;
}
this->current_channel_++;
this->handle_actions_();
}
void BL0906::setup() {
while (this->available())
this->flush();
this->write_array(USR_WRPROT_WITABLE, sizeof(USR_WRPROT_WITABLE));
// Calibration (1: register address; 2: value before calibration; 3: value after calibration)
this->bias_correction_(BL0906_RMSOS_1, 0.01600, 0); // Calibration current_1
this->bias_correction_(BL0906_RMSOS_2, 0.01500, 0);
this->bias_correction_(BL0906_RMSOS_3, 0.01400, 0);
this->bias_correction_(BL0906_RMSOS_4, 0.01300, 0);
this->bias_correction_(BL0906_RMSOS_5, 0.01200, 0);
this->bias_correction_(BL0906_RMSOS_6, 0.01200, 0); // Calibration current_6
this->write_array(USR_WRPROT_ONLYREAD, sizeof(USR_WRPROT_ONLYREAD));
}
void BL0906::update() { this->current_channel_ = 0; }
size_t BL0906::enqueue_action_(ActionCallbackFuncPtr function) {
this->action_queue_.push_back(function);
return this->action_queue_.size();
}
void BL0906::handle_actions_() {
if (this->action_queue_.empty()) {
return;
}
ActionCallbackFuncPtr ptr_func = nullptr;
for (int i = 0; i < this->action_queue_.size(); i++) {
ptr_func = this->action_queue_[i];
if (ptr_func) {
ESP_LOGI(TAG, "HandleActionCallback[%d]...", i);
(this->*ptr_func)();
}
}
while (this->available()) {
this->read();
}
this->action_queue_.clear();
}
// Reset energy
void BL0906::reset_energy_() {
this->write_array(BL0906_INIT[0], 6);
delay(1);
this->flush();
ESP_LOGW(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_INIT[0][0], BL0906_INIT[0][1], BL0906_INIT[0][2],
BL0906_INIT[0][3], BL0906_INIT[0][4], BL0906_INIT[0][5]);
}
// Read data
void BL0906::read_data_(const uint8_t address, const float reference, sensor::Sensor *sensor) {
if (sensor == nullptr) {
return;
}
DataPacket buffer;
ube24_t data_u24;
sbe24_t data_s24;
float value = 0;
bool signed_result = reference == BL0906_TREF || reference == BL0906_WATT || reference == BL0906_PREF;
this->write_byte(BL0906_READ_COMMAND);
this->write_byte(address);
if (this->read_array((uint8_t *) &buffer, sizeof(buffer) - 1)) {
if (bl0906_checksum(address, &buffer) == buffer.checksum) {
if (signed_result) {
data_s24.l = buffer.l;
data_s24.m = buffer.m;
data_s24.h = buffer.h;
} else {
data_u24.l = buffer.l;
data_u24.m = buffer.m;
data_u24.h = buffer.h;
}
} else {
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
while (read() >= 0)
;
return;
}
}
// Power
if (reference == BL0906_PREF) {
value = (float) to_int32_t(data_s24) * reference;
}
// Total power
if (reference == BL0906_WATT) {
value = (float) to_int32_t(data_s24) * reference;
}
// Voltage, current, power, total power
if (reference == BL0906_UREF || reference == BL0906_IREF || reference == BL0906_EREF || reference == BL0906_CF) {
value = (float) to_uint32_t(data_u24) * reference;
}
// Frequency
if (reference == BL0906_FREF) {
value = reference / (float) to_uint32_t(data_u24);
}
// Chip temperature
if (reference == BL0906_TREF) {
value = (float) to_int32_t(data_s24);
value = (value - 64) * 12.5 / 59 - 40;
}
sensor->publish_state(value);
}
// RMS offset correction
void BL0906::bias_correction_(uint8_t address, float measurements, float correction) {
DataPacket data;
float ki = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097; // Current coefficient
float i_rms0 = measurements * ki;
float i_rms = correction * ki;
int32_t value = (i_rms * i_rms - i_rms0 * i_rms0) / 256;
data.l = value << 24 >> 24;
data.m = value << 16 >> 24;
if (value < 0) {
data.h = (value << 8 >> 24) | 0b10000000;
}
data.address = bl0906_checksum(address, &data);
ESP_LOGV(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_WRITE_COMMAND, address, data.l, data.m, data.h, data.address);
this->write_byte(BL0906_WRITE_COMMAND);
this->write_byte(address);
this->write_byte(data.l);
this->write_byte(data.m);
this->write_byte(data.h);
this->write_byte(data.address);
}
void BL0906::dump_config() {
ESP_LOGCONFIG(TAG, "BL0906:");
LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
LOG_SENSOR(" ", "Current1", this->current_1_sensor_);
LOG_SENSOR(" ", "Current2", this->current_2_sensor_);
LOG_SENSOR(" ", "Current3", this->current_3_sensor_);
LOG_SENSOR(" ", "Current4", this->current_4_sensor_);
LOG_SENSOR(" ", "Current5", this->current_5_sensor_);
LOG_SENSOR(" ", "Current6", this->current_6_sensor_);
LOG_SENSOR(" ", "Power1", this->power_1_sensor_);
LOG_SENSOR(" ", "Power2", this->power_2_sensor_);
LOG_SENSOR(" ", "Power3", this->power_3_sensor_);
LOG_SENSOR(" ", "Power4", this->power_4_sensor_);
LOG_SENSOR(" ", "Power5", this->power_5_sensor_);
LOG_SENSOR(" ", "Power6", this->power_6_sensor_);
LOG_SENSOR(" ", "Energy1", this->energy_1_sensor_);
LOG_SENSOR(" ", "Energy2", this->energy_2_sensor_);
LOG_SENSOR(" ", "Energy3", this->energy_3_sensor_);
LOG_SENSOR(" ", "Energy4", this->energy_4_sensor_);
LOG_SENSOR(" ", "Energy5", this->energy_5_sensor_);
LOG_SENSOR(" ", "Energy6", this->energy_6_sensor_);
LOG_SENSOR(" ", "Total Power", this->total_power_sensor_);
LOG_SENSOR(" ", "Total Energy", this->total_energy_sensor_);
LOG_SENSOR(" ", "Frequency", this->frequency_sensor_);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
}
} // namespace bl0906
} // namespace esphome

View File

@@ -0,0 +1,96 @@
#pragma once
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/datatypes.h"
// https://www.belling.com.cn/media/file_object/bel_product/BL0906/datasheet/BL0906_V1.02_cn.pdf
// https://www.belling.com.cn/media/file_object/bel_product/BL0906/guide/BL0906%20APP%20Note_V1.02.pdf
namespace esphome {
namespace bl0906 {
struct DataPacket { // NOLINT(altera-struct-pack-align)
uint8_t l{0};
uint8_t m{0};
uint8_t h{0};
uint8_t checksum; // checksum
uint8_t address;
} __attribute__((packed));
struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l{0};
uint8_t m{0};
uint8_t h{0};
} __attribute__((packed));
struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l{0};
uint8_t m{0};
int8_t h{0};
} __attribute__((packed));
template<typename... Ts> class ResetEnergyAction;
class BL0906;
using ActionCallbackFuncPtr = void (BL0906::*)();
class BL0906 : public PollingComponent, public uart::UARTDevice {
SUB_SENSOR(voltage)
SUB_SENSOR(current_1)
SUB_SENSOR(current_2)
SUB_SENSOR(current_3)
SUB_SENSOR(current_4)
SUB_SENSOR(current_5)
SUB_SENSOR(current_6)
SUB_SENSOR(power_1)
SUB_SENSOR(power_2)
SUB_SENSOR(power_3)
SUB_SENSOR(power_4)
SUB_SENSOR(power_5)
SUB_SENSOR(power_6)
SUB_SENSOR(total_power)
SUB_SENSOR(energy_1)
SUB_SENSOR(energy_2)
SUB_SENSOR(energy_3)
SUB_SENSOR(energy_4)
SUB_SENSOR(energy_5)
SUB_SENSOR(energy_6)
SUB_SENSOR(total_energy)
SUB_SENSOR(frequency)
SUB_SENSOR(temperature)
public:
void loop() override;
void update() override;
void setup() override;
void dump_config() override;
protected:
template<typename... Ts> friend class ResetEnergyAction;
void reset_energy_();
void read_data_(uint8_t address, float reference, sensor::Sensor *sensor);
void bias_correction_(uint8_t address, float measurements, float correction);
uint8_t current_channel_{0};
size_t enqueue_action_(ActionCallbackFuncPtr function);
void handle_actions_();
private:
std::vector<ActionCallbackFuncPtr> action_queue_{};
};
template<typename... Ts> class ResetEnergyAction : public Action<Ts...>, public Parented<BL0906> {
public:
void play(Ts... x) override { this->parent_->enqueue_action_(&BL0906::reset_energy_); }
};
} // namespace bl0906
} // namespace esphome

View File

@@ -0,0 +1,4 @@
# const.py
ICON_ENERGY = "mdi:lightning-bolt"
ICON_FREQUENCY = "mdi:cosine-wave"
ICON_VOLTAGE = "mdi:sine-wave"

View File

@@ -0,0 +1,122 @@
#pragma once
#include <cstdint>
namespace esphome {
namespace bl0906 {
// Total power conversion
static const float BL0906_WATT = 16 * 1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) /
(40.41259 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000);
// Total Energy conversion
static const float BL0906_CF = 16 * 4194304 * 0.032768 * 16 /
(3600000 * 16 *
(40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 /
(1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000))));
// Frequency conversion
static const float BL0906_FREF = 10000000;
// Temperature conversion
static const float BL0906_TREF = 12.5 / 59 - 40;
// Current conversion
static const float BL0906_IREF = 1.097 / (12875 * 1 * (5.1 + 5.1) * 1000 / 2000);
// Voltage conversion
static const float BL0906_UREF = 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) / (13162 * 1 * 100 * 1000);
// Power conversion
static const float BL0906_PREF = 1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) /
(40.41259 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000);
// Energy conversion
static const float BL0906_EREF = 4194304 * 0.032768 * 16 /
(3600000 * 16 *
(40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 /
(1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000))));
// Current coefficient
static const float BL0906_KI = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097;
// Power coefficient
static const float BL0906_KP = 40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 / 1.097 / 1.097 /
(20000 + 20000 + 20000 + 20000 + 20000);
static const uint8_t USR_WRPROT_WITABLE[6] = {0xCA, 0x9E, 0x55, 0x55, 0x00, 0xB7};
static const uint8_t USR_WRPROT_ONLYREAD[6] = {0xCA, 0x9E, 0x00, 0x00, 0x00, 0x61};
static const uint8_t BL0906_READ_COMMAND = 0x35;
static const uint8_t BL0906_WRITE_COMMAND = 0xCA;
// Register address
// Voltage
static const uint8_t BL0906_V_RMS = 0x16;
// Total power
static const uint8_t BL0906_WATT_SUM = 0X2C;
// Current1~6
static const uint8_t BL0906_I_1_RMS = 0x0D; // current_1
static const uint8_t BL0906_I_2_RMS = 0x0E;
static const uint8_t BL0906_I_3_RMS = 0x0F;
static const uint8_t BL0906_I_4_RMS = 0x10;
static const uint8_t BL0906_I_5_RMS = 0x13;
static const uint8_t BL0906_I_6_RMS = 0x14; // current_6
// Power1~6
static const uint8_t BL0906_WATT_1 = 0X23; // power_1
static const uint8_t BL0906_WATT_2 = 0X24;
static const uint8_t BL0906_WATT_3 = 0X25;
static const uint8_t BL0906_WATT_4 = 0X26;
static const uint8_t BL0906_WATT_5 = 0X29;
static const uint8_t BL0906_WATT_6 = 0X2A; // power_6
// Active pulse count, unsigned
static const uint8_t BL0906_CF_1_CNT = 0X30; // Channel_1
static const uint8_t BL0906_CF_2_CNT = 0X31;
static const uint8_t BL0906_CF_3_CNT = 0X32;
static const uint8_t BL0906_CF_4_CNT = 0X33;
static const uint8_t BL0906_CF_5_CNT = 0X36;
static const uint8_t BL0906_CF_6_CNT = 0X37; // Channel_6
// Total active pulse count, unsigned
static const uint8_t BL0906_CF_SUM_CNT = 0X39;
// Voltage frequency cycle
static const uint8_t BL0906_FREQUENCY = 0X4E;
// Internal temperature
static const uint8_t BL0906_TEMPERATURE = 0X5E;
// Calibration register
// RMS gain adjustment register
static const uint8_t BL0906_RMSGN_1 = 0x6D; // Channel_1
static const uint8_t BL0906_RMSGN_2 = 0x6E;
static const uint8_t BL0906_RMSGN_3 = 0x6F;
static const uint8_t BL0906_RMSGN_4 = 0x70;
static const uint8_t BL0906_RMSGN_5 = 0x73;
static const uint8_t BL0906_RMSGN_6 = 0x74; // Channel_6
// RMS offset correction register
static const uint8_t BL0906_RMSOS_1 = 0x78; // Channel_1
static const uint8_t BL0906_RMSOS_2 = 0x79;
static const uint8_t BL0906_RMSOS_3 = 0x7A;
static const uint8_t BL0906_RMSOS_4 = 0x7B;
static const uint8_t BL0906_RMSOS_5 = 0x7E;
static const uint8_t BL0906_RMSOS_6 = 0x7F; // Channel_6
// Active power gain adjustment register
static const uint8_t BL0906_WATTGN_1 = 0xB7; // Channel_1
static const uint8_t BL0906_WATTGN_2 = 0xB8;
static const uint8_t BL0906_WATTGN_3 = 0xB9;
static const uint8_t BL0906_WATTGN_4 = 0xBA;
static const uint8_t BL0906_WATTGN_5 = 0xBD;
static const uint8_t BL0906_WATTGN_6 = 0xBE; // Channel_6
// User write protection setting register,
// You must first write 0x5555 to the write protection setting register before writing to other registers.
static const uint8_t BL0906_USR_WRPROT = 0x9E;
// Reset Register
static const uint8_t BL0906_SOFT_RESET = 0x9F;
const uint8_t BL0906_INIT[2][6] = {
// Reset to default
{BL0906_WRITE_COMMAND, BL0906_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x52},
// Enable User Operation Write
{BL0906_WRITE_COMMAND, BL0906_USR_WRPROT, 0x55, 0x55, 0x00, 0xB7}};
} // namespace bl0906
} // namespace esphome

View File

@@ -0,0 +1,184 @@
from esphome import automation
from esphome.automation import maybe_simple_id
import esphome.codegen as cg
from esphome.components import sensor, uart
import esphome.config_validation as cv
from esphome.const import (
CONF_CHANNEL,
CONF_CURRENT,
CONF_ENERGY,
CONF_FREQUENCY,
CONF_ID,
CONF_NAME,
CONF_POWER,
CONF_TEMPERATURE,
CONF_TOTAL_POWER,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
ICON_CURRENT_AC,
ICON_POWER,
ICON_THERMOMETER,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_CELSIUS,
UNIT_HERTZ,
UNIT_KILOWATT_HOURS,
UNIT_VOLT,
UNIT_WATT,
)
# Import ICONS not included in esphome's const.py, from the local components const.py
from .const import ICON_ENERGY, ICON_FREQUENCY, ICON_VOLTAGE
DEPENDENCIES = ["uart"]
AUTO_LOAD = ["bl0906"]
CONF_TOTAL_ENERGY = "total_energy"
bl0906_ns = cg.esphome_ns.namespace("bl0906")
BL0906 = bl0906_ns.class_("BL0906", cg.PollingComponent, uart.UARTDevice)
ResetEnergyAction = bl0906_ns.class_("ResetEnergyAction", automation.Action)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BL0906),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
icon=ICON_FREQUENCY,
accuracy_decimals=0,
device_class=DEVICE_CLASS_FREQUENCY,
unit_of_measurement=UNIT_HERTZ,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
icon=ICON_THERMOMETER,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
unit_of_measurement=UNIT_CELSIUS,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
icon=ICON_VOLTAGE,
accuracy_decimals=1,
device_class=DEVICE_CLASS_VOLTAGE,
unit_of_measurement=UNIT_VOLT,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_TOTAL_POWER): sensor.sensor_schema(
icon=ICON_POWER,
accuracy_decimals=3,
device_class=DEVICE_CLASS_POWER,
unit_of_measurement=UNIT_WATT,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_TOTAL_ENERGY): sensor.sensor_schema(
icon=ICON_ENERGY,
accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
unit_of_measurement=UNIT_KILOWATT_HOURS,
),
}
)
.extend(
cv.Schema(
{
cv.Optional(f"{CONF_CHANNEL}_{i + 1}"): cv.Schema(
{
cv.Optional(CONF_CURRENT): cv.maybe_simple_value(
sensor.sensor_schema(
icon=ICON_CURRENT_AC,
accuracy_decimals=3,
device_class=DEVICE_CLASS_CURRENT,
unit_of_measurement=UNIT_AMPERE,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_POWER): cv.maybe_simple_value(
sensor.sensor_schema(
icon=ICON_POWER,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER,
unit_of_measurement=UNIT_WATT,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_ENERGY): cv.maybe_simple_value(
sensor.sensor_schema(
icon=ICON_ENERGY,
accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY,
unit_of_measurement=UNIT_KILOWATT_HOURS,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
key=CONF_NAME,
),
}
)
for i in range(6)
}
)
)
.extend(uart.UART_DEVICE_SCHEMA)
.extend(cv.polling_component_schema("60s"))
)
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
"bl0906", baud_rate=19200, require_tx=True, require_rx=True
)
@automation.register_action(
"bl0906.reset_energy",
ResetEnergyAction,
maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(BL0906),
}
),
)
async def reset_energy_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
if frequency_config := config.get(CONF_FREQUENCY):
sens = await sensor.new_sensor(frequency_config)
cg.add(var.set_frequency_sensor(sens))
if temperature_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temperature_config)
cg.add(var.set_temperature_sensor(sens))
if voltage_config := config.get(CONF_VOLTAGE):
sens = await sensor.new_sensor(voltage_config)
cg.add(var.set_voltage_sensor(sens))
for i in range(6):
if channel_config := config.get(f"{CONF_CHANNEL}_{i + 1}"):
if current_config := channel_config.get(CONF_CURRENT):
sens = await sensor.new_sensor(current_config)
cg.add(getattr(var, f"set_current_{i + 1}_sensor")(sens))
if power_config := channel_config.get(CONF_POWER):
sens = await sensor.new_sensor(power_config)
cg.add(getattr(var, f"set_power_{i + 1}_sensor")(sens))
if energy_config := channel_config.get(CONF_ENERGY):
sens = await sensor.new_sensor(energy_config)
cg.add(getattr(var, f"set_energy_{i + 1}_sensor")(sens))
if total_power_config := config.get(CONF_TOTAL_POWER):
sens = await sensor.new_sensor(total_power_config)
cg.add(var.set_total_power_sensor(sens))
if total_energy_config := config.get(CONF_TOTAL_ENERGY):
sens = await sensor.new_sensor(total_energy_config)
cg.add(var.set_total_energy_sensor(sens))

View File

@@ -1 +1 @@
CODEOWNERS = ["@dbuezas"] CODEOWNERS = ["@dbuezas", "@dwmw2"]

View File

@@ -2,6 +2,8 @@
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes> #include <cinttypes>
// Datasheet: https://www.belling.com.cn/media/file_object/bel_product/BL0942/datasheet/BL0942_V1.06_en.pdf
namespace esphome { namespace esphome {
namespace bl0942 { namespace bl0942 {
@@ -12,43 +14,64 @@ static const uint8_t BL0942_FULL_PACKET = 0xAA;
static const uint8_t BL0942_PACKET_HEADER = 0x55; static const uint8_t BL0942_PACKET_HEADER = 0x55;
static const uint8_t BL0942_WRITE_COMMAND = 0xA8; static const uint8_t BL0942_WRITE_COMMAND = 0xA8;
static const uint8_t BL0942_REG_I_FAST_RMS_CTRL = 0x10;
static const uint8_t BL0942_REG_MODE = 0x18; static const uint8_t BL0942_REG_I_RMSOS = 0x12;
static const uint8_t BL0942_REG_SOFT_RESET = 0x19; static const uint8_t BL0942_REG_WA_CREEP = 0x14;
static const uint8_t BL0942_REG_USR_WRPROT = 0x1A; static const uint8_t BL0942_REG_I_FAST_RMS_TH = 0x15;
static const uint8_t BL0942_REG_I_FAST_RMS_CYC = 0x16;
static const uint8_t BL0942_REG_FREQ_CYC = 0x17;
static const uint8_t BL0942_REG_OT_FUNX = 0x18;
static const uint8_t BL0942_REG_MODE = 0x19;
static const uint8_t BL0942_REG_SOFT_RESET = 0x1C;
static const uint8_t BL0942_REG_USR_WRPROT = 0x1D;
static const uint8_t BL0942_REG_TPS_CTRL = 0x1B; static const uint8_t BL0942_REG_TPS_CTRL = 0x1B;
// TODO: Confirm insialisation works as intended static const uint32_t BL0942_REG_MODE_RESV = 0x03;
const uint8_t BL0942_INIT[5][6] = { static const uint32_t BL0942_REG_MODE_CF_EN = 0x04;
// Reset to default static const uint32_t BL0942_REG_MODE_RMS_UPDATE_SEL = 0x08;
{BL0942_WRITE_COMMAND, BL0942_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38}, static const uint32_t BL0942_REG_MODE_FAST_RMS_SEL = 0x10;
// Enable User Operation Write static const uint32_t BL0942_REG_MODE_AC_FREQ_SEL = 0x20;
{BL0942_WRITE_COMMAND, BL0942_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0}, static const uint32_t BL0942_REG_MODE_CF_CNT_CLR_SEL = 0x40;
// 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS static const uint32_t BL0942_REG_MODE_CF_CNT_ADD_SEL = 0x80;
{BL0942_WRITE_COMMAND, BL0942_REG_MODE, 0x00, 0x10, 0x00, 0x37}, static const uint32_t BL0942_REG_MODE_UART_RATE_19200 = 0x200;
// 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS static const uint32_t BL0942_REG_MODE_UART_RATE_38400 = 0x300;
{BL0942_WRITE_COMMAND, BL0942_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE}, static const uint32_t BL0942_REG_MODE_DEFAULT =
// 0x181C = Half cycle, Fast RMS threshold 6172 BL0942_REG_MODE_RESV | BL0942_REG_MODE_CF_EN | BL0942_REG_MODE_CF_CNT_ADD_SEL;
{BL0942_WRITE_COMMAND, BL0942_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}};
static const uint32_t BL0942_REG_SOFT_RESET_MAGIC = 0x5a5a5a;
static const uint32_t BL0942_REG_USR_WRPROT_MAGIC = 0x55;
// 23-byte packet, 11 bits per byte, 2400 baud: about 105ms
static const uint32_t PKT_TIMEOUT_MS = 200;
void BL0942::loop() { void BL0942::loop() {
DataPacket buffer; DataPacket buffer;
if (!this->available()) { int avail = this->available();
if (!avail) {
return; return;
} }
if (read_array((uint8_t *) &buffer, sizeof(buffer))) { if (avail < sizeof(buffer)) {
if (validate_checksum(&buffer)) { if (!this->rx_start_) {
received_package_(&buffer); this->rx_start_ = millis();
} else if (millis() > this->rx_start_ + PKT_TIMEOUT_MS) {
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message (%d bytes)", avail);
this->read_array((uint8_t *) &buffer, avail);
this->rx_start_ = 0;
} }
} else { return;
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
while (read() >= 0)
;
} }
if (this->read_array((uint8_t *) &buffer, sizeof(buffer))) {
if (this->validate_checksum_(&buffer)) {
this->received_package_(&buffer);
}
}
this->rx_start_ = 0;
} }
bool BL0942::validate_checksum(DataPacket *data) { bool BL0942::validate_checksum_(DataPacket *data) {
uint8_t checksum = BL0942_READ_COMMAND; uint8_t checksum = BL0942_READ_COMMAND | this->address_;
// Whole package but checksum // Whole package but checksum
uint8_t *raw = (uint8_t *) data; uint8_t *raw = (uint8_t *) data;
for (uint32_t i = 0; i < sizeof(*data) - 1; i++) { for (uint32_t i = 0; i < sizeof(*data) - 1; i++) {
@@ -61,17 +84,73 @@ bool BL0942::validate_checksum(DataPacket *data) {
return checksum == data->checksum; return checksum == data->checksum;
} }
void BL0942::update() { void BL0942::write_reg_(uint8_t reg, uint32_t val) {
uint8_t pkt[6];
this->flush(); this->flush();
this->write_byte(BL0942_READ_COMMAND); pkt[0] = BL0942_WRITE_COMMAND | this->address_;
pkt[1] = reg;
pkt[2] = (val & 0xff);
pkt[3] = (val >> 8) & 0xff;
pkt[4] = (val >> 16) & 0xff;
pkt[5] = (pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4]) ^ 0xff;
this->write_array(pkt, 6);
delay(1);
}
int BL0942::read_reg_(uint8_t reg) {
union {
uint8_t b[4];
uint32_le_t le32;
} resp;
this->write_byte(BL0942_READ_COMMAND | this->address_);
this->write_byte(reg);
this->flush();
if (this->read_array(resp.b, 4) &&
resp.b[3] ==
(uint8_t) ((BL0942_READ_COMMAND + this->address_ + reg + resp.b[0] + resp.b[1] + resp.b[2]) ^ 0xff)) {
resp.b[3] = 0;
return resp.le32;
}
return -1;
}
void BL0942::update() {
this->write_byte(BL0942_READ_COMMAND | this->address_);
this->write_byte(BL0942_FULL_PACKET); this->write_byte(BL0942_FULL_PACKET);
} }
void BL0942::setup() { void BL0942::setup() {
for (auto *i : BL0942_INIT) { // If either current or voltage references are set explicitly by the user,
this->write_array(i, 6); // calculate the power reference from it unless that is also explicitly set.
delay(1); if ((this->current_reference_set_ || this->voltage_reference_set_) && !this->power_reference_set_) {
this->power_reference_ = (this->voltage_reference_ * this->current_reference_ * 3537.0 / 305978.0) / 73989.0;
this->power_reference_set_ = true;
} }
// Similarly for energy reference, if the power reference was set by the user
// either implicitly or explicitly.
if (this->power_reference_set_ && !this->energy_reference_set_) {
this->energy_reference_ = this->power_reference_ * 3600000 / 419430.4;
this->energy_reference_set_ = true;
}
this->write_reg_(BL0942_REG_USR_WRPROT, BL0942_REG_USR_WRPROT_MAGIC);
if (this->reset_)
this->write_reg_(BL0942_REG_SOFT_RESET, BL0942_REG_SOFT_RESET_MAGIC);
uint32_t mode = BL0942_REG_MODE_DEFAULT;
mode |= BL0942_REG_MODE_RMS_UPDATE_SEL; /* 800ms refresh time */
if (this->line_freq_ == LINE_FREQUENCY_60HZ)
mode |= BL0942_REG_MODE_AC_FREQ_SEL;
this->write_reg_(BL0942_REG_MODE, mode);
this->write_reg_(BL0942_REG_USR_WRPROT, 0);
if (this->read_reg_(BL0942_REG_MODE) != mode)
this->status_set_warning("BL0942 setup failed!");
this->flush(); this->flush();
} }
@@ -82,10 +161,17 @@ void BL0942::received_package_(DataPacket *data) {
return; return;
} }
// cf_cnt is only 24 bits, so track overflows
uint32_t cf_cnt = (uint24_t) data->cf_cnt;
cf_cnt |= this->prev_cf_cnt_ & 0xff000000;
if (cf_cnt < this->prev_cf_cnt_) {
cf_cnt += 0x1000000;
}
this->prev_cf_cnt_ = cf_cnt;
float v_rms = (uint24_t) data->v_rms / voltage_reference_; float v_rms = (uint24_t) data->v_rms / voltage_reference_;
float i_rms = (uint24_t) data->i_rms / current_reference_; float i_rms = (uint24_t) data->i_rms / current_reference_;
float watt = (int24_t) data->watt / power_reference_; float watt = (int24_t) data->watt / power_reference_;
uint32_t cf_cnt = (uint24_t) data->cf_cnt;
float total_energy_consumption = cf_cnt / energy_reference_; float total_energy_consumption = cf_cnt / energy_reference_;
float frequency = 1000000.0f / data->frequency; float frequency = 1000000.0f / data->frequency;
@@ -104,18 +190,25 @@ void BL0942::received_package_(DataPacket *data) {
if (frequency_sensor_ != nullptr) { if (frequency_sensor_ != nullptr) {
frequency_sensor_->publish_state(frequency); frequency_sensor_->publish_state(frequency);
} }
this->status_clear_warning();
ESP_LOGV(TAG, "BL0942: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, frequency %fHz, status 0x%08X", v_rms, i_rms, ESP_LOGV(TAG, "BL0942: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, frequency %fHz, status 0x%08X", v_rms, i_rms,
watt, cf_cnt, total_energy_consumption, frequency, data->status); watt, cf_cnt, total_energy_consumption, frequency, data->status);
} }
void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity) void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity)
ESP_LOGCONFIG(TAG, "BL0942:"); ESP_LOGCONFIG(TAG, "BL0942:");
ESP_LOGCONFIG(TAG, " Reset: %s", TRUEFALSE(this->reset_));
ESP_LOGCONFIG(TAG, " Address: %d", this->address_);
ESP_LOGCONFIG(TAG, " Nominal line frequency: %d Hz", this->line_freq_);
ESP_LOGCONFIG(TAG, " Current reference: %f", this->current_reference_);
ESP_LOGCONFIG(TAG, " Energy reference: %f", this->energy_reference_);
ESP_LOGCONFIG(TAG, " Power reference: %f", this->power_reference_);
ESP_LOGCONFIG(TAG, " Voltage reference: %f", this->voltage_reference_);
LOG_SENSOR("", "Voltage", this->voltage_sensor_); LOG_SENSOR("", "Voltage", this->voltage_sensor_);
LOG_SENSOR("", "Current", this->current_sensor_); LOG_SENSOR("", "Current", this->current_sensor_);
LOG_SENSOR("", "Power", this->power_sensor_); LOG_SENSOR("", "Power", this->power_sensor_);
LOG_SENSOR("", "Energy", this->energy_sensor_); LOG_SENSOR("", "Energy", this->energy_sensor_);
LOG_SENSOR("", "frequency", this->frequency_sensor_); LOG_SENSOR("", "Frequency", this->frequency_sensor_);
} }
} // namespace bl0942 } // namespace bl0942

View File

@@ -8,6 +8,57 @@
namespace esphome { namespace esphome {
namespace bl0942 { namespace bl0942 {
// The BL0942 IC is "calibration-free", which means that it doesn't care
// at all about calibration, and that's left to software. It measures a
// voltage differential on its IP/IN pins which linearly proportional to
// the current flow, and another on its VP pin which is proportional to
// the line voltage. It never knows the actual calibration; the values
// it reports are solely in terms of those inputs.
//
// The datasheet refers to the input voltages as I(A) and V(V), both
// in millivolts. It measures them against a reference voltage Vref,
// which is typically 1.218V (but that absolute value is meaningless
// without the actual calibration anyway).
//
// The reported I_RMS value is 305978 I(A)/Vref, and the reported V_RMS
// value is 73989 V(V)/Vref. So we can calibrate those by applying a
// simple meter with a resistive load.
//
// The chip also measures the phase difference between voltage and
// current, and uses it to calculate the power factor (cos φ). It
// reports the WATT value of 3537 * I_RMS * V_RMS * cos φ).
//
// It also integrates total energy based on the WATT value. The time for
// one CF_CNT pulse is 1638.4*256 / WATT.
//
// So... how do we calibrate that?
//
// Using a simple resistive load and an external meter, we can measure
// the true voltage and current for a given V_RMS and I_RMS reading,
// to calculate BL0942_UREF and BL0942_IREF. Those are in units of
// "305978 counts per amp" or "73989 counts per volt" respectively.
//
// We can derive BL0942_PREF from those. Let's eliminate the weird
// factors and express the calibration in plain counts per volt/amp:
// UREF1 = UREF/73989, IREF1 = IREF/305978.
//
// Next... the true power in Watts is V * I * cos φ, so that's equal
// to WATT/3537 * IREF1 * UREF1. Which means
// BL0942_PREF = BL0942_UREF * BL0942_IREF * 3537 / 305978 / 73989.
//
// Finally the accumulated energy. The period of a CF_CNT count is
// 1638.4*256 / WATT seconds, or 419230.4 / WATT seconds. Which means
// the energy represented by a CN_CNT pulse is 419230.4 WATT-seconds.
// Factoring in the calibration, that's 419230.4 / BL0942_PREF actual
// Watt-seconds (or Joules, as the physicists like to call them).
//
// But we're not being physicists today; we we're being engineers, so
// we want to convert to kWh instead. Which we do by dividing by 1000
// and then by 3600, so the energy in kWh is
// CF_CNT * 419230.4 / BL0942_PREF / 3600000
//
// Which makes BL0952_EREF = BL0942_PREF * 3600000 / 419430.4
static const float BL0942_PREF = 596; // taken from tasmota static const float BL0942_PREF = 596; // taken from tasmota
static const float BL0942_UREF = 15873.35944299; // should be 73989/1.218 static const float BL0942_UREF = 15873.35944299; // should be 73989/1.218
static const float BL0942_IREF = 251213.46469622; // 305978/1.218 static const float BL0942_IREF = 251213.46469622; // 305978/1.218
@@ -28,6 +79,11 @@ struct DataPacket {
uint8_t checksum; uint8_t checksum;
} __attribute__((packed)); } __attribute__((packed));
enum LineFrequency : uint8_t {
LINE_FREQUENCY_50HZ = 50,
LINE_FREQUENCY_60HZ = 60,
};
class BL0942 : public PollingComponent, public uart::UARTDevice { class BL0942 : public PollingComponent, public uart::UARTDevice {
public: public:
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
@@ -35,9 +91,27 @@ class BL0942 : public PollingComponent, public uart::UARTDevice {
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; } void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; } void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; } void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; }
void set_line_freq(LineFrequency freq) { this->line_freq_ = freq; }
void set_address(uint8_t address) { this->address_ = address; }
void set_reset(bool reset) { this->reset_ = reset; }
void set_current_reference(float current_ref) {
this->current_reference_ = current_ref;
this->current_reference_set_ = true;
}
void set_energy_reference(float energy_ref) {
this->energy_reference_ = energy_ref;
this->energy_reference_set_ = true;
}
void set_power_reference(float power_ref) {
this->power_reference_ = power_ref;
this->power_reference_set_ = true;
}
void set_voltage_reference(float voltage_ref) {
this->voltage_reference_ = voltage_ref;
this->voltage_reference_set_ = true;
}
void loop() override; void loop() override;
void update() override; void update() override;
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
@@ -53,15 +127,25 @@ class BL0942 : public PollingComponent, public uart::UARTDevice {
// Divide by this to turn into Watt // Divide by this to turn into Watt
float power_reference_ = BL0942_PREF; float power_reference_ = BL0942_PREF;
bool power_reference_set_ = false;
// Divide by this to turn into Volt // Divide by this to turn into Volt
float voltage_reference_ = BL0942_UREF; float voltage_reference_ = BL0942_UREF;
bool voltage_reference_set_ = false;
// Divide by this to turn into Ampere // Divide by this to turn into Ampere
float current_reference_ = BL0942_IREF; float current_reference_ = BL0942_IREF;
bool current_reference_set_ = false;
// Divide by this to turn into kWh // Divide by this to turn into kWh
float energy_reference_ = BL0942_EREF; float energy_reference_ = BL0942_EREF;
bool energy_reference_set_ = false;
uint8_t address_ = 0;
bool reset_ = false;
LineFrequency line_freq_ = LINE_FREQUENCY_50HZ;
uint32_t rx_start_ = 0;
uint32_t prev_cf_cnt_ = 0;
static bool validate_checksum(DataPacket *data); bool validate_checksum_(DataPacket *data);
int read_reg_(uint8_t reg);
void write_reg_(uint8_t reg, uint32_t val);
void received_package_(DataPacket *data); void received_package_(DataPacket *data);
}; };
} // namespace bl0942 } // namespace bl0942

View File

@@ -1,32 +1,46 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, uart from esphome.components import sensor, uart
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ADDRESS,
CONF_CURRENT, CONF_CURRENT,
CONF_ENERGY, CONF_ENERGY,
CONF_FREQUENCY,
CONF_ID, CONF_ID,
CONF_LINE_FREQUENCY,
CONF_POWER, CONF_POWER,
CONF_VOLTAGE, CONF_VOLTAGE,
CONF_FREQUENCY,
DEVICE_CLASS_CURRENT, DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_POWER, DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_FREQUENCY,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE, UNIT_AMPERE,
UNIT_HERTZ,
UNIT_KILOWATT_HOURS, UNIT_KILOWATT_HOURS,
UNIT_VOLT, UNIT_VOLT,
UNIT_WATT, UNIT_WATT,
UNIT_HERTZ,
STATE_CLASS_TOTAL_INCREASING,
) )
CONF_CURRENT_REFERENCE = "current_reference"
CONF_ENERGY_REFERENCE = "energy_reference"
CONF_POWER_REFERENCE = "power_reference"
CONF_RESET = "reset"
CONF_VOLTAGE_REFERENCE = "voltage_reference"
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
bl0942_ns = cg.esphome_ns.namespace("bl0942") bl0942_ns = cg.esphome_ns.namespace("bl0942")
BL0942 = bl0942_ns.class_("BL0942", cg.PollingComponent, uart.UARTDevice) BL0942 = bl0942_ns.class_("BL0942", cg.PollingComponent, uart.UARTDevice)
LineFrequency = bl0942_ns.enum("LineFrequency")
LINE_FREQS = {
50: LineFrequency.LINE_FREQUENCY_50HZ,
60: LineFrequency.LINE_FREQUENCY_60HZ,
}
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
cv.Schema( cv.Schema(
{ {
@@ -45,22 +59,35 @@ CONFIG_SCHEMA = (
), ),
cv.Optional(CONF_POWER): sensor.sensor_schema( cv.Optional(CONF_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT, unit_of_measurement=UNIT_WATT,
accuracy_decimals=0, accuracy_decimals=1,
device_class=DEVICE_CLASS_POWER, device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
), ),
cv.Optional(CONF_ENERGY): sensor.sensor_schema( cv.Optional(CONF_ENERGY): sensor.sensor_schema(
unit_of_measurement=UNIT_KILOWATT_HOURS, unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=0, accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY, device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING, state_class=STATE_CLASS_TOTAL_INCREASING,
), ),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
unit_of_measurement=UNIT_HERTZ, unit_of_measurement=UNIT_HERTZ,
accuracy_decimals=0, accuracy_decimals=2,
device_class=DEVICE_CLASS_FREQUENCY, device_class=DEVICE_CLASS_FREQUENCY,
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
), ),
cv.Optional(CONF_LINE_FREQUENCY, default="50HZ"): cv.All(
cv.frequency,
cv.enum(
LINE_FREQS,
int=True,
),
),
cv.Optional(CONF_ADDRESS, default=0): cv.int_range(min=0, max=3),
cv.Optional(CONF_RESET, default=True): cv.boolean,
cv.Optional(CONF_CURRENT_REFERENCE): cv.float_,
cv.Optional(CONF_ENERGY_REFERENCE): cv.float_,
cv.Optional(CONF_POWER_REFERENCE): cv.float_,
cv.Optional(CONF_VOLTAGE_REFERENCE): cv.float_,
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
@@ -88,3 +115,14 @@ async def to_code(config):
if frequency_config := config.get(CONF_FREQUENCY): if frequency_config := config.get(CONF_FREQUENCY):
sens = await sensor.new_sensor(frequency_config) sens = await sensor.new_sensor(frequency_config)
cg.add(var.set_frequency_sensor(sens)) cg.add(var.set_frequency_sensor(sens))
cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
cg.add(var.set_address(config[CONF_ADDRESS]))
cg.add(var.set_reset(config[CONF_RESET]))
if (current_reference := config.get(CONF_CURRENT_REFERENCE, None)) is not None:
cg.add(var.set_current_reference(current_reference))
if (voltage_reference := config.get(CONF_VOLTAGE_REFERENCE, None)) is not None:
cg.add(var.set_voltage_reference(voltage_reference))
if (power_reference := config.get(CONF_POWER_REFERENCE, None)) is not None:
cg.add(var.set_power_reference(power_reference))
if (energy_reference := config.get(CONF_ENERGY_REFERENCE, None)) is not None:
cg.add(var.set_energy_reference(energy_reference))

View File

@@ -1,7 +1,8 @@
import esphome.codegen as cg from esphome import automation
import esphome.config_validation as cv
from esphome.automation import maybe_simple_id from esphome.automation import maybe_simple_id
from esphome.components import esp32_ble_tracker, esp32_ble_client import esphome.codegen as cg
from esphome.components import esp32_ble_client, esp32_ble_tracker
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_CHARACTERISTIC_UUID, CONF_CHARACTERISTIC_UUID,
CONF_ID, CONF_ID,
@@ -13,7 +14,6 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_VALUE, CONF_VALUE,
) )
from esphome import automation
AUTO_LOAD = ["esp32_ble_client"] AUTO_LOAD = ["esp32_ble_client"]
CODEOWNERS = ["@buxtronix", "@clydebarrow"] CODEOWNERS = ["@buxtronix", "@clydebarrow"]
@@ -65,9 +65,7 @@ CONF_ON_PASSKEY_NOTIFICATION = "on_passkey_notification"
CONF_ON_NUMERIC_COMPARISON_REQUEST = "on_numeric_comparison_request" CONF_ON_NUMERIC_COMPARISON_REQUEST = "on_numeric_comparison_request"
CONF_AUTO_CONNECT = "auto_connect" CONF_AUTO_CONNECT = "auto_connect"
# Espressif platformio framework is built with MAX_BLE_CONN to 3, so MULTI_CONF = True
# enforce this in yaml checks.
MULTI_CONF = 3
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
cv.Schema( cv.Schema(

View File

@@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import ble_client, esp32_ble_tracker, output from esphome.components import ble_client, esp32_ble_tracker, output
import esphome.config_validation as cv
from esphome.const import CONF_CHARACTERISTIC_UUID, CONF_ID, CONF_SERVICE_UUID from esphome.const import CONF_CHARACTERISTIC_UUID, CONF_ID, CONF_SERVICE_UUID
from .. import ble_client_ns from .. import ble_client_ns

View File

@@ -1,17 +1,18 @@
from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, esp32_ble_tracker, sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor, ble_client, esp32_ble_tracker
from esphome.const import ( from esphome.const import (
CONF_CHARACTERISTIC_UUID, CONF_CHARACTERISTIC_UUID,
CONF_LAMBDA, CONF_LAMBDA,
CONF_SERVICE_UUID,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_TYPE, CONF_TYPE,
CONF_SERVICE_UUID,
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_SIGNAL_STRENGTH,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_DECIBEL_MILLIWATT, UNIT_DECIBEL_MILLIWATT,
) )
from esphome import automation
from .. import ble_client_ns from .. import ble_client_ns
DEPENDENCIES = ["ble_client"] DEPENDENCIES = ["ble_client"]

View File

@@ -1,7 +1,8 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, switch
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import switch, ble_client
from esphome.const import ICON_BLUETOOTH from esphome.const import ICON_BLUETOOTH
from .. import ble_client_ns from .. import ble_client_ns
BLEClientSwitch = ble_client_ns.class_( BLEClientSwitch = ble_client_ns.class_(

View File

@@ -1,13 +1,14 @@
from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, esp32_ble_tracker, text_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import text_sensor, ble_client, esp32_ble_tracker
from esphome.const import ( from esphome.const import (
CONF_CHARACTERISTIC_UUID, CONF_CHARACTERISTIC_UUID,
CONF_ID, CONF_ID,
CONF_TRIGGER_ID,
CONF_SERVICE_UUID, CONF_SERVICE_UUID,
CONF_TRIGGER_ID,
) )
from esphome import automation
from .. import ble_client_ns from .. import ble_client_ns
DEPENDENCIES = ["ble_client"] DEPENDENCIES = ["ble_client"]

View File

@@ -1,13 +1,13 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor, esp32_ble_tracker from esphome.components import binary_sensor, esp32_ble_tracker
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_MAC_ADDRESS,
CONF_SERVICE_UUID,
CONF_IBEACON_MAJOR, CONF_IBEACON_MAJOR,
CONF_IBEACON_MINOR, CONF_IBEACON_MINOR,
CONF_IBEACON_UUID, CONF_IBEACON_UUID,
CONF_MAC_ADDRESS,
CONF_MIN_RSSI, CONF_MIN_RSSI,
CONF_SERVICE_UUID,
CONF_TIMEOUT, CONF_TIMEOUT,
) )

View File

@@ -1,12 +1,12 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32_ble_tracker, sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor, esp32_ble_tracker
from esphome.const import ( from esphome.const import (
CONF_IBEACON_MAJOR, CONF_IBEACON_MAJOR,
CONF_IBEACON_MINOR, CONF_IBEACON_MINOR,
CONF_IBEACON_UUID, CONF_IBEACON_UUID,
CONF_SERVICE_UUID,
CONF_MAC_ADDRESS, CONF_MAC_ADDRESS,
CONF_SERVICE_UUID,
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_SIGNAL_STRENGTH,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_DECIBEL_MILLIWATT, UNIT_DECIBEL_MILLIWATT,

View File

@@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32_ble_tracker, text_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import text_sensor, esp32_ble_tracker
DEPENDENCIES = ["esp32_ble_tracker"] DEPENDENCIES = ["esp32_ble_tracker"]

View File

@@ -1,8 +1,8 @@
from esphome.components import esp32_ble_tracker, esp32_ble_client
import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome.const import CONF_ACTIVE, CONF_ID from esphome.components import esp32_ble_client, esp32_ble_tracker
from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32 import add_idf_sdkconfig_option
import esphome.config_validation as cv
from esphome.const import CONF_ACTIVE, CONF_ID
AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"] AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
DEPENDENCIES = ["api", "esp32"] DEPENDENCIES = ["api", "esp32"]

View File

@@ -54,6 +54,9 @@ bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_p
} }
resp.advertisements.push_back(std::move(adv)); resp.advertisements.push_back(std::move(adv));
ESP_LOGV(TAG, "Proxying raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0],
result.bda[1], result.bda[2], result.bda[3], result.bda[4], result.bda[5], length, result.rssi);
} }
ESP_LOGV(TAG, "Proxying %d packets", count); ESP_LOGV(TAG, "Proxying %d packets", count);
this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp); this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp);
@@ -87,6 +90,8 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi
void BluetoothProxy::dump_config() { void BluetoothProxy::dump_config() {
ESP_LOGCONFIG(TAG, "Bluetooth Proxy:"); ESP_LOGCONFIG(TAG, "Bluetooth Proxy:");
ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_)); ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_));
ESP_LOGCONFIG(TAG, " Connections: %d", this->connections_.size());
ESP_LOGCONFIG(TAG, " Raw advertisements: %s", YESNO(this->raw_advertisements_));
} }
int BluetoothProxy::get_bluetooth_connections_free() { int BluetoothProxy::get_bluetooth_connections_free() {

View File

@@ -1,7 +1,7 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import i2c, esp32 from esphome.components import i2c, esp32
from esphome.const import CONF_ID, CONF_TEMPERATURE_OFFSET from esphome.const import CONF_ID, CONF_SAMPLE_RATE, CONF_TEMPERATURE_OFFSET
CODEOWNERS = ["@trvrnrth"] CODEOWNERS = ["@trvrnrth"]
DEPENDENCIES = ["i2c"] DEPENDENCIES = ["i2c"]
@@ -11,7 +11,6 @@ MULTI_CONF = True
CONF_BME680_BSEC_ID = "bme680_bsec_id" CONF_BME680_BSEC_ID = "bme680_bsec_id"
CONF_IAQ_MODE = "iaq_mode" CONF_IAQ_MODE = "iaq_mode"
CONF_SUPPLY_VOLTAGE = "supply_voltage" CONF_SUPPLY_VOLTAGE = "supply_voltage"
CONF_SAMPLE_RATE = "sample_rate"
CONF_STATE_SAVE_INTERVAL = "state_save_interval" CONF_STATE_SAVE_INTERVAL = "state_save_interval"
bme680_bsec_ns = cg.esphome_ns.namespace("bme680_bsec") bme680_bsec_ns = cg.esphome_ns.namespace("bme680_bsec")

View File

@@ -4,33 +4,33 @@ from esphome.components import sensor
from esphome.const import ( from esphome.const import (
CONF_GAS_RESISTANCE, CONF_GAS_RESISTANCE,
CONF_HUMIDITY, CONF_HUMIDITY,
CONF_IAQ_ACCURACY,
CONF_PRESSURE, CONF_PRESSURE,
CONF_SAMPLE_RATE,
CONF_TEMPERATURE, CONF_TEMPERATURE,
DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CARBON_DIOXIDE,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
ICON_GAS_CYLINDER,
ICON_GAUGE,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS, UNIT_CELSIUS,
UNIT_HECTOPASCAL, UNIT_HECTOPASCAL,
UNIT_OHM, UNIT_OHM,
UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_MILLION,
UNIT_PERCENT, UNIT_PERCENT,
ICON_GAS_CYLINDER,
ICON_GAUGE,
) )
from . import ( from . import (
BME680BSECComponent, BME680BSECComponent,
CONF_BME680_BSEC_ID, CONF_BME680_BSEC_ID,
CONF_SAMPLE_RATE,
SAMPLE_RATE_OPTIONS, SAMPLE_RATE_OPTIONS,
) )
DEPENDENCIES = ["bme680_bsec"] DEPENDENCIES = ["bme680_bsec"]
CONF_IAQ = "iaq" CONF_IAQ = "iaq"
CONF_IAQ_ACCURACY = "iaq_accuracy"
CONF_CO2_EQUIVALENT = "co2_equivalent" CONF_CO2_EQUIVALENT = "co2_equivalent"
CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent" CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent"
UNIT_IAQ = "IAQ" UNIT_IAQ = "IAQ"

View File

@@ -1,11 +1,11 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import text_sensor from esphome.components import text_sensor
from esphome.const import CONF_IAQ_ACCURACY
from . import BME680BSECComponent, CONF_BME680_BSEC_ID from . import BME680BSECComponent, CONF_BME680_BSEC_ID
DEPENDENCIES = ["bme680_bsec"] DEPENDENCIES = ["bme680_bsec"]
CONF_IAQ_ACCURACY = "iaq_accuracy"
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
TYPES = [CONF_IAQ_ACCURACY] TYPES = [CONF_IAQ_ACCURACY]

View File

@@ -0,0 +1,196 @@
import hashlib
from pathlib import Path
from esphome import core, external_files
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import (
CONF_ID,
CONF_MODEL,
CONF_RAW_DATA_ID,
CONF_SAMPLE_RATE,
CONF_TEMPERATURE_OFFSET,
)
CODEOWNERS = ["@neffs", "@kbx81"]
DOMAIN = "bme68x_bsec2"
BSEC2_LIBRARY_VERSION = "v1.7.2502"
CONF_ALGORITHM_OUTPUT = "algorithm_output"
CONF_BME68X_BSEC2_ID = "bme68x_bsec2_id"
CONF_IAQ_MODE = "iaq_mode"
CONF_OPERATING_AGE = "operating_age"
CONF_STATE_SAVE_INTERVAL = "state_save_interval"
CONF_SUPPLY_VOLTAGE = "supply_voltage"
bme68x_bsec2_ns = cg.esphome_ns.namespace("bme68x_bsec2")
BME68xBSEC2Component = bme68x_bsec2_ns.class_("BME68xBSEC2Component", cg.Component)
MODEL_OPTIONS = ["bme680", "bme688"]
AlgorithmOutput = bme68x_bsec2_ns.enum("AlgorithmOutput")
ALGORITHM_OUTPUT_OPTIONS = {
"classification": AlgorithmOutput.ALGORITHM_OUTPUT_CLASSIFICATION,
"regression": AlgorithmOutput.ALGORITHM_OUTPUT_REGRESSION,
}
OperatingAge = bme68x_bsec2_ns.enum("OperatingAge")
OPERATING_AGE_OPTIONS = {
"4d": OperatingAge.OPERATING_AGE_4D,
"28d": OperatingAge.OPERATING_AGE_28D,
}
SampleRate = bme68x_bsec2_ns.enum("SampleRate")
SAMPLE_RATE_OPTIONS = {
"LP": SampleRate.SAMPLE_RATE_LP,
"ULP": SampleRate.SAMPLE_RATE_ULP,
}
Voltage = bme68x_bsec2_ns.enum("Voltage")
VOLTAGE_OPTIONS = {
"1.8V": Voltage.VOLTAGE_1_8V,
"3.3V": Voltage.VOLTAGE_3_3V,
}
ALGORITHM_OUTPUT_FILE_NAME = {
"classification": "sel",
"regression": "reg",
}
SAMPLE_RATE_FILE_NAME = {
"LP": "3s",
"ULP": "300s",
}
VOLTAGE_FILE_NAME = {
"1.8V": "18v",
"3.3V": "33v",
}
def _compute_local_file_path(url: str) -> Path:
h = hashlib.new("sha256")
h.update(url.encode())
key = h.hexdigest()[:8]
base_dir = external_files.compute_local_file_dir(DOMAIN)
return base_dir / key
def _compute_url(config: dict) -> str:
model = config.get(CONF_MODEL)
operating_age = config.get(CONF_OPERATING_AGE)
sample_rate = SAMPLE_RATE_FILE_NAME[config.get(CONF_SAMPLE_RATE)]
volts = VOLTAGE_FILE_NAME[config.get(CONF_SUPPLY_VOLTAGE)]
if model == "bme688":
algo = ALGORITHM_OUTPUT_FILE_NAME[
config.get(CONF_ALGORITHM_OUTPUT, "classification")
]
filename = "bsec_selectivity"
else:
algo = "iaq"
filename = "bsec_iaq"
return f"https://raw.githubusercontent.com/boschsensortec/Bosch-BSEC2-Library/{BSEC2_LIBRARY_VERSION}/src/config/{model}/{model}_{algo}_{volts}_{sample_rate}_{operating_age}/{filename}.txt"
def download_bme68x_blob(config):
url = _compute_url(config)
path = _compute_local_file_path(url)
external_files.download_content(url, path)
return config
def validate_bme68x(config):
if CONF_ALGORITHM_OUTPUT not in config:
return config
if config[CONF_MODEL] != "bme688":
raise cv.Invalid(f"{CONF_ALGORITHM_OUTPUT} is only valid for BME688")
if config[CONF_ALGORITHM_OUTPUT] == "regression" and (
config[CONF_OPERATING_AGE] != "4d"
or config[CONF_SAMPLE_RATE] != "ULP"
or config[CONF_SUPPLY_VOLTAGE] != "1.8V"
):
raise cv.Invalid(
f" To use '{CONF_ALGORITHM_OUTPUT}: regression', {CONF_OPERATING_AGE} must be '4d', {CONF_SAMPLE_RATE} must be 'ULP' and {CONF_SUPPLY_VOLTAGE} must be '1.8V'"
)
return config
CONFIG_SCHEMA_BASE = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BME68xBSEC2Component),
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
cv.Required(CONF_MODEL): cv.one_of(*MODEL_OPTIONS, lower=True),
cv.Optional(CONF_ALGORITHM_OUTPUT): cv.enum(
ALGORITHM_OUTPUT_OPTIONS, lower=True
),
cv.Optional(CONF_OPERATING_AGE, default="28d"): cv.enum(
OPERATING_AGE_OPTIONS, lower=True
),
cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum(
SAMPLE_RATE_OPTIONS, upper=True
),
cv.Optional(CONF_SUPPLY_VOLTAGE, default="3.3V"): cv.enum(
VOLTAGE_OPTIONS, upper=True
),
cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature,
cv.Optional(
CONF_STATE_SAVE_INTERVAL, default="6hours"
): cv.positive_time_period_minutes,
},
)
.add_extra(cv.only_with_arduino)
.add_extra(validate_bme68x)
.add_extra(download_bme68x_blob)
)
async def to_code_base(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
if algo_output := config.get(CONF_ALGORITHM_OUTPUT):
cg.add(var.set_algorithm_output(algo_output))
cg.add(var.set_operating_age(config[CONF_OPERATING_AGE]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))
cg.add(var.set_voltage(config[CONF_SUPPLY_VOLTAGE]))
cg.add(var.set_temperature_offset(config[CONF_TEMPERATURE_OFFSET]))
cg.add(
var.set_state_save_interval(config[CONF_STATE_SAVE_INTERVAL].total_milliseconds)
)
path = _compute_local_file_path(_compute_url(config))
try:
with open(path, encoding="utf-8") as f:
bsec2_iaq_config = f.read()
except Exception as e:
raise core.EsphomeError(f"Could not open binary configuration file {path}: {e}")
# Convert retrieved BSEC2 config to an array of ints
rhs = [int(x) for x in bsec2_iaq_config.split(",")]
# Create an array which will reside in program memory and configure the sensor instance to use it
bsec2_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.add(var.set_bsec2_configuration(bsec2_arr, len(rhs)))
# Although this component does not use SPI, the BSEC2 library requires the SPI library
cg.add_library("SPI", None)
cg.add_library(
"BME68x Sensor library",
"1.1.40407",
)
cg.add_library(
"BSEC2 Software Library",
None,
f"https://github.com/boschsensortec/Bosch-BSEC2-Library.git#{BSEC2_LIBRARY_VERSION}",
)
cg.add_define("USE_BSEC2")
return var

View File

@@ -0,0 +1,523 @@
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifdef USE_BSEC2
#include "bme68x_bsec2.h"
#include <string>
namespace esphome {
namespace bme68x_bsec2 {
#define BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(a) (a == ALGORITHM_OUTPUT_CLASSIFICATION ? "Classification" : "Regression")
#define BME68X_BSEC2_OPERATING_AGE_LOG(o) (o == OPERATING_AGE_4D ? "4 days" : "28 days")
#define BME68X_BSEC2_SAMPLE_RATE_LOG(r) (r == SAMPLE_RATE_DEFAULT ? "Default" : (r == SAMPLE_RATE_ULP ? "ULP" : "LP"))
#define BME68X_BSEC2_VOLTAGE_LOG(v) (v == VOLTAGE_3_3V ? "3.3V" : "1.8V")
static const char *const TAG = "bme68x_bsec2.sensor";
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
void BME68xBSEC2Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up BME68X via BSEC2...");
this->bsec_status_ = bsec_init_m(&this->bsec_instance_);
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
ESP_LOGE(TAG, "bsec_init_m failed: status %d", this->bsec_status_);
return;
}
bsec_get_version_m(&this->bsec_instance_, &this->version_);
this->bme68x_status_ = bme68x_init(&this->bme68x_);
if (this->bme68x_status_ != BME68X_OK) {
this->mark_failed();
ESP_LOGE(TAG, "bme68x_init failed: status %d", this->bme68x_status_);
return;
}
if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) {
this->set_config_(this->bsec2_configuration_, this->bsec2_configuration_length_);
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
ESP_LOGE(TAG, "bsec_set_configuration_m failed: status %d", this->bsec_status_);
return;
}
}
this->update_subscription_();
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
ESP_LOGE(TAG, "bsec_update_subscription_m failed: status %d", this->bsec_status_);
return;
}
this->load_state_();
}
void BME68xBSEC2Component::dump_config() {
ESP_LOGCONFIG(TAG, "BME68X via BSEC2:");
ESP_LOGCONFIG(TAG, " BSEC2 version: %d.%d.%d.%d", this->version_.major, this->version_.minor,
this->version_.major_bugfix, this->version_.minor_bugfix);
ESP_LOGCONFIG(TAG, " BSEC2 configuration blob:");
ESP_LOGCONFIG(TAG, " Configured: %s", YESNO(this->bsec2_blob_configured_));
if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) {
ESP_LOGCONFIG(TAG, " Size: %" PRIu32, this->bsec2_configuration_length_);
}
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication failed (BSEC2 status: %d, BME68X status: %d)", this->bsec_status_,
this->bme68x_status_);
}
if (this->algorithm_output_ != ALGORITHM_OUTPUT_IAQ) {
ESP_LOGCONFIG(TAG, " Algorithm output: %s", BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(this->algorithm_output_));
}
ESP_LOGCONFIG(TAG, " Operating age: %s", BME68X_BSEC2_OPERATING_AGE_LOG(this->operating_age_));
ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->sample_rate_));
ESP_LOGCONFIG(TAG, " Voltage: %s", BME68X_BSEC2_VOLTAGE_LOG(this->voltage_));
ESP_LOGCONFIG(TAG, " State save interval: %ims", this->state_save_interval_ms_);
ESP_LOGCONFIG(TAG, " Temperature offset: %.2f", this->temperature_offset_);
#ifdef USE_SENSOR
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->temperature_sample_rate_));
LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->pressure_sample_rate_));
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->humidity_sample_rate_));
LOG_SENSOR(" ", "Gas resistance", this->gas_resistance_sensor_);
LOG_SENSOR(" ", "CO2 equivalent", this->co2_equivalent_sensor_);
LOG_SENSOR(" ", "Breath VOC equivalent", this->breath_voc_equivalent_sensor_);
LOG_SENSOR(" ", "IAQ", this->iaq_sensor_);
LOG_SENSOR(" ", "IAQ static", this->iaq_static_sensor_);
LOG_SENSOR(" ", "Numeric IAQ accuracy", this->iaq_accuracy_sensor_);
#endif
#ifdef USE_TEXT_SENSOR
LOG_TEXT_SENSOR(" ", "IAQ accuracy", this->iaq_accuracy_text_sensor_);
#endif
}
float BME68xBSEC2Component::get_setup_priority() const { return setup_priority::DATA; }
void BME68xBSEC2Component::loop() {
this->run_();
if (this->bsec_status_ < BSEC_OK || this->bme68x_status_ < BME68X_OK) {
this->status_set_error();
} else {
this->status_clear_error();
}
if (this->bsec_status_ > BSEC_OK || this->bme68x_status_ > BME68X_OK) {
this->status_set_warning();
} else {
this->status_clear_warning();
}
// Process a single action from the queue. These are primarily sensor state publishes
// that in totality take too long to send in a single call.
if (this->queue_.size()) {
auto action = std::move(this->queue_.front());
this->queue_.pop();
action();
}
}
void BME68xBSEC2Component::set_config_(const uint8_t *config, uint32_t len) {
if (len > BSEC_MAX_PROPERTY_BLOB_SIZE) {
ESP_LOGE(TAG, "Configuration is larger than BSEC_MAX_PROPERTY_BLOB_SIZE");
this->mark_failed();
return;
}
uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
this->bsec_status_ = bsec_set_configuration_m(&this->bsec_instance_, config, len, work_buffer, sizeof(work_buffer));
if (this->bsec_status_ == BSEC_OK) {
this->bsec2_blob_configured_ = true;
}
}
float BME68xBSEC2Component::calc_sensor_sample_rate_(SampleRate sample_rate) {
if (sample_rate == SAMPLE_RATE_DEFAULT) {
sample_rate = this->sample_rate_;
}
return sample_rate == SAMPLE_RATE_ULP ? BSEC_SAMPLE_RATE_ULP : BSEC_SAMPLE_RATE_LP;
}
void BME68xBSEC2Component::update_subscription_() {
bsec_sensor_configuration_t virtual_sensors[BSEC_NUMBER_OUTPUTS];
uint8_t num_virtual_sensors = 0;
#ifdef USE_SENSOR
if (this->iaq_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_IAQ;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
num_virtual_sensors++;
}
if (this->iaq_static_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
num_virtual_sensors++;
}
if (this->co2_equivalent_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
num_virtual_sensors++;
}
if (this->breath_voc_equivalent_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
num_virtual_sensors++;
}
if (this->pressure_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->pressure_sample_rate_);
num_virtual_sensors++;
}
if (this->gas_resistance_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_GAS;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
num_virtual_sensors++;
}
if (this->temperature_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->temperature_sample_rate_);
num_virtual_sensors++;
}
if (this->humidity_sensor_) {
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->humidity_sample_rate_);
num_virtual_sensors++;
}
#endif
bsec_sensor_configuration_t sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
uint8_t num_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
this->bsec_status_ = bsec_update_subscription_m(&this->bsec_instance_, virtual_sensors, num_virtual_sensors,
sensor_settings, &num_sensor_settings);
}
void BME68xBSEC2Component::run_() {
int64_t curr_time_ns = this->get_time_ns_();
if (curr_time_ns < this->next_call_ns_) {
return;
}
this->op_mode_ = this->bsec_settings_.op_mode;
uint8_t status;
ESP_LOGV(TAG, "Performing sensor run");
struct bme68x_conf bme68x_conf;
this->bsec_status_ = bsec_sensor_control_m(&this->bsec_instance_, curr_time_ns, &this->bsec_settings_);
if (this->bsec_status_ < BSEC_OK) {
ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC2 error code %d)", this->bsec_status_);
return;
}
this->next_call_ns_ = this->bsec_settings_.next_call;
if (this->bsec_settings_.trigger_measurement) {
bme68x_get_conf(&bme68x_conf, &this->bme68x_);
bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling;
bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling;
bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling;
bme68x_set_conf(&bme68x_conf, &this->bme68x_);
switch (this->bsec_settings_.op_mode) {
case BME68X_FORCED_MODE:
this->bme68x_heatr_conf_.enable = BME68X_ENABLE;
this->bme68x_heatr_conf_.heatr_temp = this->bsec_settings_.heater_temperature;
this->bme68x_heatr_conf_.heatr_dur = this->bsec_settings_.heater_duration;
status = bme68x_set_op_mode(this->bsec_settings_.op_mode, &this->bme68x_);
status = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &this->bme68x_heatr_conf_, &this->bme68x_);
status = bme68x_set_op_mode(BME68X_FORCED_MODE, &this->bme68x_);
this->op_mode_ = BME68X_FORCED_MODE;
this->sleep_mode_ = false;
ESP_LOGV(TAG, "Using forced mode");
break;
case BME68X_PARALLEL_MODE:
if (this->op_mode_ != this->bsec_settings_.op_mode) {
this->bme68x_heatr_conf_.enable = BME68X_ENABLE;
this->bme68x_heatr_conf_.heatr_temp_prof = this->bsec_settings_.heater_temperature_profile;
this->bme68x_heatr_conf_.heatr_dur_prof = this->bsec_settings_.heater_duration_profile;
this->bme68x_heatr_conf_.profile_len = this->bsec_settings_.heater_profile_len;
this->bme68x_heatr_conf_.shared_heatr_dur =
BSEC_TOTAL_HEAT_DUR -
(bme68x_get_meas_dur(BME68X_PARALLEL_MODE, &bme68x_conf, &this->bme68x_) / INT64_C(1000));
status = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &this->bme68x_heatr_conf_, &this->bme68x_);
status = bme68x_set_op_mode(BME68X_PARALLEL_MODE, &this->bme68x_);
this->op_mode_ = BME68X_PARALLEL_MODE;
this->sleep_mode_ = false;
ESP_LOGV(TAG, "Using parallel mode");
}
break;
case BME68X_SLEEP_MODE:
if (!this->sleep_mode_) {
bme68x_set_op_mode(BME68X_SLEEP_MODE, &this->bme68x_);
this->sleep_mode_ = true;
ESP_LOGV(TAG, "Using sleep mode");
}
break;
}
uint32_t meas_dur = 0;
meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_);
ESP_LOGV(TAG, "Queueing read in %uus", meas_dur);
this->set_timeout("read", meas_dur / 1000, [this, curr_time_ns]() { this->read_(curr_time_ns); });
} else {
ESP_LOGV(TAG, "Measurement not required");
this->read_(curr_time_ns);
}
}
void BME68xBSEC2Component::read_(int64_t trigger_time_ns) {
ESP_LOGV(TAG, "Reading data");
if (this->bsec_settings_.trigger_measurement) {
uint8_t current_op_mode;
this->bme68x_status_ = bme68x_get_op_mode(&current_op_mode, &this->bme68x_);
if (current_op_mode == BME68X_SLEEP_MODE) {
ESP_LOGV(TAG, "Still in sleep mode, doing nothing");
return;
}
}
if (!this->bsec_settings_.process_data) {
ESP_LOGV(TAG, "Data processing not required");
return;
}
struct bme68x_data data[3];
uint8_t nFields = 0;
this->bme68x_status_ = bme68x_get_data(this->op_mode_, &data[0], &nFields, &this->bme68x_);
if (this->bme68x_status_ != BME68X_OK) {
ESP_LOGW(TAG, "Failed to get sensor data (BME68X error code %d)", this->bme68x_status_);
return;
}
if (nFields < 1) {
ESP_LOGD(TAG, "BME68X did not provide new data");
return;
}
for (uint8_t i = 0; i < nFields; i++) {
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance
uint8_t num_inputs = 0;
if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_TEMPERATURE)) {
inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
inputs[num_inputs].signal = data[i].temperature;
inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++;
}
if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_HEATSOURCE)) {
inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
inputs[num_inputs].signal = this->temperature_offset_;
inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++;
}
if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_HUMIDITY)) {
inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
inputs[num_inputs].signal = data[i].humidity;
inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++;
}
if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_PRESSURE)) {
inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE;
inputs[num_inputs].signal = data[i].pressure;
inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++;
}
if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_GASRESISTOR)) {
if (data[i].status & BME68X_GASM_VALID_MSK) {
inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
inputs[num_inputs].signal = data[i].gas_resistance;
inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++;
} else {
ESP_LOGD(TAG, "BME68X did not report gas data");
}
}
if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_PROFILE_PART) &&
(data[i].status & BME68X_GASM_VALID_MSK)) {
inputs[num_inputs].sensor_id = BSEC_INPUT_PROFILE_PART;
inputs[num_inputs].signal = (this->op_mode_ == BME68X_FORCED_MODE) ? 0 : data[i].gas_index;
inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++;
}
if (num_inputs < 1) {
ESP_LOGD(TAG, "No signal inputs available for BSEC2");
return;
}
bsec_output_t outputs[BSEC_NUMBER_OUTPUTS];
uint8_t num_outputs = BSEC_NUMBER_OUTPUTS;
this->bsec_status_ = bsec_do_steps_m(&this->bsec_instance_, inputs, num_inputs, outputs, &num_outputs);
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "BSEC2 failed to process signals (BSEC2 error code %d)", this->bsec_status_);
return;
}
if (num_outputs < 1) {
ESP_LOGD(TAG, "No signal outputs provided by BSEC2");
return;
}
this->publish_(outputs, num_outputs);
}
}
void BME68xBSEC2Component::publish_(const bsec_output_t *outputs, uint8_t num_outputs) {
ESP_LOGV(TAG, "Publishing sensor states");
bool update_accuracy = false;
uint8_t max_accuracy = 0;
for (uint8_t i = 0; i < num_outputs; i++) {
float signal = outputs[i].signal;
switch (outputs[i].sensor_id) {
case BSEC_OUTPUT_IAQ:
max_accuracy = std::max(outputs[i].accuracy, max_accuracy);
update_accuracy = true;
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_sensor_, signal); });
#endif
break;
case BSEC_OUTPUT_STATIC_IAQ:
max_accuracy = std::max(outputs[i].accuracy, max_accuracy);
update_accuracy = true;
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_static_sensor_, signal); });
#endif
break;
case BSEC_OUTPUT_CO2_EQUIVALENT:
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->co2_equivalent_sensor_, signal); });
#endif
break;
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->breath_voc_equivalent_sensor_, signal); });
#endif
break;
case BSEC_OUTPUT_RAW_PRESSURE:
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->pressure_sensor_, signal / 100.0f); });
#endif
break;
case BSEC_OUTPUT_RAW_GAS:
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->gas_resistance_sensor_, signal); });
#endif
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->temperature_sensor_, signal); });
#endif
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
#ifdef USE_SENSOR
this->queue_push_([this, signal]() { this->publish_sensor_(this->humidity_sensor_, signal); });
#endif
break;
}
}
if (update_accuracy) {
#ifdef USE_SENSOR
this->queue_push_(
[this, max_accuracy]() { this->publish_sensor_(this->iaq_accuracy_sensor_, max_accuracy, true); });
#endif
#ifdef USE_TEXT_SENSOR
this->queue_push_([this, max_accuracy]() {
this->publish_sensor_(this->iaq_accuracy_text_sensor_, IAQ_ACCURACY_STATES[max_accuracy]);
});
#endif
// Queue up an opportunity to save state
this->queue_push_([this, max_accuracy]() { this->save_state_(max_accuracy); });
}
}
int64_t BME68xBSEC2Component::get_time_ns_() {
int64_t time_ms = millis();
if (this->last_time_ms_ > time_ms) {
this->millis_overflow_counter_++;
}
this->last_time_ms_ = time_ms;
return (time_ms + ((int64_t) this->millis_overflow_counter_ << 32)) * INT64_C(1000000);
}
#ifdef USE_SENSOR
void BME68xBSEC2Component::publish_sensor_(sensor::Sensor *sensor, float value, bool change_only) {
if (!sensor || (change_only && sensor->has_state() && sensor->state == value)) {
return;
}
sensor->publish_state(value);
}
#endif
#ifdef USE_TEXT_SENSOR
void BME68xBSEC2Component::publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value) {
if (!sensor || (sensor->has_state() && sensor->state == value)) {
return;
}
sensor->publish_state(value);
}
#endif
void BME68xBSEC2Component::load_state_() {
uint32_t hash = this->get_hash();
this->bsec_state_ = global_preferences->make_preference<uint8_t[BSEC_MAX_STATE_BLOB_SIZE]>(hash, true);
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
if (this->bsec_state_.load(&state)) {
ESP_LOGV(TAG, "Loading state");
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
this->bsec_status_ =
bsec_set_state_m(&this->bsec_instance_, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, sizeof(work_buffer));
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "Failed to load state (BSEC2 error code %d)", this->bsec_status_);
}
ESP_LOGI(TAG, "Loaded state");
}
}
void BME68xBSEC2Component::save_state_(uint8_t accuracy) {
if (accuracy < 3 || (millis() - this->last_state_save_ms_ < this->state_save_interval_ms_)) {
return;
}
ESP_LOGV(TAG, "Saving state");
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
uint32_t num_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
this->bsec_status_ = bsec_get_state_m(&this->bsec_instance_, 0, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer,
BSEC_MAX_STATE_BLOB_SIZE, &num_serialized_state);
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "Failed fetch state for save (BSEC2 error code %d)", this->bsec_status_);
return;
}
if (!this->bsec_state_.save(&state)) {
ESP_LOGW(TAG, "Failed to save state");
return;
}
this->last_state_save_ms_ = millis();
ESP_LOGI(TAG, "Saved state");
}
} // namespace bme68x_bsec2
} // namespace esphome
#endif

View File

@@ -0,0 +1,163 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/preferences.h"
#ifdef USE_BSEC2
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
#ifdef USE_TEXT_SENSOR
#include "esphome/components/text_sensor/text_sensor.h"
#endif
#include <cinttypes>
#include <queue>
#include <bsec2.h>
namespace esphome {
namespace bme68x_bsec2 {
enum AlgorithmOutput {
ALGORITHM_OUTPUT_IAQ,
ALGORITHM_OUTPUT_CLASSIFICATION,
ALGORITHM_OUTPUT_REGRESSION,
};
enum OperatingAge {
OPERATING_AGE_4D,
OPERATING_AGE_28D,
};
enum SampleRate {
SAMPLE_RATE_LP = 0,
SAMPLE_RATE_ULP = 1,
SAMPLE_RATE_DEFAULT = 2,
};
enum Voltage {
VOLTAGE_1_8V,
VOLTAGE_3_3V,
};
class BME68xBSEC2Component : public Component {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void loop() override;
void set_algorithm_output(AlgorithmOutput algorithm_output) { this->algorithm_output_ = algorithm_output; }
void set_operating_age(OperatingAge operating_age) { this->operating_age_ = operating_age; }
void set_temperature_offset(float offset) { this->temperature_offset_ = offset; }
void set_voltage(Voltage voltage) { this->voltage_ = voltage; }
void set_sample_rate(SampleRate sample_rate) { this->sample_rate_ = sample_rate; }
void set_temperature_sample_rate(SampleRate sample_rate) { this->temperature_sample_rate_ = sample_rate; }
void set_pressure_sample_rate(SampleRate sample_rate) { this->pressure_sample_rate_ = sample_rate; }
void set_humidity_sample_rate(SampleRate sample_rate) { this->humidity_sample_rate_ = sample_rate; }
void set_bsec2_configuration(const uint8_t *data, const uint32_t len) {
this->bsec2_configuration_ = data;
this->bsec2_configuration_length_ = len;
}
void set_state_save_interval(uint32_t interval) { this->state_save_interval_ms_ = interval; }
#ifdef USE_SENSOR
void set_temperature_sensor(sensor::Sensor *sensor) { this->temperature_sensor_ = sensor; }
void set_pressure_sensor(sensor::Sensor *sensor) { this->pressure_sensor_ = sensor; }
void set_humidity_sensor(sensor::Sensor *sensor) { this->humidity_sensor_ = sensor; }
void set_gas_resistance_sensor(sensor::Sensor *sensor) { this->gas_resistance_sensor_ = sensor; }
void set_iaq_sensor(sensor::Sensor *sensor) { this->iaq_sensor_ = sensor; }
void set_iaq_static_sensor(sensor::Sensor *sensor) { this->iaq_static_sensor_ = sensor; }
void set_iaq_accuracy_sensor(sensor::Sensor *sensor) { this->iaq_accuracy_sensor_ = sensor; }
void set_co2_equivalent_sensor(sensor::Sensor *sensor) { this->co2_equivalent_sensor_ = sensor; }
void set_breath_voc_equivalent_sensor(sensor::Sensor *sensor) { this->breath_voc_equivalent_sensor_ = sensor; }
#endif
#ifdef USE_TEXT_SENSOR
void set_iaq_accuracy_text_sensor(text_sensor::TextSensor *sensor) { this->iaq_accuracy_text_sensor_ = sensor; }
#endif
virtual uint32_t get_hash() = 0;
protected:
void set_config_(const uint8_t *config, u_int32_t len);
float calc_sensor_sample_rate_(SampleRate sample_rate);
void update_subscription_();
void run_();
void read_(int64_t trigger_time_ns);
void publish_(const bsec_output_t *outputs, uint8_t num_outputs);
int64_t get_time_ns_();
#ifdef USE_SENSOR
void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only = false);
#endif
#ifdef USE_TEXT_SENSOR
void publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value);
#endif
void load_state_();
void save_state_(uint8_t accuracy);
void queue_push_(std::function<void()> &&f) { this->queue_.push(std::move(f)); }
struct bme68x_dev bme68x_;
bsec_bme_settings_t bsec_settings_;
bsec_version_t version_;
uint8_t bsec_instance_[BSEC_INSTANCE_SIZE];
struct bme68x_heatr_conf bme68x_heatr_conf_;
uint8_t op_mode_; // operating mode of sensor
bool sleep_mode_;
bsec_library_return_t bsec_status_{BSEC_OK};
int8_t bme68x_status_{BME68X_OK};
int64_t last_time_ms_{0};
uint32_t millis_overflow_counter_{0};
int64_t next_call_ns_{0};
std::queue<std::function<void()>> queue_;
uint8_t const *bsec2_configuration_{nullptr};
uint32_t bsec2_configuration_length_{0};
bool bsec2_blob_configured_{false};
ESPPreferenceObject bsec_state_;
uint32_t state_save_interval_ms_{21600000}; // 6 hours - 4 times a day
uint32_t last_state_save_ms_ = 0;
float temperature_offset_{0};
AlgorithmOutput algorithm_output_{ALGORITHM_OUTPUT_IAQ};
OperatingAge operating_age_{OPERATING_AGE_28D};
Voltage voltage_{VOLTAGE_3_3V};
SampleRate sample_rate_{SAMPLE_RATE_LP}; // Core/gas sample rate
SampleRate temperature_sample_rate_{SAMPLE_RATE_DEFAULT};
SampleRate pressure_sample_rate_{SAMPLE_RATE_DEFAULT};
SampleRate humidity_sample_rate_{SAMPLE_RATE_DEFAULT};
#ifdef USE_SENSOR
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
sensor::Sensor *gas_resistance_sensor_{nullptr};
sensor::Sensor *iaq_sensor_{nullptr};
sensor::Sensor *iaq_static_sensor_{nullptr};
sensor::Sensor *iaq_accuracy_sensor_{nullptr};
sensor::Sensor *co2_equivalent_sensor_{nullptr};
sensor::Sensor *breath_voc_equivalent_sensor_{nullptr};
#endif
#ifdef USE_TEXT_SENSOR
text_sensor::TextSensor *iaq_accuracy_text_sensor_{nullptr};
#endif
};
} // namespace bme68x_bsec2
} // namespace esphome
#endif

View File

@@ -0,0 +1,130 @@
import esphome.codegen as cg
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_GAS_RESISTANCE,
CONF_HUMIDITY,
CONF_IAQ_ACCURACY,
CONF_PRESSURE,
CONF_SAMPLE_RATE,
CONF_TEMPERATURE,
DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
ICON_GAS_CYLINDER,
ICON_GAUGE,
ICON_THERMOMETER,
ICON_WATER_PERCENT,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_HECTOPASCAL,
UNIT_OHM,
UNIT_PARTS_PER_MILLION,
UNIT_PERCENT,
)
from . import CONF_BME68X_BSEC2_ID, SAMPLE_RATE_OPTIONS, BME68xBSEC2Component
DEPENDENCIES = ["bme68x_bsec2"]
CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent"
CONF_CO2_EQUIVALENT = "co2_equivalent"
CONF_IAQ = "iaq"
CONF_IAQ_STATIC = "iaq_static"
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
ICON_TEST_TUBE = "mdi:test-tube"
UNIT_IAQ = "IAQ"
TYPES = [
CONF_TEMPERATURE,
CONF_PRESSURE,
CONF_HUMIDITY,
CONF_GAS_RESISTANCE,
CONF_IAQ,
CONF_IAQ_STATIC,
CONF_IAQ_ACCURACY,
CONF_CO2_EQUIVALENT,
CONF_BREATH_VOC_EQUIVALENT,
]
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_BME68X_BSEC2_ID): cv.use_id(BME68xBSEC2Component),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_THERMOMETER,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)}
),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
unit_of_measurement=UNIT_HECTOPASCAL,
icon=ICON_GAUGE,
accuracy_decimals=1,
device_class=DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)}
),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
icon=ICON_WATER_PERCENT,
accuracy_decimals=1,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)}
),
cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema(
unit_of_measurement=UNIT_OHM,
icon=ICON_GAS_CYLINDER,
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_IAQ): sensor.sensor_schema(
unit_of_measurement=UNIT_IAQ,
icon=ICON_GAUGE,
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_IAQ_STATIC): sensor.sensor_schema(
unit_of_measurement=UNIT_IAQ,
icon=ICON_GAUGE,
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_IAQ_ACCURACY): sensor.sensor_schema(
icon=ICON_ACCURACY,
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema(
unit_of_measurement=UNIT_PARTS_PER_MILLION,
icon=ICON_TEST_TUBE,
accuracy_decimals=1,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema(
unit_of_measurement=UNIT_PARTS_PER_MILLION,
icon=ICON_TEST_TUBE,
accuracy_decimals=1,
state_class=STATE_CLASS_MEASUREMENT,
),
}
)
async def setup_conf(config, key, hub):
if conf := config.get(key):
sens = await sensor.new_sensor(conf)
cg.add(getattr(hub, f"set_{key}_sensor")(sens))
if sample_rate := conf.get(CONF_SAMPLE_RATE):
cg.add(getattr(hub, f"set_{key}_sample_rate")(sample_rate))
async def to_code(config):
hub = await cg.get_variable(config[CONF_BME68X_BSEC2_ID])
for key in TYPES:
await setup_conf(config, key, hub)

View File

@@ -0,0 +1,33 @@
import esphome.codegen as cg
from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import CONF_IAQ_ACCURACY
from . import CONF_BME68X_BSEC2_ID, BME68xBSEC2Component
DEPENDENCIES = ["bme68x_bsec2"]
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
TYPES = [CONF_IAQ_ACCURACY]
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_BME68X_BSEC2_ID): cv.use_id(BME68xBSEC2Component),
cv.Optional(CONF_IAQ_ACCURACY): text_sensor.text_sensor_schema(
icon=ICON_ACCURACY
),
}
)
async def setup_conf(config, key, hub):
if conf := config.get(key):
sens = await text_sensor.new_text_sensor(conf)
cg.add(getattr(hub, f"set_{key}_text_sensor")(sens))
async def to_code(config):
hub = await cg.get_variable(config[CONF_BME68X_BSEC2_ID])
for key in TYPES:
await setup_conf(config, key, hub)

View File

@@ -0,0 +1,28 @@
import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.bme68x_bsec2 import (
CONFIG_SCHEMA_BASE,
BME68xBSEC2Component,
to_code_base,
)
import esphome.config_validation as cv
CODEOWNERS = ["@neffs", "@kbx81"]
AUTO_LOAD = ["bme68x_bsec2"]
DEPENDENCIES = ["i2c"]
bme68x_bsec2_i2c_ns = cg.esphome_ns.namespace("bme68x_bsec2_i2c")
BME68xBSEC2I2CComponent = bme68x_bsec2_i2c_ns.class_(
"BME68xBSEC2I2CComponent", BME68xBSEC2Component, i2c.I2CDevice
)
CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(
cv.Schema({cv.GenerateID(): cv.declare_id(BME68xBSEC2I2CComponent)})
).extend(i2c.i2c_device_schema(0x76))
async def to_code(config):
var = await to_code_base(config)
await i2c.register_i2c_device(var, config)

View File

@@ -0,0 +1,53 @@
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifdef USE_BSEC2
#include "bme68x_bsec2_i2c.h"
#include "esphome/components/i2c/i2c.h"
#include <cinttypes>
namespace esphome {
namespace bme68x_bsec2_i2c {
static const char *const TAG = "bme68x_bsec2_i2c.sensor";
void BME68xBSEC2I2CComponent::setup() {
// must set up our bme68x_dev instance before calling setup()
this->bme68x_.intf_ptr = (void *) this;
this->bme68x_.intf = BME68X_I2C_INTF;
this->bme68x_.read = BME68xBSEC2I2CComponent::read_bytes_wrapper;
this->bme68x_.write = BME68xBSEC2I2CComponent::write_bytes_wrapper;
this->bme68x_.delay_us = BME68xBSEC2I2CComponent::delay_us;
this->bme68x_.amb_temp = 25;
BME68xBSEC2Component::setup();
}
void BME68xBSEC2I2CComponent::dump_config() {
LOG_I2C_DEVICE(this);
BME68xBSEC2Component::dump_config();
}
uint32_t BME68xBSEC2I2CComponent::get_hash() { return fnv1_hash("bme68x_bsec_state_" + to_string(this->address_)); }
int8_t BME68xBSEC2I2CComponent::read_bytes_wrapper(uint8_t a_register, uint8_t *data, uint32_t len, void *intfPtr) {
ESP_LOGVV(TAG, "read_bytes_wrapper: reg = %u", a_register);
return static_cast<BME68xBSEC2I2CComponent *>(intfPtr)->read_bytes(a_register, data, len) ? 0 : -1;
}
int8_t BME68xBSEC2I2CComponent::write_bytes_wrapper(uint8_t a_register, const uint8_t *data, uint32_t len,
void *intfPtr) {
ESP_LOGVV(TAG, "write_bytes_wrapper: reg = %u", a_register);
return static_cast<BME68xBSEC2I2CComponent *>(intfPtr)->write_bytes(a_register, data, len) ? 0 : -1;
}
void BME68xBSEC2I2CComponent::delay_us(uint32_t period, void *intfPtr) {
ESP_LOGVV(TAG, "Delaying for %" PRIu32 "us", period);
delayMicroseconds(period);
}
} // namespace bme68x_bsec2_i2c
} // namespace esphome
#endif

View File

@@ -0,0 +1,28 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/preferences.h"
#ifdef USE_BSEC2
#include "esphome/components/bme68x_bsec2/bme68x_bsec2.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace bme68x_bsec2_i2c {
class BME68xBSEC2I2CComponent : public bme68x_bsec2::BME68xBSEC2Component, public i2c::I2CDevice {
void setup() override;
void dump_config() override;
uint32_t get_hash() override;
static int8_t read_bytes_wrapper(uint8_t a_register, uint8_t *data, uint32_t len, void *intfPtr);
static int8_t write_bytes_wrapper(uint8_t a_register, const uint8_t *data, uint32_t len, void *intfPtr);
static void delay_us(uint32_t period, void *intfPtr);
};
} // namespace bme68x_bsec2_i2c
} // namespace esphome
#endif

View File

@@ -1,96 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import ( CONFIG_SCHEMA = cv.invalid(
CONF_ID, "The bmp280 sensor component has been renamed to bmp280_i2c."
CONF_PRESSURE,
CONF_TEMPERATURE,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_HECTOPASCAL,
CONF_IIR_FILTER,
CONF_OVERSAMPLING,
) )
DEPENDENCIES = ["i2c"]
bmp280_ns = cg.esphome_ns.namespace("bmp280")
BMP280Oversampling = bmp280_ns.enum("BMP280Oversampling")
OVERSAMPLING_OPTIONS = {
"NONE": BMP280Oversampling.BMP280_OVERSAMPLING_NONE,
"1X": BMP280Oversampling.BMP280_OVERSAMPLING_1X,
"2X": BMP280Oversampling.BMP280_OVERSAMPLING_2X,
"4X": BMP280Oversampling.BMP280_OVERSAMPLING_4X,
"8X": BMP280Oversampling.BMP280_OVERSAMPLING_8X,
"16X": BMP280Oversampling.BMP280_OVERSAMPLING_16X,
}
BMP280IIRFilter = bmp280_ns.enum("BMP280IIRFilter")
IIR_FILTER_OPTIONS = {
"OFF": BMP280IIRFilter.BMP280_IIR_FILTER_OFF,
"2X": BMP280IIRFilter.BMP280_IIR_FILTER_2X,
"4X": BMP280IIRFilter.BMP280_IIR_FILTER_4X,
"8X": BMP280IIRFilter.BMP280_IIR_FILTER_8X,
"16X": BMP280IIRFilter.BMP280_IIR_FILTER_16X,
}
BMP280Component = bmp280_ns.class_(
"BMP280Component", cg.PollingComponent, i2c.I2CDevice
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BMP280Component),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
unit_of_measurement=UNIT_HECTOPASCAL,
accuracy_decimals=1,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
IIR_FILTER_OPTIONS, upper=True
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x77))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
if temperature_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temperature_config)
cg.add(var.set_temperature_sensor(sens))
cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING]))
if pressure_config := config.get(CONF_PRESSURE):
sens = await sensor.new_sensor(pressure_config)
cg.add(var.set_pressure_sensor(sens))
cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING]))
cg.add(var.set_iir_filter(config[CONF_IIR_FILTER]))

View File

@@ -0,0 +1,88 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_ID,
CONF_IIR_FILTER,
CONF_OVERSAMPLING,
CONF_PRESSURE,
CONF_TEMPERATURE,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_HECTOPASCAL,
)
CODEOWNERS = ["@ademuri"]
bmp280_ns = cg.esphome_ns.namespace("bmp280_base")
BMP280Oversampling = bmp280_ns.enum("BMP280Oversampling")
OVERSAMPLING_OPTIONS = {
"NONE": BMP280Oversampling.BMP280_OVERSAMPLING_NONE,
"1X": BMP280Oversampling.BMP280_OVERSAMPLING_1X,
"2X": BMP280Oversampling.BMP280_OVERSAMPLING_2X,
"4X": BMP280Oversampling.BMP280_OVERSAMPLING_4X,
"8X": BMP280Oversampling.BMP280_OVERSAMPLING_8X,
"16X": BMP280Oversampling.BMP280_OVERSAMPLING_16X,
}
BMP280IIRFilter = bmp280_ns.enum("BMP280IIRFilter")
IIR_FILTER_OPTIONS = {
"OFF": BMP280IIRFilter.BMP280_IIR_FILTER_OFF,
"2X": BMP280IIRFilter.BMP280_IIR_FILTER_2X,
"4X": BMP280IIRFilter.BMP280_IIR_FILTER_4X,
"8X": BMP280IIRFilter.BMP280_IIR_FILTER_8X,
"16X": BMP280IIRFilter.BMP280_IIR_FILTER_16X,
}
CONFIG_SCHEMA_BASE = cv.Schema(
{
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
unit_of_measurement=UNIT_HECTOPASCAL,
accuracy_decimals=1,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
IIR_FILTER_OPTIONS, upper=True
),
}
).extend(cv.polling_component_schema("60s"))
async def to_code_base(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
if temperature_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temperature_config)
cg.add(var.set_temperature_sensor(sens))
cg.add(var.set_temperature_oversampling(temperature_config[CONF_OVERSAMPLING]))
if pressure_config := config.get(CONF_PRESSURE):
sens = await sensor.new_sensor(pressure_config)
cg.add(var.set_pressure_sensor(sens))
cg.add(var.set_pressure_oversampling(pressure_config[CONF_OVERSAMPLING]))
cg.add(var.set_iir_filter(config[CONF_IIR_FILTER]))
return var

View File

@@ -1,9 +1,9 @@
#include "bmp280.h" #include "bmp280_base.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {
namespace bmp280 { namespace bmp280_base {
static const char *const TAG = "bmp280.sensor"; static const char *const TAG = "bmp280.sensor";
@@ -59,6 +59,14 @@ static const char *iir_filter_to_str(BMP280IIRFilter filter) {
void BMP280Component::setup() { void BMP280Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up BMP280..."); ESP_LOGCONFIG(TAG, "Setting up BMP280...");
uint8_t chip_id = 0; uint8_t chip_id = 0;
// Read the chip id twice, to work around a bug where the first read is 0.
// https://community.st.com/t5/stm32-mcus-products/issue-with-reading-bmp280-chip-id-using-spi/td-p/691855
if (!this->read_byte(0xD0, &chip_id)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (!this->read_byte(0xD0, &chip_id)) { if (!this->read_byte(0xD0, &chip_id)) {
this->error_code_ = COMMUNICATION_FAILED; this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed(); this->mark_failed();
@@ -122,7 +130,6 @@ void BMP280Component::setup() {
} }
void BMP280Component::dump_config() { void BMP280Component::dump_config() {
ESP_LOGCONFIG(TAG, "BMP280:"); ESP_LOGCONFIG(TAG, "BMP280:");
LOG_I2C_DEVICE(this);
switch (this->error_code_) { switch (this->error_code_) {
case COMMUNICATION_FAILED: case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Communication with BMP280 failed!"); ESP_LOGE(TAG, "Communication with BMP280 failed!");
@@ -262,5 +269,5 @@ uint16_t BMP280Component::read_u16_le_(uint8_t a_register) {
} }
int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); } int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); }
} // namespace bmp280 } // namespace bmp280_base
} // namespace esphome } // namespace esphome

View File

@@ -2,10 +2,9 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome { namespace esphome {
namespace bmp280 { namespace bmp280_base {
/// Internal struct storing the calibration values of an BMP280. /// Internal struct storing the calibration values of an BMP280.
struct BMP280CalibrationData { struct BMP280CalibrationData {
@@ -50,8 +49,8 @@ enum BMP280IIRFilter {
BMP280_IIR_FILTER_16X = 0b100, BMP280_IIR_FILTER_16X = 0b100,
}; };
/// This class implements support for the BMP280 Temperature+Pressure i2c sensor. /// This class implements support for the BMP280 Temperature+Pressure sensor.
class BMP280Component : public PollingComponent, public i2c::I2CDevice { class BMP280Component : public PollingComponent {
public: public:
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; } void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
@@ -68,6 +67,11 @@ class BMP280Component : public PollingComponent, public i2c::I2CDevice {
float get_setup_priority() const override; float get_setup_priority() const override;
void update() override; void update() override;
virtual bool read_byte(uint8_t a_register, uint8_t *data) = 0;
virtual bool write_byte(uint8_t a_register, uint8_t data) = 0;
virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0;
virtual bool read_byte_16(uint8_t a_register, uint16_t *data) = 0;
protected: protected:
/// Read the temperature value and store the calculated ambient temperature in t_fine. /// Read the temperature value and store the calculated ambient temperature in t_fine.
float read_temperature_(int32_t *t_fine); float read_temperature_(int32_t *t_fine);
@@ -90,5 +94,5 @@ class BMP280Component : public PollingComponent, public i2c::I2CDevice {
} error_code_{NONE}; } error_code_{NONE};
}; };
} // namespace bmp280 } // namespace bmp280_base
} // namespace esphome } // namespace esphome

View File

@@ -0,0 +1,27 @@
#include "bmp280_i2c.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bmp280_i2c {
bool BMP280I2CComponent::read_byte(uint8_t a_register, uint8_t *data) {
return I2CDevice::read_byte(a_register, data);
};
bool BMP280I2CComponent::write_byte(uint8_t a_register, uint8_t data) {
return I2CDevice::write_byte(a_register, data);
};
bool BMP280I2CComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
return I2CDevice::read_bytes(a_register, data, len);
};
bool BMP280I2CComponent::read_byte_16(uint8_t a_register, uint16_t *data) {
return I2CDevice::read_byte_16(a_register, data);
};
void BMP280I2CComponent::dump_config() {
LOG_I2C_DEVICE(this);
BMP280Component::dump_config();
}
} // namespace bmp280_i2c
} // namespace esphome

View File

@@ -0,0 +1,22 @@
#pragma once
#include "esphome/components/bmp280_base/bmp280_base.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace bmp280_i2c {
static const char *const TAG = "bmp280_i2c.sensor";
/// This class implements support for the BMP280 Temperature+Pressure i2c sensor.
class BMP280I2CComponent : public esphome::bmp280_base::BMP280Component, public i2c::I2CDevice {
public:
bool read_byte(uint8_t a_register, uint8_t *data) override;
bool write_byte(uint8_t a_register, uint8_t data) override;
bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
bool read_byte_16(uint8_t a_register, uint16_t *data) override;
void dump_config() override;
};
} // namespace bmp280_i2c
} // namespace esphome

View File

@@ -0,0 +1,22 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
from ..bmp280_base import to_code_base, CONFIG_SCHEMA_BASE
AUTO_LOAD = ["bmp280_base"]
CODEOWNERS = ["@ademuri"]
DEPENDENCIES = ["i2c"]
bmp280_ns = cg.esphome_ns.namespace("bmp280_i2c")
BMP280I2CComponent = bmp280_ns.class_(
"BMP280I2CComponent", cg.PollingComponent, i2c.I2CDevice
)
CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(
i2c.i2c_device_schema(default_address=0x77)
).extend({cv.GenerateID(): cv.declare_id(BMP280I2CComponent)})
async def to_code(config):
var = await to_code_base(config)
await i2c.register_i2c_device(var, config)

View File

@@ -0,0 +1,65 @@
#include <cstdint>
#include <cstddef>
#include "bmp280_spi.h"
#include <esphome/components/bmp280_base/bmp280_base.h>
namespace esphome {
namespace bmp280_spi {
uint8_t set_bit(uint8_t num, uint8_t position) {
uint8_t mask = 1 << position;
return num | mask;
}
uint8_t clear_bit(uint8_t num, uint8_t position) {
uint8_t mask = 1 << position;
return num & ~mask;
}
void BMP280SPIComponent::setup() {
this->spi_setup();
BMP280Component::setup();
};
// In SPI mode, only 7 bits of the register addresses are used; the MSB of register address is not used
// and replaced by a read/write bit (RW = 0 for write and RW = 1 for read).
// Example: address 0xF7 is accessed by using SPI register address 0x77. For write access, the byte
// 0x77 is transferred, for read access, the byte 0xF7 is transferred.
// https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
bool BMP280SPIComponent::read_byte(uint8_t a_register, uint8_t *data) {
this->enable();
this->transfer_byte(set_bit(a_register, 7));
*data = this->transfer_byte(0);
this->disable();
return true;
}
bool BMP280SPIComponent::write_byte(uint8_t a_register, uint8_t data) {
this->enable();
this->transfer_byte(clear_bit(a_register, 7));
this->transfer_byte(data);
this->disable();
return true;
}
bool BMP280SPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
this->enable();
this->transfer_byte(set_bit(a_register, 7));
this->read_array(data, len);
this->disable();
return true;
}
bool BMP280SPIComponent::read_byte_16(uint8_t a_register, uint16_t *data) {
this->enable();
this->transfer_byte(set_bit(a_register, 7));
((uint8_t *) data)[1] = this->transfer_byte(0);
((uint8_t *) data)[0] = this->transfer_byte(0);
this->disable();
return true;
}
} // namespace bmp280_spi
} // namespace esphome

View File

@@ -0,0 +1,20 @@
#pragma once
#include "esphome/components/bmp280_base/bmp280_base.h"
#include "esphome/components/spi/spi.h"
namespace esphome {
namespace bmp280_spi {
class BMP280SPIComponent : public esphome::bmp280_base::BMP280Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_200KHZ> {
void setup() override;
bool read_byte(uint8_t a_register, uint8_t *data) override;
bool write_byte(uint8_t a_register, uint8_t data) override;
bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
bool read_byte_16(uint8_t a_register, uint16_t *data) override;
};
} // namespace bmp280_spi
} // namespace esphome

View File

@@ -0,0 +1,22 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import spi
from ..bmp280_base import to_code_base, CONFIG_SCHEMA_BASE
AUTO_LOAD = ["bmp280_base"]
CODEOWNERS = ["@ademuri"]
DEPENDENCIES = ["spi"]
bmp280_ns = cg.esphome_ns.namespace("bmp280_spi")
BMP280SPIComponent = bmp280_ns.class_(
"BMP280SPIComponent", cg.PollingComponent, spi.SPIDevice
)
CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(
spi.spi_device_schema(default_mode="mode3")
).extend({cv.GenerateID(): cv.declare_id(BMP280SPIComponent)})
async def to_code(config):
var = await to_code_base(config)
await spi.register_spi_device(var, config)

View File

@@ -2,6 +2,6 @@ import esphome.config_validation as cv
CODEOWNERS = ["@latonita"] CODEOWNERS = ["@latonita"]
CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid( CONFIG_SCHEMA = cv.invalid(
"The bmp3xx sensor component has been renamed to bmp3xx_i2c." "The bmp3xx sensor component has been renamed to bmp3xx_i2c."
) )

View File

@@ -1,16 +1,16 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation from esphome import automation
from esphome.automation import maybe_simple_id from esphome.automation import maybe_simple_id
import esphome.codegen as cg
from esphome.components import mqtt, web_server from esphome.components import mqtt, web_server
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
CONF_ENTITY_CATEGORY, CONF_ENTITY_CATEGORY,
CONF_ICON, CONF_ICON,
CONF_ID, CONF_ID,
CONF_MQTT_ID,
CONF_ON_PRESS, CONF_ON_PRESS,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_MQTT_ID,
CONF_WEB_SERVER_ID, CONF_WEB_SERVER_ID,
DEVICE_CLASS_EMPTY, DEVICE_CLASS_EMPTY,
DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_IDENTIFY,
@@ -18,8 +18,8 @@ from esphome.const import (
DEVICE_CLASS_UPDATE, DEVICE_CLASS_UPDATE,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
from esphome.cpp_helpers import setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
from esphome.cpp_helpers import setup_entity
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True

View File

@@ -1,4 +1,5 @@
#include "captive_portal.h" #include "captive_portal.h"
#ifdef USE_CAPTIVE_PORTAL
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/components/wifi/wifi_component.h" #include "esphome/components/wifi/wifi_component.h"
@@ -91,3 +92,4 @@ CaptivePortal *global_captive_portal = nullptr; // NOLINT(cppcoreguidelines-avo
} // namespace captive_portal } // namespace captive_portal
} // namespace esphome } // namespace esphome
#endif

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "esphome/core/defines.h"
#ifdef USE_CAPTIVE_PORTAL
#include <memory> #include <memory>
#ifdef USE_ARDUINO #ifdef USE_ARDUINO
#include <DNSServer.h> #include <DNSServer.h>
@@ -71,3 +72,4 @@ extern CaptivePortal *global_captive_portal; // NOLINT(cppcoreguidelines-avoid-
} // namespace captive_portal } // namespace captive_portal
} // namespace esphome } // namespace esphome
#endif

View File

@@ -0,0 +1,67 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import i2c
import esphome.config_validation as cv
from esphome.const import (
CONF_ID,
CONF_INPUT,
CONF_INVERTED,
CONF_MODE,
CONF_NUMBER,
CONF_OUTPUT,
CONF_RESTORE_VALUE,
)
CODEOWNERS = ["@jesterret"]
DEPENDENCIES = ["i2c"]
MULTI_CONF = True
ch422g_ns = cg.esphome_ns.namespace("ch422g")
CH422GComponent = ch422g_ns.class_("CH422GComponent", cg.Component, i2c.I2CDevice)
CH422GGPIOPin = ch422g_ns.class_(
"CH422GGPIOPin", cg.GPIOPin, cg.Parented.template(CH422GComponent)
)
CONF_CH422G = "ch422g"
CONFIG_SCHEMA = (
cv.Schema(
{
cv.Required(CONF_ID): cv.declare_id(CH422GComponent),
cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x24))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE]))
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
CH422G_PIN_SCHEMA = pins.gpio_base_schema(
CH422GGPIOPin,
cv.int_range(min=0, max=7),
modes=[CONF_INPUT, CONF_OUTPUT],
).extend(
{
cv.Required(CONF_CH422G): cv.use_id(CH422GComponent),
}
)
@pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA)
async def ch422g_pin_to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
parent = await cg.get_variable(config[CONF_CH422G])
cg.add(var.set_parent(parent))
num = config[CONF_NUMBER]
cg.add(var.set_pin(num))
cg.add(var.set_inverted(config[CONF_INVERTED]))
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
return var

Some files were not shown because too many files have changed in this diff Show More