Compare commits

..

688 Commits

Author SHA1 Message Date
Jesse Hills
8a83670f54 Merge pull request #6891 from esphome/bump-2024.6.0b1
2024.6.0b1
2024-06-12 19:28:36 +12:00
Jesse Hills
f9f98fa6c6 Bump version to 2024.6.0b1 2024-06-12 14:16:43 +12:00
Clyde Stubbs
f25c296303 [ili9xxx] Implement st7735 support (#6838) 2024-06-12 13:47:52 +12:00
Clyde Stubbs
bc408ad08c [display] SDL2 display driver for host platform (#6825) 2024-06-12 13:42:01 +12:00
Tudor Sandu
e2c1af199c Fix media_player.volume_set when media player is not started (#6859)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-06-12 01:39:01 +00:00
Clyde Stubbs
7c843437a7 [config] Early termination of validation steps on error (#6837) 2024-06-12 13:26:43 +12:00
Gábor Poczkodi
4bf7c97088 WebSocket overrides check_origin for reverse proxy configuration (#6845) 2024-06-12 13:19:18 +12:00
Clyde Stubbs
7b9fb57bb2 [config] Retain path information in validated configuration (#6785) 2024-06-12 13:15:57 +12:00
guillempages
699d00e218 [image] Make PIL import local (#6864) 2024-06-12 13:11:00 +12:00
Clyde Stubbs
e2784d077d [he60r] Don't publish state unless it has changed. [BUGFIX] (#6869) 2024-06-12 13:09:20 +12:00
Samuel Sieb
13fabf1cd8 change to new 1-wire platform (#6860)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-06-12 13:05:44 +12:00
NMartin354
7b60543afd [safe_mode] Allow user-defined interval for successful boot (#6882)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2024-06-12 12:38:20 +12:00
Daniel D'Abate
562700bd2c Climate IR LG - Support fan only mode and all "on" commands (#3712) 2024-06-11 17:04:25 -07:00
Peter Ericson
a64106e48c [waveshare_epaper] Add support for 13.3in-k (#6443) 2024-06-12 11:51:04 +12:00
Landon Rohatensky
c723fd1f80 [animation] Allow loading external url at build time (#6876) 2024-06-12 10:56:27 +12:00
Anton Sergunov
3a97244b83 [Deep sleep] Compilation error with IDF >= 5.* (#6879) 2024-06-12 10:42:20 +12:00
Pieter Viljoen
1f8449ec0e [Dockerfile] Sync platformio version with requirements.txt (#6888) 2024-06-12 10:38:26 +12:00
Jesse Hills
3cd2fb0843 [core] Update Entities (#6885) 2024-06-12 09:57:36 +12:00
esphomebot
7dc07c5632 Update webserver local assets to 20240610-230854 (#6886) 2024-06-10 23:33:42 +00:00
Jesse Hills
95e45dc12c Allow parse_json to return a boolean result (#6884)
* Allow parse_json to return a boolean result

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

* Fix ifdefs

* Lint

* clang

* Set else to fail with error message

* Use unique_ptr

* Fix

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

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

* Remove unique_ptr wrapper

* Fix

* Use reference

* Add duration code into new split files

* Add config for tx/rx buffer on idf

* Fix

* Try reserve response data with rx buffer size

* Update http_request.h

* Move client cleanup to be earlier

* Move capture_response to bool on struct and remove global

* Fix returns

* Change quotes to brackets

* Rework http request

* Remove http request from old test yamls

* Update component tests

* Validate md5 length when hardcoded string

* Linting

* Add duration_ms to container

* More lint

* const

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

* Add virtual destructor to HttpContainer

* Undo const HEADER_KEYS

* 🤦

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

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

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

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

* lint

* Move header keys inline

* Add missing WatchdogManagers

* CAPS

* Fix "follow redirects" string in config dump

* IDF 5+ fix

---------

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

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

* Set operatingmode on other than ESP-IDF

---------

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

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

* Disable ipv6 for bk72 wireguard test

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

Added missing millimeter

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

* LTR303 tidy up

* LTR303 unused var

* LTR303 tidy up + test

* LTR303 auto sensitivity mode

* LTR303 auto sensitivity mode tidy

* LTR303 State machine version

* LTR303 name fix

* publish split

* minor

* new definitions for LTR

* als-ps test

* als-ps test

* als-ps test

* ps options

* ps options

* trgger bug fixed

* trgger bug fixed

* Minor comments

* ltr303->ltr_als_ps

* codeowners, tests

* tidy up

* tidy up

* tidy up

* gain enum name fix

* auto gain fix

* tweaks

* new style tests

* als/ps separate init

* logd->logv

* reconfiguration count changed

* old-style tests removed

* const py

* ambient light const in vmel7700 and ltr390

* Update esphome/components/ltr_als_ps/ltr_als_ps.cpp

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

* Apply suggestions from code review

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

* remove commented code

---------

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

* add idfv5 specific w5500 config init

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

* Header fix

* Couple tweaks

---------

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

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

Replace usage of I2S_NUM_MAX with I2S_NUM_1

* Update i2s_audio_microphone.cpp

Replace I2S_MCLK_MULTIPLE_DEFAULT with I2S_MCLK_MULTIPLE_256

* Update i2s_audio_speaker.cpp

Replace I2S_MCLK_MULTIPLE_DEFAULT with I2S_MCLK_MULTIPLE_256

* Update voice_assistant.cpp

Fix  msg.event_type format

* check SOC_I2S_NUM for c3

* use I2S_NUM_AUTO

* Update i2s_audio.cpp

* Couple tweaks

* Why did they take away I2S_NUM_MAX

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

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-28 01:42:59 +00:00
Jesse Hills
d2b35adcc8 Merge branch 'release' into dev 2024-05-28 12:51:22 +12:00
Jesse Hills
3fe2fc9b56 Merge pull request #6820 from esphome/bump-2024.5.4
2024.5.4
2024-05-28 12:50:30 +12:00
Jesse Hills
4cd4b168b4 Bump version to 2024.5.4 2024-05-28 08:29:19 +12:00
Gábor Poczkodi
f07479419c [helpers] Move Base64 string to cpp (#6819) 2024-05-28 08:29:19 +12:00
Jesse Hills
54b51269ab [web_server_base] Bump ESPAsyncWebServer-esphome to 3.2.2 (#6797)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2024-05-28 08:29:18 +12:00
Gábor Poczkodi
6e4fd428e7 [helpers] Move Base64 string to cpp (#6819) 2024-05-28 08:19:22 +12:00
august huber
e285196709 fix libretiny regression from #6715 (#6806) 2024-05-27 07:41:29 +12:00
august huber
17c6bf57cd [tuya] add support for extended services (#6808) 2024-05-27 07:40:38 +12:00
Sašo Domadenik
4125b48b86 Fix incorrect naming of the AdaFruit MagTag display. (#6810) 2024-05-27 07:23:00 +12:00
Jesse Hills
6d341ce4e7 [web_server_base] Bump ESPAsyncWebServer-esphome to 3.2.2 (#6797)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2024-05-27 07:15:05 +12:00
Jesse Hills
964410bd64 Merge branch 'release' into dev 2024-05-25 08:25:31 +12:00
Jesse Hills
d72ab25d46 Merge pull request #6804 from esphome/bump-2024.5.3
2024.5.3
2024-05-25 08:24:38 +12:00
Jesse Hills
af755380b7 Bump version to 2024.5.3 2024-05-25 08:14:39 +12:00
Jesse Hills
04db724295 [voice_assistant] Don't allocate buffers until starting the microphone for the first time (#6800) 2024-05-25 08:14:39 +12:00
Jesse Hills
863bee28d9 [voice_assistant] Don't allocate buffers until starting the microphone for the first time (#6800) 2024-05-25 07:42:24 +12:00
Edward Firmo
9d03f47233 [nextion] Add basic functions to Intelligent series (#6791) 2024-05-24 09:11:34 +12:00
polyfloyd
c2d67659f3 mpr121: Add GPIO support (#6776)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-24 09:08:28 +12:00
Pavlo Dudnytskyi
aed0593793 [haier] `text_sensor and button` platforms (#6780) 2024-05-24 09:07:39 +12:00
Jesse Hills
4ab7a5d964 [ledc] Change some logging lines from debug to verbose (#6796) 2024-05-23 00:04:33 -05:00
Penny Wood
7f9383c83b [sx1509] Output open drain pin mode (#6788) 2024-05-23 09:31:56 +12:00
Keith Burzinski
9a6fde21ee Add on_safe_mode trigger (#6790) 2024-05-23 07:43:13 +12:00
Jeroen van Oort
1ca7c2d7dd Add support for acting as Modbus server (#4874)
Co-authored-by: Jeroen van Oort <jeroen.vanoort@webparking.nl>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-22 16:17:32 +12:00
Keith Burzinski
76abf2200c Uncouple safe_mode from OTA (#6759) 2024-05-22 13:08:53 +12:00
Jesse Hills
83d3584173 Merge branch 'release' into dev 2024-05-21 12:30:00 +12:00
Jesse Hills
0ee4348777 Merge pull request #6786 from esphome/bump-2024.5.2
2024.5.2
2024-05-21 12:29:09 +12:00
Jesse Hills
fcdf36e991 Bump version to 2024.5.2 2024-05-21 11:07:20 +12:00
esphomebot
5eb8efd8b3 Update webserver local assets to 20240519-215627 (#6779) 2024-05-21 11:07:20 +12:00
Jesse Hills
cd0f557940 [remote_receiver] Add better error message for tolerance breaking change (#6784) 2024-05-21 11:07:20 +12:00
J. Nick Koston
efde677ca9 Fix DashboardEntries.all() call (#6783) 2024-05-21 11:07:20 +12:00
J. Nick Koston
2eebee1de7 Revert "Fix MQTT dashboard discovery (Exception in MqttStatusThread)." (#6782) 2024-05-21 11:07:20 +12:00
esphomebot
525c4891d5 Update webserver local assets to 20240519-215627 (#6779) 2024-05-21 10:55:56 +12:00
Anton Viktorov
ce6dc040da Tiny fix in automation.h - unused return value removed (#6760) 2024-05-21 10:54:38 +12:00
Jesse Hills
9de67feccd [remote_receiver] Add better error message for tolerance breaking change (#6784) 2024-05-21 10:53:16 +12:00
Clyde Stubbs
bad400e1cd [ili9xxx] Add 18bit mode selection and custom init sequence (#6745) 2024-05-21 09:18:13 +12:00
J. Nick Koston
59b1e9c1b0 Fix DashboardEntries.all() call (#6783) 2024-05-20 11:52:24 +00:00
J. Nick Koston
25ee24299a Revert "Fix MQTT dashboard discovery (Exception in MqttStatusThread)." (#6782) 2024-05-20 11:49:00 +00:00
Jesse Hills
81ef67cfbb Merge branch 'release' into dev 2024-05-20 19:50:39 +12:00
Jesse Hills
f235dcc096 Merge pull request #6781 from esphome/bump-2024.5.1
2024.5.1
2024-05-20 19:48:55 +12:00
Jesse Hills
d2d3db4b8c Bump version to 2024.5.1 2024-05-20 17:14:17 +12:00
Markus
ec6d86c8f5 Fix MQTT dashboard discovery (Exception in MqttStatusThread). (#6775) 2024-05-20 17:14:17 +12:00
Markus
7452879fb1 Fix Upload from Dashboard with MQTT discovery. (#6774)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-20 17:14:17 +12:00
esphomebot
4fc2f2284a Synchronise Device Classes from Home Assistant (#6768) 2024-05-20 17:14:17 +12:00
acshef
840f69ffe6 Add device_class to valve core config (#6765) 2024-05-20 17:14:17 +12:00
fodfodfod
b9bb3cd4be add rp2040 support to the wizard (#6239) 2024-05-20 12:42:30 +12:00
Markus
91e7a44c31 Fix MQTT dashboard discovery (Exception in MqttStatusThread). (#6775) 2024-05-20 11:52:14 +12:00
Markus
080f8bc86e Fix Upload from Dashboard with MQTT discovery. (#6774)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-19 20:33:20 +00:00
dependabot[bot]
a85d37a1cf Bump actions/checkout from 4.1.5 to 4.1.6 (#6764)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 08:12:32 +12:00
tomaszduda23
ba73187c1b separate deep_sleep component for each platform in different file (#6762)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-20 08:11:27 +12:00
tomaszduda23
4469ba4024 [tests] make test_build_components work with venv without installing esphome (#6761) 2024-05-19 11:47:23 +12:00
Sebastian Muszynski
70e0925f9a Fix pip3 install (#6771) 2024-05-19 11:31:36 +12:00
esphomebot
1164cb8610 Synchronise Device Classes from Home Assistant (#6768) 2024-05-18 07:15:52 +00:00
acshef
94b63d7bc2 Add device_class to valve core config (#6765) 2024-05-18 16:17:09 +12:00
Jesse Hills
df838b5788 [core] Remove references to deleted setup.py (#6757) 2024-05-16 22:33:33 +12:00
Edward Firmo
d410cc4f7b [nextion] Fix type on sprintf for IDF v5 (#6758) 2024-05-16 22:22:18 +12:00
Anton Viktorov
b06e0746f5 INA228/INA229, INA238/INA239, INA237 power/energy/charge monitor (I2C, SPI) (#6138)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 16:50:28 +12:00
Jesse Hills
034c196ad8 [core] Update some coroutine priorities (#6755) 2024-05-16 16:46:16 +12:00
Keith Burzinski
996f71c03c Fix wifi compile error on IDF 5.1+ (#6756) 2024-05-16 04:40:21 +00:00
Anton Viktorov
98cb6555df SPI and I2C for ENS160 (#6369) 2024-05-16 15:22:40 +12:00
Faidon Liambotis
0bb2773c64 Port wifi_component_esp32_arduino from tcpip_adapter to esp_netif (#6476)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 14:49:40 +12:00
Jesse Hills
7c243dafb3 [core] Fix some extends cases (#6748) 2024-05-16 14:11:54 +12:00
Mat931
247b2eee30 Add ADC multisampling (#6330) 2024-05-16 14:11:21 +12:00
Keith Burzinski
f46c499c4e Separate OTABackend from OTA component (#6459)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 14:01:09 +12:00
Jesse Hills
f91c31f093 [core] Fix running pylint via pre-commit from GUI apps (#6754) 2024-05-16 13:47:56 +12:00
Jesse Hills
a27c05483c [core] Move pylint config into pyproject.toml (#6739) 2024-05-16 13:47:36 +12:00
Jesse Hills
bf48ccaf22 [core] Move pytest config into pyproject.toml (#6740) 2024-05-16 13:20:12 +12:00
Jesse Hills
f2ef06d8b5 [core] Migrate to pyproject.toml (#6737) 2024-05-16 13:19:37 +12:00
Andrew McFague
f0ec900e48 Skip gpio validation (#5615) 2024-05-16 11:49:04 +12:00
Shawn Wilsher
7d804bf90f Fix Prometheus Output to Match Spec (#6032) 2024-05-16 11:39:57 +12:00
shxshxshxshx
2921831b55 WPA2 Enterprise - Explicitly set TTLS Phase 2 (#6436)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:37:53 +12:00
heggi
08509f7755 Mirage remote receiver & transmitter (#6479)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:35:17 +12:00
Daniel Mahaney
ebfccc64c7 fix rp2040_pio_led flicker and proper multi-strip support (#6194)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:33:52 +12:00
lbilger
8952719045 Allow one timing to cancel others (#6744)
Co-authored-by: Lars Bilger <lars.bilger@lht.dlh.de>
2024-05-16 11:33:27 +12:00
ius
073fb4c124 i2c: fix format string specifiers (#6746) 2024-05-16 11:33:15 +12:00
Mat931
46eee4a4f0 Add beken_spi_led_strip component (#6515)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2024-05-16 11:32:48 +12:00
Alex Boyd
773951d85e BedJet: expose the outlet temperature on the climate and as a sensor (#6633) 2024-05-16 11:31:08 +12:00
Jesse Hills
1f29023c92 Merge branch 'release' into dev 2024-05-15 18:29:15 +12:00
Jesse Hills
caa8c820de Merge pull request #6753 from esphome/bump-2024.5.0
2024.5.0
2024-05-15 18:27:28 +12:00
dependabot[bot]
9f1ba00b7c Bump esphome-dashboard from 20240412.0 to 20240429.1 (#6743)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 17:16:04 +12:00
Keith Burzinski
891f56b421 [tests] `test2.yaml` has become too large (#6750) 2024-05-15 17:14:19 +12:00
Jesse Hills
0d3adc8f0c Bump version to 2024.5.0 2024-05-15 17:08:43 +12:00
Jesse Hills
d7cb953994 Merge branch 'beta' into dev 2024-05-15 16:33:46 +12:00
Jesse Hills
ad0a1c5c35 Merge pull request #6751 from esphome/bump-2024.5.0b6
2024.5.0b6
2024-05-15 16:24:15 +12:00
Jesse Hills
5d2e3a7d8d Bump version to 2024.5.0b6 2024-05-15 13:14:15 +12:00
Jesse Hills
ebc3f0fe17 [adc] Fix 11db deprecation warning (#6749) 2024-05-15 13:14:15 +12:00
Jesse Hills
9a6e90af54 [adc] Fix 11db deprecation warning (#6749) 2024-05-15 12:51:01 +12:00
Jesse Hills
55e4532a88 Merge branch 'beta' into dev 2024-05-15 10:03:05 +12:00
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 649b923804 (r1278620976), 649b923804 (r1278621039), 649b923804 (r1278620904), and 649b923804 (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
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
3433 changed files with 94226 additions and 12393 deletions

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": [

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

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.4.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.4.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

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

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
.github/workflows/ci-api-proto.yml vendored Normal file
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.'
});
}
}

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

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 libsdl2-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

View File

@@ -1,7 +1,6 @@
---
name: Lock
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "30 0 * * *"

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.2.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.2.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.2.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.2.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
}
})

View File

@@ -1,7 +1,6 @@
---
name: Stale
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "30 0 * * *"

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.5
with:
commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@nabucasa.com>

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

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.4.2
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]

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

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,17 @@ 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/dallas_temp/* @ssieb
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 +111,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,23 +124,28 @@ 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
esphome/components/gpio/one_wire/* @ssieb
esphome/components/gps/* @coogle
esphome/components/graph/* @synco
esphome/components/graphical_display_menu/* @MrMDavidson
@@ -130,6 +154,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
@@ -141,9 +169,13 @@ esphome/components/homeassistant/* @OttoWinter
esphome/components/honeywell_hih_i2c/* @Benichou34
esphome/components/honeywellabp/* @RubyBailey
esphome/components/honeywellabp2_i2c/* @jpfaff
esphome/components/host/* @esphome/core
esphome/components/host/* @clydebarrow @esphome/core
esphome/components/host/time/* @clydebarrow
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/hte501/* @Stock-M
esphome/components/http_request/ota/* @oarcher
esphome/components/http_request/update/* @jesserockz
esphome/components/htu31d/* @betterengineering
esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/hyt271/* @Philippe12
esphome/components/i2c/* @esphome/core
@@ -155,13 +187,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
@@ -177,6 +215,7 @@ esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core
esphome/components/ltr390/* @sjtrny
esphome/components/ltr_als_ps/* @latonita
esphome/components/matrix_keypad/* @ssieb
esphome/components/max31865/* @DAVe3283
esphome/components/max44009/* @berfenger
@@ -223,8 +262,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
@@ -232,6 +272,7 @@ esphome/components/nextion/text_sensor/* @senexcrenshaw
esphome/components/nfc/* @jesserockz @kbx81
esphome/components/noblex/* @AGalfra
esphome/components/number/* @esphome/core
esphome/components/one_wire/* @ssieb
esphome/components/ota/* @esphome/core
esphome/components/output/* @esphome/core
esphome/components/pca6416a/* @Mat931
@@ -259,6 +300,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 +314,16 @@ 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/sdl/* @clydebarrow
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 +335,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 +369,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 +383,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 +415,37 @@ esphome/components/uart/button/* @ssieb
esphome/components/ufire_ec/* @pvizeli
esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter
esphome/components/update/* @jesserockz
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/wake_on_lan/* @clydebarrow @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

View File

@@ -81,7 +81,8 @@ RUN \
fi; \
pip3 install \
--break-system-packages --no-cache-dir \
platformio==6.1.13 \
# Keep platformio version in sync with requirements.txt
platformio==6.1.15 \
# Change some platformio settings
&& platformio settings set enable_telemetry No \
&& platformio settings set check_platformio_interval 1000000 \
@@ -100,6 +101,9 @@ RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "a
--break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
&& /platformio_install_deps.py /platformio.ini --libraries
# Avoid unsafe git error when container user and file config volume permissions don't match
RUN git config --system --add safe.directory '*'
# ======================= docker-type image =======================
FROM base AS docker
@@ -110,7 +114,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 +164,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 \

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 "$@"

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

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(

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")

View File

@@ -58,6 +58,7 @@ from esphome.cpp_types import ( # noqa
bool_,
int_,
std_ns,
std_shared_ptr,
std_string,
std_vector,
uint8,
@@ -87,4 +88,5 @@ from esphome.cpp_types import ( # noqa
gpio_Flags,
EntityCategory,
Parented,
ESPTime,
)

View File

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

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",
}

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

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};

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":

View File

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

View File

@@ -0,0 +1,304 @@
// 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"
#include <cinttypes>
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 %" PRIu32 " 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: %" PRId32, this->channel_a_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_a_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_a_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_a_->phase_angle_calibration);
}
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: %" PRId32, this->channel_b_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_b_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_b_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_b_->phase_angle_calibration);
}
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: %" PRId32, this->channel_c_->current_gain_calibration);
ESP_LOGCONFIG(TAG, " Voltage: %" PRId32, this->channel_c_->voltage_gain_calibration);
ESP_LOGCONFIG(TAG, " Power: %" PRId32, this->channel_c_->power_gain_calibration);
ESP_LOGCONFIG(TAG, " Phase Angle: %u", this->channel_c_->phase_angle_calibration);
}
if (this->channel_n_ != nullptr) {
ESP_LOGCONFIG(TAG, " Neutral:");
LOG_SENSOR(" ", "Current", this->channel_n_->current);
ESP_LOGCONFIG(TAG, " Calibration:");
ESP_LOGCONFIG(TAG, " Current: %" PRId32, 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

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

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

View File

@@ -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

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))

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,

View File

@@ -1,11 +1,16 @@
#include "ade7953_base.h"
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome {
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 +39,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 +58,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 +92,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 +100,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=%" PRIu32 " 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);

View File

@@ -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;

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];

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(
{

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

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

View File

@@ -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))

View File

@@ -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

View File

@@ -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

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)

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

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

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
CODEOWNERS = ["@mak-42"]

View File

@@ -0,0 +1,214 @@
#include "ags10.h"
#include <cinttypes>
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%08" PRIX32, *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

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

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

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; }

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

View File

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

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: {

View File

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

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

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

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))

View File

@@ -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: {

View File

@@ -3,7 +3,13 @@ import logging
from esphome import automation, core
from esphome.components import font
import esphome.components.image as espImage
from esphome.components.image import CONF_USE_TRANSPARENCY
from esphome.components.image import (
CONF_USE_TRANSPARENCY,
LOCAL_SCHEMA,
WEB_SCHEMA,
SOURCE_WEB,
SOURCE_LOCAL,
)
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import (
@@ -13,6 +19,9 @@ from esphome.const import (
CONF_REPEAT,
CONF_RESIZE,
CONF_TYPE,
CONF_SOURCE,
CONF_PATH,
CONF_URL,
)
from esphome.core import CORE, HexInt
@@ -43,6 +52,40 @@ SetFrameAction = animation_ns.class_(
"AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_)
)
TYPED_FILE_SCHEMA = cv.typed_schema(
{
SOURCE_LOCAL: LOCAL_SCHEMA,
SOURCE_WEB: WEB_SCHEMA,
},
key=CONF_SOURCE,
)
def _file_schema(value):
if isinstance(value, str):
return validate_file_shorthand(value)
return TYPED_FILE_SCHEMA(value)
FILE_SCHEMA = cv.Schema(_file_schema)
def validate_file_shorthand(value):
value = cv.string_strict(value)
if value.startswith("http://") or value.startswith("https://"):
return FILE_SCHEMA(
{
CONF_SOURCE: SOURCE_WEB,
CONF_URL: value,
}
)
return FILE_SCHEMA(
{
CONF_SOURCE: SOURCE_LOCAL,
CONF_PATH: value,
}
)
def validate_cross_dependencies(config):
"""
@@ -67,7 +110,7 @@ ANIMATION_SCHEMA = cv.Schema(
cv.All(
{
cv.Required(CONF_ID): cv.declare_id(Animation_),
cv.Required(CONF_FILE): cv.file_,
cv.Required(CONF_FILE): FILE_SCHEMA,
cv.Optional(CONF_RESIZE): cv.dimensions,
cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(
espImage.IMAGE_TYPE, upper=True
@@ -124,7 +167,11 @@ async def animation_action_to_code(config, action_id, template_arg, args):
async def to_code(config):
from PIL import Image
path = CORE.relative_config_path(config[CONF_FILE])
conf_file = config[CONF_FILE]
if conf_file[CONF_SOURCE] == SOURCE_LOCAL:
path = CORE.relative_config_path(conf_file[CONF_PATH])
elif conf_file[CONF_SOURCE] == SOURCE_WEB:
path = espImage.compute_local_image_path(conf_file).as_posix()
try:
image = Image.open(path)
except Exception as e:
@@ -157,7 +204,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 +227,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 +250,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 +279,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

View File

@@ -43,7 +43,12 @@ 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 update_command (UpdateCommandRequest) returns (void) {}
rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {}
@@ -216,7 +221,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 +606,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 +1148,9 @@ message MediaPlayerCommandRequest {
bool has_media_url = 6;
string media_url = 7;
bool has_announcement = 8;
bool announcement = 9;
}
// ==================== BLUETOOTH ====================
@@ -1420,12 +1430,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 +1465,7 @@ message VoiceAssistantRequest {
string conversation_id = 2;
uint32 flags = 3;
VoiceAssistantAudioSettings audio_settings = 4;
string wake_word_phrase = 5;
}
message VoiceAssistantResponse {
@@ -1492,6 +1509,35 @@ 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;
}
enum VoiceAssistantTimerEvent {
VOICE_ASSISTANT_TIMER_STARTED = 0;
VOICE_ASSISTANT_TIMER_UPDATED = 1;
VOICE_ASSISTANT_TIMER_CANCELLED = 2;
VOICE_ASSISTANT_TIMER_FINISHED = 3;
}
message VoiceAssistantTimerEventResponse {
option (id) = 115;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
VoiceAssistantTimerEvent event_type = 1;
string timer_id = 2;
string name = 3;
uint32 total_seconds = 4;
uint32 seconds_left = 5;
bool is_active = 6;
}
// ==================== ALARM CONTROL PANEL ====================
enum AlarmControlPanelState {
ALARM_STATE_DISARMED = 0;
@@ -1596,3 +1642,242 @@ 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;
}
// ==================== UPDATE ====================
message ListEntitiesUpdateResponse {
option (id) = 116;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_UPDATE";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
bool disabled_by_default = 6;
EntityCategory entity_category = 7;
string device_class = 8;
}
message UpdateStateResponse {
option (id) = 117;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_UPDATE";
option (no_delay) = true;
fixed32 key = 1;
bool missing_state = 2;
bool in_progress = 3;
bool has_progress = 4;
float progress = 5;
string current_version = 6;
string latest_version = 7;
string title = 8;
string release_summary = 9;
string release_url = 10;
}
message UpdateCommandRequest {
option (id) = 118;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_UPDATE";
option (no_delay) = true;
fixed32 key = 1;
bool install = 2;
}

View File

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

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,8 @@ 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;
void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
@@ -137,6 +159,17 @@ 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
#ifdef USE_UPDATE
bool send_update_state(update::UpdateEntity *update);
bool send_update_info(update::UpdateEntity *update);
void update_command(const UpdateCommandRequest &msg) override;
#endif
void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override {
// we initiated ping

File diff suppressed because it is too large Load Diff

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

View File

@@ -476,6 +476,16 @@ 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_VOICE_ASSISTANT
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response(
const ListEntitiesAlarmControlPanelResponse &msg) {
@@ -513,6 +523,112 @@ 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
#ifdef USE_UPDATE
bool APIServerConnectionBase::send_list_entities_update_response(const ListEntitiesUpdateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_update_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesUpdateResponse>(msg, 116);
}
#endif
#ifdef USE_UPDATE
bool APIServerConnectionBase::send_update_state_response(const UpdateStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_update_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<UpdateStateResponse>(msg, 117);
}
#endif
#ifdef USE_UPDATE
#endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) {
case 1: {
@@ -942,6 +1058,83 @@ 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;
}
case 115: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantTimerEventResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_timer_event_response(msg);
#endif
break;
}
case 118: {
#ifdef USE_UPDATE
UpdateCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
#endif
this->on_update_command_request(msg);
#endif
break;
}
@@ -1205,6 +1398,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 +1424,58 @@ 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_UPDATE
void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->update_command(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {

View File

@@ -240,6 +240,13 @@ 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_VOICE_ASSISTANT
virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){};
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg);
#endif
@@ -257,6 +264,57 @@ 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
#ifdef USE_UPDATE
bool send_list_entities_update_response(const ListEntitiesUpdateResponse &msg);
#endif
#ifdef USE_UPDATE
bool send_update_state_response(const UpdateStateResponse &msg);
#endif
#ifdef USE_UPDATE
virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif
protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
@@ -309,9 +367,24 @@ 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_UPDATE
virtual void update_command(const UpdateCommandRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif
@@ -395,9 +468,24 @@ 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_UPDATE
void on_update_command_request(const UpdateCommandRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif

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,20 @@ 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
#ifdef USE_UPDATE
void APIServer::on_update(update::UpdateEntity *obj) {
for (auto &c : this->clients_)
c->send_update_state(obj);
}
#endif
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void APIServer::set_port(uint16_t port) { this->port_ = port; }
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

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,12 @@ 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
#ifdef USE_UPDATE
void on_update(update::UpdateEntity *obj) override;
#endif
bool is_connected() const;

View File

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

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,12 @@ 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
#ifdef USE_UPDATE
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_info(update); }
#endif
} // namespace api
} // namespace esphome

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,20 @@ 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
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
#endif
bool on_end() override;

View File

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

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,20 @@ 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
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
#endif
protected:
APIConnection *client_;

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"

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"

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")

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

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

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

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

View File

@@ -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))

View File

@@ -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

View File

@@ -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

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;
}

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

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

View File

@@ -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

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]))

View File

@@ -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;

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),
}
)

View File

@@ -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

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

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,

View File

@@ -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]))

View File

@@ -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) {

View File

@@ -28,6 +28,8 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
/** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */
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_();

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