Compare commits

...

622 Commits

Author SHA1 Message Date
Jesse Hills 22351be1e4 Log incoming device requests from HA 2024-05-28 08:11:46 +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
Jesse Hills bd8afa51cd Merge pull request #6741 from esphome/bump-2024.5.0b5
2024.5.0b5
2024-05-15 09:57:25 +12:00
Jesse Hills db4aa0b679 Bump version to 2024.5.0b5 2024-05-15 07:37:22 +12:00
Mischa Siekmann 28a09cc0d0 Add ANNOUNCING state to media_player. (#6691) 2024-05-15 07:37:21 +12:00
Mischa Siekmann 128fad57b3 Voice-Assistant: Start-order change for VAD disabled: start va-pipeline when microphon… (#6391) 2024-05-15 07:37:21 +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
Jesse Hills 142c4a87d2 Merge pull request #6733 from esphome/bump-2024.5.0b4
2024.5.0b4
2024-05-14 11:38:00 +12:00
Jesse Hills 1e4d6ee344 Bump version to 2024.5.0b4 2024-05-14 10:02:22 +12:00
Jesse Hills 5afe0e5ec2 Fix ESPHOME_PROJECT_VERSION_30 (#6731) 2024-05-14 10:02:22 +12:00
dependabot[bot] ba3fc4c5d0 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 10:02:22 +12:00
Mischa Siekmann 694f75117e Set FEATURE_API_AUDIO flag also if the speaker component is not used (#6712) 2024-05-14 10:02:22 +12:00
Marcin Krasowski 4ec2ef27a8 fix(ltr390): stuck ALS values when configured for ALS+UV readings (#6723) 2024-05-14 10:02:21 +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 448b4f5cb6 Merge pull request #6713 from esphome/bump-2024.5.0b3
2024.5.0b3
2024-05-09 23:04:30 +12:00
Jesse Hills 8ae8cd1168 Bump version to 2024.5.0b3 2024-05-09 21:55:34 +12:00
Jesse Hills bd776baf8d [github] Fix digest artifact name (#6710) 2024-05-09 21:55:34 +12:00
Clyde Stubbs 819bb9f8bc [color] Fix crash when hex color parses as int, improve error reporting. (#6707) 2024-05-09 21:55:34 +12:00
Clyde Stubbs 26048d18ef [core] Ensure that a generated ID name is distinct from its type. (#6706) 2024-05-09 21:55:34 +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
Jesse Hills 0883f0efd7 Merge pull request #6708 from esphome/bump-2024.5.0b2
2024.5.0b2
2024-05-09 17:29:33 +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
Jesse Hills 0ca395e8d0 Bump version to 2024.5.0b2 2024-05-09 14:45:40 +12:00
J. Nick Koston 98dc9fde6c Bump recommended ESP-IDF to 4.4.7 (#6703) 2024-05-09 14:45:40 +12:00
Nate Clark ed1344edd2 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 14:45:40 +12:00
Jesse Hills 2fbe80c1f7 [ethernet] Use constexpr instead of inline define for KSZ80XX_PC2R_REG_ADDR (#6705) 2024-05-09 14:45:40 +12:00
Mat931 879f404b48 [remote_receiver, remote_transmitter] Improve error messages on the ESP32 (#6701) 2024-05-09 14:45:40 +12:00
Edward Firmo 34585a6f15 [nextion] Replace flags to USE_ARDUINO (#6700) 2024-05-09 14:45:40 +12:00
Jesse Hills 054587c0e4 [github] Upgrade to actions/{upload,download}-artifact v4 (#6698) 2024-05-09 14:45:39 +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 e027c6248a Merge pull request #6697 from esphome/bump-2024.5.0b1
2024.5.0b1
2024-05-08 14:08:15 +12:00
Jesse Hills b7c6125a0b Bump version to 2024.6.0-dev 2024-05-08 13:22:05 +12:00
Jesse Hills bd8ccde862 Bump version to 2024.5.0b1 2024-05-08 13:22:04 +12:00
Jesse Hills 24aac10abe Merge branch 'release' into dev 2024-05-08 13:21:39 +12:00
esphomebot d9fca585a2 Update webserver local assets to 20240507-231331 (#6696) 2024-05-08 11:57:03 +12:00
Trent Houliston b545d57236 Make pulse_meter PULSE filter report the pulse as soon as it can (#6014) 2024-05-08 10:13:15 +12:00
Keith Burzinski f6a3784eba Consolidate test files where all tests are identical (#6690) 2024-05-08 07:33:37 +12:00
Clyde Stubbs 829bfbdaa4 Migrate some constants to core code (#6692) 2024-05-08 07:26:04 +12:00
Samuel Sieb 5edf4970bd proceed if AP mode is set up (#6631) 2024-05-06 20:44:36 -07:00
RFDarter 1e196bac98 fix date_time validation (#6688)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-07 12:47:07 +12:00
Jesse Hills 7b0536fda3 Bump esphome/ESPAsyncWebServer-esphome to 3.2.0 (#6687) 2024-05-07 11:54:01 +12:00
RFDarter 5ee2a5f935 Fix Datetime-Datetime compiler error (#6686)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-07 10:44:49 +12:00
dependabot[bot] 594769be3c Bump actions/checkout from 4.1.1 to 4.1.5 (#6685)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 09:09:04 +12:00
tomaszduda23 8463f897e1 fix conflict with EMPTY macro in zephyr (#6679) 2024-05-07 07:20:01 +12:00
Markus d1758a46bd Use clang-apply-replacements when clang-apply-replacements-14 does not exist (#6684) 2024-05-07 07:17:03 +12:00
Tomek Wasilczyk f2caaf85c8 External components: optional configurable path for git source (#6677)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-06 15:19:13 +12:00
Anton Viktorov 599dbf27e0 Minor tidy up of BME280 code (#6672)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-06 14:19:25 +12:00
mkmer 833d31ef7a Add fast update to HMC5883L (#6669) 2024-05-06 10:48:09 +12:00
Edward Firmo f78397c77e Fix recent definitions into defines.h (#6667)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-05-06 10:12:09 +12:00
tomaszduda23 8796a4c1a7 print task name if logger is called from other than main thread (#6630) 2024-05-06 10:10:49 +12:00
tomaszduda23 f1584205af [core] Rename ALWAYS_INLINE to ESPHOME_ALWAYS_INLINE (#6636) 2024-05-06 07:52:47 +12:00
Jesse Hills ccbf5148aa Set "CONF_" CI counter to fail on 3 or more definitions (#6668) 2024-05-05 00:32:47 -05:00
Anton Viktorov c7c0d97a5e SPI and I2C for BMP390 and BMP380 (#6652)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-02 13:49:01 +12:00
tronikos bc65e6e914 Make fast update intervals in qmc5883l work (#6647)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-02 13:24:18 +12:00
Mat931 1b9a30e921 Remote receiver improvements (#4642)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-02 13:21:57 +12:00
tronikos 539c369eea Add a function to return the loop_interval (#6666) 2024-05-02 12:39:15 +12:00
Edward Firmo a4a23d73b3 [nextion] Use persistent http connection for TFT upload (ESP-IDF) (#6576)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-02 10:05:37 +12:00
Keith Burzinski 5ddad26476 Extend and consolidate script tests (#6663) 2024-05-02 07:17:11 +12:00
Keith Burzinski c69cdec052 Extend MQTT tests (#6648) 2024-05-01 16:49:20 +12:00
Edward Firmo c299dff124 [nextion] Use persistent http connection for TFT upload (Arduino) (#6582)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-01 09:43:49 +12:00
Anton Sergunov 6fe328ef2b [TM1637] Let turn off the display (#6656)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-30 22:35:41 +12:00
Edward Firmo 74fd52e05f [nextion] Set alternative TFT update baud rate (#6587) 2024-04-30 21:29:57 +12:00
Jesse Hills 48fa549042 Merge pull request #6660 from esphome/bump-2024.4.2
2024.4.2
2024-04-30 16:30:03 +12:00
Jesse Hills 516971a255 Bump version to 2024.4.2 2024-04-30 15:47:40 +12:00
Jesse Hills 4936cbec0d [i2s_audio.microphone] Fixing adc bug (#6654) 2024-04-30 15:47:40 +12:00
tronikos 9832fa4d76 Revert #6458 (#6650)
Reading the z-axis register is required.
2024-04-30 15:47:40 +12:00
Samuel Sieb 5838af646b allow defaults with no include vars (#6613) 2024-04-30 15:47:40 +12:00
mrtoy-me 33e9881830 Fix SHT3xd fails sometimes in 2024.4.0 (#6592)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-30 15:47:39 +12:00
Edward Firmo 05fbb260ee [nextion] Exit reparse before update TFT (#6589) 2024-04-30 10:09:35 +12:00
esphomebot 989a64bdcf Update webserver local assets to 20240429-211523 (#6657) 2024-04-30 09:45:03 +12:00
Peter Zich 47c262832b web_server: Add support for v3 local server_index (#6563) 2024-04-30 07:24:13 +12:00
Anton Sergunov 73bb4aa4d5 [template/text] Fix lambda config (#6655)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-04-29 20:40:03 +10:00
Clyde Stubbs c007593f72 Fix for #4866 - inconsistent arguments (#6639) 2024-04-29 15:53:08 +12:00
Jesse Hills 80a0b5b1b1 [i2s_audio.microphone] Fixing adc bug (#6654) 2024-04-29 12:10:12 +12:00
Matt Quigley e7c1ddb452 patch esphome cli to skip mqtt based device discovery if --device option is specified (#6371)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-29 07:57:11 +12:00
Ulrich 9ea442f328 Fix upload command. MQTT user and password is missing from configuration. #5093 (#5766)
Co-authored-by: ulrich <u.martiensen@umartiensen.de>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-29 07:56:13 +12:00
chiahsing 8b6a358452 Fixed the issue that graph draws out of the boundary. (#6651) 2024-04-29 07:49:27 +12:00
Lucas Hartmann 5142d294f5 [light] Add transition_length to strobe effect. (#6595) 2024-04-29 07:47:15 +12:00
Keith Burzinski 8334934e08 Allow platform dependencies (#6623) 2024-04-29 07:44:40 +12:00
Jesse Hills a700ae481d Fix command line substitutions without any yaml substitutions (#6644) 2024-04-29 07:33:52 +12:00
optimusprimespace 0ef7781bb3 [hm3301] Updated the AQI based on the airnow document (#6004) 2024-04-29 07:22:14 +12:00
tronikos 76c55992ae Revert #6458 (#6650)
Reading the z-axis register is required.
2024-04-27 18:22:41 -07:00
Alex Boyd 9bfb36f58b Extract core comments from #6241 (#6643) 2024-04-26 21:41:43 +10:00
polyfloyd cd91c7050c waveshare_epaper: Add 2.90in-dke (#6492)
Co-authored-by: The_Niz <the_niz@nurdspace.nl>
2024-04-26 18:44:58 +10:00
NP v/d Spek 031e26ad98 Display: add diagnostic test_card option (#6608)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-04-26 13:23:28 +10:00
esphomebot 3ecb5fa57f Synchronise Device Classes from Home Assistant (#6638) 2024-04-26 11:40:19 +12:00
Keith Burzinski 3997503071 Remove text_sensor from sync-device-class job (#6637) 2024-04-26 11:03:24 +12:00
Anton Viktorov 8fcfcccbc3 Multiple Daly-BMS support (#6615) 2024-04-26 09:20:21 +12:00
Jesse Hills 8ef7b41c91 Add datetime entities (#6513) 2024-04-26 09:19:54 +12:00
Keith Burzinski bcef64a6fa Add event, text_sensor and valve device classes to sync script (#6624) 2024-04-26 09:04:48 +12:00
Nico Peter 5288d5ac95 Feature add last_operation to time based cover (#6084)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-26 09:04:20 +12:00
chiahsing de2a92e45d Fix graph hangs when y <= 0 (#6593) 2024-04-26 09:01:51 +12:00
Clyde Stubbs 0662c5e0fb Fix for #6614- use background_color, improve anti-aliasing (#6618) 2024-04-26 09:00:01 +12:00
Joakim Plate 2fa5846893 Ble client fixes for proxy (#6596) 2024-04-25 20:05:30 +10:00
tomaszduda23 bdc9c66f7e Move CONF_PLATFORM_VERSION to global const.py (#6629)
* remove duplicated definition

* format
2024-04-25 04:50:41 -05:00
Daniel Kent 41b19504bc Add get/set color temperature functions in Kelvin (#5006)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-24 04:18:54 +00:00
Patrick 1775c73e53 Fix issue when setting cw/ww brightness via temperature (#5976) 2024-04-23 22:56:56 -05:00
rforro e2b0d561bc Add Roomba IR protocol (#4595)
Co-authored-by: Richard Forro <r@f.rf>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-24 15:21:08 +12:00
Evgeny a7079f8fba Added base64 helper (#4866)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-24 15:07:07 +12:00
Jesse Hills 1ac855f2e0 Only check c/c++ files with clang-format (#6620) 2024-04-24 14:49:16 +12:00
David Friedland c531a528f0 Event entity support (#6451)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-24 14:35:26 +12:00
Mike La Spina b03d0f37a4 Limit Rx wait loop time to 3 seconds. (#6594)
Co-authored-by: descipher <mike.laspina@gelidus.ca>
2024-04-24 14:01:28 +12:00
Jesse Hills 217988fd99 Sort mqtt_const alphabetically (#6619) 2024-04-24 13:49:08 +12:00
Jean Louis-Guerin f8cdb087fc Add the WeiKai SPI/I2C UART/IO Expander components to esphome (#5218)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-24 13:21:44 +12:00
Jesse Hills f9ce35c894 Allow UART to be AUTO LOADed (#6617) 2024-04-24 09:59:19 +12:00
Clyde Stubbs b8f0182fc5 Add null GPIO pin (#6611) 2024-04-24 08:49:14 +12:00
Clyde Stubbs 8027921ba3 graphical_display_menu requires a Display, not DisplayBuffer (#6614) 2024-04-24 07:55:27 +12:00
Keith Burzinski 06829b53fe Add some components to the new testing framework (S part 2) (#6227)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-24 07:40:20 +12:00
Keith Burzinski 7e8ed5c391 Add some components to the new testing framework (S part 1) (#6224)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-23 21:49:15 +12:00
Keith Burzinski ed381b45eb Add some components to the new testing framework (T) (#6229) 2024-04-23 21:49:03 +12:00
Keith Burzinski 18149bc276 Add some components to the new testing framework (I) (#6185)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-23 21:36:30 +12:00
Jesse Hills b1839702f9 [tests] Run yaml tests in groups if over 100 to run (#6612) 2024-04-23 21:19:10 +12:00
Samuel Sieb 06d3829b45 allow defaults with no include vars (#6613) 2024-04-23 18:43:11 +12:00
Jesse Hills 8cb809d84d [sn74hc595] Enforce type field to distinguish gpio vs spi mode (#6609) 2024-04-23 17:22:14 +12:00
Keith Burzinski 7e5b100b77 Add some components to the new testing framework (R) (#6219)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-23 16:53:13 +12:00
Keith Burzinski eb89d99999 Add valve component (#6447)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-23 16:47:03 +12:00
Jesse Hills fa8d09aca9 [mopeka_std_check] Fix test file indentation (#6610) 2024-04-23 16:20:37 +12:00
Keith Burzinski 6806cb28f6 Add some components to the new testing framework (O) (#6211) 2024-04-23 15:45:59 +12:00
Keith Burzinski c0dc9c20fc Add some components to the new testing framework (M part 2) (#6208) 2024-04-23 15:45:25 +12:00
Keith Burzinski 2b215fecc9 Add some components to the new testing framework (M part 1) (#6207) 2024-04-23 15:45:12 +12:00
Keith Burzinski 057f473a4a Add some components to the new testing framework (P) (#6213) 2024-04-23 15:38:51 +12:00
Jesse Hills 8eeb28d797 Merge branch 'release' into dev 2024-04-23 11:58:18 +12:00
Jesse Hills fcd9e3cb5d Merge pull request #6607 from esphome/bump-2024.4.1
2024.4.1
2024-04-23 11:51:30 +12:00
mrtoy-me b737fe70a6 Fix SHT3xd fails sometimes in 2024.4.0 (#6592)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-23 11:16:55 +12:00
Jesse Hills a7fb2ce3e1 Use clang-format version from requirements_dev file (#6606) 2024-04-23 11:01:20 +12:00
Jesse Hills 7ae36b023c Bump version to 2024.4.1 2024-04-23 10:50:41 +12:00
Jonathan Swoboda 3e64876097 Fix or filter (#6574)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
2024-04-23 10:50:41 +12:00
polyfloyd 44d13f2405 esp32_ble: Consider ESP_BT_STATUS_DONE a successful state (#6493)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-04-23 10:50:41 +12:00
Clyde Stubbs 03d547d2c0 Disallow variant/family override for known boards (#6512) 2024-04-23 10:50:41 +12:00
Cody Cutrer dd8be524b4 fix streaming logs from MQTT for ESP32 devices using TLS (#6605) 2024-04-23 10:50:41 +12:00
Mat931 a29e634af1 Calibrate Beken internal temperature (#6599) 2024-04-23 10:50:41 +12:00
Javier Peletier 1a152169e0 wifi: fix reconnect issue due to enablement of fast connect (#6598) 2024-04-23 10:50:40 +12:00
zry98 496b7f45db [Tuya Climate] Fix compilation error caused by codegen (#6568) 2024-04-23 10:50:40 +12:00
Jonathan Swoboda 0874440a31 Fix or filter (#6574)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
2024-04-23 10:48:30 +12:00
polyfloyd aee2a49cad esp32_ble: Consider ESP_BT_STATUS_DONE a successful state (#6493)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-04-23 10:17:00 +12:00
Clyde Stubbs 7510468a9b Add yamllint and clang-format to pre-commit hooks (#6578)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-23 10:10:07 +12:00
Clyde Stubbs c7bfd9b46b Disallow variant/family override for known boards (#6512) 2024-04-23 10:04:56 +12:00
Cody Cutrer 7c893aa330 fix streaming logs from MQTT for ESP32 devices using TLS (#6605) 2024-04-23 09:48:29 +12:00
dependabot[bot] a9a9be32d3 Bump aioesphomeapi from 24.0.0 to 24.3.0 (#6602)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 09:14:56 +12:00
Mat931 50e3ce4c80 Calibrate Beken internal temperature (#6599) 2024-04-23 08:59:06 +12:00
Javier Peletier 927caf062b wifi: fix reconnect issue due to enablement of fast connect (#6598) 2024-04-23 08:48:06 +12:00
Edward Firmo 16e0b78c64 Define USE_ESP32_BLE (#6585) 2024-04-22 23:05:50 +12:00
Jesse Hills 45ae78de03 Create `component_dir` substitution for local files to be included in… (#6575) 2024-04-22 10:29:56 +12:00
Samuel Sieb 655dbc48b5 remove delay from tmp102 (#6577)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-04-19 07:52:22 +10:00
Clyde Stubbs 8c31aea94f Fix some printf formats for size_t. (#6542)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-18 17:03:15 +12:00
Edward Firmo 2e7ac26ada Nextion send_command method (#6540)
This is a simplified version of `send_command_printf` without the `printf` support.
Manually send a raw command to the display.
param command The pcommand, like "page 0"
return Whether the send was successful.
2024-04-18 02:16:49 +00:00
Clyde Stubbs 2fed6955de On failure, dump the output of preceding jobs in CI status (#6564) 2024-04-18 12:11:00 +12:00
Edward Firmo 197f9d6d03 Nextion - Review types (#6565) 2024-04-18 12:10:10 +12:00
Edward Firmo 39deb89108 Nextion - Do not refresh sensors while updating (#6566) 2024-04-18 12:05:37 +12:00
Cossid 5a093acbf5 SM2135 - Use standard channel ordering. (#6573) 2024-04-18 12:03:59 +12:00
Keith Burzinski abc09a15c3 Allow component final_validate (#6475)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-18 11:47:34 +12:00
Edward Firmo 8c323e2e4c Nextion - Review set_protocol_reparse_mode() (#6567) 2024-04-18 11:07:05 +12:00
dependabot[bot] 6075067e84 Bump peter-evans/create-pull-request from 6.0.3 to 6.0.4 (#6569)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-18 11:02:54 +12:00
dependabot[bot] 09def255dd Bump pytest-mock from 3.12.0 to 3.14.0 (#6572)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-18 11:02:37 +12:00
Jesse Hills 4559e963b3 Housecleaning: Use walrus operator in sensor (#6553)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-04-18 09:43:18 +12:00
Jesse Hills 72c1c3f091 Housecleaning: Use walrus operator in lock (#6554)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-04-18 09:43:11 +12:00
Jesse Hills c8cdb30459 Housecleaning: Use walrus operator in switch (#6558) 2024-04-18 09:43:00 +12:00
zry98 51ed6d62d9 [Tuya Climate] Fix compilation error caused by codegen (#6568) 2024-04-18 09:31:20 +12:00
J. Nick Koston 987ffcbaba Bump zeroconf to 0.132.2 (#6548) 2024-04-18 09:09:42 +12:00
Jesse Hills 7733781e09 Housecleaning: Use walrus operator in text_sensor (#6559) 2024-04-17 02:51:33 -05:00
Jesse Hills 214c237c8d Housecleaning: Use walrus operator in fan (#6555)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-04-17 02:03:57 -05:00
Jesse Hills 77ade12ee9 Housecleaning: Use walrus operator in climate (#6551) 2024-04-17 01:58:20 -05:00
Jesse Hills fa1adf7528 Housecleaning: Use walrus operator in cover (#6562) 2024-04-17 01:28:01 -05:00
Jesse Hills 21e3faad38 Housecleaning: Use walrus operator in number (#6561) 2024-04-17 01:27:04 -05:00
Jesse Hills 8eff3435e7 Housecleaning: Use walrus operator in select (#6557) 2024-04-17 01:26:49 -05:00
Jesse Hills 3f015562d7 Housecleaning: Use walrus operator in light (#6556) 2024-04-17 01:26:36 -05:00
Jesse Hills 2fc2d5839f Housecleaning: Use walrus operator in text (#6560) 2024-04-17 01:22:52 -05:00
Jesse Hills 717cea548f Housecleaning: Use walrus operator in datetime (#6552) 2024-04-17 00:42:40 -05:00
luar123 6104e7591e Fix uart to work with new enum definition in esp-idf-v5.2.1 (#6487) 2024-04-17 16:57:26 +12:00
Jesse Hills 83feae4eb2 Use trusted publishing token for pypi (#6545) 2024-04-17 16:55:13 +12:00
Jesse Hills ca5d38f413 Call workflow for addon with dev version (#6549) 2024-04-17 15:32:19 +12:00
Jesse Hills 0af26fdfd4 Move esphome-fork startup script to main repo. (#6523)
Co-authored-by: Blair McBride <blair@theunfocused.net>
2024-04-17 14:43:29 +12:00
Jesse Hills ec4f96aadd Merge branch 'release' into dev 2024-04-17 14:22:19 +12:00
Jesse Hills e1b861a0a1 Merge pull request #6547 from esphome/bump-2024.4.0
2024.4.0
2024-04-17 14:13:43 +12:00
Jesse Hills f2a12589f3 Bump version to 2024.4.0 2024-04-17 13:08:27 +12:00
Jesse Hills 6a1ea06744 Add enum option to typed_schema (#6546)
* Add enum option to typed_schema

* Assert keys all match
2024-04-16 18:04:10 -05:00
dependabot[bot] 7d99676fe8 Bump pyupgrade from 3.15.1 to 3.15.2 (#6543)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-16 19:50:22 +00:00
dependabot[bot] 80488a2b72 Bump aioesphomeapi from 23.2.0 to 24.0.0 (#6544)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-16 19:34:56 +00:00
dependabot[bot] 01419822f7 Bump pylint from 3.0.3 to 3.1.0 (#6287)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-16 10:59:44 +12:00
Jesse Hills 27b286b57f Bump python version in sync-device-classes workflow to 3.12 for HA (#6541) 2024-04-16 09:42:15 +12:00
dependabot[bot] cca5f818e5 Bump peter-evans/create-pull-request from 6.0.2 to 6.0.3 (#6525)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-16 09:39:27 +12:00
dependabot[bot] b3f02e54cd Bump black from 24.2.0 to 24.4.0 (#6539)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-16 08:58:10 +12:00
Edward Firmo 6876c65eda Define USE_PSRAM (#6526) 2024-04-15 17:13:31 +12:00
Jesse Hills 0e3021b5f8 Merge branch 'beta' into dev 2024-04-15 16:02:40 +12:00
Jesse Hills 3bae72a8a7 Merge pull request #6536 from esphome/bump-2024.4.0b3
2024.4.0b3
2024-04-15 16:01:34 +12:00
Jesse Hills b6f1cfd69f Bump version to 2024.4.0b3 2024-04-15 13:27:01 +12:00
Clyde Stubbs 09fbddea21 Fix no-release bug on ft6x36 (#6527) 2024-04-15 13:27:01 +12:00
Jesse Hills ed02747ebc Fix project version longer than 30 characters breaking compilation (#6535) 2024-04-15 13:27:01 +12:00
Jesse Hills ff0d33ffe3 Fix missing ifdefs in voice assistant (#6520) 2024-04-15 13:27:01 +12:00
Clyde Stubbs 86f9af13aa Fix no-release bug on ft6x36 (#6527) 2024-04-15 13:08:35 +12:00
Keith Burzinski b43ad5da6d Update homeassistant component tests with actions (#6528) 2024-04-15 12:25:10 +12:00
Jesse Hills dc200948fa Fix project version longer than 30 characters breaking compilation (#6535) 2024-04-15 12:02:19 +12:00
Keith Burzinski 6370e68670 Add actions to http_request tests (#6529) 2024-04-15 09:38:31 +12:00
Keith Burzinski 1ab4fc8faf Add all missing remote_receiver on_... tests (#6524) 2024-04-12 09:35:12 +00:00
Jimmy Hedman 76daefe21c Add ethernet DNS text sensor and simplify DNS display format (#6450) 2024-04-12 14:03:08 +10:00
Peter Zich 7eb524f920 Add "log" alias for "logs" command (#6519) 2024-04-12 15:46:59 +12:00
Jesse Hills 810cf3b0a4 Add bk72xx base test file (#6522) 2024-04-11 18:56:18 -05:00
MRemy2 39947a1634 Added Htu21d model option (#6511)
Co-authored-by: Remus <remus@intelNuc.local>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-12 11:28:59 +12:00
Jesse Hills 55433463d7 Fix missing ifdefs in voice assistant (#6520) 2024-04-11 22:19:49 +00:00
Jesse Hills 3ec7f4221f Merge pull request #6518 from esphome/bump-2024.4.0b2
2024.4.0b2
2024-04-12 09:19:33 +12:00
Jesse Hills 8ada8f5e11 Bump version to 2024.4.0b2 2024-04-12 08:02:52 +12:00
Jesse Hills 4ebbd4ebd8 Bump esphome-dashboard to 20240412.0 (#6517) 2024-04-12 08:02:52 +12:00
Jesse Hills 1d4c074ee6 ads1115: remove auto-load and split sensor into platform folder (#5981) 2024-04-12 08:02:52 +12:00
Jesse Hills 68b4d8865c Add dooya remote transmitter test (#6508) 2024-04-12 08:02:52 +12:00
Jesse Hills e6bfa275fc Bump esphome-dashboard to 20240412.0 (#6517) 2024-04-12 07:57:41 +12:00
Jesse Hills 6d480c5f05 ads1115: remove auto-load and split sensor into platform folder (#5981) 2024-04-11 10:09:25 +12:00
Keith Burzinski e59b81612f Add some components to the new testing framework (H) (#6179)
* Add some components to the new testing framework (H)

* Remove C3

* Fix indentation

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-10 03:57:22 -05:00
Jesse Hills 1e0f6e139a Add dooya remote transmitter test (#6508) 2024-04-10 19:25:35 +12:00
Jesse Hills 4a11885ef3 Merge pull request #6510 from esphome/bump-2024.4.0b1
2024.4.0b1
2024-04-10 14:05:28 +12:00
Jesse Hills a102e982b3 Bump version to 2024.5.0-dev 2024-04-10 12:49:45 +12:00
Jesse Hills 9af083af03 Bump version to 2024.4.0b1 2024-04-10 12:49:45 +12:00
Jesse Hills 8f89311ab5 Merge branch 'release' into dev 2024-04-10 12:46:15 +12:00
RFDarter b4b4e81c1c Webserver float to string fix (#6507) 2024-04-10 11:33:26 +12:00
leejoow e5e8bc8515 Only give error for connected sensors at startup (#6474)
Co-authored-by: Leo Schelvis <LSchelvis@dela.org>
2024-04-10 11:22:18 +12:00
bukureckid 522b43bb41 Add Dooya protocol to remote_base (#6488) 2024-04-10 09:04:35 +12:00
IJssel 3adfed3675 Implemented support for the TLC5971 as an output component (#6494) 2024-04-10 08:03:18 +12:00
Mat931 857b8ef363 esp32_rmt_led_strip bugfixes (#6506) 2024-04-10 07:14:56 +12:00
Jesse Hills 0ba4e8c0ba UART: ignore require_tx/rx if not a native uart implementation (#6504) 2024-04-09 04:55:20 +00:00
Jesse Hills 12aa272234 Rework tlc5947 to remove AUTO_LOAD (#6503) 2024-04-09 15:51:54 +12:00
Jesse Hills c66b2c52c1 Add rmt_channel to remote_transmitter and remote_receiver (#6497)
* Add rmt_channel to remote_transmitter and remote_receiver

* Add codeowner

* Add tests
2024-04-08 20:53:57 -05:00
MRemy2 55c49281a2 Fix Match by IRK (#6499)
Co-authored-by: Remus <remus@intelNuc.local>
2024-04-09 13:49:37 +12:00
Jesse Hills 76c5337987 Add support for time entities (#6399)
* Add time entities

* Add tests

* Add myself to datetime codeowners

* Fix publishing times with 0 values

* Log performing TimeCall

* Implement `on_time` trigger

* Rename var

* Fix initial value for time

* Add arg name for clarity

* Remove useless checks
2024-04-08 20:46:35 -05:00
Mat931 3b6e8fa666 Add ABB-Welcome / Busch-Welcome Door Intercom Protocol (#4689)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-09 13:43:53 +12:00
tracestep 5441213b27 Adds i2c timeout config (#4614)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-09 13:11:46 +12:00
cvwillegen 16d154e2e5 Add MAC address to WiFi config reply (#6489)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-04-09 01:07:04 +00:00
fariouche efc9fd060d add support for Tuya pink version of miflora (#5402) 2024-04-09 10:17:51 +12:00
dependabot[bot] 708d5034cb Bump docker/setup-buildx-action from 3.2.0 to 3.3.0 (#6502)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-09 09:48:04 +12:00
Mat931 270fb5e7ac Internal temperature: Support Beken platform (#6491) 2024-04-09 07:21:51 +12:00
Kuba Szczodrzyński 46c63f48c2 Bump LibreTiny version to 1.5.1 (#6500) 2024-04-09 07:19:50 +12:00
Clyde Stubbs e6b1187689 If the loop() took more than the required time, don't delay further (#6496) 2024-04-08 19:56:08 +12:00
RFDarter d6352b3be4 Datetime date initial value fix (#6483) 2024-04-08 19:36:23 +12:00
Jesse Hills 6f71363d9b Send/Receive Voice Assistant audio via API (#6471)
Co-authored-by: Michael Hansen <mike@rhasspy.org>
2024-04-08 16:19:22 +12:00
Clyde Stubbs 97ff87b718 Remove misleading tag/line in messages (#6495) 2024-04-08 16:13:12 +12:00
Jesse Hills 9eb7c26c80 Merge pull request #6472 from esphome/bump-2024.3.2
2024.3.2
2024-04-08 10:40:53 +12:00
Remy van Elst 38233444e7 Fix Microphone IsCapturingCondition (#6490) 2024-04-07 14:48:42 +12:00
Clyde Stubbs 2c67d83976 Include "Failed" status in config log. (#6482) 2024-04-04 23:21:56 -05:00
Jesse Hills c029ef5118 Bump version to 2024.3.2 2024-04-04 18:12:28 +13:00
NewoPL d2b3861465 fix: changing the content source when playing is paused blocks the player (#6454) 2024-04-04 18:12:28 +13:00
Samuel Sieb 87c4ad0256 Add missing ethernet types (#6444) 2024-04-04 18:12:28 +13:00
DAVe3283 4c9bcc71cb Fix logger compile error on ESP32-C6 (#6323) 2024-04-04 18:12:27 +13:00
Jesse Hills 0148ebcaa6 Replace std::regex with sscanf calls (#6468)
* Replace std::regex with sscanf calls

* Fix CI

* Use regular formatting placeholders

* Fix
2024-04-03 19:41:41 -05:00
Faidon Liambotis f09bfa7311 ESP32 Arduino WiFi: misc bug fixes (#6470) 2024-04-04 12:55:24 +13:00
Jesse Hills 5cc3d60fee web_server: Return early if no clients connected (#6467) 2024-04-03 17:13:59 -05:00
tronikos 96f4c70b6b Add temperature for QMC5883L (#6456) 2024-04-03 15:57:05 +13:00
Jesse Hills be8d188a55 Add yamllint to dev requirements (#6466) 2024-04-03 15:16:59 +13:00
Jesse Hills 02632f0cad Fix NOLINT on inclusive-language check (#6464) 2024-04-03 15:16:38 +13:00
Jesse Hills 4fcb26d69d Display menu: Allow "left" key to exit current menu if not editing (#6460) 2024-04-03 07:33:18 +13:00
Jimmy Hedman ec32501d40 Bump Arduino Pico Framework to 3.7.2 and Platform to 1.12.0 (#6386) 2024-04-02 16:00:47 +13:00
mrtoy-me e32b829670 TMP117 fix polling period config (#6452) 2024-04-02 15:35:59 +13:00
Leland Sindt 6deb253fa6 minor refactor to allow commit hash as ref value. (#6446) 2024-04-02 15:32:40 +13:00
tronikos 63db07a156 Optimize QMC5883L: Read registers only for enabled sensors (#6458) 2024-04-02 09:21:53 +13:00
NewoPL 1be5d14fd9 fix: changing the content source when playing is paused blocks the player (#6454) 2024-04-01 12:43:49 +13:00
dependabot[bot] 3a49e91ce0 Bump actions/setup-python from 5.0.0 to 5.1.0 in /.github/actions/restore-python (#6438)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 12:42:02 +13:00
dependabot[bot] 1207eda4ca Bump actions/setup-python from 5.0.0 to 5.1.0 (#6437)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 12:41:43 +13:00
Jimmy Hedman f4e8a89726 IPv6 string representation follows RFC5952 (#6449) 2024-04-01 12:40:11 +13:00
Samuel Sieb dc0a7b1e20 Add missing ethernet types (#6444) 2024-03-29 08:51:01 +13:00
mrtoy-me 731dcc40bc Minor change to support sht85 sensor (#6415) 2024-03-28 15:19:27 +13:00
Daniel Eisterhold 9194f7eb27 Add get_size method to QR Code header (#6430) 2024-03-28 12:56:26 +13:00
Jesse Hills 0ff543ffe5 Disable truthy yamllint rule (#6442) 2024-03-28 10:20:51 +13:00
MagicBear 6b7f9b15ea feat: Add Daikin ARC (tested on Daikin ARC472A62) (#6429) 2024-03-28 07:56:19 +13:00
Keith Burzinski 92b3d94cc7 Add some components to the new testing framework (L) (#6195) 2024-03-27 20:30:13 +13:00
Keith Burzinski 0630cdded3 Add some components to the new testing framework (W) (#6232)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-27 20:15:59 +13:00
Keith Burzinski 54a68bf069 Fix spacing in new test yaml (#6441) 2024-03-27 20:15:50 +13:00
Keith Burzinski dc071bed24 Add some components to the new testing framework (U) (#6230) 2024-03-27 14:26:50 +13:00
Keith Burzinski c36d7c0c3c Add some components to the new testing framework (Q) (#6218) 2024-03-27 14:25:02 +13:00
Keith Burzinski 9779989f67 Add some components to the new testing framework (N) (#6210) 2024-03-27 14:24:32 +13:00
Keith Burzinski ca6020e11a Add some components to the new testing framework (K) (#6186) 2024-03-27 14:22:54 +13:00
Keith Burzinski eee7146614 Add some components to the new testing framework (G) (#6178) 2024-03-27 14:22:01 +13:00
Jesse Hills 3290ab7f42 Merge pull request #6440 from esphome/bump-2024.3.1
2024.3.1
2024-03-27 14:14:45 +13:00
Mafus1 94e9476838 Add new Component: Ultrasonic Distance Sensor JSN-SR04T (#6023)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-27 14:14:23 +13:00
Ben Kristinsson 58de8a4ee6 Add get_contrast() and get_brightness() to SSD1306 class to get protected variables (#6435) 2024-03-27 14:13:41 +13:00
Keith Burzinski 0948a3c306 Add some components to the new testing framework (F) (#6177)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-27 14:06:57 +13:00
Jesse Hills 4d30c81b0b Bump version to 2024.3.1 2024-03-27 12:17:31 +13:00
J. Nick Koston f00d876080 Fix editor live validation (#6431) 2024-03-27 12:17:30 +13:00
Gábor Poczkodi d304e52940 Don't compile strptime unless its required (#6424) 2024-03-27 12:17:30 +13:00
ebw44 7abb82c1ca microWakeWord: Fix model path joining (#6426) 2024-03-27 12:17:30 +13:00
Clyde Stubbs 37345e11eb AHT10: Fix bug (#6409) 2024-03-27 12:17:30 +13:00
X-Ryl669 952ccf554b Add support for AT581x component (#6297)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-27 11:51:56 +13:00
J. Nick Koston 2345e7606a Fix editor live validation (#6431) 2024-03-26 20:24:58 +13:00
Gábor Poczkodi 7cb8f99884 Don't compile strptime unless its required (#6424) 2024-03-26 11:34:47 +13:00
ebw44 f5ac1bd905 microWakeWord: Fix model path joining (#6426) 2024-03-26 11:20:15 +13:00
Clyde Stubbs 121bd84854 Store preferences in disk file on host platform (#6428)
Co-authored-by: H. Árkosi Róbert <robreg@zsurob.hu>
Co-authored-by: clydeps <U5yx99dok9>
2024-03-26 11:03:51 +13:00
Clyde Stubbs e87727aed3 AHT10: Fix bug (#6409) 2024-03-25 11:44:05 +13:00
Martin Weinelt 2997964b72 setup.cfg: drop duplicate, underintended trove classifier (#6421) 2024-03-25 11:41:53 +13:00
Simone Rossetto bd8f9db037 WireGuard for esp8266 (#6365) 2024-03-25 11:21:04 +13:00
Clyde Stubbs 3801462589 Add check for use of GPIOXX in config (#6419) 2024-03-22 21:32:37 +13:00
dependabot[bot] a3b0ddf686 Bump aioesphomeapi from 23.1.1 to 23.2.0 (#6412)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-21 16:31:20 +13:00
Clyde Stubbs d0ced3471e SPI: Make some validation failures give more useful messages. (#6413) 2024-03-21 16:25:11 +13:00
Mat931 1d6f245ced Add sun_gtil2 component (for SUN-1000G2 / SUN-2000G2 grid tie inverters) (#4958)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-21 16:23:30 +13:00
Moriah Morgan 13059805d0 Add support for new modes in Tuya Climate (#5159)
* Add support support for new modes

Added support for Fan Only Mode, Dry Mode, Swing Mode and Fan Speed Control.

Also added/fixed support for entity states syncing with current operation mode.

* Add support for more climate modes in climate.tuya

Added support for Fan Only Mode, Dry Mode, Swing Mode and Fan Speed Control.

Also added/fixed support for entity states syncing with current operation mode.

This commit fixes the namespace, because I uploaded the test files to start with.

* Code Formatting Changes per Clang format.

* More clang formatting fixes.

* Breaking Change: Group YAML entries by type

Add grouping to Preset, Swing Mode, Fan Speed and Active State. This is a breaking change.

* Formatting Changes for validation

Formatting changes to be compliant with black and flake8. Also changed constants to match expected format.

* More constant value fixes

* Final black formatting check?

* Changes to init.py according to reviewer requests

Make changes to _init_.py according to https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278620976, https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278621039, https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278620904, and https://github.com/esphome/esphome/pull/5159/files/649b923804c05fa6ee750e824e3d7d70fadeabd9#r1278620549

Also put Sleep preset in its own config block to be consistent with other presets and fix logic for validate_cooling_values function to better align with existing documentation.

* Commit reviewed change

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

* update deprecated config option wording

* add "this->" to member variables that were missed

adding "this->" to some member variables in the swing_mode function.

* Update _init_.py to use Python 3.8 Walrus operator

Adding Walrus Operator in the to_code function for _init_.py similar to https://github.com/esphome/esphome/pull/5181

* Fix Temperature_Multiplier config entry for code generation

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-03-20 19:40:14 -05:00
DAVe3283 b637fb3adc Fix logger compile error on ESP32-C6 (#6323) 2024-03-21 12:57:27 +13:00
Clyde Stubbs 0cb1cc9e1c AHT10: fix temperature-only operation; add warning/error messages (#6405) 2024-03-20 21:20:42 +13:00
Jasper Albering 98466cb7f5 sm2135: add separate_modes option to support different chip variants (#6152) 2024-03-20 21:17:59 +13:00
Gagootron b0db7319f9 Allow setting htop for ledc (#6340) 2024-03-20 21:17:32 +13:00
cvwillegen b95a7f6438 Allow accept/reject delta to be specified. (#5060) 2024-03-20 21:16:52 +13:00
Jimmy Hedman 7d9fc3ceaa Bump ESP8266 Arduino versions (#5359) 2024-03-20 21:16:10 +13:00
dependabot[bot] b12ccd460b Bump actions/cache from 4.0.1 to 4.0.2 (#6404)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 21:15:03 +13:00
dependabot[bot] bdb6881cd5 Bump actions/cache from 4.0.1 to 4.0.2 in /.github/actions/restore-python (#6403)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 21:14:52 +13:00
dependabot[bot] afbaf56c0b Bump pytest-asyncio from 0.23.5.post1 to 0.23.6 (#6402)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 21:14:15 +13:00
Jesse Hills ce5a323f91 Merge pull request #6408 from esphome/bump-2024.3.0
2024.3.0
2024-03-20 18:30:49 +13:00
Jesse Hills 9541df9d88 Bump version to 2024.3.0 2024-03-20 17:15:19 +13:00
Jesse Hills be15122e8b Merge pull request #6407 from esphome/bump-2024.3.0b5
2024.3.0b5
2024-03-20 17:11:24 +13:00
Jesse Hills 6f7273d9cb Bump version to 2024.3.0b5 2024-03-20 16:38:15 +13:00
RFDarter ccca545862 web_server support for v3 (#6203) 2024-03-20 16:38:15 +13:00
Clyde Stubbs e27e342927 Show component warnings and errors in the log; (#6400) 2024-03-20 16:38:15 +13:00
Clyde Stubbs 507568db64 AHT10: Use state machine to avoid blocking delay (#6401) 2024-03-20 16:38:15 +13:00
RFDarter 7e8e658999 web_server support for v3 (#6203) 2024-03-20 16:37:18 +13:00
Clyde Stubbs 774cbde1b6 Show component warnings and errors in the log; (#6400) 2024-03-20 12:56:43 +13:00
Clyde Stubbs f0936dd22d AHT10: Use state machine to avoid blocking delay (#6401) 2024-03-20 12:53:01 +13:00
Keith Burzinski af3fb615ea Fix esp32-camera test yaml (#6398)
* Fix esp32-camera test yaml

* Fix esp32-camera test yaml, take 2
2024-03-19 00:18:03 -05:00
Jimmy Hedman 19022ace12 Make SPI compile with IDF >= 5.0 (#6383)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-03-19 15:56:36 +13:00
Jesse Hills 156d2c04f9 Merge pull request #6397 from esphome/bump-2024.3.0b4
2024.3.0b4
2024-03-19 15:37:30 +13:00
Jesse Hills 855b1fd706 Bump version to 2024.3.0b4 2024-03-19 14:22:28 +13:00
Jesse Hills c56c40cb82 Require xsrf/csrf when using a password (#6396) 2024-03-19 14:22:28 +13:00
Mike La Spina a3bd8ad025 ld2420: Firmware v1.5.4+ bug workaround (#6168) 2024-03-19 14:22:28 +13:00
Stefan Rado db1b187e80 Fix wrong initialization of vectors in ade7953_i2c (#6393) 2024-03-19 14:22:28 +13:00
Stefan Rado 9442f7a271 Fix sending packets to uponor_smatrix devices (#6392) 2024-03-19 14:22:28 +13:00
swoboda1337 b3aa950c60 Fix bug in remote_base conditional (#6281)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
2024-03-19 14:22:28 +13:00
Jesse Hills 9b7438a56d Require xsrf/csrf when using a password (#6396) 2024-03-19 13:39:01 +13:00
Keith Burzinski 61f11386a9 Add some components to the new testing framework (E) (#6176) 2024-03-19 12:52:40 +13:00
Keith Burzinski 95443a4354 Add some components to the new testing framework (X,Y,Z) (#6233) 2024-03-19 12:49:00 +13:00
Keith Burzinski d5a8bea8e9 Add some components to the new testing framework (V) (#6231) 2024-03-19 10:42:03 +13:00
Keith Burzinski cb731926be Add actions for component tests A, B and C (#6256) 2024-03-19 10:00:06 +13:00
Andres Vahter f5695733bc ld2420: fix energy mode documentation (#6225) 2024-03-19 07:28:15 +13:00
Mike La Spina d692b5404c ld2420: Firmware v1.5.4+ bug workaround (#6168) 2024-03-19 07:26:39 +13:00
Jesse Hills e7fe2a2816 Check generated proto files are as expected if any are modified in PRs (#6254) 2024-03-19 07:15:52 +13:00
Stefan Rado 55677bb68e Fix wrong initialization of vectors in ade7953_i2c (#6393) 2024-03-19 07:06:17 +13:00
Stefan Rado 1e5dc15972 Fix sending packets to uponor_smatrix devices (#6392) 2024-03-19 07:04:53 +13:00
swoboda1337 f3f7bdc4e1 Fix bug in remote_base conditional (#6281)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
2024-03-18 19:35:06 +13:00
Jesse Hills dccad040f9 Merge pull request #6390 from esphome/bump-2024.3.0b3
2024.3.0b3
2024-03-18 19:34:58 +13:00
Jesse Hills 8a8bfe01c7 Bump version to 2024.3.0b3 2024-03-18 15:54:39 +13:00
Jesse Hills 690a7d46ce Replace name and friendly name in full adopted configs (#4456) 2024-03-18 15:54:39 +13:00
Jimmy Hedman 4429e5ae56 IPv6 can't be enabled for libretiny (#6387) 2024-03-18 15:54:39 +13:00
Edward Firmo 22f427165f Shows component operation time in ms (#6388)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-18 15:54:39 +13:00
Stefan Rado 3908a9ce9d Fix compilation for uponor_smatrix without time component (#6389)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-18 15:54:39 +13:00
Kevin Ahrendt 9e378189c3 microWakeWord - add new ops and small improvements (#6360) 2024-03-18 15:54:39 +13:00
Samuel Sieb d121fa5d05 allow negative ppm for sensair (#6385) 2024-03-18 15:54:39 +13:00
Jesse Hills 4de58559c6 Fix list-components when PR is not targeting dev (#6375) 2024-03-18 15:54:38 +13:00
Federico G. Schwindt a5553827f1 Use AQI device class (#6376) 2024-03-18 15:54:38 +13:00
Jesse Hills 687553a285 Replace name and friendly name in full adopted configs (#4456) 2024-03-18 13:00:59 +13:00
Daniel Eisterhold 8fd10d6859 Add line_at_angle method to Display component (#6381) 2024-03-18 12:51:46 +13:00
Jimmy Hedman 72c6563a3b IPv6 can't be enabled for libretiny (#6387) 2024-03-18 10:06:02 +13:00
Edward Firmo 0b9a022ef6 Shows component operation time in ms (#6388)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-18 10:01:25 +13:00
Stefan Rado c24946e09f Fix compilation for uponor_smatrix without time component (#6389)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-18 10:00:07 +13:00
Kevin Ahrendt 9f121e6016 microWakeWord - add new ops and small improvements (#6360) 2024-03-18 08:13:55 +13:00
Samuel Sieb 23f8498ff9 allow negative ppm for sensair (#6385) 2024-03-18 08:10:47 +13:00
Edward Firmo e753ac3a97 Fix Nextion set_component_picture call (#6378)
This fixes the call to the Nextion display to change the pic id from a component.
It was previously changing the attribute `val`, which is related to something else.
In addition, I've changed the parameter for picture_id to be uint_8, as Nextion requires an integer from 0 to 255 on this attribute.
2024-03-16 00:19:25 -05:00
Keith Burzinski 4f59b14ab0 Fix keeloq for IDF 5+ (#6382) 2024-03-16 05:18:51 +00:00
Jesse Hills 1148d41a66 Fix list-components when PR is not targeting dev (#6375) 2024-03-16 14:22:34 +13:00
Federico G. Schwindt 5d96b5c52b Use AQI device class (#6376) 2024-03-16 14:21:44 +13:00
Federico Ferretti 6e8760eba0 Fix deep_sleep for ESP32-C6 (#6377) 2024-03-16 14:17:01 +13:00
Jesse Hills 4180eae68f Merge pull request #6374 from esphome/bump-2024.3.0b2
2024.3.0b2
2024-03-15 17:06:14 +13:00
Jesse Hills 83cc7b9d48 Bump version to 2024.3.0b2 2024-03-15 14:23:12 +13:00
Jimmy Hedman ca85a41a72 Don't try to get IPv6 addresses when disabled (#6366) 2024-03-15 14:23:12 +13:00
Samuel Sieb 92fbc61c46 fix servo restore (#6370) 2024-03-15 14:23:12 +13:00
Attila Farago 76c4bfbed3 Allow button press action in web_server to be executed via GET method (#5938) 2024-03-15 14:23:12 +13:00
Clyde Stubbs e33e09a685 SPI: Revert clk_pin to standard output pin schema (#6368) 2024-03-15 14:23:12 +13:00
dependabot[bot] e42ab71029 Bump docker/setup-buildx-action from 3.1.0 to 3.2.0 (#6372)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 12:42:38 +13:00
dependabot[bot] b7af94c76f Bump docker/build-push-action from 5.2.0 to 5.3.0 in /.github/actions/build-image (#6373)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 12:39:32 +13:00
Jimmy Hedman 4e850c3f32 Don't try to get IPv6 addresses when disabled (#6366) 2024-03-15 09:26:29 +13:00
Samuel Sieb d3842a7ab4 fix servo restore (#6370) 2024-03-13 22:08:57 -07:00
dependabot[bot] fa4adb61f4 Bump peter-evans/create-pull-request from 6.0.1 to 6.0.2 (#6361)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 17:28:05 +13:00
dependabot[bot] 72d1fa67fa Bump docker/login-action from 3.0.0 to 3.1.0 (#6367)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 17:26:10 +13:00
Attila Farago df5dfb8087 Allow button press action in web_server to be executed via GET method (#5938) 2024-03-14 15:56:17 +13:00
Clyde Stubbs dbf50381f1 SPI: Revert clk_pin to standard output pin schema (#6368) 2024-03-14 15:42:54 +13:00
Jesse Hills c4f4d25041 Merge pull request #6364 from esphome/bump-2024.3.0b1
2024.3.0b1
2024-03-13 17:28:50 +13:00
Jesse Hills bbf7e2be28 Bump version to 2024.4.0-dev 2024-03-13 16:33:43 +13:00
Jesse Hills 0ebb6efee6 Bump version to 2024.3.0b1 2024-03-13 16:33:42 +13:00
Jesse Hills a7fec07bc4 Merge branch 'release' into dev 2024-03-13 16:31:57 +13:00
kev300 de43678525 add possibility to provide different conversion times for Bus Voltage… (#6327)
Co-authored-by: Kevin Hübner <k.huebner@ceyoniq.com>
2024-03-13 16:25:38 +13:00
Chris Feenstra 64a47f840e Added Kamstrup Multical 40x component (#4200)
Co-authored-by: Chris Feenstra <chris@cfeenstra.nl>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: cfeenstra1024 <git@cfeenstra.nl>
2024-03-13 16:01:22 +13:00
Ettore Beltrame b34b10888b Emmeti infrared climate support (#5197)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-13 14:16:02 +13:00
Mark Spicer 3abf2f1d14 feat: Add HTU31D Support (#5805)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-13 14:04:59 +13:00
Sorin Iordachescu 77214a677b ADE7953: Add the ability to use accumulating energy registers, more precise power reporting (#6311)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-13 12:17:06 +13:00
Clyde Stubbs c7305e15a7 Add driver for quad SPI AMOLED displays (#6354)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-13 12:14:57 +13:00
Landon Rohatensky 2df9c30446 download font from url on build (#5254)
Co-authored-by: guillempages <guillempages@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
2024-03-13 12:07:40 +13:00
M-A d3a028f7fa Make USE_HOST compilable on msys2 (#6359) 2024-03-13 07:22:28 +11:00
Clyde Stubbs f264151537 touchscreen driver fixes (#6356) 2024-03-13 07:20:16 +13:00
Manuel Kasper f5b02056b9 Require reset_pin for certain waveshare_epaper models in YAML validation (#6357) 2024-03-12 21:35:29 +11:00
Clyde Stubbs b0a192d6a5 Add getter for font glyph data (#6355) 2024-03-12 17:26:31 +13:00
Citric Lee 4bbde8357a Add Seeed Studio mmWave Kit MR24HPC1 (#5761)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Peter Pan <twinkle-pirate@hotmail.com>
2024-03-12 16:33:40 +13:00
Anton Viktorov 5b28bd3d97 VEML7700 and VEML6030 light sensors (#6067)
* VEML7700 and VEML6030 light sensors

* VEML7700 and VEML6030 light sensors - CODEOWNERS

* VEML7700 and VEML6030 light sensors - tidy up

* VEML7700 and VEML6030 light sensors - tidy up

* VEML7700 tidy up

* VEML7700 tidy up 4

* VEML7700 tidying up more

* VEML7700 after review. non-blocking approach

* VEML7700 CONSTANT_CASE

* VEML7700 merge fix

* VEML7700 pragma pack changed to attribute

* VEML7700 pragma pack -> attribute

* Minor publish split

* minor

* LOGD->LOGV

* new school tests added

* Discard changes to tests/test1.yaml

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-03-11 21:51:01 -05:00
Clyde Stubbs 782d662c20 SPI schema now uses typed_schema with type key (#6353) 2024-03-12 15:50:24 +13:00
mrtoy-me 51ab15c40e hydreon_rgxx - add resolution option (#6077)
Co-authored-by: functionpointer <suspendfunction@gmail.com>
2024-03-12 15:31:58 +13:00
Clyde Stubbs 1dd14254b3 Drivers for RGB 16 bit parallel displays (#5872)
Co-authored-by: clydebarrow <366188+clydebarrow@users.noreply.github.com>
2024-03-12 11:55:23 +13:00
RubyBailey 8cb689b58c Mitsubishi Climate updates (#3886)
Co-authored-by: Blair McBride <blair@theunfocused.net>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: RubyBailey <ruby_bailey11@hotmail.com>
Co-authored-by: X-Ryl669 <boite.pour.spam@gmail.com>
Co-authored-by: OlympusMonds <OlympusMonds@users.noreply.github.com>
2024-03-12 10:01:05 +13:00
Manuel Kasper a96762220a Add support for Waveshare 2.13" V2 display (#6337)
* Add support for Waveshare 2.13" V2 display

* Fix clang-tidy error, add comment about BUSY in deep sleep

* Add test

* Add nullptr check and move tests to separate file

* Fix GPIO pins in test
2024-03-12 05:38:59 +11:00
dependabot[bot] 32be12423a Bump pytest from 8.0.2 to 8.1.1 (#6346)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 07:25:19 +13:00
dependabot[bot] 0ecd938570 Bump aioesphomeapi from 23.1.0 to 23.1.1 (#6348)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 07:25:11 +13:00
Mike La Spina cd89c38a07 Refactor ATM90E32 to reduce blocking time and improve accuracy. (#5670)
Co-authored-by: descipher <120155735+GelidusResearch@users.noreply.github.com>
2024-03-12 07:23:13 +13:00
Fabio Pugliese Ornellas 430ee43b93 Mhz19 warmup (#6214) 2024-03-12 07:17:47 +13:00
Clyde Stubbs e4df422798 font: add anti-aliasing and other features (#6198)
* Pack glyph bits

* Use unsigned chars for unicode strings.

* Implement multi-bit glyphs

* clang-format

* Allow extra glyphs to be added to a font

* Allow .otf and .woff file extensions

* Add printf versions with background color;
Add tests

* Whitespace...

* Move font test to new framework

* CI fix

* CI fix

* CODEOWNERS

* File extensions tested as case-insensitive
2024-03-11 04:03:39 -05:00
Clyde Stubbs 11b31483c3 Touchscreen: add support for CST226 controller chip (#6151)
---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 18:35:20 +11:00
Clyde Stubbs 221f04b9a5 ili9xxx: Add support for GC9A01A display (#6351)
* Add support for GCA901A display


---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 07:19:35 +00:00
Clyde Stubbs dfb14fc6ea Add state listeners to rotary_encoder (#6035) 2024-03-11 20:13:41 +13:00
Clyde Stubbs 501973e07b Add ble_presence binary sensor timeout config value. (#6024)
* Add binary sensor timeout config value.

* Add test
2024-03-11 17:38:47 +11:00
swoboda1337 1662f833b0 AM2315C Temperature + Humidity Sensor (#6266)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 19:33:43 +13:00
Clyde Stubbs c559ccbb83 ILI9XXX: Lazily allocate buffer (#6352) 2024-03-11 16:52:05 +11:00
Clyde Stubbs d6bcc465a8 Add CST816 touchscreen driver (#5941)
* Add CST816 touchscreen
2024-03-11 16:34:46 +11:00
OdileVidrine 9c95e570c7 Check permissions (#6255) 2024-03-11 13:33:31 +13:00
Rodrigo Martín 6a8a2aaefb feat(MQTT): Add QoS option for each MQTT component (#6279) 2024-03-11 13:12:52 +13:00
dentra c899a33d1a web_server_idf: support x-www-form-urlencoded POST requests (#6037)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 13:09:36 +13:00
NP v/d Spek 725b0c81e8 cleanup ili9xxx component by removing data rate define (#6350) 2024-03-10 23:38:40 +00:00
alexborro 8850b959e9 [Fingerprint_grow] Implements Sleep Mode feature (#6116) 2024-03-11 12:04:16 +13:00
chbmuc 247baa414a Add IRK support to allow tracking of devices with random MAC addresses (#6335)
* Add IRK support to allow tracking of devices with random MAC addresses

* make CONF_IRK a local definition

* Add tests

---------

Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
2024-03-10 22:58:50 +00:00
tomaszduda23 d4489ac373 dump config after logging CDC port is opened by host (#6169) 2024-03-11 11:43:33 +13:00
Samuel Sieb 6a46548a8b add template fan (#6310) 2024-03-10 15:42:02 -07:00
NewoPL 0cdd0b295e fix: modbus_textsensor response is too long in some cases (#6333) 2024-03-11 11:15:32 +13:00
dependabot[bot] 3e2ce363a2 Bump docker/build-push-action from 5.0.0 to 5.2.0 in /.github/actions/build-image (#6347) 2024-03-11 11:11:42 +13:00
dependabot[bot] db813bbf04 Bump actions/cache from 4.0.0 to 4.0.1 (#6306)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 11:09:40 +13:00
Solomon c52052563f ads1118 component (#5711)
Co-authored-by: Solomon <solomon.gorkhover@finnpartners.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 11:09:05 +13:00
Jesse Hills 89b3bc7d70 Set dependabot to look at composite actions versions (#6343) 2024-03-11 10:36:44 +13:00
dependabot[bot] 1253583c2d Bump docker/setup-buildx-action from 3.0.0 to 3.1.0 (#6295)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 10:22:31 +13:00
dependabot[bot] 732fcc16f3 Bump pytest-asyncio from 0.23.5 to 0.23.5.post1 (#6334)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 10:21:39 +13:00
dependabot[bot] 5015436295 Bump aioesphomeapi from 23.0.0 to 23.1.0 (#6332)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 10:20:53 +13:00
Dmitry fc0d5abc54 Add AGS10 Sensor (#6070) 2024-03-11 10:19:09 +13:00
RFDarter 1e96a19d09 Add datetime date entities (#6191)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-11 07:52:22 +13:00
rafalw 4ec2b37cc6 Update bang_bang to log two decimal places in config dump (#6304)
change of precision to two decimal places
2024-03-09 21:14:57 -06:00
Clyde Stubbs 0bc645ded7 Fix build failures on host platform caused by #6167 (#6338)
* Fix build failures for logger component on host platform

* Add climits header

* Restore logger functionality on host

* Install libsodium in ci
2024-03-09 21:08:58 -06:00
sandronidi 90f416bd0d DFPlayer: refix Bug created with PR 4758 (#5861) 2024-03-08 23:16:21 -03:00
Jimmy Hedman 13736b5c57 Update mDNS for IDF >= 5.0 (#6328) 2024-03-07 11:26:39 +13:00
Jesse Hills 833affc1bf Merge pull request #6326 from esphome/bump-2024.2.2
2024.2.2
2024-03-06 10:28:28 +13:00
Jesse Hills e2b197dc2c Bump version to 2024.2.2 2024-03-06 09:34:48 +13:00
Jesse Hills f39dc49f49 Add wake word phrase to voice assistant start command (#6290) 2024-03-06 09:34:47 +13:00
Samuel Sieb b0a25401f7 auto load output for now (#6309)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-03-06 09:34:47 +13:00
Jesse Hills 37d2b3c797 Merge pull request from GHSA-9p43-hj5j-96h5 2024-03-06 09:34:26 +13:00
Samuel Sieb 63cce916e2 fix tmp102 negative calculation (#6320) 2024-03-06 09:34:08 +13:00
星野SKY 1aab87b41c handling with the negative temperature in the sensor tmp102 (#6316) 2024-03-06 09:33:55 +13:00
puuu a3fc1acdcb CSE7766: Fix energy calculation (#6286)
Co-authored-by: DAVe3283 <DAVe3283+GitHub@gmail.com>
2024-03-06 09:32:23 +13:00
Jesse Hills b3ff23ec76 Merge pull request from GHSA-9p43-hj5j-96h5 2024-03-06 08:09:45 +13:00
Jesse Hills 01fc0578bd Add wake word phrase to voice assistant start command (#6290) 2024-03-06 07:41:18 +13:00
Samuel Sieb 96446446b2 auto load output for now (#6309)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-03-06 07:40:27 +13:00
Jesse Hills 357ac3b85f Improv: support connecting to hidden networks (#6322) 2024-03-05 13:02:05 +13:00
Nate Clark 626221c5a8 Add toggle command to cover web_server endpoint (#6319) 2024-03-05 10:55:10 +13:00
Pavlo Dudnytskyi 81b8451b8a Additional sensors and binary sensors support for Haier Climate (#6257)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Pavlo Dudnytskyi <pdudnytskyi@astrata.eu>
2024-03-05 10:54:01 +13:00
tomaszduda23 de2d5a65b5 Separate logger implementations for each hardware platform into different files (#6167)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-03-05 10:52:52 +13:00
Dan Jackson d5bfcd3bcf Support for MS8607 PHT (Pressure Humidity Temperature) sensor (#3307)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-05 10:49:57 +13:00
Andy Barcinski f3ed091395 x9c: fix off by 1 error (#6318) 2024-03-05 09:18:18 +13:00
Samuel Sieb 56837b0947 fix tmp102 negative calculation (#6320) 2024-03-04 07:33:39 +00:00
星野SKY bc74dd4980 handling with the negative temperature in the sensor tmp102 (#6316) 2024-03-04 14:02:40 +13:00
CptSkippy 0298adb1d8 aht10: Added new CMD and renamed existing CMD to match datasheet (#6303) 2024-03-04 09:00:18 +13:00
星野SKY 11cae03769 Fix return value in core/automation.h (#6314) 2024-03-01 23:53:12 -06:00
mathieu-mp 4aeb8e8081 Add regular polygon shapes to display component (#6108) 2024-03-01 16:49:26 +13:00
dependabot[bot] 082e76131b Bump aioesphomeapi from 22.0.0 to 23.0.0 (#6293)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 16:47:18 +13:00
Jimmy Hedman cf7cc179fb Fix numbering of sensors (#6305) 2024-03-01 14:02:33 +13:00
Jeroen van Oort 4a9d7771fe Adding W5500 support to ethernet component (#4424)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-03-01 13:46:08 +13:00
DAVe3283 f53f91e191 CSE7766 Apparent Power & Power Factor calculations (#6292) 2024-02-29 10:12:02 +13:00
dependabot[bot] ad7866b80e Bump peter-evans/create-pull-request from 6.0.0 to 6.0.1 (#6302)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-29 09:55:30 +13:00
Jesse Hills 3c651f4091 Add on_update trigger for Project versions (#6298) 2024-02-28 02:01:56 -06:00
NP v/d Spek 5393a09872 Touchscreen component and driver fixes (#5997)
* Introduce calibration settings for all touchscreen drivers.
this will override the common values.
The x,y coordinates only calculated when the right calibrations are set.

* resolve issues reported by CI

* remove unneeded spaces and newlines

* Forgot to remove some obsolete code

* remove get_setup_priority from xpt2046

* remove media_player changes.

* media_player: removed to much,

* Update suggestions

* referd back the `get_setup_priority` removal so it can be moved into a othe PR.

* tt21100: restore init read

* fix spacing

* load native display dimensions instead of using internal dimensons.
and load it only onse on setup

* moved `update_touches()` to protexted section

* adding Clydes PR#6049

* add multitouch test script

* Update all Touchscreen replacing `get_*_internal` to `get_native_*`

* fixed some CI recomendations

* couple of fixes

* make sure the display is running before  touchscreen is setup

* fix clang

* revert back last changes

* xpt2046: change log level for testing

* logging information

* add test file

* fix polling issue with the for example the xpt2046

* fixed some CI issues

* fixed some CI issues

* restore mirror parameter discriptions

* same for the swap_xy

* same for the transform

* remove the above const from const.py

* and put  the above const bacl const.py

* Merge branch 'nvds-touchscreen-fix1' of https://github.com/nielsnl68/esphome into nvds-touchscreen-fix1

* and put  the above const bacl const.py

* [tt21100] making interupt pin optional

* [tt21100] making interupt pin optional (now complete)

* update the display part based on @clyde'
s changes.

* fix issue with ft6x36 touvhscreen

* reverd back touch check. add comment

* add some extra checks to the ft6x36

* add an other log and a typo fixed

* okay an other fix.

* add an extra check like others do
and fix data type

* [ft6336] fix update race when ts is touched.

* [touchscreen] update some log's with a verbose level.

* fix clang issues

* fix the clang issues

* fix the clang issues

* fix virtual issue.

* fix the clang issues

* an other clang issues

* remove anti-aliased fonts support. It does not belong here.

* remove anti-aliased fonts support. It does not belong here.

* rename test script

* Moving the test files to there right location.

* rename the test files

* clean up the code

* add a new line

* clang fixings

* clang fixings

* remove comment

* remove comment

* Update esphome/components/touchscreen/__init__.py

Co-authored-by: guillempages <guillempages@users.noreply.github.com>

* Update esphome/components/touchscreen/__init__.py

Co-authored-by: guillempages <guillempages@users.noreply.github.com>

* Update esphome/components/touchscreen/__init__.py

Co-authored-by: guillempages <guillempages@users.noreply.github.com>

* Update esphome/components/touchscreen/touchscreen.cpp

* Update esphome/components/touchscreen/touchscreen.cpp

* [ft63x6] add threshold

---------

Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
Co-authored-by: guillempages <guillempages@users.noreply.github.com>
2024-02-28 02:42:11 +00:00
NP v/d Spek c43c9ad1c5 Add RTTTL volume control. (#5968)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-28 11:31:33 +13:00
Darek 37138d4f28 Waveshare e-ink 2IN9_V2 - fix full and partial update based on vendor SDK and examples (#5481)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2024-02-28 07:29:56 +11:00
Jimmy Hedman f73518dbeb Improve dualstack and IPv6 support (#5449)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-27 21:16:20 +13:00
dependabot[bot] 5e04914a11 Bump pytest from 8.0.1 to 8.0.2 (#6288)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 16:49:33 +13:00
puuu 9b77f97d87 CSE7766: Fix energy calculation (#6286)
Co-authored-by: DAVe3283 <DAVe3283+GitHub@gmail.com>
2024-02-27 16:47:45 +13:00
dougiteixeira 323849c821 Add device class support to text sensor (#6202)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-26 11:29:39 +13:00
Alexander Puzynia a8ab745479 Allow to specify global build directory (#6276) 2024-02-26 11:26:08 +13:00
Jesse Hills cc115e7cc9 Merge pull request #6284 from esphome/bump-2024.2.1
2024.2.1
2024-02-26 09:04:36 +13:00
Jesse Hills badac933ae Bump version to 2024.2.1 2024-02-26 07:52:25 +13:00
Keith Burzinski b1b8217713 Fix thermostat supplemental actions (#6282) 2024-02-26 07:52:25 +13:00
Samuel Sieb f3174c58bc fix throttle average nan handling (#6275)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-02-26 07:52:25 +13:00
Samuel Sieb e66e135a63 make output optional for speed fan (#6274)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-02-26 07:52:25 +13:00
Jesse Hills d814ed1d4a Merge pull request from GHSA-8p25-3q46-8q2p 2024-02-26 07:52:08 +13:00
J. Nick Koston 84c6e52be2 dashboard: move storage json update to a background task in edit save (#6280)
* dashboard: move storage json update to a background task in edit save

* dashboard: move storage json update to a background task in edit save

* fix typing

* docs
2024-02-26 07:50:28 +13:00
Keith Burzinski 2cf6393161 Fix RP2040 SPI pin validation (#6277) 2024-02-26 07:47:24 +13:00
Samuel Sieb 5a7759f1c4 allow multiple emc2101 (#6272) 2024-02-26 07:47:24 +13:00
Daniel Baulig db5205931b web_server: Add a position property for cover entities that have the supports position trait (#6269) 2024-02-26 07:47:24 +13:00
Jesse Hills 62d59cffcc Bump zeroconf timeout to 3000 (#6270) 2024-02-26 07:47:24 +13:00
Jesse Hills 2e7129e816 Add missing timeout to "async_request" (#6267) 2024-02-26 07:47:24 +13:00
Keith Burzinski b5e633a2f3 Fix test_build_components for macOS sed (#6278) 2024-02-26 07:37:35 +13:00
Keith Burzinski 4a3627c93e Fix thermostat supplemental actions (#6282) 2024-02-26 07:28:52 +13:00
Samuel Sieb 77916d051e fix throttle average nan handling (#6275)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-02-26 07:26:35 +13:00
Samuel Sieb 98552a0eaa make output optional for speed fan (#6274)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-02-26 07:23:01 +13:00
J. Nick Koston 83a1fc5fdb dashboard: move storage json update to a background task in edit save (#6280)
* dashboard: move storage json update to a background task in edit save

* dashboard: move storage json update to a background task in edit save

* fix typing

* docs
2024-02-24 23:39:47 -05:00
Keith Burzinski 4a54af0d57 Fix RP2040 SPI pin validation (#6277) 2024-02-24 00:31:20 -06:00
Samuel Sieb 15af08f6b7 allow multiple emc2101 (#6272) 2024-02-22 20:17:10 -06:00
Jesse Hills a748610071 Merge pull request from GHSA-8p25-3q46-8q2p 2024-02-23 07:38:24 +13:00
Stefan Rado 58c0d8c267 Add Uponor Smatrix component (#5769)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-22 16:03:14 +13:00
LouDou 76a3ffc8a9 Allow ESP8266 to use multiple i2c busses (#6145)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-22 14:51:05 +13:00
dependabot[bot] fd03d875e8 Bump aioesphomeapi from 21.0.2 to 22.0.0 (#6263)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 14:48:12 +13:00
Sybren A. Stüvel ea44166814 Improve the error message on OTA version mismatch (#6259) 2024-02-22 14:35:21 +13:00
Daniel Baulig 481f067625 web_server: Add a position property for cover entities that have the supports position trait (#6269) 2024-02-22 14:33:28 +13:00
Jesse Hills a3fa1e6c52 Bump zeroconf timeout to 3000 (#6270) 2024-02-22 14:26:00 +13:00
Jesse Hills 127cbde2a2 Add missing timeout to "async_request" (#6267) 2024-02-21 17:51:06 -06:00
Jesse Hills 75af4c3d62 Fix yamllint (#6253) 2024-02-21 17:14:30 +13:00
Stephen Tierney e847039ffd LTR390 - Multiple bugfixes (#6161) 2024-02-21 17:10:04 +13:00
dependabot[bot] d96090095a Bump pyupgrade from 3.15.0 to 3.15.1 (#6247)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-21 16:57:51 +13:00
dependabot[bot] 256d886d77 Bump voluptuous from 0.14.1 to 0.14.2 (#6181)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-21 16:57:38 +13:00
dependabot[bot] f4eb525c97 Bump frenck/action-yamllint from 1.4.2 to 1.5.0 (#6236)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 16:46:35 +13:00
dependabot[bot] f4552f5062 Bump peter-evans/create-pull-request from 5.0.2 to 6.0.0 (#6159)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 15:58:10 +13:00
dependabot[bot] 57f53a0f16 Bump codecov/codecov-action from 3 to 4 (#6160)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 15:56:28 +13:00
dependabot[bot] b75caf5ea7 Bump pytest from 7.4.4 to 8.0.1 (#6246)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 15:54:32 +13:00
dependabot[bot] 07c3ee75e5 Bump black from 23.12.1 to 24.2.0 (#6221)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2024-02-21 15:53:50 +13:00
Stephen Cox 4d8b5edb1c Provide example devcontainer config for mdns and USB passthrough (#6094) 2024-02-21 10:49:59 +13:00
sibowler 924389ba74 Tuya Fan component fix to handle enum datapoint type (#6135) 2024-02-21 10:40:17 +13:00
Michael Hansen 4b04df2f6b Voice Assistant: add on_idle trigger and fix nevermind (#6141) 2024-02-21 10:38:33 +13:00
SmartShackMaster 1f432ec7de Clear UART read buffer before sending next command (#6200) 2024-02-21 10:27:17 +13:00
Keith Burzinski 2948d87a66 Add some components to the new testing framework (D) (#6175) 2024-02-21 08:40:13 +13:00
Keith Burzinski 5ef1bab23e Fix tm1651 enum (#6248) 2024-02-21 08:12:08 +13:00
Kevin P. Fleming edd1678463 New component: ADE7880 voltage/current/power/energy sensor (#5242) 2024-02-20 12:24:44 +13:00
Samuel Sieb 5d144cff02 hold interrupt disable for dallas one-wire (#6244)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2024-02-20 08:13:12 +13:00
dependabot[bot] c39f6d0738 Bump pytest-asyncio from 0.23.3 to 0.23.5 (#6201)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 08:13:52 -06:00
Jesse Hills 967259a212 Fix xl9535 pin reads (#6242) 2024-02-19 03:44:18 +00:00
Carlos Ortega 342fb72b6a Prevent network config on rpipico board (#5832)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-02-19 14:29:41 +13:00
Anton Viktorov e1345ae7e3 INA226 - fixed improper work with signed values, added configurable ADC parameters (#6172) 2024-02-19 14:24:59 +13:00
Ivan Kravets 062db622f3 Adjust HeatpumpIR dependency (#6222) 2024-02-19 11:55:46 +13:00
Jesse Hills e3e670c084 Add optional minimum esphome version to microWakeWord manifest (#6240) 2024-02-19 11:52:37 +13:00
bisbastuner 142b33fc90 Add support for 1.8V-powered devices (#6234) 2024-02-19 07:44:24 +13:00
Marcel Hetzendorfer 8a52ba3ea3 WRGB Use correct multiplier (#6237) 2024-02-19 07:40:20 +13:00
marshn acbcb9d2be Fix to RF receiver for Drayton Digistat heating controller (#6235) 2024-02-19 07:38:32 +13:00
kahrendt db9d837d29 Add more debugging logs to microWakeWord (#6238) 2024-02-18 18:50:24 +13:00
Keith Burzinski 27a3a081c3 AUTO_LOAD sensor for shelly_dimmer (#6223) 2024-02-16 10:47:42 +13:00
Jesse Hills 7baf091d47 Bump openssh-client to 1:9.2p1-2+deb12u2 (#6216) 2024-02-13 14:29:54 +13:00
Jesse Hills 47d1a64894 Bump version to 2024.3.0-dev 2024-02-13 09:45:31 +13:00
3322 changed files with 87266 additions and 10471 deletions
+14 -1
View File
@@ -7,8 +7,21 @@
"PIP_BREAK_SYSTEM_PACKAGES": "1",
"PIP_ROOT_USER_ACTION": "ignore"
},
"runArgs": ["--privileged", "-e", "ESPHOME_DASHBOARD_USE_PING=1"],
"runArgs": [
"--privileged",
"-e",
"ESPHOME_DASHBOARD_USE_PING=1"
// uncomment and edit the path in order to pass though local USB serial to the conatiner
// , "--device=/dev/ttyACM0"
],
"appPort": 6052,
// if you are using avahi in the host device, uncomment these to allow the
// devcontainer to find devices via mdns
//"mounts": [
// "type=bind,source=/dev/bus/usb,target=/dev/bus/usb",
// "type=bind,source=/var/run/dbus,target=/var/run/dbus",
// "type=bind,source=/var/run/avahi-daemon/socket,target=/var/run/avahi-daemon/socket"
//],
"customizations": {
"vscode": {
"extensions": [
+16 -36
View File
@@ -1,20 +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
Topic :: Home Automation
[flake8]
max-line-length = 120
# Following 4 for black compatibility
@@ -38,25 +21,22 @@ max-line-length = 120
# D401 First line should be in imperative mood
ignore =
E501,
W503,
E203,
D202,
E501,
W503,
E203,
D202,
D100,
D101,
D102,
D103,
D104,
D105,
D107,
D200,
D205,
D209,
D400,
D401,
D100,
D101,
D102,
D103,
D104,
D105,
D107,
D200,
D205,
D209,
D400,
D401,
exclude = api_pb2.py
[bdist_wheel]
universal = 1
+14 -20
View File
@@ -34,16 +34,26 @@ runs:
echo $l >> $GITHUB_OUTPUT
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
id: build-ghcr
uses: docker/build-push-action@v5.0.0
uses: docker/build-push-action@v5.3.0
with:
context: .
file: ./docker/Dockerfile
platforms: ${{ inputs.platform }}
target: ${{ inputs.target }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-to: ${{ steps.cache-to.outputs.value }}
build-args: |
BASEIMGTYPE=${{ inputs.baseimg }}
BUILD_VERSION=${{ inputs.version }}
@@ -57,24 +67,16 @@ runs:
digest="${{ steps.build-ghcr.outputs.digest }}"
touch "/tmp/digests/${{ inputs.target }}/ghcr/${digest#sha256:}"
- name: Upload ghcr digest
uses: actions/upload-artifact@v3.1.3
with:
name: digests-${{ inputs.target }}-ghcr
path: /tmp/digests/${{ inputs.target }}/ghcr/*
if-no-files-found: error
retention-days: 1
- name: Build and push to dockerhub by digest
id: build-dockerhub
uses: docker/build-push-action@v5.0.0
uses: docker/build-push-action@v5.3.0
with:
context: .
file: ./docker/Dockerfile
platforms: ${{ inputs.platform }}
target: ${{ inputs.target }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-to: ${{ steps.cache-to.outputs.value }}
build-args: |
BASEIMGTYPE=${{ inputs.baseimg }}
BUILD_VERSION=${{ inputs.version }}
@@ -87,11 +89,3 @@ runs:
mkdir -p /tmp/digests/${{ inputs.target }}/dockerhub
digest="${{ steps.build-dockerhub.outputs.digest }}"
touch "/tmp/digests/${{ inputs.target }}/dockerhub/${digest#sha256:}"
- name: Upload dockerhub digest
uses: actions/upload-artifact@v3.1.3
with:
name: digests-${{ inputs.target }}-dockerhub
path: /tmp/digests/${{ inputs.target }}/dockerhub/*
if-no-files-found: error
retention-days: 1
+2 -2
View File
@@ -17,12 +17,12 @@ runs:
steps:
- name: Set up Python ${{ inputs.python-version }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@v3.3.2
uses: actions/cache/restore@v4.0.2
with:
path: venv
# yamllint disable-line rule:line-length
+10
View File
@@ -13,3 +13,13 @@ updates:
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/.github/actions/build-image"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/.github/actions/restore-python"
schedule:
interval: daily
open-pull-requests-limit: 10
+80
View File
@@ -0,0 +1,80 @@
name: API Proto CI
on:
pull_request:
paths:
- "esphome/components/api/api.proto"
- "esphome/components/api/api_pb2.cpp"
- "esphome/components/api/api_pb2.h"
- "esphome/components/api/api_pb2_service.cpp"
- "esphome/components/api/api_pb2_service.h"
- "script/api_protobuf/api_protobuf.py"
- ".github/workflows/ci-api-proto.yml"
permissions:
contents: read
pull-requests: write
jobs:
check:
name: Check generated files
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.1.6
- name: Set up Python
uses: actions/setup-python@v5.1.0
with:
python-version: "3.11"
- name: Install apt dependencies
run: |
sudo apt update
sudo apt-cache show protobuf-compiler
sudo apt install -y protobuf-compiler
protoc --version
- name: Install python dependencies
run: pip install aioesphomeapi -c requirements.txt -r requirements_dev.txt
- name: Generate files
run: script/api_protobuf/api_protobuf.py
- name: Check for changes
run: |
if ! git diff --quiet; then
echo "## Job Failed" | tee -a $GITHUB_STEP_SUMMARY
echo "You have altered the generated proto files but they do not match what is expected." | tee -a $GITHUB_STEP_SUMMARY
echo "Please run 'script/api_protobuf/api_protobuf.py' and commit the changes." | tee -a $GITHUB_STEP_SUMMARY
exit 1
fi
- if: failure()
name: Review PR
uses: actions/github-script@v7.0.1
with:
script: |
await github.rest.pulls.createReview({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
event: 'REQUEST_CHANGES',
body: 'You have altered the generated proto files but they do not match what is expected.\nPlease run "script/api_protobuf/api_protobuf.py" and commit the changes.'
})
- if: success()
name: Dismiss review
uses: actions/github-script@v7.0.1
with:
script: |
let reviews = await github.rest.pulls.listReviews({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});
for (let review of reviews.data) {
if (review.user.login === 'github-actions[bot]' && review.state === 'CHANGES_REQUESTED') {
await github.rest.pulls.dismissReview({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
review_id: review.id,
message: 'Files now match the expected proto files.'
});
}
}
+4 -4
View File
@@ -2,7 +2,7 @@
name: CI for docker images
# Only run when docker paths change
# yamllint disable-line rule:truthy
on:
push:
branches: [dev, beta, release]
@@ -40,13 +40,13 @@ jobs:
arch: [amd64, armv7, aarch64]
build_type: ["ha-addon", "docker", "lint"]
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4.1.6
- name: Set up Python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: "3.9"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
uses: docker/setup-buildx-action@v3.3.0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.0.0
+122 -32
View File
@@ -1,7 +1,6 @@
---
name: CI
# yamllint disable-line rule:truthy
on:
push:
branches: [dev, beta, release]
@@ -11,6 +10,8 @@ on:
- "**"
- "!.github/workflows/*.yml"
- ".github/workflows/ci.yml"
- "!.yamllint"
- "!.github/dependabot.yml"
merge_group:
permissions:
@@ -19,7 +20,6 @@ permissions:
env:
DEFAULT_PYTHON: "3.9"
PYUPGRADE_TARGET: "--py39-plus"
CLANG_FORMAT_VERSION: "13.0.1"
concurrency:
# yamllint disable-line rule:line-length
@@ -34,18 +34,18 @@ jobs:
cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Generate cache-key
id: cache-key
run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.0
uses: actions/cache@v4.0.2
with:
path: venv
# yamllint disable-line rule:line-length
@@ -66,7 +66,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -87,7 +87,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -108,7 +108,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -129,7 +129,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -150,7 +150,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -199,7 +199,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -218,7 +218,7 @@ jobs:
. venv/bin/activate
pytest -vv --cov-report=xml --tb=native tests
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
@@ -229,7 +229,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -238,7 +238,7 @@ jobs:
- name: Install clang-format
run: |
. venv/bin/activate
pip install clang-format==${{ env.CLANG_FORMAT_VERSION }}
pip install clang-format -c requirements_dev.txt
- name: Run clang-format
run: |
. venv/bin/activate
@@ -254,7 +254,7 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Find all YAML test files
id: set-matrix
run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
@@ -271,7 +271,7 @@ jobs:
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -303,7 +303,7 @@ jobs:
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -358,18 +358,26 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio
uses: actions/cache@v4.0.0
if: github.ref == 'refs/heads/dev'
uses: actions/cache@v4.0.2
with:
path: ~/.platformio
# yamllint disable-line rule:line-length
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
key: platformio-${{ matrix.pio_cache_key }}
- 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
run: sudo apt-get install clang-tidy-14
@@ -396,28 +404,42 @@ jobs:
runs-on: ubuntu-latest
needs:
- common
if: github.event_name == 'pull_request'
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
components: ${{ steps.list-components.outputs.components }}
count: ${{ steps.list-components.outputs.count }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
with:
# Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
fetch-depth: 500
- name: Fetch dev branch
- name: Get target branch
id: target-branch
run: |
git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/dev*:refs/remotes/origin/dev* +refs/tags/dev*:refs/tags/dev*
git merge-base refs/remotes/origin/dev HEAD
echo "branch=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT
- name: Fetch ${{ steps.target-branch.outputs.branch }} branch
run: |
git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +refs/heads/${{ steps.target-branch.outputs.branch }}:refs/remotes/origin/${{ steps.target-branch.outputs.branch }}
git merge-base refs/remotes/origin/${{ steps.target-branch.outputs.branch }} HEAD
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Find changed components
id: set-matrix
id: list-components
run: |
. venv/bin/activate
echo "matrix=$(script/list-components.py --changed | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
components=$(script/list-components.py --changed --branch ${{ steps.target-branch.outputs.branch }})
output_components=$(echo "$components" | jq -R -s -c 'split("\n")[:-1] | map(select(length > 0))')
count=$(echo "$output_components" | jq length)
echo "components=$output_components" >> $GITHUB_OUTPUT
echo "count=$count" >> $GITHUB_OUTPUT
echo "$count Components:"
echo "$output_components" | jq
test-build-components:
name: Component test ${{ matrix.file }}
@@ -425,15 +447,18 @@ jobs:
needs:
- common
- list-components
if: ${{ needs.list-components.outputs.matrix != '[]' && needs.list-components.outputs.matrix != '' }}
if: github.event_name == 'pull_request' && fromJSON(needs.list-components.outputs.count) > 0 && fromJSON(needs.list-components.outputs.count) < 100
strategy:
fail-fast: false
max-parallel: 2
matrix:
file: ${{ fromJson(needs.list-components.outputs.matrix) }}
file: ${{ fromJson(needs.list-components.outputs.components) }}
steps:
- name: Install libsodium
run: sudo apt-get install libsodium-dev
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -448,6 +473,64 @@ jobs:
. venv/bin/activate
./script/test_build_components -e compile -c ${{ matrix.file }}
test-build-components-splitter:
name: Split components for testing into 20 groups maximum
runs-on: ubuntu-latest
needs:
- common
- list-components
if: github.event_name == 'pull_request' && fromJSON(needs.list-components.outputs.count) >= 100
outputs:
matrix: ${{ steps.split.outputs.components }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Split components into 20 groups
id: split
run: |
components=$(echo '${{ needs.list-components.outputs.components }}' | jq -c '.[]' | shuf | jq -s -c '[_nwise(20) | join(" ")]')
echo "components=$components" >> $GITHUB_OUTPUT
test-build-components-split:
name: Test split components
runs-on: ubuntu-latest
needs:
- common
- list-components
- test-build-components-splitter
if: github.event_name == 'pull_request' && fromJSON(needs.list-components.outputs.count) >= 100
strategy:
fail-fast: false
max-parallel: 4
matrix:
components: ${{ fromJson(needs.test-build-components-splitter.outputs.matrix) }}
steps:
- name: List components
run: echo ${{ matrix.components }}
- name: Install libsodium
run: sudo apt-get install libsodium-dev
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Validate config
run: |
. venv/bin/activate
for component in ${{ matrix.components }}; do
./script/test_build_components -e config -c $component
done
- name: Compile config
run: |
. venv/bin/activate
for component in ${{ matrix.components }}; do
./script/test_build_components -e compile -c $component
done
ci-status:
name: CI Status
runs-on: ubuntu-latest
@@ -462,7 +545,10 @@ jobs:
- pyupgrade
- compile-tests
- clang-tidy
- list-components
- test-build-components
- test-build-components-splitter
- test-build-components-split
if: always()
steps:
- name: Success
@@ -470,4 +556,8 @@ jobs:
run: exit 0
- name: Failure
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
env:
JSON_DOC: ${{ toJSON(needs) }}
run: |
echo $JSON_DOC | jq
exit 1
-1
View File
@@ -1,7 +1,6 @@
---
name: Lock
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "30 0 * * *"
+58 -31
View File
@@ -1,7 +1,6 @@
---
name: Publish Release
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
release:
@@ -18,14 +17,16 @@ jobs:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.tag.outputs.tag }}
branch_build: ${{ steps.tag.outputs.branch_build }}
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4.1.6
- name: Get tag
id: tag
# yamllint disable rule:line-length
run: |
if [[ "$GITHUB_EVENT_NAME" = "release" ]]; then
TAG="${GITHUB_REF#refs/tags/}"
if [[ "${{ github.event_name }}" = "release" ]]; then
TAG="${{ github.event.release.tag_name}}"
BRANCH_BUILD="false"
else
TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
today="$(date --utc '+%Y%m%d')"
@@ -33,34 +34,38 @@ jobs:
BRANCH=${GITHUB_REF#refs/heads/}
if [[ "$BRANCH" != "dev" ]]; then
TAG="${TAG}-${BRANCH}"
BRANCH_BUILD="true"
else
BRANCH_BUILD="false"
fi
fi
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "branch_build=${BRANCH_BUILD}" >> $GITHUB_OUTPUT
# yamllint enable rule:line-length
deploy-pypi:
name: Build and publish to PyPi
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4.1.6
- name: Set up Python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: "3.x"
- name: Set up python environment
env:
ESPHOME_NO_VENV: 1
run: |
script/setup
pip install twine
run: script/setup
- name: Build
run: python setup.py sdist bdist_wheel
- name: Upload
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: twine upload dist/*
run: |-
pip3 install build
python3 -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@v1.8.14
deploy-docker:
name: Build ESPHome ${{ matrix.platform }}
@@ -78,25 +83,25 @@ jobs:
- linux/arm/v7
- linux/arm64
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4.1.6
- name: Set up Python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: "3.9"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
uses: docker/setup-buildx-action@v3.3.0
- name: Set up QEMU
if: matrix.platform != 'linux/amd64'
uses: docker/setup-qemu-action@v3.0.0
- name: Log in to docker hub
uses: docker/login-action@v3.0.0
uses: docker/login-action@v3.1.0
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry
uses: docker/login-action@v3.0.0
uses: docker/login-action@v3.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -129,6 +134,19 @@ jobs:
suffix: lint
version: ${{ needs.init.outputs.tag }}
- name: Sanitize platform name
id: sanitize
run: |
echo "${{ matrix.platform }}" | sed 's|/|-|g' > /tmp/platform
echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT
- name: Upload digests
uses: actions/upload-artifact@v4.3.3
with:
name: digests-${{ steps.sanitize.outputs.name }}
path: /tmp/digests
retention-days: 1
deploy-manifest:
name: Publish ESPHome ${{ matrix.image.title }} to ${{ matrix.registry }}
runs-on: ubuntu-latest
@@ -156,24 +174,27 @@ jobs:
- ghcr
- dockerhub
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4.1.6
- name: Download digests
uses: actions/download-artifact@v3.0.2
uses: actions/download-artifact@v4.1.7
with:
name: digests-${{ matrix.image.target }}-${{ matrix.registry }}
pattern: digests-*
path: /tmp/digests
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
uses: docker/setup-buildx-action@v3.3.0
- name: Log in to docker hub
if: matrix.registry == 'dockerhub'
uses: docker/login-action@v3.0.0
uses: docker/login-action@v3.1.0
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry
if: matrix.registry == 'ghcr'
uses: docker/login-action@v3.0.0
uses: docker/login-action@v3.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -192,28 +213,34 @@ jobs:
done
- name: Create manifest list and push
working-directory: /tmp/digests
working-directory: /tmp/digests/${{ matrix.image.target }}/${{ matrix.registry }}
run: |
docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \
$(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *)
deploy-ha-addon-repo:
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false'
runs-on: ubuntu-latest
needs: [deploy-manifest]
needs:
- init
- deploy-manifest
steps:
- name: Trigger Workflow
uses: actions/github-script@v7.0.1
with:
github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
script: |
let description = "ESPHome";
if (context.eventName == "release") {
description = ${{ toJSON(github.event.release.body) }};
}
github.rest.actions.createWorkflowDispatch({
owner: "esphome",
repo: "home-assistant-addon",
workflow_id: "bump-version.yml",
ref: "main",
inputs: {
version: "${{ github.event.release.tag_name }}",
content: ${{ toJSON(github.event.release.body) }}
version: "${{ needs.init.outputs.tag }}",
content: description
}
})
-1
View File
@@ -1,7 +1,6 @@
---
name: Stale
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "30 0 * * *"
+5 -5
View File
@@ -13,18 +13,18 @@ jobs:
if: github.repository == 'esphome/esphome'
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Checkout Home Assistant
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
with:
repository: home-assistant/core
path: lib/home-assistant
- name: Setup Python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: 3.11
python-version: 3.12
- name: Install Home Assistant
run: |
@@ -36,7 +36,7 @@ jobs:
python ./script/sync-device_class.py
- name: Commit changes
uses: peter-evans/create-pull-request@v5.0.2
uses: peter-evans/create-pull-request@v6.0.4
with:
commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@nabucasa.com>
+5 -2
View File
@@ -1,3 +1,4 @@
---
name: YAML lint
on:
@@ -17,6 +18,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.6
- name: Run yamllint
uses: frenck/action-yamllint@v1.4.2
uses: frenck/action-yamllint@v1.5.0
with:
strict: true
+18 -2
View File
@@ -3,7 +3,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.12.1
rev: 24.2.0
hooks:
- id: black
args:
@@ -27,7 +27,23 @@ repos:
- --branch=release
- --branch=beta
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
rev: v3.15.2
hooks:
- id: pyupgrade
args: [--py39-plus]
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.35.1
hooks:
- id: yamllint
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v13.0.1
hooks:
- id: clang-format
types_or: [c, c++]
- repo: local
hooks:
- id: pylint
name: pylint
entry: script/run-in-env.sh pylint
language: script
types: [python]
+18 -2
View File
@@ -1,3 +1,19 @@
---
ignore: |
venv/
extends: default
ignore-from-file: .gitignore
rules:
document-start: disable
empty-lines:
level: error
max: 1
max-start: 0
max-end: 1
indentation:
level: error
spaces: 2
indent-sequences: true
check-multi-line-strings: false
line-length: disable
truthy: disable
+65 -6
View File
@@ -6,7 +6,7 @@
# the integration's code owner is automatically notified.
# Core Code
setup.py @esphome/core
pyproject.toml @esphome/core
esphome/*.py @esphome/core
esphome/core/* @esphome/core
@@ -18,15 +18,19 @@ esphome/components/ac_dimmer/* @glmnet
esphome/components/adc/* @esphome/core
esphome/components/adc128s102/* @DeerMaximum
esphome/components/addressable_light/* @justfalter
esphome/components/ade7880/* @kpfleming
esphome/components/ade7953/* @angelnu
esphome/components/ade7953_i2c/* @angelnu
esphome/components/ade7953_spi/* @angelnu
esphome/components/ads1118/* @solomondg1
esphome/components/ags10/* @mak-42
esphome/components/airthings_ble/* @jeromelaban
esphome/components/airthings_wave_base/* @jeromelaban @kpfleming @ncareau
esphome/components/airthings_wave_mini/* @ncareau
esphome/components/airthings_wave_plus/* @jeromelaban
esphome/components/alarm_control_panel/* @grahambrown11 @hwstar
esphome/components/alpha3/* @jan-hofmeier
esphome/components/am2315c/* @swoboda1337
esphome/components/am43/* @buxtronix
esphome/components/am43/cover/* @buxtronix
esphome/components/am43/sensor/* @buxtronix
@@ -38,6 +42,7 @@ esphome/components/as5600/* @ammmze
esphome/components/as5600/sensor/* @ammmze
esphome/components/as7341/* @mrgnr
esphome/components/async_tcp/* @OttoWinter
esphome/components/at581x/* @X-Ryl669
esphome/components/atc_mithermometer/* @ahpohl
esphome/components/atm90e26/* @danieltwagner
esphome/components/b_parasite/* @rbaron
@@ -46,6 +51,8 @@ esphome/components/bang_bang/* @OttoWinter
esphome/components/bedjet/* @jhansche
esphome/components/bedjet/climate/* @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/binary_sensor/* @esphome/core
esphome/components/bk72xx/* @kuba2k2
@@ -58,7 +65,10 @@ esphome/components/bme280_base/* @esphome/core
esphome/components/bme280_spi/* @apbodrov
esphome/components/bme680_bsec/* @trvrnrth
esphome/components/bmi160/* @flaviut
esphome/components/bmp3xx/* @martgras
esphome/components/bmp3xx/* @latonita
esphome/components/bmp3xx_base/* @latonita @martgras
esphome/components/bmp3xx_i2c/* @latonita
esphome/components/bmp3xx_spi/* @latonita
esphome/components/bmp581/* @kahrendt
esphome/components/bp1658cj/* @Cossid
esphome/components/bp5758d/* @Cossid
@@ -77,12 +87,16 @@ esphome/components/copy/* @OttoWinter
esphome/components/cover/* @esphome/core
esphome/components/cs5460a/* @balrog-kun
esphome/components/cse7761/* @berfenger
esphome/components/cst226/* @clydebarrow
esphome/components/cst816/* @clydebarrow
esphome/components/ct_clamp/* @jesserockz
esphome/components/current_based/* @djwmarcx
esphome/components/dac7678/* @NickB1
esphome/components/daikin_arc/* @MagicBear
esphome/components/daikin_brc/* @hagak
esphome/components/daly_bms/* @s1lvi0
esphome/components/dashboard_import/* @esphome/core
esphome/components/datetime/* @jesserockz @rfdarter
esphome/components/debug/* @OttoWinter
esphome/components/delonghi/* @grob6000
esphome/components/dfplayer/* @glmnet
@@ -96,7 +110,11 @@ esphome/components/duty_time/* @dudanov
esphome/components/ee895/* @Stock-M
esphome/components/ektf2232/touchscreen/* @jesserockz
esphome/components/emc2101/* @ellull
esphome/components/ens160/* @vincentscode
esphome/components/emmeti/* @E440QF
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/esp32/* @esphome/core
esphome/components/esp32_ble/* @Rapsssito @jesserockz
@@ -105,20 +123,24 @@ esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz
esphome/components/esp8266/* @esphome/core
esphome/components/ethernet_info/* @gtjadsonsantos
esphome/components/event/* @nohat
esphome/components/exposure_notifications/* @OttoWinter
esphome/components/ezo/* @ssieb
esphome/components/ezo_pmp/* @carlos-sarmiento
esphome/components/factory_reset/* @anatoly-savchenkov
esphome/components/fastled_base/* @OttoWinter
esphome/components/feedback/* @ianchi
esphome/components/fingerprint_grow/* @OnFreund @loongyh
esphome/components/fingerprint_grow/* @OnFreund @alexborro @loongyh
esphome/components/font/* @clydebarrow @esphome/core
esphome/components/fs3000/* @kahrendt
esphome/components/ft5x06/* @clydebarrow
esphome/components/ft63x6/* @gpambrozio
esphome/components/gcja5/* @gcormier
esphome/components/gdk101/* @Szewcson
esphome/components/globals/* @esphome/core
esphome/components/gp8403/* @jesserockz
esphome/components/gpio/* @esphome/core
@@ -130,6 +152,10 @@ esphome/components/grove_tb6612fng/* @max246
esphome/components/growatt_solar/* @leeuwte
esphome/components/gt911/* @clydebarrow @jesserockz
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/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann
@@ -144,6 +170,7 @@ esphome/components/honeywellabp2_i2c/* @jpfaff
esphome/components/host/* @esphome/core
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/hte501/* @Stock-M
esphome/components/htu31d/* @betterengineering
esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/hyt271/* @Philippe12
esphome/components/i2c/* @esphome/core
@@ -155,13 +182,19 @@ esphome/components/iaqcore/* @yozik04
esphome/components/ili9xxx/* @clydebarrow @nielsnl68
esphome/components/improv_base/* @esphome/core
esphome/components/improv_serial/* @esphome/core
esphome/components/ina226/* @Sergio303 @latonita
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/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter
esphome/components/internal_temperature/* @Mat931
esphome/components/interval/* @esphome/core
esphome/components/jsn_sr04t/* @Mafus1
esphome/components/json/* @OttoWinter
esphome/components/kamstrup_kmp/* @cfeenstra1024
esphome/components/key_collector/* @ssieb
esphome/components/key_provider/* @ssieb
esphome/components/kuntze/* @ssieb
@@ -223,8 +256,9 @@ esphome/components/mopeka_pro_check/* @spbrogan
esphome/components/mopeka_std_check/* @Fabian-Schmidt
esphome/components/mpl3115a2/* @kbickar
esphome/components/mpu6886/* @fabaff
esphome/components/ms8607/* @e28eta
esphome/components/network/* @esphome/core
esphome/components/nextion/* @senexcrenshaw
esphome/components/nextion/* @edwardtfn @senexcrenshaw
esphome/components/nextion/binary_sensor/* @senexcrenshaw
esphome/components/nextion/sensor/* @senexcrenshaw
esphome/components/nextion/switch/* @senexcrenshaw
@@ -259,6 +293,7 @@ esphome/components/pvvx_mithermometer/* @pasiz
esphome/components/pylontech/* @functionpointer
esphome/components/qmp6988/* @andrewpc
esphome/components/qr_code/* @wjtje
esphome/components/qspi_amoled/* @clydebarrow
esphome/components/qwiic_pir/* @kahrendt
esphome/components/radon_eye_ble/* @jeffeb3
esphome/components/radon_eye_rd200/* @jeffeb3
@@ -272,13 +307,15 @@ esphome/components/rgbct/* @jesserockz
esphome/components/rp2040/* @jesserockz
esphome/components/rp2040_pio_led_strip/* @Papa-DMan
esphome/components/rp2040_pwm/* @jesserockz
esphome/components/rpi_dpi_rgb/* @clydebarrow
esphome/components/rtl87xx/* @kuba2k2
esphome/components/rtttl/* @glmnet
esphome/components/safe_mode/* @jsuanet @paulmonigatti
esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
esphome/components/scd4x/* @martgras @sjtrny
esphome/components/script/* @esphome/core
esphome/components/sdm_meter/* @jesserockz @polyfaces
esphome/components/sdp3x/* @Azimath
esphome/components/seeed_mr24hpc1/* @limengdu
esphome/components/selec_meter/* @sourabhjaiswal
esphome/components/select/* @esphome/core
esphome/components/sen0321/* @notjj
@@ -290,6 +327,7 @@ esphome/components/sfa30/* @ghsensdev
esphome/components/sgp40/* @SenexCrenshaw
esphome/components/sgp4x/* @SenexCrenshaw @martgras
esphome/components/shelly_dimmer/* @edge90 @rnauber
esphome/components/sht3xd/* @mrtoy-me
esphome/components/sht4x/* @sjtrny
esphome/components/shutdown/* @esphome/core @jsuanet
esphome/components/sigma_delta_output/* @Cat-Ion
@@ -323,11 +361,13 @@ esphome/components/ssd1351_spi/* @kbx81
esphome/components/st7567_base/* @latonita
esphome/components/st7567_i2c/* @latonita
esphome/components/st7567_spi/* @latonita
esphome/components/st7701s/* @clydebarrow
esphome/components/st7735/* @SenexCrenshaw
esphome/components/st7789v/* @kbx81
esphome/components/st7920/* @marsjan155
esphome/components/substitutions/* @esphome/core
esphome/components/sun/* @OttoWinter
esphome/components/sun_gtil2/* @Mat931
esphome/components/switch/* @esphome/core
esphome/components/t6615/* @tylermenezes
esphome/components/tca9548a/* @andreashergert1984
@@ -335,10 +375,14 @@ esphome/components/tcl112/* @glmnet
esphome/components/tee501/* @Stock-M
esphome/components/teleinfo/* @0hax
esphome/components/template/alarm_control_panel/* @grahambrown11 @hwstar
esphome/components/template/datetime/* @rfdarter
esphome/components/template/event/* @nohat
esphome/components/template/fan/* @ssieb
esphome/components/text/* @mauritskorse
esphome/components/thermostat/* @kbx81
esphome/components/time/* @OttoWinter
esphome/components/tlc5947/* @rnauber
esphome/components/tlc5971/* @IJIJI
esphome/components/tm1621/* @Philippe12
esphome/components/tm1637/* @glmnet
esphome/components/tm1638/* @skykingjwc
@@ -363,21 +407,36 @@ esphome/components/uart/button/* @ssieb
esphome/components/ufire_ec/* @pvizeli
esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter
esphome/components/uponor_smatrix/* @kroimon
esphome/components/valve/* @esphome/core
esphome/components/vbus/* @ssieb
esphome/components/veml3235/* @kbx81
esphome/components/veml7700/* @latonita
esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz
esphome/components/wake_on_lan/* @willwill2will54
esphome/components/waveshare_epaper/* @clydebarrow
esphome/components/web_server_base/* @OttoWinter
esphome/components/web_server_idf/* @dentra
esphome/components/weikai/* @DrCoolZic
esphome/components/weikai_i2c/* @DrCoolZic
esphome/components/weikai_spi/* @DrCoolZic
esphome/components/whirlpool/* @glmnet
esphome/components/whynter/* @aeonsablaze
esphome/components/wiegand/* @ssieb
esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard
esphome/components/wk2132_i2c/* @DrCoolZic
esphome/components/wk2132_spi/* @DrCoolZic
esphome/components/wk2168_i2c/* @DrCoolZic
esphome/components/wk2168_spi/* @DrCoolZic
esphome/components/wk2204_i2c/* @DrCoolZic
esphome/components/wk2204_spi/* @DrCoolZic
esphome/components/wk2212_i2c/* @DrCoolZic
esphome/components/wk2212_spi/* @DrCoolZic
esphome/components/wl_134/* @hobbypunk90
esphome/components/x9c/* @EtienneMD
esphome/components/xgzp68xx/* @gcormier
esphome/components/xiaomi_hhccjcy10/* @fariouche
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
esphome/components/xiaomi_mhoc303/* @drug123
esphome/components/xiaomi_mhoc401/* @vevsvevs
+2 -2
View File
@@ -110,7 +110,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
pip3 install \
--break-system-packages --no-cache-dir --no-use-pep517 -e /esphome
--break-system-packages --no-cache-dir -e /esphome
# Settings for dashboard
ENV USERNAME="" PASSWORD=""
@@ -160,7 +160,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
pip3 install \
--break-system-packages --no-cache-dir --no-use-pep517 -e /esphome
--break-system-packages --no-cache-dir -e /esphome
# Labels
LABEL \
+6
View File
@@ -21,4 +21,10 @@ export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
# If /build is mounted, use that as the build path
# otherwise use path in /config (so that builds aren't lost on container restart)
if [[ -d /build ]]; then
export ESPHOME_BUILD_PATH=/build
fi
exec esphome "$@"
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# This file installs the user ESPHome fork if specified.
# The fork must be up to date with the latest ESPHome dev branch
# and have no conflicts.
# This config option only exists in the ESPHome Dev add-on.
# ==============================================================================
declare esphome_fork
if bashio::config.has_value 'esphome_fork'; then
esphome_fork=$(bashio::config 'esphome_fork')
# format: [username][/repository]:ref
if [[ "$esphome_fork" =~ ^(([^/]+)(/([^:]+))?:)?([^:/]+)$ ]]; then
username="${BASH_REMATCH[2]:-esphome}"
repository="${BASH_REMATCH[4]:-esphome}"
ref="${BASH_REMATCH[5]}"
else
bashio::exit.nok "Invalid esphome_fork format: $esphome_fork"
fi
full_url="https://github.com/${username}/${repository}/archive/${ref}.tar.gz"
bashio::log.info "Checking forked ESPHome"
dev_version=$(python3 -c "from esphome.const import __version__; print(__version__)")
bashio::log.info "Downloading ESPHome from fork '${esphome_fork}' (${full_url})..."
curl -L -o /tmp/esphome.tar.gz "${full_url}" -qq ||
bashio::exit.nok "Failed downloading ESPHome fork."
bashio::log.info "Installing ESPHome from fork '${esphome_fork}' (${full_url})..."
rm -rf /esphome || bashio::exit.nok "Failed to remove ESPHome."
mkdir /esphome
tar -zxf /tmp/esphome.tar.gz -C /esphome --strip-components=1 ||
bashio::exit.nok "Failed installing ESPHome from fork."
pip install -U -e /esphome || bashio::exit.nok "Failed installing ESPHome from fork."
rm -f /tmp/esphome.tar.gz
fork_version=$(python3 -c "from esphome.const import __version__; print(__version__)")
if [[ "$fork_version" != "$dev_version" ]]; then
bashio::log.error "############################"
bashio::log.error "Uninstalled fork as version does not match"
bashio::log.error "Update (or ask the author to update) the branch"
bashio::log.error "This is important as the dev addon and the dev ESPHome"
bashio::log.error "branch can have changes that are not compatible with old forks"
bashio::log.error "and get reported as bugs which we cannot solve easily."
bashio::log.error "############################"
bashio::exit.nok
fi
bashio::log.info "Installed ESPHome from fork '${esphome_fork}' (${full_url})..."
fi
+42 -13
View File
@@ -18,22 +18,23 @@ from esphome.const import (
CONF_BAUD_RATE,
CONF_BROKER,
CONF_DEASSERT_RTS_DTR,
CONF_DISABLED,
CONF_ESPHOME,
CONF_LOGGER,
CONF_MDNS,
CONF_MQTT,
CONF_NAME,
CONF_OTA,
CONF_MQTT,
CONF_MDNS,
CONF_DISABLED,
CONF_PASSWORD,
CONF_PORT,
CONF_ESPHOME,
CONF_PLATFORM,
CONF_PLATFORMIO_OPTIONS,
CONF_PORT,
CONF_SUBSTITUTIONS,
PLATFORM_BK72XX,
PLATFORM_RTL87XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_RP2040,
PLATFORM_RTL87XX,
SECRETS_FILES,
)
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:'
)
for i, (desc, _) in enumerate(options):
safe_print(f" [{i+1}] {desc}")
safe_print(f" [{i + 1}] {desc}")
while True:
opt = input("(number): ")
@@ -297,8 +298,27 @@ def upload_using_platformio(config, port):
return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args)
def check_permissions(port):
if os.name == "posix" and get_port_type(port) == "SERIAL":
# Check if we can open selected serial port
if not os.access(port, os.F_OK):
raise EsphomeError(
"The selected serial port does not exist. To resolve this issue, "
"check that the device is connected to this computer with a USB cable and that "
"the USB cable can be used for data and is not a power-only cable."
)
if not (os.access(port, os.R_OK | os.W_OK)):
raise EsphomeError(
"You do not have read or write permission on the selected serial port. "
"To resolve this issue, you can add your user to the dialout group "
f"by running the following command: sudo usermod -a -G dialout {os.getlogin()}. "
"You will need to log out & back in or reboot to activate the new group access."
)
def upload_program(config, args, host):
if get_port_type(host) == "SERIAL":
check_permissions(host)
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
file = getattr(args, "file", None)
return upload_using_esptool(config, host, file)
@@ -311,22 +331,27 @@ def upload_program(config, args, host):
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(
"Cannot upload Over the Air as the config does not include the ota: "
"component"
f"Cannot upload Over the Air as the {CONF_OTA} configuration is not present or does not include {CONF_PLATFORM}: {CONF_ESPHOME}"
)
from esphome import espota2
ota_conf = config[CONF_OTA]
remote_port = ota_conf[CONF_PORT]
password = ota_conf.get(CONF_PASSWORD, "")
if (
not is_ip_address(CORE.address)
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 CONF_MQTT in config
and (not args.device or args.device in ("MQTT", "OTA"))
):
from esphome import mqtt
@@ -344,6 +369,7 @@ def show_logs(config, args, port):
if "logger" not in config:
raise EsphomeError("Logger is not configured!")
if get_port_type(port) == "SERIAL":
check_permissions(port)
return run_miniterm(config, port)
if get_port_type(port) == "NETWORK" and "api" in config:
if config[CONF_MDNS][CONF_DISABLED] and CONF_MQTT in config:
@@ -748,7 +774,9 @@ def parse_args(argv):
)
parser_upload = subparsers.add_parser(
"upload", help="Validate the configuration and upload the latest binary."
"upload",
help="Validate the configuration and upload the latest binary.",
parents=[mqtt_options],
)
parser_upload.add_argument(
"configuration", help="Your YAML configuration file(s).", nargs="+"
@@ -765,6 +793,7 @@ def parse_args(argv):
parser_logs = subparsers.add_parser(
"logs",
help="Validate the configuration and show all logs.",
aliases=["log"],
parents=[mqtt_options],
)
parser_logs.add_argument(
+10
View File
@@ -18,10 +18,20 @@ from esphome.util import Registry
def maybe_simple_id(*validators):
"""Allow a raw ID to be specified in place of a config block.
If the value that's being validated is a dictionary, it's passed as-is to the specified validators. Otherwise, it's
wrapped in a dict that looks like ``{"id": <value>}``, and that dict is then handed off to the specified validators.
"""
return maybe_conf(CONF_ID, *validators)
def maybe_conf(conf, *validators):
"""Allow a raw value to be specified in place of a config block.
If the value that's being validated is a dictionary, it's passed as-is to the specified validators. Otherwise, it's
wrapped in a dict that looks like ``{<conf>: <value>}``, and that dict is then handed off to the specified
validators.
(This is a general case of ``maybe_simple_id`` that allows the wrapping key to be something other than ``id``.)
"""
validator = cv.All(*validators)
@schema_extractor("maybe")
+1
View File
@@ -87,4 +87,5 @@ from esphome.cpp_types import ( # noqa
gpio_Flags,
EntityCategory,
Parented,
ESPTime,
)
+13 -1
View File
@@ -18,11 +18,23 @@ from esphome.components.esp32.const import (
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 = {
"0db": cg.global_ns.ADC_ATTEN_DB_0,
"2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
"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",
}
+103 -73
View File
@@ -46,27 +46,27 @@ extern "C"
ADCSensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
pin_->setup();
this->pin_->setup();
#endif
#ifdef USE_ESP32
if (channel1_ != ADC1_CHANNEL_MAX) {
if (this->channel1_ != ADC1_CHANNEL_MAX) {
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
if (!autorange_) {
adc1_config_channel_atten(channel1_, attenuation_);
if (!this->autorange_) {
adc1_config_channel_atten(this->channel1_, this->attenuation_);
}
} else if (channel2_ != ADC2_CHANNEL_MAX) {
if (!autorange_) {
adc2_config_channel_atten(channel2_, attenuation_);
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
if (!this->autorange_) {
adc2_config_channel_atten(this->channel2_, this->attenuation_);
}
}
// load characteristics for each attenuation
for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) {
auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
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,
1100, // default vref
&cal_characteristics_[i]);
&this->cal_characteristics_[i]);
switch (cal_value) {
case ESP_ADC_CAL_VAL_EFUSE_VREF:
ESP_LOGV(TAG, "Using eFuse Vref for calibration");
@@ -99,27 +99,27 @@ void ADCSensor::dump_config() {
#ifdef USE_ADC_SENSOR_VCC
ESP_LOGCONFIG(TAG, " Pin: VCC");
#else
LOG_PIN(" Pin: ", pin_);
LOG_PIN(" Pin: ", this->pin_);
#endif
#endif // USE_ESP8266 || USE_LIBRETINY
#ifdef USE_ESP32
LOG_PIN(" Pin: ", pin_);
if (autorange_) {
ESP_LOGCONFIG(TAG, " Attenuation: auto");
LOG_PIN(" Pin: ", this->pin_);
if (this->autorange_) {
ESP_LOGCONFIG(TAG, " Attenuation: auto");
} else {
switch (this->attenuation_) {
case ADC_ATTEN_DB_0:
ESP_LOGCONFIG(TAG, " Attenuation: 0db");
ESP_LOGCONFIG(TAG, " Attenuation: 0db");
break;
case ADC_ATTEN_DB_2_5:
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
break;
case ADC_ATTEN_DB_6:
ESP_LOGCONFIG(TAG, " Attenuation: 6db");
ESP_LOGCONFIG(TAG, " Attenuation: 6db");
break;
case ADC_ATTEN_DB_11:
ESP_LOGCONFIG(TAG, " Attenuation: 11db");
case ADC_ATTEN_DB_12_COMPAT:
ESP_LOGCONFIG(TAG, " Attenuation: 12db");
break;
default: // This is to satisfy the unused ADC_ATTEN_MAX
break;
@@ -134,11 +134,11 @@ void ADCSensor::dump_config() {
#ifdef USE_ADC_SENSOR_VCC
ESP_LOGCONFIG(TAG, " Pin: VCC");
#else
LOG_PIN(" Pin: ", pin_);
LOG_PIN(" Pin: ", this->pin_);
#endif // USE_ADC_SENSOR_VCC
}
#endif // USE_RP2040
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
LOG_UPDATE_INTERVAL(this);
}
@@ -149,14 +149,24 @@ void ADCSensor::update() {
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
float ADCSensor::sample() {
uint32_t raw = 0;
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
#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
int32_t raw = analogRead(this->pin_->get_pin()); // NOLINT
raw += analogRead(this->pin_->get_pin()); // NOLINT
#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 / 1024.0f;
@@ -165,77 +175,81 @@ float ADCSensor::sample() {
#ifdef USE_ESP32
float ADCSensor::sample() {
if (!autorange_) {
int raw = -1;
if (channel1_ != ADC1_CHANNEL_MAX) {
raw = adc1_get_raw(channel1_);
} else if (channel2_ != ADC2_CHANNEL_MAX) {
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
if (!this->autorange_) {
uint32_t sum = 0;
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
int raw = -1;
if (this->channel1_ != ADC1_CHANNEL_MAX) {
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;
}
if (raw == -1) {
return NAN;
sum = (sum + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
if (this->output_raw_) {
return sum;
}
if (output_raw_) {
return raw;
}
uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]);
uint32_t mv = esp_adc_cal_raw_to_voltage(sum, &this->cal_characteristics_[(int32_t) this->attenuation_]);
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) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11);
raw11 = adc1_get_raw(channel1_);
if (raw11 < ADC_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6);
raw6 = adc1_get_raw(channel1_);
if (this->channel1_ != ADC1_CHANNEL_MAX) {
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
raw12 = adc1_get_raw(this->channel1_);
if (raw12 < ADC_MAX) {
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
raw6 = adc1_get_raw(this->channel1_);
if (raw6 < ADC_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5);
raw2 = adc1_get_raw(channel1_);
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
raw2 = adc1_get_raw(this->channel1_);
if (raw2 < ADC_MAX) {
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0);
raw0 = adc1_get_raw(channel1_);
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
raw0 = adc1_get_raw(this->channel1_);
}
}
}
} else if (channel2_ != ADC2_CHANNEL_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11);
if (raw11 < ADC_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
if (raw12 < ADC_MAX) {
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
if (raw6 < ADC_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
if (raw2 < ADC_MAX) {
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0);
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
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;
}
uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]);
uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &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 mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
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, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
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, &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)
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 c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
// 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
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);
}
#endif // USE_ESP32
@@ -246,8 +260,11 @@ float ADCSensor::sample() {
adc_set_temp_sensor_enabled(true);
delay(1);
adc_select_input(4);
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)
adc_set_temp_sensor_enabled(false);
if (this->output_raw_) {
return raw;
@@ -268,7 +285,11 @@ float ADCSensor::sample() {
adc_gpio_init(pin);
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
if (pin == PICO_VSYS_PIN) {
@@ -276,7 +297,7 @@ float ADCSensor::sample() {
}
#endif // CYW43_USES_VSYS_PIN
if (output_raw_) {
if (this->output_raw_) {
return raw;
}
float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
@@ -287,10 +308,19 @@ float ADCSensor::sample() {
#ifdef USE_LIBRETINY
float ADCSensor::sample() {
if (output_raw_) {
return analogRead(this->pin_->get_pin()); // NOLINT
uint32_t raw = 0;
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
+29 -12
View File
@@ -1,33 +1,48 @@
#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/voltage_sampler/voltage_sampler.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#ifdef USE_ESP32
#include "driver/adc.h"
#include <esp_adc_cal.h>
#include "driver/adc.h"
#endif
namespace esphome {
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 {
public:
#ifdef USE_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) {
channel1_ = channel;
channel2_ = ADC2_CHANNEL_MAX;
this->channel1_ = channel;
this->channel2_ = ADC2_CHANNEL_MAX;
}
void set_channel2(adc2_channel_t channel) {
channel2_ = channel;
channel1_ = ADC1_CHANNEL_MAX;
this->channel2_ = channel;
this->channel1_ = ADC1_CHANNEL_MAX;
}
void set_autorange(bool autorange) { autorange_ = autorange; }
void set_autorange(bool autorange) { this->autorange_ = autorange; }
#endif
/// Update ADC values
@@ -38,7 +53,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
/// `HARDWARE_LATE` setup priority
float get_setup_priority() const override;
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;
#ifdef USE_ESP8266
@@ -46,12 +62,13 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#endif
#ifdef USE_RP2040
void set_is_temperature() { is_temperature_ = true; }
void set_is_temperature() { this->is_temperature_ = true; }
#endif
protected:
InternalGPIOPin *pin_;
bool output_raw_{false};
uint8_t sample_count_{1};
#ifdef USE_RP2040
bool is_temperature_{false};
+24 -2
View File
@@ -1,3 +1,5 @@
import logging
import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.final_validate as fv
@@ -19,16 +21,35 @@ from . import (
ATTENUATION_MODES,
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
adc_ns,
validate_adc_pin,
)
_LOGGER = logging.getLogger(__name__)
AUTO_LOAD = ["voltage_sampler"]
CONF_SAMPLES = "samples"
_attenuation = cv.enum(ATTENUATION_MODES, lower=True)
def validate_config(config):
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
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
@@ -47,7 +68,6 @@ def final_validate_config(config):
return config
adc_ns = cg.esphome_ns.namespace("adc")
ADCSensor = adc_ns.class_(
"ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
)
@@ -65,8 +85,9 @@ CONFIG_SCHEMA = cv.All(
cv.Required(CONF_PIN): validate_adc_pin,
cv.Optional(CONF_RAW, default=False): cv.boolean,
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")),
@@ -90,6 +111,7 @@ async def to_code(config):
cg.add(var.set_pin(pin))
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 == "auto":
+1
View File
@@ -0,0 +1 @@
CODEOWNERS = ["@kpfleming"]
+302
View File
@@ -0,0 +1,302 @@
// This component was developed using knowledge gathered by a number
// of people who reverse-engineered the Shelly 3EM:
//
// @AndreKR on GitHub
// Axel (@Axel830 on GitHub)
// Marko (@goodkiller on GitHub)
// Michaël Piron (@michaelpiron on GitHub)
// Theo Arends (@arendst on GitHub)
#include "ade7880.h"
#include "ade7880_registers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ade7880 {
static const char *const TAG = "ade7880";
void IRAM_ATTR ADE7880Store::gpio_intr(ADE7880Store *arg) { arg->reset_done = true; }
void ADE7880::setup() {
if (this->irq0_pin_ != nullptr) {
this->irq0_pin_->setup();
}
this->irq1_pin_->setup();
if (this->reset_pin_ != nullptr) {
this->reset_pin_->setup();
}
this->store_.irq1_pin = this->irq1_pin_->to_isr();
this->irq1_pin_->attach_interrupt(ADE7880Store::gpio_intr, &this->store_, gpio::INTERRUPT_FALLING_EDGE);
// if IRQ1 is already asserted, the cause must be determined
if (this->irq1_pin_->digital_read() == 0) {
ESP_LOGD(TAG, "IRQ1 found asserted during setup()");
auto status1 = read_u32_register16_(STATUS1);
if ((status1 & ~STATUS1_RSTDONE) != 0) {
// not safe to proceed, must initiate reset
ESP_LOGD(TAG, "IRQ1 asserted for !RSTDONE, resetting device");
this->reset_device_();
return;
}
if ((status1 & STATUS1_RSTDONE) == STATUS1_RSTDONE) {
// safe to proceed, device has just completed reset cycle
ESP_LOGD(TAG, "Acknowledging RSTDONE");
this->write_u32_register16_(STATUS0, 0xFFFF);
this->write_u32_register16_(STATUS1, 0xFFFF);
this->init_device_();
return;
}
}
this->reset_device_();
}
void ADE7880::loop() {
// check for completion of a reset cycle
if (!this->store_.reset_done) {
return;
}
ESP_LOGD(TAG, "Acknowledging RSTDONE");
this->write_u32_register16_(STATUS0, 0xFFFF);
this->write_u32_register16_(STATUS1, 0xFFFF);
this->init_device_();
this->store_.reset_done = false;
this->store_.reset_pending = false;
}
template<typename F>
void ADE7880::update_sensor_from_s24zp_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) {
if (sensor == nullptr) {
return;
}
float val = this->read_s24zp_register16_(a_register);
sensor->publish_state(f(val));
}
template<typename F>
void ADE7880::update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) {
if (sensor == nullptr) {
return;
}
float val = this->read_s16_register16_(a_register);
sensor->publish_state(f(val));
}
template<typename F>
void ADE7880::update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) {
if (sensor == nullptr) {
return;
}
float val = this->read_s32_register16_(a_register);
sensor->publish_state(f(val));
}
void ADE7880::update() {
if (this->store_.reset_pending) {
return;
}
auto start = millis();
if (this->channel_n_ != nullptr) {
auto *chan = this->channel_n_;
this->update_sensor_from_s24zp_register16_(chan->current, NIRMS, [](float val) { return val / 100000.0f; });
}
if (this->channel_a_ != nullptr) {
auto *chan = this->channel_a_;
this->update_sensor_from_s24zp_register16_(chan->current, AIRMS, [](float val) { return val / 100000.0f; });
this->update_sensor_from_s24zp_register16_(chan->voltage, BVRMS, [](float val) { return val / 10000.0f; });
this->update_sensor_from_s24zp_register16_(chan->active_power, AWATT, [](float val) { return val / 100.0f; });
this->update_sensor_from_s24zp_register16_(chan->apparent_power, AVA, [](float val) { return val / 100.0f; });
this->update_sensor_from_s16_register16_(chan->power_factor, APF,
[](float val) { return std::abs(val / -327.68f); });
this->update_sensor_from_s32_register16_(chan->forward_active_energy, AFWATTHR, [&chan](float val) {
return chan->forward_active_energy_total += val / 14400.0f;
});
this->update_sensor_from_s32_register16_(chan->reverse_active_energy, AFWATTHR, [&chan](float val) {
return chan->reverse_active_energy_total += val / 14400.0f;
});
}
if (this->channel_b_ != nullptr) {
auto *chan = this->channel_b_;
this->update_sensor_from_s24zp_register16_(chan->current, BIRMS, [](float val) { return val / 100000.0f; });
this->update_sensor_from_s24zp_register16_(chan->voltage, BVRMS, [](float val) { return val / 10000.0f; });
this->update_sensor_from_s24zp_register16_(chan->active_power, BWATT, [](float val) { return val / 100.0f; });
this->update_sensor_from_s24zp_register16_(chan->apparent_power, BVA, [](float val) { return val / 100.0f; });
this->update_sensor_from_s16_register16_(chan->power_factor, BPF,
[](float val) { return std::abs(val / -327.68f); });
this->update_sensor_from_s32_register16_(chan->forward_active_energy, BFWATTHR, [&chan](float val) {
return chan->forward_active_energy_total += val / 14400.0f;
});
this->update_sensor_from_s32_register16_(chan->reverse_active_energy, BFWATTHR, [&chan](float val) {
return chan->reverse_active_energy_total += val / 14400.0f;
});
}
if (this->channel_c_ != nullptr) {
auto *chan = this->channel_c_;
this->update_sensor_from_s24zp_register16_(chan->current, CIRMS, [](float val) { return val / 100000.0f; });
this->update_sensor_from_s24zp_register16_(chan->voltage, CVRMS, [](float val) { return val / 10000.0f; });
this->update_sensor_from_s24zp_register16_(chan->active_power, CWATT, [](float val) { return val / 100.0f; });
this->update_sensor_from_s24zp_register16_(chan->apparent_power, CVA, [](float val) { return val / 100.0f; });
this->update_sensor_from_s16_register16_(chan->power_factor, CPF,
[](float val) { return std::abs(val / -327.68f); });
this->update_sensor_from_s32_register16_(chan->forward_active_energy, CFWATTHR, [&chan](float val) {
return chan->forward_active_energy_total += val / 14400.0f;
});
this->update_sensor_from_s32_register16_(chan->reverse_active_energy, CFWATTHR, [&chan](float val) {
return chan->reverse_active_energy_total += val / 14400.0f;
});
}
ESP_LOGD(TAG, "update took %u ms", millis() - start);
}
void ADE7880::dump_config() {
ESP_LOGCONFIG(TAG, "ADE7880:");
LOG_PIN(" IRQ0 Pin: ", this->irq0_pin_);
LOG_PIN(" IRQ1 Pin: ", this->irq1_pin_);
LOG_PIN(" RESET Pin: ", this->reset_pin_);
ESP_LOGCONFIG(TAG, " Frequency: %.0f Hz", this->frequency_);
if (this->channel_a_ != nullptr) {
ESP_LOGCONFIG(TAG, " Phase A:");
LOG_SENSOR(" ", "Current", this->channel_a_->current);
LOG_SENSOR(" ", "Voltage", this->channel_a_->voltage);
LOG_SENSOR(" ", "Active Power", this->channel_a_->active_power);
LOG_SENSOR(" ", "Apparent Power", this->channel_a_->apparent_power);
LOG_SENSOR(" ", "Power Factor", this->channel_a_->power_factor);
LOG_SENSOR(" ", "Forward Active Energy", this->channel_a_->forward_active_energy);
LOG_SENSOR(" ", "Reverse Active Energy", this->channel_a_->reverse_active_energy);
ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_a_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_a_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %d", this->channel_a_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_a_->phase_angle_calibration);
}
if (this->channel_b_ != nullptr) {
ESP_LOGCONFIG(TAG, " Phase B:");
LOG_SENSOR(" ", "Current", this->channel_b_->current);
LOG_SENSOR(" ", "Voltage", this->channel_b_->voltage);
LOG_SENSOR(" ", "Active Power", this->channel_b_->active_power);
LOG_SENSOR(" ", "Apparent Power", this->channel_b_->apparent_power);
LOG_SENSOR(" ", "Power Factor", this->channel_b_->power_factor);
LOG_SENSOR(" ", "Forward Active Energy", this->channel_b_->forward_active_energy);
LOG_SENSOR(" ", "Reverse Active Energy", this->channel_b_->reverse_active_energy);
ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_b_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_b_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %d", this->channel_b_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_b_->phase_angle_calibration);
}
if (this->channel_c_ != nullptr) {
ESP_LOGCONFIG(TAG, " Phase C:");
LOG_SENSOR(" ", "Current", this->channel_c_->current);
LOG_SENSOR(" ", "Voltage", this->channel_c_->voltage);
LOG_SENSOR(" ", "Active Power", this->channel_c_->active_power);
LOG_SENSOR(" ", "Apparent Power", this->channel_c_->apparent_power);
LOG_SENSOR(" ", "Power Factor", this->channel_c_->power_factor);
LOG_SENSOR(" ", "Forward Active Energy", this->channel_c_->forward_active_energy);
LOG_SENSOR(" ", "Reverse Active Energy", this->channel_c_->reverse_active_energy);
ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_c_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %d", this->channel_c_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %d", this->channel_c_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_c_->phase_angle_calibration);
}
if (this->channel_n_ != nullptr) {
ESP_LOGCONFIG(TAG, " Neutral:");
LOG_SENSOR(" ", "Current", this->channel_n_->current);
ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %u", this->channel_n_->current_gain_calibration);
}
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
}
void ADE7880::calibrate_s10zp_reading_(uint16_t a_register, int16_t calibration) {
if (calibration == 0) {
return;
}
this->write_s10zp_register16_(a_register, calibration);
}
void ADE7880::calibrate_s24zpse_reading_(uint16_t a_register, int32_t calibration) {
if (calibration == 0) {
return;
}
this->write_s24zpse_register16_(a_register, calibration);
}
void ADE7880::init_device_() {
this->write_u8_register16_(CONFIG2, CONFIG2_I2C_LOCK);
this->write_u16_register16_(GAIN, 0);
if (this->frequency_ > 55) {
this->write_u16_register16_(COMPMODE, COMPMODE_DEFAULT | COMPMODE_SELFREQ);
}
if (this->channel_n_ != nullptr) {
this->calibrate_s24zpse_reading_(NIGAIN, this->channel_n_->current_gain_calibration);
}
if (this->channel_a_ != nullptr) {
this->calibrate_s24zpse_reading_(AIGAIN, this->channel_a_->current_gain_calibration);
this->calibrate_s24zpse_reading_(AVGAIN, this->channel_a_->voltage_gain_calibration);
this->calibrate_s24zpse_reading_(APGAIN, this->channel_a_->power_gain_calibration);
this->calibrate_s10zp_reading_(APHCAL, this->channel_a_->phase_angle_calibration);
}
if (this->channel_b_ != nullptr) {
this->calibrate_s24zpse_reading_(BIGAIN, this->channel_b_->current_gain_calibration);
this->calibrate_s24zpse_reading_(BVGAIN, this->channel_b_->voltage_gain_calibration);
this->calibrate_s24zpse_reading_(BPGAIN, this->channel_b_->power_gain_calibration);
this->calibrate_s10zp_reading_(BPHCAL, this->channel_b_->phase_angle_calibration);
}
if (this->channel_c_ != nullptr) {
this->calibrate_s24zpse_reading_(CIGAIN, this->channel_c_->current_gain_calibration);
this->calibrate_s24zpse_reading_(CVGAIN, this->channel_c_->voltage_gain_calibration);
this->calibrate_s24zpse_reading_(CPGAIN, this->channel_c_->power_gain_calibration);
this->calibrate_s10zp_reading_(CPHCAL, this->channel_c_->phase_angle_calibration);
}
// write three default values to data memory RAM to flush the I2C write queue
this->write_s32_register16_(VLEVEL, 0);
this->write_s32_register16_(VLEVEL, 0);
this->write_s32_register16_(VLEVEL, 0);
this->write_u8_register16_(DSPWP_SEL, DSPWP_SEL_SET);
this->write_u8_register16_(DSPWP_SET, DSPWP_SET_RO);
this->write_u16_register16_(RUN, RUN_ENABLE);
}
void ADE7880::reset_device_() {
if (this->reset_pin_ != nullptr) {
ESP_LOGD(TAG, "Reset device using RESET pin");
this->reset_pin_->digital_write(false);
delay(1);
this->reset_pin_->digital_write(true);
} else {
ESP_LOGD(TAG, "Reset device using SWRST command");
this->write_u16_register16_(CONFIG, CONFIG_SWRST);
}
this->store_.reset_pending = true;
}
} // namespace ade7880
} // namespace esphome
+131
View File
@@ -0,0 +1,131 @@
#pragma once
// This component was developed using knowledge gathered by a number
// of people who reverse-engineered the Shelly 3EM:
//
// @AndreKR on GitHub
// Axel (@Axel830 on GitHub)
// Marko (@goodkiller on GitHub)
// Michaël Piron (@michaelpiron on GitHub)
// Theo Arends (@arendst on GitHub)
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/sensor/sensor.h"
#include "ade7880_registers.h"
namespace esphome {
namespace ade7880 {
struct NeutralChannel {
void set_current(sensor::Sensor *sens) { this->current = sens; }
void set_current_gain_calibration(int32_t val) { this->current_gain_calibration = val; }
sensor::Sensor *current{nullptr};
int32_t current_gain_calibration{0};
};
struct PowerChannel {
void set_current(sensor::Sensor *sens) { this->current = sens; }
void set_voltage(sensor::Sensor *sens) { this->voltage = sens; }
void set_active_power(sensor::Sensor *sens) { this->active_power = sens; }
void set_apparent_power(sensor::Sensor *sens) { this->apparent_power = sens; }
void set_power_factor(sensor::Sensor *sens) { this->power_factor = sens; }
void set_forward_active_energy(sensor::Sensor *sens) { this->forward_active_energy = sens; }
void set_reverse_active_energy(sensor::Sensor *sens) { this->reverse_active_energy = sens; }
void set_current_gain_calibration(int32_t val) { this->current_gain_calibration = val; }
void set_voltage_gain_calibration(int32_t val) { this->voltage_gain_calibration = val; }
void set_power_gain_calibration(int32_t val) { this->power_gain_calibration = val; }
void set_phase_angle_calibration(int32_t val) { this->phase_angle_calibration = val; }
sensor::Sensor *current{nullptr};
sensor::Sensor *voltage{nullptr};
sensor::Sensor *active_power{nullptr};
sensor::Sensor *apparent_power{nullptr};
sensor::Sensor *power_factor{nullptr};
sensor::Sensor *forward_active_energy{nullptr};
sensor::Sensor *reverse_active_energy{nullptr};
int32_t current_gain_calibration{0};
int32_t voltage_gain_calibration{0};
int32_t power_gain_calibration{0};
uint16_t phase_angle_calibration{0};
float forward_active_energy_total{0};
float reverse_active_energy_total{0};
};
// Store data in a class that doesn't use multiple-inheritance (no vtables in flash!)
struct ADE7880Store {
volatile bool reset_done{false};
bool reset_pending{false};
ISRInternalGPIOPin irq1_pin;
static void gpio_intr(ADE7880Store *arg);
};
class ADE7880 : public i2c::I2CDevice, public PollingComponent {
public:
void set_irq0_pin(InternalGPIOPin *pin) { this->irq0_pin_ = pin; }
void set_irq1_pin(InternalGPIOPin *pin) { this->irq1_pin_ = pin; }
void set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; }
void set_frequency(float frequency) { this->frequency_ = frequency; }
void set_channel_n(NeutralChannel *channel) { this->channel_n_ = channel; }
void set_channel_a(PowerChannel *channel) { this->channel_a_ = channel; }
void set_channel_b(PowerChannel *channel) { this->channel_b_ = channel; }
void set_channel_c(PowerChannel *channel) { this->channel_c_ = channel; }
void setup() override;
void loop() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
ADE7880Store store_{};
InternalGPIOPin *irq0_pin_{nullptr};
InternalGPIOPin *irq1_pin_{nullptr};
InternalGPIOPin *reset_pin_{nullptr};
float frequency_;
NeutralChannel *channel_n_{nullptr};
PowerChannel *channel_a_{nullptr};
PowerChannel *channel_b_{nullptr};
PowerChannel *channel_c_{nullptr};
void calibrate_s10zp_reading_(uint16_t a_register, int16_t calibration);
void calibrate_s24zpse_reading_(uint16_t a_register, int32_t calibration);
void init_device_();
// each of these functions allow the caller to pass in a lambda (or any other callable)
// which modifies the value read from the register before it is passed to the sensor
// the callable will be passed a 'float' value and is expected to return a 'float'
template<typename F> void update_sensor_from_s24zp_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
template<typename F> void update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
template<typename F> void update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
void reset_device_();
uint8_t read_u8_register16_(uint16_t a_register);
int16_t read_s16_register16_(uint16_t a_register);
uint16_t read_u16_register16_(uint16_t a_register);
int32_t read_s24zp_register16_(uint16_t a_register);
int32_t read_s32_register16_(uint16_t a_register);
uint32_t read_u32_register16_(uint16_t a_register);
void write_u8_register16_(uint16_t a_register, uint8_t value);
void write_s10zp_register16_(uint16_t a_register, int16_t value);
void write_u16_register16_(uint16_t a_register, uint16_t value);
void write_s24zpse_register16_(uint16_t a_register, int32_t value);
void write_s32_register16_(uint16_t a_register, int32_t value);
void write_u32_register16_(uint16_t a_register, uint32_t value);
};
} // namespace ade7880
} // namespace esphome
+101
View File
@@ -0,0 +1,101 @@
// This component was developed using knowledge gathered by a number
// of people who reverse-engineered the Shelly 3EM:
//
// @AndreKR on GitHub
// Axel (@Axel830 on GitHub)
// Marko (@goodkiller on GitHub)
// Michaël Piron (@michaelpiron on GitHub)
// Theo Arends (@arendst on GitHub)
#include "ade7880.h"
namespace esphome {
namespace ade7880 {
// adapted from https://stackoverflow.com/a/55912127/1886371
template<size_t Bits, typename T> inline T sign_extend(const T &v) noexcept {
using S = struct { signed Val : Bits; };
return reinterpret_cast<const S *>(&v)->Val;
}
// Register types
// unsigned 8-bit (uint8_t)
// signed 10-bit - 16-bit ZP on wire (int16_t, needs sign extension)
// unsigned 16-bit (uint16_t)
// unsigned 20-bit - 32-bit ZP on wire (uint32_t)
// signed 24-bit - 32-bit ZPSE on wire (int32_t, needs sign extension)
// signed 24-bit - 32-bit ZP on wire (int32_t, needs sign extension)
// signed 24-bit - 32-bit SE on wire (int32_t)
// signed 28-bit - 32-bit ZP on wire (int32_t, needs sign extension)
// unsigned 32-bit (uint32_t)
// signed 32-bit (int32_t)
uint8_t ADE7880::read_u8_register16_(uint16_t a_register) {
uint8_t in;
this->read_register16(a_register, &in, sizeof(in));
return in;
}
int16_t ADE7880::read_s16_register16_(uint16_t a_register) {
int16_t in;
this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in));
return convert_big_endian(in);
}
uint16_t ADE7880::read_u16_register16_(uint16_t a_register) {
uint16_t in;
this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in));
return convert_big_endian(in);
}
int32_t ADE7880::read_s24zp_register16_(uint16_t a_register) {
// s24zp means 24 bit signed value in the lower 24 bits of a 32-bit register
int32_t in;
this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in));
return sign_extend<24>(convert_big_endian(in));
}
int32_t ADE7880::read_s32_register16_(uint16_t a_register) {
int32_t in;
this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in));
return convert_big_endian(in);
}
uint32_t ADE7880::read_u32_register16_(uint16_t a_register) {
uint32_t in;
this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in));
return convert_big_endian(in);
}
void ADE7880::write_u8_register16_(uint16_t a_register, uint8_t value) {
this->write_register16(a_register, &value, sizeof(value));
}
void ADE7880::write_s10zp_register16_(uint16_t a_register, int16_t value) {
int16_t out = convert_big_endian(value & 0x03FF);
this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out));
}
void ADE7880::write_u16_register16_(uint16_t a_register, uint16_t value) {
uint16_t out = convert_big_endian(value);
this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out));
}
void ADE7880::write_s24zpse_register16_(uint16_t a_register, int32_t value) {
// s24zpse means a 24-bit signed value, sign-extended to 28 bits, in the lower 28 bits of a 32-bit register
int32_t out = convert_big_endian(value & 0x0FFFFFFF);
this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out));
}
void ADE7880::write_s32_register16_(uint16_t a_register, int32_t value) {
int32_t out = convert_big_endian(value);
this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out));
}
void ADE7880::write_u32_register16_(uint16_t a_register, uint32_t value) {
uint32_t out = convert_big_endian(value);
this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out));
}
} // namespace ade7880
} // namespace esphome
@@ -0,0 +1,243 @@
#pragma once
// This file is a modified version of the one created by Michaël Piron (@michaelpiron on GitHub)
// Source: https://www.analog.com/media/en/technical-documentation/application-notes/AN-1127.pdf
namespace esphome {
namespace ade7880 {
// DSP Data Memory RAM registers
constexpr uint16_t AIGAIN = 0x4380;
constexpr uint16_t AVGAIN = 0x4381;
constexpr uint16_t BIGAIN = 0x4382;
constexpr uint16_t BVGAIN = 0x4383;
constexpr uint16_t CIGAIN = 0x4384;
constexpr uint16_t CVGAIN = 0x4385;
constexpr uint16_t NIGAIN = 0x4386;
constexpr uint16_t DICOEFF = 0x4388;
constexpr uint16_t APGAIN = 0x4389;
constexpr uint16_t AWATTOS = 0x438A;
constexpr uint16_t BPGAIN = 0x438B;
constexpr uint16_t BWATTOS = 0x438C;
constexpr uint16_t CPGAIN = 0x438D;
constexpr uint16_t CWATTOS = 0x438E;
constexpr uint16_t AIRMSOS = 0x438F;
constexpr uint16_t AVRMSOS = 0x4390;
constexpr uint16_t BIRMSOS = 0x4391;
constexpr uint16_t BVRMSOS = 0x4392;
constexpr uint16_t CIRMSOS = 0x4393;
constexpr uint16_t CVRMSOS = 0x4394;
constexpr uint16_t NIRMSOS = 0x4395;
constexpr uint16_t HPGAIN = 0x4398;
constexpr uint16_t ISUMLVL = 0x4399;
constexpr uint16_t VLEVEL = 0x439F;
constexpr uint16_t AFWATTOS = 0x43A2;
constexpr uint16_t BFWATTOS = 0x43A3;
constexpr uint16_t CFWATTOS = 0x43A4;
constexpr uint16_t AFVAROS = 0x43A5;
constexpr uint16_t BFVAROS = 0x43A6;
constexpr uint16_t CFVAROS = 0x43A7;
constexpr uint16_t AFIRMSOS = 0x43A8;
constexpr uint16_t BFIRMSOS = 0x43A9;
constexpr uint16_t CFIRMSOS = 0x43AA;
constexpr uint16_t AFVRMSOS = 0x43AB;
constexpr uint16_t BFVRMSOS = 0x43AC;
constexpr uint16_t CFVRMSOS = 0x43AD;
constexpr uint16_t HXWATTOS = 0x43AE;
constexpr uint16_t HYWATTOS = 0x43AF;
constexpr uint16_t HZWATTOS = 0x43B0;
constexpr uint16_t HXVAROS = 0x43B1;
constexpr uint16_t HYVAROS = 0x43B2;
constexpr uint16_t HZVAROS = 0x43B3;
constexpr uint16_t HXIRMSOS = 0x43B4;
constexpr uint16_t HYIRMSOS = 0x43B5;
constexpr uint16_t HZIRMSOS = 0x43B6;
constexpr uint16_t HXVRMSOS = 0x43B7;
constexpr uint16_t HYVRMSOS = 0x43B8;
constexpr uint16_t HZVRMSOS = 0x43B9;
constexpr uint16_t AIRMS = 0x43C0;
constexpr uint16_t AVRMS = 0x43C1;
constexpr uint16_t BIRMS = 0x43C2;
constexpr uint16_t BVRMS = 0x43C3;
constexpr uint16_t CIRMS = 0x43C4;
constexpr uint16_t CVRMS = 0x43C5;
constexpr uint16_t NIRMS = 0x43C6;
constexpr uint16_t ISUM = 0x43C7;
// Internal DSP Memory RAM registers
constexpr uint16_t RUN = 0xE228;
constexpr uint16_t AWATTHR = 0xE400;
constexpr uint16_t BWATTHR = 0xE401;
constexpr uint16_t CWATTHR = 0xE402;
constexpr uint16_t AFWATTHR = 0xE403;
constexpr uint16_t BFWATTHR = 0xE404;
constexpr uint16_t CFWATTHR = 0xE405;
constexpr uint16_t AFVARHR = 0xE409;
constexpr uint16_t BFVARHR = 0xE40A;
constexpr uint16_t CFVARHR = 0xE40B;
constexpr uint16_t AVAHR = 0xE40C;
constexpr uint16_t BVAHR = 0xE40D;
constexpr uint16_t CVAHR = 0xE40E;
constexpr uint16_t IPEAK = 0xE500;
constexpr uint16_t VPEAK = 0xE501;
constexpr uint16_t STATUS0 = 0xE502;
constexpr uint16_t STATUS1 = 0xE503;
constexpr uint16_t AIMAV = 0xE504;
constexpr uint16_t BIMAV = 0xE505;
constexpr uint16_t CIMAV = 0xE506;
constexpr uint16_t OILVL = 0xE507;
constexpr uint16_t OVLVL = 0xE508;
constexpr uint16_t SAGLVL = 0xE509;
constexpr uint16_t MASK0 = 0xE50A;
constexpr uint16_t MASK1 = 0xE50B;
constexpr uint16_t IAWV = 0xE50C;
constexpr uint16_t IBWV = 0xE50D;
constexpr uint16_t ICWV = 0xE50E;
constexpr uint16_t INWV = 0xE50F;
constexpr uint16_t VAWV = 0xE510;
constexpr uint16_t VBWV = 0xE511;
constexpr uint16_t VCWV = 0xE512;
constexpr uint16_t AWATT = 0xE513;
constexpr uint16_t BWATT = 0xE514;
constexpr uint16_t CWATT = 0xE515;
constexpr uint16_t AFVAR = 0xE516;
constexpr uint16_t BFVAR = 0xE517;
constexpr uint16_t CFVAR = 0xE518;
constexpr uint16_t AVA = 0xE519;
constexpr uint16_t BVA = 0xE51A;
constexpr uint16_t CVA = 0xE51B;
constexpr uint16_t CHECKSUM = 0xE51F;
constexpr uint16_t VNOM = 0xE520;
constexpr uint16_t LAST_RWDATA_24BIT = 0xE5FF;
constexpr uint16_t PHSTATUS = 0xE600;
constexpr uint16_t ANGLE0 = 0xE601;
constexpr uint16_t ANGLE1 = 0xE602;
constexpr uint16_t ANGLE2 = 0xE603;
constexpr uint16_t PHNOLOAD = 0xE608;
constexpr uint16_t LINECYC = 0xE60C;
constexpr uint16_t ZXTOUT = 0xE60D;
constexpr uint16_t COMPMODE = 0xE60E;
constexpr uint16_t GAIN = 0xE60F;
constexpr uint16_t CFMODE = 0xE610;
constexpr uint16_t CF1DEN = 0xE611;
constexpr uint16_t CF2DEN = 0xE612;
constexpr uint16_t CF3DEN = 0xE613;
constexpr uint16_t APHCAL = 0xE614;
constexpr uint16_t BPHCAL = 0xE615;
constexpr uint16_t CPHCAL = 0xE616;
constexpr uint16_t PHSIGN = 0xE617;
constexpr uint16_t CONFIG = 0xE618;
constexpr uint16_t MMODE = 0xE700;
constexpr uint16_t ACCMODE = 0xE701;
constexpr uint16_t LCYCMODE = 0xE702;
constexpr uint16_t PEAKCYC = 0xE703;
constexpr uint16_t SAGCYC = 0xE704;
constexpr uint16_t CFCYC = 0xE705;
constexpr uint16_t HSDC_CFG = 0xE706;
constexpr uint16_t VERSION = 0xE707;
constexpr uint16_t DSPWP_SET = 0xE7E3;
constexpr uint16_t LAST_RWDATA_8BIT = 0xE7FD;
constexpr uint16_t DSPWP_SEL = 0xE7FE;
constexpr uint16_t FVRMS = 0xE880;
constexpr uint16_t FIRMS = 0xE881;
constexpr uint16_t FWATT = 0xE882;
constexpr uint16_t FVAR = 0xE883;
constexpr uint16_t FVA = 0xE884;
constexpr uint16_t FPF = 0xE885;
constexpr uint16_t VTHDN = 0xE886;
constexpr uint16_t ITHDN = 0xE887;
constexpr uint16_t HXVRMS = 0xE888;
constexpr uint16_t HXIRMS = 0xE889;
constexpr uint16_t HXWATT = 0xE88A;
constexpr uint16_t HXVAR = 0xE88B;
constexpr uint16_t HXVA = 0xE88C;
constexpr uint16_t HXPF = 0xE88D;
constexpr uint16_t HXVHD = 0xE88E;
constexpr uint16_t HXIHD = 0xE88F;
constexpr uint16_t HYVRMS = 0xE890;
constexpr uint16_t HYIRMS = 0xE891;
constexpr uint16_t HYWATT = 0xE892;
constexpr uint16_t HYVAR = 0xE893;
constexpr uint16_t HYVA = 0xE894;
constexpr uint16_t HYPF = 0xE895;
constexpr uint16_t HYVHD = 0xE896;
constexpr uint16_t HYIHD = 0xE897;
constexpr uint16_t HZVRMS = 0xE898;
constexpr uint16_t HZIRMS = 0xE899;
constexpr uint16_t HZWATT = 0xE89A;
constexpr uint16_t HZVAR = 0xE89B;
constexpr uint16_t HZVA = 0xE89C;
constexpr uint16_t HZPF = 0xE89D;
constexpr uint16_t HZVHD = 0xE89E;
constexpr uint16_t HZIHD = 0xE89F;
constexpr uint16_t HCONFIG = 0xE900;
constexpr uint16_t APF = 0xE902;
constexpr uint16_t BPF = 0xE903;
constexpr uint16_t CPF = 0xE904;
constexpr uint16_t APERIOD = 0xE905;
constexpr uint16_t BPERIOD = 0xE906;
constexpr uint16_t CPERIOD = 0xE907;
constexpr uint16_t APNOLOAD = 0xE908;
constexpr uint16_t VARNOLOAD = 0xE909;
constexpr uint16_t VANOLOAD = 0xE90A;
constexpr uint16_t LAST_ADD = 0xE9FE;
constexpr uint16_t LAST_RWDATA_16BIT = 0xE9FF;
constexpr uint16_t CONFIG3 = 0xEA00;
constexpr uint16_t LAST_OP = 0xEA01;
constexpr uint16_t WTHR = 0xEA02;
constexpr uint16_t VARTHR = 0xEA03;
constexpr uint16_t VATHR = 0xEA04;
constexpr uint16_t HX_REG = 0xEA08;
constexpr uint16_t HY_REG = 0xEA09;
constexpr uint16_t HZ_REG = 0xEA0A;
constexpr uint16_t LPOILVL = 0xEC00;
constexpr uint16_t CONFIG2 = 0xEC01;
// STATUS1 Register Bits
constexpr uint32_t STATUS1_RSTDONE = (1 << 15);
// CONFIG Register Bits
constexpr uint16_t CONFIG_SWRST = (1 << 7);
// CONFIG2 Register Bits
constexpr uint8_t CONFIG2_I2C_LOCK = (1 << 1);
// COMPMODE Register Bits
constexpr uint16_t COMPMODE_DEFAULT = 0x01FF;
constexpr uint16_t COMPMODE_SELFREQ = (1 << 14);
// RUN Register Bits
constexpr uint16_t RUN_ENABLE = (1 << 0);
// DSPWP_SET Register Bits
constexpr uint8_t DSPWP_SET_RO = (1 << 7);
// DSPWP_SEL Register Bits
constexpr uint8_t DSPWP_SEL_SET = 0xAD;
} // namespace ade7880
} // namespace esphome
+290
View File
@@ -0,0 +1,290 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, i2c
from esphome import pins
from esphome.const import (
CONF_ACTIVE_POWER,
CONF_APPARENT_POWER,
CONF_CALIBRATION,
CONF_CURRENT,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_FREQUENCY,
CONF_ID,
CONF_NAME,
CONF_PHASE_A,
CONF_PHASE_ANGLE,
CONF_PHASE_B,
CONF_PHASE_C,
CONF_POWER_FACTOR,
CONF_RESET_PIN,
CONF_REVERSE_ACTIVE_ENERGY,
CONF_VOLTAGE,
CONF_VOLTAGE_GAIN,
DEVICE_CLASS_APPARENT_POWER,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_POWER_FACTOR,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_PERCENT,
UNIT_VOLT,
UNIT_VOLT_AMPS,
UNIT_VOLT_AMPS_REACTIVE_HOURS,
UNIT_WATT,
UNIT_WATT_HOURS,
)
DEPENDENCIES = ["i2c"]
ade7880_ns = cg.esphome_ns.namespace("ade7880")
ADE7880 = ade7880_ns.class_("ADE7880", cg.PollingComponent, i2c.I2CDevice)
NeutralChannel = ade7880_ns.struct("NeutralChannel")
PowerChannel = ade7880_ns.struct("PowerChannel")
CONF_CURRENT_GAIN = "current_gain"
CONF_IRQ0_PIN = "irq0_pin"
CONF_IRQ1_PIN = "irq1_pin"
CONF_POWER_GAIN = "power_gain"
CONF_NEUTRAL = "neutral"
NEUTRAL_CHANNEL_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(NeutralChannel),
cv.Optional(CONF_NAME): cv.string_strict,
cv.Required(CONF_CURRENT): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=2,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Required(CONF_CALIBRATION): cv.Schema(
{
cv.Required(CONF_CURRENT_GAIN): cv.int_,
},
),
}
)
POWER_CHANNEL_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(PowerChannel),
cv.Optional(CONF_NAME): cv.string_strict,
cv.Optional(CONF_VOLTAGE): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=1,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_CURRENT): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=2,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_ACTIVE_POWER): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=1,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_APPARENT_POWER): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT_AMPS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_APPARENT_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_POWER_FACTOR): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER_FACTOR,
state_class=STATE_CLASS_MEASUREMENT,
),
key=CONF_NAME,
),
cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_WATT_HOURS,
accuracy_decimals=2,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
key=CONF_NAME,
),
cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): cv.maybe_simple_value(
sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT_AMPS_REACTIVE_HOURS,
accuracy_decimals=2,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
key=CONF_NAME,
),
cv.Required(CONF_CALIBRATION): cv.Schema(
{
cv.Required(CONF_CURRENT_GAIN): cv.int_,
cv.Required(CONF_VOLTAGE_GAIN): cv.int_,
cv.Required(CONF_POWER_GAIN): cv.int_,
cv.Required(CONF_PHASE_ANGLE): cv.int_,
},
),
}
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ADE7880),
cv.Optional(CONF_FREQUENCY, default="50Hz"): cv.All(
cv.frequency, cv.Range(min=45.0, max=66.0)
),
cv.Optional(CONF_IRQ0_PIN): pins.internal_gpio_input_pin_schema,
cv.Required(CONF_IRQ1_PIN): pins.internal_gpio_input_pin_schema,
cv.Optional(CONF_RESET_PIN): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_PHASE_A): POWER_CHANNEL_SCHEMA,
cv.Optional(CONF_PHASE_B): POWER_CHANNEL_SCHEMA,
cv.Optional(CONF_PHASE_C): POWER_CHANNEL_SCHEMA,
cv.Optional(CONF_NEUTRAL): NEUTRAL_CHANNEL_SCHEMA,
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x38))
)
async def neutral_channel(config):
var = cg.new_Pvariable(config[CONF_ID])
current = config[CONF_CURRENT]
sens = await sensor.new_sensor(current)
cg.add(var.set_current(sens))
cg.add(
var.set_current_gain_calibration(config[CONF_CALIBRATION][CONF_CURRENT_GAIN])
)
return var
async def power_channel(config):
var = cg.new_Pvariable(config[CONF_ID])
for sensor_type in [
CONF_CURRENT,
CONF_VOLTAGE,
CONF_ACTIVE_POWER,
CONF_APPARENT_POWER,
CONF_POWER_FACTOR,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_REVERSE_ACTIVE_ENERGY,
]:
if conf := config.get(sensor_type):
sens = await sensor.new_sensor(conf)
cg.add(getattr(var, f"set_{sensor_type}")(sens))
for calib_type in [
CONF_CURRENT_GAIN,
CONF_VOLTAGE_GAIN,
CONF_POWER_GAIN,
CONF_PHASE_ANGLE,
]:
cg.add(
getattr(var, f"set_{calib_type}_calibration")(
config[CONF_CALIBRATION][calib_type]
)
)
return var
def final_validate(config):
for channel in [CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]:
if channel := config.get(channel):
channel_name = channel.get(CONF_NAME)
for sensor_type in [
CONF_CURRENT,
CONF_VOLTAGE,
CONF_ACTIVE_POWER,
CONF_APPARENT_POWER,
CONF_POWER_FACTOR,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_REVERSE_ACTIVE_ENERGY,
]:
if conf := channel.get(sensor_type):
sensor_name = conf.get(CONF_NAME)
if (
sensor_name
and channel_name
and not sensor_name.startswith(channel_name)
):
conf[CONF_NAME] = f"{channel_name} {sensor_name}"
if channel := config.get(CONF_NEUTRAL):
channel_name = channel.get(CONF_NAME)
if conf := channel.get(CONF_CURRENT):
sensor_name = conf.get(CONF_NAME)
if (
sensor_name
and channel_name
and not sensor_name.startswith(channel_name)
):
conf[CONF_NAME] = f"{channel_name} {sensor_name}"
FINAL_VALIDATE_SCHEMA = final_validate
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
if irq0_pin := config.get(CONF_IRQ0_PIN):
pin = await cg.gpio_pin_expression(irq0_pin)
cg.add(var.set_irq0_pin(pin))
pin = await cg.gpio_pin_expression(config[CONF_IRQ1_PIN])
cg.add(var.set_irq1_pin(pin))
if reset_pin := config.get(CONF_RESET_PIN):
pin = await cg.gpio_pin_expression(reset_pin)
cg.add(var.set_reset_pin(pin))
if frequency := config.get(CONF_FREQUENCY):
cg.add(var.set_frequency(frequency))
if channel := config.get(CONF_PHASE_A):
chan = await power_channel(channel)
cg.add(var.set_channel_a(chan))
if channel := config.get(CONF_PHASE_B):
chan = await power_channel(channel)
cg.add(var.set_channel_b(chan))
if channel := config.get(CONF_PHASE_C):
chan = await power_channel(channel)
cg.add(var.set_channel_c(chan))
if channel := config.get(CONF_NEUTRAL):
chan = await neutral_channel(channel)
cg.add(var.set_channel_n(chan))
+6 -1
View File
@@ -6,6 +6,7 @@ from esphome.const import (
CONF_IRQ_PIN,
CONF_VOLTAGE,
CONF_FREQUENCY,
CONF_VOLTAGE_GAIN,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_APPARENT_POWER,
DEVICE_CLASS_POWER,
@@ -36,11 +37,11 @@ CONF_POWER_FACTOR_B = "power_factor_b"
CONF_VOLTAGE_PGA_GAIN = "voltage_pga_gain"
CONF_CURRENT_PGA_GAIN_A = "current_pga_gain_a"
CONF_CURRENT_PGA_GAIN_B = "current_pga_gain_b"
CONF_VOLTAGE_GAIN = "voltage_gain"
CONF_CURRENT_GAIN_A = "current_gain_a"
CONF_CURRENT_GAIN_B = "current_gain_b"
CONF_ACTIVE_POWER_GAIN_A = "active_power_gain_a"
CONF_ACTIVE_POWER_GAIN_B = "active_power_gain_b"
CONF_USE_ACCUMULATED_ENERGY_REGISTERS = "use_accumulated_energy_registers"
PGA_GAINS = {
"1x": 0b000,
"2x": 0b001,
@@ -155,6 +156,7 @@ ADE7953_CONFIG_SCHEMA = cv.Schema(
cv.Optional(CONF_ACTIVE_POWER_GAIN_B, default=0x400000): cv.hex_int_range(
min=0x100000, max=0x800000
),
cv.Optional(CONF_USE_ACCUMULATED_ENERGY_REGISTERS, default=False): cv.boolean,
}
).extend(cv.polling_component_schema("60s"))
@@ -174,6 +176,9 @@ async def register_ade7953(var, config):
cg.add(var.set_bigain(config.get(CONF_CURRENT_GAIN_B)))
cg.add(var.set_awgain(config.get(CONF_ACTIVE_POWER_GAIN_A)))
cg.add(var.set_bwgain(config.get(CONF_ACTIVE_POWER_GAIN_B)))
cg.add(
var.set_use_acc_energy_regs(config.get(CONF_USE_ACCUMULATED_ENERGY_REGISTERS))
)
for key in [
CONF_VOLTAGE,
@@ -6,6 +6,9 @@ namespace ade7953_base {
static const char *const TAG = "ade7953";
static const float ADE_POWER_FACTOR = 154.0f;
static const float ADE_WATTSEC_POWER_FACTOR = ADE_POWER_FACTOR * ADE_POWER_FACTOR / 3600;
void ADE7953::setup() {
if (this->irq_pin_ != nullptr) {
this->irq_pin_->setup();
@@ -34,6 +37,7 @@ void ADE7953::setup() {
this->ade_read_32(BIGAIN_32, &bigain_);
this->ade_read_32(AWGAIN_32, &awgain_);
this->ade_read_32(BWGAIN_32, &bwgain_);
this->last_update_ = millis();
this->is_setup_ = true;
});
}
@@ -52,6 +56,7 @@ void ADE7953::dump_config() {
LOG_SENSOR(" ", "Active Power B Sensor", this->active_power_b_sensor_);
LOG_SENSOR(" ", "Rective Power A Sensor", this->reactive_power_a_sensor_);
LOG_SENSOR(" ", "Reactive Power B Sensor", this->reactive_power_b_sensor_);
ESP_LOGCONFIG(TAG, " USE_ACC_ENERGY_REGS: %d", this->use_acc_energy_regs_);
ESP_LOGCONFIG(TAG, " PGA_V_8: 0x%X", pga_v_);
ESP_LOGCONFIG(TAG, " PGA_IA_8: 0x%X", pga_ia_);
ESP_LOGCONFIG(TAG, " PGA_IB_8: 0x%X", pga_ib_);
@@ -85,6 +90,7 @@ void ADE7953::update() {
uint32_t val;
uint16_t val_16;
uint16_t reg;
// Power factor
err = this->ade_read_16(0x010A, &val_16);
@@ -92,23 +98,36 @@ void ADE7953::update() {
err = this->ade_read_16(0x010B, &val_16);
ADE_PUBLISH(power_factor_b, (int16_t) val_16, (0x7FFF / 100.0f));
float pf = ADE_POWER_FACTOR;
if (this->use_acc_energy_regs_) {
const uint32_t now = millis();
const auto diff = now - this->last_update_;
this->last_update_ = now;
// prevent DIV/0
pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000;
ESP_LOGVV(TAG, "ADE7953::update() diff=%d pf=%f", diff, pf);
}
// Apparent power
err = this->ade_read_32(0x0310, &val);
ADE_PUBLISH(apparent_power_a, (int32_t) val, 154.0f);
err = this->ade_read_32(0x0311, &val);
ADE_PUBLISH(apparent_power_b, (int32_t) val, 154.0f);
reg = this->use_acc_energy_regs_ ? 0x0322 : 0x0310;
err = this->ade_read_32(reg, &val);
ADE_PUBLISH(apparent_power_a, (int32_t) val, pf);
err = this->ade_read_32(reg + 1, &val);
ADE_PUBLISH(apparent_power_b, (int32_t) val, pf);
// Active power
err = this->ade_read_32(0x0312, &val);
ADE_PUBLISH(active_power_a, (int32_t) val, 154.0f);
err = this->ade_read_32(0x0313, &val);
ADE_PUBLISH(active_power_b, (int32_t) val, 154.0f);
reg = this->use_acc_energy_regs_ ? 0x031E : 0x0312;
err = this->ade_read_32(reg, &val);
ADE_PUBLISH(active_power_a, (int32_t) val, pf);
err = this->ade_read_32(reg + 1, &val);
ADE_PUBLISH(active_power_b, (int32_t) val, pf);
// Reactive power
err = this->ade_read_32(0x0314, &val);
ADE_PUBLISH(reactive_power_a, (int32_t) val, 154.0f);
err = this->ade_read_32(0x0315, &val);
ADE_PUBLISH(reactive_power_b, (int32_t) val, 154.0f);
reg = this->use_acc_energy_regs_ ? 0x0320 : 0x0314;
err = this->ade_read_32(reg, &val);
ADE_PUBLISH(reactive_power_a, (int32_t) val, pf);
err = this->ade_read_32(reg + 1, &val);
ADE_PUBLISH(reactive_power_b, (int32_t) val, pf);
// Current
err = this->ade_read_32(0x031A, &val);
@@ -52,6 +52,8 @@ class ADE7953 : public PollingComponent, public sensor::Sensor {
void set_awgain(uint32_t awgain) { awgain_ = awgain; }
void set_bwgain(uint32_t bwgain) { bwgain_ = bwgain; }
void set_use_acc_energy_regs(bool use_acc_energy_regs) { use_acc_energy_regs_ = use_acc_energy_regs; }
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; }
@@ -103,6 +105,8 @@ class ADE7953 : public PollingComponent, public sensor::Sensor {
uint32_t bigain_;
uint32_t awgain_;
uint32_t bwgain_;
bool use_acc_energy_regs_{false};
uint32_t last_update_;
virtual bool ade_write_8(uint16_t reg, uint8_t value) = 0;
+19 -19
View File
@@ -13,29 +13,29 @@ void AdE7953I2c::dump_config() {
ade7953_base::ADE7953::dump_config();
}
bool AdE7953I2c::ade_write_8(uint16_t reg, uint8_t value) {
std::vector<uint8_t> data(3);
data.push_back(reg >> 8);
data.push_back(reg >> 0);
data.push_back(value);
return this->write(data.data(), data.size()) != i2c::ERROR_OK;
uint8_t data[3];
data[0] = reg >> 8;
data[1] = reg >> 0;
data[2] = value;
return this->write(data, 3) != i2c::ERROR_OK;
}
bool AdE7953I2c::ade_write_16(uint16_t reg, uint16_t value) {
std::vector<uint8_t> data(4);
data.push_back(reg >> 8);
data.push_back(reg >> 0);
data.push_back(value >> 8);
data.push_back(value >> 0);
return this->write(data.data(), data.size()) != i2c::ERROR_OK;
uint8_t data[4];
data[0] = reg >> 8;
data[1] = reg >> 0;
data[2] = value >> 8;
data[3] = value >> 0;
return this->write(data, 4) != i2c::ERROR_OK;
}
bool AdE7953I2c::ade_write_32(uint16_t reg, uint32_t value) {
std::vector<uint8_t> data(6);
data.push_back(reg >> 8);
data.push_back(reg >> 0);
data.push_back(value >> 24);
data.push_back(value >> 16);
data.push_back(value >> 8);
data.push_back(value >> 0);
return this->write(data.data(), data.size()) != i2c::ERROR_OK;
uint8_t data[6];
data[0] = reg >> 8;
data[1] = reg >> 0;
data[2] = value >> 24;
data[3] = value >> 16;
data[4] = value >> 8;
data[5] = value >> 0;
return this->write(data, 6) != i2c::ERROR_OK;
}
bool AdE7953I2c::ade_read_8(uint16_t reg, uint8_t *value) {
uint8_t reg_data[2];
+2 -1
View File
@@ -4,13 +4,14 @@ from esphome.components import i2c
from esphome.const import CONF_ID
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["sensor", "voltage_sampler"]
MULTI_CONF = True
ads1115_ns = cg.esphome_ns.namespace("ads1115")
ADS1115Component = ads1115_ns.class_("ADS1115Component", cg.Component, i2c.I2CDevice)
CONF_CONTINUOUS_MODE = "continuous_mode"
CONF_ADS1115_ID = "ads1115_id"
CONFIG_SCHEMA = (
cv.Schema(
{
+8 -23
View File
@@ -1,6 +1,6 @@
#include "ads1115.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ads1115 {
@@ -75,25 +75,19 @@ void ADS1115Component::dump_config() {
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with ADS1115 failed!");
}
for (auto *sensor : this->sensors_) {
LOG_SENSOR(" ", "Sensor", sensor);
ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer());
ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain());
ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution());
}
}
float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
ADS1115Resolution resolution) {
uint16_t config = this->prev_config_;
// Multiplexer
// 0bxBBBxxxxxxxxxxxx
config &= 0b1000111111111111;
config |= (sensor->get_multiplexer() & 0b111) << 12;
config |= (multiplexer & 0b111) << 12;
// Gain
// 0bxxxxBBBxxxxxxxxx
config &= 0b1111000111111111;
config |= (sensor->get_gain() & 0b111) << 9;
config |= (gain & 0b111) << 9;
if (!this->continuous_mode_) {
// Start conversion
@@ -132,7 +126,7 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
return NAN;
}
if (sensor->get_resolution() == ADS1015_12_BITS) {
if (resolution == ADS1015_12_BITS) {
bool negative = (raw_conversion >> 15) == 1;
// shift raw_conversion as it's only 12-bits, left justified
@@ -151,8 +145,8 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
auto signed_conversion = static_cast<int16_t>(raw_conversion);
float millivolts;
float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f;
switch (sensor->get_gain()) {
float divider = (resolution == ADS1115_16_BITS) ? 32768.0f : 2048.0f;
switch (gain) {
case ADS1115_GAIN_6P144:
millivolts = (signed_conversion * 6144) / divider;
break;
@@ -179,14 +173,5 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
return millivolts / 1e3f;
}
float ADS1115Sensor::sample() { return this->parent_->request_measurement(this); }
void ADS1115Sensor::update() {
float v = this->parent_->request_measurement(this);
if (!std::isnan(v)) {
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
this->publish_state(v);
}
}
} // namespace ads1115
} // namespace esphome
+2 -29
View File
@@ -1,9 +1,7 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
#include "esphome/core/component.h"
#include <vector>
@@ -35,12 +33,8 @@ enum ADS1115Resolution {
ADS1015_12_BITS = 12,
};
class ADS1115Sensor;
class ADS1115Component : public Component, public i2c::I2CDevice {
public:
void register_sensor(ADS1115Sensor *obj) { this->sensors_.push_back(obj); }
/// Set up the internal sensor array.
void setup() override;
void dump_config() override;
/// HARDWARE_LATE setup priority
@@ -48,33 +42,12 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
/// Helper method to request a measurement from a sensor.
float request_measurement(ADS1115Sensor *sensor);
float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution);
protected:
std::vector<ADS1115Sensor *> sensors_;
uint16_t prev_config_{0};
bool continuous_mode_;
};
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
public:
ADS1115Sensor(ADS1115Component *parent) : parent_(parent) {}
void update() override;
void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; }
void set_gain(ADS1115Gain gain) { gain_ = gain; }
void set_resolution(ADS1115Resolution resolution) { resolution_ = resolution; }
float sample() override;
uint8_t get_multiplexer() const { return multiplexer_; }
uint8_t get_gain() const { return gain_; }
uint8_t get_resolution() const { return resolution_; }
protected:
ADS1115Component *parent_;
ADS1115Multiplexer multiplexer_;
ADS1115Gain gain_;
ADS1115Resolution resolution_;
};
} // namespace ads1115
} // namespace esphome
@@ -10,8 +10,9 @@ from esphome.const import (
UNIT_VOLT,
CONF_ID,
)
from . import ads1115_ns, ADS1115Component
from .. import ads1115_ns, ADS1115Component, CONF_ADS1115_ID
AUTO_LOAD = ["voltage_sampler"]
DEPENDENCIES = ["ads1115"]
ADS1115Multiplexer = ads1115_ns.enum("ADS1115Multiplexer")
@@ -43,20 +44,10 @@ RESOLUTION = {
}
def validate_gain(value):
if isinstance(value, float):
value = f"{value:0.03f}"
elif not isinstance(value, str):
raise cv.Invalid(f'invalid gain "{value}"')
return cv.enum(GAIN)(value)
ADS1115Sensor = ads1115_ns.class_(
"ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
)
CONF_ADS1115_ID = "ads1115_id"
CONFIG_SCHEMA = (
sensor.sensor_schema(
ADS1115Sensor,
@@ -69,7 +60,7 @@ CONFIG_SCHEMA = (
{
cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
cv.Required(CONF_GAIN): validate_gain,
cv.Required(CONF_GAIN): cv.enum(GAIN, string=True),
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
RESOLUTION, upper=True, space="_"
),
@@ -80,13 +71,11 @@ CONFIG_SCHEMA = (
async def to_code(config):
paren = await cg.get_variable(config[CONF_ADS1115_ID])
var = cg.new_Pvariable(config[CONF_ID], paren)
var = cg.new_Pvariable(config[CONF_ID])
await sensor.register_sensor(var, config)
await cg.register_component(var, config)
await cg.register_parented(var, config[CONF_ADS1115_ID])
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
cg.add(var.set_gain(config[CONF_GAIN]))
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
cg.add(paren.register_sensor(var))
@@ -0,0 +1,30 @@
#include "ads1115_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ads1115 {
static const char *const TAG = "ads1115.sensor";
float ADS1115Sensor::sample() {
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_);
}
void ADS1115Sensor::update() {
float v = this->sample();
if (!std::isnan(v)) {
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
this->publish_state(v);
}
}
void ADS1115Sensor::dump_config() {
LOG_SENSOR(" ", "ADS1115 Sensor", this);
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_);
}
} // namespace ads1115
} // namespace esphome
@@ -0,0 +1,35 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
#include "../ads1115.h"
namespace esphome {
namespace ads1115 {
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
class ADS1115Sensor : public sensor::Sensor,
public PollingComponent,
public voltage_sampler::VoltageSampler,
public Parented<ADS1115Component> {
public:
void update() override;
void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
void set_gain(ADS1115Gain gain) { this->gain_ = gain; }
void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; }
float sample() override;
void dump_config() override;
protected:
ADS1115Multiplexer multiplexer_;
ADS1115Gain gain_;
ADS1115Resolution resolution_;
};
} // namespace ads1115
} // namespace esphome
+25
View File
@@ -0,0 +1,25 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import spi
from esphome.const import CONF_ID
CODEOWNERS = ["@solomondg1"]
DEPENDENCIES = ["spi"]
MULTI_CONF = True
CONF_ADS1118_ID = "ads1118_id"
ads1118_ns = cg.esphome_ns.namespace("ads1118")
ADS1118 = ads1118_ns.class_("ADS1118", cg.Component, spi.SPIDevice)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(ADS1118),
}
).extend(spi.spi_device_schema(cs_pin_required=True))
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await spi.register_spi_device(var, config)
+126
View File
@@ -0,0 +1,126 @@
#include "ads1118.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ads1118 {
static const char *const TAG = "ads1118";
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
void ADS1118::setup() {
ESP_LOGCONFIG(TAG, "Setting up ads1118");
this->spi_setup();
this->config_ = 0;
// Setup multiplexer
// 0bx000xxxxxxxxxxxx
this->config_ |= ADS1118_MULTIPLEXER_P0_NG << 12;
// Setup Gain
// 0bxxxx000xxxxxxxxx
this->config_ |= ADS1118_GAIN_6P144 << 9;
// Set singleshot mode
// 0bxxxxxxx1xxxxxxxx
this->config_ |= 0b0000000100000000;
// Set data rate - 860 samples per second (we're in singleshot mode)
// 0bxxxxxxxx100xxxxx
this->config_ |= ADS1118_DATA_RATE_860_SPS << 5;
// Set temperature sensor mode - ADC
// 0bxxxxxxxxxxx0xxxx
this->config_ |= 0b0000000000000000;
// Set DOUT pull up - enable
// 0bxxxxxxxxxxxx0xxx
this->config_ |= 0b0000000000001000;
// NOP - must be 01
// 0bxxxxxxxxxxxxx01x
this->config_ |= 0b0000000000000010;
// Not used - can be 0 or 1, lets be positive
// 0bxxxxxxxxxxxxxxx1
this->config_ |= 0b0000000000000001;
}
void ADS1118::dump_config() {
ESP_LOGCONFIG(TAG, "ADS1118:");
LOG_PIN(" CS Pin:", this->cs_);
}
float ADS1118::request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode) {
uint16_t temp_config = this->config_;
// Multiplexer
// 0bxBBBxxxxxxxxxxxx
temp_config &= 0b1000111111111111;
temp_config |= (multiplexer & 0b111) << 12;
// Gain
// 0bxxxxBBBxxxxxxxxx
temp_config &= 0b1111000111111111;
temp_config |= (gain & 0b111) << 9;
if (temperature_mode) {
// Set temperature sensor mode
// 0bxxxxxxxxxxx1xxxx
temp_config |= 0b0000000000010000;
} else {
// Set ADC mode
// 0bxxxxxxxxxxx0xxxx
temp_config &= 0b1111111111101111;
}
// Start conversion
temp_config |= 0b1000000000000000;
this->enable();
this->write_byte16(temp_config);
this->disable();
// about 1.2 ms with 860 samples per second
delay(2);
this->enable();
uint8_t adc_first_byte = this->read_byte();
uint8_t adc_second_byte = this->read_byte();
this->disable();
uint16_t raw_conversion = encode_uint16(adc_first_byte, adc_second_byte);
auto signed_conversion = static_cast<int16_t>(raw_conversion);
if (temperature_mode) {
return (signed_conversion >> 2) * 0.03125f;
} else {
float millivolts;
float divider = 32768.0f;
switch (gain) {
case ADS1118_GAIN_6P144:
millivolts = (signed_conversion * 6144) / divider;
break;
case ADS1118_GAIN_4P096:
millivolts = (signed_conversion * 4096) / divider;
break;
case ADS1118_GAIN_2P048:
millivolts = (signed_conversion * 2048) / divider;
break;
case ADS1118_GAIN_1P024:
millivolts = (signed_conversion * 1024) / divider;
break;
case ADS1118_GAIN_0P512:
millivolts = (signed_conversion * 512) / divider;
break;
case ADS1118_GAIN_0P256:
millivolts = (signed_conversion * 256) / divider;
break;
default:
millivolts = NAN;
}
return millivolts / 1e3f;
}
}
} // namespace ads1118
} // namespace esphome
+46
View File
@@ -0,0 +1,46 @@
#pragma once
#include "esphome/components/spi/spi.h"
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace ads1118 {
enum ADS1118Multiplexer {
ADS1118_MULTIPLEXER_P0_N1 = 0b000,
ADS1118_MULTIPLEXER_P0_N3 = 0b001,
ADS1118_MULTIPLEXER_P1_N3 = 0b010,
ADS1118_MULTIPLEXER_P2_N3 = 0b011,
ADS1118_MULTIPLEXER_P0_NG = 0b100,
ADS1118_MULTIPLEXER_P1_NG = 0b101,
ADS1118_MULTIPLEXER_P2_NG = 0b110,
ADS1118_MULTIPLEXER_P3_NG = 0b111,
};
enum ADS1118Gain {
ADS1118_GAIN_6P144 = 0b000,
ADS1118_GAIN_4P096 = 0b001,
ADS1118_GAIN_2P048 = 0b010,
ADS1118_GAIN_1P024 = 0b011,
ADS1118_GAIN_0P512 = 0b100,
ADS1118_GAIN_0P256 = 0b101,
};
class ADS1118 : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_TRAILING,
spi::DATA_RATE_1MHZ> {
public:
ADS1118() = default;
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/// Helper method to request a measurement from a sensor.
float request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode);
protected:
uint16_t config_{0};
};
} // namespace ads1118
} // namespace esphome
@@ -0,0 +1,97 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, voltage_sampler
from esphome.const import (
CONF_GAIN,
CONF_MULTIPLEXER,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_VOLT,
CONF_TYPE,
)
from .. import ads1118_ns, ADS1118, CONF_ADS1118_ID
AUTO_LOAD = ["voltage_sampler"]
DEPENDENCIES = ["ads1118"]
ADS1118Multiplexer = ads1118_ns.enum("ADS1118Multiplexer")
MUX = {
"A0_A1": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P0_N1,
"A0_A3": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P0_N3,
"A1_A3": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P1_N3,
"A2_A3": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P2_N3,
"A0_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P0_NG,
"A1_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P1_NG,
"A2_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P2_NG,
"A3_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P3_NG,
}
ADS1118Gain = ads1118_ns.enum("ADS1118Gain")
GAIN = {
"6.144": ADS1118Gain.ADS1118_GAIN_6P144,
"4.096": ADS1118Gain.ADS1118_GAIN_4P096,
"2.048": ADS1118Gain.ADS1118_GAIN_2P048,
"1.024": ADS1118Gain.ADS1118_GAIN_1P024,
"0.512": ADS1118Gain.ADS1118_GAIN_0P512,
"0.256": ADS1118Gain.ADS1118_GAIN_0P256,
}
ADS1118Sensor = ads1118_ns.class_(
"ADS1118Sensor",
cg.PollingComponent,
sensor.Sensor,
voltage_sampler.VoltageSampler,
cg.Parented.template(ADS1118),
)
TYPE_ADC = "adc"
TYPE_TEMPERATURE = "temperature"
CONFIG_SCHEMA = cv.typed_schema(
{
TYPE_ADC: sensor.sensor_schema(
ADS1118Sensor,
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=3,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.GenerateID(CONF_ADS1118_ID): cv.use_id(ADS1118),
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
cv.Required(CONF_GAIN): cv.enum(GAIN, string=True),
}
)
.extend(cv.polling_component_schema("60s")),
TYPE_TEMPERATURE: sensor.sensor_schema(
ADS1118Sensor,
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=2,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.GenerateID(CONF_ADS1118_ID): cv.use_id(ADS1118),
}
)
.extend(cv.polling_component_schema("60s")),
},
default_type=TYPE_ADC,
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
await cg.register_parented(var, config[CONF_ADS1118_ID])
if config[CONF_TYPE] == TYPE_ADC:
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
cg.add(var.set_gain(config[CONF_GAIN]))
if config[CONF_TYPE] == TYPE_TEMPERATURE:
cg.add(var.set_temperature_mode(True))
@@ -0,0 +1,29 @@
#include "ads1118_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ads1118 {
static const char *const TAG = "ads1118.sensor";
void ADS1118Sensor::dump_config() {
LOG_SENSOR(" ", "ADS1118 Sensor", this);
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
}
float ADS1118Sensor::sample() {
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->temperature_mode_);
}
void ADS1118Sensor::update() {
float v = this->sample();
if (!std::isnan(v)) {
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
this->publish_state(v);
}
}
} // namespace ads1118
} // namespace esphome
@@ -0,0 +1,36 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
#include "../ads1118.h"
namespace esphome {
namespace ads1118 {
class ADS1118Sensor : public PollingComponent,
public sensor::Sensor,
public voltage_sampler::VoltageSampler,
public Parented<ADS1118> {
public:
void update() override;
void set_multiplexer(ADS1118Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
void set_gain(ADS1118Gain gain) { this->gain_ = gain; }
void set_temperature_mode(bool temp) { this->temperature_mode_ = temp; }
float sample() override;
void dump_config() override;
protected:
ADS1118Multiplexer multiplexer_{ADS1118_MULTIPLEXER_P0_NG};
ADS1118Gain gain_{ADS1118_GAIN_6P144};
bool temperature_mode_;
};
} // namespace ads1118
} // namespace esphome
+1
View File
@@ -0,0 +1 @@
CODEOWNERS = ["@mak-42"]
+212
View File
@@ -0,0 +1,212 @@
#include "ags10.h"
namespace esphome {
namespace ags10 {
static const char *const TAG = "ags10";
// Data acquisition.
static const uint8_t REG_TVOC = 0x00;
// Zero-point calibration.
static const uint8_t REG_CALIBRATION = 0x01;
// Read version.
static const uint8_t REG_VERSION = 0x11;
// Read current resistance.
static const uint8_t REG_RESISTANCE = 0x20;
// Modify target address.
static const uint8_t REG_ADDRESS = 0x21;
// Zero-point calibration with current resistance.
static const uint16_t ZP_CURRENT = 0x0000;
// Zero-point reset.
static const uint16_t ZP_DEFAULT = 0xFFFF;
void AGS10Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up ags10...");
auto version = this->read_version_();
if (version) {
ESP_LOGD(TAG, "AGS10 Sensor Version: 0x%02X", *version);
if (this->version_ != nullptr) {
this->version_->publish_state(*version);
}
} else {
ESP_LOGE(TAG, "AGS10 Sensor Version: unknown");
}
auto resistance = this->read_resistance_();
if (resistance) {
ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08X", *resistance);
if (this->resistance_ != nullptr) {
this->resistance_->publish_state(*resistance);
}
} else {
ESP_LOGE(TAG, "AGS10 Sensor Resistance: unknown");
}
ESP_LOGD(TAG, "Sensor initialized");
}
void AGS10Component::update() {
auto tvoc = this->read_tvoc_();
if (tvoc) {
this->tvoc_->publish_state(*tvoc);
this->status_clear_warning();
} else {
this->status_set_warning();
}
}
void AGS10Component::dump_config() {
ESP_LOGCONFIG(TAG, "AGS10:");
LOG_I2C_DEVICE(this);
switch (this->error_code_) {
case NONE:
break;
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Communication with AGS10 failed!");
break;
case CRC_CHECK_FAILED:
ESP_LOGE(TAG, "The crc check failed");
break;
case ILLEGAL_STATUS:
ESP_LOGE(TAG, "AGS10 is not ready to return TVOC data or sensor in pre-heat stage.");
break;
case UNSUPPORTED_UNITS:
ESP_LOGE(TAG, "AGS10 returns TVOC data in unsupported units.");
break;
default:
ESP_LOGE(TAG, "Unknown error: %d", this->error_code_);
break;
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "TVOC Sensor", this->tvoc_);
LOG_SENSOR(" ", "Firmware Version Sensor", this->version_);
LOG_SENSOR(" ", "Resistance Sensor", this->resistance_);
}
/**
* Sets new I2C address of AGS10.
*/
bool AGS10Component::new_i2c_address(uint8_t newaddress) {
uint8_t rev_newaddress = ~newaddress;
std::array<uint8_t, 5> data{newaddress, rev_newaddress, newaddress, rev_newaddress, 0};
data[4] = calc_crc8_(data, 4);
if (!this->write_bytes(REG_ADDRESS, data)) {
this->error_code_ = COMMUNICATION_FAILED;
this->status_set_warning();
ESP_LOGE(TAG, "couldn't write the new I2C address 0x%02X", newaddress);
return false;
}
this->set_i2c_address(newaddress);
ESP_LOGW(TAG, "changed I2C address to 0x%02X", newaddress);
this->error_code_ = NONE;
this->status_clear_warning();
return true;
}
bool AGS10Component::set_zero_point_with_factory_defaults() { return this->set_zero_point_with(ZP_DEFAULT); }
bool AGS10Component::set_zero_point_with_current_resistance() { return this->set_zero_point_with(ZP_CURRENT); }
bool AGS10Component::set_zero_point_with(uint16_t value) {
std::array<uint8_t, 5> data{0x00, 0x0C, (uint8_t) ((value >> 8) & 0xFF), (uint8_t) (value & 0xFF), 0};
data[4] = calc_crc8_(data, 4);
if (!this->write_bytes(REG_CALIBRATION, data)) {
this->error_code_ = COMMUNICATION_FAILED;
this->status_set_warning();
ESP_LOGE(TAG, "unable to set zero-point calibration with 0x%02X", value);
return false;
}
if (value == ZP_CURRENT) {
ESP_LOGI(TAG, "zero-point calibration has been set with current resistance");
} else if (value == ZP_DEFAULT) {
ESP_LOGI(TAG, "zero-point calibration has been reset to the factory defaults");
} else {
ESP_LOGI(TAG, "zero-point calibration has been set with 0x%02X", value);
}
this->error_code_ = NONE;
this->status_clear_warning();
return true;
}
optional<uint32_t> AGS10Component::read_tvoc_() {
auto data = this->read_and_check_<5>(REG_TVOC);
if (!data) {
return nullopt;
}
auto res = *data;
auto status_byte = res[0];
int units = status_byte & 0x0e;
int status_bit = status_byte & 0x01;
if (status_bit != 0) {
this->error_code_ = ILLEGAL_STATUS;
ESP_LOGW(TAG, "Reading AGS10 data failed: illegal status (not ready or sensor in pre-heat stage)!");
return nullopt;
}
if (units != 0) {
this->error_code_ = UNSUPPORTED_UNITS;
ESP_LOGE(TAG, "Reading AGS10 data failed: unsupported units (%d)!", units);
return nullopt;
}
return encode_uint24(res[1], res[2], res[3]);
}
optional<uint8_t> AGS10Component::read_version_() {
auto data = this->read_and_check_<5>(REG_VERSION);
if (data) {
auto res = *data;
return res[3];
}
return nullopt;
}
optional<uint32_t> AGS10Component::read_resistance_() {
auto data = this->read_and_check_<5>(REG_RESISTANCE);
if (data) {
auto res = *data;
return encode_uint32(res[0], res[1], res[2], res[3]);
}
return nullopt;
}
template<size_t N> optional<std::array<uint8_t, N>> AGS10Component::read_and_check_(uint8_t a_register) {
auto data = this->read_bytes<N>(a_register);
if (!data.has_value()) {
this->error_code_ = COMMUNICATION_FAILED;
ESP_LOGE(TAG, "Reading AGS10 version failed!");
return optional<std::array<uint8_t, N>>();
}
auto len = N - 1;
auto res = *data;
auto crc_byte = res[len];
if (crc_byte != calc_crc8_(res, len)) {
this->error_code_ = CRC_CHECK_FAILED;
ESP_LOGE(TAG, "Reading AGS10 version failed: crc error!");
return optional<std::array<uint8_t, N>>();
}
return data;
}
template<size_t N> uint8_t AGS10Component::calc_crc8_(std::array<uint8_t, N> dat, uint8_t num) {
uint8_t i, byte1, crc = 0xFF;
for (byte1 = 0; byte1 < num; byte1++) {
crc ^= (dat[byte1]);
for (i = 0; i < 8; i++) {
if (crc & 0x80) {
crc = (crc << 1) ^ 0x31;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
} // namespace ags10
} // namespace esphome
+152
View File
@@ -0,0 +1,152 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace ags10 {
class AGS10Component : public PollingComponent, public i2c::I2CDevice {
public:
/**
* Sets TVOC sensor.
*/
void set_tvoc(sensor::Sensor *tvoc) { this->tvoc_ = tvoc; }
/**
* Sets version info sensor.
*/
void set_version(sensor::Sensor *version) { this->version_ = version; }
/**
* Sets resistance info sensor.
*/
void set_resistance(sensor::Sensor *resistance) { this->resistance_ = resistance; }
void setup() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/**
* Modifies target address of AGS10.
*
* New address is saved and takes effect immediately even after power-off.
*/
bool new_i2c_address(uint8_t newaddress);
/**
* Sets zero-point with factory defaults.
*/
bool set_zero_point_with_factory_defaults();
/**
* Sets zero-point with current sensor resistance.
*/
bool set_zero_point_with_current_resistance();
/**
* Sets zero-point with the value.
*/
bool set_zero_point_with(uint16_t value);
protected:
/**
* TVOC.
*/
sensor::Sensor *tvoc_{nullptr};
/**
* Firmvare version.
*/
sensor::Sensor *version_{nullptr};
/**
* Resistance.
*/
sensor::Sensor *resistance_{nullptr};
/**
* Last operation error code.
*/
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
CRC_CHECK_FAILED,
ILLEGAL_STATUS,
UNSUPPORTED_UNITS,
} error_code_{NONE};
/**
* Reads and returns value of TVOC.
*/
optional<uint32_t> read_tvoc_();
/**
* Reads and returns a firmware version of AGS10.
*/
optional<uint8_t> read_version_();
/**
* Reads and returns the resistance of AGS10.
*/
optional<uint32_t> read_resistance_();
/**
* Read, checks and returns data from the sensor.
*/
template<size_t N> optional<std::array<uint8_t, N>> read_and_check_(uint8_t a_register);
/**
* Calculates CRC8 value.
*
* CRC8 calculation, initial value: 0xFF, polynomial: 0x31 (x8+ x5+ x4+1)
*
* @param[in] dat the data buffer
* @param num number of bytes in the buffer
*/
template<size_t N> uint8_t calc_crc8_(std::array<uint8_t, N> dat, uint8_t num);
};
template<typename... Ts> class AGS10NewI2cAddressAction : public Action<Ts...>, public Parented<AGS10Component> {
public:
TEMPLATABLE_VALUE(uint8_t, new_address)
void play(Ts... x) override { this->parent_->new_i2c_address(this->new_address_.value(x...)); }
};
enum AGS10SetZeroPointActionMode {
// Zero-point reset.
FACTORY_DEFAULT,
// Zero-point calibration with current resistance.
CURRENT_VALUE,
// Zero-point calibration with custom resistance.
CUSTOM_VALUE,
};
template<typename... Ts> class AGS10SetZeroPointAction : public Action<Ts...>, public Parented<AGS10Component> {
public:
TEMPLATABLE_VALUE(uint16_t, value)
TEMPLATABLE_VALUE(AGS10SetZeroPointActionMode, mode)
void play(Ts... x) override {
switch (this->mode_.value(x...)) {
case FACTORY_DEFAULT:
this->parent_->set_zero_point_with_factory_defaults();
break;
case CURRENT_VALUE:
this->parent_->set_zero_point_with_current_resistance();
break;
case CUSTOM_VALUE:
this->parent_->set_zero_point_with(this->value_.value(x...));
break;
}
}
};
} // namespace ags10
} // namespace esphome
+132
View File
@@ -0,0 +1,132 @@
import esphome.codegen as cg
from esphome import automation
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
ICON_RADIATOR,
ICON_RESTART,
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
ENTITY_CATEGORY_DIAGNOSTIC,
STATE_CLASS_MEASUREMENT,
UNIT_OHM,
UNIT_PARTS_PER_BILLION,
CONF_ADDRESS,
CONF_TVOC,
CONF_VERSION,
CONF_MODE,
CONF_VALUE,
)
CONF_RESISTANCE = "resistance"
DEPENDENCIES = ["i2c"]
ags10_ns = cg.esphome_ns.namespace("ags10")
AGS10Component = ags10_ns.class_("AGS10Component", cg.PollingComponent, i2c.I2CDevice)
# Actions
AGS10NewI2cAddressAction = ags10_ns.class_(
"AGS10NewI2cAddressAction", automation.Action
)
AGS10SetZeroPointAction = ags10_ns.class_("AGS10SetZeroPointAction", automation.Action)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(AGS10Component),
cv.Optional(CONF_TVOC): sensor.sensor_schema(
unit_of_measurement=UNIT_PARTS_PER_BILLION,
icon=ICON_RADIATOR,
accuracy_decimals=0,
device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_VERSION): sensor.sensor_schema(
icon=ICON_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
cv.Optional(CONF_RESISTANCE): sensor.sensor_schema(
unit_of_measurement=UNIT_OHM,
icon=ICON_RESTART,
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x1A))
)
FINAL_VALIDATE_SCHEMA = i2c.final_validate_device_schema("ags10", max_frequency="15khz")
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
sens = await sensor.new_sensor(config[CONF_TVOC])
cg.add(var.set_tvoc(sens))
if version_config := config.get(CONF_VERSION):
sens = await sensor.new_sensor(version_config)
cg.add(var.set_version(sens))
if resistance_config := config.get(CONF_RESISTANCE):
sens = await sensor.new_sensor(resistance_config)
cg.add(var.set_resistance(sens))
AGS10_NEW_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(AGS10Component),
cv.Required(CONF_ADDRESS): cv.templatable(cv.i2c_address),
},
key=CONF_ADDRESS,
)
@automation.register_action(
"ags10.new_i2c_address",
AGS10NewI2cAddressAction,
AGS10_NEW_I2C_ADDRESS_SCHEMA,
)
async def ags10newi2caddress_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
address = await cg.templatable(config[CONF_ADDRESS], args, int)
cg.add(var.set_new_address(address))
return var
AGS10SetZeroPointActionMode = ags10_ns.enum("AGS10SetZeroPointActionMode")
AGS10_SET_ZERO_POINT_ACTION_MODE = {
"FACTORY_DEFAULT": AGS10SetZeroPointActionMode.FACTORY_DEFAULT,
"CURRENT_VALUE": AGS10SetZeroPointActionMode.CURRENT_VALUE,
"CUSTOM_VALUE": AGS10SetZeroPointActionMode.CUSTOM_VALUE,
}
AGS10_SET_ZERO_POINT_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(AGS10Component),
cv.Required(CONF_MODE): cv.enum(AGS10_SET_ZERO_POINT_ACTION_MODE, upper=True),
cv.Optional(CONF_VALUE, default=0xFFFF): cv.templatable(cv.uint16_t),
},
)
@automation.register_action(
"ags10.set_zero_point",
AGS10SetZeroPointAction,
AGS10_SET_ZERO_POINT_SCHEMA,
)
async def ags10setzeropoint_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
mode = await cg.templatable(config.get(CONF_MODE), args, enumerate)
cg.add(var.set_mode(mode))
value = await cg.templatable(config[CONF_VALUE], args, int)
cg.add(var.set_value(value))
return var
+77 -67
View File
@@ -15,36 +15,43 @@
#include "aht10.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include <cinttypes>
namespace esphome {
namespace aht10 {
static const char *const TAG = "aht10";
static const size_t SIZE_CALIBRATE_CMD = 3;
static const uint8_t AHT10_CALIBRATE_CMD[] = {0xE1, 0x08, 0x00};
static const uint8_t AHT20_CALIBRATE_CMD[] = {0xBE, 0x08, 0x00};
static const uint8_t AHT10_INITIALIZE_CMD[] = {0xE1, 0x08, 0x00};
static const uint8_t AHT20_INITIALIZE_CMD[] = {0xBE, 0x08, 0x00};
static const uint8_t AHT10_MEASURE_CMD[] = {0xAC, 0x33, 0x00};
static const uint8_t AHT10_DEFAULT_DELAY = 5; // ms, for calibration and temperature measurement
static const uint8_t AHT10_HUMIDITY_DELAY = 30; // ms
static const uint8_t AHT10_ATTEMPTS = 3; // safety margin, normally 3 attempts are enough: 3*30=90ms
static const uint8_t AHT10_CAL_ATTEMPTS = 10;
static const uint8_t AHT10_SOFTRESET_CMD[] = {0xBA};
static const uint8_t AHT10_DEFAULT_DELAY = 5; // ms, for initialization and temperature measurement
static const uint8_t AHT10_READ_DELAY = 80; // ms, time to wait for conversion result
static const uint8_t AHT10_SOFTRESET_DELAY = 30; // ms
static const uint8_t AHT10_ATTEMPTS = 3; // safety margin, normally 3 attempts are enough: 3*30=90ms
static const uint8_t AHT10_INIT_ATTEMPTS = 10;
static const uint8_t AHT10_STATUS_BUSY = 0x80;
void AHT10Component::setup() {
const uint8_t *calibrate_cmd;
if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Reset AHT10 failed!");
}
delay(AHT10_SOFTRESET_DELAY);
i2c::ErrorCode error_code = i2c::ERROR_INVALID_ARGUMENT;
switch (this->variant_) {
case AHT10Variant::AHT20:
calibrate_cmd = AHT20_CALIBRATE_CMD;
ESP_LOGCONFIG(TAG, "Setting up AHT20");
error_code = this->write(AHT20_INITIALIZE_CMD, sizeof(AHT20_INITIALIZE_CMD));
break;
case AHT10Variant::AHT10:
default:
calibrate_cmd = AHT10_CALIBRATE_CMD;
ESP_LOGCONFIG(TAG, "Setting up AHT10");
error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD));
break;
}
if (this->write(calibrate_cmd, SIZE_CALIBRATE_CMD) != i2c::ERROR_OK) {
if (error_code != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with AHT10 failed!");
this->mark_failed();
return;
@@ -59,89 +66,92 @@ void AHT10Component::setup() {
return;
}
++cal_attempts;
if (cal_attempts > AHT10_CAL_ATTEMPTS) {
ESP_LOGE(TAG, "AHT10 calibration timed out!");
if (cal_attempts > AHT10_INIT_ATTEMPTS) {
ESP_LOGE(TAG, "AHT10 initialization timed out!");
this->mark_failed();
return;
}
}
if ((data & 0x68) != 0x08) { // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED
ESP_LOGE(TAG, "AHT10 calibration failed!");
ESP_LOGE(TAG, "AHT10 initialization failed!");
this->mark_failed();
return;
}
ESP_LOGV(TAG, "AHT10 calibrated");
ESP_LOGV(TAG, "AHT10 initialization");
}
void AHT10Component::update() {
if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with AHT10 failed!");
this->status_set_warning();
void AHT10Component::restart_read_() {
if (this->read_count_ == AHT10_ATTEMPTS) {
this->read_count_ = 0;
this->status_set_error("Measurements reading timed-out!");
return;
}
this->read_count_++;
this->set_timeout(AHT10_READ_DELAY, [this]() { this->read_data_(); });
}
void AHT10Component::read_data_() {
uint8_t data[6];
uint8_t delay_ms = AHT10_DEFAULT_DELAY;
if (this->humidity_sensor_ != nullptr)
delay_ms = AHT10_HUMIDITY_DELAY;
bool success = false;
for (int i = 0; i < AHT10_ATTEMPTS; ++i) {
ESP_LOGVV(TAG, "Attempt %d at %6" PRIu32, i, millis());
delay(delay_ms);
if (this->read(data, 6) != i2c::ERROR_OK) {
ESP_LOGD(TAG, "Communication with AHT10 failed, waiting...");
continue;
}
if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy
ESP_LOGD(TAG, "AHT10 is busy, waiting...");
} else if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) {
// Unrealistic humidity (0x0)
if (this->humidity_sensor_ == nullptr) {
ESP_LOGVV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required");
break;
} else {
ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying...");
if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with AHT10 failed!");
this->status_set_warning();
return;
}
}
} else {
// data is valid, we can break the loop
ESP_LOGVV(TAG, "Answer at %6" PRIu32, millis());
success = true;
break;
}
}
if (!success || (data[0] & 0x80) == 0x80) {
ESP_LOGE(TAG, "Measurements reading timed-out!");
this->status_set_warning();
if (this->read_count_ > 1)
ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_));
if (this->read(data, 6) != i2c::ERROR_OK) {
this->status_set_warning("AHT10 read failed, retrying soon");
this->restart_read_();
return;
}
if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy
ESP_LOGD(TAG, "AHT10 is busy, waiting...");
this->restart_read_();
return;
}
if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) {
// Unrealistic humidity (0x0)
if (this->humidity_sensor_ == nullptr) {
ESP_LOGV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required");
} else {
ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying...");
if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
this->status_set_warning("Communication with AHT10 failed!");
}
this->restart_read_();
return;
}
}
if (this->read_count_ > 1)
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_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4;
float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f;
float humidity;
if (raw_humidity == 0) { // unrealistic value
humidity = NAN;
} else {
humidity = (float) raw_humidity * 100.0f / 1048576.0f;
}
if (this->temperature_sensor_ != nullptr) {
float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f;
this->temperature_sensor_->publish_state(temperature);
}
if (this->humidity_sensor_ != nullptr) {
float humidity;
if (raw_humidity == 0) { // unrealistic value
humidity = NAN;
} else {
humidity = (float) raw_humidity * 100.0f / 1048576.0f;
}
if (std::isnan(humidity)) {
ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
}
this->humidity_sensor_->publish_state(humidity);
}
this->status_clear_warning();
this->read_count_ = 0;
}
void AHT10Component::update() {
if (this->read_count_ != 0)
return;
this->start_time_ = millis();
if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
this->status_set_warning("Communication with AHT10 failed!");
return;
}
this->restart_read_();
}
float AHT10Component::get_setup_priority() const { return setup_priority::DATA; }
+4
View File
@@ -26,6 +26,10 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice {
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
AHT10Variant variant_{};
unsigned read_count_{};
void read_data_();
void restart_read_();
uint32_t start_time_{};
};
} // namespace aht10
+5 -3
View File
@@ -97,9 +97,11 @@ void Alpha3::handle_geni_response_(const uint8_t *response, uint16_t length) {
void Alpha3::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
switch (event) {
case ESP_GATTC_OPEN_EVT: {
this->response_offset_ = 0;
this->response_length_ = 0;
ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str().c_str());
if (param->open.status == ESP_GATT_OK) {
this->response_offset_ = 0;
this->response_length_ = 0;
ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str().c_str());
}
break;
}
case ESP_GATTC_CONNECT_EVT: {
+1
View File
@@ -0,0 +1 @@
CODEOWNERS = ["@swoboda1337"]
+200
View File
@@ -0,0 +1,200 @@
// MIT License
//
// Copyright (c) 2023-2024 Rob Tillaart
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "am2315c.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace am2315c {
static const char *const TAG = "am2315c";
uint8_t AM2315C::crc8_(uint8_t *data, uint8_t len) {
uint8_t crc = 0xFF;
while (len--) {
crc ^= *data++;
for (uint8_t i = 0; i < 8; i++) {
if (crc & 0x80) {
crc <<= 1;
crc ^= 0x31;
} else {
crc <<= 1;
}
}
}
return crc;
}
bool AM2315C::reset_register_(uint8_t reg) {
// code based on demo code sent by www.aosong.com
// no further documentation.
// 0x1B returned 18, 0, 4
// 0x1C returned 18, 65, 0
// 0x1E returned 18, 8, 0
// 18 seems to be status register
// other values unknown.
uint8_t data[3];
data[0] = reg;
data[1] = 0;
data[2] = 0;
ESP_LOGD(TAG, "Reset register: 0x%02x", reg);
if (this->write(data, 3) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Write failed!");
this->mark_failed();
return false;
}
delay(5);
if (this->read(data, 3) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Read failed!");
this->mark_failed();
return false;
}
delay(10);
data[0] = 0xB0 | reg;
if (this->write(data, 3) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Write failed!");
this->mark_failed();
return false;
}
delay(5);
return true;
}
bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) {
uint32_t raw;
raw = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4);
humidity = raw * 9.5367431640625e-5;
raw = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
temperature = raw * 1.9073486328125e-4 - 50;
return this->crc8_(data, 6) == data[6];
}
void AM2315C::setup() {
ESP_LOGCONFIG(TAG, "Setting up AM2315C...");
// get status
uint8_t status = 0;
if (this->read(&status, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Read failed!");
this->mark_failed();
return;
}
// reset registers if required, according to the datasheet
// this can be required after power on, although this was
// never required during testing
if ((status & 0x18) != 0x18) {
ESP_LOGD(TAG, "Resetting AM2315C registers");
if (!this->reset_register_(0x1B)) {
this->mark_failed();
return;
}
if (!this->reset_register_(0x1C)) {
this->mark_failed();
return;
}
if (!this->reset_register_(0x1E)) {
this->mark_failed();
return;
}
}
}
void AM2315C::update() {
// request measurement
uint8_t data[3];
data[0] = 0xAC;
data[1] = 0x33;
data[2] = 0x00;
if (this->write(data, 3) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Write failed!");
this->mark_failed();
return;
}
// wait for hw to complete measurement
set_timeout(160, [this]() {
// check status
uint8_t status = 0;
if (this->read(&status, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Read failed!");
this->mark_failed();
return;
}
if ((status & 0x80) == 0x80) {
ESP_LOGE(TAG, "HW still busy!");
this->mark_failed();
return;
}
// read
uint8_t data[7];
if (this->read(data, 7) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Read failed!");
this->mark_failed();
return;
}
// check for all zeros
bool zeros = true;
for (uint8_t i : data) {
zeros = zeros && (i == 0);
}
if (zeros) {
ESP_LOGW(TAG, "Data all zeros!");
this->status_set_warning();
return;
}
// convert
float temperature = 0.0;
float humidity = 0.0;
if (this->convert_(data, humidity, temperature)) {
if (this->temperature_sensor_ != nullptr) {
this->temperature_sensor_->publish_state(temperature);
}
if (this->humidity_sensor_ != nullptr) {
this->humidity_sensor_->publish_state(humidity);
}
this->status_clear_warning();
} else {
ESP_LOGW(TAG, "CRC failed!");
this->status_set_warning();
}
});
}
void AM2315C::dump_config() {
ESP_LOGCONFIG(TAG, "AM2315C:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with AM2315C failed!");
}
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
float AM2315C::get_setup_priority() const { return setup_priority::DATA; }
} // namespace am2315c
} // namespace esphome
+51
View File
@@ -0,0 +1,51 @@
// MIT License
//
// Copyright (c) 2023-2024 Rob Tillaart
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace am2315c {
class AM2315C : public PollingComponent, public i2c::I2CDevice {
public:
void dump_config() override;
void update() override;
void setup() override;
float get_setup_priority() const override;
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
protected:
uint8_t crc8_(uint8_t *data, uint8_t len);
bool convert_(uint8_t *data, float &humidity, float &temperature);
bool reset_register_(uint8_t reg);
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace am2315c
} // namespace esphome
+54
View File
@@ -0,0 +1,54 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_HUMIDITY,
CONF_ID,
CONF_TEMPERATURE,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_PERCENT,
)
DEPENDENCIES = ["i2c"]
am2315c_ns = cg.esphome_ns.namespace("am2315c")
AM2315C = am2315c_ns.class_("AM2315C", cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(AM2315C),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=1,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x38))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
if temperature_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temperature_config)
cg.add(var.set_temperature_sensor(sens))
if humidity_config := config.get(CONF_HUMIDITY):
sens = await sensor.new_sensor(humidity_config)
cg.add(var.set_humidity_sensor(sens))
@@ -26,7 +26,9 @@ void Am43::setup() {
void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
switch (event) {
case ESP_GATTC_OPEN_EVT: {
this->logged_in_ = false;
if (param->open.status == ESP_GATT_OK) {
this->logged_in_ = false;
}
break;
}
case ESP_GATTC_DISCONNECT_EVT: {
+4 -4
View File
@@ -157,7 +157,7 @@ async def to_code(config):
pixels = list(frame.getdata())
if len(pixels) != height * width:
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:
if transparent:
@@ -180,7 +180,7 @@ async def to_code(config):
pixels = list(frame.getdata())
if len(pixels) != height * width:
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:
data[pos] = pix[0]
@@ -203,7 +203,7 @@ async def to_code(config):
pixels = list(frame.getdata())
if len(pixels) != height * width:
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:
if transparent:
@@ -232,7 +232,7 @@ async def to_code(config):
pixels = list(frame.getdata())
if len(pixels) != height * width:
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:
R = r >> 3
+223 -1
View File
@@ -43,7 +43,11 @@ service APIConnection {
rpc select_command (SelectCommandRequest) returns (void) {}
rpc button_command (ButtonCommandRequest) returns (void) {}
rpc lock_command (LockCommandRequest) returns (void) {}
rpc valve_command (ValveCommandRequest) returns (void) {}
rpc media_player_command (MediaPlayerCommandRequest) returns (void) {}
rpc date_command (DateCommandRequest) returns (void) {}
rpc time_command (TimeCommandRequest) returns (void) {}
rpc datetime_command (DateTimeCommandRequest) returns (void) {}
rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {}
@@ -216,7 +220,8 @@ message DeviceInfoResponse {
string friendly_name = 13;
uint32 voice_assistant_version = 14;
uint32 legacy_voice_assistant_version = 14;
uint32 voice_assistant_feature_flags = 17;
string suggested_area = 16;
}
@@ -600,6 +605,7 @@ message ListEntitiesTextSensorResponse {
string icon = 5;
bool disabled_by_default = 6;
EntityCategory entity_category = 7;
string device_class = 8;
}
message TextSensorStateResponse {
option (id) = 27;
@@ -1141,6 +1147,9 @@ message MediaPlayerCommandRequest {
bool has_media_url = 6;
string media_url = 7;
bool has_announcement = 8;
bool announcement = 9;
}
// ==================== BLUETOOTH ====================
@@ -1420,12 +1429,18 @@ message BluetoothDeviceClearCacheResponse {
}
// ==================== PUSH TO TALK ====================
enum VoiceAssistantSubscribeFlag {
VOICE_ASSISTANT_SUBSCRIBE_NONE = 0;
VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1;
}
message SubscribeVoiceAssistantRequest {
option (id) = 89;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
bool subscribe = 1;
uint32 flags = 2;
}
enum VoiceAssistantRequestFlag {
@@ -1449,6 +1464,7 @@ message VoiceAssistantRequest {
string conversation_id = 2;
uint32 flags = 3;
VoiceAssistantAudioSettings audio_settings = 4;
string wake_word_phrase = 5;
}
message VoiceAssistantResponse {
@@ -1492,6 +1508,16 @@ message VoiceAssistantEventResponse {
repeated VoiceAssistantEventData data = 2;
}
message VoiceAssistantAudio {
option (id) = 106;
option (source) = SOURCE_BOTH;
option (ifdef) = "USE_VOICE_ASSISTANT";
bytes data = 1;
bool end = 2;
}
// ==================== ALARM CONTROL PANEL ====================
enum AlarmControlPanelState {
ALARM_STATE_DISARMED = 0;
@@ -1596,3 +1622,199 @@ message TextCommandRequest {
fixed32 key = 1;
string state = 2;
}
// ==================== DATETIME DATE ====================
message ListEntitiesDateResponse {
option (id) = 100;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_DATETIME_DATE";
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;
}
message DateStateResponse {
option (id) = 101;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_DATETIME_DATE";
option (no_delay) = true;
fixed32 key = 1;
// If the date does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 2;
uint32 year = 3;
uint32 month = 4;
uint32 day = 5;
}
message DateCommandRequest {
option (id) = 102;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_DATETIME_DATE";
option (no_delay) = true;
fixed32 key = 1;
uint32 year = 2;
uint32 month = 3;
uint32 day = 4;
}
// ==================== DATETIME TIME ====================
message ListEntitiesTimeResponse {
option (id) = 103;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_DATETIME_TIME";
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;
}
message TimeStateResponse {
option (id) = 104;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_DATETIME_TIME";
option (no_delay) = true;
fixed32 key = 1;
// If the time does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 2;
uint32 hour = 3;
uint32 minute = 4;
uint32 second = 5;
}
message TimeCommandRequest {
option (id) = 105;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_DATETIME_TIME";
option (no_delay) = true;
fixed32 key = 1;
uint32 hour = 2;
uint32 minute = 3;
uint32 second = 4;
}
// ==================== EVENT ====================
message ListEntitiesEventResponse {
option (id) = 107;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_EVENT";
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;
repeated string event_types = 9;
}
message EventResponse {
option (id) = 108;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_EVENT";
fixed32 key = 1;
string event_type = 2;
}
// ==================== VALVE ====================
message ListEntitiesValveResponse {
option (id) = 109;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_VALVE";
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;
bool assumed_state = 9;
bool supports_position = 10;
bool supports_stop = 11;
}
enum ValveOperation {
VALVE_OPERATION_IDLE = 0;
VALVE_OPERATION_IS_OPENING = 1;
VALVE_OPERATION_IS_CLOSING = 2;
}
message ValveStateResponse {
option (id) = 110;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_VALVE";
option (no_delay) = true;
fixed32 key = 1;
float position = 2;
ValveOperation current_operation = 3;
}
message ValveCommandRequest {
option (id) = 111;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VALVE";
option (no_delay) = true;
fixed32 key = 1;
bool has_position = 2;
float position = 3;
bool stop = 4;
}
// ==================== DATETIME DATETIME ====================
message ListEntitiesDateTimeResponse {
option (id) = 112;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_DATETIME_DATETIME";
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;
}
message DateTimeStateResponse {
option (id) = 113;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_DATETIME_DATETIME";
option (no_delay) = true;
fixed32 key = 1;
// If the datetime does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 2;
fixed32 epoch_seconds = 3;
}
message DateTimeCommandRequest {
option (id) = 114;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_DATETIME_DATETIME";
option (no_delay) = true;
fixed32 key = 1;
fixed32 epoch_seconds = 2;
}
+208 -7
View File
@@ -543,6 +543,7 @@ bool APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor)
msg.icon = text_sensor->get_icon();
msg.disabled_by_default = text_sensor->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(text_sensor->get_entity_category());
msg.device_class = text_sensor->get_device_class();
return this->send_list_entities_text_sensor_response(msg);
}
#endif
@@ -697,6 +698,118 @@ void APIConnection::number_command(const NumberCommandRequest &msg) {
}
#endif
#ifdef USE_DATETIME_DATE
bool APIConnection::send_date_state(datetime::DateEntity *date) {
if (!this->state_subscription_)
return false;
DateStateResponse resp{};
resp.key = date->get_object_id_hash();
resp.missing_state = !date->has_state();
resp.year = date->year;
resp.month = date->month;
resp.day = date->day;
return this->send_date_state_response(resp);
}
bool APIConnection::send_date_info(datetime::DateEntity *date) {
ListEntitiesDateResponse msg;
msg.key = date->get_object_id_hash();
msg.object_id = date->get_object_id();
if (date->has_own_name())
msg.name = date->get_name();
msg.unique_id = get_default_unique_id("date", date);
msg.icon = date->get_icon();
msg.disabled_by_default = date->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(date->get_entity_category());
return this->send_list_entities_date_response(msg);
}
void APIConnection::date_command(const DateCommandRequest &msg) {
datetime::DateEntity *date = App.get_date_by_key(msg.key);
if (date == nullptr)
return;
auto call = date->make_call();
call.set_date(msg.year, msg.month, msg.day);
call.perform();
}
#endif
#ifdef USE_DATETIME_TIME
bool APIConnection::send_time_state(datetime::TimeEntity *time) {
if (!this->state_subscription_)
return false;
TimeStateResponse resp{};
resp.key = time->get_object_id_hash();
resp.missing_state = !time->has_state();
resp.hour = time->hour;
resp.minute = time->minute;
resp.second = time->second;
return this->send_time_state_response(resp);
}
bool APIConnection::send_time_info(datetime::TimeEntity *time) {
ListEntitiesTimeResponse msg;
msg.key = time->get_object_id_hash();
msg.object_id = time->get_object_id();
if (time->has_own_name())
msg.name = time->get_name();
msg.unique_id = get_default_unique_id("time", time);
msg.icon = time->get_icon();
msg.disabled_by_default = time->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(time->get_entity_category());
return this->send_list_entities_time_response(msg);
}
void APIConnection::time_command(const TimeCommandRequest &msg) {
datetime::TimeEntity *time = App.get_time_by_key(msg.key);
if (time == nullptr)
return;
auto call = time->make_call();
call.set_time(msg.hour, msg.minute, msg.second);
call.perform();
}
#endif
#ifdef USE_DATETIME_DATETIME
bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
if (!this->state_subscription_)
return false;
DateTimeStateResponse resp{};
resp.key = datetime->get_object_id_hash();
resp.missing_state = !datetime->has_state();
if (datetime->has_state()) {
ESPTime state = datetime->state_as_esptime();
resp.epoch_seconds = state.timestamp;
}
return this->send_date_time_state_response(resp);
}
bool APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
ListEntitiesDateTimeResponse msg;
msg.key = datetime->get_object_id_hash();
msg.object_id = datetime->get_object_id();
if (datetime->has_own_name())
msg.name = datetime->get_name();
msg.unique_id = get_default_unique_id("datetime", datetime);
msg.icon = datetime->get_icon();
msg.disabled_by_default = datetime->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(datetime->get_entity_category());
return this->send_list_entities_date_time_response(msg);
}
void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
datetime::DateTimeEntity *datetime = App.get_datetime_by_key(msg.key);
if (datetime == nullptr)
return;
auto call = datetime->make_call();
call.set_datetime(msg.epoch_seconds);
call.perform();
}
#endif
#ifdef USE_TEXT
bool APIConnection::send_text_state(text::Text *text, std::string state) {
if (!this->state_subscription_)
@@ -840,6 +953,48 @@ void APIConnection::lock_command(const LockCommandRequest &msg) {
}
#endif
#ifdef USE_VALVE
bool APIConnection::send_valve_state(valve::Valve *valve) {
if (!this->state_subscription_)
return false;
ValveStateResponse resp{};
resp.key = valve->get_object_id_hash();
resp.position = valve->position;
resp.current_operation = static_cast<enums::ValveOperation>(valve->current_operation);
return this->send_valve_state_response(resp);
}
bool APIConnection::send_valve_info(valve::Valve *valve) {
auto traits = valve->get_traits();
ListEntitiesValveResponse msg;
msg.key = valve->get_object_id_hash();
msg.object_id = valve->get_object_id();
if (valve->has_own_name())
msg.name = valve->get_name();
msg.unique_id = get_default_unique_id("valve", valve);
msg.icon = valve->get_icon();
msg.disabled_by_default = valve->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(valve->get_entity_category());
msg.device_class = valve->get_device_class();
msg.assumed_state = traits.get_is_assumed_state();
msg.supports_position = traits.get_supports_position();
msg.supports_stop = traits.get_supports_stop();
return this->send_list_entities_valve_response(msg);
}
void APIConnection::valve_command(const ValveCommandRequest &msg) {
valve::Valve *valve = App.get_valve_by_key(msg.key);
if (valve == nullptr)
return;
auto call = valve->make_call();
if (msg.has_position)
call.set_position(msg.position);
if (msg.stop)
call.set_command_stop();
call.perform();
}
#endif
#ifdef USE_MEDIA_PLAYER
bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
if (!this->state_subscription_)
@@ -847,7 +1002,11 @@ bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_pla
MediaPlayerStateResponse resp{};
resp.key = media_player->get_object_id_hash();
resp.state = static_cast<enums::MediaPlayerState>(media_player->state);
media_player::MediaPlayerState report_state = media_player->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING
? media_player::MEDIA_PLAYER_STATE_PLAYING
: media_player->state;
resp.state = static_cast<enums::MediaPlayerState>(report_state);
resp.volume = media_player->volume;
resp.muted = media_player->is_muted();
return this->send_media_player_state_response(resp);
@@ -883,6 +1042,9 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
if (msg.has_media_url) {
call.set_media_url(msg.media_url);
}
if (msg.has_announcement) {
call.set_announcement(msg.announcement);
}
call.perform();
}
#endif
@@ -1002,10 +1164,15 @@ void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &ms
voice_assistant::global_voice_assistant->failed_to_start();
return;
}
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
this->helper_->getpeername((struct sockaddr *) &storage, &len);
voice_assistant::global_voice_assistant->start_streaming(&storage, msg.port);
if (msg.port == 0) {
// Use API Audio
voice_assistant::global_voice_assistant->start_streaming();
} else {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
this->helper_->getpeername((struct sockaddr *) &storage, &len);
voice_assistant::global_voice_assistant->start_streaming(&storage, msg.port);
}
}
};
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
@@ -1017,6 +1184,15 @@ void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventR
voice_assistant::global_voice_assistant->on_event(msg);
}
}
void APIConnection::on_voice_assistant_audio(const VoiceAssistantAudio &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_audio(msg);
}
};
#endif
@@ -1078,6 +1254,30 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
}
#endif
#ifdef USE_EVENT
bool APIConnection::send_event(event::Event *event, std::string event_type) {
EventResponse resp{};
resp.key = event->get_object_id_hash();
resp.event_type = std::move(event_type);
return this->send_event_response(resp);
}
bool APIConnection::send_event_info(event::Event *event) {
ListEntitiesEventResponse msg;
msg.key = event->get_object_id_hash();
msg.object_id = event->get_object_id();
if (event->has_own_name())
msg.name = event->get_name();
msg.unique_id = get_default_unique_id("event", event);
msg.icon = event->get_icon();
msg.disabled_by_default = event->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(event->get_entity_category());
msg.device_class = event->get_device_class();
for (const auto &event_type : event->get_event_types())
msg.event_types.push_back(event_type);
return this->send_list_entities_event_response(msg);
}
#endif
bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level)
return false;
@@ -1104,7 +1304,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
HelloResponse resp;
resp.api_version_major = 1;
resp.api_version_minor = 9;
resp.api_version_minor = 10;
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name();
@@ -1165,7 +1365,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags();
#endif
#ifdef USE_VOICE_ASSISTANT
resp.voice_assistant_version = voice_assistant::global_voice_assistant->get_version();
resp.legacy_voice_assistant_version = voice_assistant::global_voice_assistant->get_legacy_version();
resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
#endif
return resp;
}
+26
View File
@@ -72,6 +72,21 @@ class APIConnection : public APIServerConnection {
bool send_number_info(number::Number *number);
void number_command(const NumberCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATE
bool send_date_state(datetime::DateEntity *date);
bool send_date_info(datetime::DateEntity *date);
void date_command(const DateCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_TIME
bool send_time_state(datetime::TimeEntity *time);
bool send_time_info(datetime::TimeEntity *time);
void time_command(const TimeCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool send_datetime_state(datetime::DateTimeEntity *datetime);
bool send_datetime_info(datetime::DateTimeEntity *datetime);
void datetime_command(const DateTimeCommandRequest &msg) override;
#endif
#ifdef USE_TEXT
bool send_text_state(text::Text *text, std::string state);
bool send_text_info(text::Text *text);
@@ -91,6 +106,11 @@ class APIConnection : public APIServerConnection {
bool send_lock_info(lock::Lock *a_lock);
void lock_command(const LockCommandRequest &msg) override;
#endif
#ifdef USE_VALVE
bool send_valve_state(valve::Valve *valve);
bool send_valve_info(valve::Valve *valve);
void valve_command(const ValveCommandRequest &msg) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool send_media_player_state(media_player::MediaPlayer *media_player);
bool send_media_player_info(media_player::MediaPlayer *media_player);
@@ -129,6 +149,7 @@ class APIConnection : public APIServerConnection {
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &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_audio(const VoiceAssistantAudio &msg) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
@@ -137,6 +158,11 @@ class APIConnection : public APIServerConnection {
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#endif
#ifdef USE_EVENT
bool send_event(event::Event *event, std::string event_type);
bool send_event_info(event::Event *event);
#endif
void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override {
// we initiated ping
File diff suppressed because it is too large Load Diff
+260 -1
View File
@@ -165,6 +165,10 @@ enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6,
};
enum VoiceAssistantSubscribeFlag : uint32_t {
VOICE_ASSISTANT_SUBSCRIBE_NONE = 0,
VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1,
};
enum VoiceAssistantRequestFlag : uint32_t {
VOICE_ASSISTANT_REQUEST_NONE = 0,
VOICE_ASSISTANT_REQUEST_USE_VAD = 1,
@@ -212,6 +216,11 @@ enum TextMode : uint32_t {
TEXT_MODE_TEXT = 0,
TEXT_MODE_PASSWORD = 1,
};
enum ValveOperation : uint32_t {
VALVE_OPERATION_IDLE = 0,
VALVE_OPERATION_IS_OPENING = 1,
VALVE_OPERATION_IS_CLOSING = 2,
};
} // namespace enums
@@ -327,7 +336,8 @@ class DeviceInfoResponse : public ProtoMessage {
uint32_t bluetooth_proxy_feature_flags{0};
std::string manufacturer{};
std::string friendly_name{};
uint32_t voice_assistant_version{0};
uint32_t legacy_voice_assistant_version{0};
uint32_t voice_assistant_feature_flags{0};
std::string suggested_area{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -713,6 +723,7 @@ class ListEntitiesTextSensorResponse : public ProtoMessage {
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;
@@ -1287,6 +1298,8 @@ class MediaPlayerCommandRequest : public ProtoMessage {
float volume{0.0f};
bool has_media_url{false};
std::string media_url{};
bool has_announcement{false};
bool announcement{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1673,6 +1686,7 @@ class BluetoothDeviceClearCacheResponse : public ProtoMessage {
class SubscribeVoiceAssistantRequest : public ProtoMessage {
public:
bool subscribe{false};
uint32_t flags{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1701,6 +1715,7 @@ class VoiceAssistantRequest : public ProtoMessage {
std::string conversation_id{};
uint32_t flags{0};
VoiceAssistantAudioSettings audio_settings{};
std::string wake_word_phrase{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1747,6 +1762,19 @@ class VoiceAssistantEventResponse : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantAudio : public ProtoMessage {
public:
std::string data{};
bool end{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 {
public:
std::string object_id{};
@@ -1848,6 +1876,237 @@ class TextCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class ListEntitiesDateResponse : 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{};
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 DateStateResponse : public ProtoMessage {
public:
uint32_t key{0};
bool missing_state{false};
uint32_t year{0};
uint32_t month{0};
uint32_t day{0};
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;
};
class DateCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
uint32_t year{0};
uint32_t month{0};
uint32_t day{0};
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;
};
class ListEntitiesTimeResponse : 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{};
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 TimeStateResponse : public ProtoMessage {
public:
uint32_t key{0};
bool missing_state{false};
uint32_t hour{0};
uint32_t minute{0};
uint32_t second{0};
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;
};
class TimeCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
uint32_t hour{0};
uint32_t minute{0};
uint32_t second{0};
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;
};
class ListEntitiesEventResponse : 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{};
std::vector<std::string> event_types{};
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 EventResponse : public ProtoMessage {
public:
uint32_t key{0};
std::string event_type{};
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;
};
class ListEntitiesValveResponse : 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{};
bool assumed_state{false};
bool supports_position{false};
bool supports_stop{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_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class ValveStateResponse : public ProtoMessage {
public:
uint32_t key{0};
float position{0.0f};
enums::ValveOperation current_operation{};
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;
};
class ValveCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
bool has_position{false};
float position{0.0f};
bool stop{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;
};
class ListEntitiesDateTimeResponse : 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{};
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 DateTimeStateResponse : public ProtoMessage {
public:
uint32_t key{0};
bool missing_state{false};
uint32_t epoch_seconds{0};
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;
};
class DateTimeCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
uint32_t epoch_seconds{0};
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;
};
} // namespace api
} // namespace esphome
+203
View File
@@ -476,6 +476,14 @@ bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantR
#endif
#ifdef USE_VOICE_ASSISTANT
#endif
#ifdef USE_VOICE_ASSISTANT
bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAudio &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_voice_assistant_audio: %s", msg.dump().c_str());
#endif
return this->send_message_<VoiceAssistantAudio>(msg, 106);
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response(
const ListEntitiesAlarmControlPanelResponse &msg) {
@@ -513,6 +521,94 @@ bool APIServerConnectionBase::send_text_state_response(const TextStateResponse &
#endif
#ifdef USE_TEXT
#endif
#ifdef USE_DATETIME_DATE
bool APIServerConnectionBase::send_list_entities_date_response(const ListEntitiesDateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_date_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesDateResponse>(msg, 100);
}
#endif
#ifdef USE_DATETIME_DATE
bool APIServerConnectionBase::send_date_state_response(const DateStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_date_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<DateStateResponse>(msg, 101);
}
#endif
#ifdef USE_DATETIME_DATE
#endif
#ifdef USE_DATETIME_TIME
bool APIServerConnectionBase::send_list_entities_time_response(const ListEntitiesTimeResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_time_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesTimeResponse>(msg, 103);
}
#endif
#ifdef USE_DATETIME_TIME
bool APIServerConnectionBase::send_time_state_response(const TimeStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_time_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<TimeStateResponse>(msg, 104);
}
#endif
#ifdef USE_DATETIME_TIME
#endif
#ifdef USE_EVENT
bool APIServerConnectionBase::send_list_entities_event_response(const ListEntitiesEventResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_event_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesEventResponse>(msg, 107);
}
#endif
#ifdef USE_EVENT
bool APIServerConnectionBase::send_event_response(const EventResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_event_response: %s", msg.dump().c_str());
#endif
return this->send_message_<EventResponse>(msg, 108);
}
#endif
#ifdef USE_VALVE
bool APIServerConnectionBase::send_list_entities_valve_response(const ListEntitiesValveResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_valve_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesValveResponse>(msg, 109);
}
#endif
#ifdef USE_VALVE
bool APIServerConnectionBase::send_valve_state_response(const ValveStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_valve_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ValveStateResponse>(msg, 110);
}
#endif
#ifdef USE_VALVE
#endif
#ifdef USE_DATETIME_DATETIME
bool APIServerConnectionBase::send_list_entities_date_time_response(const ListEntitiesDateTimeResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_date_time_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesDateTimeResponse>(msg, 112);
}
#endif
#ifdef USE_DATETIME_DATETIME
bool APIServerConnectionBase::send_date_time_state_response(const DateTimeStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_date_time_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<DateTimeStateResponse>(msg, 113);
}
#endif
#ifdef USE_DATETIME_DATETIME
#endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) {
case 1: {
@@ -942,6 +1038,61 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_text_command_request: %s", msg.dump().c_str());
#endif
this->on_text_command_request(msg);
#endif
break;
}
case 102: {
#ifdef USE_DATETIME_DATE
DateCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str());
#endif
this->on_date_command_request(msg);
#endif
break;
}
case 105: {
#ifdef USE_DATETIME_TIME
TimeCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_time_command_request: %s", msg.dump().c_str());
#endif
this->on_time_command_request(msg);
#endif
break;
}
case 106: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantAudio msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_audio(msg);
#endif
break;
}
case 111: {
#ifdef USE_VALVE
ValveCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str());
#endif
this->on_valve_command_request(msg);
#endif
break;
}
case 114: {
#ifdef USE_DATETIME_DATETIME
DateTimeCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str());
#endif
this->on_date_time_command_request(msg);
#endif
break;
}
@@ -1205,6 +1356,19 @@ void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg)
this->lock_command(msg);
}
#endif
#ifdef USE_VALVE
void APIServerConnection::on_valve_command_request(const ValveCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->valve_command(msg);
}
#endif
#ifdef USE_MEDIA_PLAYER
void APIServerConnection::on_media_player_command_request(const MediaPlayerCommandRequest &msg) {
if (!this->is_connection_setup()) {
@@ -1218,6 +1382,45 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma
this->media_player_command(msg);
}
#endif
#ifdef USE_DATETIME_DATE
void APIServerConnection::on_date_command_request(const DateCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->date_command(msg);
}
#endif
#ifdef USE_DATETIME_TIME
void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->time_command(msg);
}
#endif
#ifdef USE_DATETIME_DATETIME
void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->datetime_command(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {
+70
View File
@@ -240,6 +240,10 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){};
#endif
#ifdef USE_VOICE_ASSISTANT
bool send_voice_assistant_audio(const VoiceAssistantAudio &msg);
virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){};
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg);
#endif
@@ -257,6 +261,48 @@ class APIServerConnectionBase : public ProtoService {
#endif
#ifdef USE_TEXT
virtual void on_text_command_request(const TextCommandRequest &value){};
#endif
#ifdef USE_DATETIME_DATE
bool send_list_entities_date_response(const ListEntitiesDateResponse &msg);
#endif
#ifdef USE_DATETIME_DATE
bool send_date_state_response(const DateStateResponse &msg);
#endif
#ifdef USE_DATETIME_DATE
virtual void on_date_command_request(const DateCommandRequest &value){};
#endif
#ifdef USE_DATETIME_TIME
bool send_list_entities_time_response(const ListEntitiesTimeResponse &msg);
#endif
#ifdef USE_DATETIME_TIME
bool send_time_state_response(const TimeStateResponse &msg);
#endif
#ifdef USE_DATETIME_TIME
virtual void on_time_command_request(const TimeCommandRequest &value){};
#endif
#ifdef USE_EVENT
bool send_list_entities_event_response(const ListEntitiesEventResponse &msg);
#endif
#ifdef USE_EVENT
bool send_event_response(const EventResponse &msg);
#endif
#ifdef USE_VALVE
bool send_list_entities_valve_response(const ListEntitiesValveResponse &msg);
#endif
#ifdef USE_VALVE
bool send_valve_state_response(const ValveStateResponse &msg);
#endif
#ifdef USE_VALVE
virtual void on_valve_command_request(const ValveCommandRequest &value){};
#endif
#ifdef USE_DATETIME_DATETIME
bool send_list_entities_date_time_response(const ListEntitiesDateTimeResponse &msg);
#endif
#ifdef USE_DATETIME_DATETIME
bool send_date_time_state_response(const DateTimeStateResponse &msg);
#endif
#ifdef USE_DATETIME_DATETIME
virtual void on_date_time_command_request(const DateTimeCommandRequest &value){};
#endif
protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
@@ -309,9 +355,21 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_LOCK
virtual void lock_command(const LockCommandRequest &msg) = 0;
#endif
#ifdef USE_VALVE
virtual void valve_command(const ValveCommandRequest &msg) = 0;
#endif
#ifdef USE_MEDIA_PLAYER
virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0;
#endif
#ifdef USE_DATETIME_DATE
virtual void date_command(const DateCommandRequest &msg) = 0;
#endif
#ifdef USE_DATETIME_TIME
virtual void time_command(const TimeCommandRequest &msg) = 0;
#endif
#ifdef USE_DATETIME_DATETIME
virtual void datetime_command(const DateTimeCommandRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif
@@ -395,9 +453,21 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_LOCK
void on_lock_command_request(const LockCommandRequest &msg) override;
#endif
#ifdef USE_VALVE
void on_valve_command_request(const ValveCommandRequest &msg) override;
#endif
#ifdef USE_MEDIA_PLAYER
void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATE
void on_date_command_request(const DateCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_TIME
void on_time_command_request(const TimeCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATETIME
void on_date_time_command_request(const DateTimeCommandRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif
+43
View File
@@ -255,6 +255,33 @@ void APIServer::on_number_update(number::Number *obj, float state) {
}
#endif
#ifdef USE_DATETIME_DATE
void APIServer::on_date_update(datetime::DateEntity *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_date_state(obj);
}
#endif
#ifdef USE_DATETIME_TIME
void APIServer::on_time_update(datetime::TimeEntity *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_time_state(obj);
}
#endif
#ifdef USE_DATETIME_DATETIME
void APIServer::on_datetime_update(datetime::DateTimeEntity *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_datetime_state(obj);
}
#endif
#ifdef USE_TEXT
void APIServer::on_text_update(text::Text *obj, const std::string &state) {
if (obj->is_internal())
@@ -282,6 +309,15 @@ void APIServer::on_lock_update(lock::Lock *obj) {
}
#endif
#ifdef USE_VALVE
void APIServer::on_valve_update(valve::Valve *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_valve_state(obj);
}
#endif
#ifdef USE_MEDIA_PLAYER
void APIServer::on_media_player_update(media_player::MediaPlayer *obj) {
if (obj->is_internal())
@@ -291,6 +327,13 @@ void APIServer::on_media_player_update(media_player::MediaPlayer *obj) {
}
#endif
#ifdef USE_EVENT
void APIServer::on_event(event::Event *obj, const std::string &event_type) {
for (auto &c : this->clients_)
c->send_event(obj, event_type);
}
#endif
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void APIServer::set_port(uint16_t port) { this->port_ = port; }
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
+15
View File
@@ -66,6 +66,15 @@ class APIServer : public Component, public Controller {
#ifdef USE_NUMBER
void on_number_update(number::Number *obj, float state) override;
#endif
#ifdef USE_DATETIME_DATE
void on_date_update(datetime::DateEntity *obj) override;
#endif
#ifdef USE_DATETIME_TIME
void on_time_update(datetime::TimeEntity *obj) override;
#endif
#ifdef USE_DATETIME_DATETIME
void on_datetime_update(datetime::DateTimeEntity *obj) override;
#endif
#ifdef USE_TEXT
void on_text_update(text::Text *obj, const std::string &state) override;
#endif
@@ -75,6 +84,9 @@ class APIServer : public Component, public Controller {
#ifdef USE_LOCK
void on_lock_update(lock::Lock *obj) override;
#endif
#ifdef USE_VALVE
void on_valve_update(valve::Valve *obj) override;
#endif
#ifdef USE_MEDIA_PLAYER
void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif
@@ -87,6 +99,9 @@ class APIServer : public Component, public Controller {
#ifdef USE_ALARM_CONTROL_PANEL
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override;
#endif
#ifdef USE_EVENT
void on_event(event::Event *obj, const std::string &event_type) override;
#endif
bool is_connected() const;
+23 -3
View File
@@ -1,8 +1,8 @@
#include "list_entities.h"
#include "esphome/core/util.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "api_connection.h"
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/core/util.h"
namespace esphome {
namespace api {
@@ -38,6 +38,9 @@ bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor)
#ifdef USE_LOCK
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_info(a_lock); }
#endif
#ifdef USE_VALVE
bool ListEntitiesIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_info(valve); }
#endif
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
@@ -60,6 +63,20 @@ bool ListEntitiesIterator::on_climate(climate::Climate *climate) { return this->
bool ListEntitiesIterator::on_number(number::Number *number) { return this->client_->send_number_info(number); }
#endif
#ifdef USE_DATETIME_DATE
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_info(date); }
#endif
#ifdef USE_DATETIME_TIME
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_info(time); }
#endif
#ifdef USE_DATETIME_DATETIME
bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) {
return this->client_->send_datetime_info(datetime);
}
#endif
#ifdef USE_TEXT
bool ListEntitiesIterator::on_text(text::Text *text) { return this->client_->send_text_info(text); }
#endif
@@ -78,6 +95,9 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont
return this->client_->send_alarm_control_panel_info(a_alarm_control_panel);
}
#endif
#ifdef USE_EVENT
bool ListEntitiesIterator::on_event(event::Event *event) { return this->client_->send_event_info(event); }
#endif
} // namespace api
} // namespace esphome
+15
View File
@@ -46,6 +46,15 @@ class ListEntitiesIterator : public ComponentIterator {
#ifdef USE_NUMBER
bool on_number(number::Number *number) override;
#endif
#ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override;
#endif
#ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override;
#endif
#ifdef USE_TEXT
bool on_text(text::Text *text) override;
#endif
@@ -55,11 +64,17 @@ class ListEntitiesIterator : public ComponentIterator {
#ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override;
#endif
#ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override;
#endif
#ifdef USE_EVENT
bool on_event(event::Event *event) override;
#endif
bool on_end() override;
@@ -42,6 +42,17 @@ bool InitialStateIterator::on_number(number::Number *number) {
return this->client_->send_number_state(number, number->state);
}
#endif
#ifdef USE_DATETIME_DATE
bool InitialStateIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_state(date); }
#endif
#ifdef USE_DATETIME_TIME
bool InitialStateIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_state(time); }
#endif
#ifdef USE_DATETIME_DATETIME
bool InitialStateIterator::on_datetime(datetime::DateTimeEntity *datetime) {
return this->client_->send_datetime_state(datetime);
}
#endif
#ifdef USE_TEXT
bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text, text->state); }
#endif
@@ -53,6 +64,9 @@ bool InitialStateIterator::on_select(select::Select *select) {
#ifdef USE_LOCK
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); }
#endif
#ifdef USE_VALVE
bool InitialStateIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_state(valve); }
#endif
#ifdef USE_MEDIA_PLAYER
bool InitialStateIterator::on_media_player(media_player::MediaPlayer *media_player) {
return this->client_->send_media_player_state(media_player);
+15
View File
@@ -43,6 +43,15 @@ class InitialStateIterator : public ComponentIterator {
#ifdef USE_NUMBER
bool on_number(number::Number *number) override;
#endif
#ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override;
#endif
#ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override;
#endif
#ifdef USE_TEXT
bool on_text(text::Text *text) override;
#endif
@@ -52,11 +61,17 @@ class InitialStateIterator : public ComponentIterator {
#ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override;
#endif
#ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override;
#endif
#ifdef USE_EVENT
bool on_event(event::Event *event) override { return true; };
#endif
protected:
APIConnection *client_;
-1
View File
@@ -54,7 +54,6 @@ FAST_FILTER = {
"LSB10": 7,
}
CONF_ANGLE = "angle"
CONF_RAW_ANGLE = "raw_angle"
CONF_RAW_POSITION = "raw_position"
CONF_WATCHDOG = "watchdog"
+1 -1
View File
@@ -11,6 +11,7 @@ from esphome.const import (
CONF_MAGNITUDE,
CONF_STATUS,
CONF_POSITION,
CONF_ANGLE,
)
from .. import as5600_ns, AS5600Component
@@ -19,7 +20,6 @@ DEPENDENCIES = ["as5600"]
AS5600Sensor = as5600_ns.class_("AS5600Sensor", sensor.Sensor, cg.PollingComponent)
CONF_ANGLE = "angle"
CONF_RAW_ANGLE = "raw_angle"
CONF_RAW_POSITION = "raw_position"
CONF_WATCHDOG = "watchdog"
+1 -1
View File
@@ -22,7 +22,7 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
if CORE.is_esp32 or CORE.is_libretiny:
# https://github.com/esphome/AsyncTCP/blob/master/library.json
cg.add_library("esphome/AsyncTCP-esphome", "2.0.1")
cg.add_library("esphome/AsyncTCP-esphome", "2.1.3")
elif CORE.is_esp8266:
# https://github.com/esphome/ESPAsyncTCP
cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0")
+223
View File
@@ -0,0 +1,223 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation, core
from esphome.components import i2c
from esphome.automation import maybe_simple_id
from esphome.const import (
CONF_ID,
CONF_FREQUENCY,
)
CODEOWNERS = ["@X-Ryl669"]
DEPENDENCIES = ["i2c"]
MULTI_CONF = True
at581x_ns = cg.esphome_ns.namespace("at581x")
AT581XComponent = at581x_ns.class_("AT581XComponent", cg.Component, i2c.I2CDevice)
CONF_AT581X_ID = "at581x_id"
CONF_SENSING_DISTANCE = "sensing_distance"
CONF_POWERON_SELFCHECK_TIME = "poweron_selfcheck_time"
CONF_PROTECT_TIME = "protect_time"
CONF_TRIGGER_BASE = "trigger_base"
CONF_TRIGGER_KEEP = "trigger_keep"
CONF_STAGE_GAIN = "stage_gain"
CONF_POWER_CONSUMPTION = "power_consumption"
CONF_HW_FRONTEND_RESET = "hw_frontend_reset"
RADAR_ALLOWED_FREQ = [
5696e6,
5715e6,
5730e6,
5748e6,
5765e6,
5784e6,
5800e6,
5819e6,
5836e6,
5851e6,
5869e6,
5888e6,
]
RADAR_ALLOWED_CUR_CONSUMPTION = [
48e-6,
56e-6,
63e-6,
70e-6,
77e-6,
91e-6,
105e-6,
115e-6,
40e-6,
44e-6,
47e-6,
51e-6,
54e-6,
61e-6,
68e-6,
78e-6,
]
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(AT581XComponent),
}
)
CONFIG_SCHEMA = cv.All(
CONFIG_SCHEMA.extend(i2c.i2c_device_schema(0x28)).extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
# Actions
AT581XResetAction = at581x_ns.class_("AT581XResetAction", automation.Action)
AT581XSettingsAction = at581x_ns.class_("AT581XSettingsAction", automation.Action)
@automation.register_action(
"at581x.reset",
AT581XResetAction,
maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(AT581XComponent),
}
),
)
async def at581x_reset_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
RADAR_SETTINGS_SCHEMA = cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(AT581XComponent),
cv.Optional(CONF_HW_FRONTEND_RESET): cv.templatable(cv.boolean),
cv.Optional(CONF_FREQUENCY, default="5800MHz"): cv.templatable(
cv.All(cv.frequency, cv.one_of(*RADAR_ALLOWED_FREQ))
),
cv.Optional(CONF_SENSING_DISTANCE, default=823): cv.templatable(
cv.int_range(min=0, max=1023)
),
cv.Optional(CONF_POWERON_SELFCHECK_TIME, default="2000ms"): cv.templatable(
cv.All(
cv.positive_time_period_milliseconds,
cv.Range(max=core.TimePeriod(milliseconds=65535)),
)
),
cv.Optional(CONF_POWER_CONSUMPTION, default="70uA"): cv.templatable(
cv.All(cv.current, cv.one_of(*RADAR_ALLOWED_CUR_CONSUMPTION))
),
cv.Optional(CONF_PROTECT_TIME, default="1000ms"): cv.templatable(
cv.All(
cv.positive_time_period_milliseconds,
cv.Range(
min=core.TimePeriod(milliseconds=1),
max=core.TimePeriod(milliseconds=65535),
),
)
),
cv.Optional(CONF_TRIGGER_BASE, default="500ms"): cv.templatable(
cv.All(
cv.positive_time_period_milliseconds,
cv.Range(
min=core.TimePeriod(milliseconds=1),
max=core.TimePeriod(milliseconds=65535),
),
)
),
cv.Optional(CONF_TRIGGER_KEEP, default="1500ms"): cv.templatable(
cv.All(
cv.positive_time_period_milliseconds,
cv.Range(
min=core.TimePeriod(milliseconds=1),
max=core.TimePeriod(milliseconds=65535),
),
)
),
cv.Optional(CONF_STAGE_GAIN, default=3): cv.templatable(
cv.int_range(min=0, max=12)
),
}
).add_extra(
cv.has_at_least_one_key(
CONF_HW_FRONTEND_RESET,
CONF_FREQUENCY,
CONF_SENSING_DISTANCE,
)
)
@automation.register_action(
"at581x.settings",
AT581XSettingsAction,
RADAR_SETTINGS_SCHEMA,
)
async def at581x_settings_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
# Radar configuration
if frontend_reset := config.get(CONF_HW_FRONTEND_RESET):
template_ = await cg.templatable(frontend_reset, args, int)
cg.add(var.set_hw_frontend_reset(template_))
if freq := config.get(CONF_FREQUENCY):
template_ = await cg.templatable(freq, args, float)
template_ = int(template_ / 1000000)
cg.add(var.set_frequency(template_))
if sens_dist := config.get(CONF_SENSING_DISTANCE):
template_ = await cg.templatable(sens_dist, args, int)
cg.add(var.set_sensing_distance(template_))
if selfcheck := config.get(CONF_POWERON_SELFCHECK_TIME):
template_ = await cg.templatable(selfcheck, args, float)
if isinstance(template_, cv.TimePeriod):
template_ = template_.total_milliseconds
template_ = int(template_)
cg.add(var.set_poweron_selfcheck_time(template_))
if protect := config.get(CONF_PROTECT_TIME):
template_ = await cg.templatable(protect, args, float)
if isinstance(template_, cv.TimePeriod):
template_ = template_.total_milliseconds
template_ = int(template_)
cg.add(var.set_protect_time(template_))
if trig_base := config.get(CONF_TRIGGER_BASE):
template_ = await cg.templatable(trig_base, args, float)
if isinstance(template_, cv.TimePeriod):
template_ = template_.total_milliseconds
template_ = int(template_)
cg.add(var.set_trigger_base(template_))
if trig_keep := config.get(CONF_TRIGGER_KEEP):
template_ = await cg.templatable(trig_keep, args, float)
if isinstance(template_, cv.TimePeriod):
template_ = template_.total_milliseconds
template_ = int(template_)
cg.add(var.set_trigger_keep(template_))
if stage_gain := config.get(CONF_STAGE_GAIN):
template_ = await cg.templatable(stage_gain, args, int)
cg.add(var.set_stage_gain(template_))
if power := config.get(CONF_POWER_CONSUMPTION):
template_ = await cg.templatable(power, args, float)
template_ = int(template_ * 1000000)
cg.add(var.set_power_consumption(template_))
return var
+195
View File
@@ -0,0 +1,195 @@
#include "at581x.h"
#include "esphome/core/log.h"
/* Select gain for AT581X (3dB per step for level1, 6dB per step for level 2), high value = small gain. (p12) */
const uint8_t GAIN_ADDR_TABLE[] = {0x5c, 0x63};
const uint8_t GAIN5C_TABLE[] = {0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8};
const uint8_t GAIN63_TABLE[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
const uint8_t GAIN61_VALUE = 0xCA; // 0xC0 | 0x02 (freq present) | 0x08 (gain present)
/*!< Power consumption configuration table (p12). */
const uint8_t POWER_TABLE[] = {48, 56, 63, 70, 77, 91, 105, 115, 40, 44, 47, 51, 54, 61, 68, 78};
const uint8_t POWER67_TABLE[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
const uint8_t POWER68_TABLE[] = {0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,
24, 24, 24, 24, 24, 24, 24, 24}; // See Page 12, shift by 3 bits
/*!< Frequency Configuration table (p14/15 of datasheet). */
const uint8_t FREQ_ADDR = 0x61;
const uint16_t FREQ_TABLE[] = {5696, 5715, 5730, 5748, 5765, 5784, 5800, 5819, 5836, 5851, 5869, 5888};
const uint8_t FREQ5F_TABLE[] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x40, 0x41, 0x42, 0x43};
const uint8_t FREQ60_TABLE[] = {0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e};
/*!< Value for RF and analog modules switch (p10). */
const uint8_t RF_OFF_TABLE[] = {0x46, 0xaa, 0x50};
const uint8_t RF_ON_TABLE[] = {0x45, 0x55, 0xA0};
const uint8_t RF_REG_ADDR[] = {0x5d, 0x62, 0x51};
/*!< Registers of Lighting delay time. Unit: ms, min 2s (p8) */
const uint8_t HIGH_LEVEL_DELAY_CONTROL_ADDR = 0x41; /*!< Time_flag_out_ctrl 0x01 */
const uint8_t HIGH_LEVEL_DELAY_VALUE_ADDR = 0x42; /*!< Time_flag_out_1 Bit<7:0> */
const uint8_t RESET_ADDR = 0x00;
/*!< Sensing distance address */
const uint8_t SIGNAL_DETECTION_THRESHOLD_ADDR_LO = 0x10;
const uint8_t SIGNAL_DETECTION_THRESHOLD_ADDR_HI = 0x11;
/*!< Bit field value for power registers */
const uint8_t POWER_THRESHOLD_ADDR_HI = 0x68;
const uint8_t POWER_THRESHOLD_ADDR_LO = 0x67;
const uint8_t PWR_WORK_TIME_EN = 8; // Reg 0x67
const uint8_t PWR_BURST_TIME_EN = 32; // Reg 0x68
const uint8_t PWR_THRESH_EN = 64; // Reg 0x68
const uint8_t PWR_THRESH_VAL_EN = 128; // Reg 0x67
/*!< Times */
const uint8_t TRIGGER_BASE_TIME_ADDR = 0x3D; // 4 bytes, so up to 0x40
const uint8_t PROTECT_TIME_ADDR = 0x4E; // 2 bytes, up to 0x4F
const uint8_t TRIGGER_KEEP_TIME_ADDR = 0x42; // 4 bytes, so up to 0x45
const uint8_t TIME41_VALUE = 1;
const uint8_t SELF_CHECK_TIME_ADDR = 0x38; // 2 bytes, up to 0x39
namespace esphome {
namespace at581x {
static const char *const TAG = "at581x";
bool AT581XComponent::i2c_write_reg(uint8_t addr, uint8_t data) {
return this->write_register(addr, &data, 1) == esphome::i2c::NO_ERROR;
}
bool AT581XComponent::i2c_write_reg(uint8_t addr, uint32_t data) {
return this->i2c_write_reg(addr + 0, uint8_t(data & 0xFF)) &&
this->i2c_write_reg(addr + 1, uint8_t((data >> 8) & 0xFF)) &&
this->i2c_write_reg(addr + 2, uint8_t((data >> 16) & 0xFF)) &&
this->i2c_write_reg(addr + 3, uint8_t((data >> 24) & 0xFF));
}
bool AT581XComponent::i2c_write_reg(uint8_t addr, uint16_t data) {
return this->i2c_write_reg(addr, uint8_t(data & 0xFF)) && this->i2c_write_reg(addr + 1, uint8_t((data >> 8) & 0xFF));
}
bool AT581XComponent::i2c_read_reg(uint8_t addr, uint8_t &data) {
return this->read_register(addr, &data, 1) == esphome::i2c::NO_ERROR;
}
void AT581XComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up AT581X..."); }
void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); }
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
bool AT581XComponent::i2c_write_config() {
ESP_LOGCONFIG(TAG, "Writing new config for AT581X...");
ESP_LOGCONFIG(TAG, "Frequency: %dMHz", this->freq_);
ESP_LOGCONFIG(TAG, "Sensing distance: %d", this->delta_);
ESP_LOGCONFIG(TAG, "Power: %dµA", this->power_);
ESP_LOGCONFIG(TAG, "Gain: %d", this->gain_);
ESP_LOGCONFIG(TAG, "Trigger base time: %dms", this->trigger_base_time_ms_);
ESP_LOGCONFIG(TAG, "Trigger keep time: %dms", this->trigger_keep_time_ms_);
ESP_LOGCONFIG(TAG, "Protect time: %dms", this->protect_time_ms_);
ESP_LOGCONFIG(TAG, "Self check time: %dms", this->self_check_time_ms_);
// Set frequency point
if (!this->i2c_write_reg(FREQ_ADDR, GAIN61_VALUE)) {
ESP_LOGE(TAG, "Failed to write AT581X Freq mode");
return false;
}
// Find the current frequency from the table to know what value to write
for (size_t i = 0; i < ARRAY_SIZE(FREQ_TABLE) + 1; i++) {
if (i == ARRAY_SIZE(FREQ_TABLE)) {
ESP_LOGE(TAG, "Set frequency not found");
return false;
}
if (FREQ_TABLE[i] == this->freq_) {
if (!this->i2c_write_reg(0x5F, FREQ5F_TABLE[i]) || !this->i2c_write_reg(0x60, FREQ60_TABLE[i])) {
ESP_LOGE(TAG, "Failed to write AT581X Freq value");
return false;
}
break;
}
}
// Set distance
if (!this->i2c_write_reg(SIGNAL_DETECTION_THRESHOLD_ADDR_LO, (uint8_t) (this->delta_ & 0xFF)) ||
!this->i2c_write_reg(SIGNAL_DETECTION_THRESHOLD_ADDR_HI, (uint8_t) (this->delta_ >> 8))) {
ESP_LOGE(TAG, "Failed to write AT581X sensing distance low");
return false;
}
// Set power setting
uint8_t pwr67 = PWR_THRESH_VAL_EN | PWR_WORK_TIME_EN, pwr68 = PWR_BURST_TIME_EN | PWR_THRESH_EN;
for (size_t i = 0; i < ARRAY_SIZE(POWER_TABLE) + 1; i++) {
if (i == ARRAY_SIZE(POWER_TABLE)) {
ESP_LOGE(TAG, "Set power not found");
return false;
}
if (POWER_TABLE[i] == this->power_) {
pwr67 |= POWER67_TABLE[i];
pwr68 |= POWER68_TABLE[i]; // See Page 12
break;
}
}
if (!this->i2c_write_reg(POWER_THRESHOLD_ADDR_LO, pwr67) || !this->i2c_write_reg(POWER_THRESHOLD_ADDR_HI, pwr68)) {
ESP_LOGE(TAG, "Failed to write AT581X power registers");
return false;
}
// Set gain
if (!this->i2c_write_reg(GAIN_ADDR_TABLE[0], GAIN5C_TABLE[this->gain_]) ||
!this->i2c_write_reg(GAIN_ADDR_TABLE[1], GAIN63_TABLE[this->gain_ >> 1])) {
ESP_LOGE(TAG, "Failed to write AT581X gain registers");
return false;
}
// Set times
if (!this->i2c_write_reg(TRIGGER_BASE_TIME_ADDR, (uint32_t) this->trigger_base_time_ms_)) {
ESP_LOGE(TAG, "Failed to write AT581X trigger base time registers");
return false;
}
if (!this->i2c_write_reg(TRIGGER_KEEP_TIME_ADDR, (uint32_t) this->trigger_keep_time_ms_)) {
ESP_LOGE(TAG, "Failed to write AT581X trigger keep time registers");
return false;
}
if (!this->i2c_write_reg(PROTECT_TIME_ADDR, (uint16_t) this->protect_time_ms_)) {
ESP_LOGE(TAG, "Failed to write AT581X protect time registers");
return false;
}
if (!this->i2c_write_reg(SELF_CHECK_TIME_ADDR, (uint16_t) this->self_check_time_ms_)) {
ESP_LOGE(TAG, "Failed to write AT581X self check time registers");
return false;
}
if (!this->i2c_write_reg(0x41, TIME41_VALUE)) {
ESP_LOGE(TAG, "Failed to enable AT581X time registers");
return false;
}
// Don't know why it's required in other code, it's not in datasheet
if (!this->i2c_write_reg(0x55, (uint8_t) 0x04)) {
ESP_LOGE(TAG, "Failed to enable AT581X");
return false;
}
// Ok, config is written, let's reset the chip so it's using the new config
return this->reset_hardware_frontend();
}
// float AT581XComponent::get_setup_priority() const { return 0; }
bool AT581XComponent::reset_hardware_frontend() {
if (!this->i2c_write_reg(RESET_ADDR, (uint8_t) 0) || !this->i2c_write_reg(RESET_ADDR, (uint8_t) 1)) {
ESP_LOGE(TAG, "Failed to reset AT581X hardware frontend");
return false;
}
return true;
}
void AT581XComponent::set_rf_mode(bool enable) {
const uint8_t *p = enable ? &RF_ON_TABLE[0] : &RF_OFF_TABLE[0];
for (size_t i = 0; i < ARRAY_SIZE(RF_REG_ADDR); i++) {
if (!this->i2c_write_reg(RF_REG_ADDR[i], p[i])) {
ESP_LOGE(TAG, "Failed to write AT581X RF mode");
return;
}
}
}
} // namespace at581x
} // namespace esphome
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <utility>
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/defines.h"
#ifdef USE_SWITCH
#include "esphome/components/switch/switch.h"
#endif
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace at581x {
class AT581XComponent : public Component, public i2c::I2CDevice {
#ifdef USE_SWITCH
protected:
switch_::Switch *rf_power_switch_{nullptr};
public:
void set_rf_power_switch(switch_::Switch *s) {
this->rf_power_switch_ = s;
s->turn_on();
}
#endif
void setup() override;
void dump_config() override;
// float get_setup_priority() const override;
void set_sensing_distance(int distance) { this->delta_ = 1023 - distance; }
void set_rf_mode(bool enabled);
void set_frequency(int frequency) { this->freq_ = frequency; }
void set_poweron_selfcheck_time(int value) { this->self_check_time_ms_ = value; }
void set_protect_time(int value) { this->protect_time_ms_ = value; }
void set_trigger_base(int value) { this->trigger_base_time_ms_ = value; }
void set_trigger_keep(int value) { this->trigger_keep_time_ms_ = value; }
void set_stage_gain(int value) { this->gain_ = value; }
void set_power_consumption(int value) { this->power_ = value; }
bool i2c_write_config();
bool reset_hardware_frontend();
bool i2c_write_reg(uint8_t addr, uint8_t data);
bool i2c_write_reg(uint8_t addr, uint32_t data);
bool i2c_write_reg(uint8_t addr, uint16_t data);
bool i2c_read_reg(uint8_t addr, uint8_t &data);
protected:
int freq_;
int self_check_time_ms_; /*!< Power-on self-test time, range: 0 ~ 65536 ms */
int protect_time_ms_; /*!< Protection time, recommended 1000 ms */
int trigger_base_time_ms_; /*!< Default: 500 ms */
int trigger_keep_time_ms_; /*!< Total trig time = TRIGGER_BASE_TIME + DEF_TRIGGER_KEEP_TIME, minimum: 1 */
int delta_; /*!< Delta value: 0 ~ 1023, the larger the value, the shorter the distance */
int gain_; /*!< Default: 9dB */
int power_; /*!< In µA */
};
} // namespace at581x
} // namespace esphome
+71
View File
@@ -0,0 +1,71 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/helpers.h"
#include "at581x.h"
namespace esphome {
namespace at581x {
template<typename... Ts> class AT581XResetAction : public Action<Ts...>, public Parented<AT581XComponent> {
public:
void play(Ts... x) { this->parent_->reset_hardware_frontend(); }
};
template<typename... Ts> class AT581XSettingsAction : public Action<Ts...>, public Parented<AT581XComponent> {
public:
TEMPLATABLE_VALUE(int8_t, hw_frontend_reset)
TEMPLATABLE_VALUE(int, frequency)
TEMPLATABLE_VALUE(int, sensing_distance)
TEMPLATABLE_VALUE(int, poweron_selfcheck_time)
TEMPLATABLE_VALUE(int, power_consumption)
TEMPLATABLE_VALUE(int, protect_time)
TEMPLATABLE_VALUE(int, trigger_base)
TEMPLATABLE_VALUE(int, trigger_keep)
TEMPLATABLE_VALUE(int, stage_gain)
void play(Ts... x) {
if (this->frequency_.has_value()) {
int v = this->frequency_.value(x...);
this->parent_->set_frequency(v);
}
if (this->sensing_distance_.has_value()) {
int v = this->sensing_distance_.value(x...);
this->parent_->set_sensing_distance(v);
}
if (this->poweron_selfcheck_time_.has_value()) {
int v = this->poweron_selfcheck_time_.value(x...);
this->parent_->set_poweron_selfcheck_time(v);
}
if (this->power_consumption_.has_value()) {
int v = this->power_consumption_.value(x...);
this->parent_->set_power_consumption(v);
}
if (this->protect_time_.has_value()) {
int v = this->protect_time_.value(x...);
this->parent_->set_protect_time(v);
}
if (this->trigger_base_.has_value()) {
int v = this->trigger_base_.value(x...);
this->parent_->set_trigger_base(v);
}
if (this->trigger_keep_.has_value()) {
int v = this->trigger_keep_.value(x...);
this->parent_->set_trigger_keep(v);
}
if (this->stage_gain_.has_value()) {
int v = this->stage_gain_.value(x...);
this->parent_->set_stage_gain(v);
}
// This actually perform all the modification on the system
this->parent_->i2c_write_config();
if (this->hw_frontend_reset_.has_value() && this->hw_frontend_reset_.value(x...) == true) {
this->parent_->reset_hardware_frontend();
}
}
};
} // namespace at581x
} // namespace esphome
@@ -0,0 +1,31 @@
import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import (
DEVICE_CLASS_SWITCH,
ICON_WIFI,
)
from .. import CONF_AT581X_ID, AT581XComponent, at581x_ns
DEPENDENCIES = ["at581x"]
RFSwitch = at581x_ns.class_("RFSwitch", switch.Switch)
CONFIG_SCHEMA = switch.switch_schema(
RFSwitch,
device_class=DEVICE_CLASS_SWITCH,
icon=ICON_WIFI,
).extend(
cv.Schema(
{
cv.GenerateID(CONF_AT581X_ID): cv.use_id(AT581XComponent),
}
)
)
async def to_code(config):
at581x_component = await cg.get_variable(config[CONF_AT581X_ID])
s = await switch.new_switch(config)
await cg.register_parented(s, config[CONF_AT581X_ID])
cg.add(at581x_component.set_rf_power_switch(s))
@@ -0,0 +1,12 @@
#include "rf_switch.h"
namespace esphome {
namespace at581x {
void RFSwitch::write_state(bool state) {
this->publish_state(state);
this->parent_->set_rf_mode(state);
}
} // namespace at581x
} // namespace esphome
@@ -0,0 +1,15 @@
#pragma once
#include "esphome/components/switch/switch.h"
#include "../at581x.h"
namespace esphome {
namespace at581x {
class RFSwitch : public switch_::Switch, public Parented<AT581XComponent> {
protected:
void write_state(bool state) override;
};
} // namespace at581x
} // namespace esphome
+9 -9
View File
@@ -117,7 +117,7 @@ void ATM90E26Component::setup() {
this->write16_(ATM90E26_REGISTER_ADJSTART,
0x8765); // Checks correctness of 31-3A registers and starts normal measurement if ok
uint16_t sys_status = this->read16_(ATM90E26_REGISTER_SYSSTATUS);
const uint16_t sys_status = this->read16_(ATM90E26_REGISTER_SYSSTATUS);
if (sys_status & 0xC000) { // Checksum 1 Error
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS1 was incorrect, expected: 0x%04X",
@@ -177,27 +177,27 @@ void ATM90E26Component::write16_(uint8_t a_register, uint16_t val) {
}
float ATM90E26Component::get_line_current_() {
uint16_t current = this->read16_(ATM90E26_REGISTER_IRMS);
const uint16_t current = this->read16_(ATM90E26_REGISTER_IRMS);
return current / 1000.0f;
}
float ATM90E26Component::get_line_voltage_() {
uint16_t voltage = this->read16_(ATM90E26_REGISTER_URMS);
const uint16_t voltage = this->read16_(ATM90E26_REGISTER_URMS);
return voltage / 100.0f;
}
float ATM90E26Component::get_active_power_() {
int16_t val = this->read16_(ATM90E26_REGISTER_PMEAN); // two's complement
const int16_t val = this->read16_(ATM90E26_REGISTER_PMEAN); // two's complement
return (float) val;
}
float ATM90E26Component::get_reactive_power_() {
int16_t val = this->read16_(ATM90E26_REGISTER_QMEAN); // two's complement
const int16_t val = this->read16_(ATM90E26_REGISTER_QMEAN); // two's complement
return (float) val;
}
float ATM90E26Component::get_power_factor_() {
uint16_t val = this->read16_(ATM90E26_REGISTER_POWERF); // signed
const uint16_t val = this->read16_(ATM90E26_REGISTER_POWERF); // signed
if (val & 0x8000) {
return -(val & 0x7FF) / 1000.0f;
} else {
@@ -206,7 +206,7 @@ float ATM90E26Component::get_power_factor_() {
}
float ATM90E26Component::get_forward_active_energy_() {
uint16_t val = this->read16_(ATM90E26_REGISTER_APENERGY);
const uint16_t val = this->read16_(ATM90E26_REGISTER_APENERGY);
if ((UINT32_MAX - this->cumulative_forward_active_energy_) > val) {
this->cumulative_forward_active_energy_ += val;
} else {
@@ -217,7 +217,7 @@ float ATM90E26Component::get_forward_active_energy_() {
}
float ATM90E26Component::get_reverse_active_energy_() {
uint16_t val = this->read16_(ATM90E26_REGISTER_ANENERGY);
const uint16_t val = this->read16_(ATM90E26_REGISTER_ANENERGY);
if (UINT32_MAX - this->cumulative_reverse_active_energy_ > val) {
this->cumulative_reverse_active_energy_ += val;
} else {
@@ -227,7 +227,7 @@ float ATM90E26Component::get_reverse_active_energy_() {
}
float ATM90E26Component::get_frequency_() {
uint16_t freq = this->read16_(ATM90E26_REGISTER_FREQ);
const uint16_t freq = this->read16_(ATM90E26_REGISTER_FREQ);
return freq / 100.0f;
}
+339 -227
View File
@@ -7,82 +7,128 @@ namespace esphome {
namespace atm90e32 {
static const char *const TAG = "atm90e32";
void ATM90E32Component::loop() {
if (this->get_publish_interval_flag_()) {
this->set_publish_interval_flag_(false);
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].voltage_sensor_ != nullptr) {
this->phase_[phase].voltage_ = this->get_phase_voltage_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].current_sensor_ != nullptr) {
this->phase_[phase].current_ = this->get_phase_current_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].power_sensor_ != nullptr) {
this->phase_[phase].active_power_ = this->get_phase_active_power_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].power_factor_sensor_ != nullptr) {
this->phase_[phase].power_factor_ = this->get_phase_power_factor_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].reactive_power_sensor_ != nullptr) {
this->phase_[phase].reactive_power_ = this->get_phase_reactive_power_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].forward_active_energy_sensor_ != nullptr) {
this->phase_[phase].forward_active_energy_ = this->get_phase_forward_active_energy_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
this->phase_[phase].reverse_active_energy_ = this->get_phase_reverse_active_energy_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].phase_angle_sensor_ != nullptr) {
this->phase_[phase].phase_angle_ = this->get_phase_angle_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
this->phase_[phase].harmonic_active_power_ = this->get_phase_harmonic_active_power_(phase);
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].peak_current_sensor_ != nullptr) {
this->phase_[phase].peak_current_ = this->get_phase_peak_current_(phase);
}
}
// After the local store in collected we can publish them trusting they are withing +-1 haardware sampling
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].voltage_sensor_ != nullptr) {
this->phase_[phase].voltage_sensor_->publish_state(this->get_local_phase_voltage_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].current_sensor_ != nullptr) {
this->phase_[phase].current_sensor_->publish_state(this->get_local_phase_current_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].power_sensor_ != nullptr) {
this->phase_[phase].power_sensor_->publish_state(this->get_local_phase_active_power_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].power_factor_sensor_ != nullptr) {
this->phase_[phase].power_factor_sensor_->publish_state(this->get_local_phase_power_factor_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].reactive_power_sensor_ != nullptr) {
this->phase_[phase].reactive_power_sensor_->publish_state(this->get_local_phase_reactive_power_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].forward_active_energy_sensor_ != nullptr) {
this->phase_[phase].forward_active_energy_sensor_->publish_state(
this->get_local_phase_forward_active_energy_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
this->phase_[phase].reverse_active_energy_sensor_->publish_state(
this->get_local_phase_reverse_active_energy_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].phase_angle_sensor_ != nullptr) {
this->phase_[phase].phase_angle_sensor_->publish_state(this->get_local_phase_angle_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
this->phase_[phase].harmonic_active_power_sensor_->publish_state(
this->get_local_phase_harmonic_active_power_(phase));
}
}
for (uint8_t phase = 0; phase < 3; phase++) {
if (this->phase_[phase].peak_current_sensor_ != nullptr) {
this->phase_[phase].peak_current_sensor_->publish_state(this->get_local_phase_peak_current_(phase));
}
}
if (this->freq_sensor_ != nullptr) {
this->freq_sensor_->publish_state(this->get_frequency_());
}
if (this->chip_temperature_sensor_ != nullptr) {
this->chip_temperature_sensor_->publish_state(this->get_chip_temperature_());
}
}
}
void ATM90E32Component::update() {
if (this->read16_(ATM90E32_REGISTER_METEREN) != 1) {
this->status_set_warning();
return;
}
if (this->phase_[0].voltage_sensor_ != nullptr) {
this->phase_[0].voltage_sensor_->publish_state(this->get_line_voltage_a_());
}
if (this->phase_[1].voltage_sensor_ != nullptr) {
this->phase_[1].voltage_sensor_->publish_state(this->get_line_voltage_b_());
}
if (this->phase_[2].voltage_sensor_ != nullptr) {
this->phase_[2].voltage_sensor_->publish_state(this->get_line_voltage_c_());
}
if (this->phase_[0].current_sensor_ != nullptr) {
this->phase_[0].current_sensor_->publish_state(this->get_line_current_a_());
}
if (this->phase_[1].current_sensor_ != nullptr) {
this->phase_[1].current_sensor_->publish_state(this->get_line_current_b_());
}
if (this->phase_[2].current_sensor_ != nullptr) {
this->phase_[2].current_sensor_->publish_state(this->get_line_current_c_());
}
if (this->phase_[0].power_sensor_ != nullptr) {
this->phase_[0].power_sensor_->publish_state(this->get_active_power_a_());
}
if (this->phase_[1].power_sensor_ != nullptr) {
this->phase_[1].power_sensor_->publish_state(this->get_active_power_b_());
}
if (this->phase_[2].power_sensor_ != nullptr) {
this->phase_[2].power_sensor_->publish_state(this->get_active_power_c_());
}
if (this->phase_[0].reactive_power_sensor_ != nullptr) {
this->phase_[0].reactive_power_sensor_->publish_state(this->get_reactive_power_a_());
}
if (this->phase_[1].reactive_power_sensor_ != nullptr) {
this->phase_[1].reactive_power_sensor_->publish_state(this->get_reactive_power_b_());
}
if (this->phase_[2].reactive_power_sensor_ != nullptr) {
this->phase_[2].reactive_power_sensor_->publish_state(this->get_reactive_power_c_());
}
if (this->phase_[0].power_factor_sensor_ != nullptr) {
this->phase_[0].power_factor_sensor_->publish_state(this->get_power_factor_a_());
}
if (this->phase_[1].power_factor_sensor_ != nullptr) {
this->phase_[1].power_factor_sensor_->publish_state(this->get_power_factor_b_());
}
if (this->phase_[2].power_factor_sensor_ != nullptr) {
this->phase_[2].power_factor_sensor_->publish_state(this->get_power_factor_c_());
}
if (this->phase_[0].forward_active_energy_sensor_ != nullptr) {
this->phase_[0].forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_a_());
}
if (this->phase_[1].forward_active_energy_sensor_ != nullptr) {
this->phase_[1].forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_b_());
}
if (this->phase_[2].forward_active_energy_sensor_ != nullptr) {
this->phase_[2].forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_c_());
}
if (this->phase_[0].reverse_active_energy_sensor_ != nullptr) {
this->phase_[0].reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_a_());
}
if (this->phase_[1].reverse_active_energy_sensor_ != nullptr) {
this->phase_[1].reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_b_());
}
if (this->phase_[2].reverse_active_energy_sensor_ != nullptr) {
this->phase_[2].reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_c_());
}
if (this->freq_sensor_ != nullptr) {
this->freq_sensor_->publish_state(this->get_frequency_());
}
if (this->chip_temperature_sensor_ != nullptr) {
this->chip_temperature_sensor_->publish_state(this->get_chip_temperature_());
}
this->set_publish_interval_flag_(true);
this->status_clear_warning();
}
@@ -101,29 +147,51 @@ void ATM90E32Component::setup() {
}
this->write16_(ATM90E32_REGISTER_SOFTRESET, 0x789A); // Perform soft reset
delay(6); // Wait for the minimum 5ms + 1ms
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA); // enable register config access
this->write16_(ATM90E32_REGISTER_METEREN, 0x0001); // Enable Metering
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != 0x0001) {
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != 0x55AA) {
ESP_LOGW(TAG, "Could not initialize ATM90E32 IC, check SPI settings");
this->mark_failed();
return;
}
this->write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861); // PL Constant MSB (default) = 140625000
this->write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468); // PL Constant LSB (default)
this->write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654); // ZX2, ZX1, ZX0 pin config
this->write16_(ATM90E32_REGISTER_MMODE0, mmode0); // Mode Config (frequency set in main program)
this->write16_(ATM90E32_REGISTER_MMODE1, pga_gain_); // PGA Gain Configuration for Current Channels
this->write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C); // All Active Startup Power Threshold - 0.02A/0.00032 = 7500
this->write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10%
this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[0].volt_gain_); // A Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[0].ct_gain_); // A line current gain
this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[1].volt_gain_); // B Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[1].ct_gain_); // B line current gain
this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[2].volt_gain_); // C Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[2].ct_gain_); // C line current gain
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000); // end configuration
this->write16_(ATM90E32_REGISTER_METEREN, 0x0001); // Enable Metering
this->write16_(ATM90E32_REGISTER_SAGPEAKDETCFG, 0xFF3F); // Peak Detector time ms (15:8), Sag Period ms (7:0)
this->write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861); // PL Constant MSB (default) = 140625000
this->write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468); // PL Constant LSB (default)
this->write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654); // ZX2, ZX1, ZX0 pin config
this->write16_(ATM90E32_REGISTER_MMODE0, mmode0); // Mode Config (frequency set in main program)
this->write16_(ATM90E32_REGISTER_MMODE1, pga_gain_); // PGA Gain Configuration for Current Channels
this->write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C); // All Active Startup Power Threshold - 0.02A/0.00032 = 7500
this->write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
this->write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10%
// Setup voltage and current calibration offsets for PHASE A
this->phase_[PHASEA].voltage_offset_ = calibrate_voltage_offset_phase(PHASEA);
this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // A Voltage offset
this->phase_[PHASEA].current_offset_ = calibrate_current_offset_phase(PHASEA);
this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // A Current offset
// Setup voltage and current gain for PHASE A
this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[PHASEA].voltage_gain_); // A Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[PHASEA].ct_gain_); // A line current gain
// Setup voltage and current calibration offsets for PHASE B
this->phase_[PHASEB].voltage_offset_ = calibrate_voltage_offset_phase(PHASEB);
this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // B Voltage offset
this->phase_[PHASEB].current_offset_ = calibrate_current_offset_phase(PHASEB);
this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // B Current offset
// Setup voltage and current gain for PHASE B
this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[PHASEB].voltage_gain_); // B Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[PHASEB].ct_gain_); // B line current gain
// Setup voltage and current calibration offsets for PHASE C
this->phase_[PHASEC].voltage_offset_ = calibrate_voltage_offset_phase(PHASEC);
this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
this->phase_[PHASEC].current_offset_ = calibrate_current_offset_phase(PHASEC);
this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
// Setup voltage and current gain for PHASE C
this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[PHASEC].voltage_gain_); // C Voltage rms gain
this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[PHASEC].ct_gain_); // C line current gain
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000); // end configuration
}
void ATM90E32Component::dump_config() {
@@ -133,43 +201,54 @@ void ATM90E32Component::dump_config() {
ESP_LOGE(TAG, "Communication with ATM90E32 failed!");
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Voltage A", this->phase_[0].voltage_sensor_);
LOG_SENSOR(" ", "Current A", this->phase_[0].current_sensor_);
LOG_SENSOR(" ", "Power A", this->phase_[0].power_sensor_);
LOG_SENSOR(" ", "Reactive Power A", this->phase_[0].reactive_power_sensor_);
LOG_SENSOR(" ", "PF A", this->phase_[0].power_factor_sensor_);
LOG_SENSOR(" ", "Active Forward Energy A", this->phase_[0].forward_active_energy_sensor_);
LOG_SENSOR(" ", "Active Reverse Energy A", this->phase_[0].reverse_active_energy_sensor_);
LOG_SENSOR(" ", "Voltage B", this->phase_[1].voltage_sensor_);
LOG_SENSOR(" ", "Current B", this->phase_[1].current_sensor_);
LOG_SENSOR(" ", "Power B", this->phase_[1].power_sensor_);
LOG_SENSOR(" ", "Reactive Power B", this->phase_[1].reactive_power_sensor_);
LOG_SENSOR(" ", "PF B", this->phase_[1].power_factor_sensor_);
LOG_SENSOR(" ", "Active Forward Energy B", this->phase_[1].forward_active_energy_sensor_);
LOG_SENSOR(" ", "Active Reverse Energy B", this->phase_[1].reverse_active_energy_sensor_);
LOG_SENSOR(" ", "Voltage C", this->phase_[2].voltage_sensor_);
LOG_SENSOR(" ", "Current C", this->phase_[2].current_sensor_);
LOG_SENSOR(" ", "Power C", this->phase_[2].power_sensor_);
LOG_SENSOR(" ", "Reactive Power C", this->phase_[2].reactive_power_sensor_);
LOG_SENSOR(" ", "PF C", this->phase_[2].power_factor_sensor_);
LOG_SENSOR(" ", "Active Forward Energy C", this->phase_[2].forward_active_energy_sensor_);
LOG_SENSOR(" ", "Active Reverse Energy C", this->phase_[2].reverse_active_energy_sensor_);
LOG_SENSOR(" ", "Voltage A", this->phase_[PHASEA].voltage_sensor_);
LOG_SENSOR(" ", "Current A", this->phase_[PHASEA].current_sensor_);
LOG_SENSOR(" ", "Power A", this->phase_[PHASEA].power_sensor_);
LOG_SENSOR(" ", "Reactive Power A", this->phase_[PHASEA].reactive_power_sensor_);
LOG_SENSOR(" ", "PF A", this->phase_[PHASEA].power_factor_sensor_);
LOG_SENSOR(" ", "Active Forward Energy A", this->phase_[PHASEA].forward_active_energy_sensor_);
LOG_SENSOR(" ", "Active Reverse Energy A", this->phase_[PHASEA].reverse_active_energy_sensor_);
LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEA].harmonic_active_power_sensor_);
LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEA].phase_angle_sensor_);
LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEA].peak_current_sensor_);
LOG_SENSOR(" ", "Voltage B", this->phase_[PHASEB].voltage_sensor_);
LOG_SENSOR(" ", "Current B", this->phase_[PHASEB].current_sensor_);
LOG_SENSOR(" ", "Power B", this->phase_[PHASEB].power_sensor_);
LOG_SENSOR(" ", "Reactive Power B", this->phase_[PHASEB].reactive_power_sensor_);
LOG_SENSOR(" ", "PF B", this->phase_[PHASEB].power_factor_sensor_);
LOG_SENSOR(" ", "Active Forward Energy B", this->phase_[PHASEB].forward_active_energy_sensor_);
LOG_SENSOR(" ", "Active Reverse Energy B", this->phase_[PHASEB].reverse_active_energy_sensor_);
LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEB].harmonic_active_power_sensor_);
LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEB].phase_angle_sensor_);
LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEB].peak_current_sensor_);
LOG_SENSOR(" ", "Voltage C", this->phase_[PHASEC].voltage_sensor_);
LOG_SENSOR(" ", "Current C", this->phase_[PHASEC].current_sensor_);
LOG_SENSOR(" ", "Power C", this->phase_[PHASEC].power_sensor_);
LOG_SENSOR(" ", "Reactive Power C", this->phase_[PHASEC].reactive_power_sensor_);
LOG_SENSOR(" ", "PF C", this->phase_[PHASEC].power_factor_sensor_);
LOG_SENSOR(" ", "Active Forward Energy C", this->phase_[PHASEC].forward_active_energy_sensor_);
LOG_SENSOR(" ", "Active Reverse Energy C", this->phase_[PHASEC].reverse_active_energy_sensor_);
LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEC].harmonic_active_power_sensor_);
LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEC].phase_angle_sensor_);
LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEC].peak_current_sensor_);
LOG_SENSOR(" ", "Frequency", this->freq_sensor_);
LOG_SENSOR(" ", "Chip Temp", this->chip_temperature_sensor_);
}
float ATM90E32Component::get_setup_priority() const { return setup_priority::DATA; }
float ATM90E32Component::get_setup_priority() const { return setup_priority::IO; }
// R/C registers can conly be cleared after the LastSPIData register is updated (register 78H)
// Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period
// Default is 143FH (20ms, 63ms)
uint16_t ATM90E32Component::read16_(uint16_t a_register) {
uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
uint8_t addrl = (a_register & 0xFF);
uint8_t data[2];
uint16_t output;
this->enable();
delayMicroseconds(10);
delay_microseconds_safe(10);
this->write_byte(addrh);
this->write_byte(addrl);
delayMicroseconds(4);
this->read_array(data, 2);
this->disable();
@@ -179,9 +258,9 @@ uint16_t ATM90E32Component::read16_(uint16_t a_register) {
}
int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) {
uint16_t val_h = this->read16_(addr_h);
uint16_t val_l = this->read16_(addr_l);
int32_t val = (val_h << 16) | val_l;
const uint16_t val_h = this->read16_(addr_h);
const uint16_t val_l = this->read16_(addr_l);
const int32_t val = (val_h << 16) | val_l;
ESP_LOGVV(TAG,
"read32_ addr_h 0x%04" PRIX16 " val_h 0x%04" PRIX16 " addr_l 0x%04" PRIX16 " val_l 0x%04" PRIX16
@@ -192,141 +271,174 @@ int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) {
}
void ATM90E32Component::write16_(uint16_t a_register, uint16_t val) {
uint8_t addrh = (a_register >> 8) & 0x03;
uint8_t addrl = (a_register & 0xFF);
ESP_LOGVV(TAG, "write16_ 0x%04" PRIX16 " val 0x%04" PRIX16, a_register, val);
this->enable();
delayMicroseconds(10);
this->write_byte(addrh);
this->write_byte(addrl);
delayMicroseconds(4);
this->write_byte((val >> 8) & 0xff);
this->write_byte(val & 0xFF);
this->write_byte16(a_register);
this->write_byte16(val);
this->disable();
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != val)
ESP_LOGW(TAG, "SPI write error 0x%04X val 0x%04X", a_register, val);
}
float ATM90E32Component::get_line_voltage_a_() {
uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMSA);
float ATM90E32Component::get_local_phase_voltage_(uint8_t phase) { return this->phase_[phase].voltage_; }
float ATM90E32Component::get_local_phase_current_(uint8_t phase) { return this->phase_[phase].current_; }
float ATM90E32Component::get_local_phase_active_power_(uint8_t phase) { return this->phase_[phase].active_power_; }
float ATM90E32Component::get_local_phase_reactive_power_(uint8_t phase) { return this->phase_[phase].reactive_power_; }
float ATM90E32Component::get_local_phase_power_factor_(uint8_t phase) { return this->phase_[phase].power_factor_; }
float ATM90E32Component::get_local_phase_forward_active_energy_(uint8_t phase) {
return this->phase_[phase].forward_active_energy_;
}
float ATM90E32Component::get_local_phase_reverse_active_energy_(uint8_t phase) {
return this->phase_[phase].reverse_active_energy_;
}
float ATM90E32Component::get_local_phase_angle_(uint8_t phase) { return this->phase_[phase].phase_angle_; }
float ATM90E32Component::get_local_phase_harmonic_active_power_(uint8_t phase) {
return this->phase_[phase].harmonic_active_power_;
}
float ATM90E32Component::get_local_phase_peak_current_(uint8_t phase) { return this->phase_[phase].peak_current_; }
float ATM90E32Component::get_phase_voltage_(uint8_t phase) {
const uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMS + phase);
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != voltage)
ESP_LOGW(TAG, "SPI URMS voltage register read error.");
return (float) voltage / 100;
}
float ATM90E32Component::get_line_voltage_b_() {
uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMSB);
return (float) voltage / 100;
float ATM90E32Component::get_phase_voltage_avg_(uint8_t phase) {
const uint8_t reads = 10;
uint32_t accumulation = 0;
uint16_t voltage = 0;
for (uint8_t i = 0; i < reads; i++) {
voltage = this->read16_(ATM90E32_REGISTER_URMS + phase);
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != voltage)
ESP_LOGW(TAG, "SPI URMS voltage register read error.");
accumulation += voltage;
}
voltage = accumulation / reads;
this->phase_[phase].voltage_ = (float) voltage / 100;
return this->phase_[phase].voltage_;
}
float ATM90E32Component::get_line_voltage_c_() {
uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMSC);
return (float) voltage / 100;
float ATM90E32Component::get_phase_current_avg_(uint8_t phase) {
const uint8_t reads = 10;
uint32_t accumulation = 0;
uint16_t current = 0;
for (uint8_t i = 0; i < reads; i++) {
current = this->read16_(ATM90E32_REGISTER_IRMS + phase);
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != current)
ESP_LOGW(TAG, "SPI IRMS current register read error.");
accumulation += current;
}
current = accumulation / reads;
this->phase_[phase].current_ = (float) current / 1000;
return this->phase_[phase].current_;
}
float ATM90E32Component::get_line_current_a_() {
uint16_t current = this->read16_(ATM90E32_REGISTER_IRMSA);
float ATM90E32Component::get_phase_current_(uint8_t phase) {
const uint16_t current = this->read16_(ATM90E32_REGISTER_IRMS + phase);
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != current)
ESP_LOGW(TAG, "SPI IRMS current register read error.");
return (float) current / 1000;
}
float ATM90E32Component::get_line_current_b_() {
uint16_t current = this->read16_(ATM90E32_REGISTER_IRMSB);
return (float) current / 1000;
}
float ATM90E32Component::get_line_current_c_() {
uint16_t current = this->read16_(ATM90E32_REGISTER_IRMSC);
return (float) current / 1000;
}
float ATM90E32Component::get_active_power_a_() {
int val = this->read32_(ATM90E32_REGISTER_PMEANA, ATM90E32_REGISTER_PMEANALSB);
float ATM90E32Component::get_phase_active_power_(uint8_t phase) {
const int val = this->read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
return val * 0.00032f;
}
float ATM90E32Component::get_active_power_b_() {
int val = this->read32_(ATM90E32_REGISTER_PMEANB, ATM90E32_REGISTER_PMEANBLSB);
float ATM90E32Component::get_phase_reactive_power_(uint8_t phase) {
const int val = this->read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase);
return val * 0.00032f;
}
float ATM90E32Component::get_active_power_c_() {
int val = this->read32_(ATM90E32_REGISTER_PMEANC, ATM90E32_REGISTER_PMEANCLSB);
float ATM90E32Component::get_phase_power_factor_(uint8_t phase) {
const int16_t powerfactor = this->read16_(ATM90E32_REGISTER_PFMEAN + phase);
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != powerfactor)
ESP_LOGW(TAG, "SPI power factor read error.");
return (float) powerfactor / 1000;
}
float ATM90E32Component::get_phase_forward_active_energy_(uint8_t phase) {
const uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGY + phase);
if ((UINT32_MAX - this->phase_[phase].cumulative_forward_active_energy_) > val) {
this->phase_[phase].cumulative_forward_active_energy_ += val;
} else {
this->phase_[phase].cumulative_forward_active_energy_ = val;
}
return ((float) this->phase_[phase].cumulative_forward_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_phase_reverse_active_energy_(uint8_t phase) {
const uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGY);
if (UINT32_MAX - this->phase_[phase].cumulative_reverse_active_energy_ > val) {
this->phase_[phase].cumulative_reverse_active_energy_ += val;
} else {
this->phase_[phase].cumulative_reverse_active_energy_ = val;
}
return ((float) this->phase_[phase].cumulative_reverse_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_phase_harmonic_active_power_(uint8_t phase) {
int val = this->read32_(ATM90E32_REGISTER_PMEANH + phase, ATM90E32_REGISTER_PMEANHLSB + phase);
return val * 0.00032f;
}
float ATM90E32Component::get_reactive_power_a_() {
int val = this->read32_(ATM90E32_REGISTER_QMEANA, ATM90E32_REGISTER_QMEANALSB);
return val * 0.00032f;
float ATM90E32Component::get_phase_angle_(uint8_t phase) {
uint16_t val = this->read16_(ATM90E32_REGISTER_PANGLE + phase) / 10.0;
return (float) (val > 180) ? val - 360.0 : val;
}
float ATM90E32Component::get_reactive_power_b_() {
int val = this->read32_(ATM90E32_REGISTER_QMEANB, ATM90E32_REGISTER_QMEANBLSB);
return val * 0.00032f;
}
float ATM90E32Component::get_reactive_power_c_() {
int val = this->read32_(ATM90E32_REGISTER_QMEANC, ATM90E32_REGISTER_QMEANCLSB);
return val * 0.00032f;
}
float ATM90E32Component::get_power_factor_a_() {
int16_t pf = this->read16_(ATM90E32_REGISTER_PFMEANA);
return (float) pf / 1000;
}
float ATM90E32Component::get_power_factor_b_() {
int16_t pf = this->read16_(ATM90E32_REGISTER_PFMEANB);
return (float) pf / 1000;
}
float ATM90E32Component::get_power_factor_c_() {
int16_t pf = this->read16_(ATM90E32_REGISTER_PFMEANC);
return (float) pf / 1000;
}
float ATM90E32Component::get_forward_active_energy_a_() {
uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGYA);
if ((UINT32_MAX - this->phase_[0].cumulative_forward_active_energy_) > val) {
this->phase_[0].cumulative_forward_active_energy_ += val;
} else {
this->phase_[0].cumulative_forward_active_energy_ = val;
}
return ((float) this->phase_[0].cumulative_forward_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_forward_active_energy_b_() {
uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGYB);
if (UINT32_MAX - this->phase_[1].cumulative_forward_active_energy_ > val) {
this->phase_[1].cumulative_forward_active_energy_ += val;
} else {
this->phase_[1].cumulative_forward_active_energy_ = val;
}
return ((float) this->phase_[1].cumulative_forward_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_forward_active_energy_c_() {
uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGYC);
if (UINT32_MAX - this->phase_[2].cumulative_forward_active_energy_ > val) {
this->phase_[2].cumulative_forward_active_energy_ += val;
} else {
this->phase_[2].cumulative_forward_active_energy_ = val;
}
return ((float) this->phase_[2].cumulative_forward_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_reverse_active_energy_a_() {
uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGYA);
if (UINT32_MAX - this->phase_[0].cumulative_reverse_active_energy_ > val) {
this->phase_[0].cumulative_reverse_active_energy_ += val;
} else {
this->phase_[0].cumulative_reverse_active_energy_ = val;
}
return ((float) this->phase_[0].cumulative_reverse_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_reverse_active_energy_b_() {
uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGYB);
if (UINT32_MAX - this->phase_[1].cumulative_reverse_active_energy_ > val) {
this->phase_[1].cumulative_reverse_active_energy_ += val;
} else {
this->phase_[1].cumulative_reverse_active_energy_ = val;
}
return ((float) this->phase_[1].cumulative_reverse_active_energy_ * 10 / 3200);
}
float ATM90E32Component::get_reverse_active_energy_c_() {
uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGYC);
if (UINT32_MAX - this->phase_[2].cumulative_reverse_active_energy_ > val) {
this->phase_[2].cumulative_reverse_active_energy_ += val;
} else {
this->phase_[2].cumulative_reverse_active_energy_ = val;
}
return ((float) this->phase_[2].cumulative_reverse_active_energy_ * 10 / 3200);
float ATM90E32Component::get_phase_peak_current_(uint8_t phase) {
int16_t val = (float) this->read16_(ATM90E32_REGISTER_IPEAK + phase);
if (!this->peak_current_signed_)
val = abs(val);
// phase register * phase current gain value / 1000 * 2^13
return (float) (val * this->phase_[phase].ct_gain_ / 8192000.0);
}
float ATM90E32Component::get_frequency_() {
uint16_t freq = this->read16_(ATM90E32_REGISTER_FREQ);
const uint16_t freq = this->read16_(ATM90E32_REGISTER_FREQ);
return (float) freq / 100;
}
float ATM90E32Component::get_chip_temperature_() {
uint16_t ctemp = this->read16_(ATM90E32_REGISTER_TEMP);
const uint16_t ctemp = this->read16_(ATM90E32_REGISTER_TEMP);
return (float) ctemp;
}
uint16_t ATM90E32Component::calibrate_voltage_offset_phase(uint8_t phase) {
const uint8_t num_reads = 5;
uint64_t total_value = 0;
for (int i = 0; i < num_reads; ++i) {
const uint32_t measurement_value = read32_(ATM90E32_REGISTER_URMS + phase, ATM90E32_REGISTER_URMSLSB + phase);
total_value += measurement_value;
}
const uint32_t average_value = total_value / num_reads;
const uint32_t shifted_value = average_value >> 7;
const uint32_t voltage_offset = ~shifted_value + 1;
return voltage_offset & 0xFFFF; // Take the lower 16 bits
}
uint16_t ATM90E32Component::calibrate_current_offset_phase(uint8_t phase) {
const uint8_t num_reads = 5;
uint64_t total_value = 0;
for (int i = 0; i < num_reads; ++i) {
const uint32_t measurement_value = read32_(ATM90E32_REGISTER_IRMS + phase, ATM90E32_REGISTER_IRMSLSB + phase);
total_value += measurement_value;
}
const uint32_t average_value = total_value / num_reads;
const uint32_t current_offset = ~average_value + 1;
return current_offset & 0xFFFF; // Take the lower 16 bits
}
} // namespace atm90e32
} // namespace esphome
+62 -26
View File
@@ -3,14 +3,19 @@
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/spi/spi.h"
#include "atm90e32_reg.h"
namespace esphome {
namespace atm90e32 {
class ATM90E32Component : public PollingComponent,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH,
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_200KHZ> {
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_1MHZ> {
public:
static const uint8_t PHASEA = 0;
static const uint8_t PHASEB = 1;
static const uint8_t PHASEC = 2;
void loop() override;
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
@@ -20,6 +25,7 @@ class ATM90E32Component : public PollingComponent,
void set_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].current_sensor_ = obj; }
void set_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_sensor_ = obj; }
void set_reactive_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].reactive_power_sensor_ = obj; }
void set_apparent_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].apparent_power_sensor_ = obj; }
void set_forward_active_energy_sensor(int phase, sensor::Sensor *obj) {
this->phase_[phase].forward_active_energy_sensor_ = obj;
}
@@ -27,64 +33,94 @@ class ATM90E32Component : public PollingComponent,
this->phase_[phase].reverse_active_energy_sensor_ = obj;
}
void set_power_factor_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_factor_sensor_ = obj; }
void set_volt_gain(int phase, uint16_t gain) { this->phase_[phase].volt_gain_ = gain; }
void set_phase_angle_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].phase_angle_sensor_ = obj; }
void set_harmonic_active_power_sensor(int phase, sensor::Sensor *obj) {
this->phase_[phase].harmonic_active_power_sensor_ = obj;
}
void set_peak_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].peak_current_sensor_ = obj; }
void set_volt_gain(int phase, uint16_t gain) { this->phase_[phase].voltage_gain_ = gain; }
void set_ct_gain(int phase, uint16_t gain) { this->phase_[phase].ct_gain_ = gain; }
void set_freq_sensor(sensor::Sensor *freq_sensor) { freq_sensor_ = freq_sensor; }
void set_peak_current_signed(bool flag) { peak_current_signed_ = flag; }
void set_chip_temperature_sensor(sensor::Sensor *chip_temperature_sensor) {
chip_temperature_sensor_ = chip_temperature_sensor;
}
void set_line_freq(int freq) { line_freq_ = freq; }
void set_current_phases(int phases) { current_phases_ = phases; }
void set_pga_gain(uint16_t gain) { pga_gain_ = gain; }
uint16_t calibrate_voltage_offset_phase(uint8_t /*phase*/);
uint16_t calibrate_current_offset_phase(uint8_t /*phase*/);
int32_t last_periodic_millis = millis();
protected:
uint16_t read16_(uint16_t a_register);
int read32_(uint16_t addr_h, uint16_t addr_l);
void write16_(uint16_t a_register, uint16_t val);
float get_line_voltage_a_();
float get_line_voltage_b_();
float get_line_voltage_c_();
float get_line_current_a_();
float get_line_current_b_();
float get_line_current_c_();
float get_active_power_a_();
float get_active_power_b_();
float get_active_power_c_();
float get_reactive_power_a_();
float get_reactive_power_b_();
float get_reactive_power_c_();
float get_power_factor_a_();
float get_power_factor_b_();
float get_power_factor_c_();
float get_forward_active_energy_a_();
float get_forward_active_energy_b_();
float get_forward_active_energy_c_();
float get_reverse_active_energy_a_();
float get_reverse_active_energy_b_();
float get_reverse_active_energy_c_();
float get_local_phase_voltage_(uint8_t /*phase*/);
float get_local_phase_current_(uint8_t /*phase*/);
float get_local_phase_active_power_(uint8_t /*phase*/);
float get_local_phase_reactive_power_(uint8_t /*phase*/);
float get_local_phase_power_factor_(uint8_t /*phase*/);
float get_local_phase_forward_active_energy_(uint8_t /*phase*/);
float get_local_phase_reverse_active_energy_(uint8_t /*phase*/);
float get_local_phase_angle_(uint8_t /*phase*/);
float get_local_phase_harmonic_active_power_(uint8_t /*phase*/);
float get_local_phase_peak_current_(uint8_t /*phase*/);
float get_phase_voltage_(uint8_t /*phase*/);
float get_phase_voltage_avg_(uint8_t /*phase*/);
float get_phase_current_(uint8_t /*phase*/);
float get_phase_current_avg_(uint8_t /*phase*/);
float get_phase_active_power_(uint8_t /*phase*/);
float get_phase_reactive_power_(uint8_t /*phase*/);
float get_phase_power_factor_(uint8_t /*phase*/);
float get_phase_forward_active_energy_(uint8_t /*phase*/);
float get_phase_reverse_active_energy_(uint8_t /*phase*/);
float get_phase_angle_(uint8_t /*phase*/);
float get_phase_harmonic_active_power_(uint8_t /*phase*/);
float get_phase_peak_current_(uint8_t /*phase*/);
float get_frequency_();
float get_chip_temperature_();
bool get_publish_interval_flag_() { return publish_interval_flag_; };
void set_publish_interval_flag_(bool flag) { publish_interval_flag_ = flag; };
struct ATM90E32Phase {
uint16_t volt_gain_{7305};
uint16_t voltage_gain_{7305};
uint16_t ct_gain_{27961};
uint16_t voltage_offset_{0};
uint16_t current_offset_{0};
float voltage_{0};
float current_{0};
float active_power_{0};
float reactive_power_{0};
float power_factor_{0};
float forward_active_energy_{0};
float reverse_active_energy_{0};
float phase_angle_{0};
float harmonic_active_power_{0};
float peak_current_{0};
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *reactive_power_sensor_{nullptr};
sensor::Sensor *apparent_power_sensor_{nullptr};
sensor::Sensor *power_factor_sensor_{nullptr};
sensor::Sensor *forward_active_energy_sensor_{nullptr};
sensor::Sensor *reverse_active_energy_sensor_{nullptr};
sensor::Sensor *phase_angle_sensor_{nullptr};
sensor::Sensor *harmonic_active_power_sensor_{nullptr};
sensor::Sensor *peak_current_sensor_{nullptr};
uint32_t cumulative_forward_active_energy_{0};
uint32_t cumulative_reverse_active_energy_{0};
} phase_[3];
sensor::Sensor *freq_sensor_{nullptr};
sensor::Sensor *chip_temperature_sensor_{nullptr};
uint16_t pga_gain_{0x15};
int line_freq_{60};
int current_phases_{3};
bool publish_interval_flag_{true};
bool peak_current_signed_{false};
};
} // namespace atm90e32
@@ -131,10 +131,12 @@ static const uint16_t ATM90E32_REGISTER_IOFFSETN = 0x6E; // N Current Offset
/* ENERGY REGISTERS */
static const uint16_t ATM90E32_REGISTER_APENERGYT = 0x80; // Total Forward Active
static const uint16_t ATM90E32_REGISTER_APENERGY = 0x81; // Forward Active Reg Base
static const uint16_t ATM90E32_REGISTER_APENERGYA = 0x81; // A Forward Active
static const uint16_t ATM90E32_REGISTER_APENERGYB = 0x82; // B Forward Active
static const uint16_t ATM90E32_REGISTER_APENERGYC = 0x83; // C Forward Active
static const uint16_t ATM90E32_REGISTER_ANENERGYT = 0x84; // Total Reverse Active
static const uint16_t ATM90E32_REGISTER_ANENERGY = 0x85; // Reverse Active Reg Base
static const uint16_t ATM90E32_REGISTER_ANENERGYA = 0x85; // A Reverse Active
static const uint16_t ATM90E32_REGISTER_ANENERGYB = 0x86; // B Reverse Active
static const uint16_t ATM90E32_REGISTER_ANENERGYC = 0x87; // C Reverse Active
@@ -172,10 +174,12 @@ static const uint16_t ATM90E32_REGISTER_ANENERGYCH = 0xAF; // C Reverse Harm. E
/* POWER & P.F. REGISTERS */
static const uint16_t ATM90E32_REGISTER_PMEANT = 0xB0; // Total Mean Power (P)
static const uint16_t ATM90E32_REGISTER_PMEAN = 0xB1; // Mean Power Reg Base (P)
static const uint16_t ATM90E32_REGISTER_PMEANA = 0xB1; // A Mean Power (P)
static const uint16_t ATM90E32_REGISTER_PMEANB = 0xB2; // B Mean Power (P)
static const uint16_t ATM90E32_REGISTER_PMEANC = 0xB3; // C Mean Power (P)
static const uint16_t ATM90E32_REGISTER_QMEANT = 0xB4; // Total Mean Power (Q)
static const uint16_t ATM90E32_REGISTER_QMEAN = 0xB5; // Mean Power Reg Base (Q)
static const uint16_t ATM90E32_REGISTER_QMEANA = 0xB5; // A Mean Power (Q)
static const uint16_t ATM90E32_REGISTER_QMEANB = 0xB6; // B Mean Power (Q)
static const uint16_t ATM90E32_REGISTER_QMEANC = 0xB7; // C Mean Power (Q)
@@ -184,15 +188,18 @@ static const uint16_t ATM90E32_REGISTER_SMEANA = 0xB9; // A Mean Power (S)
static const uint16_t ATM90E32_REGISTER_SMEANB = 0xBA; // B Mean Power (S)
static const uint16_t ATM90E32_REGISTER_SMEANC = 0xBB; // C Mean Power (S)
static const uint16_t ATM90E32_REGISTER_PFMEANT = 0xBC; // Mean Power Factor
static const uint16_t ATM90E32_REGISTER_PFMEAN = 0xBD; // Power Factor Reg Base
static const uint16_t ATM90E32_REGISTER_PFMEANA = 0xBD; // A Power Factor
static const uint16_t ATM90E32_REGISTER_PFMEANB = 0xBE; // B Power Factor
static const uint16_t ATM90E32_REGISTER_PFMEANC = 0xBF; // C Power Factor
static const uint16_t ATM90E32_REGISTER_PMEANTLSB = 0xC0; // Lower Word (Tot. Act. Power)
static const uint16_t ATM90E32_REGISTER_PMEANLSB = 0xC1; // Lower Word Reg Base (Active Power)
static const uint16_t ATM90E32_REGISTER_PMEANALSB = 0xC1; // Lower Word (A Act. Power)
static const uint16_t ATM90E32_REGISTER_PMEANBLSB = 0xC2; // Lower Word (B Act. Power)
static const uint16_t ATM90E32_REGISTER_PMEANCLSB = 0xC3; // Lower Word (C Act. Power)
static const uint16_t ATM90E32_REGISTER_QMEANTLSB = 0xC4; // Lower Word (Tot. React. Power)
static const uint16_t ATM90E32_REGISTER_QMEANLSB = 0xC5; // Lower Word Reg Base (Reactive Power)
static const uint16_t ATM90E32_REGISTER_QMEANALSB = 0xC5; // Lower Word (A React. Power)
static const uint16_t ATM90E32_REGISTER_QMEANBLSB = 0xC6; // Lower Word (B React. Power)
static const uint16_t ATM90E32_REGISTER_QMEANCLSB = 0xC7; // Lower Word (C React. Power)
@@ -207,12 +214,15 @@ static const uint16_t ATM90E32_REGISTER_PMEANAF = 0xD1; // A Active Fund. Power
static const uint16_t ATM90E32_REGISTER_PMEANBF = 0xD2; // B Active Fund. Power
static const uint16_t ATM90E32_REGISTER_PMEANCF = 0xD3; // C Active Fund. Power
static const uint16_t ATM90E32_REGISTER_PMEANTH = 0xD4; // Total Active Harm. Power
static const uint16_t ATM90E32_REGISTER_PMEANH = 0xD5; // Active Harm. Power Reg Base
static const uint16_t ATM90E32_REGISTER_PMEANAH = 0xD5; // A Active Harm. Power
static const uint16_t ATM90E32_REGISTER_PMEANBH = 0xD6; // B Active Harm. Power
static const uint16_t ATM90E32_REGISTER_PMEANCH = 0xD7; // C Active Harm. Power
static const uint16_t ATM90E32_REGISTER_URMS = 0xD9; // RMS Voltage Reg Base
static const uint16_t ATM90E32_REGISTER_URMSA = 0xD9; // A RMS Voltage
static const uint16_t ATM90E32_REGISTER_URMSB = 0xDA; // B RMS Voltage
static const uint16_t ATM90E32_REGISTER_URMSC = 0xDB; // C RMS Voltage
static const uint16_t ATM90E32_REGISTER_IRMS = 0xDD; // RMS Current Reg Base
static const uint16_t ATM90E32_REGISTER_IRMSA = 0xDD; // A RMS Current
static const uint16_t ATM90E32_REGISTER_IRMSB = 0xDE; // B RMS Current
static const uint16_t ATM90E32_REGISTER_IRMSC = 0xDF; // C RMS Current
@@ -223,12 +233,15 @@ static const uint16_t ATM90E32_REGISTER_PMEANAFLSB = 0xE1; // Lower Word (A Act
static const uint16_t ATM90E32_REGISTER_PMEANBFLSB = 0xE2; // Lower Word (B Act. Fund. Power)
static const uint16_t ATM90E32_REGISTER_PMEANCFLSB = 0xE3; // Lower Word (C Act. Fund. Power)
static const uint16_t ATM90E32_REGISTER_PMEANTHLSB = 0xE4; // Lower Word (Tot. Act. Harm. Power)
static const uint16_t ATM90E32_REGISTER_PMEANHLSB = 0xE5; // Lower Word (A Act. Harm. Power) Reg Base
static const uint16_t ATM90E32_REGISTER_PMEANAHLSB = 0xE5; // Lower Word (A Act. Harm. Power)
static const uint16_t ATM90E32_REGISTER_PMEANBHLSB = 0xE6; // Lower Word (B Act. Harm. Power)
static const uint16_t ATM90E32_REGISTER_PMEANCHLSB = 0xE7; // Lower Word (C Act. Harm. Power)
static const uint16_t ATM90E32_REGISTER_URMSLSB = 0xE9; // Lower Word RMS Voltage Reg Base
static const uint16_t ATM90E32_REGISTER_URMSALSB = 0xE9; // Lower Word (A RMS Voltage)
static const uint16_t ATM90E32_REGISTER_URMSBLSB = 0xEA; // Lower Word (B RMS Voltage)
static const uint16_t ATM90E32_REGISTER_URMSCLSB = 0xEB; // Lower Word (C RMS Voltage)
static const uint16_t ATM90E32_REGISTER_IRMSLSB = 0xED; // Lower Word RMS Current Reg Base
static const uint16_t ATM90E32_REGISTER_IRMSALSB = 0xED; // Lower Word (A RMS Current)
static const uint16_t ATM90E32_REGISTER_IRMSBLSB = 0xEE; // Lower Word (B RMS Current)
static const uint16_t ATM90E32_REGISTER_IRMSCLSB = 0xEF; // Lower Word (C RMS Current)
@@ -237,10 +250,12 @@ static const uint16_t ATM90E32_REGISTER_IRMSCLSB = 0xEF; // Lower Word (C RMS
static const uint16_t ATM90E32_REGISTER_UPEAKA = 0xF1; // A Voltage Peak
static const uint16_t ATM90E32_REGISTER_UPEAKB = 0xF2; // B Voltage Peak
static const uint16_t ATM90E32_REGISTER_UPEAKC = 0xF3; // C Voltage Peak
static const uint16_t ATM90E32_REGISTER_IPEAK = 0xF5; // Peak Current Reg Base
static const uint16_t ATM90E32_REGISTER_IPEAKA = 0xF5; // A Current Peak
static const uint16_t ATM90E32_REGISTER_IPEAKB = 0xF6; // B Current Peak
static const uint16_t ATM90E32_REGISTER_IPEAKC = 0xF7; // C Current Peak
static const uint16_t ATM90E32_REGISTER_FREQ = 0xF8; // Frequency
static const uint16_t ATM90E32_REGISTER_PANGLE = 0xF9; // Mean Phase Angle Reg Base
static const uint16_t ATM90E32_REGISTER_PANGLEA = 0xF9; // A Mean Phase Angle
static const uint16_t ATM90E32_REGISTER_PANGLEB = 0xFA; // B Mean Phase Angle
static const uint16_t ATM90E32_REGISTER_PANGLEC = 0xFB; // C Mean Phase Angle
+48 -3
View File
@@ -9,8 +9,10 @@ from esphome.const import (
CONF_PHASE_A,
CONF_PHASE_B,
CONF_PHASE_C,
CONF_PHASE_ANGLE,
CONF_POWER,
CONF_POWER_FACTOR,
CONF_APPARENT_POWER,
CONF_FREQUENCY,
CONF_FORWARD_ACTIVE_ENERGY,
CONF_REVERSE_ACTIVE_ENERGY,
@@ -25,12 +27,13 @@ from esphome.const import (
ICON_CURRENT_AC,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_DEGREES,
UNIT_CELSIUS,
UNIT_HERTZ,
UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
UNIT_CELSIUS,
UNIT_VOLT_AMPS_REACTIVE,
UNIT_WATT,
UNIT_WATT_HOURS,
)
@@ -40,6 +43,10 @@ CONF_GAIN_PGA = "gain_pga"
CONF_CURRENT_PHASES = "current_phases"
CONF_GAIN_VOLTAGE = "gain_voltage"
CONF_GAIN_CT = "gain_ct"
CONF_HARMONIC_POWER = "harmonic_power"
CONF_PEAK_CURRENT = "peak_current"
CONF_PEAK_CURRENT_SIGNED = "peak_current_signed"
UNIT_DEG = "degrees"
LINE_FREQS = {
"50HZ": 50,
"60HZ": 60,
@@ -85,6 +92,12 @@ ATM90E32_PHASE_SCHEMA = cv.Schema(
accuracy_decimals=2,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_APPARENT_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema(
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER_FACTOR,
@@ -102,6 +115,24 @@ ATM90E32_PHASE_SCHEMA = cv.Schema(
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_PHASE_ANGLE): sensor.sensor_schema(
unit_of_measurement=UNIT_DEGREES,
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_HARMONIC_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_PEAK_CURRENT): sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=2,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t,
cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t,
}
@@ -132,6 +163,7 @@ CONFIG_SCHEMA = (
CURRENT_PHASES, upper=True
),
cv.Optional(CONF_GAIN_PGA, default="2X"): cv.enum(PGA_GAINS, upper=True),
cv.Optional(CONF_PEAK_CURRENT_SIGNED, default=False): cv.boolean,
}
)
.extend(cv.polling_component_schema("60s"))
@@ -162,6 +194,9 @@ async def to_code(config):
if reactive_power_config := conf.get(CONF_REACTIVE_POWER):
sens = await sensor.new_sensor(reactive_power_config)
cg.add(var.set_reactive_power_sensor(i, sens))
if apparent_power_config := conf.get(CONF_APPARENT_POWER):
sens = await sensor.new_sensor(apparent_power_config)
cg.add(var.set_apparent_power_sensor(i, sens))
if power_factor_config := conf.get(CONF_POWER_FACTOR):
sens = await sensor.new_sensor(power_factor_config)
cg.add(var.set_power_factor_sensor(i, sens))
@@ -171,6 +206,15 @@ async def to_code(config):
if reverse_active_energy_config := conf.get(CONF_REVERSE_ACTIVE_ENERGY):
sens = await sensor.new_sensor(reverse_active_energy_config)
cg.add(var.set_reverse_active_energy_sensor(i, sens))
if phase_angle_config := conf.get(CONF_PHASE_ANGLE):
sens = await sensor.new_sensor(phase_angle_config)
cg.add(var.set_phase_angle_sensor(i, sens))
if harmonic_active_power_config := conf.get(CONF_HARMONIC_POWER):
sens = await sensor.new_sensor(harmonic_active_power_config)
cg.add(var.set_harmonic_active_power_sensor(i, sens))
if peak_current_config := conf.get(CONF_PEAK_CURRENT):
sens = await sensor.new_sensor(peak_current_config)
cg.add(var.set_peak_current_sensor(i, sens))
if frequency_config := config.get(CONF_FREQUENCY):
sens = await sensor.new_sensor(frequency_config)
@@ -182,3 +226,4 @@ async def to_code(config):
cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES]))
cg.add(var.set_pga_gain(config[CONF_GAIN_PGA]))
cg.add(var.set_peak_current_signed(config[CONF_PEAK_CURRENT_SIGNED]))
@@ -194,8 +194,8 @@ void BangBangClimate::dump_config() {
ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_));
ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_));
ESP_LOGCONFIG(TAG, " Supports AWAY mode: %s", YESNO(this->supports_away_));
ESP_LOGCONFIG(TAG, " Default Target Temperature Low: %.1f°C", this->normal_config_.default_temperature_low);
ESP_LOGCONFIG(TAG, " Default Target Temperature High: %.1f°C", this->normal_config_.default_temperature_high);
ESP_LOGCONFIG(TAG, " Default Target Temperature Low: %.2f°C", this->normal_config_.default_temperature_low);
ESP_LOGCONFIG(TAG, " Default Target Temperature High: %.2f°C", this->normal_config_.default_temperature_high);
}
BangBangClimateTargetTempConfig::BangBangClimateTargetTempConfig() = default;
+1 -1
View File
@@ -31,7 +31,7 @@ CONFIG_SCHEMA = (
BEDJET_CLIENT_SCHEMA = cv.Schema(
{
cv.Required(CONF_BEDJET_ID): cv.use_id(BedJetHub),
cv.GenerateID(CONF_BEDJET_ID): cv.use_id(BedJetHub),
}
)
@@ -157,5 +157,11 @@ bool BedjetCodec::compare(const uint8_t *data, uint16_t length) {
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 esphome
+3
View File
@@ -187,5 +187,8 @@ class BedjetCodec {
BedjetStatusPacket buf_;
};
/// Converts a BedJet temp step into degrees Celsius.
float bedjet_temp_to_c(uint8_t temp);
} // namespace bedjet
} // namespace esphome
+8
View File
@@ -40,6 +40,14 @@ enum BedjetHeatMode {
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 {
/// Turn BedJet off
BTN_OFF = 0x1,
@@ -7,6 +7,7 @@ from esphome.const import (
CONF_HEAT_MODE,
CONF_ID,
CONF_RECEIVE_TIMEOUT,
CONF_TEMPERATURE_SOURCE,
CONF_TIME_ID,
)
from .. import (
@@ -21,10 +22,15 @@ DEPENDENCIES = ["bedjet"]
BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent)
BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode")
BedjetTemperatureSource = bedjet_ns.enum("BedjetTemperatureSource")
BEDJET_HEAT_MODES = {
"heat": BedjetHeatMode.HEAT_MODE_HEAT,
"extended": BedjetHeatMode.HEAT_MODE_EXTENDED,
}
BEDJET_TEMPERATURE_SOURCES = {
"outlet": BedjetTemperatureSource.TEMPERATURE_SOURCE_OUTLET,
"ambient": BedjetTemperatureSource.TEMPERATURE_SOURCE_AMBIENT,
}
CONFIG_SCHEMA = (
climate.CLIMATE_SCHEMA.extend(
@@ -33,6 +39,9 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum(
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"))
@@ -63,3 +72,4 @@ async def to_code(config):
await register_bedjet_child(var, config)
cg.add(var.set_heating_mode(config[CONF_HEAT_MODE]))
cg.add(var.set_temperature_source(config[CONF_TEMPERATURE_SOURCE]))
@@ -8,12 +8,6 @@ namespace bedjet {
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) {
if (fan_step < BEDJET_FAN_SPEED_COUNT)
return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step];
@@ -236,9 +230,14 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) {
if (converted_temp > 0)
this->target_temperature = converted_temp;
converted_temp = bedjet_temp_to_c(data->ambient_temp_step);
if (converted_temp > 0)
if (this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET) {
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;
}
const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step);
if (fan_mode_name != nullptr) {
@@ -28,6 +28,8 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
/** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */
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 {
auto traits = climate::ClimateTraits();
@@ -74,6 +76,7 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
void control(const climate::ClimateCall &call) override;
BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT;
BedjetTemperatureSource temperature_source_ = TEMPERATURE_SOURCE_AMBIENT;
void reset_state_();
bool update_status_();
@@ -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))
@@ -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
@@ -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

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