1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-06 10:01:51 +00:00

Compare commits

...

398 Commits

Author SHA1 Message Date
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
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
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
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
Jesse Hills
04b268e319 Merge pull request #7073 from esphome/bump-2024.7.0b1
2024.7.0b1
2024-07-11 16:31:07 +12:00
Jesse Hills
6417f1f907 Bump version to 2024.7.0b1 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
7b3d6747d5 Merge pull request #7004 from esphome/bump-2024.6.4
2024.6.4
2024-06-27 18:39:53 +12:00
Jesse Hills
7904d3b157 Bump version to 2024.6.4 2024-06-27 17:19:13 +12:00
Markus
3a48b10757 Fix LEDC 100% is not 100% duty with ESP32 IDF (#6997) 2024-06-27 17:19:12 +12:00
Keith Burzinski
0e50cac399 [ota-esphome] Merge configurations by port (#7001) 2024-06-27 17:19:12 +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
Jesse Hills
04225d5717 Merge pull request #6994 from esphome/bump-2024.6.3
2024.6.3
2024-06-26 23:17:44 +12:00
Jesse Hills
86791422f0 Bump version to 2024.6.3 2024-06-26 22:41:48 +12:00
Sergey Dudanov
9c2af6318c [modbus-text-sensor] fix potential buffer overflow (#6993) 2024-06-26 22:41:48 +12:00
Samuel Sieb
c747d7d45d [dallas_temp] fix ds18s20 temp calc (#6988) 2024-06-26 22:41:48 +12:00
Petapton
bbd7c9cf86 Fix float encoding in modbus server (#6986) 2024-06-26 22:41:48 +12:00
Pieter Viljoen
169fb79c97 [ds1307] Initialize uninitialized struct members (#6985) 2024-06-26 22:41:48 +12:00
Kevin P. Fleming
1579dfeb80 Improve 'body' handling in http_request on_response triggers (#6968) 2024-06-26 22:41:48 +12:00
Keith Burzinski
d8a6d8594a [ota-esphome] Validate for multiple esphome ota instances (#6984) 2024-06-26 22:41:48 +12:00
Jesse Hills
7be071a0e9 [safe_mode] Set safe mode core data in disabled cases (#6983) 2024-06-26 22:41:47 +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
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
Jesse Hills
53cfa8d3a1 Merge branch 'release' into dev 2024-06-25 13:58:30 +12:00
Jesse Hills
0262a99274 Merge pull request #6981 from esphome/bump-2024.6.2
2024.6.2
2024-06-25 13:45:15 +12:00
Jesse Hills
09a947beaa Bump version to 2024.6.2 2024-06-25 08:57:38 +12:00
Sergey Dudanov
a6e1ef2dd1 [midea] fix fan speed compatibility with some models (#6978) 2024-06-25 08:57:38 +12:00
Samuel Sieb
c5aae8ee25 fix potential hang (#6976)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-06-25 08:57:38 +12:00
Brian Kaufman
5bd5b777a6 Await cg.get_variable in Update component (#6974) 2024-06-25 08:57:38 +12:00
Gábor Poczkodi
e39961f7f1 [http_request] memory leak fix (#6973) 2024-06-25 08:57:38 +12:00
Samuel Sieb
0d3cf5cb78 Onewire (#6967)
* retry scan

* setup pin and log retries

* fix retries

* remove retries

---------

Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-06-25 08:57:37 +12:00
Kevin P. Fleming
96d63de292 ESP-IDF 4.x expects seconds for esp_task_wdt_init(), not milliseconds. (#6964) 2024-06-25 08:57:37 +12:00
Kevin P. Fleming
ae2962259e Fix infinite loop in http_request for ESP-IDF. (#6963) 2024-06-25 08:57:37 +12:00
Jesse Hills
7dbc20b776 [update] Set entity_category to config & Publish state to logs (#6954) 2024-06-25 08:57:37 +12:00
Jesse Hills
a21dab334c [core] Fix package merging with lists of primitives (#6952) 2024-06-25 08:57:37 +12: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
Jesse Hills
1863523cfd Merge pull request #6946 from esphome/bump-2024.6.1
2024.6.1
2024-06-20 17:05:37 +12:00
Jesse Hills
a7a9eb6f71 Bump version to 2024.6.1 2024-06-20 15:59:27 +12:00
Jesse Hills
c868dae44a Bump esphome-dashboard to 20240620.0 (#6944) 2024-06-20 15:59:27 +12:00
Cossid
ad8cf69897 debug_libretiny - Fix typo (#6942) 2024-06-20 15:59:27 +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
0fe18a6144 Merge pull request #6940 from esphome/bump-2024.6.0
2024.6.0
2024-06-20 08:26:41 +12:00
Jesse Hills
a6d1aa91de Bump version to 2024.6.0 2024-06-19 21:52:47 +12:00
Jesse Hills
ba11f2ab0c Merge branch 'beta' into dev 2024-06-19 18:22:52 +12:00
Jesse Hills
9747811b82 Merge pull request #6938 from esphome/bump-2024.6.0b5
2024.6.0b5
2024-06-19 18:19:14 +12:00
Jesse Hills
ff803aa108 Rename test files 2024-06-19 16:37:33 +12:00
Jesse Hills
8bac82f804 Bump version to 2024.6.0b5 2024-06-19 15:37:43 +12:00
Jesse Hills
6682451ee0 [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-19 15:37:43 +12:00
dependabot[bot]
c17090c1e5 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 15:37:43 +12:00
dependabot[bot]
acf69bb56f 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-19 15:37:43 +12:00
dependabot[bot]
fd7a212562 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-19 15:37:43 +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
Jesse Hills
c053a33fe8 Merge pull request #6930 from esphome/bump-2024.6.0b4
2024.6.0b4
2024-06-18 16:12:04 +12:00
Jesse Hills
ff07637dfd Bump version to 2024.6.0b4 2024-06-18 14:26:24 +12:00
Jesse Hills
43b5c2deb7 Rename legacy/modern to ota/factory (#6922)
* Rename legacy/modern to ota/factory

* Add modern/legacy in brackets
2024-06-18 14:26:24 +12:00
Jesse Hills
d27e7b3b70 [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-18 14:26:24 +12:00
Giel van Schijndel
5dec62bf1e fix(dallas): make recovery time for 1-bit equal to that of 0-bit (#6763) 2024-06-18 14:26:24 +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
cfe28ce7a3 Merge pull request #6915 from esphome/bump-2024.6.0b3
2024.6.0b3
2024-06-17 16:27:24 +12:00
Jesse Hills
25a3db1637 Bump version to 2024.6.0b3 2024-06-17 15:35:53 +12:00
Jesse Hills
65638bf614 [mqtt] Fix datetime copy pasta (#6914) 2024-06-17 15:35:52 +12:00
Jesse Hills
1e66241b26 [ili9xxx] Fix init for GC9A01A (#6913) 2024-06-17 15:35:52 +12:00
esphomebot
eb50f0eafd Synchronise Device Classes from Home Assistant (#6904) 2024-06-17 15:35:52 +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
4e8a7986cd Merge pull request #6902 from esphome/bump-2024.6.0b2
2024.6.0b2
2024-06-13 11:40:44 +12:00
Jesse Hills
3db71b98ae Bump version to 2024.6.0b2 2024-06-13 10:31:08 +12:00
Jesse Hills
73cb3ec852 Bump esphome-dashboard to 20240613.0 (#6901) 2024-06-13 10:31:08 +12:00
Jesse Hills
91e72fe121 [host] Execute host program when using run command (#6897) 2024-06-13 10:31:08 +12:00
Oliver Hihn
be486e0ca6 Add step_delay option to X9C component (#6890) 2024-06-13 10:31:07 +12:00
Jesse Hills
fdefc825bb [CI] Fix for sdl (#6892) 2024-06-13 10:31:07 +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
8a83670f54 Merge pull request #6891 from esphome/bump-2024.6.0b1
2024.6.0b1
2024-06-12 19:28:36 +12:00
Jesse Hills
bd7e8fbf86 Bump version to 2024.7.0-dev 2024-06-12 14:16:43 +12:00
Jesse Hills
f9f98fa6c6 Bump version to 2024.6.0b1 2024-06-12 14:16:43 +12:00
Clyde Stubbs
f25c296303 [ili9xxx] Implement st7735 support (#6838) 2024-06-12 13:47:52 +12:00
Clyde Stubbs
bc408ad08c [display] SDL2 display driver for host platform (#6825) 2024-06-12 13:42:01 +12:00
Tudor Sandu
e2c1af199c Fix media_player.volume_set when media player is not started (#6859)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-06-12 01:39:01 +00:00
Clyde Stubbs
7c843437a7 [config] Early termination of validation steps on error (#6837) 2024-06-12 13:26:43 +12:00
Gábor Poczkodi
4bf7c97088 WebSocket overrides check_origin for reverse proxy configuration (#6845) 2024-06-12 13:19:18 +12:00
Clyde Stubbs
7b9fb57bb2 [config] Retain path information in validated configuration (#6785) 2024-06-12 13:15:57 +12:00
guillempages
699d00e218 [image] Make PIL import local (#6864) 2024-06-12 13:11:00 +12:00
Clyde Stubbs
e2784d077d [he60r] Don't publish state unless it has changed. [BUGFIX] (#6869) 2024-06-12 13:09:20 +12:00
Samuel Sieb
13fabf1cd8 change to new 1-wire platform (#6860)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-06-12 13:05:44 +12:00
NMartin354
7b60543afd [safe_mode] Allow user-defined interval for successful boot (#6882)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-06-12 12:38:20 +12:00
Daniel D'Abate
562700bd2c Climate IR LG - Support fan only mode and all "on" commands (#3712) 2024-06-11 17:04:25 -07:00
Peter Ericson
a64106e48c [waveshare_epaper] Add support for 13.3in-k (#6443) 2024-06-12 11:51:04 +12:00
Landon Rohatensky
c723fd1f80 [animation] Allow loading external url at build time (#6876) 2024-06-12 10:56:27 +12:00
Anton Sergunov
3a97244b83 [Deep sleep] Compilation error with IDF >= 5.* (#6879) 2024-06-12 10:42:20 +12:00
Pieter Viljoen
1f8449ec0e [Dockerfile] Sync platformio version with requirements.txt (#6888) 2024-06-12 10:38:26 +12:00
Jesse Hills
3cd2fb0843 [core] Update Entities (#6885) 2024-06-12 09:57:36 +12:00
esphomebot
7dc07c5632 Update webserver local assets to 20240610-230854 (#6886) 2024-06-10 23:33:42 +00:00
Jesse Hills
95e45dc12c Allow parse_json to return a boolean result (#6884)
* Allow parse_json to return a boolean result

* Remove pass variable
2024-06-10 22:40:56 +00:00
dependabot[bot]
51a8a7e875 Bump docker/build-push-action from 5.3.0 to 5.4.0 in /.github/actions/build-image (#6883)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-11 10:17:18 +12:00
Jesse Hills
dceab6ce29 [voice_assistant] Write less data to speaker each loop (#6877) 2024-06-10 15:22:55 +12:00
Jesse Hills
6de79d6cfb [i2s_speaker] A few fixes (#6872) 2024-06-10 15:22:41 +12:00
Jesse Hills
7b45498de6 [http_request] Add esp-idf and rp2040 support (#3256)
* Implement http_request component for esp-idf

* Fix ifdefs

* Lint

* clang

* Set else to fail with error message

* Use unique_ptr

* Fix

* Tidy up casting, explicit HttpResponse lifetime (#3265)

Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com>

* Remove unique_ptr wrapper

* Fix

* Use reference

* Add duration code into new split files

* Add config for tx/rx buffer on idf

* Fix

* Try reserve response data with rx buffer size

* Update http_request.h

* Move client cleanup to be earlier

* Move capture_response to bool on struct and remove global

* Fix returns

* Change quotes to brackets

* Rework http request

* Remove http request from old test yamls

* Update component tests

* Validate md5 length when hardcoded string

* Linting

* Add duration_ms to container

* More lint

* const

* Remove default arguments and add helper functions for get and post

* Add virtual destructor to HttpContainer

* Undo const HEADER_KEYS

* 🤦

* Update esphome/components/http_request/ota/ota_http_request.cpp

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>

* Update esphome/components/http_request/ota/ota_http_request.cpp

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>

* lint

* Move header keys inline

* Add missing WatchdogManagers

* CAPS

* Fix "follow redirects" string in config dump

* IDF 5+ fix

---------

Co-authored-by: Daniel Cousens <413395+dcousens@users.noreply.github.com>
Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-06-09 15:15:29 -05:00
Mischa Siekmann
618102fe8c fix: arduino media player still sets wrong state. (#6875) 2024-06-09 18:34:21 +12:00
esphomebot
38b7bed2fa Update webserver local assets to 20240608-093147 (#6874) 2024-06-08 09:55:57 +00:00
RFDarter
d77ea46157 [datetime] datetime-datetime strptime support value string without seconds (#6867) 2024-06-08 08:29:10 +12:00
Mischa Siekmann
8718e15a6a fix: arduino media player sets wrong state for announcements (#6849)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-06-08 07:43:22 +12:00
RFDarter
861a23d039 [datetime] Add logs on DateCall perform (#6868) 2024-06-08 07:37:05 +12:00
Pieter Viljoen
276eea2b69 [docker] Avoid unsafe git error when container user and file config volume permissions don't match (#6873) 2024-06-08 07:36:07 +12:00
Jesse Hills
ccab57fc58 [logger] Fix defines for development (#6870)
* [logger] Fix defines for development

* Set debugging flags for rp2040
2024-06-06 23:30:49 -05:00
Olivier ARCHER
8ef4aaa70e [ota] http_request update platform (#5586)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Edward Firmo <94725493+edwardtfn@users.noreply.github.com>
2024-06-06 14:35:28 +12:00
Clyde Stubbs
7143e9cd9e [config] Allow file: scheme for git external components (#6844) 2024-06-06 07:27:06 +12:00
zry98
cc217d8a83 [Tuya Climate] Support both datapoint and pins for active state (#6789) 2024-06-05 08:11:19 +00:00
Will Rouesnel
c52d5c0279 Add invert_position_report to tuya.cover (#6020) 2024-06-05 07:52:19 +00:00
svxa
f36a96c8e2 Add carrier_frequency option to remote_transmitter.transmit_aeha (#6792) 2024-06-05 00:35:19 -07:00
Nate Clark
594856899a [ethernet] Add config option to set arbitrary PHY register values (#6836) 2024-06-05 18:51:56 +12:00
Jesse Hills
f7742cdf19 Merge branch 'release' into dev 2024-06-05 16:39:19 +12:00
Jesse Hills
5b062a222c Merge pull request #6863 from esphome/bump-2024.5.5
2024.5.5
2024-06-05 16:38:27 +12:00
Jesse Hills
664ee56dc5 Bump version to 2024.5.5 2024-06-05 15:51:29 +12:00
Keith Burzinski
388b2c2de0 [improv_serial] Fix for IDF 4.4.7 (#6855) 2024-06-05 15:51:29 +12:00
Jesse Hills
ce4a3d9950 [i2s_speaker] Add buffer allocation failure checks (#6829) 2024-06-05 15:51:29 +12:00
Jesse Hills
ac9f57600d [voice_assistant] Half the microphone ringbuffer size (#6830) 2024-06-05 15:51:29 +12:00
Jesse Hills
69d38f6137 [ft5x06] Interrupt pin and code quality improvements (#6851)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-06-05 11:02:18 +10:00
Keith Burzinski
eb75778f84 [improv_serial] Fix for IDF 4.4.7 (#6855) 2024-06-04 03:18:20 +00:00
Keith Burzinski
2d56d8d84f [wireguard] Implement workaround for crash on IDF 5+ (#6846) 2024-06-04 15:10:44 +12:00
Clyde Stubbs
cdf83c5d8c Add host time platform; remove host support from sntp. (#6854) 2024-06-04 15:09:46 +12:00
Pieter Viljoen
78b48209aa Add Ethernet MAC address to ethernet_info (#6835) 2024-06-04 14:57:05 +12:00
Pieter Viljoen
05491e756b Avoid unsafe git error when container user and file config volume permissions don't match (#6843) 2024-06-04 13:34:47 +12:00
Jimmy Hedman
b8d2a6f574 [sntp] fix for ESP-IDF > 5.0 (#6769)
* Make sntp work with ESP-IDF >= 5.0

* Set operatingmode on other than ESP-IDF

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-06-02 22:23:49 -05:00
Kevin P. Fleming
2353b2b5e1 Add messages when WiFi and Ethernet components set 'warning' flag. (#6850) 2024-06-02 10:40:50 +12:00
Simone Rossetto
2beb1f0336 Wireguard support for bk72 microcontrollers (#6842)
* Bump esp_wireguard to v0.4.1

* add support for bk72 microcontrollers (thanks to kuba2k2)
* fix compilation error using esp-idf v5 (thanks to kbx81)
* fix crash on vpn disconnection with alive tcp connection (thanks to jefftharris)

* Disable ipv6 for bk72 wireguard test

* Completely remove ipv6 entry from bk72 wg test
2024-05-31 21:36:51 -05:00
Pieter Viljoen
41e13fa6f4 Replace random non-ascii-print characters with standard substitutes (#6840) 2024-06-01 10:49:48 +10:00
Keith Burzinski
1f301df51d Fix log message in VA for IDF 5 (#6839) 2024-05-31 17:49:11 +12:00
NonaSuomy
2894a138e7 Update const.py added missing millimeter (#6834)
* Update const.py added missing millimeter

Added missing millimeter

* Fixed UNIT_MILLIMETER in multiple locations.
2024-05-31 05:13:11 +00:00
Anton Viktorov
8dfe1d5220 LTR-303, LTR-329, LTR-553, LTR-556, LTR-559, LTR-659 Series of Lite-On Light (ALS) and Proximity(PS) sensors (#6076)
* LTR303 and LTR329 light sensors

* LTR303 tidy up

* LTR303 unused var

* LTR303 tidy up + test

* LTR303 auto sensitivity mode

* LTR303 auto sensitivity mode tidy

* LTR303 State machine version

* LTR303 name fix

* publish split

* minor

* new definitions for LTR

* als-ps test

* als-ps test

* als-ps test

* ps options

* ps options

* trgger bug fixed

* trgger bug fixed

* Minor comments

* ltr303->ltr_als_ps

* codeowners, tests

* tidy up

* tidy up

* tidy up

* gain enum name fix

* auto gain fix

* tweaks

* new style tests

* als/ps separate init

* logd->logv

* reconfiguration count changed

* old-style tests removed

* const py

* ambient light const in vmel7700 and ltr390

* Update esphome/components/ltr_als_ps/ltr_als_ps.cpp

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>

* Apply suggestions from code review

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>

* remove commented code

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-05-30 03:46:52 -05:00
Jesse Hills
dd27881336 [i2s_speaker] Add buffer allocation failure checks (#6829) 2024-05-30 03:01:39 -05:00
Jesse Hills
8aba890e69 [voice_assistant] Half the microphone ringbuffer size (#6830) 2024-05-30 03:00:09 -05:00
Jesse Hills
63fc8ab10a [core] Const-ify some Component fields (#6831) 2024-05-30 02:59:15 -05:00
Erdem
9de8eaff24 Fix DHT reading timing for SI7021 on ESP32 (#6604)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-30 17:31:09 +12:00
Michael Hansen
c130ddbe9c [micro_wake_word] Ensure model string is Path (#6826) 2024-05-30 13:58:13 +12:00
RFDarter
a7fc1a6298 [web_server] add entity sorting for v3 (#6445)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-30 13:54:20 +12:00
Jesse Hills
854d3f2e4a [voice_assistant] Timers (#6821)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-05-30 13:09:19 +12:00
dependabot[bot]
5ae32e81c3 Bump black from 24.4.0 to 24.4.2 (#6646)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-29 17:11:34 +12:00
dependabot[bot]
439fd94718 Bump peter-evans/create-pull-request from 6.0.4 to 6.0.5 (#6635)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 17:11:02 +12:00
dependabot[bot]
6d5d382f3d Bump pytest-cov from 4.1.0 to 5.0.0 (#6580)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 17:10:47 +12:00
dependabot[bot]
60433c5e64 Bump docker/login-action from 3.1.0 to 3.2.0 (#6823)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 17:09:13 +12:00
Keith Burzinski
bff24e2977 Fix a bunch of components for IDF 5 compatibility and #6802 (#6805) 2024-05-29 17:05:19 +12:00
Clyde Stubbs
ec3164f800 [wake_on_lan] Make component platform independent (#6815) 2024-05-29 16:36:49 +12:00
Frederik
2b691ad5ad Make SPI Ethernet (W5500) compatible with ESP-IDF v5 (#6778)
* change MAC PHY init order according to IDF examples

* add idfv5 specific w5500 config init

* esp_mac.h needs to be included directly starting with idf5

* Header fix

* Couple tweaks

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-05-28 17:02:45 -05:00
DAVe3283
06996def72 Use uint8_t instead of uint32_t for 8-bit values on mitsubishi (#6824)
This solves some printf formatting issues on ESP-IDF and saves RAM on all platforms.
2024-05-28 20:44:47 +00:00
DAVe3283
db6f6f0cb7 Fix compile errors on ESP32-C6 with latest ESP-IDF (#6822)
* Use <cinttypes> PRI macros to fix ESP32-C6 compile

* Fix compile error on latest ESP-IDF framework & platform
2024-05-28 14:40:34 -05:00
pimdo
497cf8742f Make i2s_audio compatible with IDF 5+ (#6534)
* Update i2s_audio.cpp

Replace usage of I2S_NUM_MAX with I2S_NUM_1

* Update i2s_audio_microphone.cpp

Replace I2S_MCLK_MULTIPLE_DEFAULT with I2S_MCLK_MULTIPLE_256

* Update i2s_audio_speaker.cpp

Replace I2S_MCLK_MULTIPLE_DEFAULT with I2S_MCLK_MULTIPLE_256

* Update voice_assistant.cpp

Fix  msg.event_type format

* check SOC_I2S_NUM for c3

* use I2S_NUM_AUTO

* Update i2s_audio.cpp

* Couple tweaks

* Why did they take away I2S_NUM_MAX

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>
2024-05-28 01:42:59 +00:00
Jesse Hills
d2b35adcc8 Merge branch 'release' into dev 2024-05-28 12:51:22 +12:00
Jesse Hills
3fe2fc9b56 Merge pull request #6820 from esphome/bump-2024.5.4
2024.5.4
2024-05-28 12:50:30 +12:00
Jesse Hills
4cd4b168b4 Bump version to 2024.5.4 2024-05-28 08:29:19 +12:00
Gábor Poczkodi
f07479419c [helpers] Move Base64 string to cpp (#6819) 2024-05-28 08:29:19 +12:00
Jesse Hills
54b51269ab [web_server_base] Bump ESPAsyncWebServer-esphome to 3.2.2 (#6797)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2024-05-28 08:29:18 +12:00
Gábor Poczkodi
6e4fd428e7 [helpers] Move Base64 string to cpp (#6819) 2024-05-28 08:19:22 +12:00
august huber
e285196709 fix libretiny regression from #6715 (#6806) 2024-05-27 07:41:29 +12:00
august huber
17c6bf57cd [tuya] add support for extended services (#6808) 2024-05-27 07:40:38 +12:00
Sašo Domadenik
4125b48b86 Fix incorrect naming of the AdaFruit MagTag display. (#6810) 2024-05-27 07:23:00 +12:00
Jesse Hills
6d341ce4e7 [web_server_base] Bump ESPAsyncWebServer-esphome to 3.2.2 (#6797)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2024-05-27 07:15:05 +12:00
Jesse Hills
964410bd64 Merge branch 'release' into dev 2024-05-25 08:25:31 +12:00
Jesse Hills
d72ab25d46 Merge pull request #6804 from esphome/bump-2024.5.3
2024.5.3
2024-05-25 08:24:38 +12:00
Jesse Hills
af755380b7 Bump version to 2024.5.3 2024-05-25 08:14:39 +12:00
Jesse Hills
04db724295 [voice_assistant] Don't allocate buffers until starting the microphone for the first time (#6800) 2024-05-25 08:14:39 +12:00
Jesse Hills
863bee28d9 [voice_assistant] Don't allocate buffers until starting the microphone for the first time (#6800) 2024-05-25 07:42:24 +12:00
Edward Firmo
9d03f47233 [nextion] Add basic functions to Intelligent series (#6791) 2024-05-24 09:11:34 +12:00
polyfloyd
c2d67659f3 mpr121: Add GPIO support (#6776)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-24 09:08:28 +12:00
Pavlo Dudnytskyi
aed0593793 [haier] `text_sensor and button` platforms (#6780) 2024-05-24 09:07:39 +12:00
Jesse Hills
4ab7a5d964 [ledc] Change some logging lines from debug to verbose (#6796) 2024-05-23 00:04:33 -05:00
Penny Wood
7f9383c83b [sx1509] Output open drain pin mode (#6788) 2024-05-23 09:31:56 +12:00
Keith Burzinski
9a6fde21ee Add on_safe_mode trigger (#6790) 2024-05-23 07:43:13 +12:00
Jeroen van Oort
1ca7c2d7dd Add support for acting as Modbus server (#4874)
Co-authored-by: Jeroen van Oort <jeroen.vanoort@webparking.nl>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-22 16:17:32 +12:00
Keith Burzinski
76abf2200c Uncouple safe_mode from OTA (#6759) 2024-05-22 13:08:53 +12:00
Jesse Hills
83d3584173 Merge branch 'release' into dev 2024-05-21 12:30:00 +12:00
Jesse Hills
0ee4348777 Merge pull request #6786 from esphome/bump-2024.5.2
2024.5.2
2024-05-21 12:29:09 +12:00
Jesse Hills
fcdf36e991 Bump version to 2024.5.2 2024-05-21 11:07:20 +12:00
esphomebot
5eb8efd8b3 Update webserver local assets to 20240519-215627 (#6779) 2024-05-21 11:07:20 +12:00
Jesse Hills
cd0f557940 [remote_receiver] Add better error message for tolerance breaking change (#6784) 2024-05-21 11:07:20 +12:00
J. Nick Koston
efde677ca9 Fix DashboardEntries.all() call (#6783) 2024-05-21 11:07:20 +12:00
J. Nick Koston
2eebee1de7 Revert "Fix MQTT dashboard discovery (Exception in MqttStatusThread)." (#6782) 2024-05-21 11:07:20 +12:00
esphomebot
525c4891d5 Update webserver local assets to 20240519-215627 (#6779) 2024-05-21 10:55:56 +12:00
Anton Viktorov
ce6dc040da Tiny fix in automation.h - unused return value removed (#6760) 2024-05-21 10:54:38 +12:00
Jesse Hills
9de67feccd [remote_receiver] Add better error message for tolerance breaking change (#6784) 2024-05-21 10:53:16 +12:00
Clyde Stubbs
bad400e1cd [ili9xxx] Add 18bit mode selection and custom init sequence (#6745) 2024-05-21 09:18:13 +12:00
J. Nick Koston
59b1e9c1b0 Fix DashboardEntries.all() call (#6783) 2024-05-20 11:52:24 +00:00
J. Nick Koston
25ee24299a Revert "Fix MQTT dashboard discovery (Exception in MqttStatusThread)." (#6782) 2024-05-20 11:49:00 +00:00
Jesse Hills
81ef67cfbb Merge branch 'release' into dev 2024-05-20 19:50:39 +12:00
Jesse Hills
f235dcc096 Merge pull request #6781 from esphome/bump-2024.5.1
2024.5.1
2024-05-20 19:48:55 +12:00
Jesse Hills
d2d3db4b8c Bump version to 2024.5.1 2024-05-20 17:14:17 +12:00
Markus
ec6d86c8f5 Fix MQTT dashboard discovery (Exception in MqttStatusThread). (#6775) 2024-05-20 17:14:17 +12:00
Markus
7452879fb1 Fix Upload from Dashboard with MQTT discovery. (#6774)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-20 17:14:17 +12:00
esphomebot
4fc2f2284a Synchronise Device Classes from Home Assistant (#6768) 2024-05-20 17:14:17 +12:00
acshef
840f69ffe6 Add device_class to valve core config (#6765) 2024-05-20 17:14:17 +12:00
fodfodfod
b9bb3cd4be add rp2040 support to the wizard (#6239) 2024-05-20 12:42:30 +12:00
Markus
91e7a44c31 Fix MQTT dashboard discovery (Exception in MqttStatusThread). (#6775) 2024-05-20 11:52:14 +12:00
Markus
080f8bc86e Fix Upload from Dashboard with MQTT discovery. (#6774)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-19 20:33:20 +00:00
dependabot[bot]
a85d37a1cf Bump actions/checkout from 4.1.5 to 4.1.6 (#6764)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 08:12:32 +12:00
tomaszduda23
ba73187c1b separate deep_sleep component for each platform in different file (#6762)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-20 08:11:27 +12:00
tomaszduda23
4469ba4024 [tests] make test_build_components work with venv without installing esphome (#6761) 2024-05-19 11:47:23 +12:00
Sebastian Muszynski
70e0925f9a Fix pip3 install (#6771) 2024-05-19 11:31:36 +12:00
esphomebot
1164cb8610 Synchronise Device Classes from Home Assistant (#6768) 2024-05-18 07:15:52 +00:00
acshef
94b63d7bc2 Add device_class to valve core config (#6765) 2024-05-18 16:17:09 +12:00
Jesse Hills
df838b5788 [core] Remove references to deleted setup.py (#6757) 2024-05-16 22:33:33 +12:00
Edward Firmo
d410cc4f7b [nextion] Fix type on sprintf for IDF v5 (#6758) 2024-05-16 22:22:18 +12:00
Anton Viktorov
b06e0746f5 INA228/INA229, INA238/INA239, INA237 power/energy/charge monitor (I2C, SPI) (#6138)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 16:50:28 +12:00
Jesse Hills
034c196ad8 [core] Update some coroutine priorities (#6755) 2024-05-16 16:46:16 +12:00
Keith Burzinski
996f71c03c Fix wifi compile error on IDF 5.1+ (#6756) 2024-05-16 04:40:21 +00:00
Anton Viktorov
98cb6555df SPI and I2C for ENS160 (#6369) 2024-05-16 15:22:40 +12:00
Faidon Liambotis
0bb2773c64 Port wifi_component_esp32_arduino from tcpip_adapter to esp_netif (#6476)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 14:49:40 +12:00
Jesse Hills
7c243dafb3 [core] Fix some extends cases (#6748) 2024-05-16 14:11:54 +12:00
Mat931
247b2eee30 Add ADC multisampling (#6330) 2024-05-16 14:11:21 +12:00
Keith Burzinski
f46c499c4e Separate OTABackend from OTA component (#6459)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 14:01:09 +12:00
Jesse Hills
f91c31f093 [core] Fix running pylint via pre-commit from GUI apps (#6754) 2024-05-16 13:47:56 +12:00
Jesse Hills
a27c05483c [core] Move pylint config into pyproject.toml (#6739) 2024-05-16 13:47:36 +12:00
Jesse Hills
bf48ccaf22 [core] Move pytest config into pyproject.toml (#6740) 2024-05-16 13:20:12 +12:00
Jesse Hills
f2ef06d8b5 [core] Migrate to pyproject.toml (#6737) 2024-05-16 13:19:37 +12:00
Andrew McFague
f0ec900e48 Skip gpio validation (#5615) 2024-05-16 11:49:04 +12:00
Shawn Wilsher
7d804bf90f Fix Prometheus Output to Match Spec (#6032) 2024-05-16 11:39:57 +12:00
shxshxshxshx
2921831b55 WPA2 Enterprise - Explicitly set TTLS Phase 2 (#6436)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:37:53 +12:00
heggi
08509f7755 Mirage remote receiver & transmitter (#6479)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:35:17 +12:00
Daniel Mahaney
ebfccc64c7 fix rp2040_pio_led flicker and proper multi-strip support (#6194)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:33:52 +12:00
lbilger
8952719045 Allow one timing to cancel others (#6744)
Co-authored-by: Lars Bilger <lars.bilger@lht.dlh.de>
2024-05-16 11:33:27 +12:00
ius
073fb4c124 i2c: fix format string specifiers (#6746) 2024-05-16 11:33:15 +12:00
Mat931
46eee4a4f0 Add beken_spi_led_strip component (#6515)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:32:48 +12:00
Alex Boyd
773951d85e BedJet: expose the outlet temperature on the climate and as a sensor (#6633) 2024-05-16 11:31:08 +12:00
Jesse Hills
1f29023c92 Merge branch 'release' into dev 2024-05-15 18:29:15 +12:00
Jesse Hills
caa8c820de Merge pull request #6753 from esphome/bump-2024.5.0
2024.5.0
2024-05-15 18:27:28 +12:00
dependabot[bot]
9f1ba00b7c Bump esphome-dashboard from 20240412.0 to 20240429.1 (#6743)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 17:16:04 +12:00
Keith Burzinski
891f56b421 [tests] `test2.yaml` has become too large (#6750) 2024-05-15 17:14:19 +12:00
Jesse Hills
0d3adc8f0c Bump version to 2024.5.0 2024-05-15 17:08:43 +12:00
Jesse Hills
d7cb953994 Merge branch 'beta' into dev 2024-05-15 16:33:46 +12:00
Jesse Hills
ad0a1c5c35 Merge pull request #6751 from esphome/bump-2024.5.0b6
2024.5.0b6
2024-05-15 16:24:15 +12:00
Jesse Hills
5d2e3a7d8d Bump version to 2024.5.0b6 2024-05-15 13:14:15 +12:00
Jesse Hills
ebc3f0fe17 [adc] Fix 11db deprecation warning (#6749) 2024-05-15 13:14:15 +12:00
Jesse Hills
9a6e90af54 [adc] Fix 11db deprecation warning (#6749) 2024-05-15 12:51:01 +12:00
Jesse Hills
55e4532a88 Merge branch 'beta' into dev 2024-05-15 10:03:05 +12:00
Mischa Siekmann
6f53607e5a Add ANNOUNCING state to media_player. (#6691) 2024-05-14 21:40:08 +12:00
Clyde Stubbs
d5eeab81d6 [config] Improve error reporting (#6736) 2024-05-14 21:31:03 +12:00
Jesse Hills
636037cec1 [core] Fix minor formatting issues (#6738) 2024-05-14 17:01:07 +12:00
Jesse Hills
7d791cbdfb [esp32_ble] Fix compilation error on esp32c6 (#6734) 2024-05-14 16:22:43 +12:00
Jesse Hills
036a666e36 [web_server] Minor python formatting (#6735) 2024-05-14 15:38:53 +12:00
Mischa Siekmann
921e56f2c6 Voice-Assistant: Start-order change for VAD disabled: start va-pipeline when microphon… (#6391) 2024-05-14 13:25:24 +12:00
Jesse Hills
c94f638c0b Merge branch 'beta' into dev 2024-05-14 11:49:01 +12:00
dependabot[bot]
2ac0821cab Bump pytest from 8.1.1 to 8.2.0 (#6732)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 09:58:43 +12:00
Jesse Hills
47b40505c2 Fix ESPHOME_PROJECT_VERSION_30 (#6731) 2024-05-14 09:42:53 +12:00
dependabot[bot]
eae97dbaa0 Bump platformio from 6.1.13 to 6.1.15 (#6634)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-14 07:11:59 +12:00
Ludovic BOUÉ
91007952e2 [CST816] Add support for Hynitron Microelectronics CST826 capacitive touch (#6682) 2024-05-13 20:21:06 +10:00
Mischa Siekmann
5ee4bf3802 Set FEATURE_API_AUDIO flag also if the speaker component is not used (#6712) 2024-05-13 16:05:13 +12:00
Jorge-Crespo-Celdran
a23d1631e1 time_based_cover.cpp with manual control fix (#6719) 2024-05-13 16:04:06 +12:00
Clyde Stubbs
dd81c83686 Typing hint and doc fixes (#6729) 2024-05-13 15:21:02 +12:00
Szewcson
13e3920c13 GDK101 support (#4703)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-13 13:36:10 +12:00
tomaszduda23
67ca60e2af separate debug component for each platform in different file (#6715)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-13 11:54:43 +12:00
Marcin Krasowski
61b65e2726 fix(ltr390): stuck ALS values when configured for ALS+UV readings (#6723) 2024-05-13 11:25:41 +12:00
Clyde Stubbs
1a45858904 Add pylint to git pre-commit hooks (#6726) 2024-05-13 09:56:55 +12:00
Jesse Hills
47a1710b1e Only cache docker images on dev branch (#6714) 2024-05-10 11:55:35 +12:00
Jesse Hills
ca5050d4a5 [github] Only save platformio cache for dev branch (#6711) 2024-05-10 11:04:32 +12:00
Jesse Hills
8280772b91 Add new Error type to skip prepending path (#6716) 2024-05-10 10:57:47 +12:00
Jesse Hills
026c3a69b8 Merge branch 'beta' into dev 2024-05-09 23:23:14 +12:00
Jesse Hills
78d1a50853 [github] Fix digest artifact name (#6710) 2024-05-09 21:25:48 +12:00
Jesse Hills
ca031287a1 Merge branch 'beta' into dev 2024-05-09 17:35:13 +12:00
Clyde Stubbs
5956bebcb7 [color] Fix crash when hex color parses as int, improve error reporting. (#6707) 2024-05-09 03:14:31 +00:00
Clyde Stubbs
afe81184a8 [core] Ensure that a generated ID name is distinct from its type. (#6706) 2024-05-09 15:08:30 +12:00
chbmuc
d0120cefd2 Add IRK support to ble_rssi (#6422)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-09 15:02:43 +12:00
J. Nick Koston
3ec4a66c9e Bump recommended ESP-IDF to 4.4.7 (#6703) 2024-05-09 13:45:10 +12:00
Nate Clark
819be76013 Add PHY register writes to enable external clock on Ethernet with RTL8201 (#6704)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-09 12:47:25 +12:00
Jesse Hills
72481006e4 [ethernet] Use constexpr instead of inline define for KSZ80XX_PC2R_REG_ADDR (#6705) 2024-05-09 12:25:57 +12:00
Mat931
487e171443 [remote_receiver, remote_transmitter] Improve error messages on the ESP32 (#6701) 2024-05-09 09:58:40 +12:00
Edward Firmo
e48d02495b [nextion] Replace flags to USE_ARDUINO (#6700) 2024-05-09 07:05:24 +12:00
Jesse Hills
7764ab2411 [github] Upgrade to actions/{upload,download}-artifact v4 (#6698) 2024-05-08 16:17:45 +12:00
Jesse Hills
225beb305d Merge branch 'beta' into dev 2024-05-08 14:09:30 +12:00
Jesse Hills
b7c6125a0b Bump version to 2024.6.0-dev 2024-05-08 13:22:05 +12:00
2313 changed files with 21937 additions and 22053 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

@@ -1,19 +1,3 @@
[metadata]
license = MIT
license_file = LICENSE
platforms = any
description = Make creating custom firmwares for ESP32/ESP8266 super easy.
long_description = file: README.md
keywords = home, automation
classifier =
Environment :: Console
Intended Audience :: Developers
Intended Audience :: End Users/Desktop
License :: OSI Approved :: MIT License
Programming Language :: C++
Programming Language :: Python :: 3
Topic :: Home Automation
[flake8] [flake8]
max-line-length = 120 max-line-length = 120
# Following 4 for black compatibility # Following 4 for black compatibility
@@ -37,25 +21,22 @@ max-line-length = 120
# D401 First line should be in imperative mood # D401 First line should be in imperative mood
ignore = ignore =
E501, E501,
W503, W503,
E203, E203,
D202, D202,
D100, D100,
D101, D101,
D102, D102,
D103, D103,
D104, D104,
D105, D105,
D107, D107,
D200, D200,
D205, D205,
D209, D209,
D400, D400,
D401, D401,
exclude = api_pb2.py exclude = api_pb2.py
[bdist_wheel]
universal = 1

View File

@@ -34,16 +34,26 @@ runs:
echo $l >> $GITHUB_OUTPUT echo $l >> $GITHUB_OUTPUT
done done
# set cache-to only if dev branch
- id: cache-to
shell: bash
run: |-
if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then
echo "value=type=gha,mode=max" >> $GITHUB_OUTPUT
else
echo "value=" >> $GITHUB_OUTPUT
fi
- 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@v5.3.0 uses: docker/build-push-action@v6.3.0
with: with:
context: . context: .
file: ./docker/Dockerfile file: ./docker/Dockerfile
platforms: ${{ inputs.platform }} platforms: ${{ inputs.platform }}
target: ${{ inputs.target }} target: ${{ inputs.target }}
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: ${{ steps.cache-to.outputs.value }}
build-args: | build-args: |
BASEIMGTYPE=${{ inputs.baseimg }} BASEIMGTYPE=${{ inputs.baseimg }}
BUILD_VERSION=${{ inputs.version }} BUILD_VERSION=${{ inputs.version }}
@@ -59,14 +69,14 @@ 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@v5.3.0 uses: docker/build-push-action@v6.3.0
with: with:
context: . context: .
file: ./docker/Dockerfile file: ./docker/Dockerfile
platforms: ${{ inputs.platform }} platforms: ${{ inputs.platform }}
target: ${{ inputs.target }} target: ${{ inputs.target }}
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: ${{ steps.cache-to.outputs.value }}
build-args: | build-args: |
BASEIMGTYPE=${{ inputs.baseimg }} BASEIMGTYPE=${{ inputs.baseimg }}
BUILD_VERSION=${{ inputs.version }} BUILD_VERSION=${{ inputs.version }}

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.1.1
with: with:
python-version: ${{ inputs.python-version }} python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment - name: Restore Python virtual environment

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.5 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.1.0
with: with:

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.5 - 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.1.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.4.0
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3.0.0 uses: docker/setup-qemu-action@v3.1.0
- name: Set TAG - name: Set TAG
run: | run: |

View File

@@ -34,7 +34,7 @@ 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.5 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
@@ -66,7 +66,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +87,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +108,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +129,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +150,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +199,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +229,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 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 +248,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.5
- 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.5
- 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.5
- 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,18 +292,26 @@ jobs:
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }} cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio - name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@v4.0.2 uses: actions/cache@v4.0.2
with: with:
path: ~/.platformio path: ~/.platformio
# yamllint disable-line rule:line-length key: platformio-${{ matrix.pio_cache_key }}
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@v4.0.2
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}
- name: Install clang-tidy - name: Install clang-tidy
run: sudo apt-get install clang-tidy-14 run: sudo apt-get install clang-tidy-14
@@ -379,6 +321,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
@@ -402,7 +351,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.5 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
@@ -446,11 +395,11 @@ jobs:
matrix: matrix:
file: ${{ fromJson(needs.list-components.outputs.components) }} file: ${{ fromJson(needs.list-components.outputs.components) }}
steps: steps:
- name: Install libsodium - name: Install dependencies
run: sudo apt-get install libsodium-dev run: sudo apt-get install libsodium-dev libsdl2-dev
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -476,7 +425,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.5 uses: actions/checkout@v4.1.7
- name: Split components into 20 groups - name: Split components into 20 groups
id: split id: split
run: | run: |
@@ -500,11 +449,11 @@ jobs:
- name: List components - name: List components
run: echo ${{ matrix.components }} run: echo ${{ matrix.components }}
- name: Install libsodium - name: Install dependencies
run: sudo apt-get install libsodium-dev run: sudo apt-get install libsodium-dev libsdl2-dev
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.5 uses: actions/checkout@v4.1.7
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@@ -535,7 +484,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.5 - 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,7 +51,7 @@ jobs:
contents: read contents: read
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v4.1.5 - 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.1.0
with: with:
@@ -61,9 +61,11 @@ jobs:
ESPHOME_NO_VENV: 1 ESPHOME_NO_VENV: 1
run: script/setup run: script/setup
- name: Build - name: Build
run: python setup.py sdist bdist_wheel run: |-
pip3 install build
python3 -m build
- name: Publish - name: Publish
uses: pypa/gh-action-pypi-publish@v1.8.14 uses: pypa/gh-action-pypi-publish@v1.9.0
deploy-docker: deploy-docker:
name: Build ESPHome ${{ matrix.platform }} name: Build ESPHome ${{ matrix.platform }}
@@ -81,25 +83,25 @@ jobs:
- linux/arm/v7 - linux/arm/v7
- linux/arm64 - linux/arm64
steps: steps:
- uses: actions/checkout@v4.1.5 - 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.1.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.4.0
- 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.1.0
- name: Log in to docker hub - name: Log in to docker hub
uses: docker/login-action@v3.1.0 uses: docker/login-action@v3.2.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.1.0 uses: docker/login-action@v3.2.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
@@ -139,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.3.4
with: with:
name: digests-${{ steps.sanitize.outputs.name }} name: digests-${{ steps.sanitize.outputs.name }}
path: /tmp/digests path: /tmp/digests
@@ -172,27 +174,27 @@ jobs:
- ghcr - ghcr
- dockerhub - dockerhub
steps: steps:
- uses: actions/checkout@v4.1.5 - 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.4.0
- 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.1.0 uses: docker/login-action@v3.2.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.1.0 uses: docker/login-action@v3.2.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}

View File

@@ -13,10 +13,10 @@ jobs:
if: github.repository == 'esphome/esphome' if: github.repository == 'esphome/esphome'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.5 uses: actions/checkout@v4.1.7
- name: Checkout Home Assistant - name: Checkout Home Assistant
uses: actions/checkout@v4.1.5 uses: actions/checkout@v4.1.7
with: with:
repository: home-assistant/core repository: home-assistant/core
path: lib/home-assistant path: lib/home-assistant
@@ -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.4 uses: peter-evans/create-pull-request@v6.1.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.5 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:

View File

@@ -3,7 +3,7 @@
# 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/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.2.0 rev: 24.4.2
hooks: hooks:
- id: black - id: black
args: args:
@@ -40,3 +40,10 @@ repos:
hooks: hooks:
- id: clang-format - id: clang-format
types_or: [c, c++] types_or: [c, c++]
- repo: local
hooks:
- id: pylint
name: pylint
entry: script/run-in-env.sh pylint
language: script
types: [python]

View File

@@ -6,7 +6,7 @@
# the integration's code owner is automatically notified. # the integration's code owner is automatically notified.
# Core Code # Core Code
setup.py @esphome/core pyproject.toml @esphome/core
esphome/*.py @esphome/core esphome/*.py @esphome/core
esphome/core/* @esphome/core esphome/core/* @esphome/core
@@ -51,6 +51,8 @@ esphome/components/bang_bang/* @OttoWinter
esphome/components/bedjet/* @jhansche esphome/components/bedjet/* @jhansche
esphome/components/bedjet/climate/* @jhansche esphome/components/bedjet/climate/* @jhansche
esphome/components/bedjet/fan/* @jhansche esphome/components/bedjet/fan/* @jhansche
esphome/components/bedjet/sensor/* @javawizard @jhansche
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
@@ -92,6 +94,7 @@ esphome/components/current_based/* @djwmarcx
esphome/components/dac7678/* @NickB1 esphome/components/dac7678/* @NickB1
esphome/components/daikin_arc/* @MagicBear esphome/components/daikin_arc/* @MagicBear
esphome/components/daikin_brc/* @hagak esphome/components/daikin_brc/* @hagak
esphome/components/dallas_temp/* @ssieb
esphome/components/daly_bms/* @s1lvi0 esphome/components/daly_bms/* @s1lvi0
esphome/components/dashboard_import/* @esphome/core esphome/components/dashboard_import/* @esphome/core
esphome/components/datetime/* @jesserockz @rfdarter esphome/components/datetime/* @jesserockz @rfdarter
@@ -109,7 +112,10 @@ esphome/components/ee895/* @Stock-M
esphome/components/ektf2232/touchscreen/* @jesserockz esphome/components/ektf2232/touchscreen/* @jesserockz
esphome/components/emc2101/* @ellull esphome/components/emc2101/* @ellull
esphome/components/emmeti/* @E440QF esphome/components/emmeti/* @E440QF
esphome/components/ens160/* @vincentscode esphome/components/ens160/* @latonita
esphome/components/ens160_base/* @latonita @vincentscode
esphome/components/ens160_i2c/* @latonita
esphome/components/ens160_spi/* @latonita
esphome/components/ens210/* @itn3rd77 esphome/components/ens210/* @itn3rd77
esphome/components/esp32/* @esphome/core esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @Rapsssito @jesserockz esphome/components/esp32_ble/* @Rapsssito @jesserockz
@@ -135,9 +141,11 @@ esphome/components/fs3000/* @kahrendt
esphome/components/ft5x06/* @clydebarrow esphome/components/ft5x06/* @clydebarrow
esphome/components/ft63x6/* @gpambrozio esphome/components/ft63x6/* @gpambrozio
esphome/components/gcja5/* @gcormier esphome/components/gcja5/* @gcormier
esphome/components/gdk101/* @Szewcson
esphome/components/globals/* @esphome/core esphome/components/globals/* @esphome/core
esphome/components/gp8403/* @jesserockz esphome/components/gp8403/* @jesserockz
esphome/components/gpio/* @esphome/core esphome/components/gpio/* @esphome/core
esphome/components/gpio/one_wire/* @ssieb
esphome/components/gps/* @coogle esphome/components/gps/* @coogle
esphome/components/graph/* @synco esphome/components/graph/* @synco
esphome/components/graphical_display_menu/* @MrMDavidson esphome/components/graphical_display_menu/* @MrMDavidson
@@ -146,6 +154,10 @@ esphome/components/grove_tb6612fng/* @max246
esphome/components/growatt_solar/* @leeuwte esphome/components/growatt_solar/* @leeuwte
esphome/components/gt911/* @clydebarrow @jesserockz esphome/components/gt911/* @clydebarrow @jesserockz
esphome/components/haier/* @paveldn esphome/components/haier/* @paveldn
esphome/components/haier/binary_sensor/* @paveldn
esphome/components/haier/button/* @paveldn
esphome/components/haier/sensor/* @paveldn
esphome/components/haier/text_sensor/* @paveldn
esphome/components/havells_solar/* @sourabhjaiswal esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann esphome/components/hbridge/light/* @DotNetDann
@@ -157,9 +169,12 @@ esphome/components/homeassistant/* @OttoWinter
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
esphome/components/host/* @esphome/core esphome/components/host/* @clydebarrow @esphome/core
esphome/components/host/time/* @clydebarrow
esphome/components/hrxl_maxsonar_wr/* @netmikey esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/hte501/* @Stock-M esphome/components/hte501/* @Stock-M
esphome/components/http_request/ota/* @oarcher
esphome/components/http_request/update/* @jesserockz
esphome/components/htu31d/* @betterengineering esphome/components/htu31d/* @betterengineering
esphome/components/hydreon_rgxx/* @functionpointer esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/hyt271/* @Philippe12 esphome/components/hyt271/* @Philippe12
@@ -174,6 +189,9 @@ esphome/components/improv_base/* @esphome/core
esphome/components/improv_serial/* @esphome/core esphome/components/improv_serial/* @esphome/core
esphome/components/ina226/* @Sergio303 @latonita esphome/components/ina226/* @Sergio303 @latonita
esphome/components/ina260/* @mreditor97 esphome/components/ina260/* @mreditor97
esphome/components/ina2xx_base/* @latonita
esphome/components/ina2xx_i2c/* @latonita
esphome/components/ina2xx_spi/* @latonita
esphome/components/inkbird_ibsth1_mini/* @fkirill esphome/components/inkbird_ibsth1_mini/* @fkirill
esphome/components/inkplate6/* @jesserockz esphome/components/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter esphome/components/integration/* @OttoWinter
@@ -196,7 +214,8 @@ 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/ltr_als_ps/* @latonita
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
@@ -253,6 +272,7 @@ esphome/components/nextion/text_sensor/* @senexcrenshaw
esphome/components/nfc/* @jesserockz @kbx81 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/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
@@ -297,9 +317,10 @@ esphome/components/rp2040_pwm/* @jesserockz
esphome/components/rpi_dpi_rgb/* @clydebarrow esphome/components/rpi_dpi_rgb/* @clydebarrow
esphome/components/rtl87xx/* @kuba2k2 esphome/components/rtl87xx/* @kuba2k2
esphome/components/rtttl/* @glmnet esphome/components/rtttl/* @glmnet
esphome/components/safe_mode/* @jsuanet @paulmonigatti esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
esphome/components/scd4x/* @martgras @sjtrny esphome/components/scd4x/* @martgras @sjtrny
esphome/components/script/* @esphome/core esphome/components/script/* @esphome/core
esphome/components/sdl/* @clydebarrow
esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sdm_meter/* @jesserockz @polyfaces
esphome/components/sdp3x/* @Azimath esphome/components/sdp3x/* @Azimath
esphome/components/seeed_mr24hpc1/* @limengdu esphome/components/seeed_mr24hpc1/* @limengdu
@@ -394,6 +415,7 @@ esphome/components/uart/button/* @ssieb
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
esphome/components/update/* @jesserockz
esphome/components/uponor_smatrix/* @kroimon esphome/components/uponor_smatrix/* @kroimon
esphome/components/valve/* @esphome/core esphome/components/valve/* @esphome/core
esphome/components/vbus/* @ssieb esphome/components/vbus/* @ssieb
@@ -401,7 +423,7 @@ esphome/components/veml3235/* @kbx81
esphome/components/veml7700/* @latonita 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/* @willwill2will54 esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
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

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+deb12u6 \
openssh-client=1:9.2p1-2+deb12u2 \ openssh-client=1:9.2p1-2+deb12u2 \
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.13-1~deb12u1 \
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/*
@@ -81,7 +85,8 @@ RUN \
fi; \ fi; \
pip3 install \ pip3 install \
--break-system-packages --no-cache-dir \ --break-system-packages --no-cache-dir \
platformio==6.1.13 \ # Keep platformio version in sync with requirements.txt
platformio==6.1.15 \
# Change some platformio settings # Change some platformio settings
&& platformio settings set enable_telemetry No \ && platformio settings set enable_telemetry No \
&& platformio settings set check_platformio_interval 1000000 \ && platformio settings set check_platformio_interval 1000000 \
@@ -100,6 +105,9 @@ RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "a
--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 && /platformio_install_deps.py /platformio.ini --libraries
# Avoid unsafe git error when container user and file config volume permissions don't match
RUN git config --system --add safe.directory '*'
# ======================= docker-type image ======================= # ======================= docker-type image =======================
FROM base AS docker FROM base AS docker
@@ -110,7 +118,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \ fi; \
pip3 install \ pip3 install \
--break-system-packages --no-cache-dir --no-use-pep517 -e /esphome --break-system-packages --no-cache-dir -e /esphome
# Settings for dashboard # Settings for dashboard
ENV USERNAME="" PASSWORD="" ENV USERNAME="" PASSWORD=""
@@ -160,7 +168,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \ export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \ fi; \
pip3 install \ pip3 install \
--break-system-packages --no-cache-dir --no-use-pep517 -e /esphome --break-system-packages --no-cache-dir -e /esphome
# Labels # Labels
LABEL \ LABEL \
@@ -186,8 +194,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

@@ -18,22 +18,23 @@ from esphome.const import (
CONF_BAUD_RATE, CONF_BAUD_RATE,
CONF_BROKER, CONF_BROKER,
CONF_DEASSERT_RTS_DTR, CONF_DEASSERT_RTS_DTR,
CONF_DISABLED,
CONF_ESPHOME,
CONF_LOGGER, CONF_LOGGER,
CONF_MDNS,
CONF_MQTT,
CONF_NAME, CONF_NAME,
CONF_OTA, CONF_OTA,
CONF_MQTT,
CONF_MDNS,
CONF_DISABLED,
CONF_PASSWORD, CONF_PASSWORD,
CONF_PORT, CONF_PLATFORM,
CONF_ESPHOME,
CONF_PLATFORMIO_OPTIONS, CONF_PLATFORMIO_OPTIONS,
CONF_PORT,
CONF_SUBSTITUTIONS, CONF_SUBSTITUTIONS,
PLATFORM_BK72XX, PLATFORM_BK72XX,
PLATFORM_RTL87XX,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_RP2040, PLATFORM_RP2040,
PLATFORM_RTL87XX,
SECRETS_FILES, SECRETS_FILES,
) )
from esphome.core import CORE, EsphomeError, coroutine from esphome.core import CORE, EsphomeError, coroutine
@@ -65,7 +66,7 @@ def choose_prompt(options, purpose: str = None):
f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:' f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:'
) )
for i, (desc, _) in enumerate(options): for i, (desc, _) in enumerate(options):
safe_print(f" [{i+1}] {desc}") safe_print(f" [{i + 1}] {desc}")
while True: while True:
opt = input("(number): ") opt = input("(number): ")
@@ -330,15 +331,19 @@ def upload_program(config, args, host):
return 1 # Unknown target platform return 1 # Unknown target platform
if CONF_OTA not in config: ota_conf = {}
for ota_item in config.get(CONF_OTA, []):
if ota_item[CONF_PLATFORM] == CONF_ESPHOME:
ota_conf = ota_item
break
if not ota_conf:
raise EsphomeError( raise EsphomeError(
"Cannot upload Over the Air as the config does not include the ota: " f"Cannot upload Over the Air as the {CONF_OTA} configuration is not present or does not include {CONF_PLATFORM}: {CONF_ESPHOME}"
"component"
) )
from esphome import espota2 from esphome import espota2
ota_conf = config[CONF_OTA]
remote_port = ota_conf[CONF_PORT] remote_port = ota_conf[CONF_PORT]
password = ota_conf.get(CONF_PASSWORD, "") password = ota_conf.get(CONF_PASSWORD, "")
@@ -346,7 +351,7 @@ def upload_program(config, args, host):
not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions
and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]) and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
and CONF_MQTT in config and CONF_MQTT in config
and (not args.device or args.device == "MQTT") and (not args.device or args.device in ("MQTT", "OTA"))
): ):
from esphome import mqtt from esphome import mqtt
@@ -483,6 +488,15 @@ def command_run(args, config):
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info("Successfully compiled program.") _LOGGER.info("Successfully compiled program.")
if CORE.is_host:
from esphome.platformio_api import get_idedata
idedata = get_idedata(config)
if idedata is None:
return 1
program_path = idedata.raw["prog_path"]
return run_external_process(program_path)
port = choose_upload_log_host( port = choose_upload_log_host(
default=args.device, default=args.device,
check_default=None, check_default=None,

View File

@@ -58,7 +58,9 @@ from esphome.cpp_types import ( # noqa
bool_, bool_,
int_, int_,
std_ns, std_ns,
std_shared_ptr,
std_string, std_string,
std_string_ref,
std_vector, std_vector,
uint8, uint8,
uint16, uint16,

View File

@@ -4,11 +4,11 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
ICON_ARROW_EXPAND_VERTICAL, ICON_ARROW_EXPAND_VERTICAL,
DEVICE_CLASS_DISTANCE, DEVICE_CLASS_DISTANCE,
UNIT_MILLIMETER,
) )
CODEOWNERS = ["@TH-Braemer"] CODEOWNERS = ["@TH-Braemer"]
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
UNIT_MILLIMETERS = "mm"
a02yyuw_ns = cg.esphome_ns.namespace("a02yyuw") a02yyuw_ns = cg.esphome_ns.namespace("a02yyuw")
A02yyuwComponent = a02yyuw_ns.class_( A02yyuwComponent = a02yyuw_ns.class_(
@@ -17,7 +17,7 @@ A02yyuwComponent = a02yyuw_ns.class_(
CONFIG_SCHEMA = sensor.sensor_schema( CONFIG_SCHEMA = sensor.sensor_schema(
A02yyuwComponent, A02yyuwComponent,
unit_of_measurement=UNIT_MILLIMETERS, unit_of_measurement=UNIT_MILLIMETER,
icon=ICON_ARROW_EXPAND_VERTICAL, icon=ICON_ARROW_EXPAND_VERTICAL,
accuracy_decimals=0, accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,

View File

@@ -18,11 +18,23 @@ from esphome.components.esp32.const import (
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
adc_ns = cg.esphome_ns.namespace("adc")
"""
From the below patch versions (and 5.2+) ADC_ATTEN_DB_11 is deprecated and replaced with ADC_ATTEN_DB_12.
4.4.7
5.0.5
5.1.3
5.2+
"""
ATTENUATION_MODES = { ATTENUATION_MODES = {
"0db": cg.global_ns.ADC_ATTEN_DB_0, "0db": cg.global_ns.ADC_ATTEN_DB_0,
"2.5db": cg.global_ns.ADC_ATTEN_DB_2_5, "2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
"6db": cg.global_ns.ADC_ATTEN_DB_6, "6db": cg.global_ns.ADC_ATTEN_DB_6,
"11db": cg.global_ns.ADC_ATTEN_DB_11, "11db": adc_ns.ADC_ATTEN_DB_12_COMPAT,
"12db": adc_ns.ADC_ATTEN_DB_12_COMPAT,
"auto": "auto", "auto": "auto",
} }

View File

@@ -46,27 +46,27 @@ extern "C"
ADCSensor::setup() { ADCSensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040) #if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
pin_->setup(); this->pin_->setup();
#endif #endif
#ifdef USE_ESP32 #ifdef USE_ESP32
if (channel1_ != ADC1_CHANNEL_MAX) { if (this->channel1_ != ADC1_CHANNEL_MAX) {
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
if (!autorange_) { if (!this->autorange_) {
adc1_config_channel_atten(channel1_, attenuation_); adc1_config_channel_atten(this->channel1_, this->attenuation_);
} }
} else if (channel2_ != ADC2_CHANNEL_MAX) { } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
if (!autorange_) { if (!this->autorange_) {
adc2_config_channel_atten(channel2_, attenuation_); adc2_config_channel_atten(this->channel2_, this->attenuation_);
} }
} }
// load characteristics for each attenuation // load characteristics for each attenuation
for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) { for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2; auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
1100, // default vref 1100, // default vref
&cal_characteristics_[i]); &this->cal_characteristics_[i]);
switch (cal_value) { switch (cal_value) {
case ESP_ADC_CAL_VAL_EFUSE_VREF: case ESP_ADC_CAL_VAL_EFUSE_VREF:
ESP_LOGV(TAG, "Using eFuse Vref for calibration"); ESP_LOGV(TAG, "Using eFuse Vref for calibration");
@@ -99,27 +99,27 @@ void ADCSensor::dump_config() {
#ifdef USE_ADC_SENSOR_VCC #ifdef USE_ADC_SENSOR_VCC
ESP_LOGCONFIG(TAG, " Pin: VCC"); ESP_LOGCONFIG(TAG, " Pin: VCC");
#else #else
LOG_PIN(" Pin: ", pin_); LOG_PIN(" Pin: ", this->pin_);
#endif #endif
#endif // USE_ESP8266 || USE_LIBRETINY #endif // USE_ESP8266 || USE_LIBRETINY
#ifdef USE_ESP32 #ifdef USE_ESP32
LOG_PIN(" Pin: ", pin_); LOG_PIN(" Pin: ", this->pin_);
if (autorange_) { if (this->autorange_) {
ESP_LOGCONFIG(TAG, " Attenuation: auto"); ESP_LOGCONFIG(TAG, " Attenuation: auto");
} else { } else {
switch (this->attenuation_) { switch (this->attenuation_) {
case ADC_ATTEN_DB_0: case ADC_ATTEN_DB_0:
ESP_LOGCONFIG(TAG, " Attenuation: 0db"); ESP_LOGCONFIG(TAG, " Attenuation: 0db");
break; break;
case ADC_ATTEN_DB_2_5: case ADC_ATTEN_DB_2_5:
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db"); ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
break; break;
case ADC_ATTEN_DB_6: case ADC_ATTEN_DB_6:
ESP_LOGCONFIG(TAG, " Attenuation: 6db"); ESP_LOGCONFIG(TAG, " Attenuation: 6db");
break; break;
case ADC_ATTEN_DB_11: case ADC_ATTEN_DB_12_COMPAT:
ESP_LOGCONFIG(TAG, " Attenuation: 11db"); ESP_LOGCONFIG(TAG, " Attenuation: 12db");
break; break;
default: // This is to satisfy the unused ADC_ATTEN_MAX default: // This is to satisfy the unused ADC_ATTEN_MAX
break; break;
@@ -134,11 +134,11 @@ void ADCSensor::dump_config() {
#ifdef USE_ADC_SENSOR_VCC #ifdef USE_ADC_SENSOR_VCC
ESP_LOGCONFIG(TAG, " Pin: VCC"); ESP_LOGCONFIG(TAG, " Pin: VCC");
#else #else
LOG_PIN(" Pin: ", pin_); LOG_PIN(" Pin: ", this->pin_);
#endif // USE_ADC_SENSOR_VCC #endif // USE_ADC_SENSOR_VCC
} }
#endif // USE_RP2040 #endif // USE_RP2040
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
@@ -149,14 +149,24 @@ void ADCSensor::update() {
this->publish_state(value_v); this->publish_state(value_v);
} }
void ADCSensor::set_sample_count(uint8_t sample_count) {
if (sample_count != 0) {
this->sample_count_ = sample_count;
}
}
#ifdef USE_ESP8266 #ifdef USE_ESP8266
float ADCSensor::sample() { float ADCSensor::sample() {
uint32_t raw = 0;
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
#ifdef USE_ADC_SENSOR_VCC #ifdef USE_ADC_SENSOR_VCC
int32_t raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance) raw += ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance)
#else #else
int32_t raw = analogRead(this->pin_->get_pin()); // NOLINT raw += analogRead(this->pin_->get_pin()); // NOLINT
#endif #endif
if (output_raw_) { }
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
if (this->output_raw_) {
return raw; return raw;
} }
return raw / 1024.0f; return raw / 1024.0f;
@@ -165,77 +175,81 @@ float ADCSensor::sample() {
#ifdef USE_ESP32 #ifdef USE_ESP32
float ADCSensor::sample() { float ADCSensor::sample() {
if (!autorange_) { if (!this->autorange_) {
int raw = -1; uint32_t sum = 0;
if (channel1_ != ADC1_CHANNEL_MAX) { for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
raw = adc1_get_raw(channel1_); int raw = -1;
} else if (channel2_ != ADC2_CHANNEL_MAX) { if (this->channel1_ != ADC1_CHANNEL_MAX) {
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw); raw = adc1_get_raw(this->channel1_);
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
}
if (raw == -1) {
return NAN;
}
sum += raw;
} }
sum = (sum + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
if (raw == -1) { if (this->output_raw_) {
return NAN; return sum;
} }
if (output_raw_) { uint32_t mv = esp_adc_cal_raw_to_voltage(sum, &this->cal_characteristics_[(int32_t) this->attenuation_]);
return raw;
}
uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]);
return mv / 1000.0f; return mv / 1000.0f;
} }
int raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX; int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
if (channel1_ != ADC1_CHANNEL_MAX) { if (this->channel1_ != ADC1_CHANNEL_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
raw11 = adc1_get_raw(channel1_); raw12 = adc1_get_raw(this->channel1_);
if (raw11 < ADC_MAX) { if (raw12 < ADC_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
raw6 = adc1_get_raw(channel1_); raw6 = adc1_get_raw(this->channel1_);
if (raw6 < ADC_MAX) { if (raw6 < ADC_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5); adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
raw2 = adc1_get_raw(channel1_); raw2 = adc1_get_raw(this->channel1_);
if (raw2 < ADC_MAX) { if (raw2 < ADC_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0); adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
raw0 = adc1_get_raw(channel1_); raw0 = adc1_get_raw(this->channel1_);
} }
} }
} }
} else if (channel2_ != ADC2_CHANNEL_MAX) { } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11); adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11); adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
if (raw11 < ADC_MAX) { if (raw12 < ADC_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6); adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6); adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
if (raw6 < ADC_MAX) { if (raw6 < ADC_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5); adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2); adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
if (raw2 < ADC_MAX) { if (raw2 < ADC_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0); adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0); adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
} }
} }
} }
} }
if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw11 == -1) { if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) {
return NAN; return NAN;
} }
uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]); uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]);
uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]); uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]); uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]); uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
// Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC) // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
uint32_t c11 = std::min(raw11, ADC_HALF); uint32_t c12 = std::min(raw12, ADC_HALF);
uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF); uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF); uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF); uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
// max theoretical csum value is 4096*4 = 16384 // max theoretical csum value is 4096*4 = 16384
uint32_t csum = c11 + c6 + c2 + c0; uint32_t csum = c12 + c6 + c2 + c0;
// each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32 // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
uint32_t mv_scaled = (mv11 * c11) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0); uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
return mv_scaled / (float) (csum * 1000U); return mv_scaled / (float) (csum * 1000U);
} }
#endif // USE_ESP32 #endif // USE_ESP32
@@ -246,8 +260,11 @@ float ADCSensor::sample() {
adc_set_temp_sensor_enabled(true); adc_set_temp_sensor_enabled(true);
delay(1); delay(1);
adc_select_input(4); adc_select_input(4);
uint32_t raw = 0;
int32_t raw = adc_read(); for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
raw += adc_read();
}
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
adc_set_temp_sensor_enabled(false); adc_set_temp_sensor_enabled(false);
if (this->output_raw_) { if (this->output_raw_) {
return raw; return raw;
@@ -268,7 +285,11 @@ float ADCSensor::sample() {
adc_gpio_init(pin); adc_gpio_init(pin);
adc_select_input(pin - 26); adc_select_input(pin - 26);
int32_t raw = adc_read(); uint32_t raw = 0;
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
raw += adc_read();
}
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
#ifdef CYW43_USES_VSYS_PIN #ifdef CYW43_USES_VSYS_PIN
if (pin == PICO_VSYS_PIN) { if (pin == PICO_VSYS_PIN) {
@@ -276,7 +297,7 @@ float ADCSensor::sample() {
} }
#endif // CYW43_USES_VSYS_PIN #endif // CYW43_USES_VSYS_PIN
if (output_raw_) { if (this->output_raw_) {
return raw; return raw;
} }
float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0; float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
@@ -287,10 +308,19 @@ float ADCSensor::sample() {
#ifdef USE_LIBRETINY #ifdef USE_LIBRETINY
float ADCSensor::sample() { float ADCSensor::sample() {
if (output_raw_) { uint32_t raw = 0;
return analogRead(this->pin_->get_pin()); // NOLINT if (this->output_raw_) {
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
raw += analogRead(this->pin_->get_pin()); // NOLINT
}
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
return raw;
} }
return analogReadVoltage(this->pin_->get_pin()) / 1000.0f; // NOLINT for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
raw += analogReadVoltage(this->pin_->get_pin()); // NOLINT
}
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
return raw / 1000.0f;
} }
#endif // USE_LIBRETINY #endif // USE_LIBRETINY

View File

@@ -1,33 +1,48 @@
#pragma once #pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/defines.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h" #include "esphome/components/voltage_sampler/voltage_sampler.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#ifdef USE_ESP32 #ifdef USE_ESP32
#include "driver/adc.h"
#include <esp_adc_cal.h> #include <esp_adc_cal.h>
#include "driver/adc.h"
#endif #endif
namespace esphome { namespace esphome {
namespace adc { namespace adc {
#ifdef USE_ESP32
// clang-format off
#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \
(ESP_IDF_VERSION_MAJOR == 5 && \
((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \
(ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \
(ESP_IDF_VERSION_MINOR >= 2)) \
)
// clang-format on
static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_12;
#else
static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11;
#endif
#endif // USE_ESP32
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
public: public:
#ifdef USE_ESP32 #ifdef USE_ESP32
/// Set the attenuation for this pin. Only available on the ESP32. /// Set the attenuation for this pin. Only available on the ESP32.
void set_attenuation(adc_atten_t attenuation) { attenuation_ = attenuation; } void set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; }
void set_channel1(adc1_channel_t channel) { void set_channel1(adc1_channel_t channel) {
channel1_ = channel; this->channel1_ = channel;
channel2_ = ADC2_CHANNEL_MAX; this->channel2_ = ADC2_CHANNEL_MAX;
} }
void set_channel2(adc2_channel_t channel) { void set_channel2(adc2_channel_t channel) {
channel2_ = channel; this->channel2_ = channel;
channel1_ = ADC1_CHANNEL_MAX; this->channel1_ = ADC1_CHANNEL_MAX;
} }
void set_autorange(bool autorange) { autorange_ = autorange; } void set_autorange(bool autorange) { this->autorange_ = autorange; }
#endif #endif
/// Update ADC values /// Update ADC values
@@ -38,7 +53,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
/// `HARDWARE_LATE` setup priority /// `HARDWARE_LATE` setup priority
float get_setup_priority() const override; float get_setup_priority() const override;
void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; } void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
void set_output_raw(bool output_raw) { output_raw_ = output_raw; } void set_output_raw(bool output_raw) { this->output_raw_ = output_raw; }
void set_sample_count(uint8_t sample_count);
float sample() override; float sample() override;
#ifdef USE_ESP8266 #ifdef USE_ESP8266
@@ -46,12 +62,13 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#endif #endif
#ifdef USE_RP2040 #ifdef USE_RP2040
void set_is_temperature() { is_temperature_ = true; } void set_is_temperature() { this->is_temperature_ = true; }
#endif #endif
protected: protected:
InternalGPIOPin *pin_; InternalGPIOPin *pin_;
bool output_raw_{false}; bool output_raw_{false};
uint8_t sample_count_{1};
#ifdef USE_RP2040 #ifdef USE_RP2040
bool is_temperature_{false}; bool is_temperature_{false};

View File

@@ -1,3 +1,5 @@
import logging
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.final_validate as fv import esphome.final_validate as fv
@@ -19,16 +21,35 @@ from . import (
ATTENUATION_MODES, ATTENUATION_MODES,
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL, ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
adc_ns,
validate_adc_pin, validate_adc_pin,
) )
_LOGGER = logging.getLogger(__name__)
AUTO_LOAD = ["voltage_sampler"] AUTO_LOAD = ["voltage_sampler"]
CONF_SAMPLES = "samples"
_attenuation = cv.enum(ATTENUATION_MODES, lower=True)
def validate_config(config): def validate_config(config):
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto": if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
raise cv.Invalid("Automatic attenuation cannot be used when raw output is set") raise cv.Invalid("Automatic attenuation cannot be used when raw output is set")
if config.get(CONF_ATTENUATION, None) == "auto" and config.get(CONF_SAMPLES, 1) > 1:
raise cv.Invalid(
"Automatic attenuation cannot be used when multisampling is set"
)
if config.get(CONF_ATTENUATION) == "11db":
_LOGGER.warning(
"`attenuation: 11db` is deprecated, use `attenuation: 12db` instead"
)
# Alter value here so `config` command prints the recommended change
config[CONF_ATTENUATION] = _attenuation("12db")
return config return config
@@ -47,7 +68,6 @@ def final_validate_config(config):
return config return config
adc_ns = cg.esphome_ns.namespace("adc")
ADCSensor = adc_ns.class_( ADCSensor = adc_ns.class_(
"ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler "ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
) )
@@ -65,8 +85,9 @@ CONFIG_SCHEMA = cv.All(
cv.Required(CONF_PIN): validate_adc_pin, cv.Required(CONF_PIN): validate_adc_pin,
cv.Optional(CONF_RAW, default=False): cv.boolean, cv.Optional(CONF_RAW, default=False): cv.boolean,
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All( cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
cv.only_on_esp32, cv.enum(ATTENUATION_MODES, lower=True) cv.only_on_esp32, _attenuation
), ),
cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255),
} }
) )
.extend(cv.polling_component_schema("60s")), .extend(cv.polling_component_schema("60s")),
@@ -90,6 +111,7 @@ async def to_code(config):
cg.add(var.set_pin(pin)) cg.add(var.set_pin(pin))
cg.add(var.set_output_raw(config[CONF_RAW])) cg.add(var.set_output_raw(config[CONF_RAW]))
cg.add(var.set_sample_count(config[CONF_SAMPLES]))
if attenuation := config.get(CONF_ATTENUATION): if attenuation := config.get(CONF_ATTENUATION):
if attenuation == "auto": if attenuation == "auto":

View File

@@ -11,6 +11,8 @@
#include "ade7880_registers.h" #include "ade7880_registers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace ade7880 { namespace ade7880 {
@@ -156,7 +158,7 @@ void ADE7880::update() {
}); });
} }
ESP_LOGD(TAG, "update took %u ms", millis() - start); ESP_LOGD(TAG, "update took %" PRIu32 " ms", millis() - start);
} }
void ADE7880::dump_config() { void ADE7880::dump_config() {
@@ -176,9 +178,9 @@ void ADE7880::dump_config() {
LOG_SENSOR(" ", "Forward Active Energy", this->channel_a_->forward_active_energy); LOG_SENSOR(" ", "Forward Active Energy", this->channel_a_->forward_active_energy);
LOG_SENSOR(" ", "Reverse Active Energy", this->channel_a_->reverse_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_a_->reverse_active_energy);
ESP_LOGCONFIG(TAG, " Calibration:"); ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_a_->current_gain_calibration); ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_a_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_a_->voltage_gain_calibration); ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_a_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %d", this->channel_a_->power_gain_calibration); ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_a_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_a_->phase_angle_calibration); ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_a_->phase_angle_calibration);
} }
@@ -192,9 +194,9 @@ void ADE7880::dump_config() {
LOG_SENSOR(" ", "Forward Active Energy", this->channel_b_->forward_active_energy); LOG_SENSOR(" ", "Forward Active Energy", this->channel_b_->forward_active_energy);
LOG_SENSOR(" ", "Reverse Active Energy", this->channel_b_->reverse_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_b_->reverse_active_energy);
ESP_LOGCONFIG(TAG, " Calibration:"); ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_b_->current_gain_calibration); ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_b_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_b_->voltage_gain_calibration); ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_b_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %d", this->channel_b_->power_gain_calibration); ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_b_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_b_->phase_angle_calibration); ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_b_->phase_angle_calibration);
} }
@@ -208,9 +210,9 @@ void ADE7880::dump_config() {
LOG_SENSOR(" ", "Forward Active Energy", this->channel_c_->forward_active_energy); LOG_SENSOR(" ", "Forward Active Energy", this->channel_c_->forward_active_energy);
LOG_SENSOR(" ", "Reverse Active Energy", this->channel_c_->reverse_active_energy); LOG_SENSOR(" ", "Reverse Active Energy", this->channel_c_->reverse_active_energy);
ESP_LOGCONFIG(TAG, " Calibration:"); ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_c_->current_gain_calibration); ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_c_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_c_->voltage_gain_calibration); ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_c_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %d", this->channel_c_->power_gain_calibration); ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_c_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_c_->phase_angle_calibration); ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_c_->phase_angle_calibration);
} }
@@ -218,7 +220,7 @@ void ADE7880::dump_config() {
ESP_LOGCONFIG(TAG, " Neutral:"); ESP_LOGCONFIG(TAG, " Neutral:");
LOG_SENSOR(" ", "Current", this->channel_n_->current); LOG_SENSOR(" ", "Current", this->channel_n_->current);
ESP_LOGCONFIG(TAG, " Calibration:"); ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_n_->current_gain_calibration); ESP_LOGCONFIG(TAG, " Current: %" PRId32, this->channel_n_->current_gain_calibration);
} }
LOG_I2C_DEVICE(this); LOG_I2C_DEVICE(this);

View File

@@ -1,6 +1,8 @@
#include "ade7953_base.h" #include "ade7953_base.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace ade7953_base { namespace ade7953_base {
@@ -105,7 +107,7 @@ void ADE7953::update() {
this->last_update_ = now; this->last_update_ = now;
// prevent DIV/0 // prevent DIV/0
pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000; pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000;
ESP_LOGVV(TAG, "ADE7953::update() diff=%d pf=%f", diff, pf); ESP_LOGVV(TAG, "ADE7953::update() diff=%" PRIu32 " pf=%f", diff, pf);
} }
// Apparent power // Apparent power

View File

@@ -1,5 +1,7 @@
#include "ags10.h" #include "ags10.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace ags10 { namespace ags10 {
static const char *const TAG = "ags10"; static const char *const TAG = "ags10";
@@ -35,7 +37,7 @@ void AGS10Component::setup() {
auto resistance = this->read_resistance_(); auto resistance = this->read_resistance_();
if (resistance) { if (resistance) {
ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08X", *resistance); ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08" PRIX32, *resistance);
if (this->resistance_ != nullptr) { if (this->resistance_ != nullptr) {
this->resistance_->publish_state(*resistance); this->resistance_->publish_state(*resistance);
} }

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

@@ -1,5 +1,6 @@
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 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 from esphome.core import CORE, coroutine_with_priority
@@ -8,6 +9,7 @@ from esphome.const import (
CONF_ON_STATE, CONF_ON_STATE,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_CODE, CONF_CODE,
CONF_WEB_SERVER_ID,
) )
from esphome.cpp_helpers import setup_entity from esphome.cpp_helpers import setup_entity
@@ -76,6 +78,8 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
) )
ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
web_server.WEBSERVER_SORTING_SCHEMA
).extend(
{ {
cv.GenerateID(): cv.declare_id(AlarmControlPanel), cv.GenerateID(): cv.declare_id(AlarmControlPanel),
cv.Optional(CONF_ON_STATE): automation.validate_automation( cv.Optional(CONF_ON_STATE): automation.validate_automation(
@@ -185,6 +189,9 @@ async def setup_alarm_control_panel_core_(var, config):
for conf in config.get(CONF_ON_READY, []): for conf in config.get(CONF_ON_READY, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf) await automation.build_automation(trigger, [], conf)
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config)
async def register_alarm_control_panel(var, config): async def register_alarm_control_panel(var, config):

View File

@@ -3,7 +3,13 @@ import logging
from esphome import automation, core from esphome import automation, core
from esphome.components import font from esphome.components import font
import esphome.components.image as espImage import esphome.components.image as espImage
from esphome.components.image import CONF_USE_TRANSPARENCY from esphome.components.image import (
CONF_USE_TRANSPARENCY,
LOCAL_SCHEMA,
WEB_SCHEMA,
SOURCE_WEB,
SOURCE_LOCAL,
)
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome.const import ( from esphome.const import (
@@ -13,6 +19,9 @@ from esphome.const import (
CONF_REPEAT, CONF_REPEAT,
CONF_RESIZE, CONF_RESIZE,
CONF_TYPE, CONF_TYPE,
CONF_SOURCE,
CONF_PATH,
CONF_URL,
) )
from esphome.core import CORE, HexInt from esphome.core import CORE, HexInt
@@ -43,6 +52,40 @@ SetFrameAction = animation_ns.class_(
"AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_) "AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_)
) )
TYPED_FILE_SCHEMA = cv.typed_schema(
{
SOURCE_LOCAL: LOCAL_SCHEMA,
SOURCE_WEB: WEB_SCHEMA,
},
key=CONF_SOURCE,
)
def _file_schema(value):
if isinstance(value, str):
return validate_file_shorthand(value)
return TYPED_FILE_SCHEMA(value)
FILE_SCHEMA = cv.Schema(_file_schema)
def validate_file_shorthand(value):
value = cv.string_strict(value)
if value.startswith("http://") or value.startswith("https://"):
return FILE_SCHEMA(
{
CONF_SOURCE: SOURCE_WEB,
CONF_URL: value,
}
)
return FILE_SCHEMA(
{
CONF_SOURCE: SOURCE_LOCAL,
CONF_PATH: value,
}
)
def validate_cross_dependencies(config): def validate_cross_dependencies(config):
""" """
@@ -67,7 +110,7 @@ ANIMATION_SCHEMA = cv.Schema(
cv.All( cv.All(
{ {
cv.Required(CONF_ID): cv.declare_id(Animation_), cv.Required(CONF_ID): cv.declare_id(Animation_),
cv.Required(CONF_FILE): cv.file_, cv.Required(CONF_FILE): FILE_SCHEMA,
cv.Optional(CONF_RESIZE): cv.dimensions, cv.Optional(CONF_RESIZE): cv.dimensions,
cv.Optional(CONF_TYPE, default="BINARY"): cv.enum( cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(
espImage.IMAGE_TYPE, upper=True espImage.IMAGE_TYPE, upper=True
@@ -124,7 +167,11 @@ async def animation_action_to_code(config, action_id, template_arg, args):
async def to_code(config): async def to_code(config):
from PIL import Image from PIL import Image
path = CORE.relative_config_path(config[CONF_FILE]) conf_file = config[CONF_FILE]
if conf_file[CONF_SOURCE] == SOURCE_LOCAL:
path = CORE.relative_config_path(conf_file[CONF_PATH])
elif conf_file[CONF_SOURCE] == SOURCE_WEB:
path = espImage.compute_local_image_path(conf_file).as_posix()
try: try:
image = Image.open(path) image = Image.open(path)
except Exception as e: except Exception as e:
@@ -157,7 +204,7 @@ async def to_code(config):
pixels = list(frame.getdata()) pixels = list(frame.getdata())
if len(pixels) != height * width: if len(pixels) != height * width:
raise core.EsphomeError( raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
) )
for pix, a in pixels: for pix, a in pixels:
if transparent: if transparent:
@@ -180,7 +227,7 @@ async def to_code(config):
pixels = list(frame.getdata()) pixels = list(frame.getdata())
if len(pixels) != height * width: if len(pixels) != height * width:
raise core.EsphomeError( raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
) )
for pix in pixels: for pix in pixels:
data[pos] = pix[0] data[pos] = pix[0]
@@ -203,7 +250,7 @@ async def to_code(config):
pixels = list(frame.getdata()) pixels = list(frame.getdata())
if len(pixels) != height * width: if len(pixels) != height * width:
raise core.EsphomeError( raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
) )
for r, g, b, a in pixels: for r, g, b, a in pixels:
if transparent: if transparent:
@@ -232,7 +279,7 @@ async def to_code(config):
pixels = list(frame.getdata()) pixels = list(frame.getdata())
if len(pixels) != height * width: if len(pixels) != height * width:
raise core.EsphomeError( raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})" f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
) )
for r, g, b, a in pixels: for r, g, b, a in pixels:
R = r >> 3 R = r >> 3

View File

@@ -48,6 +48,7 @@ service APIConnection {
rpc date_command (DateCommandRequest) returns (void) {} rpc date_command (DateCommandRequest) returns (void) {}
rpc time_command (TimeCommandRequest) returns (void) {} rpc time_command (TimeCommandRequest) returns (void) {}
rpc datetime_command (DateTimeCommandRequest) returns (void) {} rpc datetime_command (DateTimeCommandRequest) returns (void) {}
rpc update_command (UpdateCommandRequest) returns (void) {}
rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {} rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {} rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {}
@@ -1517,6 +1518,25 @@ message VoiceAssistantAudio {
bool end = 2; bool end = 2;
} }
enum VoiceAssistantTimerEvent {
VOICE_ASSISTANT_TIMER_STARTED = 0;
VOICE_ASSISTANT_TIMER_UPDATED = 1;
VOICE_ASSISTANT_TIMER_CANCELLED = 2;
VOICE_ASSISTANT_TIMER_FINISHED = 3;
}
message VoiceAssistantTimerEventResponse {
option (id) = 115;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
VoiceAssistantTimerEvent event_type = 1;
string timer_id = 2;
string name = 3;
uint32 total_seconds = 4;
uint32 seconds_left = 5;
bool is_active = 6;
}
// ==================== ALARM CONTROL PANEL ==================== // ==================== ALARM CONTROL PANEL ====================
enum AlarmControlPanelState { enum AlarmControlPanelState {
@@ -1818,3 +1838,46 @@ message DateTimeCommandRequest {
fixed32 key = 1; fixed32 key = 1;
fixed32 epoch_seconds = 2; fixed32 epoch_seconds = 2;
} }
// ==================== UPDATE ====================
message ListEntitiesUpdateResponse {
option (id) = 116;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_UPDATE";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
bool disabled_by_default = 6;
EntityCategory entity_category = 7;
string device_class = 8;
}
message UpdateStateResponse {
option (id) = 117;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_UPDATE";
option (no_delay) = true;
fixed32 key = 1;
bool missing_state = 2;
bool in_progress = 3;
bool has_progress = 4;
float progress = 5;
string current_version = 6;
string latest_version = 7;
string title = 8;
string release_summary = 9;
string release_url = 10;
}
message UpdateCommandRequest {
option (id) = 118;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_UPDATE";
option (no_delay) = true;
fixed32 key = 1;
bool install = 2;
}

View File

@@ -1193,6 +1193,15 @@ void APIConnection::on_voice_assistant_audio(const VoiceAssistantAudio &msg) {
voice_assistant::global_voice_assistant->on_audio(msg); voice_assistant::global_voice_assistant->on_audio(msg);
} }
}; };
void APIConnection::on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &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_timer_event(msg);
}
};
#endif #endif
@@ -1278,6 +1287,51 @@ bool APIConnection::send_event_info(event::Event *event) {
} }
#endif #endif
#ifdef USE_UPDATE
bool APIConnection::send_update_state(update::UpdateEntity *update) {
if (!this->state_subscription_)
return false;
UpdateStateResponse resp{};
resp.key = update->get_object_id_hash();
resp.missing_state = !update->has_state();
if (update->has_state()) {
resp.in_progress = update->state == update::UpdateState::UPDATE_STATE_INSTALLING;
if (update->update_info.has_progress) {
resp.has_progress = true;
resp.progress = update->update_info.progress;
}
resp.current_version = update->update_info.current_version;
resp.latest_version = update->update_info.latest_version;
resp.title = update->update_info.title;
resp.release_summary = update->update_info.summary;
resp.release_url = update->update_info.release_url;
}
return this->send_update_state_response(resp);
}
bool APIConnection::send_update_info(update::UpdateEntity *update) {
ListEntitiesUpdateResponse msg;
msg.key = update->get_object_id_hash();
msg.object_id = update->get_object_id();
if (update->has_own_name())
msg.name = update->get_name();
msg.unique_id = get_default_unique_id("update", update);
msg.icon = update->get_icon();
msg.disabled_by_default = update->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(update->get_entity_category());
msg.device_class = update->get_device_class();
return this->send_list_entities_update_response(msg);
}
void APIConnection::update_command(const UpdateCommandRequest &msg) {
update::UpdateEntity *update = App.get_update_by_key(msg.key);
if (update == nullptr)
return;
update->perform();
}
#endif
bool APIConnection::send_log_message(int level, const char *tag, const char *line) { bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level) if (this->log_subscription_ < level)
return false; return false;

View File

@@ -150,6 +150,7 @@ class APIConnection : public APIServerConnection {
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
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;
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
@@ -163,6 +164,12 @@ class APIConnection : public APIServerConnection {
bool send_event_info(event::Event *event); bool send_event_info(event::Event *event);
#endif #endif
#ifdef USE_UPDATE
bool send_update_state(update::UpdateEntity *update);
bool send_update_info(update::UpdateEntity *update);
void update_command(const UpdateCommandRequest &msg) override;
#endif
void on_disconnect_response(const DisconnectResponse &value) override; void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override { void on_ping_response(const PingResponse &value) override {
// we initiated ping // we initiated ping

View File

@@ -475,6 +475,22 @@ template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::V
} }
#endif #endif
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::VoiceAssistantTimerEvent>(enums::VoiceAssistantTimerEvent value) {
switch (value) {
case enums::VOICE_ASSISTANT_TIMER_STARTED:
return "VOICE_ASSISTANT_TIMER_STARTED";
case enums::VOICE_ASSISTANT_TIMER_UPDATED:
return "VOICE_ASSISTANT_TIMER_UPDATED";
case enums::VOICE_ASSISTANT_TIMER_CANCELLED:
return "VOICE_ASSISTANT_TIMER_CANCELLED";
case enums::VOICE_ASSISTANT_TIMER_FINISHED:
return "VOICE_ASSISTANT_TIMER_FINISHED";
default:
return "UNKNOWN";
}
}
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::AlarmControlPanelState>(enums::AlarmControlPanelState value) { template<> const char *proto_enum_to_string<enums::AlarmControlPanelState>(enums::AlarmControlPanelState value) {
switch (value) { switch (value) {
case enums::ALARM_STATE_DISARMED: case enums::ALARM_STATE_DISARMED:
@@ -6857,6 +6873,82 @@ void VoiceAssistantAudio::dump_to(std::string &out) const {
out.append("}"); out.append("}");
} }
#endif #endif
bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->event_type = value.as_enum<enums::VoiceAssistantTimerEvent>();
return true;
}
case 4: {
this->total_seconds = value.as_uint32();
return true;
}
case 5: {
this->seconds_left = value.as_uint32();
return true;
}
case 6: {
this->is_active = value.as_bool();
return true;
}
default:
return false;
}
}
bool VoiceAssistantTimerEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
this->timer_id = value.as_string();
return true;
}
case 3: {
this->name = value.as_string();
return true;
}
default:
return false;
}
}
void VoiceAssistantTimerEventResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_enum<enums::VoiceAssistantTimerEvent>(1, this->event_type);
buffer.encode_string(2, this->timer_id);
buffer.encode_string(3, this->name);
buffer.encode_uint32(4, this->total_seconds);
buffer.encode_uint32(5, this->seconds_left);
buffer.encode_bool(6, this->is_active);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantTimerEventResponse {\n");
out.append(" event_type: ");
out.append(proto_enum_to_string<enums::VoiceAssistantTimerEvent>(this->event_type));
out.append("\n");
out.append(" timer_id: ");
out.append("'").append(this->timer_id).append("'");
out.append("\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" total_seconds: ");
sprintf(buffer, "%" PRIu32, this->total_seconds);
out.append(buffer);
out.append("\n");
out.append(" seconds_left: ");
sprintf(buffer, "%" PRIu32, this->seconds_left);
out.append(buffer);
out.append("\n");
out.append(" is_active: ");
out.append(YESNO(this->is_active));
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: {
@@ -8284,6 +8376,262 @@ void DateTimeCommandRequest::dump_to(std::string &out) const {
out.append("}"); out.append("}");
} }
#endif #endif
bool ListEntitiesUpdateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 6: {
this->disabled_by_default = value.as_bool();
return true;
}
case 7: {
this->entity_category = value.as_enum<enums::EntityCategory>();
return true;
}
default:
return false;
}
}
bool ListEntitiesUpdateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->object_id = value.as_string();
return true;
}
case 3: {
this->name = value.as_string();
return true;
}
case 4: {
this->unique_id = value.as_string();
return true;
}
case 5: {
this->icon = value.as_string();
return true;
}
case 8: {
this->device_class = value.as_string();
return true;
}
default:
return false;
}
}
bool ListEntitiesUpdateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 2: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->object_id);
buffer.encode_fixed32(2, this->key);
buffer.encode_string(3, this->name);
buffer.encode_string(4, this->unique_id);
buffer.encode_string(5, this->icon);
buffer.encode_bool(6, this->disabled_by_default);
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
buffer.encode_string(8, this->device_class);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesUpdateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("ListEntitiesUpdateResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
out.append("\n");
out.append(" key: ");
sprintf(buffer, "%" PRIu32, this->key);
out.append(buffer);
out.append("\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" unique_id: ");
out.append("'").append(this->unique_id).append("'");
out.append("\n");
out.append(" icon: ");
out.append("'").append(this->icon).append("'");
out.append("\n");
out.append(" disabled_by_default: ");
out.append(YESNO(this->disabled_by_default));
out.append("\n");
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" device_class: ");
out.append("'").append(this->device_class).append("'");
out.append("\n");
out.append("}");
}
#endif
bool UpdateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->missing_state = value.as_bool();
return true;
}
case 3: {
this->in_progress = value.as_bool();
return true;
}
case 4: {
this->has_progress = value.as_bool();
return true;
}
default:
return false;
}
}
bool UpdateStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 6: {
this->current_version = value.as_string();
return true;
}
case 7: {
this->latest_version = value.as_string();
return true;
}
case 8: {
this->title = value.as_string();
return true;
}
case 9: {
this->release_summary = value.as_string();
return true;
}
case 10: {
this->release_url = value.as_string();
return true;
}
default:
return false;
}
}
bool UpdateStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1: {
this->key = value.as_fixed32();
return true;
}
case 5: {
this->progress = value.as_float();
return true;
}
default:
return false;
}
}
void UpdateStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_bool(2, this->missing_state);
buffer.encode_bool(3, this->in_progress);
buffer.encode_bool(4, this->has_progress);
buffer.encode_float(5, this->progress);
buffer.encode_string(6, this->current_version);
buffer.encode_string(7, this->latest_version);
buffer.encode_string(8, this->title);
buffer.encode_string(9, this->release_summary);
buffer.encode_string(10, this->release_url);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void UpdateStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("UpdateStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%" PRIu32, this->key);
out.append(buffer);
out.append("\n");
out.append(" missing_state: ");
out.append(YESNO(this->missing_state));
out.append("\n");
out.append(" in_progress: ");
out.append(YESNO(this->in_progress));
out.append("\n");
out.append(" has_progress: ");
out.append(YESNO(this->has_progress));
out.append("\n");
out.append(" progress: ");
sprintf(buffer, "%g", this->progress);
out.append(buffer);
out.append("\n");
out.append(" current_version: ");
out.append("'").append(this->current_version).append("'");
out.append("\n");
out.append(" latest_version: ");
out.append("'").append(this->latest_version).append("'");
out.append("\n");
out.append(" title: ");
out.append("'").append(this->title).append("'");
out.append("\n");
out.append(" release_summary: ");
out.append("'").append(this->release_summary).append("'");
out.append("\n");
out.append(" release_url: ");
out.append("'").append(this->release_url).append("'");
out.append("\n");
out.append("}");
}
#endif
bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->install = value.as_bool();
return true;
}
default:
return false;
}
}
bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void UpdateCommandRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_bool(2, this->install);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void UpdateCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("UpdateCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%" PRIu32, this->key);
out.append(buffer);
out.append("\n");
out.append(" install: ");
out.append(YESNO(this->install));
out.append("\n");
out.append("}");
}
#endif
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

View File

@@ -191,6 +191,12 @@ enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_TTS_STREAM_START = 98, VOICE_ASSISTANT_TTS_STREAM_START = 98,
VOICE_ASSISTANT_TTS_STREAM_END = 99, VOICE_ASSISTANT_TTS_STREAM_END = 99,
}; };
enum VoiceAssistantTimerEvent : uint32_t {
VOICE_ASSISTANT_TIMER_STARTED = 0,
VOICE_ASSISTANT_TIMER_UPDATED = 1,
VOICE_ASSISTANT_TIMER_CANCELLED = 2,
VOICE_ASSISTANT_TIMER_FINISHED = 3,
};
enum AlarmControlPanelState : uint32_t { enum AlarmControlPanelState : uint32_t {
ALARM_STATE_DISARMED = 0, ALARM_STATE_DISARMED = 0,
ALARM_STATE_ARMED_HOME = 1, ALARM_STATE_ARMED_HOME = 1,
@@ -1775,6 +1781,23 @@ class VoiceAssistantAudio : 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 VoiceAssistantTimerEventResponse : public ProtoMessage {
public:
enums::VoiceAssistantTimerEvent event_type{};
std::string timer_id{};
std::string name{};
uint32_t total_seconds{0};
uint32_t seconds_left{0};
bool is_active{false};
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 ListEntitiesAlarmControlPanelResponse : public ProtoMessage { class ListEntitiesAlarmControlPanelResponse : public ProtoMessage {
public: public:
std::string object_id{}; std::string object_id{};
@@ -2107,6 +2130,61 @@ class DateTimeCommandRequest : 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 ListEntitiesUpdateResponse : public ProtoMessage {
public:
std::string object_id{};
uint32_t key{0};
std::string name{};
std::string unique_id{};
std::string icon{};
bool disabled_by_default{false};
enums::EntityCategory entity_category{};
std::string device_class{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class UpdateStateResponse : public ProtoMessage {
public:
uint32_t key{0};
bool missing_state{false};
bool in_progress{false};
bool has_progress{false};
float progress{0.0f};
std::string current_version{};
std::string latest_version{};
std::string title{};
std::string release_summary{};
std::string release_url{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class UpdateCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
bool install{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

View File

@@ -484,6 +484,8 @@ bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAud
return this->send_message_<VoiceAssistantAudio>(msg, 106); return this->send_message_<VoiceAssistantAudio>(msg, 106);
} }
#endif #endif
#ifdef USE_VOICE_ASSISTANT
#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) {
@@ -609,6 +611,24 @@ bool APIServerConnectionBase::send_date_time_state_response(const DateTimeStateR
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
#endif #endif
#ifdef USE_UPDATE
bool APIServerConnectionBase::send_list_entities_update_response(const ListEntitiesUpdateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_update_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesUpdateResponse>(msg, 116);
}
#endif
#ifdef USE_UPDATE
bool APIServerConnectionBase::send_update_state_response(const UpdateStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_update_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<UpdateStateResponse>(msg, 117);
}
#endif
#ifdef USE_UPDATE
#endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) { switch (msg_type) {
case 1: { case 1: {
@@ -1093,6 +1113,28 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str());
#endif #endif
this->on_date_time_command_request(msg); this->on_date_time_command_request(msg);
#endif
break;
}
case 115: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantTimerEventResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_timer_event_response(msg);
#endif
break;
}
case 118: {
#ifdef USE_UPDATE
UpdateCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
#endif
this->on_update_command_request(msg);
#endif #endif
break; break;
} }
@@ -1421,6 +1463,19 @@ void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequ
this->datetime_command(msg); this->datetime_command(msg);
} }
#endif #endif
#ifdef USE_UPDATE
void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->update_command(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) { const SubscribeBluetoothLEAdvertisementsRequest &msg) {

View File

@@ -244,6 +244,9 @@ class APIServerConnectionBase : public ProtoService {
bool send_voice_assistant_audio(const VoiceAssistantAudio &msg); bool send_voice_assistant_audio(const VoiceAssistantAudio &msg);
virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){}; virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){};
#endif #endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){};
#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
@@ -303,6 +306,15 @@ class APIServerConnectionBase : public ProtoService {
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
virtual void on_date_time_command_request(const DateTimeCommandRequest &value){}; virtual void on_date_time_command_request(const DateTimeCommandRequest &value){};
#endif
#ifdef USE_UPDATE
bool send_list_entities_update_response(const ListEntitiesUpdateResponse &msg);
#endif
#ifdef USE_UPDATE
bool send_update_state_response(const UpdateStateResponse &msg);
#endif
#ifdef USE_UPDATE
virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif #endif
protected: protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
@@ -370,6 +382,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
virtual void datetime_command(const DateTimeCommandRequest &msg) = 0; virtual void datetime_command(const DateTimeCommandRequest &msg) = 0;
#endif #endif
#ifdef USE_UPDATE
virtual void update_command(const UpdateCommandRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif #endif
@@ -468,6 +483,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
void on_date_time_command_request(const DateTimeCommandRequest &msg) override; void on_date_time_command_request(const DateTimeCommandRequest &msg) override;
#endif #endif
#ifdef USE_UPDATE
void on_update_command_request(const UpdateCommandRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif #endif

View File

@@ -334,6 +334,13 @@ void APIServer::on_event(event::Event *obj, const std::string &event_type) {
} }
#endif #endif
#ifdef USE_UPDATE
void APIServer::on_update(update::UpdateEntity *obj) {
for (auto &c : this->clients_)
c->send_update_state(obj);
}
#endif
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void APIServer::set_port(uint16_t port) { this->port_ = port; } void APIServer::set_port(uint16_t port) { this->port_ = port; }
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

View File

@@ -102,6 +102,9 @@ class APIServer : public Component, public Controller {
#ifdef USE_EVENT #ifdef USE_EVENT
void on_event(event::Event *obj, const std::string &event_type) override; void on_event(event::Event *obj, const std::string &event_type) override;
#endif #endif
#ifdef USE_UPDATE
void on_update(update::UpdateEntity *obj) override;
#endif
bool is_connected() const; bool is_connected() const;

View File

@@ -105,7 +105,7 @@ class CustomAPIDevice {
/** Subscribe to the state (or attribute state) of an entity from Home Assistant. /** Subscribe to the state (or attribute state) of an entity from Home Assistant.
* *
* Usage: * Usage:
*å *
* ```cpp * ```cpp
* void setup() override { * void setup() override {
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast"); * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");

View File

@@ -98,6 +98,9 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont
#ifdef USE_EVENT #ifdef USE_EVENT
bool ListEntitiesIterator::on_event(event::Event *event) { return this->client_->send_event_info(event); } bool ListEntitiesIterator::on_event(event::Event *event) { return this->client_->send_event_info(event); }
#endif #endif
#ifdef USE_UPDATE
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_info(update); }
#endif
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

View File

@@ -75,6 +75,9 @@ class ListEntitiesIterator : public ComponentIterator {
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *event) override; bool on_event(event::Event *event) override;
#endif
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
#endif #endif
bool on_end() override; bool on_end() override;

View File

@@ -77,6 +77,9 @@ bool InitialStateIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont
return this->client_->send_alarm_control_panel_state(a_alarm_control_panel); return this->client_->send_alarm_control_panel_state(a_alarm_control_panel);
} }
#endif #endif
#ifdef USE_UPDATE
bool InitialStateIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_state(update); }
#endif
InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {} InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {}
} // namespace api } // namespace api

View File

@@ -72,6 +72,9 @@ class InitialStateIterator : public ComponentIterator {
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *event) override { return true; }; bool on_event(event::Event *event) override { return true; };
#endif
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
#endif #endif
protected: protected:
APIConnection *client_; APIConnection *client_;

View File

@@ -31,7 +31,7 @@ CONFIG_SCHEMA = (
BEDJET_CLIENT_SCHEMA = cv.Schema( BEDJET_CLIENT_SCHEMA = cv.Schema(
{ {
cv.Required(CONF_BEDJET_ID): cv.use_id(BedJetHub), cv.GenerateID(CONF_BEDJET_ID): cv.use_id(BedJetHub),
} }
) )

View File

@@ -157,5 +157,11 @@ bool BedjetCodec::compare(const uint8_t *data, uint16_t length) {
return explicit_fields_changed; return explicit_fields_changed;
} }
/// Converts a BedJet temp step into degrees Celsius.
float bedjet_temp_to_c(uint8_t temp) {
// BedJet temp is "C*2"; to get C, divide by 2.
return temp / 2.0f;
}
} // namespace bedjet } // namespace bedjet
} // namespace esphome } // namespace esphome

View File

@@ -187,5 +187,8 @@ class BedjetCodec {
BedjetStatusPacket buf_; BedjetStatusPacket buf_;
}; };
/// Converts a BedJet temp step into degrees Celsius.
float bedjet_temp_to_c(uint8_t temp);
} // namespace bedjet } // namespace bedjet
} // namespace esphome } // namespace esphome

View File

@@ -40,6 +40,14 @@ enum BedjetHeatMode {
HEAT_MODE_EXTENDED, HEAT_MODE_EXTENDED,
}; };
// Which temperature to use as the climate entity's current temperature reading
enum BedjetTemperatureSource {
// Use the temperature of the air the BedJet is putting out
TEMPERATURE_SOURCE_OUTLET,
// Use the ambient temperature of the room the BedJet is in
TEMPERATURE_SOURCE_AMBIENT
};
enum BedjetButton : uint8_t { enum BedjetButton : uint8_t {
/// Turn BedJet off /// Turn BedJet off
BTN_OFF = 0x1, BTN_OFF = 0x1,

View File

@@ -7,6 +7,7 @@ from esphome.const import (
CONF_HEAT_MODE, CONF_HEAT_MODE,
CONF_ID, CONF_ID,
CONF_RECEIVE_TIMEOUT, CONF_RECEIVE_TIMEOUT,
CONF_TEMPERATURE_SOURCE,
CONF_TIME_ID, CONF_TIME_ID,
) )
from .. import ( from .. import (
@@ -21,10 +22,15 @@ DEPENDENCIES = ["bedjet"]
BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent) BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent)
BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode") BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode")
BedjetTemperatureSource = bedjet_ns.enum("BedjetTemperatureSource")
BEDJET_HEAT_MODES = { BEDJET_HEAT_MODES = {
"heat": BedjetHeatMode.HEAT_MODE_HEAT, "heat": BedjetHeatMode.HEAT_MODE_HEAT,
"extended": BedjetHeatMode.HEAT_MODE_EXTENDED, "extended": BedjetHeatMode.HEAT_MODE_EXTENDED,
} }
BEDJET_TEMPERATURE_SOURCES = {
"outlet": BedjetTemperatureSource.TEMPERATURE_SOURCE_OUTLET,
"ambient": BedjetTemperatureSource.TEMPERATURE_SOURCE_AMBIENT,
}
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
climate.CLIMATE_SCHEMA.extend( climate.CLIMATE_SCHEMA.extend(
@@ -33,6 +39,9 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum( cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum(
BEDJET_HEAT_MODES, lower=True BEDJET_HEAT_MODES, lower=True
), ),
cv.Optional(CONF_TEMPERATURE_SOURCE, default="ambient"): cv.enum(
BEDJET_TEMPERATURE_SOURCES, lower=True
),
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
@@ -63,3 +72,4 @@ async def to_code(config):
await register_bedjet_child(var, config) await register_bedjet_child(var, config)
cg.add(var.set_heating_mode(config[CONF_HEAT_MODE])) cg.add(var.set_heating_mode(config[CONF_HEAT_MODE]))
cg.add(var.set_temperature_source(config[CONF_TEMPERATURE_SOURCE]))

View File

@@ -8,12 +8,6 @@ namespace bedjet {
using namespace esphome::climate; using namespace esphome::climate;
/// Converts a BedJet temp step into degrees Celsius.
float bedjet_temp_to_c(const uint8_t temp) {
// BedJet temp is "C*2"; to get C, divide by 2.
return temp / 2.0f;
}
static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) { static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) {
if (fan_step < BEDJET_FAN_SPEED_COUNT) if (fan_step < BEDJET_FAN_SPEED_COUNT)
return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step]; return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step];
@@ -236,9 +230,14 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) {
if (converted_temp > 0) if (converted_temp > 0)
this->target_temperature = converted_temp; this->target_temperature = converted_temp;
converted_temp = bedjet_temp_to_c(data->ambient_temp_step); if (this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET) {
if (converted_temp > 0) converted_temp = bedjet_temp_to_c(data->actual_temp_step);
} else {
converted_temp = bedjet_temp_to_c(data->ambient_temp_step);
}
if (converted_temp > 0) {
this->current_temperature = converted_temp; this->current_temperature = converted_temp;
}
const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step); const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step);
if (fan_mode_name != nullptr) { if (fan_mode_name != nullptr) {

View File

@@ -28,6 +28,8 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
/** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */ /** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */
void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; } void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; }
/** Sets the temperature source to use for the climate entity's current temperature */
void set_temperature_source(BedjetTemperatureSource source) { this->temperature_source_ = source; }
climate::ClimateTraits traits() override { climate::ClimateTraits traits() override {
auto traits = climate::ClimateTraits(); auto traits = climate::ClimateTraits();
@@ -74,6 +76,7 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
void control(const climate::ClimateCall &call) override; void control(const climate::ClimateCall &call) override;
BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT; BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT;
BedjetTemperatureSource temperature_source_ = TEMPERATURE_SOURCE_AMBIENT;
void reset_state_(); void reset_state_();
bool update_status_(); bool update_status_();

View File

@@ -0,0 +1,55 @@
import logging
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_ID,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
)
from .. import (
BEDJET_CLIENT_SCHEMA,
bedjet_ns,
register_bedjet_child,
)
_LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@jhansche", "@javawizard"]
DEPENDENCIES = ["bedjet"]
CONF_OUTLET_TEMPERATURE = "outlet_temperature"
CONF_AMBIENT_TEMPERATURE = "ambient_temperature"
BedjetSensor = bedjet_ns.class_("BedjetSensor", cg.Component)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(BedjetSensor),
cv.Optional(CONF_OUTLET_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_AMBIENT_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
}
).extend(BEDJET_CLIENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await register_bedjet_child(var, config)
if outlet_temperature_sensor := config.get(CONF_OUTLET_TEMPERATURE):
sensor_var = await sensor.new_sensor(outlet_temperature_sensor)
cg.add(var.set_outlet_temperature_sensor(sensor_var))
if ambient_temperature_sensor := config.get(CONF_AMBIENT_TEMPERATURE):
sensor_var = await sensor.new_sensor(ambient_temperature_sensor)
cg.add(var.set_ambient_temperature_sensor(sensor_var))

View File

@@ -0,0 +1,34 @@
#include "bedjet_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bedjet {
std::string BedjetSensor::describe() { return "BedJet Sensor"; }
void BedjetSensor::dump_config() {
ESP_LOGCONFIG(TAG, "BedJet Sensor:");
LOG_SENSOR(" ", "Outlet Temperature", this->outlet_temperature_sensor_);
LOG_SENSOR(" ", "Ambient Temperature", this->ambient_temperature_sensor_);
}
void BedjetSensor::on_bedjet_state(bool is_ready) {}
void BedjetSensor::on_status(const BedjetStatusPacket *data) {
if (this->outlet_temperature_sensor_ != nullptr) {
float converted_temp = bedjet_temp_to_c(data->actual_temp_step);
if (converted_temp > 0) {
this->outlet_temperature_sensor_->publish_state(converted_temp);
}
}
if (this->ambient_temperature_sensor_ != nullptr) {
float converted_temp = bedjet_temp_to_c(data->ambient_temp_step);
if (converted_temp > 0) {
this->ambient_temperature_sensor_->publish_state(converted_temp);
}
}
}
} // namespace bedjet
} // namespace esphome

View File

@@ -0,0 +1,32 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/bedjet/bedjet_child.h"
#include "esphome/components/bedjet/bedjet_codec.h"
namespace esphome {
namespace bedjet {
class BedjetSensor : public BedJetClient, public Component {
public:
void dump_config() override;
void on_status(const BedjetStatusPacket *data) override;
void on_bedjet_state(bool is_ready) override;
std::string describe() override;
void set_outlet_temperature_sensor(sensor::Sensor *outlet_temperature_sensor) {
this->outlet_temperature_sensor_ = outlet_temperature_sensor;
}
void set_ambient_temperature_sensor(sensor::Sensor *ambient_temperature_sensor) {
this->ambient_temperature_sensor_ = ambient_temperature_sensor;
}
protected:
sensor::Sensor *outlet_temperature_sensor_{nullptr};
sensor::Sensor *ambient_temperature_sensor_{nullptr};
};
} // namespace bedjet
} // namespace esphome

View File

@@ -0,0 +1,384 @@
#include "led_strip.h"
#ifdef USE_BK72XX
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
extern "C" {
#include "rtos_pub.h"
#include "spi.h"
#include "arm_arch.h"
#include "general_dma_pub.h"
#include "gpio_pub.h"
#include "icu_pub.h"
#undef SPI_DAT
#undef SPI_BASE
};
static const uint32_t SPI_TX_DMA_CHANNEL = GDMA_CHANNEL_3;
// TODO: Check if SPI_PERI_CLK_DCO depends on the chip variant
static const uint32_t SPI_PERI_CLK_26M = 26000000;
static const uint32_t SPI_PERI_CLK_DCO = 120000000;
static const uint32_t SPI_BASE = 0x00802700;
static const uint32_t SPI_DAT = SPI_BASE + 3 * 4;
static const uint32_t SPI_CONFIG = SPI_BASE + 1 * 4;
static const uint32_t SPI_TX_EN = 1 << 0;
static const uint32_t CTRL_NSSMD_3 = 1 << 17;
static const uint32_t SPI_TX_FINISH_EN = 1 << 2;
static const uint32_t SPI_RX_FINISH_EN = 1 << 3;
namespace esphome {
namespace beken_spi_led_strip {
static const char *const TAG = "beken_spi_led_strip";
struct spi_data_t {
SemaphoreHandle_t dma_tx_semaphore;
volatile bool tx_in_progress;
bool first_run;
};
static spi_data_t *spi_data = nullptr;
static void set_spi_ctrl_register(unsigned long bit, bool val) {
uint32_t value = REG_READ(SPI_CTRL);
if (val == 0) {
value &= ~bit;
} else if (val == 1) {
value |= bit;
}
REG_WRITE(SPI_CTRL, value);
}
static void set_spi_config_register(unsigned long bit, bool val) {
uint32_t value = REG_READ(SPI_CONFIG);
if (val == 0) {
value &= ~bit;
} else if (val == 1) {
value |= bit;
}
REG_WRITE(SPI_CONFIG, value);
}
void spi_dma_tx_enable(bool enable) {
GDMA_CFG_ST en_cfg;
set_spi_config_register(SPI_TX_EN, enable ? 1 : 0);
en_cfg.channel = SPI_TX_DMA_CHANNEL;
en_cfg.param = enable ? 1 : 0;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg);
}
static void spi_set_clock(uint32_t max_hz) {
int source_clk = 0;
int spi_clk = 0;
int div = 0;
uint32_t param;
if (max_hz > 4333000) {
if (max_hz > 30000000) {
spi_clk = 30000000;
} else {
spi_clk = max_hz;
}
sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_DOWN, &param);
source_clk = SPI_PERI_CLK_DCO;
param = PCLK_POSI_SPI;
sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_DCO, &param);
param = PWD_SPI_CLK_BIT;
sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, &param);
} else {
spi_clk = max_hz;
#if CFG_XTAL_FREQUENCE
source_clk = CFG_XTAL_FREQUENCE;
#else
source_clk = SPI_PERI_CLK_26M;
#endif
param = PCLK_POSI_SPI;
sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, &param);
}
div = ((source_clk >> 1) / spi_clk);
if (div < 2) {
div = 2;
} else if (div >= 255) {
div = 255;
}
param = REG_READ(SPI_CTRL);
param &= ~(SPI_CKR_MASK << SPI_CKR_POSI);
param |= (div << SPI_CKR_POSI);
REG_WRITE(SPI_CTRL, param);
ESP_LOGD(TAG, "target frequency: %d, actual frequency: %d", max_hz, source_clk / 2 / div);
}
void spi_dma_tx_finish_callback(unsigned int param) {
spi_data->tx_in_progress = false;
xSemaphoreGive(spi_data->dma_tx_semaphore);
spi_dma_tx_enable(0);
}
void BekenSPILEDStripLightOutput::setup() {
ESP_LOGCONFIG(TAG, "Setting up Beken SPI LED Strip...");
size_t buffer_size = this->get_buffer_size_();
size_t dma_buffer_size = (buffer_size * 8) + (2 * 64);
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
this->buf_ = allocator.allocate(buffer_size);
if (this->buf_ == nullptr) {
ESP_LOGE(TAG, "Cannot allocate LED buffer!");
this->mark_failed();
return;
}
this->effect_data_ = allocator.allocate(this->num_leds_);
if (this->effect_data_ == nullptr) {
ESP_LOGE(TAG, "Cannot allocate effect data!");
this->mark_failed();
return;
}
this->dma_buf_ = allocator.allocate(dma_buffer_size);
if (this->dma_buf_ == nullptr) {
ESP_LOGE(TAG, "Cannot allocate DMA buffer!");
this->mark_failed();
return;
}
memset(this->buf_, 0, buffer_size);
memset(this->effect_data_, 0, this->num_leds_);
memset(this->dma_buf_, 0, dma_buffer_size);
uint32_t value = PCLK_POSI_SPI;
sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, &value);
value = PWD_SPI_CLK_BIT;
sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, &value);
if (spi_data != nullptr) {
ESP_LOGE(TAG, "SPI device already initialized!");
this->mark_failed();
return;
}
spi_data = (spi_data_t *) calloc(1, sizeof(spi_data_t));
if (spi_data == nullptr) {
ESP_LOGE(TAG, "Cannot allocate spi_data!");
this->mark_failed();
return;
}
spi_data->dma_tx_semaphore = xSemaphoreCreateBinary();
if (spi_data->dma_tx_semaphore == nullptr) {
ESP_LOGE(TAG, "TX Semaphore init faild!");
this->mark_failed();
return;
}
spi_data->first_run = true;
set_spi_ctrl_register(MSTEN, 0);
set_spi_ctrl_register(BIT_WDTH, 0);
spi_set_clock(this->spi_frequency_);
set_spi_ctrl_register(CKPOL, 0);
set_spi_ctrl_register(CKPHA, 0);
set_spi_ctrl_register(MSTEN, 1);
set_spi_ctrl_register(SPIEN, 1);
set_spi_ctrl_register(TXINT_EN, 0);
set_spi_ctrl_register(RXINT_EN, 0);
set_spi_config_register(SPI_TX_FINISH_EN, 1);
set_spi_config_register(SPI_RX_FINISH_EN, 1);
set_spi_ctrl_register(RXOVR_EN, 0);
set_spi_ctrl_register(TXOVR_EN, 0);
value = REG_READ(SPI_CTRL);
value &= ~CTRL_NSSMD_3;
value |= (1 << 17);
REG_WRITE(SPI_CTRL, value);
value = GFUNC_MODE_SPI_DMA;
sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &value);
set_spi_ctrl_register(SPI_S_CS_UP_INT_EN, 0);
GDMA_CFG_ST en_cfg;
GDMACFG_TPYES_ST init_cfg;
memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST));
init_cfg.dstdat_width = 8;
init_cfg.srcdat_width = 32;
init_cfg.dstptr_incr = 0;
init_cfg.srcptr_incr = 1;
init_cfg.src_start_addr = this->dma_buf_;
init_cfg.dst_start_addr = (void *) SPI_DAT; // SPI_DMA_REG4_TXFIFO
init_cfg.channel = SPI_TX_DMA_CHANNEL;
init_cfg.prio = 0; // 10
init_cfg.u.type4.src_loop_start_addr = this->dma_buf_;
init_cfg.u.type4.src_loop_end_addr = this->dma_buf_ + dma_buffer_size;
init_cfg.half_fin_handler = nullptr;
init_cfg.fin_handler = spi_dma_tx_finish_callback;
init_cfg.src_module = GDMA_X_SRC_DTCM_RD_REQ;
init_cfg.dst_module = GDMA_X_DST_GSPI_TX_REQ; // GDMA_X_DST_HSSPI_TX_REQ
sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE4, (void *) &init_cfg);
en_cfg.channel = SPI_TX_DMA_CHANNEL;
en_cfg.param = dma_buffer_size;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *) &en_cfg);
en_cfg.channel = SPI_TX_DMA_CHANNEL;
en_cfg.param = 0;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_WORK_MODE, (void *) &en_cfg);
en_cfg.channel = SPI_TX_DMA_CHANNEL;
en_cfg.param = 0;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_SRCADDR_LOOP, &en_cfg);
spi_dma_tx_enable(0);
value = REG_READ(SPI_CONFIG);
value &= ~(0xFFF << 8);
value |= ((dma_buffer_size & 0xFFF) << 8);
REG_WRITE(SPI_CONFIG, value);
}
void BekenSPILEDStripLightOutput::set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency) {
this->bit0_ = bit0;
this->bit1_ = bit1;
this->spi_frequency_ = spi_frequency;
}
void BekenSPILEDStripLightOutput::write_state(light::LightState *state) {
// protect from refreshing too often
uint32_t now = micros();
if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
// try again next loop iteration, so that this change won't get lost
this->schedule_show();
return;
}
this->last_refresh_ = now;
this->mark_shown_();
ESP_LOGVV(TAG, "Writing RGB values to bus...");
if (spi_data == nullptr) {
ESP_LOGE(TAG, "SPI not initialized");
this->status_set_warning();
return;
}
if (!spi_data->first_run && !xSemaphoreTake(spi_data->dma_tx_semaphore, 10 / portTICK_PERIOD_MS)) {
ESP_LOGE(TAG, "Timed out waiting for semaphore");
return;
}
if (spi_data->tx_in_progress) {
ESP_LOGE(TAG, "tx_in_progress is set");
this->status_set_warning();
return;
}
spi_data->tx_in_progress = true;
size_t buffer_size = this->get_buffer_size_();
size_t size = 0;
uint8_t *psrc = this->buf_;
uint8_t *pdest = this->dma_buf_ + 64;
// The 64 byte padding is a workaround for a SPI DMA bug where the
// output doesn't exactly start at the beginning of dma_buf_
while (size < buffer_size) {
uint8_t b = *psrc;
for (int i = 0; i < 8; i++) {
*pdest++ = b & (1 << (7 - i)) ? this->bit1_ : this->bit0_;
}
size++;
psrc++;
}
spi_data->first_run = false;
spi_dma_tx_enable(1);
this->status_clear_warning();
}
light::ESPColorView BekenSPILEDStripLightOutput::get_view_internal(int32_t index) const {
int32_t r = 0, g = 0, b = 0;
switch (this->rgb_order_) {
case ORDER_RGB:
r = 0;
g = 1;
b = 2;
break;
case ORDER_RBG:
r = 0;
g = 2;
b = 1;
break;
case ORDER_GRB:
r = 1;
g = 0;
b = 2;
break;
case ORDER_GBR:
r = 2;
g = 0;
b = 1;
break;
case ORDER_BGR:
r = 2;
g = 1;
b = 0;
break;
case ORDER_BRG:
r = 1;
g = 2;
b = 0;
break;
}
uint8_t multiplier = this->is_rgbw_ || this->is_wrgb_ ? 4 : 3;
uint8_t white = this->is_wrgb_ ? 0 : 3;
return {this->buf_ + (index * multiplier) + r + this->is_wrgb_,
this->buf_ + (index * multiplier) + g + this->is_wrgb_,
this->buf_ + (index * multiplier) + b + this->is_wrgb_,
this->is_rgbw_ || this->is_wrgb_ ? this->buf_ + (index * multiplier) + white : nullptr,
&this->effect_data_[index],
&this->correction_};
}
void BekenSPILEDStripLightOutput::dump_config() {
ESP_LOGCONFIG(TAG, "Beken SPI LED Strip:");
ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_);
const char *rgb_order;
switch (this->rgb_order_) {
case ORDER_RGB:
rgb_order = "RGB";
break;
case ORDER_RBG:
rgb_order = "RBG";
break;
case ORDER_GRB:
rgb_order = "GRB";
break;
case ORDER_GBR:
rgb_order = "GBR";
break;
case ORDER_BGR:
rgb_order = "BGR";
break;
case ORDER_BRG:
rgb_order = "BRG";
break;
default:
rgb_order = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order);
ESP_LOGCONFIG(TAG, " Max refresh rate: %" PRIu32, *this->max_refresh_rate_);
ESP_LOGCONFIG(TAG, " Number of LEDs: %u", this->num_leds_);
}
float BekenSPILEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }
} // namespace beken_spi_led_strip
} // namespace esphome
#endif // USE_BK72XX

View File

@@ -0,0 +1,85 @@
#pragma once
#ifdef USE_BK72XX
#include "esphome/components/light/addressable_light.h"
#include "esphome/components/light/light_output.h"
#include "esphome/core/color.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace beken_spi_led_strip {
enum RGBOrder : uint8_t {
ORDER_RGB,
ORDER_RBG,
ORDER_GRB,
ORDER_GBR,
ORDER_BGR,
ORDER_BRG,
};
class BekenSPILEDStripLightOutput : public light::AddressableLight {
public:
void setup() override;
void write_state(light::LightState *state) override;
float get_setup_priority() const override;
int32_t size() const override { return this->num_leds_; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
if (this->is_rgbw_ || this->is_wrgb_) {
traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
} else {
traits.set_supported_color_modes({light::ColorMode::RGB});
}
return traits;
}
void set_pin(uint8_t pin) { this->pin_ = pin; }
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
void set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency);
void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; }
void clear_effect_data() override {
for (int i = 0; i < this->size(); i++)
this->effect_data_[i] = 0;
}
void dump_config() override;
protected:
light::ESPColorView get_view_internal(int32_t index) const override;
size_t get_buffer_size_() const { return this->num_leds_ * (this->is_rgbw_ || this->is_wrgb_ ? 4 : 3); }
uint8_t *buf_{nullptr};
uint8_t *effect_data_{nullptr};
uint8_t *dma_buf_{nullptr};
uint8_t pin_;
uint16_t num_leds_;
bool is_rgbw_;
bool is_wrgb_;
uint32_t spi_frequency_{6666666};
uint8_t bit0_{0xE0};
uint8_t bit1_{0xFC};
RGBOrder rgb_order_;
uint32_t last_refresh_{0};
optional<uint32_t> max_refresh_rate_{};
};
} // namespace beken_spi_led_strip
} // namespace esphome
#endif // USE_BK72XX

View File

@@ -0,0 +1,134 @@
from dataclasses import dataclass
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import libretiny, light
from esphome.const import (
CONF_CHIPSET,
CONF_IS_RGBW,
CONF_MAX_REFRESH_RATE,
CONF_NUM_LEDS,
CONF_OUTPUT_ID,
CONF_PIN,
CONF_RGB_ORDER,
)
CODEOWNERS = ["@Mat931"]
DEPENDENCIES = ["libretiny"]
beken_spi_led_strip_ns = cg.esphome_ns.namespace("beken_spi_led_strip")
BekenSPILEDStripLightOutput = beken_spi_led_strip_ns.class_(
"BekenSPILEDStripLightOutput", light.AddressableLight
)
RGBOrder = beken_spi_led_strip_ns.enum("RGBOrder")
RGB_ORDERS = {
"RGB": RGBOrder.ORDER_RGB,
"RBG": RGBOrder.ORDER_RBG,
"GRB": RGBOrder.ORDER_GRB,
"GBR": RGBOrder.ORDER_GBR,
"BGR": RGBOrder.ORDER_BGR,
"BRG": RGBOrder.ORDER_BRG,
}
@dataclass
class LEDStripTimings:
bit0: int
bit1: int
spi_frequency: int
CHIPSETS = {
"WS2812": LEDStripTimings(
0b11100000, 0b11111100, 6666666
), # Clock divider: 9, Bit time: 1350ns
"SK6812": LEDStripTimings(
0b11000000, 0b11111000, 7500000
), # Clock divider: 8, Bit time: 1200ns
"APA106": LEDStripTimings(
0b11000000, 0b11111110, 5454545
), # Clock divider: 11, Bit time: 1650ns
"SM16703": LEDStripTimings(
0b11000000, 0b11111110, 7500000
), # Clock divider: 8, Bit time: 1200ns
}
CONF_IS_WRGB = "is_wrgb"
SUPPORTED_PINS = {
libretiny.const.FAMILY_BK7231N: [16],
libretiny.const.FAMILY_BK7231T: [16],
libretiny.const.FAMILY_BK7251: [16],
}
def _validate_pin(value):
family = libretiny.get_libretiny_family()
if family not in SUPPORTED_PINS:
raise cv.Invalid(f"Chip family {family} is not supported.")
if value not in SUPPORTED_PINS[family]:
supported_pin_info = ", ".join(f"{x}" for x in SUPPORTED_PINS[family])
raise cv.Invalid(
f"Pin {value} is not supported on the {family}. Supported pins: {supported_pin_info}"
)
return value
def _validate_num_leds(value):
max_num_leds = 165 # 170
if value[CONF_IS_RGBW] or value[CONF_IS_WRGB]:
max_num_leds = 123 # 127
if value[CONF_NUM_LEDS] > max_num_leds:
raise cv.Invalid(
f"The maximum number of LEDs for this configuration is {max_num_leds}.",
path=CONF_NUM_LEDS,
)
return value
CONFIG_SCHEMA = cv.All(
light.ADDRESSABLE_LIGHT_SCHEMA.extend(
{
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(BekenSPILEDStripLightOutput),
cv.Required(CONF_PIN): cv.All(
pins.internal_gpio_output_pin_number, _validate_pin
),
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True),
cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
cv.Required(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
}
),
_validate_num_leds,
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
await light.register_light(var, config)
await cg.register_component(var, config)
cg.add(var.set_num_leds(config[CONF_NUM_LEDS]))
cg.add(var.set_pin(config[CONF_PIN]))
if CONF_MAX_REFRESH_RATE in config:
cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
chipset = CHIPSETS[config[CONF_CHIPSET]]
cg.add(
var.set_led_params(
chipset.bit0,
chipset.bit1,
chipset.spi_frequency,
)
)
cg.add(var.set_rgb_order(config[CONF_RGB_ORDER]))
cg.add(var.set_is_rgbw(config[CONF_IS_RGBW]))
cg.add(var.set_is_wrgb(config[CONF_IS_WRGB]))

View File

@@ -4,7 +4,7 @@ from esphome.cpp_generator import MockObjClass
from esphome.cpp_helpers import setup_entity 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
from esphome.components import mqtt from esphome.components import mqtt, web_server
from esphome.const import ( from esphome.const import (
CONF_DELAY, CONF_DELAY,
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
@@ -27,6 +27,7 @@ from esphome.const import (
CONF_TIMING, CONF_TIMING,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_MQTT_ID, CONF_MQTT_ID,
CONF_WEB_SERVER_ID,
DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY,
DEVICE_CLASS_BATTERY_CHARGING, DEVICE_CLASS_BATTERY_CHARGING,
DEVICE_CLASS_CARBON_MONOXIDE, DEVICE_CLASS_CARBON_MONOXIDE,
@@ -385,70 +386,76 @@ def validate_click_timing(value):
return value return value
BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( BINARY_SENSOR_SCHEMA = (
{ cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
cv.GenerateID(): cv.declare_id(BinarySensor), .extend(cv.MQTT_COMPONENT_SCHEMA)
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( .extend(
mqtt.MQTTBinarySensorComponent {
), cv.GenerateID(): cv.declare_id(BinarySensor),
cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean, cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
cv.Optional(CONF_DEVICE_CLASS): validate_device_class, mqtt.MQTTBinarySensorComponent
cv.Optional(CONF_FILTERS): validate_filters, ),
cv.Optional(CONF_ON_PRESS): automation.validate_automation( cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean,
{ cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger), cv.Optional(CONF_FILTERS): validate_filters,
} cv.Optional(CONF_ON_PRESS): automation.validate_automation(
),
cv.Optional(CONF_ON_RELEASE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger),
}
),
cv.Optional(CONF_ON_CLICK): cv.All(
automation.validate_automation(
{ {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger),
cv.Optional(
CONF_MIN_LENGTH, default="50ms"
): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_MAX_LENGTH, default="350ms"
): cv.positive_time_period_milliseconds,
} }
), ),
validate_click_timing, cv.Optional(CONF_ON_RELEASE): automation.validate_automation(
),
cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All(
automation.validate_automation(
{ {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger),
cv.Optional(
CONF_MIN_LENGTH, default="50ms"
): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_MAX_LENGTH, default="350ms"
): cv.positive_time_period_milliseconds,
} }
), ),
validate_click_timing, cv.Optional(CONF_ON_CLICK): cv.All(
), automation.validate_automation(
cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation( {
{ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger), cv.Optional(
cv.Required(CONF_TIMING): cv.All( CONF_MIN_LENGTH, default="50ms"
[parse_multi_click_timing_str], validate_multi_click_timing ): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_MAX_LENGTH, default="350ms"
): cv.positive_time_period_milliseconds,
}
), ),
cv.Optional( validate_click_timing,
CONF_INVALID_COOLDOWN, default="1s" ),
): cv.positive_time_period_milliseconds, cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All(
} automation.validate_automation(
), {
cv.Optional(CONF_ON_STATE): automation.validate_automation( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
{ DoubleClickTrigger
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), ),
} cv.Optional(
), CONF_MIN_LENGTH, default="50ms"
} ): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_MAX_LENGTH, default="350ms"
): cv.positive_time_period_milliseconds,
}
),
validate_click_timing,
),
cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger),
cv.Required(CONF_TIMING): cv.All(
[parse_multi_click_timing_str], validate_multi_click_timing
),
cv.Optional(
CONF_INVALID_COOLDOWN, default="1s"
): cv.positive_time_period_milliseconds,
}
),
cv.Optional(CONF_ON_STATE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
}
),
}
)
) )
_UNDEF = object() _UNDEF = object()
@@ -536,6 +543,10 @@ async def setup_binary_sensor_core_(var, config):
mqtt_ = cg.new_Pvariable(mqtt_id, var) mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config) await mqtt.register_mqtt_component(mqtt_, config)
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config)
async def register_binary_sensor(var, config): async def register_binary_sensor(var, config):
if not CORE.has_id(config[CONF_ID]): if not CORE.has_id(config[CONF_ID]):

View File

@@ -98,6 +98,11 @@ void binary_sensor::MultiClickTrigger::schedule_is_not_valid_(uint32_t max_lengt
this->schedule_cooldown_(); this->schedule_cooldown_();
}); });
} }
void binary_sensor::MultiClickTrigger::cancel() {
ESP_LOGV(TAG, "Multi Click: Sequence explicitly cancelled.");
this->is_valid_ = false;
this->schedule_cooldown_();
}
void binary_sensor::MultiClickTrigger::trigger_() { void binary_sensor::MultiClickTrigger::trigger_() {
ESP_LOGV(TAG, "Multi Click: Hooray, multi click is valid. Triggering!"); ESP_LOGV(TAG, "Multi Click: Hooray, multi click is valid. Triggering!");
this->at_index_.reset(); this->at_index_.reset();

View File

@@ -105,6 +105,8 @@ class MultiClickTrigger : public Trigger<>, public Component {
void set_invalid_cooldown(uint32_t invalid_cooldown) { this->invalid_cooldown_ = invalid_cooldown; } void set_invalid_cooldown(uint32_t invalid_cooldown) { this->invalid_cooldown_ = invalid_cooldown; }
void cancel();
protected: protected:
void on_state_(bool state); void on_state_(bool state);
void schedule_cooldown_(); void schedule_cooldown_();

View File

@@ -6,16 +6,6 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#ifdef USE_ARDUINO
#include "mbedtls/aes.h"
#include "mbedtls/base64.h"
#endif
#ifdef USE_ESP_IDF
#define MBEDTLS_AES_ALT
#include <aes_alt.h>
#endif
namespace esphome { namespace esphome {
namespace ble_presence { namespace ble_presence {
@@ -72,7 +62,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
} }
break; break;
case MATCH_BY_IRK: case MATCH_BY_IRK:
if (resolve_irk_(device.address_uint64(), this->irk_)) { if (device.resolve_irk(this->irk_)) {
this->set_found_(true); this->set_found_(true);
return true; return true;
} }
@@ -142,43 +132,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
bool check_ibeacon_minor_{false}; bool check_ibeacon_minor_{false};
bool check_minimum_rssi_{false}; bool check_minimum_rssi_{false};
bool resolve_irk_(uint64_t addr64, const uint8_t *irk) {
uint8_t ecb_key[16];
uint8_t ecb_plaintext[16];
uint8_t ecb_ciphertext[16];
memcpy(&ecb_key, irk, 16);
memset(&ecb_plaintext, 0, 16);
ecb_plaintext[13] = (addr64 >> 40) & 0xff;
ecb_plaintext[14] = (addr64 >> 32) & 0xff;
ecb_plaintext[15] = (addr64 >> 24) & 0xff;
mbedtls_aes_context ctx = {0, 0, {0}};
mbedtls_aes_init(&ctx);
if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) {
mbedtls_aes_free(&ctx);
return false;
}
if (mbedtls_aes_crypt_ecb(&ctx,
#ifdef USE_ARDUINO
MBEDTLS_AES_ENCRYPT,
#elif defined(USE_ESP_IDF)
ESP_AES_ENCRYPT,
#endif
ecb_plaintext, ecb_ciphertext) != 0) {
mbedtls_aes_free(&ctx);
return false;
}
mbedtls_aes_free(&ctx);
return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
}
bool found_{false}; bool found_{false};
uint32_t last_seen_{}; uint32_t last_seen_{};
uint32_t timeout_{}; uint32_t timeout_{};

View File

@@ -15,6 +15,10 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
this->match_by_ = MATCH_BY_MAC_ADDRESS; this->match_by_ = MATCH_BY_MAC_ADDRESS;
this->address_ = address; this->address_ = address;
} }
void set_irk(uint8_t *irk) {
this->match_by_ = MATCH_BY_IRK;
this->irk_ = irk;
}
void set_service_uuid16(uint16_t uuid) { void set_service_uuid16(uint16_t uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID; this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid); this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid);
@@ -53,6 +57,13 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
return true; return true;
} }
break; break;
case MATCH_BY_IRK:
if (device.resolve_irk(this->irk_)) {
this->publish_state(device.get_rssi());
this->found_ = true;
return true;
}
break;
case MATCH_BY_SERVICE_UUID: case MATCH_BY_SERVICE_UUID:
for (auto uuid : device.get_service_uuids()) { for (auto uuid : device.get_service_uuids()) {
if (this->uuid_ == uuid) { if (this->uuid_ == uuid) {
@@ -91,12 +102,13 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
float get_setup_priority() const override { return setup_priority::DATA; } float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID }; enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID };
MatchType match_by_; MatchType match_by_;
bool found_{false}; bool found_{false};
uint64_t address_; uint64_t address_;
uint8_t *irk_;
esp32_ble_tracker::ESPBTUUID uuid_; esp32_ble_tracker::ESPBTUUID uuid_;

View File

@@ -12,6 +12,8 @@ from esphome.const import (
UNIT_DECIBEL_MILLIWATT, UNIT_DECIBEL_MILLIWATT,
) )
CONF_IRK = "irk"
DEPENDENCIES = ["esp32_ble_tracker"] DEPENDENCIES = ["esp32_ble_tracker"]
ble_rssi_ns = cg.esphome_ns.namespace("ble_rssi") ble_rssi_ns = cg.esphome_ns.namespace("ble_rssi")
@@ -39,6 +41,7 @@ CONFIG_SCHEMA = cv.All(
.extend( .extend(
{ {
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_IRK): cv.uuid,
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
@@ -47,7 +50,9 @@ CONFIG_SCHEMA = cv.All(
) )
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA), .extend(cv.COMPONENT_SCHEMA),
cv.has_exactly_one_key(CONF_MAC_ADDRESS, CONF_SERVICE_UUID, CONF_IBEACON_UUID), cv.has_exactly_one_key(
CONF_MAC_ADDRESS, CONF_IRK, CONF_SERVICE_UUID, CONF_IBEACON_UUID
),
_validate, _validate,
) )
@@ -60,6 +65,10 @@ async def to_code(config):
if mac_address := config.get(CONF_MAC_ADDRESS): if mac_address := config.get(CONF_MAC_ADDRESS):
cg.add(var.set_address(mac_address.as_hex)) cg.add(var.set_address(mac_address.as_hex))
if irk := config.get(CONF_IRK):
irk = esp32_ble_tracker.as_hex_array(str(irk))
cg.add(var.set_irk(irk))
if service_uuid := config.get(CONF_SERVICE_UUID): if service_uuid := config.get(CONF_SERVICE_UUID):
if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format): if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format):
cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid))) cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid)))

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

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv 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
from esphome.components import mqtt from esphome.components import mqtt, web_server
from esphome.const import ( from esphome.const import (
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
CONF_ENTITY_CATEGORY, CONF_ENTITY_CATEGORY,
@@ -11,6 +11,7 @@ from esphome.const import (
CONF_ON_PRESS, CONF_ON_PRESS,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_MQTT_ID, CONF_MQTT_ID,
CONF_WEB_SERVER_ID,
DEVICE_CLASS_EMPTY, DEVICE_CLASS_EMPTY,
DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_IDENTIFY,
DEVICE_CLASS_RESTART, DEVICE_CLASS_RESTART,
@@ -43,16 +44,20 @@ ButtonPressTrigger = button_ns.class_(
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
BUTTON_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( BUTTON_SCHEMA = (
{ cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent), .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
cv.Optional(CONF_DEVICE_CLASS): validate_device_class, .extend(
cv.Optional(CONF_ON_PRESS): automation.validate_automation( {
{ cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent),
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger), cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
} cv.Optional(CONF_ON_PRESS): automation.validate_automation(
), {
} cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger),
}
),
}
)
) )
_UNDEF = object() _UNDEF = object()
@@ -92,6 +97,10 @@ async def setup_button_core_(var, config):
mqtt_ = cg.new_Pvariable(mqtt_id, var) mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config) await mqtt.register_mqtt_component(mqtt_, config)
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config)
async def register_button(var, config): async def register_button(var, config):
if not CORE.has_id(config[CONF_ID]): if not CORE.has_id(config[CONF_ID]):

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.cpp_helpers import setup_entity from esphome.cpp_helpers import setup_entity
from esphome import automation from esphome import automation
from esphome.components import mqtt from esphome.components import mqtt, web_server
from esphome.const import ( from esphome.const import (
CONF_ACTION_STATE_TOPIC, CONF_ACTION_STATE_TOPIC,
CONF_AWAY, CONF_AWAY,
@@ -44,6 +44,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_VISUAL, CONF_VISUAL,
CONF_MQTT_ID, CONF_MQTT_ID,
CONF_WEB_SERVER_ID,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@@ -150,93 +151,97 @@ VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Any(
), ),
) )
CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( CLIMATE_SCHEMA = (
{ cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
cv.GenerateID(): cv.declare_id(Climate), .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent), .extend(
cv.Optional(CONF_VISUAL, default={}): cv.Schema( {
{ cv.GenerateID(): cv.declare_id(Climate),
cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature, cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent),
cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature, cv.Optional(CONF_VISUAL, default={}): cv.Schema(
cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA, {
cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int, cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int, cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
} cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA,
), cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int,
cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All( cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int,
cv.requires_component("mqtt"), cv.publish_topic }
), ),
cv.Optional(CONF_AWAY_COMMAND_TOPIC): cv.All( cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_AWAY_STATE_TOPIC): cv.All( cv.Optional(CONF_AWAY_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_CURRENT_TEMPERATURE_STATE_TOPIC): cv.All( cv.Optional(CONF_AWAY_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_CURRENT_HUMIDITY_STATE_TOPIC): cv.All( cv.Optional(CONF_CURRENT_TEMPERATURE_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_FAN_MODE_COMMAND_TOPIC): cv.All( cv.Optional(CONF_CURRENT_HUMIDITY_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_FAN_MODE_STATE_TOPIC): cv.All( cv.Optional(CONF_FAN_MODE_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_MODE_COMMAND_TOPIC): cv.All( cv.Optional(CONF_FAN_MODE_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_MODE_STATE_TOPIC): cv.All( cv.Optional(CONF_MODE_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All( cv.Optional(CONF_MODE_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All( cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All( cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_SWING_MODE_STATE_TOPIC): cv.All( cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_TEMPERATURE_COMMAND_TOPIC): cv.All( cv.Optional(CONF_SWING_MODE_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_TEMPERATURE_STATE_TOPIC): cv.All( cv.Optional(CONF_TARGET_TEMPERATURE_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC): cv.All( cv.Optional(CONF_TARGET_TEMPERATURE_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC): cv.All( cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC): cv.All( cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All( cv.Optional(CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): cv.All( cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): cv.All( cv.Optional(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_ON_CONTROL): automation.validate_automation( cv.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): cv.All(
{ cv.requires_component("mqtt"), cv.publish_topic
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger), ),
} cv.Optional(CONF_ON_CONTROL): automation.validate_automation(
), {
cv.Optional(CONF_ON_STATE): automation.validate_automation( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger),
{ }
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger), ),
} cv.Optional(CONF_ON_STATE): automation.validate_automation(
), {
} cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
}
),
}
)
) )
@@ -403,6 +408,10 @@ async def setup_climate_core_(var, config):
trigger, [(ClimateCall.operator("ref"), "x")], conf trigger, [(ClimateCall.operator("ref"), "x")], conf
) )
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config)
async def register_climate(var, config): async def register_climate(var, config):
if not CORE.has_id(config[CONF_ID]): if not CORE.has_id(config[CONF_ID]):

View File

@@ -574,21 +574,25 @@ void Climate::dump_traits_(const char *tag) {
ESP_LOGCONFIG(tag, " - Max temperature: %.1f", traits.get_visual_max_temperature()); ESP_LOGCONFIG(tag, " - Max temperature: %.1f", traits.get_visual_max_temperature());
ESP_LOGCONFIG(tag, " - Temperature step:"); ESP_LOGCONFIG(tag, " - Temperature step:");
ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step()); ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step());
ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step());
ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity());
ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity());
if (traits.get_supports_current_temperature()) { if (traits.get_supports_current_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports current temperature"); ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step());
} }
if (traits.get_supports_current_humidity()) { if (traits.get_supports_target_humidity() || traits.get_supports_current_humidity()) {
ESP_LOGCONFIG(tag, " [x] Supports current humidity"); ESP_LOGCONFIG(tag, " - Min humidity: %.0f", traits.get_visual_min_humidity());
ESP_LOGCONFIG(tag, " - Max humidity: %.0f", traits.get_visual_max_humidity());
} }
if (traits.get_supports_two_point_target_temperature()) { if (traits.get_supports_two_point_target_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature"); ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature");
} }
if (traits.get_supports_current_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports current temperature");
}
if (traits.get_supports_target_humidity()) { if (traits.get_supports_target_humidity()) {
ESP_LOGCONFIG(tag, " [x] Supports target humidity"); ESP_LOGCONFIG(tag, " [x] Supports target humidity");
} }
if (traits.get_supports_current_humidity()) {
ESP_LOGCONFIG(tag, " [x] Supports current humidity");
}
if (traits.get_supports_action()) { if (traits.get_supports_action()) {
ESP_LOGCONFIG(tag, " [x] Supports action"); ESP_LOGCONFIG(tag, " [x] Supports action");
} }

View File

@@ -73,7 +73,7 @@ class ClimateTraits {
ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20")
void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); } void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); }
bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); } bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); }
std::set<ClimateMode> get_supported_modes() const { return supported_modes_; } const std::set<ClimateMode> &get_supported_modes() const { return supported_modes_; }
void set_supports_action(bool supports_action) { supports_action_ = supports_action; } void set_supports_action(bool supports_action) { supports_action_ = supports_action; }
bool get_supports_action() const { return supports_action_; } bool get_supports_action() const { return supports_action_; }
@@ -101,7 +101,7 @@ class ClimateTraits {
void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); } void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); }
bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); } bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); }
bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); } bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); }
std::set<ClimateFanMode> get_supported_fan_modes() const { return supported_fan_modes_; } const std::set<ClimateFanMode> &get_supported_fan_modes() const { return supported_fan_modes_; }
void set_supported_custom_fan_modes(std::set<std::string> supported_custom_fan_modes) { void set_supported_custom_fan_modes(std::set<std::string> supported_custom_fan_modes) {
supported_custom_fan_modes_ = std::move(supported_custom_fan_modes); supported_custom_fan_modes_ = std::move(supported_custom_fan_modes);
@@ -140,7 +140,7 @@ class ClimateTraits {
} }
bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); } bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); }
bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); } bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); }
std::set<ClimateSwingMode> get_supported_swing_modes() const { return supported_swing_modes_; } const std::set<ClimateSwingMode> &get_supported_swing_modes() const { return supported_swing_modes_; }
float get_visual_min_temperature() const { return visual_min_temperature_; } float get_visual_min_temperature() const { return visual_min_temperature_; }
void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; } void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; }

View File

@@ -6,18 +6,24 @@ namespace climate_ir_lg {
static const char *const TAG = "climate.climate_ir_lg"; static const char *const TAG = "climate.climate_ir_lg";
const uint32_t COMMAND_ON = 0x00000; // Commands
const uint32_t COMMAND_ON_AI = 0x03000; const uint32_t COMMAND_MASK = 0xFF000;
const uint32_t COMMAND_COOL = 0x08000;
const uint32_t COMMAND_HEAT = 0x0C000;
const uint32_t COMMAND_OFF = 0xC0000; const uint32_t COMMAND_OFF = 0xC0000;
const uint32_t COMMAND_SWING = 0x10000; const uint32_t COMMAND_SWING = 0x10000;
// On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore.
const uint32_t COMMAND_AUTO = 0x0B000;
const uint32_t COMMAND_DRY_FAN = 0x09000;
const uint32_t COMMAND_MASK = 0xFF000; const uint32_t COMMAND_ON_COOL = 0x00000;
const uint32_t COMMAND_ON_DRY = 0x01000;
const uint32_t COMMAND_ON_FAN_ONLY = 0x02000;
const uint32_t COMMAND_ON_AI = 0x03000;
const uint32_t COMMAND_ON_HEAT = 0x04000;
const uint32_t COMMAND_COOL = 0x08000;
const uint32_t COMMAND_DRY = 0x09000;
const uint32_t COMMAND_FAN_ONLY = 0x0A000;
const uint32_t COMMAND_AI = 0x0B000;
const uint32_t COMMAND_HEAT = 0x0C000;
// Fan speed
const uint32_t FAN_MASK = 0xF0; const uint32_t FAN_MASK = 0xF0;
const uint32_t FAN_AUTO = 0x50; const uint32_t FAN_AUTO = 0x50;
const uint32_t FAN_MIN = 0x00; const uint32_t FAN_MIN = 0x00;
@@ -35,69 +41,67 @@ void LgIrClimate::transmit_state() {
uint32_t remote_state = 0x8800000; uint32_t remote_state = 0x8800000;
// ESP_LOGD(TAG, "climate_lg_ir mode_before_ code: 0x%02X", modeBefore_); // ESP_LOGD(TAG, "climate_lg_ir mode_before_ code: 0x%02X", modeBefore_);
// Set command
if (send_swing_cmd_) { if (send_swing_cmd_) {
send_swing_cmd_ = false; send_swing_cmd_ = false;
remote_state |= COMMAND_SWING; remote_state |= COMMAND_SWING;
} else { } else {
if (mode_before_ == climate::CLIMATE_MODE_OFF && this->mode == climate::CLIMATE_MODE_HEAT_COOL) { bool climate_is_off = (mode_before_ == climate::CLIMATE_MODE_OFF);
remote_state |= COMMAND_ON_AI; switch (this->mode) {
} else if (mode_before_ == climate::CLIMATE_MODE_OFF && this->mode != climate::CLIMATE_MODE_OFF) { case climate::CLIMATE_MODE_COOL:
remote_state |= COMMAND_ON; remote_state |= climate_is_off ? COMMAND_ON_COOL : COMMAND_COOL;
this->mode = climate::CLIMATE_MODE_COOL; break;
} else { case climate::CLIMATE_MODE_DRY:
switch (this->mode) { remote_state |= climate_is_off ? COMMAND_ON_DRY : COMMAND_DRY;
case climate::CLIMATE_MODE_COOL: break;
remote_state |= COMMAND_COOL; case climate::CLIMATE_MODE_FAN_ONLY:
break; remote_state |= climate_is_off ? COMMAND_ON_FAN_ONLY : COMMAND_FAN_ONLY;
case climate::CLIMATE_MODE_HEAT: break;
remote_state |= COMMAND_HEAT; case climate::CLIMATE_MODE_HEAT_COOL:
break; remote_state |= climate_is_off ? COMMAND_ON_AI : COMMAND_AI;
case climate::CLIMATE_MODE_HEAT_COOL: break;
remote_state |= COMMAND_AUTO; case climate::CLIMATE_MODE_HEAT:
break; remote_state |= climate_is_off ? COMMAND_ON_HEAT : COMMAND_HEAT;
case climate::CLIMATE_MODE_DRY: break;
remote_state |= COMMAND_DRY_FAN; case climate::CLIMATE_MODE_OFF:
break; default:
case climate::CLIMATE_MODE_OFF: remote_state |= COMMAND_OFF;
default: break;
remote_state |= COMMAND_OFF;
break;
}
}
mode_before_ = this->mode;
ESP_LOGD(TAG, "climate_lg_ir mode code: 0x%02X", this->mode);
if (this->mode == climate::CLIMATE_MODE_OFF) {
remote_state |= FAN_AUTO;
} else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY ||
this->mode == climate::CLIMATE_MODE_HEAT) {
switch (this->fan_mode.value()) {
case climate::CLIMATE_FAN_HIGH:
remote_state |= FAN_MAX;
break;
case climate::CLIMATE_FAN_MEDIUM:
remote_state |= FAN_MED;
break;
case climate::CLIMATE_FAN_LOW:
remote_state |= FAN_MIN;
break;
case climate::CLIMATE_FAN_AUTO:
default:
remote_state |= FAN_AUTO;
break;
}
}
if (this->mode == climate::CLIMATE_MODE_HEAT_COOL) {
this->fan_mode = climate::CLIMATE_FAN_AUTO;
// remote_state |= FAN_MODE_AUTO_DRY;
}
if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) {
auto temp = (uint8_t) roundf(clamp<float>(this->target_temperature, TEMP_MIN, TEMP_MAX));
remote_state |= ((temp - 15) << TEMP_SHIFT);
} }
} }
mode_before_ = this->mode;
ESP_LOGD(TAG, "climate_lg_ir mode code: 0x%02X", this->mode);
// Set fan speed
if (this->mode == climate::CLIMATE_MODE_OFF) {
remote_state |= FAN_AUTO;
} else {
switch (this->fan_mode.value()) {
case climate::CLIMATE_FAN_HIGH:
remote_state |= FAN_MAX;
break;
case climate::CLIMATE_FAN_MEDIUM:
remote_state |= FAN_MED;
break;
case climate::CLIMATE_FAN_LOW:
remote_state |= FAN_MIN;
break;
case climate::CLIMATE_FAN_AUTO:
default:
remote_state |= FAN_AUTO;
break;
}
}
// Set temperature
if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) {
auto temp = (uint8_t) roundf(clamp<float>(this->target_temperature, TEMP_MIN, TEMP_MAX));
remote_state |= ((temp - 15) << TEMP_SHIFT);
}
transmit_(remote_state); transmit_(remote_state);
this->publish_state(); this->publish_state();
} }
@@ -125,37 +129,42 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) {
if ((remote_state & 0xFF00000) != 0x8800000) if ((remote_state & 0xFF00000) != 0x8800000)
return false; return false;
if ((remote_state & COMMAND_MASK) == COMMAND_ON) { // Get command
this->mode = climate::CLIMATE_MODE_COOL;
} else if ((remote_state & COMMAND_MASK) == COMMAND_ON_AI) {
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
}
if ((remote_state & COMMAND_MASK) == COMMAND_OFF) { if ((remote_state & COMMAND_MASK) == COMMAND_OFF) {
this->mode = climate::CLIMATE_MODE_OFF; this->mode = climate::CLIMATE_MODE_OFF;
} else if ((remote_state & COMMAND_MASK) == COMMAND_SWING) { } else if ((remote_state & COMMAND_MASK) == COMMAND_SWING) {
this->swing_mode = this->swing_mode =
this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF;
} else { } else {
if ((remote_state & COMMAND_MASK) == COMMAND_AUTO) { switch (remote_state & COMMAND_MASK) {
this->mode = climate::CLIMATE_MODE_HEAT_COOL; case COMMAND_DRY:
} else if ((remote_state & COMMAND_MASK) == COMMAND_DRY_FAN) { case COMMAND_ON_DRY:
this->mode = climate::CLIMATE_MODE_DRY; this->mode = climate::CLIMATE_MODE_DRY;
} else if ((remote_state & COMMAND_MASK) == COMMAND_HEAT) { break;
this->mode = climate::CLIMATE_MODE_HEAT; case COMMAND_FAN_ONLY:
} else { case COMMAND_ON_FAN_ONLY:
this->mode = climate::CLIMATE_MODE_COOL; this->mode = climate::CLIMATE_MODE_FAN_ONLY;
break;
case COMMAND_AI:
case COMMAND_ON_AI:
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
break;
case COMMAND_HEAT:
case COMMAND_ON_HEAT:
this->mode = climate::CLIMATE_MODE_HEAT;
break;
case COMMAND_COOL:
case COMMAND_ON_COOL:
default:
this->mode = climate::CLIMATE_MODE_COOL;
break;
} }
// Temperature // Get fan speed
if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT)
this->target_temperature = ((remote_state & TEMP_MASK) >> TEMP_SHIFT) + 15;
// Fan Speed
if (this->mode == climate::CLIMATE_MODE_HEAT_COOL) { if (this->mode == climate::CLIMATE_MODE_HEAT_COOL) {
this->fan_mode = climate::CLIMATE_FAN_AUTO; this->fan_mode = climate::CLIMATE_FAN_AUTO;
} else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT || } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY ||
this->mode == climate::CLIMATE_MODE_DRY) { this->mode == climate::CLIMATE_MODE_FAN_ONLY || this->mode == climate::CLIMATE_MODE_HEAT) {
if ((remote_state & FAN_MASK) == FAN_AUTO) { if ((remote_state & FAN_MASK) == FAN_AUTO) {
this->fan_mode = climate::CLIMATE_FAN_AUTO; this->fan_mode = climate::CLIMATE_FAN_AUTO;
} else if ((remote_state & FAN_MASK) == FAN_MIN) { } else if ((remote_state & FAN_MASK) == FAN_MIN) {
@@ -166,11 +175,17 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) {
this->fan_mode = climate::CLIMATE_FAN_HIGH; this->fan_mode = climate::CLIMATE_FAN_HIGH;
} }
} }
// Get temperature
if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT) {
this->target_temperature = ((remote_state & TEMP_MASK) >> TEMP_SHIFT) + 15;
}
} }
this->publish_state(); this->publish_state();
return true; return true;
} }
void LgIrClimate::transmit_(uint32_t value) { void LgIrClimate::transmit_(uint32_t value) {
calc_checksum_(value); calc_checksum_(value);
ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02" PRIX32, value); ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02" PRIX32, value);

View File

@@ -14,7 +14,7 @@ const uint8_t TEMP_MAX = 30; // Celsius
class LgIrClimate : public climate_ir::ClimateIR { class LgIrClimate : public climate_ir::ClimateIR {
public: public:
LgIrClimate() LgIrClimate()
: climate_ir::ClimateIR(TEMP_MIN, TEMP_MAX, 1.0f, true, false, : climate_ir::ClimateIR(TEMP_MIN, TEMP_MAX, 1.0f, true, true,
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM,
climate::CLIMATE_FAN_HIGH}, climate::CLIMATE_FAN_HIGH},
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {} {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {}

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome import automation from esphome import automation
from esphome.automation import maybe_simple_id, Condition from esphome.automation import maybe_simple_id, Condition
from esphome.components import mqtt from esphome.components import mqtt, web_server
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_ID,
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
@@ -16,6 +16,7 @@ from esphome.const import (
CONF_TILT_STATE_TOPIC, CONF_TILT_STATE_TOPIC,
CONF_STOP, CONF_STOP,
CONF_MQTT_ID, CONF_MQTT_ID,
CONF_WEB_SERVER_ID,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
DEVICE_CLASS_AWNING, DEVICE_CLASS_AWNING,
DEVICE_CLASS_BLIND, DEVICE_CLASS_BLIND,
@@ -88,34 +89,38 @@ CoverClosedTrigger = cover_ns.class_(
CONF_ON_CLOSED = "on_closed" CONF_ON_CLOSED = "on_closed"
COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( COVER_SCHEMA = (
{ cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
cv.GenerateID(): cv.declare_id(Cover), .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent), .extend(
cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), {
cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All( cv.GenerateID(): cv.declare_id(Cover),
cv.requires_component("mqtt"), cv.subscribe_topic cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent),
), cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True),
cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All( cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.subscribe_topic cv.requires_component("mqtt"), cv.subscribe_topic
), ),
cv.Optional(CONF_TILT_COMMAND_TOPIC): cv.All( cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.subscribe_topic cv.requires_component("mqtt"), cv.subscribe_topic
), ),
cv.Optional(CONF_TILT_STATE_TOPIC): cv.All( cv.Optional(CONF_TILT_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.subscribe_topic cv.requires_component("mqtt"), cv.subscribe_topic
), ),
cv.Optional(CONF_ON_OPEN): automation.validate_automation( cv.Optional(CONF_TILT_STATE_TOPIC): cv.All(
{ cv.requires_component("mqtt"), cv.subscribe_topic
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverOpenTrigger), ),
} cv.Optional(CONF_ON_OPEN): automation.validate_automation(
), {
cv.Optional(CONF_ON_CLOSED): automation.validate_automation( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverOpenTrigger),
{ }
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosedTrigger), ),
} cv.Optional(CONF_ON_CLOSED): automation.validate_automation(
), {
} cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosedTrigger),
}
),
}
)
) )
@@ -132,6 +137,10 @@ async def setup_cover_core_(var, config):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf) await automation.build_automation(trigger, [], conf)
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config)
if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
mqtt_ = cg.new_Pvariable(mqtt_id, var) mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config) await mqtt.register_mqtt_component(mqtt_, config)

View File

@@ -129,13 +129,13 @@ class Cover : public EntityBase, public EntityBase_DeviceClass {
* *
* This is a legacy method and may be removed later, please use `.make_call()` instead. * This is a legacy method and may be removed later, please use `.make_call()` instead.
*/ */
ESPDEPRECATED("open() is deprecated, use make_call().set_command_open() instead.", "2021.9") ESPDEPRECATED("open() is deprecated, use make_call().set_command_open().perform() instead.", "2021.9")
void open(); void open();
/** Close the cover. /** Close the cover.
* *
* This is a legacy method and may be removed later, please use `.make_call()` instead. * This is a legacy method and may be removed later, please use `.make_call()` instead.
*/ */
ESPDEPRECATED("close() is deprecated, use make_call().set_command_close() instead.", "2021.9") ESPDEPRECATED("close() is deprecated, use make_call().set_command_close().perform() instead.", "2021.9")
void close(); void close();
/** Stop the cover. /** Stop the cover.
* *

View File

@@ -15,6 +15,7 @@ void CST816Touchscreen::continue_setup_() {
} }
switch (this->chip_id_) { switch (this->chip_id_) {
case CST820_CHIP_ID: case CST820_CHIP_ID:
case CST826_CHIP_ID:
case CST716_CHIP_ID: case CST716_CHIP_ID:
case CST816S_CHIP_ID: case CST816S_CHIP_ID:
case CST816D_CHIP_ID: case CST816D_CHIP_ID:
@@ -90,6 +91,9 @@ void CST816Touchscreen::dump_config() {
case CST820_CHIP_ID: case CST820_CHIP_ID:
name = "CST820"; name = "CST820";
break; break;
case CST826_CHIP_ID:
name = "CST826";
break;
case CST816S_CHIP_ID: case CST816S_CHIP_ID:
name = "CST816S"; name = "CST816S";
break; break;

View File

@@ -24,6 +24,7 @@ static const uint8_t REG_SLEEP = 0xE5;
static const uint8_t REG_IRQ_CTL = 0xFA; static const uint8_t REG_IRQ_CTL = 0xFA;
static const uint8_t IRQ_EN_MOTION = 0x70; static const uint8_t IRQ_EN_MOTION = 0x70;
static const uint8_t CST826_CHIP_ID = 0x11;
static const uint8_t CST820_CHIP_ID = 0xB7; static const uint8_t CST820_CHIP_ID = 0xB7;
static const uint8_t CST816S_CHIP_ID = 0xB4; static const uint8_t CST816S_CHIP_ID = 0xB4;
static const uint8_t CST816D_CHIP_ID = 0xB6; static const uint8_t CST816D_CHIP_ID = 0xB6;

View File

@@ -1,6 +1,7 @@
#include "ct_clamp_sensor.h" #include "ct_clamp_sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
#include <cmath> #include <cmath>
namespace esphome { namespace esphome {
@@ -37,8 +38,8 @@ void CTClampSensor::update() {
float rms_ac = 0; float rms_ac = 0;
if (rms_ac_squared > 0) if (rms_ac_squared > 0)
rms_ac = std::sqrt(rms_ac_squared); rms_ac = std::sqrt(rms_ac_squared);
ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac, ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %" PRIu32 " different samples (%" PRIu32 " SPS)",
this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_); this->name_.c_str(), rms_ac, this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_);
this->publish_state(rms_ac); this->publish_state(rms_ac);
}); });

View File

@@ -1,25 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_ID, CONF_PIN
MULTI_CONF = True MULTI_CONF = True
AUTO_LOAD = ["sensor"]
dallas_ns = cg.esphome_ns.namespace("dallas") CONFIG_SCHEMA = cv.invalid(
DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent) 'The "dallas" component has been replaced by the "one_wire" component.\nhttps://esphome.io/components/one_wire'
)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(DallasComponent),
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema,
}
).extend(cv.polling_component_schema("60s"))
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
pin = await cg.gpio_pin_expression(config[CONF_PIN])
cg.add(var.set_pin(pin))

View File

@@ -1,287 +0,0 @@
#include "dallas_component.h"
#include "esphome/core/log.h"
namespace esphome {
namespace dallas {
static const char *const TAG = "dallas.sensor";
static const uint8_t DALLAS_MODEL_DS18S20 = 0x10;
static const uint8_t DALLAS_MODEL_DS1822 = 0x22;
static const uint8_t DALLAS_MODEL_DS18B20 = 0x28;
static const uint8_t DALLAS_MODEL_DS1825 = 0x3B;
static const uint8_t DALLAS_MODEL_DS28EA00 = 0x42;
static const uint8_t DALLAS_COMMAND_START_CONVERSION = 0x44;
static const uint8_t DALLAS_COMMAND_READ_SCRATCH_PAD = 0xBE;
static const uint8_t DALLAS_COMMAND_WRITE_SCRATCH_PAD = 0x4E;
uint16_t DallasTemperatureSensor::millis_to_wait_for_conversion() const {
switch (this->resolution_) {
case 9:
return 94;
case 10:
return 188;
case 11:
return 375;
default:
return 750;
}
}
void DallasComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
pin_->setup();
// clear bus with 480µs high, otherwise initial reset in search_vec() fails
pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
delayMicroseconds(480);
one_wire_ = new ESPOneWire(pin_); // NOLINT(cppcoreguidelines-owning-memory)
std::vector<uint64_t> raw_sensors;
raw_sensors = this->one_wire_->search_vec();
for (auto &address : raw_sensors) {
auto *address8 = reinterpret_cast<uint8_t *>(&address);
if (crc8(address8, 7) != address8[7]) {
ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex(address).c_str());
continue;
}
if (address8[0] != DALLAS_MODEL_DS18S20 && address8[0] != DALLAS_MODEL_DS1822 &&
address8[0] != DALLAS_MODEL_DS18B20 && address8[0] != DALLAS_MODEL_DS1825 &&
address8[0] != DALLAS_MODEL_DS28EA00) {
ESP_LOGW(TAG, "Unknown device type 0x%02X.", address8[0]);
continue;
}
this->found_sensors_.push_back(address);
}
for (auto *sensor : this->sensors_) {
if (sensor->get_index().has_value()) {
if (*sensor->get_index() >= this->found_sensors_.size()) {
this->status_set_error("Sensor configured by index but not found");
continue;
}
sensor->set_address(this->found_sensors_[*sensor->get_index()]);
}
if (!sensor->setup_sensor()) {
this->status_set_error();
}
}
}
void DallasComponent::dump_config() {
ESP_LOGCONFIG(TAG, "DallasComponent:");
LOG_PIN(" Pin: ", this->pin_);
LOG_UPDATE_INTERVAL(this);
if (this->found_sensors_.empty()) {
ESP_LOGW(TAG, " Found no sensors!");
} else {
ESP_LOGD(TAG, " Found sensors:");
for (auto &address : this->found_sensors_) {
ESP_LOGD(TAG, " 0x%s", format_hex(address).c_str());
}
}
for (auto *sensor : this->sensors_) {
LOG_SENSOR(" ", "Device", sensor);
if (sensor->get_index().has_value()) {
ESP_LOGCONFIG(TAG, " Index %u", *sensor->get_index());
if (*sensor->get_index() >= this->found_sensors_.size()) {
ESP_LOGE(TAG, "Couldn't find sensor by index - not connected. Proceeding without it.");
continue;
}
}
ESP_LOGCONFIG(TAG, " Address: %s", sensor->get_address_name().c_str());
ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution());
}
}
void DallasComponent::register_sensor(DallasTemperatureSensor *sensor) { this->sensors_.push_back(sensor); }
void DallasComponent::update() {
this->status_clear_warning();
bool result;
{
InterruptLock lock;
result = this->one_wire_->reset();
}
if (!result) {
if (!this->found_sensors_.empty()) {
// Only log error if at the start sensors were found (and thus are disconnected during uptime)
ESP_LOGE(TAG, "Requesting conversion failed");
this->status_set_warning();
}
for (auto *sensor : this->sensors_) {
sensor->publish_state(NAN);
}
return;
}
{
InterruptLock lock;
this->one_wire_->skip();
this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
}
for (auto *sensor : this->sensors_) {
if (sensor->get_address() == 0) {
ESP_LOGV(TAG, "'%s' - Indexed sensor not found at startup, skipping update", sensor->get_name().c_str());
sensor->publish_state(NAN);
continue;
}
this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] {
bool res = sensor->read_scratch_pad();
if (!res) {
ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str());
sensor->publish_state(NAN);
this->status_set_warning();
return;
}
if (!sensor->check_scratch_pad()) {
sensor->publish_state(NAN);
this->status_set_warning();
return;
}
float tempc = sensor->get_temp_c();
ESP_LOGD(TAG, "'%s': Got Temperature=%.1f°C", sensor->get_name().c_str(), tempc);
sensor->publish_state(tempc);
});
}
}
void DallasTemperatureSensor::set_address(uint64_t address) { this->address_ = address; }
uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; }
void DallasTemperatureSensor::set_resolution(uint8_t resolution) { this->resolution_ = resolution; }
optional<uint8_t> DallasTemperatureSensor::get_index() const { return this->index_; }
void DallasTemperatureSensor::set_index(uint8_t index) { this->index_ = index; }
uint8_t *DallasTemperatureSensor::get_address8() { return reinterpret_cast<uint8_t *>(&this->address_); }
uint64_t DallasTemperatureSensor::get_address() { return this->address_; }
const std::string &DallasTemperatureSensor::get_address_name() {
if (this->address_name_.empty()) {
this->address_name_ = std::string("0x") + format_hex(this->address_);
}
return this->address_name_;
}
bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
auto *wire = this->parent_->one_wire_;
{
InterruptLock lock;
if (!wire->reset()) {
return false;
}
wire->select(this->address_);
wire->write8(DALLAS_COMMAND_READ_SCRATCH_PAD);
for (unsigned char &i : this->scratch_pad_) {
i = wire->read8();
}
}
return true;
}
bool DallasTemperatureSensor::setup_sensor() {
bool r = this->read_scratch_pad();
if (!r) {
ESP_LOGE(TAG, "Reading scratchpad failed: reset");
return false;
}
if (!this->check_scratch_pad())
return false;
if (this->scratch_pad_[4] == this->resolution_)
return false;
if (this->get_address8()[0] == DALLAS_MODEL_DS18S20) {
// DS18S20 doesn't support resolution.
ESP_LOGW(TAG, "DS18S20 doesn't support setting resolution.");
return false;
}
switch (this->resolution_) {
case 12:
this->scratch_pad_[4] = 0x7F;
break;
case 11:
this->scratch_pad_[4] = 0x5F;
break;
case 10:
this->scratch_pad_[4] = 0x3F;
break;
case 9:
default:
this->scratch_pad_[4] = 0x1F;
break;
}
auto *wire = this->parent_->one_wire_;
{
InterruptLock lock;
if (wire->reset()) {
wire->select(this->address_);
wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
wire->write8(this->scratch_pad_[2]); // high alarm temp
wire->write8(this->scratch_pad_[3]); // low alarm temp
wire->write8(this->scratch_pad_[4]); // resolution
wire->reset();
// write value to EEPROM
wire->select(this->address_);
wire->write8(0x48);
}
}
delay(20); // allow it to finish operation
wire->reset();
return true;
}
bool DallasTemperatureSensor::check_scratch_pad() {
bool chksum_validity = (crc8(this->scratch_pad_, 8) == this->scratch_pad_[8]);
bool config_validity = false;
switch (this->get_address8()[0]) {
case DALLAS_MODEL_DS18B20:
config_validity = ((this->scratch_pad_[4] & 0x9F) == 0x1F);
break;
default:
config_validity = ((this->scratch_pad_[4] & 0x10) == 0x10);
}
#ifdef ESPHOME_LOG_LEVEL_VERY_VERBOSE
ESP_LOGVV(TAG, "Scratch pad: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X (%02X)", this->scratch_pad_[0],
this->scratch_pad_[1], this->scratch_pad_[2], this->scratch_pad_[3], this->scratch_pad_[4],
this->scratch_pad_[5], this->scratch_pad_[6], this->scratch_pad_[7], this->scratch_pad_[8],
crc8(this->scratch_pad_, 8));
#endif
if (!chksum_validity) {
ESP_LOGW(TAG, "'%s' - Scratch pad checksum invalid!", this->get_name().c_str());
} else if (!config_validity) {
ESP_LOGW(TAG, "'%s' - Scratch pad config register invalid!", this->get_name().c_str());
}
return chksum_validity && config_validity;
}
float DallasTemperatureSensor::get_temp_c() {
int16_t temp = (int16_t(this->scratch_pad_[1]) << 11) | (int16_t(this->scratch_pad_[0]) << 3);
if (this->get_address8()[0] == DALLAS_MODEL_DS18S20) {
int diff = (this->scratch_pad_[7] - this->scratch_pad_[6]) << 7;
temp = ((temp & 0xFFF0) << 3) - 16 + (diff / this->scratch_pad_[7]);
}
return temp / 128.0f;
}
std::string DallasTemperatureSensor::unique_id() { return "dallas-" + str_lower_case(format_hex(this->address_)); }
} // namespace dallas
} // namespace esphome

View File

@@ -1,79 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esp_one_wire.h"
#include <vector>
namespace esphome {
namespace dallas {
class DallasTemperatureSensor;
class DallasComponent : public PollingComponent {
public:
void set_pin(InternalGPIOPin *pin) { pin_ = pin; }
void register_sensor(DallasTemperatureSensor *sensor);
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void update() override;
protected:
friend DallasTemperatureSensor;
InternalGPIOPin *pin_;
ESPOneWire *one_wire_;
std::vector<DallasTemperatureSensor *> sensors_;
std::vector<uint64_t> found_sensors_;
};
/// Internal class that helps us create multiple sensors for one Dallas hub.
class DallasTemperatureSensor : public sensor::Sensor {
public:
void set_parent(DallasComponent *parent) { parent_ = parent; }
/// Helper to get a pointer to the address as uint8_t.
uint8_t *get_address8();
uint64_t get_address();
/// Helper to create (and cache) the name for this sensor. For example "0xfe0000031f1eaf29".
const std::string &get_address_name();
/// Set the 64-bit unsigned address for this sensor.
void set_address(uint64_t address);
/// Get the index of this sensor. (0 if using address.)
optional<uint8_t> get_index() const;
/// Set the index of this sensor. If using index, address will be set after setup.
void set_index(uint8_t index);
/// Get the set resolution for this sensor.
uint8_t get_resolution() const;
/// Set the resolution for this sensor.
void set_resolution(uint8_t resolution);
/// Get the number of milliseconds we have to wait for the conversion phase.
uint16_t millis_to_wait_for_conversion() const;
bool setup_sensor();
bool read_scratch_pad();
bool check_scratch_pad();
float get_temp_c();
std::string unique_id() override;
protected:
DallasComponent *parent_;
uint64_t address_;
optional<uint8_t> index_;
uint8_t resolution_;
std::string address_name_;
uint8_t scratch_pad_[9] = {
0,
};
};
} // namespace dallas
} // namespace esphome

View File

@@ -1,252 +0,0 @@
#include "esp_one_wire.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace dallas {
static const char *const TAG = "dallas.one_wire";
const uint8_t ONE_WIRE_ROM_SELECT = 0x55;
const int ONE_WIRE_ROM_SEARCH = 0xF0;
ESPOneWire::ESPOneWire(InternalGPIOPin *pin) { pin_ = pin->to_isr(); }
bool HOT IRAM_ATTR ESPOneWire::reset() {
// See reset here:
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
// Wait for communication to clear (delay G)
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
uint8_t retries = 125;
do {
if (--retries == 0)
return false;
delayMicroseconds(2);
} while (!pin_.digital_read());
// Send 480µs LOW TX reset pulse (drive bus low, delay H)
pin_.pin_mode(gpio::FLAG_OUTPUT);
pin_.digital_write(false);
delayMicroseconds(480);
// Release the bus, delay I
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
delayMicroseconds(70);
// sample bus, 0=device(s) present, 1=no device present
bool r = !pin_.digital_read();
// delay J
delayMicroseconds(410);
return r;
}
void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
// drive bus low
pin_.pin_mode(gpio::FLAG_OUTPUT);
pin_.digital_write(false);
// from datasheet:
// write 0 low time: t_low0: min=60µs, max=120µs
// write 1 low time: t_low1: min=1µs, max=15µs
// time slot: t_slot: min=60µs, max=120µs
// recovery time: t_rec: min=1µs
// ds18b20 appears to read the bus after roughly 14µs
uint32_t delay0 = bit ? 6 : 60;
uint32_t delay1 = bit ? 54 : 5;
// delay A/C
delayMicroseconds(delay0);
// release bus
pin_.digital_write(true);
// delay B/D
delayMicroseconds(delay1);
}
bool HOT IRAM_ATTR ESPOneWire::read_bit() {
// drive bus low
pin_.pin_mode(gpio::FLAG_OUTPUT);
pin_.digital_write(false);
// note: for reading we'll need very accurate timing, as the
// timing for the digital_read() is tight; according to the datasheet,
// we should read at the end of 16µs starting from the bus low
// typically, the ds18b20 pulls the line high after 11µs for a logical 1
// and 29µs for a logical 0
uint32_t start = micros();
// datasheet says >1µs
delayMicroseconds(3);
// release bus, delay E
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
// Unfortunately some frameworks have different characteristics than others
// esp32 arduino appears to pull the bus low only after the digital_write(false),
// whereas on esp-idf it already happens during the pin_mode(OUTPUT)
// manually correct for this with these constants.
#ifdef USE_ESP32
uint32_t timing_constant = 12;
#else
uint32_t timing_constant = 14;
#endif
// measure from start value directly, to get best accurate timing no matter
// how long pin_mode/delayMicroseconds took
while (micros() - start < timing_constant)
;
// sample bus to read bit from peer
bool r = pin_.digital_read();
// read slot is at least 60µs; get as close to 60µs to spend less time with interrupts locked
uint32_t now = micros();
if (now - start < 60)
delayMicroseconds(60 - (now - start));
return r;
}
void IRAM_ATTR ESPOneWire::write8(uint8_t val) {
for (uint8_t i = 0; i < 8; i++) {
this->write_bit(bool((1u << i) & val));
}
}
void IRAM_ATTR ESPOneWire::write64(uint64_t val) {
for (uint8_t i = 0; i < 64; i++) {
this->write_bit(bool((1ULL << i) & val));
}
}
uint8_t IRAM_ATTR ESPOneWire::read8() {
uint8_t ret = 0;
for (uint8_t i = 0; i < 8; i++) {
ret |= (uint8_t(this->read_bit()) << i);
}
return ret;
}
uint64_t IRAM_ATTR ESPOneWire::read64() {
uint64_t ret = 0;
for (uint8_t i = 0; i < 8; i++) {
ret |= (uint64_t(this->read_bit()) << i);
}
return ret;
}
void IRAM_ATTR ESPOneWire::select(uint64_t address) {
this->write8(ONE_WIRE_ROM_SELECT);
this->write64(address);
}
void IRAM_ATTR ESPOneWire::reset_search() {
this->last_discrepancy_ = 0;
this->last_device_flag_ = false;
this->rom_number_ = 0;
}
uint64_t IRAM_ATTR ESPOneWire::search() {
if (this->last_device_flag_) {
return 0u;
}
{
InterruptLock lock;
if (!this->reset()) {
// Reset failed or no devices present
this->reset_search();
return 0u;
}
}
uint8_t id_bit_number = 1;
uint8_t last_zero = 0;
uint8_t rom_byte_number = 0;
bool search_result = false;
uint8_t rom_byte_mask = 1;
{
InterruptLock lock;
// Initiate search
this->write8(ONE_WIRE_ROM_SEARCH);
do {
// read bit
bool id_bit = this->read_bit();
// read its complement
bool cmp_id_bit = this->read_bit();
if (id_bit && cmp_id_bit) {
// No devices participating in search
break;
}
bool branch;
if (id_bit != cmp_id_bit) {
// only chose one branch, the other one doesn't have any devices.
branch = id_bit;
} else {
// there are devices with both 0s and 1s at this bit
if (id_bit_number < this->last_discrepancy_) {
branch = (this->rom_number8_()[rom_byte_number] & rom_byte_mask) > 0;
} else {
branch = id_bit_number == this->last_discrepancy_;
}
if (!branch) {
last_zero = id_bit_number;
}
}
if (branch) {
// set bit
this->rom_number8_()[rom_byte_number] |= rom_byte_mask;
} else {
// clear bit
this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask;
}
// choose/announce branch
this->write_bit(branch);
id_bit_number++;
rom_byte_mask <<= 1;
if (rom_byte_mask == 0u) {
// go to next byte
rom_byte_number++;
rom_byte_mask = 1;
}
} while (rom_byte_number < 8); // loop through all bytes
}
if (id_bit_number >= 65) {
this->last_discrepancy_ = last_zero;
if (this->last_discrepancy_ == 0) {
// we're at root and have no choices left, so this was the last one.
this->last_device_flag_ = true;
}
search_result = true;
}
search_result = search_result && (this->rom_number8_()[0] != 0);
if (!search_result) {
this->reset_search();
return 0u;
}
return this->rom_number_;
}
std::vector<uint64_t> ESPOneWire::search_vec() {
std::vector<uint64_t> res;
this->reset_search();
uint64_t address;
while ((address = this->search()) != 0u)
res.push_back(address);
return res;
}
void IRAM_ATTR ESPOneWire::skip() {
this->write8(0xCC); // skip ROM
}
uint8_t IRAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); }
} // namespace dallas
} // namespace esphome

View File

@@ -1,68 +0,0 @@
#pragma once
#include "esphome/core/hal.h"
#include <vector>
namespace esphome {
namespace dallas {
extern const uint8_t ONE_WIRE_ROM_SELECT;
extern const int ONE_WIRE_ROM_SEARCH;
class ESPOneWire {
public:
explicit ESPOneWire(InternalGPIOPin *pin);
/** Reset the bus, should be done before all write operations.
*
* Takes approximately 1ms.
*
* @return Whether the operation was successful.
*/
bool reset();
/// Write a single bit to the bus, takes about 70µs.
void write_bit(bool bit);
/// Read a single bit from the bus, takes about 70µs
bool read_bit();
/// Write a word to the bus. LSB first.
void write8(uint8_t val);
/// Write a 64 bit unsigned integer to the bus. LSB first.
void write64(uint64_t val);
/// Write a command to the bus that addresses all devices by skipping the ROM.
void skip();
/// Read an 8 bit word from the bus.
uint8_t read8();
/// Read an 64-bit unsigned integer from the bus.
uint64_t read64();
/// Select a specific address on the bus for the following command.
void select(uint64_t address);
/// Reset the device search.
void reset_search();
/// Search for a 1-Wire device on the bus. Returns 0 if all devices have been found.
uint64_t search();
/// Helper that wraps search in a std::vector.
std::vector<uint64_t> search_vec();
protected:
/// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer.
inline uint8_t *rom_number8_();
ISRInternalGPIOPin pin_;
uint8_t last_discrepancy_{0};
bool last_device_flag_{false};
uint64_t rom_number_{0};
};
} // namespace dallas
} // namespace esphome

View File

@@ -1,50 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import ( CONFIG_SCHEMA = cv.invalid(
CONF_ADDRESS, 'The "dallas" sensor is now "dallas_temp"\nhttps://esphome.io/components/sensor/dallas_temp'
CONF_DALLAS_ID,
CONF_INDEX,
CONF_RESOLUTION,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
) )
from . import DallasComponent, dallas_ns
DallasTemperatureSensor = dallas_ns.class_("DallasTemperatureSensor", sensor.Sensor)
CONFIG_SCHEMA = cv.All(
sensor.sensor_schema(
DallasTemperatureSensor,
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent),
cv.Optional(CONF_ADDRESS): cv.hex_uint64_t,
cv.Optional(CONF_INDEX): cv.positive_int,
cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12),
}
),
cv.has_exactly_one_key(CONF_ADDRESS, CONF_INDEX),
)
async def to_code(config):
hub = await cg.get_variable(config[CONF_DALLAS_ID])
var = await sensor.new_sensor(config)
if CONF_ADDRESS in config:
cg.add(var.set_address(config[CONF_ADDRESS]))
else:
cg.add(var.set_index(config[CONF_INDEX]))
if CONF_RESOLUTION in config:
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
cg.add(var.set_parent(hub))
cg.add(hub.register_sensor(var))

View File

@@ -0,0 +1 @@
CODEOWNERS = ["@ssieb"]

View File

@@ -0,0 +1,169 @@
#include "dallas_temp.h"
#include "esphome/core/log.h"
namespace esphome {
namespace dallas_temp {
static const char *const TAG = "dallas.temp.sensor";
static const uint8_t DALLAS_MODEL_DS18S20 = 0x10;
static const uint8_t DALLAS_COMMAND_START_CONVERSION = 0x44;
static const uint8_t DALLAS_COMMAND_READ_SCRATCH_PAD = 0xBE;
static const uint8_t DALLAS_COMMAND_WRITE_SCRATCH_PAD = 0x4E;
static const uint8_t DALLAS_COMMAND_COPY_SCRATCH_PAD = 0x48;
uint16_t DallasTemperatureSensor::millis_to_wait_for_conversion_() const {
switch (this->resolution_) {
case 9:
return 94;
case 10:
return 188;
case 11:
return 375;
default:
return 750;
}
}
void DallasTemperatureSensor::dump_config() {
ESP_LOGCONFIG(TAG, "Dallas Temperature Sensor:");
if (this->address_ == 0) {
ESP_LOGW(TAG, " Unable to select an address");
return;
}
LOG_ONE_WIRE_DEVICE(this);
ESP_LOGCONFIG(TAG, " Resolution: %u bits", this->resolution_);
LOG_UPDATE_INTERVAL(this);
}
void DallasTemperatureSensor::update() {
if (this->address_ == 0)
return;
this->status_clear_warning();
this->send_command_(DALLAS_COMMAND_START_CONVERSION);
this->set_timeout(this->get_address_name(), this->millis_to_wait_for_conversion_(), [this] {
if (!this->read_scratch_pad_() || !this->check_scratch_pad_()) {
this->publish_state(NAN);
return;
}
float tempc = this->get_temp_c_();
ESP_LOGD(TAG, "'%s': Got Temperature=%.1f°C", this->get_name().c_str(), tempc);
this->publish_state(tempc);
});
}
void IRAM_ATTR DallasTemperatureSensor::read_scratch_pad_int_() {
for (uint8_t &i : this->scratch_pad_) {
i = this->bus_->read8();
}
}
bool DallasTemperatureSensor::read_scratch_pad_() {
bool success;
{
InterruptLock lock;
success = this->send_command_(DALLAS_COMMAND_READ_SCRATCH_PAD);
if (success)
this->read_scratch_pad_int_();
}
if (!success) {
ESP_LOGW(TAG, "'%s' - reading scratch pad failed bus reset", this->get_name().c_str());
this->status_set_warning("bus reset failed");
}
return success;
}
void DallasTemperatureSensor::setup() {
ESP_LOGCONFIG(TAG, "setting up Dallas temperature sensor...");
if (!this->check_address_())
return;
if (!this->read_scratch_pad_())
return;
if (!this->check_scratch_pad_())
return;
if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) {
// DS18S20 doesn't support resolution.
ESP_LOGW(TAG, "DS18S20 doesn't support setting resolution.");
return;
}
uint8_t res;
switch (this->resolution_) {
case 12:
res = 0x7F;
break;
case 11:
res = 0x5F;
break;
case 10:
res = 0x3F;
break;
case 9:
default:
res = 0x1F;
break;
}
if (this->scratch_pad_[4] == res)
return;
this->scratch_pad_[4] = res;
{
InterruptLock lock;
if (this->send_command_(DALLAS_COMMAND_WRITE_SCRATCH_PAD)) {
this->bus_->write8(this->scratch_pad_[2]); // high alarm temp
this->bus_->write8(this->scratch_pad_[3]); // low alarm temp
this->bus_->write8(this->scratch_pad_[4]); // resolution
}
// write value to EEPROM
this->send_command_(DALLAS_COMMAND_COPY_SCRATCH_PAD);
}
}
bool DallasTemperatureSensor::check_scratch_pad_() {
bool chksum_validity = (crc8(this->scratch_pad_, 8) == this->scratch_pad_[8]);
#ifdef ESPHOME_LOG_LEVEL_VERY_VERBOSE
ESP_LOGVV(TAG, "Scratch pad: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X (%02X)", this->scratch_pad_[0],
this->scratch_pad_[1], this->scratch_pad_[2], this->scratch_pad_[3], this->scratch_pad_[4],
this->scratch_pad_[5], this->scratch_pad_[6], this->scratch_pad_[7], this->scratch_pad_[8],
crc8(this->scratch_pad_, 8));
#endif
if (!chksum_validity) {
ESP_LOGW(TAG, "'%s' - Scratch pad checksum invalid!", this->get_name().c_str());
this->status_set_warning("scratch pad checksum invalid");
}
return chksum_validity;
}
float DallasTemperatureSensor::get_temp_c_() {
int16_t temp = (this->scratch_pad_[1] << 8) | this->scratch_pad_[0];
if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) {
return (temp >> 1) + (this->scratch_pad_[7] - this->scratch_pad_[6]) / float(this->scratch_pad_[7]) - 0.25;
}
switch (this->resolution_) {
case 9:
temp &= 0xfff8;
break;
case 10:
temp &= 0xfffc;
break;
case 11:
temp &= 0xfffe;
break;
case 12:
default:
break;
}
return temp / 16.0f;
}
} // namespace dallas_temp
} // namespace esphome

View File

@@ -0,0 +1,32 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/one_wire/one_wire.h"
namespace esphome {
namespace dallas_temp {
class DallasTemperatureSensor : public PollingComponent, public sensor::Sensor, public one_wire::OneWireDevice {
public:
void setup() override;
void update() override;
void dump_config() override;
/// Set the resolution for this sensor.
void set_resolution(uint8_t resolution) { this->resolution_ = resolution; }
protected:
uint8_t resolution_;
uint8_t scratch_pad_[9] = {0};
/// Get the number of milliseconds we have to wait for the conversion phase.
uint16_t millis_to_wait_for_conversion_() const;
bool read_scratch_pad_();
void read_scratch_pad_int_();
bool check_scratch_pad_();
float get_temp_c_();
};
} // namespace dallas_temp
} // namespace esphome

View File

@@ -0,0 +1,43 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import one_wire, sensor
from esphome.const import (
CONF_RESOLUTION,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
)
dallas_temp_ns = cg.esphome_ns.namespace("dallas_temp")
DallasTemperatureSensor = dallas_temp_ns.class_(
"DallasTemperatureSensor",
cg.PollingComponent,
sensor.Sensor,
one_wire.OneWireDevice,
)
CONFIG_SCHEMA = (
sensor.sensor_schema(
DallasTemperatureSensor,
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12),
}
)
.extend(one_wire.one_wire_device_schema())
.extend(cv.polling_component_schema("60s"))
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
await one_wire.register_one_wire_device(var, config)
cg.add(var.set_resolution(config[CONF_RESOLUTION]))

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome import automation from esphome import automation
from esphome.components import mqtt, time from esphome.components import mqtt, web_server, time
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_ID,
CONF_ON_TIME, CONF_ON_TIME,
@@ -11,6 +11,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_TYPE, CONF_TYPE,
CONF_MQTT_ID, CONF_MQTT_ID,
CONF_WEB_SERVER_ID,
CONF_DATE, CONF_DATE,
CONF_DATETIME, CONF_DATETIME,
CONF_TIME, CONF_TIME,
@@ -63,16 +64,20 @@ DATETIME_MODES = [
] ]
_DATETIME_SCHEMA = cv.Schema( _DATETIME_SCHEMA = (
{ cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
cv.Optional(CONF_ON_VALUE): automation.validate_automation( .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
{ .extend(
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger), {
} cv.Optional(CONF_ON_VALUE): automation.validate_automation(
), {
cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger),
} }
).extend(cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)) ),
cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
}
)
)
def date_schema(class_: MockObjClass) -> cv.Schema: def date_schema(class_: MockObjClass) -> cv.Schema:
@@ -128,6 +133,9 @@ async def setup_datetime_core_(var, config):
if (mqtt_id := config.get(CONF_MQTT_ID)) is not None: if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
mqtt_ = cg.new_Pvariable(mqtt_id, var) mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config) await mqtt.register_mqtt_component(mqtt_, config)
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
web_server_ = await cg.get_variable(webserver_id)
web_server.add_entity_to_sorting_list(web_server_, var, config)
for conf in config.get(CONF_ON_VALUE, []): for conf in config.get(CONF_ON_VALUE, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf) await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf)
@@ -156,7 +164,7 @@ async def new_datetime(config, *args):
return var return var
@coroutine_with_priority(40.0) @coroutine_with_priority(100.0)
async def to_code(config): async def to_code(config):
cg.add_define("USE_DATETIME") cg.add_define("USE_DATETIME")
cg.add_global(datetime_ns.using) cg.add_global(datetime_ns.using)

View File

@@ -80,6 +80,17 @@ void DateCall::validate_() {
void DateCall::perform() { void DateCall::perform() {
this->validate_(); this->validate_();
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
if (this->year_.has_value()) {
ESP_LOGD(TAG, " Year: %d", *this->year_);
}
if (this->month_.has_value()) {
ESP_LOGD(TAG, " Month: %d", *this->month_);
}
if (this->day_.has_value()) {
ESP_LOGD(TAG, " Day: %d", *this->day_);
}
this->parent_->control(*this); this->parent_->control(*this);
} }

View File

@@ -8,62 +8,16 @@
#include <cinttypes> #include <cinttypes>
#include <climits> #include <climits>
#ifdef USE_ESP32
#include <esp_heap_caps.h>
#include <esp_system.h>
#include <esp_chip_info.h>
#if defined(USE_ESP32_VARIANT_ESP32)
#include <esp32/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32C3)
#include <esp32c3/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32C6)
#include <esp32c6/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32S2)
#include <esp32s2/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32S3)
#include <esp32s3/rom/rtc.h>
#endif
#endif // USE_ESP32
#ifdef USE_ARDUINO
#ifdef USE_RP2040
#include <Arduino.h>
#elif defined(USE_ESP32) || defined(USE_ESP8266)
#include <Esp.h>
#endif
#endif
namespace esphome { namespace esphome {
namespace debug { namespace debug {
static const char *const TAG = "debug"; static const char *const TAG = "debug";
static uint32_t get_free_heap() {
#if defined(USE_ESP8266)
return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
#elif defined(USE_ESP32)
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
#elif defined(USE_RP2040)
return rp2040.getFreeHeap();
#elif defined(USE_LIBRETINY)
return lt_heap_get_free();
#elif defined(USE_HOST)
return INT_MAX;
#endif
}
void DebugComponent::dump_config() { void DebugComponent::dump_config() {
#ifndef ESPHOME_LOG_HAS_DEBUG #ifndef ESPHOME_LOG_HAS_DEBUG
return; // Can't log below if debug logging is disabled return; // Can't log below if debug logging is disabled
#endif #endif
std::string device_info;
std::string reset_reason;
device_info.reserve(256);
ESP_LOGCONFIG(TAG, "Debug component:"); ESP_LOGCONFIG(TAG, "Debug component:");
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
LOG_TEXT_SENSOR(" ", "Device info", this->device_info_); LOG_TEXT_SENSOR(" ", "Device info", this->device_info_);
@@ -76,305 +30,15 @@ void DebugComponent::dump_config() {
#endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) #endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
#endif // USE_SENSOR #endif // USE_SENSOR
std::string device_info;
device_info.reserve(256);
ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION); ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION);
device_info += ESPHOME_VERSION; device_info += ESPHOME_VERSION;
this->free_heap_ = get_free_heap(); this->free_heap_ = get_free_heap_();
ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_);
#if defined(USE_ARDUINO) && (defined(USE_ESP32) || defined(USE_ESP8266)) get_device_info_(device_info);
const char *flash_mode;
switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
case FM_QIO:
flash_mode = "QIO";
break;
case FM_QOUT:
flash_mode = "QOUT";
break;
case FM_DIO:
flash_mode = "DIO";
break;
case FM_DOUT:
flash_mode = "DOUT";
break;
#ifdef USE_ESP32
case FM_FAST_READ:
flash_mode = "FAST_READ";
break;
case FM_SLOW_READ:
flash_mode = "SLOW_READ";
break;
#endif
default:
flash_mode = "UNKNOWN";
}
ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
ESP.getFlashChipSize() / 1024, // NOLINT
ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT
device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT
"kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT
device_info += flash_mode;
#endif // USE_ARDUINO && (USE_ESP32 || USE_ESP8266)
#ifdef USE_ESP32
esp_chip_info_t info;
esp_chip_info(&info);
const char *model;
#if defined(USE_ESP32_VARIANT_ESP32)
model = "ESP32";
#elif defined(USE_ESP32_VARIANT_ESP32C3)
model = "ESP32-C3";
#elif defined(USE_ESP32_VARIANT_ESP32C6)
model = "ESP32-C6";
#elif defined(USE_ESP32_VARIANT_ESP32S2)
model = "ESP32-S2";
#elif defined(USE_ESP32_VARIANT_ESP32S3)
model = "ESP32-S3";
#elif defined(USE_ESP32_VARIANT_ESP32H2)
model = "ESP32-H2";
#else
model = "UNKNOWN";
#endif
std::string features;
if (info.features & CHIP_FEATURE_EMB_FLASH) {
features += "EMB_FLASH,";
info.features &= ~CHIP_FEATURE_EMB_FLASH;
}
if (info.features & CHIP_FEATURE_WIFI_BGN) {
features += "WIFI_BGN,";
info.features &= ~CHIP_FEATURE_WIFI_BGN;
}
if (info.features & CHIP_FEATURE_BLE) {
features += "BLE,";
info.features &= ~CHIP_FEATURE_BLE;
}
if (info.features & CHIP_FEATURE_BT) {
features += "BT,";
info.features &= ~CHIP_FEATURE_BT;
}
if (info.features & CHIP_FEATURE_EMB_PSRAM) {
features += "EMB_PSRAM,";
info.features &= ~CHIP_FEATURE_EMB_PSRAM;
}
if (info.features)
features += "Other:" + format_hex(info.features);
ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
info.revision);
device_info += "|Chip: ";
device_info += model;
device_info += " Features:";
device_info += features;
device_info += " Cores:" + to_string(info.cores);
device_info += " Revision:" + to_string(info.revision);
ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
device_info += "|ESP-IDF: ";
device_info += esp_get_idf_version();
std::string mac = get_mac_address_pretty();
ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
device_info += "|EFuse MAC: ";
device_info += mac;
switch (rtc_get_reset_reason(0)) {
case POWERON_RESET:
reset_reason = "Power On Reset";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case SW_RESET:
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case RTC_SW_SYS_RESET:
#endif
reset_reason = "Software Reset Digital Core";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case OWDT_RESET:
reset_reason = "Watch Dog Reset Digital Core";
break;
#endif
case DEEPSLEEP_RESET:
reset_reason = "Deep Sleep Reset Digital Core";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case SDIO_RESET:
reset_reason = "SLC Module Reset Digital Core";
break;
#endif
case TG0WDT_SYS_RESET:
reset_reason = "Timer Group 0 Watch Dog Reset Digital Core";
break;
case TG1WDT_SYS_RESET:
reset_reason = "Timer Group 1 Watch Dog Reset Digital Core";
break;
case RTCWDT_SYS_RESET:
reset_reason = "RTC Watch Dog Reset Digital Core";
break;
#if !defined(USE_ESP32_VARIANT_ESP32C6)
case INTRUSION_RESET:
reset_reason = "Intrusion Reset CPU";
break;
#endif
#if defined(USE_ESP32_VARIANT_ESP32)
case TGWDT_CPU_RESET:
reset_reason = "Timer Group Reset CPU";
break;
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case TG0WDT_CPU_RESET:
reset_reason = "Timer Group 0 Reset CPU";
break;
#endif
#if defined(USE_ESP32_VARIANT_ESP32)
case SW_CPU_RESET:
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case RTC_SW_CPU_RESET:
#endif
reset_reason = "Software Reset CPU";
break;
case RTCWDT_CPU_RESET:
reset_reason = "RTC Watch Dog Reset CPU";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case EXT_CPU_RESET:
reset_reason = "External CPU Reset";
break;
#endif
case RTCWDT_BROWN_OUT_RESET:
reset_reason = "Voltage Unstable Reset";
break;
case RTCWDT_RTC_RESET:
reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module";
break;
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case TG1WDT_CPU_RESET:
reset_reason = "Timer Group 1 Reset CPU";
break;
case SUPER_WDT_RESET:
reset_reason = "Super Watchdog Reset Digital Core And RTC Module";
break;
case GLITCH_RTC_RESET:
reset_reason = "Glitch Reset Digital Core And RTC Module";
break;
case EFUSE_RESET:
reset_reason = "eFuse Reset Digital Core";
break;
#endif
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3)
case USB_UART_CHIP_RESET:
reset_reason = "USB UART Reset Digital Core";
break;
case USB_JTAG_CHIP_RESET:
reset_reason = "USB JTAG Reset Digital Core";
break;
case POWER_GLITCH_RESET:
reset_reason = "Power Glitch Reset Digital Core And RTC Module";
break;
#endif
default:
reset_reason = "Unknown Reset Reason";
}
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
device_info += "|Reset: ";
device_info += reset_reason;
const char *wakeup_reason;
switch (rtc_get_wakeup_cause()) {
case NO_SLEEP:
wakeup_reason = "No Sleep";
break;
case EXT_EVENT0_TRIG:
wakeup_reason = "External Event 0";
break;
case EXT_EVENT1_TRIG:
wakeup_reason = "External Event 1";
break;
case GPIO_TRIG:
wakeup_reason = "GPIO";
break;
case TIMER_EXPIRE:
wakeup_reason = "Wakeup Timer";
break;
case SDIO_TRIG:
wakeup_reason = "SDIO";
break;
case MAC_TRIG:
wakeup_reason = "MAC";
break;
case UART0_TRIG:
wakeup_reason = "UART0";
break;
case UART1_TRIG:
wakeup_reason = "UART1";
break;
case TOUCH_TRIG:
wakeup_reason = "Touch";
break;
case SAR_TRIG:
wakeup_reason = "SAR";
break;
case BT_TRIG:
wakeup_reason = "BT";
break;
default:
wakeup_reason = "Unknown";
}
ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason);
device_info += "|Wakeup: ";
device_info += wakeup_reason;
#endif
#if defined(USE_ESP8266) && !defined(CLANG_TIDY)
ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId());
ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion());
ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str());
ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode());
ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz());
ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId());
ESP_LOGD(TAG, "Reset Reason: %s", ESP.getResetReason().c_str());
ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str());
device_info += "|Chip: 0x" + format_hex(ESP.getChipId());
device_info += "|SDK: ";
device_info += ESP.getSdkVersion();
device_info += "|Core: ";
device_info += ESP.getCoreVersion().c_str();
device_info += "|Boot: ";
device_info += to_string(ESP.getBootVersion());
device_info += "|Mode: " + to_string(ESP.getBootMode());
device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz());
device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId());
device_info += "|Reset: ";
device_info += ESP.getResetReason().c_str();
device_info += "|";
device_info += ESP.getResetInfo().c_str();
reset_reason = ESP.getResetReason().c_str();
#endif
#ifdef USE_RP2040
ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu());
device_info += "CPU Frequency: " + to_string(rp2040.f_cpu());
#endif // USE_RP2040
#ifdef USE_LIBRETINY
ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version());
ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz());
ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id());
ESP_LOGD(TAG, "Board: %s", lt_get_board_code());
ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024);
ESP_LOGD(TAG, "Reset Reason: %s", lt_get_reboot_reason_name(lt_get_reboot_reason()));
device_info += "|Version: ";
device_info += LT_BANNER_STR + 10;
device_info += "|Reset Reason: ";
device_info += lt_get_reboot_reason_name(lt_get_reboot_reason());
device_info += "|Chip Name: ";
device_info += lt_cpu_get_model_name();
device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id());
device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB";
device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB";
reset_reason = lt_get_reboot_reason_name(lt_get_reboot_reason());
#endif // USE_LIBRETINY
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
if (this->device_info_ != nullptr) { if (this->device_info_ != nullptr) {
@@ -383,14 +47,14 @@ void DebugComponent::dump_config() {
this->device_info_->publish_state(device_info); this->device_info_->publish_state(device_info);
} }
if (this->reset_reason_ != nullptr) { if (this->reset_reason_ != nullptr) {
this->reset_reason_->publish_state(reset_reason); this->reset_reason_->publish_state(get_reset_reason_());
} }
#endif // USE_TEXT_SENSOR #endif // USE_TEXT_SENSOR
} }
void DebugComponent::loop() { void DebugComponent::loop() {
// log when free heap space has halved // log when free heap space has halved
uint32_t new_free_heap = get_free_heap(); uint32_t new_free_heap = get_free_heap_();
if (new_free_heap < this->free_heap_ / 2) { if (new_free_heap < this->free_heap_ / 2) {
this->free_heap_ = new_free_heap; this->free_heap_ = new_free_heap;
ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_);
@@ -411,38 +75,16 @@ void DebugComponent::loop() {
void DebugComponent::update() { void DebugComponent::update() {
#ifdef USE_SENSOR #ifdef USE_SENSOR
if (this->free_sensor_ != nullptr) { if (this->free_sensor_ != nullptr) {
this->free_sensor_->publish_state(get_free_heap()); this->free_sensor_->publish_state(get_free_heap_());
} }
if (this->block_sensor_ != nullptr) {
#if defined(USE_ESP8266)
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize());
#elif defined(USE_ESP32)
this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
#elif defined(USE_LIBRETINY)
this->block_sensor_->publish_state(lt_heap_get_max_alloc());
#endif
}
#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
if (this->fragmentation_sensor_ != nullptr) {
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
}
#endif
if (this->loop_time_sensor_ != nullptr) { if (this->loop_time_sensor_ != nullptr) {
this->loop_time_sensor_->publish_state(this->max_loop_time_); this->loop_time_sensor_->publish_state(this->max_loop_time_);
this->max_loop_time_ = 0; this->max_loop_time_ = 0;
} }
#ifdef USE_ESP32
if (this->psram_sensor_ != nullptr) {
this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
}
#endif // USE_ESP32
#endif // USE_SENSOR #endif // USE_SENSOR
update_platform_();
} }
float DebugComponent::get_setup_priority() const { return setup_priority::LATE; } float DebugComponent::get_setup_priority() const { return setup_priority::LATE; }

View File

@@ -59,6 +59,11 @@ class DebugComponent : public PollingComponent {
text_sensor::TextSensor *device_info_{nullptr}; text_sensor::TextSensor *device_info_{nullptr};
text_sensor::TextSensor *reset_reason_{nullptr}; text_sensor::TextSensor *reset_reason_{nullptr};
#endif // USE_TEXT_SENSOR #endif // USE_TEXT_SENSOR
std::string get_reset_reason_();
uint32_t get_free_heap_();
void get_device_info_(std::string &device_info);
void update_platform_();
}; };
} // namespace debug } // namespace debug

View File

@@ -0,0 +1,287 @@
#include "debug_component.h"
#ifdef USE_ESP32
#include "esphome/core/log.h"
#include <esp_heap_caps.h>
#include <esp_system.h>
#include <esp_chip_info.h>
#if defined(USE_ESP32_VARIANT_ESP32)
#include <esp32/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32C3)
#include <esp32c3/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32C6)
#include <esp32c6/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32S2)
#include <esp32s2/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32S3)
#include <esp32s3/rom/rtc.h>
#endif
#ifdef USE_ARDUINO
#include <Esp.h>
#endif
namespace esphome {
namespace debug {
static const char *const TAG = "debug";
std::string DebugComponent::get_reset_reason_() {
std::string reset_reason;
switch (rtc_get_reset_reason(0)) {
case POWERON_RESET:
reset_reason = "Power On Reset";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case SW_RESET:
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case RTC_SW_SYS_RESET:
#endif
reset_reason = "Software Reset Digital Core";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case OWDT_RESET:
reset_reason = "Watch Dog Reset Digital Core";
break;
#endif
case DEEPSLEEP_RESET:
reset_reason = "Deep Sleep Reset Digital Core";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case SDIO_RESET:
reset_reason = "SLC Module Reset Digital Core";
break;
#endif
case TG0WDT_SYS_RESET:
reset_reason = "Timer Group 0 Watch Dog Reset Digital Core";
break;
case TG1WDT_SYS_RESET:
reset_reason = "Timer Group 1 Watch Dog Reset Digital Core";
break;
case RTCWDT_SYS_RESET:
reset_reason = "RTC Watch Dog Reset Digital Core";
break;
#if !defined(USE_ESP32_VARIANT_ESP32C6)
case INTRUSION_RESET:
reset_reason = "Intrusion Reset CPU";
break;
#endif
#if defined(USE_ESP32_VARIANT_ESP32)
case TGWDT_CPU_RESET:
reset_reason = "Timer Group Reset CPU";
break;
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case TG0WDT_CPU_RESET:
reset_reason = "Timer Group 0 Reset CPU";
break;
#endif
#if defined(USE_ESP32_VARIANT_ESP32)
case SW_CPU_RESET:
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case RTC_SW_CPU_RESET:
#endif
reset_reason = "Software Reset CPU";
break;
case RTCWDT_CPU_RESET:
reset_reason = "RTC Watch Dog Reset CPU";
break;
#if defined(USE_ESP32_VARIANT_ESP32)
case EXT_CPU_RESET:
reset_reason = "External CPU Reset";
break;
#endif
case RTCWDT_BROWN_OUT_RESET:
reset_reason = "Voltage Unstable Reset";
break;
case RTCWDT_RTC_RESET:
reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module";
break;
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case TG1WDT_CPU_RESET:
reset_reason = "Timer Group 1 Reset CPU";
break;
case SUPER_WDT_RESET:
reset_reason = "Super Watchdog Reset Digital Core And RTC Module";
break;
case GLITCH_RTC_RESET:
reset_reason = "Glitch Reset Digital Core And RTC Module";
break;
case EFUSE_RESET:
reset_reason = "eFuse Reset Digital Core";
break;
#endif
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3)
case USB_UART_CHIP_RESET:
reset_reason = "USB UART Reset Digital Core";
break;
case USB_JTAG_CHIP_RESET:
reset_reason = "USB JTAG Reset Digital Core";
break;
case POWER_GLITCH_RESET:
reset_reason = "Power Glitch Reset Digital Core And RTC Module";
break;
#endif
default:
reset_reason = "Unknown Reset Reason";
}
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
return reset_reason;
}
uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); }
void DebugComponent::get_device_info_(std::string &device_info) {
#if defined(USE_ARDUINO)
const char *flash_mode;
switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
case FM_QIO:
flash_mode = "QIO";
break;
case FM_QOUT:
flash_mode = "QOUT";
break;
case FM_DIO:
flash_mode = "DIO";
break;
case FM_DOUT:
flash_mode = "DOUT";
break;
case FM_FAST_READ:
flash_mode = "FAST_READ";
break;
case FM_SLOW_READ:
flash_mode = "SLOW_READ";
break;
default:
flash_mode = "UNKNOWN";
}
ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
ESP.getFlashChipSize() / 1024, // NOLINT
ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT
device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT
"kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT
device_info += flash_mode;
#endif
esp_chip_info_t info;
esp_chip_info(&info);
const char *model;
#if defined(USE_ESP32_VARIANT_ESP32)
model = "ESP32";
#elif defined(USE_ESP32_VARIANT_ESP32C3)
model = "ESP32-C3";
#elif defined(USE_ESP32_VARIANT_ESP32C6)
model = "ESP32-C6";
#elif defined(USE_ESP32_VARIANT_ESP32S2)
model = "ESP32-S2";
#elif defined(USE_ESP32_VARIANT_ESP32S3)
model = "ESP32-S3";
#elif defined(USE_ESP32_VARIANT_ESP32H2)
model = "ESP32-H2";
#else
model = "UNKNOWN";
#endif
std::string features;
if (info.features & CHIP_FEATURE_EMB_FLASH) {
features += "EMB_FLASH,";
info.features &= ~CHIP_FEATURE_EMB_FLASH;
}
if (info.features & CHIP_FEATURE_WIFI_BGN) {
features += "WIFI_BGN,";
info.features &= ~CHIP_FEATURE_WIFI_BGN;
}
if (info.features & CHIP_FEATURE_BLE) {
features += "BLE,";
info.features &= ~CHIP_FEATURE_BLE;
}
if (info.features & CHIP_FEATURE_BT) {
features += "BT,";
info.features &= ~CHIP_FEATURE_BT;
}
if (info.features & CHIP_FEATURE_EMB_PSRAM) {
features += "EMB_PSRAM,";
info.features &= ~CHIP_FEATURE_EMB_PSRAM;
}
if (info.features)
features += "Other:" + format_hex(info.features);
ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
info.revision);
device_info += "|Chip: ";
device_info += model;
device_info += " Features:";
device_info += features;
device_info += " Cores:" + to_string(info.cores);
device_info += " Revision:" + to_string(info.revision);
ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
device_info += "|ESP-IDF: ";
device_info += esp_get_idf_version();
std::string mac = get_mac_address_pretty();
ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
device_info += "|EFuse MAC: ";
device_info += mac;
device_info += "|Reset: ";
device_info += get_reset_reason_();
const char *wakeup_reason;
switch (rtc_get_wakeup_cause()) {
case NO_SLEEP:
wakeup_reason = "No Sleep";
break;
case EXT_EVENT0_TRIG:
wakeup_reason = "External Event 0";
break;
case EXT_EVENT1_TRIG:
wakeup_reason = "External Event 1";
break;
case GPIO_TRIG:
wakeup_reason = "GPIO";
break;
case TIMER_EXPIRE:
wakeup_reason = "Wakeup Timer";
break;
case SDIO_TRIG:
wakeup_reason = "SDIO";
break;
case MAC_TRIG:
wakeup_reason = "MAC";
break;
case UART0_TRIG:
wakeup_reason = "UART0";
break;
case UART1_TRIG:
wakeup_reason = "UART1";
break;
case TOUCH_TRIG:
wakeup_reason = "Touch";
break;
case SAR_TRIG:
wakeup_reason = "SAR";
break;
case BT_TRIG:
wakeup_reason = "BT";
break;
default:
wakeup_reason = "Unknown";
}
ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason);
device_info += "|Wakeup: ";
device_info += wakeup_reason;
}
void DebugComponent::update_platform_() {
#ifdef USE_SENSOR
if (this->block_sensor_ != nullptr) {
this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
}
if (this->psram_sensor_ != nullptr) {
this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
}
#endif
}
} // namespace debug
} // namespace esphome
#endif

View File

@@ -0,0 +1,94 @@
#include "debug_component.h"
#ifdef USE_ESP8266
#include "esphome/core/log.h"
#include <Esp.h>
namespace esphome {
namespace debug {
static const char *const TAG = "debug";
std::string DebugComponent::get_reset_reason_() {
#if !defined(CLANG_TIDY)
return ESP.getResetReason().c_str();
#else
return "";
#endif
}
uint32_t DebugComponent::get_free_heap_() {
return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
}
void DebugComponent::get_device_info_(std::string &device_info) {
const char *flash_mode;
switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
case FM_QIO:
flash_mode = "QIO";
break;
case FM_QOUT:
flash_mode = "QOUT";
break;
case FM_DIO:
flash_mode = "DIO";
break;
case FM_DOUT:
flash_mode = "DOUT";
break;
default:
flash_mode = "UNKNOWN";
}
ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
ESP.getFlashChipSize() / 1024, // NOLINT
ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT
device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT
"kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT
device_info += flash_mode;
#if !defined(CLANG_TIDY)
auto reset_reason = get_reset_reason_();
ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId());
ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion());
ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str());
ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode());
ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz());
ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId());
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str());
device_info += "|Chip: 0x" + format_hex(ESP.getChipId());
device_info += "|SDK: ";
device_info += ESP.getSdkVersion();
device_info += "|Core: ";
device_info += ESP.getCoreVersion().c_str();
device_info += "|Boot: ";
device_info += to_string(ESP.getBootVersion());
device_info += "|Mode: " + to_string(ESP.getBootMode());
device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz());
device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId());
device_info += "|Reset: ";
device_info += reset_reason;
device_info += "|";
device_info += ESP.getResetInfo().c_str();
#endif
}
void DebugComponent::update_platform_() {
#ifdef USE_SENSOR
if (this->block_sensor_ != nullptr) {
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize());
}
#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
if (this->fragmentation_sensor_ != nullptr) {
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
}
#endif
#endif
}
} // namespace debug
} // namespace esphome
#endif

View File

@@ -0,0 +1,18 @@
#include "debug_component.h"
#ifdef USE_HOST
#include <climits>
namespace esphome {
namespace debug {
std::string DebugComponent::get_reset_reason_() { return ""; }
uint32_t DebugComponent::get_free_heap_() { return INT_MAX; }
void DebugComponent::get_device_info_(std::string &device_info) {}
void DebugComponent::update_platform_() {}
} // namespace debug
} // namespace esphome
#endif

View File

@@ -0,0 +1,44 @@
#include "debug_component.h"
#ifdef USE_LIBRETINY
#include "esphome/core/log.h"
namespace esphome {
namespace debug {
static const char *const TAG = "debug";
std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_name(lt_get_reboot_reason()); }
uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); }
void DebugComponent::get_device_info_(std::string &device_info) {
std::string reset_reason = get_reset_reason_();
ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version());
ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz());
ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id());
ESP_LOGD(TAG, "Board: %s", lt_get_board_code());
ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024);
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
device_info += "|Version: ";
device_info += LT_BANNER_STR + 10;
device_info += "|Reset Reason: ";
device_info += reset_reason;
device_info += "|Chip Name: ";
device_info += lt_cpu_get_model_name();
device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id());
device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB";
device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB";
}
void DebugComponent::update_platform_() {
#ifdef USE_SENSOR
if (this->block_sensor_ != nullptr) {
this->block_sensor_->publish_state(lt_heap_get_max_alloc());
}
#endif
}
} // namespace debug
} // namespace esphome
#endif

View File

@@ -0,0 +1,23 @@
#include "debug_component.h"
#ifdef USE_RP2040
#include "esphome/core/log.h"
#include <Arduino.h>
namespace esphome {
namespace debug {
static const char *const TAG = "debug";
std::string DebugComponent::get_reset_reason_() { return ""; }
uint32_t DebugComponent::get_free_heap_() { return rp2040.getFreeHeap(); }
void DebugComponent::get_device_info_(std::string &device_info) {
ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu());
device_info += "CPU Frequency: " + to_string(rp2040.f_cpu());
}
void DebugComponent::update_platform_() {}
} // namespace debug
} // namespace esphome
#endif

View File

@@ -1,12 +1,7 @@
#include "deep_sleep_component.h" #include "deep_sleep_component.h"
#include <cinttypes>
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#ifdef USE_ESP8266
#include <Esp.h>
#endif
namespace esphome { namespace esphome {
namespace deep_sleep { namespace deep_sleep {
@@ -14,25 +9,6 @@ static const char *const TAG = "deep_sleep";
bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
optional<uint32_t> DeepSleepComponent::get_run_duration_() const {
#ifdef USE_ESP32
if (this->wakeup_cause_to_run_duration_.has_value()) {
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
switch (wakeup_cause) {
case ESP_SLEEP_WAKEUP_EXT0:
case ESP_SLEEP_WAKEUP_EXT1:
case ESP_SLEEP_WAKEUP_GPIO:
return this->wakeup_cause_to_run_duration_->gpio_cause;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
return this->wakeup_cause_to_run_duration_->touch_cause;
default:
return this->wakeup_cause_to_run_duration_->default_cause;
}
}
#endif
return this->run_duration_;
}
void DeepSleepComponent::setup() { void DeepSleepComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
global_has_deep_sleep = true; global_has_deep_sleep = true;
@@ -45,6 +21,7 @@ void DeepSleepComponent::setup() {
ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured."); ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
} }
} }
void DeepSleepComponent::dump_config() { void DeepSleepComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
if (this->sleep_duration_.has_value()) { if (this->sleep_duration_.has_value()) {
@@ -54,65 +31,31 @@ void DeepSleepComponent::dump_config() {
if (this->run_duration_.has_value()) { if (this->run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Run Duration: %" PRIu32 " ms", *this->run_duration_); ESP_LOGCONFIG(TAG, " Run Duration: %" PRIu32 " ms", *this->run_duration_);
} }
#ifdef USE_ESP32 this->dump_config_platform_();
if (wakeup_pin_ != nullptr) {
LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_);
}
if (this->wakeup_cause_to_run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms",
this->wakeup_cause_to_run_duration_->default_cause);
ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause);
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
}
#endif
} }
void DeepSleepComponent::loop() { void DeepSleepComponent::loop() {
if (this->next_enter_deep_sleep_) if (this->next_enter_deep_sleep_)
this->begin_sleep(); this->begin_sleep();
} }
float DeepSleepComponent::get_loop_priority() const { float DeepSleepComponent::get_loop_priority() const {
return -100.0f; // run after everything else is ready return -100.0f; // run after everything else is ready
} }
void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; } void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; }
#if defined(USE_ESP32)
void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) {
this->wakeup_pin_mode_ = wakeup_pin_mode;
}
#endif
#if defined(USE_ESP32)
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; }
void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
#endif
void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) {
wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration;
}
#endif
void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; } void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; }
void DeepSleepComponent::begin_sleep(bool manual) { void DeepSleepComponent::begin_sleep(bool manual) {
if (this->prevent_ && !manual) { if (this->prevent_ && !manual) {
this->next_enter_deep_sleep_ = true; this->next_enter_deep_sleep_ = true;
return; return;
} }
#ifdef USE_ESP32
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr && if (!this->prepare_to_sleep_()) {
!this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) {
// Defer deep sleep until inactive
if (!this->next_enter_deep_sleep_) {
this->status_set_warning();
ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep...");
}
this->next_enter_deep_sleep_ = true;
return; return;
} }
#endif
ESP_LOGI(TAG, "Beginning Deep Sleep"); ESP_LOGI(TAG, "Beginning Deep Sleep");
if (this->sleep_duration_.has_value()) { if (this->sleep_duration_.has_value()) {
@@ -120,47 +63,13 @@ void DeepSleepComponent::begin_sleep(bool manual) {
} }
App.run_safe_shutdown_hooks(); App.run_safe_shutdown_hooks();
#if defined(USE_ESP32) this->deep_sleep_();
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
if (this->sleep_duration_.has_value())
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
if (this->wakeup_pin_ != nullptr) {
bool level = !this->wakeup_pin_->is_inverted();
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
level = !level;
}
esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level);
}
if (this->ext1_wakeup_.has_value()) {
esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode);
}
if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) {
esp_sleep_enable_touchpad_wakeup();
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
}
#endif
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6)
if (this->sleep_duration_.has_value())
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
if (this->wakeup_pin_ != nullptr) {
bool level = !this->wakeup_pin_->is_inverted();
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
level = !level;
}
esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
}
#endif
esp_deep_sleep_start();
#endif
#ifdef USE_ESP8266
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
#endif
} }
float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; } float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; }
void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; } void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; }
void DeepSleepComponent::allow_deep_sleep() { this->prevent_ = false; } void DeepSleepComponent::allow_deep_sleep() { this->prevent_ = false; }
} // namespace deep_sleep } // namespace deep_sleep

View File

@@ -34,10 +34,12 @@ enum WakeupPinMode {
WAKEUP_PIN_MODE_INVERT_WAKEUP, WAKEUP_PIN_MODE_INVERT_WAKEUP,
}; };
#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3)
struct Ext1Wakeup { struct Ext1Wakeup {
uint64_t mask; uint64_t mask;
esp_sleep_ext1_wakeup_mode_t wakeup_mode; esp_sleep_ext1_wakeup_mode_t wakeup_mode;
}; };
#endif
struct WakeupCauseToRunDuration { struct WakeupCauseToRunDuration {
// Run duration if woken up by timer or any other reason besides those below. // Run duration if woken up by timer or any other reason besides those below.
@@ -106,11 +108,19 @@ class DeepSleepComponent : public Component {
// duration before entering deep sleep. // duration before entering deep sleep.
optional<uint32_t> get_run_duration_() const; optional<uint32_t> get_run_duration_() const;
void dump_config_platform_();
bool prepare_to_sleep_();
void deep_sleep_();
optional<uint64_t> sleep_duration_; optional<uint64_t> sleep_duration_;
#ifdef USE_ESP32 #ifdef USE_ESP32
InternalGPIOPin *wakeup_pin_; InternalGPIOPin *wakeup_pin_;
WakeupPinMode wakeup_pin_mode_{WAKEUP_PIN_MODE_IGNORE}; WakeupPinMode wakeup_pin_mode_{WAKEUP_PIN_MODE_IGNORE};
#if !defined(USE_ESP32_VARIANT_ESP32C3)
optional<Ext1Wakeup> ext1_wakeup_; optional<Ext1Wakeup> ext1_wakeup_;
#endif
optional<bool> touch_wakeup_; optional<bool> touch_wakeup_;
optional<WakeupCauseToRunDuration> wakeup_cause_to_run_duration_; optional<WakeupCauseToRunDuration> wakeup_cause_to_run_duration_;
#endif #endif

View File

@@ -0,0 +1,104 @@
#ifdef USE_ESP32
#include "deep_sleep_component.h"
#include "esphome/core/log.h"
namespace esphome {
namespace deep_sleep {
static const char *const TAG = "deep_sleep";
optional<uint32_t> DeepSleepComponent::get_run_duration_() const {
if (this->wakeup_cause_to_run_duration_.has_value()) {
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
switch (wakeup_cause) {
case ESP_SLEEP_WAKEUP_EXT0:
case ESP_SLEEP_WAKEUP_EXT1:
case ESP_SLEEP_WAKEUP_GPIO:
return this->wakeup_cause_to_run_duration_->gpio_cause;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
return this->wakeup_cause_to_run_duration_->touch_cause;
default:
return this->wakeup_cause_to_run_duration_->default_cause;
}
}
return this->run_duration_;
}
void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) {
this->wakeup_pin_mode_ = wakeup_pin_mode;
}
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; }
void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
#endif
void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) {
wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration;
}
void DeepSleepComponent::dump_config_platform_() {
if (wakeup_pin_ != nullptr) {
LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_);
}
if (this->wakeup_cause_to_run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms",
this->wakeup_cause_to_run_duration_->default_cause);
ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause);
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
}
}
bool DeepSleepComponent::prepare_to_sleep_() {
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr &&
!this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) {
// Defer deep sleep until inactive
if (!this->next_enter_deep_sleep_) {
this->status_set_warning();
ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep...");
}
this->next_enter_deep_sleep_ = true;
return false;
}
return true;
}
void DeepSleepComponent::deep_sleep_() {
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
if (this->sleep_duration_.has_value())
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
if (this->wakeup_pin_ != nullptr) {
bool level = !this->wakeup_pin_->is_inverted();
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
level = !level;
}
esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level);
}
if (this->ext1_wakeup_.has_value()) {
esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode);
}
if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) {
esp_sleep_enable_touchpad_wakeup();
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
}
#endif
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6)
if (this->sleep_duration_.has_value())
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
if (this->wakeup_pin_ != nullptr) {
bool level = !this->wakeup_pin_->is_inverted();
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
level = !level;
}
esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
}
#endif
esp_deep_sleep_start();
}
} // namespace deep_sleep
} // namespace esphome
#endif

View File

@@ -0,0 +1,23 @@
#ifdef USE_ESP8266
#include "deep_sleep_component.h"
#include <Esp.h>
namespace esphome {
namespace deep_sleep {
static const char *const TAG = "deep_sleep";
optional<uint32_t> DeepSleepComponent::get_run_duration_() const { return this->run_duration_; }
void DeepSleepComponent::dump_config_platform_() {}
bool DeepSleepComponent::prepare_to_sleep_() { return true; }
void DeepSleepComponent::deep_sleep_() {
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
}
} // namespace deep_sleep
} // namespace esphome
#endif

View File

@@ -86,9 +86,14 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r
if (this->model_ == DHT_MODEL_DHT11) { if (this->model_ == DHT_MODEL_DHT11) {
delayMicroseconds(18000); delayMicroseconds(18000);
} else if (this->model_ == DHT_MODEL_SI7021) { } else if (this->model_ == DHT_MODEL_SI7021) {
#ifdef USE_ESP8266
delayMicroseconds(500); delayMicroseconds(500);
this->pin_->digital_write(true); this->pin_->digital_write(true);
delayMicroseconds(40); delayMicroseconds(40);
#else
delayMicroseconds(400);
this->pin_->digital_write(true);
#endif
} else if (this->model_ == DHT_MODEL_DHT22_TYPE2) { } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) {
delayMicroseconds(2000); delayMicroseconds(2000);
} else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) { } else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) {

View File

@@ -37,14 +37,18 @@ void DS1307Component::read_time() {
ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
return; return;
} }
ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10), ESPTime rtc_time{
.minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10), .second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10),
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10), .minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10),
.day_of_week = uint8_t(ds1307_.reg.weekday), .hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
.day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10), .day_of_week = uint8_t(ds1307_.reg.weekday),
.day_of_year = 1, // ignored by recalc_timestamp_utc(false) .day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10),
.month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10), .day_of_year = 1, // ignored by recalc_timestamp_utc(false)
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)}; .month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10),
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000),
.is_dst = false, // not used
.timestamp = 0 // overwritten by recalc_timestamp_utc(false)
};
rtc_time.recalc_timestamp_utc(false); rtc_time.recalc_timestamp_utc(false);
if (!rtc_time.is_valid()) { if (!rtc_time.is_valid()) {
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock."); ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");

View File

@@ -1 +0,0 @@
CODEOWNERS = ["@vincentscode"]

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