Compare commits

..

380 Commits

Author SHA1 Message Date
Jesse Hills
70aa5d0f6c Merge pull request #4870 from esphome/bump-2023.5.2
2023.5.2
2023-05-22 12:15:07 +12:00
Jesse Hills
8fcec8e2cb Bump version to 2023.5.2 2023-05-22 11:31:30 +12:00
Stefan Rado
2d3b48f86f Fix i2s_audio media_player mutex acquisition (#4867)
Co-authored-by: Rajan Patel <rpatel3001@gmail.com>
2023-05-22 11:31:30 +12:00
Jesse Hills
99c10bc6de Merge pull request #4852 from esphome/bump-2023.5.1
2023.5.1
2023-05-18 14:27:55 +12:00
Jesse Hills
f30f20db86 Bump version to 2023.5.1 2023-05-18 13:00:37 +12:00
Keith Burzinski
9bf946e196 Sprinkler fixes (#4816) 2023-05-18 13:00:36 +12:00
Jesse Hills
bfaad1f28d Remove i2c dependency from ttp229_bsf (#4851) 2023-05-18 13:00:36 +12:00
Jesse Hills
f90e9ba871 Merge pull request #4846 from esphome/bump-2023.5.0
2023.5.0
2023-05-17 13:17:10 +12:00
Jesse Hills
726bdd7be2 Bump version to 2023.5.0 2023-05-17 12:45:42 +12:00
Jesse Hills
52db40eb41 Merge pull request #4845 from esphome/bump-2023.5.0b5
2023.5.0b5
2023-05-17 12:04:22 +12:00
Jesse Hills
3c371a0c59 Bump version to 2023.5.0b5 2023-05-17 09:57:36 +12:00
Samuel Sieb
c941bc4109 handle Wiegand 8-bit keys (#4837)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-05-17 09:57:35 +12:00
Samuel Sieb
cc76e5353c support sending keys to the collector (#4838)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-05-17 09:57:35 +12:00
Jesse Hills
11bb46e393 Merge pull request #4835 from esphome/bump-2023.5.0b4
2023.5.0b4
2023-05-16 12:00:39 +12:00
Jesse Hills
71c4714a6e Bump version to 2023.5.0b4 2023-05-16 11:16:14 +12:00
github-actions[bot]
a4e63c5f86 Synchronise Device Classes from Home Assistant (#4825)
Co-authored-by: esphomebot <esphome@nabucasa.com>
2023-05-16 11:16:14 +12:00
Justin Gerace
c71e7d0132 Start UART assignment at UART0 if the logger is not enabled or is not configured for hardware logging on ESP32 (#4762) 2023-05-16 11:16:13 +12:00
dependabot[bot]
daa966975e Bump tzlocal from 4.2 to 5.0.1 (#4829)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 11:16:13 +12:00
Federico G. Schwindt
2e5757a3f0 Fix time period validation for the auto cleaning interval (#4811) 2023-05-16 11:16:13 +12:00
Jesse Hills
f66024b37c Bump esphome-dashboard to 20230516.0 (#4831) 2023-05-16 11:16:13 +12:00
Christian
c16ca7be13 Update PulseLightEffect with range brightness (#4820)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-05-16 11:16:13 +12:00
dependabot[bot]
e13e754bc4 Bump aioesphomeapi from 13.7.2 to 13.7.5 (#4830)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 11:16:13 +12:00
RoboMagus
6ccea59f71 Fix missing stop trait in send_cover_info (#4826) 2023-05-16 11:16:13 +12:00
Jesse Hills
71b28be3c8 Merge pull request #4822 from esphome/bump-2023.5.0b3
2023.5.0b3
2023-05-15 13:06:10 +12:00
Jesse Hills
e25d92e1f5 Bump version to 2023.5.0b3 2023-05-15 11:37:55 +12:00
Jesse Hills
65cda10884 Dontr try stop if not actually started (#4814) 2023-05-15 11:37:55 +12:00
Jesse Hills
625126df68 Fix i2s media player volume control (#4813) 2023-05-15 11:37:55 +12:00
richardhopton
e0ee8ca17c Tuya: Prevent loop when setting colors on case-sensitive dps (#4809)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2023-05-15 11:37:54 +12:00
Federico G. Schwindt
af95e781f5 Wording (#4805) 2023-05-15 11:37:54 +12:00
Jesse Hills
9b230a7d93 Merge pull request #4808 from esphome/bump-2023.5.0b2
2023.5.0b2
2023-05-12 11:02:45 +12:00
Jesse Hills
e2f3e7c3a6 Bump version to 2023.5.0b2 2023-05-12 10:32:59 +12:00
Alex Dekker
2fd2e5ceb2 Supposed to fix #4069, by changing the default value to 0s (timeunit instead of int) to pass validation (#4806)
Co-authored-by: Alex1602 <alex1602@gmail.com>
2023-05-12 10:32:59 +12:00
Jesse Hills
d88358be8e Remove AUTO_LOAD from apds9960 (#4746) 2023-05-12 10:32:59 +12:00
Jimmy Hedman
d80885c7a8 Fixed access point for ESP32 IDF platform (#4784) 2023-05-12 10:32:59 +12:00
Jesse Hills
c7c9c49f4e Merge pull request #4803 from esphome/bump-2023.5.0b1
2023.5.0b1
2023-05-11 10:54:30 +12:00
Jesse Hills
2c160a8a25 Bump version to 2023.5.0b1 2023-05-11 09:38:21 +12:00
Jesse Hills
cc576cf1a9 Merge branch 'dev' into bump-2023.5.0b1 2023-05-11 09:38:20 +12:00
Jesse Hills
97a71482a9 Validate project details are set for dashboard_import (#4802) 2023-05-11 08:55:05 +12:00
Jesse Hills
8822b6c808 Make i2s_audio bclk_pin optional (#4801) 2023-05-11 07:17:59 +12:00
Jesse Hills
5099595aee Wrap VA code (#4800) 2023-05-10 16:46:32 +12:00
Jesse Hills
39a650ee54 Add more configuration for microphones - i2s/pdm/adc (#4775) 2023-05-10 16:37:21 +12:00
Jimmy Hedman
b19c7d462b Fixed calculation of start and end dhcp range (#4785) 2023-05-10 13:03:43 +12:00
Fabian
a8b821c213 [display] Small display print performance improvement (#4788) 2023-05-10 12:47:24 +12:00
Fabian
535003014b Keep Unit of Measurement in Flash. (#4719)
Co-authored-by: Your Name <you@example.com>
2023-05-10 11:42:55 +12:00
Jesse Hills
3c05ae4e1a Add more envs to root platformio (#4799) 2023-05-10 11:38:51 +12:00
Jesse Hills
c835b67bac Add host target platform (#4783)
Co-authored-by: Otto winter <otto@otto-winter.com>
2023-05-10 11:38:18 +12:00
Fabian
8c32941428 [ili9xxx] Improve fill operation performance (#4702)
Co-authored-by: Your Name <you@example.com>
2023-05-10 11:19:28 +12:00
Alfredo
b5dac00dcb Fix ezo parsing (#4792) 2023-05-10 11:16:14 +12:00
bouhaa
ffdc721c79 SM2135 Add optional current configuration, avoid communication failures. (#3850)
Co-authored-by: matika77 <xmaximx@gmx.net>
Co-authored-by: Dion <contact@dd32.id.au>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-05-10 11:06:26 +12:00
Jesse Hills
0828a9fc11 Bump ESP32-audioI2s to 2.0.7 (#4796) 2023-05-10 09:13:01 +12:00
Jesse Hills
4b664b6f09 Create esp32 rmt addressable light driver (#4708) 2023-05-09 09:33:43 +12:00
Jesse Hills
679633245d Add gp8403 output component (#4495)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2023-05-08 12:45:12 +12:00
Jesse Hills
ce8a77c765 Speaker support (#4743) 2023-05-08 10:36:17 +12:00
Jesse Hills
2f78c4acfa Merge pull request #4778 from esphome/bump-2023.4.4
2023.4.4
2023-05-04 11:31:40 +12:00
Jesse Hills
72f6841aac Bump version to 2023.4.4 2023-05-04 10:53:06 +12:00
Tim Niemueller
10bd9b14fc Fixes for Arduino 2.7.4 (for FastLED) (#4777) 2023-05-04 10:53:05 +12:00
Guillermo Ruffino
3498aade85 update schema gen to 2023.4.0 (#4772) 2023-05-04 10:18:45 +12:00
Chris Nussbaum
c4539e10fb Revert "Template sensors always publish on update interval (#2224)" (#4774) 2023-05-04 10:16:00 +12:00
Tim Niemueller
2b3052e9d7 Fixes for Arduino 2.7.4 (for FastLED) (#4777) 2023-05-04 10:13:30 +12:00
Jesse Hills
e725e15f7a Merge pull request #4769 from esphome/bump-2023.4.3
2023.4.3
2023-05-02 17:28:32 +12:00
Jesse Hills
4d1113e265 Bump version to 2023.4.3 2023-05-02 17:10:46 +12:00
Jesse Hills
52352ac27a Fix i2s media player on devices with no internal DAC (#4768) 2023-05-02 17:10:46 +12:00
Keith Burzinski
f60b2b754d Fix sprinkler switch restore_mode (#4756) 2023-05-02 17:10:46 +12:00
Jesse Hills
4a3f9712b2 Fix i2s media player on devices with no internal DAC (#4768) 2023-05-02 16:57:40 +12:00
dependabot[bot]
fb094fca0f Bump zeroconf from 0.56.0 to 0.60.0 (#4767)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-02 09:52:42 +12:00
looping40
de10b356cf Max6956 support added (#3764)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-05-02 09:51:48 +12:00
cooki35
bd6d6caa8a Add support for V2 of the waveshare 5.83in e-paper display. (#3660) 2023-05-02 09:36:20 +12:00
Mat931
1c4af08ed3 Add support for BLE passkey authentication (#4258)
Co-authored-by: Branden Cash <203336+ammmze@users.noreply.github.com>
2023-05-02 09:25:10 +12:00
Philippe FOUQUET
c97d361b6c Add support for hyt271 (#4282)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-05-01 16:18:31 +12:00
marshn
379b1d84dd RF Codec for Drayton Digistat heating controller (#4494) 2023-05-01 16:12:53 +12:00
Luis Andrade
c13e20643b play_folder bugfix and addition of play_mp3 (#4758) 2023-05-01 16:01:24 +12:00
Mat931
76b6fcf554 Add PCA6416A Support (#4681) 2023-05-01 16:00:21 +12:00
Jesse Hills
57e909e790 Only pre-install libraries in docker images (#4766) 2023-05-01 15:57:57 +12:00
dependabot[bot]
d6f7876e68 Bump pyupgrade from 3.3.1 to 3.3.2 (#4751)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-05-01 00:01:52 +00:00
Jesse Hills
56e0923c22 Switch ESPAsyncTCP-esphome to esphome fork (#4764) 2023-05-01 11:09:01 +12:00
tracestep
f4b98f5e32 Power down PN532 before deep sleep (#4707) 2023-05-01 09:24:15 +12:00
Jesse Hills
2d56b70a36 Bump git version in Dockerfile (#4763) 2023-05-01 08:51:46 +12:00
dependabot[bot]
980cfaf295 Bump aioesphomeapi from 13.7.1 to 13.7.2 (#4753)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-01 07:57:02 +12:00
Keith Burzinski
c2a43c733a Fix sprinkler switch restore_mode (#4756) 2023-05-01 07:52:05 +12:00
RoboMagus
568e65a6ab Fix assumed_state switch webserver (#4259) 2023-05-01 07:28:21 +12:00
Jesse Hills
59d6b3afa0 Merge branch 'release' into dev 2023-04-27 20:06:04 +12:00
Jesse Hills
b89c04b928 Merge pull request #4748 from esphome/bump-2023.4.2
2023.4.2
2023-04-27 20:02:15 +12:00
Jesse Hills
12090657bb Bump version to 2023.4.2 2023-04-27 19:36:21 +12:00
itpeters
4e21cf0bdd Don't allow fingerprint_grow enroll cancellation when no enrollment started (#4745) 2023-04-27 19:36:21 +12:00
Jesse Hills
ba4ef72d56 Only request VA port from first client that is subscribed (#4747) 2023-04-27 19:36:21 +12:00
Jimmy Hedman
f3e6a4314f Debug component doesn't work on RP2040 (#4728) 2023-04-27 19:36:21 +12:00
gcopeland
e14ce3d950 I2c scan recovery reset fix (#4724)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-27 19:36:21 +12:00
itpeters
70aa38f5bd Don't allow fingerprint_grow enroll cancellation when no enrollment started (#4745) 2023-04-27 16:34:20 +12:00
Jesse Hills
55ec082628 Only request VA port from first client that is subscribed (#4747) 2023-04-27 04:22:12 +00:00
Jesse Hills
6f27126c8d Move am43 sensor code and remove auto load on cover (#4631) 2023-04-27 13:24:42 +12:00
Jesse Hills
ee21a91313 Add mlx90614 sensors (#3749)
Co-authored-by: Greg Arnold <greg@arnoldassociates.com>
Co-authored-by: notsonominal <130870838+notsonominal@users.noreply.github.com>
2023-04-27 13:17:09 +12:00
Jesse Hills
c5efaa1c00 Remove climate legacy away flags (#4744) 2023-04-27 13:11:32 +12:00
Jesse Hills
6476357596 Expand the platformio dep installer to also install platforms and tools (#4716) 2023-04-27 12:26:06 +12:00
dependabot[bot]
77f71acbc8 Bump pytest from 7.3.0 to 7.3.1 (#4686)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-27 11:45:23 +12:00
dependabot[bot]
4a08a5413d Bump tornado from 6.2 to 6.3.1 (#4741) 2023-04-27 11:00:34 +12:00
dependabot[bot]
e3d89cc6b6 Bump pylint from 2.17.2 to 2.17.3 (#4740)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-27 10:49:40 +12:00
RoboMagus
64afb07e91 Fix 'blutooth' typo in esp32_ble component (#4738) 2023-04-27 10:48:53 +12:00
Keith Burzinski
f639f7c280 Add on_tag_removed trigger for RC522 (#4742) 2023-04-27 10:47:45 +12:00
Jimmy Hedman
986dd2ddd2 Debug component doesn't work on RP2040 (#4728) 2023-04-27 08:03:30 +12:00
gcopeland
7abdb5d046 I2c scan recovery reset fix (#4724)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-27 08:00:37 +12:00
Jesse Hills
0f1e186189 Merge pull request #4732 from esphome/bump-2023.4.1
2023.4.1
2023-04-24 09:47:08 +12:00
Jesse Hills
96d208e0d8 Bump version to 2023.4.1 2023-04-24 09:11:07 +12:00
Jesse Hills
38ed38864e Use proper schema for delta filter (#4723) 2023-04-24 09:11:07 +12:00
Samuel Sieb
a12ba7bd38 fix flip_x (#4727) 2023-04-24 09:11:06 +12:00
dependabot[bot]
4a177e3931 Bump aioesphomeapi from 13.7.0 to 13.7.1 (#4725)
Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.7.0 to 13.7.1.
- [Release notes](https://github.com/esphome/aioesphomeapi/releases)
- [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.7.0...v13.7.1)

---
updated-dependencies:
- dependency-name: aioesphomeapi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-23 20:53:50 +00:00
Alexander Momchilov
bef5b38d49 Add supports_stop trait to Cover (#3897)
* Add "stop" trait to Cover

* Add `supports_stop` to Cover protobuf msg

* Run `script/api_protobuf/api_protobuf.py`

... followed by `script/clang-format -i`

* Add `has_stop` field to template Cover

* Set `has_stop` during Cover codegen

* Set `supports_stop` trait on all other Cover types

* Bump APIVersion to 1.8

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-23 20:51:32 +00:00
Rebbe Pod
0a95f116fc Get Sunrise & Sunset for a Specific Date (#4712)
* Update real_time_clock.cpp

* Update real_time_clock.h

* Update sun.h

* Update sun.h

* Update sun.h

* Enable the sunAtLocation to be used externally

* Enable the sunAtLocation to be used externally

* Update sun.h

* Update sun.h

* update

* update

* update to only use one function

* Update sun.h

* Update sun.cpp
2023-04-23 20:44:35 +00:00
Jesse Hills
327cd662b4 Use proper schema for delta filter (#4723) 2023-04-23 20:42:46 +00:00
Samuel Sieb
bb05ba3d00 fix flip_x (#4727) 2023-04-22 07:41:12 +00:00
Keith Burzinski
c0ad5d1d16 Initial attempt at supporting ESP-IDF 5.0.0 (#4364)
* requirements: add pyparsing >= 3.0

ESP-IDF >= 5.0 requires pyparsing's rest_of_file, which was introduced
in version 3.0.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

* esp32: fix build with ESP-IDF >= 5

We need to include esp_timer.h to be able to use esp_timer_get_time().
This header existed in ESP-IDF < 5 so we don't need if guards.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

* ota: fix build with ESP-IDF >= 5

As of version 5, esp_task_wdt_init() takes a struct as argument. We also
need to include spi_flash_mmap.h.

[split unrelated change into separate commits, maintain ESP-IDF < 5
compat, use esp_task_wdt_reconfigure, add commit message]
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

* core: fix build with ESP-IDF >= 5

These header files already existed in ESP-IDF < 5 so skip if guards.

[add commit message]
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

* wifi: fix build with ESP-IDF >= 5

ESP-IDF 4.1 introduced the esp-netif API as successor to the tcp_adapter
API. The tcp_adapter API was removed in ESP-IDF 5.0.0. Part of the wifi
component was already migrated to the new API. Migrate the leftover uses
of the old API to the new API to fix build on ESP-IDF >= 5.

The version of ESP-IDF currently in use (4.4.4) supports the new API, so
we don't need any if guards to maintain backwards compatibility.

Also replace xQueueHandle, which is a pre FreeRTOS v8.0.0 data type,
with QueueHandle_t, so we don't need to enable backward compatibility
(CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY).

This reverts part of commit d42f35de5d to wifi_component_esp_idf.cpp,
as the esp-netif API handles that internally.

[replace pre FreeRTOS v8.0.0 data type, add commit message]
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

* mdns: fix build with ESP-IDF >= 5

In ESP-IDF 5.0.0, the mdns component was removed and moved to another
repository. Since the mdns component in esphome is always built, we
need to add the mdns component from the esp-protocols repository. This
component depends on ESP-IDF >= 5.0, so we need to add a version guard.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

* docker: install python3-venv

As of version 6.0.1, platform-espressif32 requires python3-venv.
Switching between esp-idf 4.4.4 and 5.0 causes problems with esp-idf
python dependencies installed by PlatformIO. They've solved this by
using venv. Install python3-venv so that platform-espressif32 6.0.1 and
later can be used, and we don't need to wipe the dependencies manually
when switching esp-idf versions.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>

---------

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Co-authored-by: Stijn Tintel <stijn@linux-ipv6.be>
2023-04-20 03:54:06 +00:00
Bella Coola
4c39631428 Add support for passive WiFi scanning (#4666)
* Add support for passive WiFi scanning.

* Apply suggestions from code review

Made changes suggested by @jesserockz

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

---------

Co-authored-by: BellaCoola <unknown>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-20 03:53:42 +00:00
Fabian
afc2b3b74f Keep Device Class in Flash. (#4639)
* Keep Device Class in Flash.

* Remove blank line

---------

Co-authored-by: Your Name <you@example.com>
2023-04-20 03:53:35 +00:00
Jesse Hills
19fc1417ae Merge pull request #4715 from esphome/bump-2023.4.0
2023.4.0
2023-04-20 15:18:09 +12:00
Jesse Hills
e2fefa51f5 Bump version to 2023.4.0 2023-04-20 14:06:53 +12:00
Jesse Hills
f668d5617f Merge branch 'beta' into bump-2023.4.0 2023-04-20 14:06:52 +12:00
Jesse Hills
47c4ff15d6 Merge pull request #4714 from esphome/bump-2023.4.0b4
2023.4.0b4
2023-04-20 14:00:12 +12:00
Jesse Hills
ccf1bdc0b4 Bump version to 2023.4.0b4 2023-04-20 13:10:26 +12:00
Jesse Hills
e993fcf80c Bump arduino platform version to 5.3.0 (#4713)
* Bump arduino platform version to 5.3.0

* Update root platformio.ini
2023-04-20 13:10:25 +12:00
tracestep
1bdc30a09e Add ethernet powerdown (fixes esphome/issues#4420) (#4706)
* Add ethernet powerdown

* Add on_shutdown (fixes esphome/issues#4420

* Sync dev and clang-tidy fix

* fix typo and trainling space

* Initialize phy_ member

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

* Use `this` pointer

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

* Member initialized at declaration

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

* Use `this` pointer

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

* Use `this` pointer

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-20 13:10:25 +12:00
Jesse Hills
0f7e34e7ec Bump arduino platform version to 5.3.0 (#4713)
* Bump arduino platform version to 5.3.0

* Update root platformio.ini
2023-04-20 00:44:49 +00:00
Jesse Hills
f56e89597f Merge pull request #4711 from esphome/bump-2023.4.0b3
2023.4.0b3
2023-04-20 11:14:00 +12:00
Jesse Hills
9460fb28c4 Bump version to 2023.4.0b3 2023-04-20 10:15:34 +12:00
Jesse Hills
7207b9734f Call on_error if no api client connected that handles voice (#4709) 2023-04-20 10:15:34 +12:00
tracestep
2be703b329 Add ethernet powerdown (fixes esphome/issues#4420) (#4706)
* Add ethernet powerdown

* Add on_shutdown (fixes esphome/issues#4420

* Sync dev and clang-tidy fix

* fix typo and trainling space

* Initialize phy_ member

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

* Use `this` pointer

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

* Member initialized at declaration

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

* Use `this` pointer

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

* Use `this` pointer

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-19 22:10:01 +00:00
Jesse Hills
4cea74ef3b Call on_error if no api client connected that handles voice (#4709) 2023-04-19 20:56:37 +00:00
Jesse Hills
3be3267d06 Merge pull request #4700 from esphome/bump-2023.4.0b2
2023.4.0b2
2023-04-17 17:16:16 +12:00
Jesse Hills
98db604dba Bump version to 2023.4.0b2 2023-04-17 15:45:35 +12:00
Jesse Hills
ebf6f8c6de Add event triggers to voice_assistant (#4699)
* Add event triggers to voice_assistant

* Add triggers to test
2023-04-17 15:45:34 +12:00
Szewcson
2ebacad398 Add timeout to i2c write error logs (#4697) 2023-04-17 15:45:34 +12:00
Jimmy Hedman
53c59cf675 Fixed dns2 for ethernet (#4698) 2023-04-17 15:45:34 +12:00
Jesse Hills
9da261cb39 debug component, allow without debug logging (#4685) 2023-04-17 15:45:34 +12:00
Jesse Hills
3a587ea0d4 Add event triggers to voice_assistant (#4699)
* Add event triggers to voice_assistant

* Add triggers to test
2023-04-17 02:57:28 +00:00
Szewcson
8a60919e1f Add timeout to i2c write error logs (#4697) 2023-04-16 20:12:13 +00:00
Jimmy Hedman
382dcddf12 Fixed dns2 for ethernet (#4698) 2023-04-16 20:10:07 +00:00
Jesse Hills
6b67acbeb5 debug component, allow without debug logging (#4685) 2023-04-14 02:29:28 +00:00
dependabot[bot]
7b0fca6824 Bump docker/build-push-action from 3 to 4 (#4367)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-13 08:13:13 +00:00
dependabot[bot]
47555d314a Bump peter-evans/create-pull-request from 4 to 5 (#4661)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4 to 5.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v4...v5)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-13 08:12:24 +00:00
dependabot[bot]
0643b71908 Bump aioesphomeapi from 13.5.1 to 13.7.0 (#4676)
Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.5.1 to 13.7.0.
- [Release notes](https://github.com/esphome/aioesphomeapi/releases)
- [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.5.1...v13.7.0)

---
updated-dependencies:
- dependency-name: aioesphomeapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-13 05:31:47 +00:00
kahrendt
afc848bf22 Add Bayesian type for binary_sensor_map component (#4640)
* initial support for Bayesian type

* Cast bool state of binary_sensor to uint64_t

* Rename channels to observations with Bayesian

* Improve/standardize comments for all types

* Use black to correct sensor.py formatting

* Add SUM and BAYESIAN binary sensor map tests

* Remove unused variable

* Update esphome/components/binary_sensor_map/binary_sensor_map.cpp

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

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-13 01:48:29 +00:00
Jesse Hills
9fbbcd6d8a Merge pull request #4683 from esphome/bump-2023.4.0b1
2023.4.0b1
2023-04-13 11:06:53 +12:00
Jesse Hills
cc1eb648f9 Only allow 5 jobs from each CI run to be in parallel (#4682) 2023-04-12 22:46:19 +00:00
Jesse Hills
04a139fe3d Bump version to 2023.5.0-dev 2023-04-13 10:13:53 +12:00
Jesse Hills
1a86167a47 Bump version to 2023.4.0b1 2023-04-13 10:13:52 +12:00
Jesse Hills
614ed7fd0c Merge branch 'dev' into bump-2023.4.0b1 2023-04-13 10:13:52 +12:00
spacemanspiff2007
4eb69d6af5 Fix restore (#4655)
* ALWAYS_OFF for fan

* ALWAYS_OFF for light

* ALWAYS_OFF for switch
2023-04-12 21:28:02 +00:00
Fabian
0547f2a931 Add KSZ8081 support. (#4668)
Co-authored-by: Your Name <you@example.com>
2023-04-12 21:22:08 +00:00
unhold
b5fbe0b145 Fix cut-off on 2.13" waveshare/ttgo epaper displays (#4255)
The controller of the 2.13" waveshare/ttgo epaper displays operates with a 128x250 buffer,
while only 122x250 pixels are shown. While this can be ignored for rotations 0/270°,
with roations 90/180°, 6 pixels are cut-off from the top or left edge.
This change introduces a distinction between object width and controller width,
resulting in pixel-perfect rotations.
2023-04-12 21:19:52 +00:00
unhold
443c3c2a56 Fix graph limits for negative values and other corner cases (#4253)
Fix lower graph limit for negative values by rounding down instead of truncating.
Consistently handle the corner cases: empty trace, min=max (e.g. single value)
by drawing the grid lines for a single grid division.
2023-04-12 21:18:09 +00:00
X-Ryl669
d75daa9644 Add always trigger stop (#4249)
* feat: Add manual control config override 1/3

* feat: Add manual control config override 2/3

* feat: Add manual control config override 3/3

* No magical number is better

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

---------

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2023-04-12 21:16:44 +00:00
Joe
7963abb27a Fix BedJet setup priority [fixes esphome/issues#3807] (#4677)
There is a race condition where a BedJet unit previously had its BLE
"notify" flag enabled, and it continues to broadcast these notify
packets even after the ESP32 (and BLEClient) goes away, such as during
a crash or unplugging power.

BLEClient::setup_priority=AFTER_BLUETOOTH, while
BedJetHub::setup_priority=AFTER_WIFI. When the ESP32 starts back up
again, BLEClient::setup() happens first and will start receiving the
BLE notify packets almost immediately. Since we register the BLEClient
child from codegen, BedJetHub is registered as a child already by this
point, so BLEClient dispatches the notify status packet (and other gatt
events) to the BedJetHub handler, even though BedJetHub::setup() has
not been called yet.

We initialize BedJetHub::codec_ in setup(), so if BLEClient starts
dispatching gatt events before setup() is called, then codec_ will not
be initialized yet. This causes BedJetHub's gatt notify handler to call
`this->codec_->decode_notify()` on an uninitialized null pointer. Since
invoking a method does not have to dereference the pointer, that method
invocation is allowed; but later trying to access memory on that
instance results in a StoreProhibited panic.

Changing the BedJetHub's setup_priority to BLUETOOTH causes it to be
setup before BLEClient, so that by the time BLEClient starts to receive
BLE packets, BedJetHub is ready to receive them.
2023-04-12 08:33:15 +00:00
Jesse Hills
0b9e8fda34 Fix pin schema for i2s microphone (#4680) 2023-04-12 08:25:19 +00:00
Dave Johnston
a3cacc0c8b Add support for SSD1306 72x40 displays (#4659)
* add SSD1306 72x40

* fix indents

* fix clang style
2023-04-12 04:02:29 +00:00
Keith Burzinski
5a4840f641 Fix some NFC/PN532 crashes (#4678)
* Add + use some constants, fix some crashes

* Fix PN532 crashes
2023-04-12 02:29:06 +00:00
Keith Burzinski
3d7d689040 Fix ESP32 SPI hardware assignment in Arduino fw (#4669) 2023-04-12 01:38:41 +00:00
Jesse Hills
b60c08dd28 Add push to talk voice assistant (#4648)
* Add push to talk voice assistant

* Refactor most code into voice_assistant

* Make voice_assistant the component and remove push_to_talk (can be done in yaml)

* Fix component setup

* Always AF_INET to match serverside

* Fix microphone and media player co-existence

* Format

* Update codeowners

* Update test file

* Fix endifs

* nullptr not NULL

* clang-tidy

* Format

* fixup: Add VA event data

* Generate proto

* Parse and log events

* Add default to switch

* Fix

* Add mic/va to test5
2023-04-11 23:45:10 +00:00
dependabot[bot]
80bc567c31 Bump pytest from 7.2.2 to 7.3.0 (#4673)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.2 to 7.3.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.2.2...7.3.0)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 22:29:40 +00:00
dependabot[bot]
888ac2e180 Bump zeroconf from 0.47.4 to 0.56.0 (#4674)
Bumps [zeroconf](https://github.com/python-zeroconf/python-zeroconf) from 0.47.4 to 0.56.0.
- [Release notes](https://github.com/python-zeroconf/python-zeroconf/releases)
- [Changelog](https://github.com/python-zeroconf/python-zeroconf/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python-zeroconf/python-zeroconf/compare/0.47.4...0.56.0)

---
updated-dependencies:
- dependency-name: zeroconf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 22:29:22 +00:00
Jörg Thalheim
421ebcc8b2 use PRIx macros for printing u32/i32 ints (#4671)
This fix compilation issues with the latest esp-idf.
2023-04-10 22:20:02 +00:00
dependabot[bot]
b56fa8c50a Bump black from 23.1.0 to 23.3.0 (#4635)
* Bump black from 23.1.0 to 23.3.0

Bumps [black](https://github.com/psf/black) from 23.1.0 to 23.3.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/23.1.0...23.3.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update black in pre-commit

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-04 02:34:36 +00:00
Ben Hoff
42401775e1 Added in mmc5603 code (#4175)
* added in mmc5603 code

* added in codeowner

* fix linter errors

* whitespace linter errors

* added codeowner

* clang format

* remove clang format from python code

* fix whitespace

* add tests

* fix test

* make requested edits

* remove status manipulation

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-04 02:34:14 +00:00
dependabot[bot]
9c9bc58c16 Bump pylint from 2.16.4 to 2.17.2 (#4650)
* Bump pylint from 2.16.4 to 2.17.2

Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.4 to 2.17.2.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.16.4...v2.17.2)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add return 0 to run_miniterm

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-03 23:55:00 +00:00
tracestep
fbc129cccc Version retry (fixes esphome/issues#3823) (#4651) 2023-04-03 22:23:31 +00:00
Jesse Hills
99638190cb VSCode / devcontainer updates (#4647) 2023-04-03 19:44:46 +00:00
RoboMagus
d78e9e6aa8 Number step not optional (#4649)
* Number step not optional

* Update __init__.py

* Update __init__.py

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-04-03 19:31:11 +00:00
Mikkel Jeppesen
878155a03d Log calibration results at level INFO (#4240)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-31 09:05:28 +00:00
Fabian
9922eb83e2 Support advanced UART customization (#4465)
* Add methods to get hardware uart details.

* Fix `setRxBufferSize` error.

---------

Co-authored-by: Your Name <you@example.com>
2023-03-31 04:30:24 +00:00
Fabian
79f861f012 Avoid sensor padding. (#4638)
Co-authored-by: Your Name <you@example.com>
2023-03-31 04:29:17 +00:00
Fabian
4faa9d109e entity_base avoid padding bytes. (#4637)
Co-authored-by: Your Name <you@example.com>
2023-03-31 04:28:49 +00:00
kahrendt
28534ecc61 Binary map bugfixes (#4636)
* limit configuration to 64 binary sensors to match code limitation

* remove superfluous debug logging

* improve state publishing logic eliminating NAN being sent on boot in certain cases

* adjust type for bitmask shift to match mask variable type
2023-03-31 04:27:24 +00:00
felixlungu
616e0a21d8 add bluetooth mac address in dump_config() (#4628)
* add bluetooth mac address in dump_config()

* Update ble.cpp

* Update ble.cpp

* Update ble.cpp

* Update ble.cpp

* Update ble.cpp

* Update ble.cpp

* Update ble.cpp
2023-03-30 01:12:06 +00:00
Jesse Hills
a546ffd490 Add ifdef to new bt proxy unsubscribe (#4634)
* Add ifdef to new bt proxy unsubscribe

* Also add to subscribe message and wrap api conneciton code

* Format file
2023-03-30 01:08:51 +00:00
Jesse Hills
b5d0aede38 Remove AUTO_LOAD from as3935 (#4630) 2023-03-30 01:08:31 +00:00
github-actions[bot]
a014d853a4 Synchronise Device Classes from Home Assistant (#4633)
* Synchronise Device Classes from Home Assistant

* Remove count do the `DEVICE_CLASSES` list is also updated

* Format file

---------

Co-authored-by: esphomebot <esphome@nabucasa.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-29 02:47:00 +00:00
Jesse Hills
c4ddf7697d Update sync-device-classes.yml 2023-03-29 14:02:34 +13:00
Jesse Hills
a2931b6774 Add workflow to sync device classes with HA dev (#4629) 2023-03-28 23:31:07 +00:00
Fabian
3ac7bf3761 EntityBase: Move ObjectId to Flash (#4569)
* Move EntityBase Object Id from memory to flash.

* Sprinkler use common `setup_entity` method.

* Remove `EntityBase` from Sprinkler.

* Support for entity names set to None

* change so gh PR picks up commit.

---------

Co-authored-by: Your Name <you@example.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-28 09:00:34 +00:00
richardhopton
922344811f feat: Add support to unsubscribe from BLE advertisements (#4620)
* feat: Add support to unsubscribe from BLE advertisements

* Fix tests & clang

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-28 08:54:58 +00:00
Fabian
cb2fcaa9b1 EntityBase Name can stay in flash. (#4594)
* `EntityBase`can stay in flash.

* Trying to please the CI.

---------

Co-authored-by: Your Name <you@example.com>
2023-03-28 06:38:56 +00:00
Alfredo
1f50bd0649 Fix EzoCommandType enum (#4593)
* Fix EzoCommandType enum

Assign explicit value to EZO_CALIBRATION, and rescale all subsequent values.

* Remove enum values

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-27 22:08:26 +00:00
Jesse Hills
e4b2de5c68 Merge pull request #4623 from esphome/bump-2023.3.2
2023.3.2
2023-03-27 16:45:14 +13:00
Jesse Hills
f862b479e7 Bump version to 2023.3.2 2023-03-27 15:58:29 +13:00
tracestep
358c59bd8d SX1509 minimum loop period (fixes esphome/issues#4325) (#4613)
* Minimum loop period (fixes esphome/issues#4325)

* clang-tidy suggestions

* More clang-tidy suggestions
2023-03-27 15:58:28 +13:00
guillempages
74fe135c9c Fix animation resizing (#4608)
Animation resizing in RGB24 format is causing an error "Image cannot be resized to a bigger size". Other image types do not show the issue, and the only difference is the "image.thumbnail" call.

Removed the call and tested; the animation is shown with the desired size.
2023-03-27 15:58:28 +13:00
Jesse Hills
8d3896172d Swap curly brackets for round on LockGuard (#4610) 2023-03-27 15:58:28 +13:00
Kai Gerken
9d9725144d Fix compile error on pzemdc.h (#4583) 2023-03-27 15:58:28 +13:00
Jesse Hills
06f83bf1c0 Fix platform restriction for bme680_bsec (#4616)
* Fix platform restriction for bme680_bsec

* Fix

* revert spi change

* Add comment back

* Dont crash on rp2040 platform
2023-03-26 22:50:33 +00:00
Jesse Hills
c2756d57d8 Allow entity names to be set to None (#4607)
* Allow entity names to be set to None so they take on the device friendly_name automatically

* Use empty
2023-03-26 22:49:09 +00:00
Berend Haan
56504692af Lower range of CONF_FREQUENCY (#4619) 2023-03-26 22:48:17 +00:00
Jesse Hills
e542e75b9e Require step to be set when calling register_number (#4622) 2023-03-26 22:44:56 +00:00
tracestep
806e43c34c SX1509 minimum loop period (fixes esphome/issues#4325) (#4613)
* Minimum loop period (fixes esphome/issues#4325)

* clang-tidy suggestions

* More clang-tidy suggestions
2023-03-26 21:59:57 +00:00
dependabot[bot]
29e7d00894 Bump actions/stale from 7 to 8 (#4615)
Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-26 21:51:37 +00:00
J. Nick Koston
9ee661c1e4 Add ability to clear the gatt cache (#4621)
* Add ability to clear the gatt cache

With BlueZ we can fully clear the cache when something goes wrong with the services, however since this is also a cache on the ESP32 we need to be able to clear the on device cache as well for the proxies since if something goes wrong with the service resolution it can cache the bad resolution on NVS forever.

Our current client implementation is limited to clearing the memory cache in Home Assistant 89355e0879/homeassistant/components/esphome/bluetooth/client.py (L512)

related issue https://github.com/esphome/issues/issues/4156

https://github.com/esphome/aioesphomeapi/pull/410

* naming

* lint

* lint

* naming

* naming

* naming

* 88 now that 87 is taken

* make const

* Update esphome/components/api/api_frame_helper.cpp
2023-03-26 21:48:56 +00:00
Regev Brody
36c0e2416d add select_schema to select component (#4545)
* add select_schema to select component

* add select_schema to select component

* fix cr
2023-03-26 20:01:35 +00:00
RoboMagus
e4ba3ff1db Limit range on filter time period for remote_receiver (#4604)
* Limit range on filter time period for remote_receiver

* pylint
2023-03-23 18:41:14 +00:00
dependabot[bot]
be69b49880 Bump pytest-asyncio from 0.20.3 to 0.21.0 (#4599)
Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.20.3 to 0.21.0.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.20.3...v0.21.0)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 18:38:47 +00:00
dependabot[bot]
cc317d27f5 Bump zeroconf from 0.47.3 to 0.47.4 (#4597)
Bumps [zeroconf](https://github.com/python-zeroconf/python-zeroconf) from 0.47.3 to 0.47.4.
- [Release notes](https://github.com/python-zeroconf/python-zeroconf/releases)
- [Changelog](https://github.com/python-zeroconf/python-zeroconf/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python-zeroconf/python-zeroconf/compare/0.47.3...0.47.4)

---
updated-dependencies:
- dependency-name: zeroconf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 18:38:20 +00:00
Dominik Skalník
c16709ed95 fix wrong port multiplexer name in dump GPIO function (#4592) 2023-03-23 18:37:40 +00:00
guillempages
e13eaf6706 Fix animation resizing (#4608)
Animation resizing in RGB24 format is causing an error "Image cannot be resized to a bigger size". Other image types do not show the issue, and the only difference is the "image.thumbnail" call.

Removed the call and tested; the animation is shown with the desired size.
2023-03-22 08:05:09 +00:00
Jesse Hills
a1eb3b8475 Swap curly brackets for round on LockGuard (#4610) 2023-03-22 07:56:02 +00:00
Jesse Hills
d52e425ba2 Remove EntityBase from sprinkler (#4606)
* Remove EntityBase form sprinkler

* remove unneeded method

* Set name correctly
Move some timers to `setup` that rely on this->name_

* Fix SprinklerControllerSwitch setup

* Update esphome/components/sprinkler/__init__.py

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

---------

Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2023-03-22 07:35:16 +00:00
Jesse Hills
dd8dc1ef1d Merge pull request #4609 from esphome/bump-2023.3.1
2023.3.1
2023-03-22 12:40:28 +13:00
Jesse Hills
bc427de16a Bump version to 2023.3.1 2023-03-22 12:03:34 +13:00
Jesse Hills
db5988bbe1 rp2040: Use fake Mutex lock (#4602) 2023-03-22 12:03:34 +13:00
Nathaniel Wesley Filardo
a3875af4b4 climate: brown paper bag fix for on_configure (#4573)
I forgot this hunk in https://github.com/esphome/esphome/pull/4511 .
I'm sorry for the noise.
2023-03-22 12:03:34 +13:00
Jesse Hills
d70e7da0ef rp2040: Use fake Mutex lock (#4602) 2023-03-21 20:25:19 +00:00
Jesse Hills
d42f35de5d Wrap ipv6 code a bit more (#4574)
* Wrap ipv6 code a bit more for when ipv6 support should not be compiled in

* More checks

* More uses

* Fix
2023-03-21 20:24:14 +00:00
jerome992
cd57469e06 Fix negative sqrt root in ct_clamp_sensor.cpp (#2701) (#4236)
Co-authored-by: Jerome <jerome992@internet.lu>
2023-03-20 04:22:22 +00:00
Aaron S. Jackson
d98d6ff45f B/W support for GooDisplay GDEY029T94 (as used on Adafruit MagTag) (#4222)
* B/W support for GooDisplay GDEY029T94

* Fix python style ci

* linter recommendations

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-20 03:45:50 +00:00
Oxan van Leeuwen
14e38f0469 Upgrade clang-format to v13 (#4535)
* Upgrade clang-format to v13

* Apply clang-format-13 formatting changes

* Format

* Format bme_680

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-20 03:38:41 +00:00
Jesse Hills
f0f6d3f1cd Disallow uart0/1/2 as ids in config (#4446)
* Disallow uart0/1/2 as ids in config

* Update test files
2023-03-20 02:29:21 +00:00
Jesse Hills
0b383542da Split test3.yaml (#4591) 2023-03-19 22:39:02 +00:00
Michael Bisbjerg
b2cec10601 Fix outdated filter string in platformio_api (#4587) 2023-03-19 19:11:18 +00:00
Sybren A. Stüvel
48658d5a55 Add a simple 'skip_initial' filter (#4582)
* Add a simple 'skip' filter

This filter simply skips the first `send_first_at` values, then passes
everything as-is. This is quite useful when you know the first few sensor
readings should be ignored.

Example YAML:

```yaml
sensor:
  - platform: sgp30
    id: mysensor_sgp30
    eco2:
      id: mysensor_sgp30_co2
      name: "eCO₂"
      accuracy_decimals: 0
      filters:
        - skip:
            send_first_at: 41
```

* Rename the filter to `skip_initial` and simplify the schema

New usage:

```yaml
      filters:
        - skip_initial: 41
```

* Apply clang-format
2023-03-19 19:08:51 +00:00
Peter Halicky
5207ca1d52 Add support for ESP32 CAM resolutions for 3MP and 5MP sensors (OV5640 for example). Also support (almost) arbitrary camera clock, some cameras/ESP chips need slightly lower clock than 20MHz to avoid image corruption. (#4580) 2023-03-19 19:03:38 +00:00
Fabian
7196fb8e82 add define __str__ method (#4576)
Co-authored-by: Your Name <you@example.com>
2023-03-19 18:55:12 +00:00
dependabot[bot]
48ada2eebb Bump aioesphomeapi from 13.5.0 to 13.5.1 (#4572)
Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.5.0 to 13.5.1.
- [Release notes](https://github.com/esphome/aioesphomeapi/releases)
- [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.5.0...v13.5.1)

---
updated-dependencies:
- dependency-name: aioesphomeapi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-19 18:54:18 +00:00
Nathaniel Wesley Filardo
0de5808ed2 climate: brown paper bag fix for on_configure (#4573)
I forgot this hunk in https://github.com/esphome/esphome/pull/4511 .
I'm sorry for the noise.
2023-03-19 18:54:00 +00:00
Kai Gerken
ebc544e4b4 Fix compile error on pzemdc.h (#4583) 2023-03-19 18:31:05 +00:00
Raph
a31fb3c987 Add option flip_x (#4555)
* Adding flip_x

* Adding flip_x

* Adding flip_x

* Adding flip_x

* Adding flip_x

* convert tab to space

* update format
2023-03-15 22:23:01 +00:00
Samuel Sieb
dfc7cd7f5d allow using a binary output for the status led (#4532)
* allow using a binary output for the status led

* lint

* output status as well

* simplify

---------

Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-03-15 22:21:35 +00:00
Witold Krecicki
a8bb2a42a1 Add an option to force SPI into software mode, useful when (#4556)
reusing pins for different purposes.
2023-03-15 22:21:25 +00:00
R Huish
3d4c0e6667 Added missing PM_1_0 and PM_10_0 for PMS5003T and PMS5003ST (#4560)
* Added missing PM_1_0 and PM_10_0 for PMS5003T

Added missing PM_1_0 and PM_10_0 for PMS5003T

* Revert "Added missing PM_1_0 and PM_10_0 for PMS5003T"

This reverts commit 86084f7c61.

* Added tests for PMS5003T

* Added missing PM_1_0 and PM_10_0 for PMS5003T PMS5003ST

* Added missing PM_1_0 and PM_10_0 for PMS5003T

* lint: Trailing whitespace fixed

* tab character removed

* Clang format suggested edit
2023-03-15 22:21:10 +00:00
Trent Houliston
25fb288016 Update the delta filter to take a percentage value as well as an absolute value (#4391) 2023-03-15 22:20:18 +00:00
Fabian
1b8b8cdd11 EntityBase: Icon string can stay in flash. (#4566)
* Icon string can stay in flash.

* Remove redundant const.

---------

Co-authored-by: Your Name <you@example.com>
2023-03-15 22:20:12 +00:00
Jesse Hills
e6737479f7 Merge pull request #4568 from esphome/bump-2023.3.0
2023.3.0
2023-03-16 10:40:18 +13:00
Jesse Hills
7f75832bf1 Bump version to 2023.3.0 2023-03-16 09:38:19 +13:00
Jesse Hills
33339e3bd8 Merge branch 'beta' into bump-2023.3.0 2023-03-16 09:38:19 +13:00
Jesse Hills
c298c1166f Merge pull request #4567 from esphome/bump-2023.3.0b6
2023.3.0b6
2023-03-16 09:34:00 +13:00
Jesse Hills
c3d9eef01f Bump version to 2023.3.0b6 2023-03-16 08:57:54 +13:00
NP v/d Spek
5ffdc66864 fixing shrink and extend functions of the displaybuffer's Rect class (#4565)
* fixing rectangle's `shrink` and `extend`

* fixed the rect::shrink and rect::inside methods
and added rect:equal() method

* fixed internal clang issue again. When would is
this going to be fixed :(

* fixed internal clang issue again. When would is
this going to be fixed :(

* remove trailing space
2023-03-16 08:57:54 +13:00
NP v/d Spek
2f50e18eb5 fixing shrink and extend functions of the displaybuffer's Rect class (#4565)
* fixing rectangle's `shrink` and `extend`

* fixed the rect::shrink and rect::inside methods
and added rect:equal() method

* fixed internal clang issue again. When would is
this going to be fixed :(

* fixed internal clang issue again. When would is
this going to be fixed :(

* remove trailing space
2023-03-15 19:45:50 +00:00
Jesse Hills
9922c1503a Merge pull request #4564 from esphome/bump-2023.3.0b5
2023.3.0b5
2023-03-15 23:46:14 +13:00
Jesse Hills
fce99d4b17 Bump version to 2023.3.0b5 2023-03-15 21:20:08 +13:00
Jesse Hills
11567085d8 Mark esp32_touch supported only on standard esp32 variant (#4562)
* Mark esp32_touch supported only on standard esp32 variant

* Add back default
2023-03-15 21:20:08 +13:00
Keith Burzinski
83f8e84247 Remove switch actions during config; bump setup priority (#4563) 2023-03-15 21:20:08 +13:00
Jesse Hills
215107e8ea Mark esp32_touch supported only on standard esp32 variant (#4562)
* Mark esp32_touch supported only on standard esp32 variant

* Add back default
2023-03-15 07:42:33 +00:00
Keith Burzinski
d3f2b93c42 Remove switch actions during config; bump setup priority (#4563) 2023-03-15 05:21:23 +00:00
Jesse Hills
11eb5cb0fa Merge pull request #4559 from esphome/bump-2023.3.0b4
2023.3.0b4
2023-03-14 16:17:51 +13:00
Jesse Hills
9a7af97b2d Bump version to 2023.3.0b4 2023-03-14 14:11:55 +13:00
Stroe Andrei Catalin
5e11469f50 Added response for Tuya RSSI command (#4549)
* Added wifi rssi util
Added tuya mcu response to wifi rssi command

* Cleanup

* PR Comments

* PR Comments
2023-03-14 14:11:55 +13:00
DAVe3283
0c7a3d1fff Revert "Remove state class from uptime sensor (#4345)" (#4557)
This reverts commit 36c2e770bf.
Addresses esphome/issues#4193.
2023-03-14 14:11:55 +13:00
Eduardo Roldan
8a705bf4b0 pipsolar component. Correct the sscanf format for QPIG command parsing to set pv_input_voltage as float (not int) (#4165) 2023-03-14 14:11:55 +13:00
Stroe Andrei Catalin
ee7102fcd1 Added response for Tuya RSSI command (#4549)
* Added wifi rssi util
Added tuya mcu response to wifi rssi command

* Cleanup

* PR Comments

* PR Comments
2023-03-14 00:54:35 +00:00
DAVe3283
a44e38300b Revert "Remove state class from uptime sensor (#4345)" (#4557)
This reverts commit 36c2e770bf.
Addresses esphome/issues#4193.
2023-03-14 00:52:19 +00:00
Eduardo Roldan
b00e20c29f pipsolar component. Correct the sscanf format for QPIG command parsing to set pv_input_voltage as float (not int) (#4165) 2023-03-13 22:46:46 +00:00
Jesse Hills
6a89180deb Merge pull request #4553 from esphome/bump-2023.3.0b3
2023.3.0b3
2023-03-13 15:31:04 +13:00
Jesse Hills
65d2b806cc Bump version to 2023.3.0b3 2023-03-13 13:32:21 +13:00
Jesse Hills
c149a3033c Map gpio pins for touch on esp32-s2/s3 (#4552)
* Map gpio pins for touch on esp32-s2/s3

* fix value
2023-03-13 13:32:21 +13:00
NP v/d Spek
4b7c233f1a On the ILI9xxx display's enable the psram on esp32 and allow big screen (#4551)
* enable the psram on esp32 and allow big screen

* update CODEOWNERS

* small update

* update CODEOWNERS again.

* Removed the M5STACK because it is a ESP32 device.

* i removed the wrong model

* update the error message.
2023-03-13 13:32:21 +13:00
Jesse Hills
6e8e9c2aa9 Allow AUTO_LOAD to be a function (#4550) 2023-03-13 13:32:21 +13:00
Dorian Zedler
b6f628ee40 Feat: add support for hex color in color component (#4493)
* Feat: add support for hex color in color component

* Chore: move hex color validator to color component

* Chore: add test

* Chore: fix formatting

* Chore: make linter happy

* Chore: make linter happy

* Fix: parse correct offsets

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>

* Chore: use cv.Invalid

* Fix: remove # because it indicates a comment in yaml

* Fix: only allow hex if no other color value is set

* Fix: tests

* Fix: mutual exclusion of raw and hex colors

* Chore: format file

* Update __init__.py

---------

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-13 13:32:21 +13:00
Martin Murray
bf79a700b7 Add carbon dioxide device class to scd30 sensor schema. (#4547) 2023-03-13 13:32:21 +13:00
jakehdk
cdeb6e750f Add support for new clones of mpu6050 responding with 0x70 address (#4546)
Co-authored-by: jakehdk <Jake@Jakobs-MacBook-Pro.local>
2023-03-13 13:32:21 +13:00
Jesse Hills
d642aeba0f Map gpio pins for touch on esp32-s2/s3 (#4552)
* Map gpio pins for touch on esp32-s2/s3

* fix value
2023-03-13 00:13:36 +00:00
NP v/d Spek
6a6aee510d On the ILI9xxx display's enable the psram on esp32 and allow big screen (#4551)
* enable the psram on esp32 and allow big screen

* update CODEOWNERS

* small update

* update CODEOWNERS again.

* Removed the M5STACK because it is a ESP32 device.

* i removed the wrong model

* update the error message.
2023-03-13 00:13:19 +00:00
Jesse Hills
ea17a92dbc Allow AUTO_LOAD to be a function (#4550) 2023-03-12 22:43:31 +00:00
Dorian Zedler
32a0a60480 Feat: add support for hex color in color component (#4493)
* Feat: add support for hex color in color component

* Chore: move hex color validator to color component

* Chore: add test

* Chore: fix formatting

* Chore: make linter happy

* Chore: make linter happy

* Fix: parse correct offsets

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>

* Chore: use cv.Invalid

* Fix: remove # because it indicates a comment in yaml

* Fix: only allow hex if no other color value is set

* Fix: tests

* Fix: mutual exclusion of raw and hex colors

* Chore: format file

* Update __init__.py

---------

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-12 20:26:27 +00:00
Martin Murray
5a56644702 Add carbon dioxide device class to scd30 sensor schema. (#4547) 2023-03-12 20:16:48 +00:00
jakehdk
29113808ee Add support for new clones of mpu6050 responding with 0x70 address (#4546)
Co-authored-by: jakehdk <Jake@Jakobs-MacBook-Pro.local>
2023-03-12 20:14:00 +00:00
Jesse Hills
dd226360bb Merge pull request #4542 from esphome/bump-2023.3.0b2
2023.3.0b2
2023-03-09 19:03:39 +13:00
Jesse Hills
1a9aedf152 Bump version to 2023.3.0b2 2023-03-09 15:47:57 +13:00
Carlos Garcia Saura
d82c6df57e Correct BME680 gas calculation and heater_off (#4498)
* Fix missing data array

* Fix incorrect bit offset

* Correct variable types

* Do same conversions as in original library

* Correct clang-format

* Move out float conversion for clarity

* Added check for heater stability

* Correct clang format

* Allow reporting gas resistance when heater is disabled

* Correct clang format

* Better error reporting by @DAVe3283

* Correct signed operation, range switching error was positive all the time
2023-03-09 15:47:57 +13:00
Oxan van Leeuwen
7c91b4474a Revert storing Font glyphs in manually-allocated memory (#4516)
This partially reverts commit 62459a8ae1.
2023-03-09 15:47:57 +13:00
Oxan van Leeuwen
a4f21db272 Drop broken logging macros (#4534) 2023-03-09 15:47:57 +13:00
NP v/d Spek
58a8e1859e Renaming and extending the ili9341 to the ili9xxx component (#4275)
* - Removed cleaning the screen twice.
  \Should be handled by  `DisplayBuffer::init_internal_();`
- Made ili9341::initalize() protected and renamed
  \ it to ili9341::initalize().
- ili9341::initalize() should only init the display
  \ and set the width and heigth.

* removed to much

* clang format fixes

* removing trailing underscors for
protected virtual methods

* removed the "override"  on display()

* clang fixes

* restored old changes

* Renamed the ili9341 platform to ili9xxx and added
multiple drivers as well. including PR #3848

* fixed most of the clang reported issues

* fixed reported issues

* last fixes

* Setting the right codeowners

* missing changes

* fixed naming Display() method.

* clang again

* clang fix

* fixes reported by @jesserockz & @gpambrozio

* a change to display.py removing an unneeded var

* re-introduce **backlight** option.

* update the ili9488 initialization

* update the ili9488 initialization and fix typo

* fixed typo

* add missing constants

* swap height and width back for the ili9488

* init fixes ili9488

* fixed lint issue
testing the init code

* oeps

* init fixes ili9488

* fixed wrong define

* fixed wrong define again

* removed some spaces

* revert to ili9341

* Remove parts that where used for
the switchplate

* lint fixes and removing unused function

* fix error and introducing 16bit color option

* fix error and introducing 16bit color option

* fix clang issue

* clang fix

* clang issue again

* is this what clang exprect

* clang fix

* clang fix

* try again

* let try again

* and again

* and the last clang fix

* remove the need of wifi

* update dimentions

* update ili8488 init code.

* update dimentions

* allow to change height and width

* dump color mode config

* fix

* fix

* modify logging

* referd back unrelated change

* code formatting commit and moving functions around

* add missing ;

* update code

* update code

* use the correct write_array for sending uint16_t

* fix panic loop

* fix panic loop

* - update the test file
- fixed sending display data

* clang fixes

* clang fixes

* clang fixes again

* remove .gitignore items

* remove .gitignore items

* make sure Update() can can not be called while
called

* clang correction

* adding a test yaml for the ili9341

* Update ili9341 example

* Make test ili9xxx/tests only local

* restore back old ili9341 driver code

* Add a new config for the M5Core

* fix clang request

* reverd to restore of the old ili9341
there is no proper way to say it is depricated.

* Remove the backlight/led pin from the config.
You need to use a proper light platform component

* Ili9488init changes (#88)

Fixed ILI9488 init settings, and adjusted pixel handling code to push pixels in 18 bit format.
This does not change the internal 16-bit representation.

* fixed some leftover clang issues from the merge.

* fixed the slang-tidy request.

* remove `backlight_pin` warning.

---------

Co-authored-by: JD Steffen <jdsteffen81@gmail.com>
2023-03-09 15:47:57 +13:00
Russell Cloran
2bed5b18c1 Add ESP32-S3 support in NeoPixelBus component (#4114)
* Add ESP32-S3 support in NeoPixelBus component

* Update NeoPixelBus version in platformio.ini
2023-03-09 15:47:57 +13:00
Jared Sanson
fb5eb57345 Fix ethernet clk_mode for GPIO0_OUT (#4307)
* Fix GPIO0_OUT definition for ethernet component

* Formatting

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-09 15:47:57 +13:00
Jesse Hills
6471361715 Format test files (#4541) 2023-03-09 01:54:51 +00:00
Carlos Garcia Saura
01687a9d57 Correct BME680 gas calculation and heater_off (#4498)
* Fix missing data array

* Fix incorrect bit offset

* Correct variable types

* Do same conversions as in original library

* Correct clang-format

* Move out float conversion for clarity

* Added check for heater stability

* Correct clang format

* Allow reporting gas resistance when heater is disabled

* Correct clang format

* Better error reporting by @DAVe3283

* Correct signed operation, range switching error was positive all the time
2023-03-09 00:34:06 +00:00
Oxan van Leeuwen
801fbf44c5 Revert storing Font glyphs in manually-allocated memory (#4516)
This partially reverts commit 62459a8ae1.
2023-03-09 00:14:34 +00:00
Oxan van Leeuwen
ba1416cc0e Drop deprecated entity property base methods (#4539) 2023-03-09 00:08:45 +00:00
Oxan van Leeuwen
afc1c83af4 Mark unique_id() override as deprecated (#4538) 2023-03-09 00:06:20 +00:00
Oxan van Leeuwen
da056866ff Drop broken logging macros (#4534) 2023-03-09 00:03:33 +00:00
NP v/d Spek
336c2d34e6 Renaming and extending the ili9341 to the ili9xxx component (#4275)
* - Removed cleaning the screen twice.
  \Should be handled by  `DisplayBuffer::init_internal_();`
- Made ili9341::initalize() protected and renamed
  \ it to ili9341::initalize().
- ili9341::initalize() should only init the display
  \ and set the width and heigth.

* removed to much

* clang format fixes

* removing trailing underscors for
protected virtual methods

* removed the "override"  on display()

* clang fixes

* restored old changes

* Renamed the ili9341 platform to ili9xxx and added
multiple drivers as well. including PR #3848

* fixed most of the clang reported issues

* fixed reported issues

* last fixes

* Setting the right codeowners

* missing changes

* fixed naming Display() method.

* clang again

* clang fix

* fixes reported by @jesserockz & @gpambrozio

* a change to display.py removing an unneeded var

* re-introduce **backlight** option.

* update the ili9488 initialization

* update the ili9488 initialization and fix typo

* fixed typo

* add missing constants

* swap height and width back for the ili9488

* init fixes ili9488

* fixed lint issue
testing the init code

* oeps

* init fixes ili9488

* fixed wrong define

* fixed wrong define again

* removed some spaces

* revert to ili9341

* Remove parts that where used for
the switchplate

* lint fixes and removing unused function

* fix error and introducing 16bit color option

* fix error and introducing 16bit color option

* fix clang issue

* clang fix

* clang issue again

* is this what clang exprect

* clang fix

* clang fix

* try again

* let try again

* and again

* and the last clang fix

* remove the need of wifi

* update dimentions

* update ili8488 init code.

* update dimentions

* allow to change height and width

* dump color mode config

* fix

* fix

* modify logging

* referd back unrelated change

* code formatting commit and moving functions around

* add missing ;

* update code

* update code

* use the correct write_array for sending uint16_t

* fix panic loop

* fix panic loop

* - update the test file
- fixed sending display data

* clang fixes

* clang fixes

* clang fixes again

* remove .gitignore items

* remove .gitignore items

* make sure Update() can can not be called while
called

* clang correction

* adding a test yaml for the ili9341

* Update ili9341 example

* Make test ili9xxx/tests only local

* restore back old ili9341 driver code

* Add a new config for the M5Core

* fix clang request

* reverd to restore of the old ili9341
there is no proper way to say it is depricated.

* Remove the backlight/led pin from the config.
You need to use a proper light platform component

* Ili9488init changes (#88)

Fixed ILI9488 init settings, and adjusted pixel handling code to push pixels in 18 bit format.
This does not change the internal 16-bit representation.

* fixed some leftover clang issues from the merge.

* fixed the slang-tidy request.

* remove `backlight_pin` warning.

---------

Co-authored-by: JD Steffen <jdsteffen81@gmail.com>
2023-03-08 23:03:49 +00:00
Russell Cloran
f3a969d35c Add ESP32-S3 support in NeoPixelBus component (#4114)
* Add ESP32-S3 support in NeoPixelBus component

* Update NeoPixelBus version in platformio.ini
2023-03-08 22:35:40 +00:00
Jesse Hills
63db42a1d4 Merge pull request #4536 from esphome/bump-2023.3.0b1
2023.3.0b1
2023-03-09 10:43:40 +13:00
Jared Sanson
c12dd77c64 Fix ethernet clk_mode for GPIO0_OUT (#4307)
* Fix GPIO0_OUT definition for ethernet component

* Formatting

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-08 21:03:11 +00:00
Jesse Hills
f58ffe41f8 Bump version to 2023.3.0b1 2023-03-09 09:09:39 +13:00
Jesse Hills
4f138c600b Bump version to 2023.4.0-dev 2023-03-09 09:09:39 +13:00
Jesse Hills
445d2e372c Merge branch 'dev' into bump-2023.3.0b1 2023-03-09 09:09:39 +13:00
Kai Gerken
1087cb55b4 Added pzemdc reset energy action (#4481)
* remove unused sensors on pzemdc

* add reset energy action for pzemdc

* fix lint errors

* remove trailing space on pzemdc.h

* make method reset_energy of pzemdc public

* Apply suggestions from code review

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-08 19:00:44 +00:00
J. Nick Koston
600f4be2c4 Bump esp-idf to 4.4.4 (#4528)
There are some nice BLE fixes and this uses about ~5000-8000 bytes
less RAM

https://github.com/espressif/esp-idf/releases/tag/v4.4.4
2023-03-08 18:25:25 +00:00
Fabian
5e6665494d Use PSRam for BLE scan results. (#4486)
* Use PSRam for BLE scan results.

* Format Document

* Use generic define `CONFIG_SPIRAM`.

* Formatting changes.

* Memory allocation is allowed to fail.

* Use mark_failed instead of abort.

---------

Co-authored-by: Your Name <you@example.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-08 18:23:02 +00:00
Jesse Hills
2ef25f3153 Fix ethernet driver setting gpio 5 high when no power pin defined (#4531) 2023-03-08 07:12:07 +00:00
Morgan Robertson
bc28ea1fde Add AS7341 spectral color sensor (#4331)
* Add support for AS7341 spectral color sensor.

* Run clang-format and clang-tidy.

* Post-review changes.

* Apply suggestions from code review

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-08 01:15:49 +00:00
Jesse Hills
623e31ddee sn74hc165 fixes (#4457)
* Add delay between clock changes on sn74hc165

* Increase to 10us

* Add another delay after clock low

* Print input bits every second

* Fix pin order

* Remove log

* Fix for inverted pins

* formatting
2023-03-08 01:11:12 +00:00
Oxan van Leeuwen
ceebe14628 Add ability to await safe mode in codegen (#4529)
* Add ability to await OTA safe mode

* Make pylint happy
2023-03-07 21:29:45 +00:00
DAVe3283
b29cc58144 Add absolute humidity component (#4519)
* Import Absolute Humidity component

https://PigLab.ReaperLegion.net/home-automation/hass/esphome/custom-components/absolute-humidity

* Fix terminology, add some docstrings

* Switch from double to float

https://github.com/esphome/esphome/pull/4519#pullrequestreview-1327615169
The additional precision doesn't matter in practice.

* Address code review suggestions

* Lint code
2023-03-07 20:47:25 +00:00
dependabot[bot]
1b328da265 Bump pylint from 2.16.2 to 2.16.4 (#4524)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.2 to 2.16.4.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.16.2...v2.16.4)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-07 07:21:45 +00:00
dependabot[bot]
06ca5354b2 Bump pytest from 7.2.1 to 7.2.2 (#4505)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.1 to 7.2.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.2.1...7.2.2)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-07 07:21:23 +00:00
bisbastuner
356efdb92c Add support for multiple devices in bme680_bsec (#3550)
* Add initial support for multiple devices

Re-introduce support for multiple I2C devices (it was suppressed in df37a7635f). Devices are identified by their I2C address, and the BME680 can only have the 0x76 or 0x77 address, so this adds support for a maximum of two devices.

* Reintegrate commit ebf13a0b

Reintegrate commit ebf13a0ba0 which was lost in my changes (I were working on old files)

* wrong commit

* wrong commit

* Reintegrate commit ebf13a0b

Reintegrate commit ebf13a0ba0 which was lost due to me working on old files

* Reintroduce newlines at end of files

* Reintroduce newlines at end of files

* Adhere to codebase standards

Obey the "All uses of class members and member functions should be prefixed with this-> to distinguish them from global functions in code review" rule of the Codebase Standards

* Fix formatting according to clang-format

* Perform the BSEC library reinitialization+snapshot only when more than one device is present

* Fix formatting according to clang-format

* Degrade abort message in restore_state_() from warning to verbose

This always happen at initial setup, so it's not a really useful message; when some real problems arise, we'll have a more useful warning from snapshot_state_()

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

* Reduce peak stack usage to avoid bootloops on ESP8266

Achieved mainly by moving the work_buffer needed by the BSEC library to the heap, as a single global work buffer shared by all instances.
::set_config_ has been reverted to a code path similar to the original, as that reduces peak stack usage enough to be OK on ESP8266 even without moving the work_buffer to the heap.

* Fix formatting according to clang-format

* Add support for devices with the same i2c address

Devices are now identified using their index in the BME680BSECComponent::instances member, which became a vector. This allows adding two devices with the same i2c address (which should be placed on different i2c buses). Since a BME680 can only have an address of 0x76 or 0x77, a maximum of 2 devices could be added before this commit. Now there is no theoretical limit on the number of devices which could be added.

* Fix formatting according to clang-format

* Fix formatting according to clang-format

---------

Co-authored-by: Trevor North <trevor@freedisc.co.uk>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-07 07:15:40 +00:00
dependabot[bot]
bb5ab8b36d Bump esptool from 4.5 to 4.5.1 (#4497)
Bumps [esptool](https://github.com/espressif/esptool) from 4.5 to 4.5.1.
- [Release notes](https://github.com/espressif/esptool/releases)
- [Commits](https://github.com/espressif/esptool/compare/v4.5...v4.5.1)

---
updated-dependencies:
- dependency-name: esptool
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-07 06:38:05 +00:00
kahrendt
6ecf4ecac6 FS3000 sensor (#4502)
* Add support for FS3000 sensor.

* add fs3000 to test yaml

* Clean up code with clang.

* Clean up sensor.py file.

* Update CODEOWNERS file.

* Apply suggestions from code review regarding sensor.py

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

* Apply suggestions from code review for basic issues regarding C++ code

- removed unnecessary default for FS3000Model
- use "this->" before any sensor update

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

* Move model setup to overall setup function.

* Remove unneeded CONF_ID from sensor.py

* Run clang-format

* Move set_model code to header file now that it is simplified

* Update fs3000.h

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-07 04:25:14 +00:00
Nathaniel Wesley Filardo
05ab49a615 climate: add on_control callbacks (#4511)
This lets downstream components respond to climate configuration
changes, which take place through ClimateCall objects, without also
being notified every time the state changes, which happens every time
the input sensor announces a new value.

FIXES https://github.com/esphome/feature-requests/issues/2136
2023-03-07 04:19:49 +00:00
Fabian
3773c385c7 Ensure component is ready before update. (#4523)
Co-authored-by: Your Name <you@example.com>
2023-03-07 04:16:42 +00:00
dependabot[bot]
3227ef4bca Bump aioesphomeapi from 13.4.0 to 13.5.0 (#4525)
Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.4.0 to 13.5.0.
- [Release notes](https://github.com/esphome/aioesphomeapi/releases)
- [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.4.0...v13.5.0)

---
updated-dependencies:
- dependency-name: aioesphomeapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-07 04:07:15 +00:00
Jesse Hills
5a07e8d32b Bump docker dependencies (#4526)
* Bump curl to 7.74.0-1.3+deb11u7

* Bump docker base images
2023-03-07 04:06:42 +00:00
Fredrik Gustafsson
29571a1acd implement pairing for bluetooth proxy (#4475)
* default to just-works encryption

This patch will turn on encryption when making active connections in order to comply with just-works BLE encryption.

* Revert "default to just-works encryption"

This reverts commit 05bc9e9f1c.

* implement pair method

* adhere to clang formatter

* fix oopsie

* bump bluetooth_proxy_version

* add auth callback

* generate new protos

* fix another oopsie

* add pairing status to connection

* clear paired on connect()

* lint

* add unpair ("forget") ble method

* compile protos

* fix oopsie

* add missing unpairing method

* add unpairing

* fix get_paired return type

* remove unused memcpy

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

* change to is_paired

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

* Update bluetooth_proxy.cpp

* actually add missing method

* send auth cb on set_encryption failure

* cleanup from havin the worst test setup

* lint

* match auth events to bd_addr

* add second addr check to auth cb

* add addr check to third auth cb

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-06 18:04:35 +00:00
Oxan van Leeuwen
b8538c2c12 Fix typo (#4515) 2023-03-05 23:02:36 +00:00
tljuniper
7466773ac8 substitutions: Don't warn when passwords look like a substitution (#4161)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-03-05 20:28:46 +00:00
Jesse Hills
b8ca40170e Remove idf components before checking if any in config (#4506)
* Remove idf components before checking if any in config

* Fix bug with no refresh time specified
2023-03-05 20:17:32 +00:00
Aliasghar Dashkhaneh
bd86a0ac3b Update __init__.py (#4514)
In some Sony remote codes, the **data** is more than 16 bits.
2023-03-05 18:45:54 +00:00
Jesse Hills
df3f13ded8 Add int16 to codegen (#4507) 2023-03-04 07:19:51 +00:00
Jesse Hills
a428e2b689 Fix copy-pasta mistake (#4492) 2023-02-27 01:20:56 +00:00
GitforZhangXL
86407b9f6f Change variable "skip_updates" and "skip_updates_counter" type from "uint8_t" to "uint16_t" (#4487)
* change 'skip_updates'from 'uint8' to 'uint16_t'

* Delete modbus_controller_fix.md

* Update modbus_controller.h

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-26 22:35:00 +00:00
Jesse Hills
eceb79ceab Make test3 use huge_app (#4488) 2023-02-26 22:34:51 +00:00
Oxan van Leeuwen
43fb68f8a0 Fix parallel invocations of repeat action (#4480)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-26 22:23:04 +00:00
Jesse Hills
14e7b8a1ef Run CI on merge group (#4489) 2023-02-26 20:13:45 +00:00
Fabian
62459a8ae1 Move Font glyphs to SPI RAM. (#4485)
Co-authored-by: Your Name <you@example.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-26 18:45:30 +00:00
Oxan van Leeuwen
86c0e6114f Lock scheduler items while modifying them (#4410)
* Cosmetic fixes to scheduler code

* Add generic Mutex API

* Lock scheduler items while modifying them

* Always defer MQTT callbacks on Arduino
2023-02-26 18:43:08 +00:00
Fabian
1a9141877d use same heap_caps_malloc parameter as ps_malloc. (#4484)
Co-authored-by: Your Name <you@example.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-26 18:42:29 +00:00
Jesse Hills
6ec18fc630 Update esp32 esp-idf dev and latest version numbers (#4479) 2023-02-26 18:25:22 +00:00
Andreas Hergert
4d674392e8 Add energy to pzemdc (#3626)
* added energy to pzemdc

* fixed calculation

* added test

* moved tests

---------

Co-authored-by: Andreas Hergert <andreas.hergert@otrs.com>
2023-02-23 17:38:34 +00:00
J. Nick Koston
6704b2cedf Bump esp-idf to 4.4.3 via platformio/espressif32 @ 5.3.0 (#4254)
* Bump esp-idf to 3.4.3 via platformio/espressif32 @ 5.3.0

The new version appears to improve the stability of
BLE + WiFi

* bump recommended version as well
2023-02-23 02:08:06 +00:00
Yaroslav Heriatovych
fe4fb5f1ac Add Haier climate component (#4001)
* Basic functionality works

* Cleanup

* Add tests

* Separate header

* Fix send_data_

* Formatting fix

* Add __init__.py

* Fix type

* Add codeowners

* Rename supported_swing_modes

* Use multiple swing modes, same as midea platform

* Add CLIMATE_FAN_QUIET handler

* PR fixes
2023-02-23 02:05:33 +00:00
Samuel Sieb
350d4e5071 add kuntze component (#4411)
* add kuntze component

* fixes

* more lint

---------

Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-02-23 01:31:35 +00:00
Jesse Hills
23f47d0ad2 Initial stab at importing idf components (#4000)
* Initial stab at importing idf components

* Handle repo with multiple components
Allow components directly from yaml

* Actually use the refresh config var

* Update esphome/components/esp32/__init__.py
2023-02-23 01:22:39 +00:00
Jesse Hills
c037e95861 Merge pull request #4478 from esphome/bump-2023.2.4
2023.2.4
2023-02-23 14:17:01 +13:00
Jesse Hills
2e1b35959f Bump version to 2023.2.4 2023-02-23 13:42:02 +13:00
Jesse Hills
7f46d9e0f9 Fix multiple remote_receivers with triggers (#4477) 2023-02-23 13:42:01 +13:00
Samuel Sieb
069b5f81a0 fix parity (#4476)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-02-23 13:42:01 +13:00
konsulten
3a36d0b13f BL0939 state_class set for energy sensors (#4463)
BL0939 was missing TOTAL_INCREASING for energy (kWh) thus it did not show as statistics in home assistant
2023-02-23 13:42:01 +13:00
Jesse Hills
f98d93efa8 Fix multiple remote_receivers with triggers (#4477) 2023-02-23 00:38:45 +00:00
Shreyas Karnik
91e037346b add person sensor (SEN21231) from usefulsensors (#4454)
* add person sensor (SEN21231) from usefulsensors

* add person sensor (SEN21231) from usefulsensors

* change file mode

* fix tests

* fix tests

* rollback un-intended changes

* Update esphome/components/sen21231/sen21231.cpp

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

* Update esphome/components/sen21231/sen21231.cpp

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

* Update esphome/components/sen21231/sen21231.cpp

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

* Update esphome/components/sen21231/sen21231.cpp

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

* Update esphome/components/sen21231/sen21231.cpp

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

* Update esphome/components/sen21231/sen21231.h

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

* Update esphome/components/sen21231/sensor.py

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

* Update esphome/components/sen21231/sensor.py

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

* Update esphome/components/sen21231/sensor.py

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

* Update esphome/components/sen21231/sensor.py

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

* remove unused import

* Update esphome/components/sen21231/sen21231.h

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

* Apply suggestions from code review

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

* Update esphome/components/sen21231/sensor.py

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

* Update esphome/components/sen21231/sensor.py

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

* Update esphome/components/sen21231/sen21231.h

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

* Update esphome/components/sen21231/sen21231.h

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

* remove unused import

* Update sen21231.h

* lint changes

* linting

* linting

* Update sen21231.h

* Update sen21231.cpp linting

* linting fixes

* fix codeowners

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-23 00:37:23 +00:00
Samuel Sieb
8e1430243e fix parity (#4476)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-02-22 23:40:20 +00:00
Keith Burzinski
98b3d294aa Sprinkler "v2" updates (#4159)
* Add standby switch

* Add support for arbitrary run duration in start_single_valve action

* Add divider feature

* Allow zero multiplier

* Fixes for #3740, misc. cleanup and polishing

* Integrate number components for multiplier, repeat and run duration

* Add various methods to get time remaining

* Add next_prev_ignore_disabled flag

* Optimize next/previous valve selection methods

* Add numbers_use_minutes flag

* Initialize switch states as they are set up

* Ensure SprinklerControllerSwitch has state if it's not restored

* Add repeat validation

* Misc. clean-up and tweaking

* Fix bugprone-integer-division

* More clean-up

* Set entity_category for standby_switch

* Set default entity_category for numbers

* More housekeeping

* Add run request tracking

* Fix time remaining calculation

* Use native unit_of_measurement for run duration numbers

* Unstack some ifs
2023-02-22 01:47:50 +00:00
Mikhail Zakharov
38a01988a5 fix library override logic (#4474)
* fix library override logic

* formatting
2023-02-21 21:52:06 +00:00
Fabian
d16eff5039 Support Mopeka Standard LPG tank bluetooth sensor (#4351)
* Add mopeka standard tank sensor.

* Enhance mopeka ble to find standard sensors.

* Updated `CODEOWNERS` file

* Move default from cpp to py.

* Format documents with esphome settings.

* Linter wants changes.

* Update name of `get_lpg_speed_of_sound`.

* manually update `CODEOWNERS`.

* Manually update CODEOWNER, because `build_codeowners.py. is failing.

* Add comments.

* Use percentage for `propane_butane_mix`.

* add config to `dump_config()`

* Formatting

* Use struct for data parsing and find best data.

* Add `this`.

* Consistant naming of configuration.

* Fix format issues.

* Make clang-tidy happy.

* Adjust loop variable.

---------

Co-authored-by: Your Name <you@example.com>
2023-02-21 21:48:29 +00:00
dependabot[bot]
8fb481751f Bump esptool from 4.4 to 4.5 (#4428)
Bumps [esptool](https://github.com/espressif/esptool) from 4.4 to 4.5.
- [Release notes](https://github.com/espressif/esptool/releases)
- [Commits](https://github.com/espressif/esptool/compare/v4.4...v4.5)

---
updated-dependencies:
- dependency-name: esptool
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-20 23:01:49 +00:00
Michael Muré
ba6f89a757 toshiba: add support for quiet fan mode (#4283) 2023-02-20 22:31:25 +00:00
dependabot[bot]
48e76e1538 Bump aioesphomeapi from 13.3.1 to 13.4.0 (#4472)
Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.3.1 to 13.4.0.
- [Release notes](https://github.com/esphome/aioesphomeapi/releases)
- [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.3.1...v13.4.0)

---
updated-dependencies:
- dependency-name: aioesphomeapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-20 22:29:20 +00:00
Jesse Hills
0e1d018ce3 Allow specifying target and current visual steps for climate (#4440)
* Allow specifying target and current visual steps for climate

* Fixes

* format

* format
2023-02-20 22:22:43 +00:00
Jesse Hills
50fbbf2d3b Move remaining SENSOR_SCHEMA to use sensor_schema() (#4471) 2023-02-20 03:22:37 +00:00
konsulten
247916fe89 BL0939 state_class set for energy sensors (#4463)
BL0939 was missing TOTAL_INCREASING for energy (kWh) thus it did not show as statistics in home assistant
2023-02-20 02:48:59 +00:00
Mat931
ed801f7a27 Add internal_temperature component (#4330)
* Add cpu_temperature component

* Add tests

* Fix formatting

* Possible fix for "sensor not shown in HomeAssistant"

* Rename component to internal_temperature

* Update esphome/components/internal_temperature/internal_temperature.cpp

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>

* Update esphome/components/internal_temperature/internal_temperature.cpp

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>

* Update esphome/components/internal_temperature/internal_temperature.cpp

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>

* Update internal_temperature.h

* Remove unique_id

* Update ESP32 variant detection

---------

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
2023-02-20 02:47:37 +00:00
irtimaled
f68d577986 Add configurable color datapoint (#4383)
* Add configurable color datapoint

* Lint fixes

* Review comments

* Linting
2023-02-19 21:50:46 +00:00
Jesse Hills
5c49730cb9 Simplify binary_sensor_schema function (#4469) 2023-02-19 21:13:40 +00:00
Jesse Hills
04c12823b5 Simplify button_schema function (#4468) 2023-02-19 21:13:37 +00:00
Jesse Hills
add40c7652 Simplify number_schema function (#4467) 2023-02-19 21:13:35 +00:00
Jesse Hills
f0760e99b7 Merge pull request #4466 from esphome/bump-2023.2.3
2023.2.3
2023-02-20 08:54:32 +13:00
Regev Brody
72391389a3 add SUB_BUTTON macro and ability to button schema to define the class (#4450)
* add ability to button schema to define the class

* add SUB_BUTTON macro
2023-02-19 19:54:03 +00:00
Regev Brody
e68beb8a43 add SUB_NUMBER macro and schema to number (#4449)
* add SUB_NUMBER macro and schema

* add SUB_NUMBER macro and schema

* add SUB_NUMBER macro and schema
2023-02-19 19:54:00 +00:00
Paulus Schoutsen
40e2832e67 Simplify sensor schema generation (#4462)
* Simplify sensor schema generation

* Mark class not optional

* Fix assignment
2023-02-19 19:20:13 +00:00
Jesse Hills
18fecf8c09 Bump version to 2023.2.3 2023-02-20 08:16:47 +13:00
Jesse Hills
414cf1b333 Update Manifest to rmeove unused dashboard files and include .c ethernet drivers (#4459) 2023-02-20 08:16:46 +13:00
jmichiel
d10f891f51 fix preset discovery config (#4451)
Co-authored-by: Michiel, Jeroen <jeroen.michiel@teledyneflir.com>
2023-02-20 08:16:46 +13:00
Jesse Hills
36a1f6cfb1 Update Manifest to rmeove unused dashboard files and include .c ethernet drivers (#4459) 2023-02-19 19:12:29 +00:00
Regev Brody
12bef16d54 add SUB_TEXT_SENSOR macro (#4448) 2023-02-19 19:11:24 +00:00
Regev Brody
77db8c8401 add SUB_BINARY_SENSOR macro (#4447) 2023-02-19 19:11:21 +00:00
Adam Jacques
66eecd3675 NeoPixel - Add support for ESP32-S3 (#4435) 2023-02-19 13:38:27 +00:00
jmichiel
c03b1fae68 fix preset discovery config (#4451)
Co-authored-by: Michiel, Jeroen <jeroen.michiel@teledyneflir.com>
2023-02-19 13:33:52 +00:00
Jesse Hills
37d55b55fc Fix adoption of variants and pico-w (#4455) 2023-02-17 06:06:18 +00:00
Oxan van Leeuwen
9aed758d1b Automate syncing device classes with HA (#4438)
* Sync device classes with HA

* Rename blacklist
2023-02-16 00:28:12 +00:00
Jesse Hills
dbe5587806 Add ESPHome version to generated platformio.ini (#4443)
* Add ESPHome version to generated platformio.ini

* Move description to platformio section
2023-02-16 00:27:32 +00:00
dependabot[bot]
30eec5adee Bump zeroconf from 0.47.1 to 0.47.3 (#4437)
Bumps [zeroconf](https://github.com/python-zeroconf/python-zeroconf) from 0.47.1 to 0.47.3.
- [Release notes](https://github.com/python-zeroconf/python-zeroconf/releases)
- [Changelog](https://github.com/python-zeroconf/python-zeroconf/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python-zeroconf/python-zeroconf/compare/0.47.1...0.47.3)

---
updated-dependencies:
- dependency-name: zeroconf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-15 06:19:03 +00:00
Oxan van Leeuwen
5307dfee21 Initialize all fields in ESPTime in PCF85063 (#4439) 2023-02-14 22:45:27 +00:00
Dominik Wagenknecht
8b5b9e508b Deep Sleep capable ports for ESP32S3 (#4230)
Update to provide RTC capable ports for ESP32S3.
Fresh from [espressif gpio docs](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/gpio.html)
2023-02-14 21:09:07 +00:00
Sergey Dudanov
a0d04ba091 Fix setting wrong traits on midea climate component (#4425)
* Fix issue3914

* Remove also default presets and modes

* Fix traits after autoconf
2023-02-14 00:34:50 +00:00
Jesse Hills
c02871fdfe Add final job so branch protection can require matrix ci steps (#4432) 2023-02-13 23:54:38 +00:00
Jesse Hills
0d52f555b2 Add concurrency limit to ci-docker (#4407) 2023-02-13 23:07:09 +00:00
dependabot[bot]
025cf6320f Bump aioesphomeapi from 13.1.0 to 13.3.1 (#4427)
Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.1.0 to 13.3.1.
- [Release notes](https://github.com/esphome/aioesphomeapi/releases)
- [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.1.0...v13.3.1)

---
updated-dependencies:
- dependency-name: aioesphomeapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-13 22:56:14 +00:00
dependabot[bot]
5997401e9e Bump pylint from 2.15.10 to 2.16.2 (#4426)
* Bump pylint from 2.15.10 to 2.16.2

Bumps [pylint](https://github.com/PyCQA/pylint) from 2.15.10 to 2.16.2.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.15.10...v2.16.2)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Lint

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-13 22:55:36 +00:00
dependabot[bot]
b4068dac56 Bump platformio from 6.1.5 to 6.1.6 (#4341)
* Bump platformio from 6.1.5 to 6.1.6

Bumps [platformio](https://github.com/platformio/platformio) from 6.1.5 to 6.1.6.
- [Release notes](https://github.com/platformio/platformio/releases)
- [Changelog](https://github.com/platformio/platformio-core/blob/develop/HISTORY.rst)
- [Commits](https://github.com/platformio/platformio/compare/v6.1.5...v6.1.6)

---
updated-dependencies:
- dependency-name: platformio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update dockerfile

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-13 22:41:14 +00:00
Jesse Hills
458d6e24fc Bump esphome-dashboard to 20230214.0 (#4431) 2023-02-14 11:38:37 +13:00
Jesse Hills
4f4ca61ada Handle uart.write in json-config endpoint (#4430) 2023-02-14 11:38:21 +13:00
Jesse Hills
dfeeccfcca Add version api endpoint (#4429) 2023-02-14 11:38:05 +13:00
WitchKing
3a101e8ec5 Ledc fix (#4338) 2023-02-13 15:53:40 +13:00
Expaso
7a2d7fdd19 Fixed PlatformIO Build on DEV (#4422)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-13 15:43:52 +13:00
Andre Borie
78f5c417a4 Gracefully reject vacuum map upload requests (#4414)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-13 14:43:11 +13:00
Andre Borie
b8c0f88440 Improve tuya network status command (#4415) 2023-02-13 14:14:35 +13:00
NP v/d Spek
58eeb6b1b8 Fix check for empty clipping array (#4421) 2023-02-12 17:03:53 +01:00
NP v/d Spek
f8acc45be4 Add Clipping to displaybuffer (#4271)
* adding Clipping support to the displaybuffer
- add rect structure

* removed unused define

* add missing property for storing the clipped areas

* include log header

* Move Rect method's code to cpp file
- removed obsolete remarks

* fixed reported issues

* make Rect class methods public

* clang fix

* Remove commented code

* Renaming clipping methods

* Multiple changes:
- replaced 32766 with VALUE_NO_SET
- fixed the way *_clipping(left, top, right, bottom) is stored
- add `is_clipping();`
- make sure that all clipped region are closed after `do_update_()`
- rename de parameters for `Rect::expand();`

* remove unneeded space

* replace define with static const uint8_t

* correcting my copy paste mistake

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-11 09:56:15 +13:00
dependabot[bot]
b7ab00b699 Bump black from 22.12.0 to 23.1.0 (#4375)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-10 07:40:04 +13:00
Patrick Collins
045489e6d7 Climate PID Autotune Logging fixes (#4136)
* pid autotune logging fixes

* fixed clang-format request

* improved and clarified logging

* changed logging not to alter the TAG

* logging now does not alter TAG. fixed clang formattting

* fixed string issues

* playing with strings to please the clang gods

* playing with strings

* Delete secrets.yaml

* Delete console-fan-autotune-test.yaml

* Update esphome/components/pid/pid_autotuner.cpp

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

* Update esphome/components/pid/pid_autotuner.cpp

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

* Update esphome/components/pid/pid_autotuner.cpp

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

* Update esphome/components/pid/pid_autotuner.cpp

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

* Update esphome/components/pid/pid_autotuner.cpp

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

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-09 22:37:31 +13:00
dependabot[bot]
b14e774a27 Bump pyupgrade from 3.3.0 to 3.3.1 (#4160)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-09 18:27:58 +13:00
dependabot[bot]
2a8745d7e0 Bump frenck/action-yamllint from 1.3.1 to 1.4.0 (#4289)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 18:27:30 +13:00
Oxan van Leeuwen
499cb615f1 socket: Format IPv4-mapped IPv6 addresses as regular IPv4 address (#4382) 2023-02-09 18:17:45 +13:00
Jesse Hills
4d192c7387 Fix release workflow (#4405) 2023-02-09 17:37:55 +13:00
Jesse Hills
9dd01b30bd Bump curl version in docker (#4403) 2023-02-09 16:26:06 +13:00
Jesse Hills
881cd535b9 Bump version to 2023.3.0-dev 2023-02-09 15:33:02 +13:00
499 changed files with 15925 additions and 3824 deletions

View File

@@ -4,53 +4,60 @@
"postCreateCommand": [
"script/devcontainer-post-create"
],
"containerEnv": {
"DEVCONTAINER": "1"
},
"runArgs": [
"--privileged",
"-e",
"ESPHOME_DASHBOARD_USE_PING=1"
],
"appPort": 6052,
"extensions": [
// python
"ms-python.python",
"visualstudioexptteam.vscodeintellicode",
// yaml
"redhat.vscode-yaml",
// cpp
"ms-vscode.cpptools",
// editorconfig
"editorconfig.editorconfig",
],
"settings": {
"python.languageServer": "Pylance",
"python.pythonPath": "/usr/bin/python3",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"terminal.integrated.defaultProfile.linux": "bash",
"yaml.customTags": [
"!secret scalar",
"!lambda scalar",
"!include_dir_named scalar",
"!include_dir_list scalar",
"!include_dir_merge_list scalar",
"!include_dir_merge_named scalar"
],
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/*.pyc": {
"when": "$(basename).py"
},
"**/__pycache__": true
},
"files.associations": {
"**/.vscode/*.json": "jsonc"
},
"C_Cpp.clang_format_path": "/usr/bin/clang-format-11",
"customizations": {
"vscode": {
"extensions": [
// python
"ms-python.python",
"visualstudioexptteam.vscodeintellicode",
// yaml
"redhat.vscode-yaml",
// cpp
"ms-vscode.cpptools",
// editorconfig
"editorconfig.editorconfig",
],
"settings": {
"python.languageServer": "Pylance",
"python.pythonPath": "/usr/bin/python3",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"terminal.integrated.defaultProfile.linux": "bash",
"yaml.customTags": [
"!secret scalar",
"!lambda scalar",
"!include_dir_named scalar",
"!include_dir_list scalar",
"!include_dir_merge_list scalar",
"!include_dir_merge_named scalar"
],
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/*.pyc": {
"when": "$(basename).py"
},
"**/__pycache__": true
},
"files.associations": {
"**/.vscode/*.json": "jsonc"
},
"C_Cpp.clang_format_path": "/usr/bin/clang-format-13"
}
}
}
}

View File

@@ -11,6 +11,7 @@ on:
- ".github/workflows/**"
- "requirements*.txt"
- "platformio.ini"
- "script/platformio_install_deps.py"
pull_request:
paths:
@@ -18,11 +19,17 @@ on:
- ".github/workflows/**"
- "requirements*.txt"
- "platformio.ini"
- "script/platformio_install_deps.py"
permissions:
contents: read
packages: read
concurrency:
# yamllint disable-line rule:line-length
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
check-docker:
name: Build docker containers

View File

@@ -7,6 +7,7 @@ on:
branches: [dev, beta, release]
pull_request:
merge_group:
permissions:
contents: read
@@ -22,6 +23,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
include:
- id: ci-custom
@@ -40,6 +42,10 @@ jobs:
file: tests/test3.yaml
name: Test tests/test3.yaml
pio_cache_key: test3
- id: test
file: tests/test3.1.yaml
name: Test tests/test3.1.yaml
pio_cache_key: test3.1
- id: test
file: tests/test4.yaml
name: Test tests/test4.yaml
@@ -128,7 +134,7 @@ jobs:
- name: Install clang tools
run: |
sudo apt-get install \
clang-format-11 \
clang-format-13 \
clang-tidy-11
if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format'
@@ -181,9 +187,22 @@ jobs:
- name: Run yamllint
if: matrix.id == 'yamllint'
uses: frenck/action-yamllint@v1.3.1
uses: frenck/action-yamllint@v1.4.0
- name: Suggested changes
run: script/ci-suggest-changes
# yamllint disable-line rule:line-length
if: always() && (matrix.id == 'clang-tidy' || matrix.id == 'clang-format' || matrix.id == 'lint-python')
ci-status:
name: CI Status
runs-on: ubuntu-latest
needs: [ci]
if: always()
steps:
- name: Successful deploy
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failing deploy
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1

View File

@@ -117,7 +117,7 @@ jobs:
--suffix "${{ matrix.image.suffix }}"
- name: Build and push
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
with:
context: .
file: ./docker/Dockerfile

View File

@@ -18,7 +18,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v7
- uses: actions/stale@v8
with:
days-before-pr-stale: 90
days-before-pr-close: 7
@@ -38,7 +38,7 @@ jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v7
- uses: actions/stale@v8
with:
days-before-pr-stale: -1
days-before-pr-close: -1

View File

@@ -0,0 +1,60 @@
---
name: Synchronise Device Classes from Home Assistant
on:
workflow_dispatch:
schedule:
- cron: '45 6 * * *'
permissions:
contents: write
pull-requests: write
jobs:
sync:
name: Sync Device Classes
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Checkout Home Assistant
uses: actions/checkout@v3
with:
repository: home-assistant/core
path: lib/home-assistant
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Install Home Assistant
run: |
python -m pip install --upgrade pip
pip install -e lib/home-assistant
- name: Sync
run: |
python ./script/sync-device_class.py
- name: Get PR template
id: pr-template-body
run: |
body=$(cat .github/PULL_REQUEST_TEMPLATE.md)
delimiter="$(openssl rand -hex 8)"
echo "body<<$delimiter" >> $GITHUB_OUTPUT
echo "$body" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
- name: Commit changes
uses: peter-evans/create-pull-request@v5
with:
commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@nabucasa.com>
author: esphomebot <esphome@nabucasa.com>
branch: sync/device-classes/
branch-suffix: timestamp
delete-branch: true
title: "Synchronise Device Classes from Home Assistant"
body: ${{ steps.pr-template-body.outputs.body }}

View File

@@ -2,8 +2,8 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/ambv/black
rev: 22.12.0
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
args:
@@ -27,7 +27,7 @@ repos:
- --branch=release
- --branch=beta
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.0
rev: v3.3.2
hooks:
- id: pyupgrade
args: [--py39-plus]

15
.vscode/tasks.json vendored
View File

@@ -2,15 +2,24 @@
"version": "2.0.0",
"tasks": [
{
"label": "run",
"label": "Run Dashboard",
"type": "shell",
"command": "python3 -m esphome dashboard config/",
"command": "${command:python.interpreterPath}",
"args": [
"-m",
"esphome",
"dashboard",
"config/"
],
"problemMatcher": []
},
{
"label": "clang-tidy",
"type": "shell",
"command": "./script/clang-tidy",
"command": "${command:python.interpreterPath}",
"args": [
"./script/clang-tidy"
],
"problemMatcher": [
{
"owner": "clang-tidy",

View File

@@ -11,6 +11,7 @@ esphome/*.py @esphome/core
esphome/core/* @esphome/core
# Integrations
esphome/components/absolute_humidity/* @DAVe3283
esphome/components/ac_dimmer/* @glmnet
esphome/components/adc/* @esphome/core
esphome/components/adc128s102/* @DeerMaximum
@@ -20,10 +21,12 @@ esphome/components/airthings_wave_mini/* @ncareau
esphome/components/airthings_wave_plus/* @jeromelaban
esphome/components/am43/* @buxtronix
esphome/components/am43/cover/* @buxtronix
esphome/components/am43/sensor/* @buxtronix
esphome/components/analog_threshold/* @ianchi
esphome/components/animation/* @syndlex
esphome/components/anova/* @buxtronix
esphome/components/api/* @OttoWinter
esphome/components/as7341/* @mrgnr
esphome/components/async_tcp/* @OttoWinter
esphome/components/atc_mithermometer/* @ahpohl
esphome/components/b_parasite/* @rbaron
@@ -81,6 +84,7 @@ esphome/components/esp32_ble_server/* @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz
esphome/components/esp8266/* @esphome/core
esphome/components/ethernet_info/* @gtjadsonsantos
esphome/components/exposure_notifications/* @OttoWinter
@@ -90,11 +94,14 @@ esphome/components/factory_reset/* @anatoly-savchenkov
esphome/components/fastled_base/* @OttoWinter
esphome/components/feedback/* @ianchi
esphome/components/fingerprint_grow/* @OnFreund @loongyh
esphome/components/fs3000/* @kahrendt
esphome/components/globals/* @esphome/core
esphome/components/gp8403/* @jesserockz
esphome/components/gpio/* @esphome/core
esphome/components/gps/* @coogle
esphome/components/graph/* @synco
esphome/components/growatt_solar/* @leeuwte
esphome/components/haier/* @Yarikx
esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann
@@ -102,22 +109,30 @@ esphome/components/heatpumpir/* @rob-deutsch
esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/homeassistant/* @OttoWinter
esphome/components/honeywellabp/* @RubyBailey
esphome/components/host/* @esphome/core
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/hte501/* @Stock-M
esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/hyt271/* @Philippe12
esphome/components/i2c/* @esphome/core
esphome/components/i2s_audio/* @jesserockz
esphome/components/i2s_audio/media_player/* @jesserockz
esphome/components/i2s_audio/microphone/* @jesserockz
esphome/components/i2s_audio/speaker/* @jesserockz
esphome/components/ili9xxx/* @nielsnl68
esphome/components/improv_base/* @esphome/core
esphome/components/improv_serial/* @esphome/core
esphome/components/ina260/* @MrEditor97
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/json/* @OttoWinter
esphome/components/kalman_combinator/* @Cat-Ion
esphome/components/key_collector/* @ssieb
esphome/components/key_provider/* @ssieb
esphome/components/kuntze/* @ssieb
esphome/components/lcd_menu/* @numo68
esphome/components/ld2410/* @sebcaps
esphome/components/ledc/* @OttoWinter
@@ -129,6 +144,7 @@ esphome/components/ltr390/* @sjtrny
esphome/components/matrix_keypad/* @ssieb
esphome/components/max31865/* @DAVe3283
esphome/components/max44009/* @berfenger
esphome/components/max6956/* @looping40
esphome/components/max7219digit/* @rspaargaren
esphome/components/max9611/* @mckaymatthew
esphome/components/mcp23008/* @jesserockz
@@ -147,11 +163,14 @@ esphome/components/mcp9808/* @k7hpn
esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core
esphome/components/media_player/* @jesserockz
esphome/components/microphone/* @jesserockz
esphome/components/mics_4514/* @jesserockz
esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov
esphome/components/mitsubishi/* @RubyBailey
esphome/components/mlx90393/* @functionpointer
esphome/components/mlx90614/* @jesserockz
esphome/components/mmc5603/* @benhoff
esphome/components/modbus_controller/* @martgras
esphome/components/modbus_controller/binary_sensor/* @martgras
esphome/components/modbus_controller/number/* @martgras
@@ -160,8 +179,9 @@ esphome/components/modbus_controller/select/* @martgras @stegm
esphome/components/modbus_controller/sensor/* @martgras
esphome/components/modbus_controller/switch/* @martgras
esphome/components/modbus_controller/text_sensor/* @martgras
esphome/components/mopeka_ble/* @spbrogan
esphome/components/mopeka_ble/* @Fabian-Schmidt @spbrogan
esphome/components/mopeka_pro_check/* @spbrogan
esphome/components/mopeka_std_check/* @Fabian-Schmidt
esphome/components/mpl3115a2/* @kbickar
esphome/components/mpu6886/* @fabaff
esphome/components/network/* @esphome/core
@@ -174,6 +194,7 @@ esphome/components/nfc/* @jesserockz
esphome/components/number/* @esphome/core
esphome/components/ota/* @esphome/core
esphome/components/output/* @esphome/core
esphome/components/pca6416a/* @Mat931
esphome/components/pca9554/* @hwstar
esphome/components/pcf85063/* @brogon
esphome/components/pid/* @OttoWinter
@@ -208,6 +229,7 @@ esphome/components/sdm_meter/* @jesserockz @polyfaces
esphome/components/sdp3x/* @Azimath
esphome/components/selec_meter/* @sourabhjaiswal
esphome/components/select/* @esphome/core
esphome/components/sen21231/* @shreyaskarnik
esphome/components/sen5x/* @martgras
esphome/components/sensirion_common/* @martgras
esphome/components/sensor/* @esphome/core
@@ -219,7 +241,7 @@ esphome/components/shutdown/* @esphome/core @jsuanet
esphome/components/sigma_delta_output/* @Cat-Ion
esphome/components/sim800l/* @glmnet
esphome/components/sm10bit_base/* @Cossid
esphome/components/sm2135/* @BoukeHaarsma23
esphome/components/sm2135/* @BoukeHaarsma23 @dd32 @matika77
esphome/components/sm2235/* @Cossid
esphome/components/sm2335/* @Cossid
esphome/components/sml/* @alengwenus
@@ -227,6 +249,7 @@ esphome/components/smt100/* @piechade
esphome/components/sn74hc165/* @jesserockz
esphome/components/socket/* @esphome/core
esphome/components/sonoff_d1/* @anatoly-savchenkov
esphome/components/speaker/* @jesserockz
esphome/components/spi/* @esphome/core
esphome/components/sprinkler/* @kbx81
esphome/components/sps30/* @martgras
@@ -277,6 +300,7 @@ esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter
esphome/components/vbus/* @ssieb
esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz
esphome/components/wake_on_lan/* @willwill2will54
esphome/components/web_server_base/* @OttoWinter
esphome/components/whirlpool/* @glmnet

View File

@@ -1,8 +1,6 @@
include LICENSE
include README.md
include requirements.txt
include esphome/dashboard/templates/*.html
recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE
recursive-include esphome *.cpp *.h *.tcc
recursive-include esphome *.cpp *.h *.tcc *.c
recursive-include esphome *.py.script
recursive-include esphome LICENSE.txt

View File

@@ -6,9 +6,9 @@
ARG BASEIMGTYPE=docker
# https://github.com/hassio-addons/addon-debian-base/releases
FROM ghcr.io/hassio-addons/debian-base:6.2.0 AS base-hassio
FROM ghcr.io/hassio-addons/debian-base:6.2.3 AS base-hassio
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
FROM debian:bullseye-20221024-slim AS base-docker
FROM debian:bullseye-20230208-slim AS base-docker
FROM base-${BASEIMGTYPE} AS base
@@ -24,9 +24,10 @@ RUN \
python3-setuptools=52.0.0-4 \
python3-pil=8.1.2+dfsg-0.3+deb11u1 \
python3-cryptography=3.3.2-1 \
python3-venv=3.9.2-3 \
iputils-ping=3:20210202-1 \
git=1:2.30.2-1 \
curl=7.74.0-1.3+deb11u5 \
git=1:2.30.2-1+deb11u2 \
curl=7.74.0-1.3+deb11u7 \
openssh-client=1:8.4p1-5+deb11u1 \
&& rm -rf \
/tmp/* \
@@ -51,7 +52,7 @@ RUN \
# Ubuntu python3-pip is missing wheel
pip3 install --no-cache-dir \
wheel==0.37.1 \
platformio==6.1.5 \
platformio==6.1.6 \
# Change some platformio settings
&& platformio settings set enable_telemetry No \
&& platformio settings set check_platformio_interval 1000000 \
@@ -59,10 +60,10 @@ RUN \
# First install requirements to leverage caching when requirements don't change
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini /
RUN \
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
&& /platformio_install_deps.py /platformio.ini
&& /platformio_install_deps.py /platformio.ini --libraries
# ======================= docker-type image =======================
@@ -135,7 +136,7 @@ RUN \
apt-get update \
# Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \
clang-format-11=1:11.0.1-2 \
clang-format-13=1:13.0.1-6~deb11u1 \
clang-tidy-11=1:11.0.1-2 \
patch=2.7.6-7 \
software-properties-common=0.96.20.2-2.1 \

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env python3
# This script is used in the docker containers to preinstall
# all platformio libraries in the global storage
import configparser
import subprocess
import sys
config = configparser.ConfigParser(inline_comment_prefixes=(';', ))
config.read(sys.argv[1])
libs = []
# Extract from every lib_deps key in all sections
for section in config.sections():
conf = config[section]
if "lib_deps" not in conf:
continue
for lib_dep in conf["lib_deps"].splitlines():
if not lib_dep:
# Empty line or comment
continue
if lib_dep.startswith("${"):
# Extending from another section
continue
if "@" not in lib_dep:
# No version pinned, this is an internal lib
continue
libs.append(lib_dep)
subprocess.check_call(['platformio', 'lib', '-g', 'install', *libs])

View File

@@ -152,6 +152,8 @@ def run_miniterm(config, port):
_LOGGER.error("Could not connect to serial port %s", port)
return 1
return 0
def wrap_to_code(name, comp):
coro = coroutine(comp.to_code)

View File

@@ -254,7 +254,11 @@ async def repeat_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
cg.add(var.set_count(count_template))
actions = await build_action_list(config[CONF_THEN], template_arg, args)
actions = await build_action_list(
config[CONF_THEN],
cg.TemplateArguments(cg.uint32, *template_arg.args),
[(cg.uint32, "iteration"), *args],
)
cg.add(var.add_then(actions))
return var

View File

@@ -47,6 +47,7 @@ from esphome.cpp_helpers import ( # noqa
build_registry_list,
extract_registry_entry_config,
register_parented,
past_safe_mode,
)
from esphome.cpp_types import ( # noqa
global_ns,
@@ -63,6 +64,7 @@ from esphome.cpp_types import ( # noqa
uint16,
uint32,
uint64,
int16,
int32,
int64,
size_t,

View File

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

View File

@@ -0,0 +1,182 @@
#include "esphome/core/log.h"
#include "absolute_humidity.h"
namespace esphome {
namespace absolute_humidity {
static const char *const TAG = "absolute_humidity.sensor";
void AbsoluteHumidityComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up absolute humidity '%s'...", this->get_name().c_str());
ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
if (this->temperature_sensor_->has_state()) {
this->temperature_callback_(this->temperature_sensor_->get_state());
}
ESP_LOGD(TAG, " Added callback for relative humidity '%s'", this->humidity_sensor_->get_name().c_str());
this->humidity_sensor_->add_on_state_callback([this](float state) { this->humidity_callback_(state); });
if (this->humidity_sensor_->has_state()) {
this->humidity_callback_(this->humidity_sensor_->get_state());
}
}
void AbsoluteHumidityComponent::dump_config() {
LOG_SENSOR("", "Absolute Humidity", this);
switch (this->equation_) {
case BUCK:
ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Buck");
break;
case TETENS:
ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Tetens");
break;
case WOBUS:
ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Wobus");
break;
default:
ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
break;
}
ESP_LOGCONFIG(TAG, "Sources");
ESP_LOGCONFIG(TAG, " Temperature: '%s'", this->temperature_sensor_->get_name().c_str());
ESP_LOGCONFIG(TAG, " Relative Humidity: '%s'", this->humidity_sensor_->get_name().c_str());
}
float AbsoluteHumidityComponent::get_setup_priority() const { return setup_priority::DATA; }
void AbsoluteHumidityComponent::loop() {
if (!this->next_update_) {
return;
}
this->next_update_ = false;
// Ensure we have source data
const bool no_temperature = std::isnan(this->temperature_);
const bool no_humidity = std::isnan(this->humidity_);
if (no_temperature || no_humidity) {
if (no_temperature) {
ESP_LOGW(TAG, "No valid state from temperature sensor!");
}
if (no_humidity) {
ESP_LOGW(TAG, "No valid state from temperature sensor!");
}
ESP_LOGW(TAG, "Unable to calculate absolute humidity.");
this->publish_state(NAN);
this->status_set_warning();
return;
}
// Convert to desired units
const float temperature_c = this->temperature_;
const float temperature_k = temperature_c + 273.15;
const float hr = this->humidity_ / 100;
// Calculate saturation vapor pressure
float es;
switch (this->equation_) {
case BUCK:
es = es_buck(temperature_c);
break;
case TETENS:
es = es_tetens(temperature_c);
break;
case WOBUS:
es = es_wobus(temperature_c);
break;
default:
ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
this->publish_state(NAN);
this->status_set_error();
return;
}
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
// Calculate absolute humidity
const float absolute_humidity = vapor_density(es, hr, temperature_k);
// Publish absolute humidity
ESP_LOGD(TAG, "Publishing absolute humidity %f g/m³", absolute_humidity);
this->status_clear_warning();
this->publish_state(absolute_humidity);
}
// Buck equation (https://en.wikipedia.org/wiki/Arden_Buck_equation)
// More accurate than Tetens in normal meteorologic conditions
float AbsoluteHumidityComponent::es_buck(float temperature_c) {
float a, b, c, d;
if (temperature_c >= 0) {
a = 0.61121;
b = 18.678;
c = 234.5;
d = 257.14;
} else {
a = 0.61115;
b = 18.678;
c = 233.7;
d = 279.82;
}
return a * expf((b - (temperature_c / c)) * (temperature_c / (d + temperature_c)));
}
// Tetens equation (https://en.wikipedia.org/wiki/Tetens_equation)
float AbsoluteHumidityComponent::es_tetens(float temperature_c) {
float a, b;
if (temperature_c >= 0) {
a = 17.27;
b = 237.3;
} else {
a = 21.875;
b = 265.5;
}
return 0.61078 * expf((a * temperature_c) / (temperature_c + b));
}
// Wobus equation
// https://wahiduddin.net/calc/density_altitude.htm
// https://wahiduddin.net/calc/density_algorithms.htm
// Calculate the saturation vapor pressure (kPa)
float AbsoluteHumidityComponent::es_wobus(float t) {
// THIS FUNCTION RETURNS THE SATURATION VAPOR PRESSURE ESW (MILLIBARS)
// OVER LIQUID WATER GIVEN THE TEMPERATURE T (CELSIUS). THE POLYNOMIAL
// APPROXIMATION BELOW IS DUE TO HERMAN WOBUS, A MATHEMATICIAN WHO
// WORKED AT THE NAVY WEATHER RESEARCH FACILITY, NORFOLK, VIRGINIA,
// BUT WHO IS NOW RETIRED. THE COEFFICIENTS OF THE POLYNOMIAL WERE
// CHOSEN TO FIT THE VALUES IN TABLE 94 ON PP. 351-353 OF THE SMITH-
// SONIAN METEOROLOGICAL TABLES BY ROLAND LIST (6TH EDITION). THE
// APPROXIMATION IS VALID FOR -50 < T < 100C.
//
// Baker, Schlatter 17-MAY-1982 Original version.
const float c0 = +0.99999683e00;
const float c1 = -0.90826951e-02;
const float c2 = +0.78736169e-04;
const float c3 = -0.61117958e-06;
const float c4 = +0.43884187e-08;
const float c5 = -0.29883885e-10;
const float c6 = +0.21874425e-12;
const float c7 = -0.17892321e-14;
const float c8 = +0.11112018e-16;
const float c9 = -0.30994571e-19;
const float p = c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * (c6 + t * (c7 + t * (c8 + t * (c9)))))))));
return 0.61078 / pow(p, 8);
}
// From https://www.environmentalbiophysics.org/chalk-talk-how-to-calculate-absolute-humidity/
// H/T to https://esphome.io/cookbook/bme280_environment.html
// H/T to https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
float AbsoluteHumidityComponent::vapor_density(float es, float hr, float ta) {
// es = saturated vapor pressure (kPa)
// hr = relative humidity [0-1]
// ta = absolute temperature (K)
const float ea = hr * es * 1000; // vapor pressure of the air (Pa)
const float mw = 18.01528; // molar mass of water (g⋅mol⁻¹)
const float r = 8.31446261815324; // molar gas constant (J⋅K⁻¹)
return (ea * mw) / (r * ta);
}
} // namespace absolute_humidity
} // namespace esphome

View File

@@ -0,0 +1,76 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
namespace esphome {
namespace absolute_humidity {
/// Enum listing all implemented saturation vapor pressure equations.
enum SaturationVaporPressureEquation {
BUCK,
TETENS,
WOBUS,
};
/// This class implements calculation of absolute humidity from temperature and relative humidity.
class AbsoluteHumidityComponent : public sensor::Sensor, public Component {
public:
AbsoluteHumidityComponent() = default;
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; }
void set_equation(SaturationVaporPressureEquation equation) { this->equation_ = equation; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void loop() override;
protected:
void temperature_callback_(float state) {
this->next_update_ = true;
this->temperature_ = state;
}
void humidity_callback_(float state) {
this->next_update_ = true;
this->humidity_ = state;
}
/** Buck equation for saturation vapor pressure in kPa.
*
* @param temperature_c Air temperature in °C.
*/
static float es_buck(float temperature_c);
/** Tetens equation for saturation vapor pressure in kPa.
*
* @param temperature_c Air temperature in °C.
*/
static float es_tetens(float temperature_c);
/** Wobus equation for saturation vapor pressure in kPa.
*
* @param temperature_c Air temperature in °C.
*/
static float es_wobus(float temperature_c);
/** Calculate vapor density (absolute humidity) in g/m³.
*
* @param es Saturation vapor pressure in kPa.
* @param hr Relative humidity 0 to 1.
* @param ta Absolute temperature in K.
* @param heater_duration The duration in ms that the heater should turn on for when measuring.
*/
static float vapor_density(float es, float hr, float ta);
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
bool next_update_{false};
float temperature_{NAN};
float humidity_{NAN};
SaturationVaporPressureEquation equation_;
};
} // namespace absolute_humidity
} // namespace esphome

View File

@@ -0,0 +1,56 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_HUMIDITY,
CONF_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
CONF_EQUATION,
ICON_WATER,
UNIT_GRAMS_PER_CUBIC_METER,
)
absolute_humidity_ns = cg.esphome_ns.namespace("absolute_humidity")
AbsoluteHumidityComponent = absolute_humidity_ns.class_(
"AbsoluteHumidityComponent", sensor.Sensor, cg.Component
)
SaturationVaporPressureEquation = absolute_humidity_ns.enum(
"SaturationVaporPressureEquation"
)
EQUATION = {
"BUCK": SaturationVaporPressureEquation.BUCK,
"TETENS": SaturationVaporPressureEquation.TETENS,
"WOBUS": SaturationVaporPressureEquation.WOBUS,
}
CONFIG_SCHEMA = (
sensor.sensor_schema(
unit_of_measurement=UNIT_GRAMS_PER_CUBIC_METER,
icon=ICON_WATER,
accuracy_decimals=2,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.GenerateID(): cv.declare_id(AbsoluteHumidityComponent),
cv.Required(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
cv.Required(CONF_HUMIDITY): cv.use_id(sensor.Sensor),
cv.Optional(CONF_EQUATION, default="WOBUS"): cv.enum(EQUATION, upper=True),
}
)
.extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
temperature_sensor = await cg.get_variable(config[CONF_TEMPERATURE])
cg.add(var.set_temperature_sensor(temperature_sensor))
humidity_sensor = await cg.get_variable(config[CONF_HUMIDITY])
cg.add(var.set_humidity_sensor(humidity_sensor))
cg.add(var.set_equation(config[CONF_EQUATION]))

View File

@@ -1 +1,118 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_INPUT
from esphome.core import CORE
from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import (
VARIANT_ESP32,
VARIANT_ESP32C3,
VARIANT_ESP32H2,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
)
CODEOWNERS = ["@esphome/core"]
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,
"auto": "auto",
}
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
# pin to adc1 channel mapping
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
VARIANT_ESP32: {
36: adc1_channel_t.ADC1_CHANNEL_0,
37: adc1_channel_t.ADC1_CHANNEL_1,
38: adc1_channel_t.ADC1_CHANNEL_2,
39: adc1_channel_t.ADC1_CHANNEL_3,
32: adc1_channel_t.ADC1_CHANNEL_4,
33: adc1_channel_t.ADC1_CHANNEL_5,
34: adc1_channel_t.ADC1_CHANNEL_6,
35: adc1_channel_t.ADC1_CHANNEL_7,
},
VARIANT_ESP32S2: {
1: adc1_channel_t.ADC1_CHANNEL_0,
2: adc1_channel_t.ADC1_CHANNEL_1,
3: adc1_channel_t.ADC1_CHANNEL_2,
4: adc1_channel_t.ADC1_CHANNEL_3,
5: adc1_channel_t.ADC1_CHANNEL_4,
6: adc1_channel_t.ADC1_CHANNEL_5,
7: adc1_channel_t.ADC1_CHANNEL_6,
8: adc1_channel_t.ADC1_CHANNEL_7,
9: adc1_channel_t.ADC1_CHANNEL_8,
10: adc1_channel_t.ADC1_CHANNEL_9,
},
VARIANT_ESP32S3: {
1: adc1_channel_t.ADC1_CHANNEL_0,
2: adc1_channel_t.ADC1_CHANNEL_1,
3: adc1_channel_t.ADC1_CHANNEL_2,
4: adc1_channel_t.ADC1_CHANNEL_3,
5: adc1_channel_t.ADC1_CHANNEL_4,
6: adc1_channel_t.ADC1_CHANNEL_5,
7: adc1_channel_t.ADC1_CHANNEL_6,
8: adc1_channel_t.ADC1_CHANNEL_7,
9: adc1_channel_t.ADC1_CHANNEL_8,
10: adc1_channel_t.ADC1_CHANNEL_9,
},
VARIANT_ESP32C3: {
0: adc1_channel_t.ADC1_CHANNEL_0,
1: adc1_channel_t.ADC1_CHANNEL_1,
2: adc1_channel_t.ADC1_CHANNEL_2,
3: adc1_channel_t.ADC1_CHANNEL_3,
4: adc1_channel_t.ADC1_CHANNEL_4,
},
VARIANT_ESP32H2: {
0: adc1_channel_t.ADC1_CHANNEL_0,
1: adc1_channel_t.ADC1_CHANNEL_1,
2: adc1_channel_t.ADC1_CHANNEL_2,
3: adc1_channel_t.ADC1_CHANNEL_3,
4: adc1_channel_t.ADC1_CHANNEL_4,
},
}
def validate_adc_pin(value):
if str(value).upper() == "VCC":
return cv.only_on_esp8266("VCC")
if str(value).upper() == "TEMPERATURE":
return cv.only_on_rp2040("TEMPERATURE")
if CORE.is_esp32:
value = pins.internal_gpio_input_pin_number(value)
variant = get_esp32_variant()
if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL:
raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported")
if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]:
raise cv.Invalid(f"{variant} doesn't support ADC on this pin")
return pins.internal_gpio_input_pin_schema(value)
if CORE.is_esp8266:
from esphome.components.esp8266.gpio import CONF_ANALOG
value = pins.internal_gpio_pin_number({CONF_ANALOG: True, CONF_INPUT: True})(
value
)
if value != 17: # A0
raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.")
return pins.gpio_pin_schema(
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
)(value)
if CORE.is_rp2040:
value = pins.internal_gpio_input_pin_number(value)
if value not in (26, 27, 28, 29):
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
return pins.internal_gpio_input_pin_schema(value)
raise NotImplementedError

View File

@@ -1,133 +1,27 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor, voltage_sampler
from esphome.components.esp32 import get_esp32_variant
from esphome.const import (
CONF_ATTENUATION,
CONF_RAW,
CONF_ID,
CONF_INPUT,
CONF_NUMBER,
CONF_PIN,
CONF_RAW,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
UNIT_VOLT,
)
from esphome.core import CORE
from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import (
VARIANT_ESP32,
VARIANT_ESP32C3,
VARIANT_ESP32H2,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
from . import (
ATTENUATION_MODES,
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
validate_adc_pin,
)
AUTO_LOAD = ["voltage_sampler"]
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,
"auto": "auto",
}
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
# pin to adc1 channel mapping
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
VARIANT_ESP32: {
36: adc1_channel_t.ADC1_CHANNEL_0,
37: adc1_channel_t.ADC1_CHANNEL_1,
38: adc1_channel_t.ADC1_CHANNEL_2,
39: adc1_channel_t.ADC1_CHANNEL_3,
32: adc1_channel_t.ADC1_CHANNEL_4,
33: adc1_channel_t.ADC1_CHANNEL_5,
34: adc1_channel_t.ADC1_CHANNEL_6,
35: adc1_channel_t.ADC1_CHANNEL_7,
},
VARIANT_ESP32S2: {
1: adc1_channel_t.ADC1_CHANNEL_0,
2: adc1_channel_t.ADC1_CHANNEL_1,
3: adc1_channel_t.ADC1_CHANNEL_2,
4: adc1_channel_t.ADC1_CHANNEL_3,
5: adc1_channel_t.ADC1_CHANNEL_4,
6: adc1_channel_t.ADC1_CHANNEL_5,
7: adc1_channel_t.ADC1_CHANNEL_6,
8: adc1_channel_t.ADC1_CHANNEL_7,
9: adc1_channel_t.ADC1_CHANNEL_8,
10: adc1_channel_t.ADC1_CHANNEL_9,
},
VARIANT_ESP32S3: {
1: adc1_channel_t.ADC1_CHANNEL_0,
2: adc1_channel_t.ADC1_CHANNEL_1,
3: adc1_channel_t.ADC1_CHANNEL_2,
4: adc1_channel_t.ADC1_CHANNEL_3,
5: adc1_channel_t.ADC1_CHANNEL_4,
6: adc1_channel_t.ADC1_CHANNEL_5,
7: adc1_channel_t.ADC1_CHANNEL_6,
8: adc1_channel_t.ADC1_CHANNEL_7,
9: adc1_channel_t.ADC1_CHANNEL_8,
10: adc1_channel_t.ADC1_CHANNEL_9,
},
VARIANT_ESP32C3: {
0: adc1_channel_t.ADC1_CHANNEL_0,
1: adc1_channel_t.ADC1_CHANNEL_1,
2: adc1_channel_t.ADC1_CHANNEL_2,
3: adc1_channel_t.ADC1_CHANNEL_3,
4: adc1_channel_t.ADC1_CHANNEL_4,
},
VARIANT_ESP32H2: {
0: adc1_channel_t.ADC1_CHANNEL_0,
1: adc1_channel_t.ADC1_CHANNEL_1,
2: adc1_channel_t.ADC1_CHANNEL_2,
3: adc1_channel_t.ADC1_CHANNEL_3,
4: adc1_channel_t.ADC1_CHANNEL_4,
},
}
def validate_adc_pin(value):
if str(value).upper() == "VCC":
return cv.only_on_esp8266("VCC")
if str(value).upper() == "TEMPERATURE":
return cv.only_on_rp2040("TEMPERATURE")
if CORE.is_esp32:
value = pins.internal_gpio_input_pin_number(value)
variant = get_esp32_variant()
if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL:
raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported")
if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]:
raise cv.Invalid(f"{variant} doesn't support ADC on this pin")
return pins.internal_gpio_input_pin_schema(value)
if CORE.is_esp8266:
from esphome.components.esp8266.gpio import CONF_ANALOG
value = pins.internal_gpio_pin_number({CONF_ANALOG: True, CONF_INPUT: True})(
value
)
if value != 17: # A0
raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.")
return pins.gpio_pin_schema(
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
)(value)
if CORE.is_rp2040:
value = pins.internal_gpio_input_pin_number(value)
if value not in (26, 27, 28, 29):
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
return pins.internal_gpio_input_pin_schema(value)
raise NotImplementedError
def validate_config(config):
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":

View File

@@ -16,13 +16,16 @@ ADC128S102Sensor = adc128s102_ns.class_(
)
CONF_ADC128S102_ID = "adc128s102_id"
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(ADC128S102Sensor),
cv.GenerateID(CONF_ADC128S102_ID): cv.use_id(ADC128S102),
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
}
).extend(cv.polling_component_schema("60s"))
CONFIG_SCHEMA = (
sensor.sensor_schema(ADC128S102Sensor)
.extend(
{
cv.GenerateID(CONF_ADC128S102_ID): cv.use_id(ADC128S102),
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
}
)
.extend(cv.polling_component_schema("60s"))
)
async def to_code(config):

View File

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

View File

@@ -5,7 +5,7 @@ from esphome.const import CONF_ID, CONF_PIN
CODEOWNERS = ["@buxtronix"]
DEPENDENCIES = ["ble_client"]
AUTO_LOAD = ["am43", "sensor"]
AUTO_LOAD = ["am43"]
CONF_INVERT_POSITION = "invert_position"
@@ -27,10 +27,10 @@ CONFIG_SCHEMA = (
)
def to_code(config):
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_pin(config[CONF_PIN]))
cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
yield cg.register_component(var, config)
yield cover.register_cover(var, config)
yield ble_client.register_ble_node(var, config)
await cg.register_component(var, config)
await cover.register_cover(var, config)
await ble_client.register_ble_node(var, config)

View File

@@ -40,6 +40,7 @@ void Am43Component::loop() {
CoverTraits Am43Component::get_traits() {
auto traits = CoverTraits();
traits.set_supports_stop(true);
traits.set_supports_position(true);
traits.set_supports_tilt(false);
traits.set_is_assumed_state(false);
@@ -65,7 +66,7 @@ void Am43Component::control(const CoverCall &call) {
if (this->invert_position_)
pos = 1 - pos;
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t) (pos * 100));
auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);

View File

@@ -11,6 +11,7 @@ from esphome.const import (
UNIT_PERCENT,
)
AUTO_LOAD = ["am43"]
CODEOWNERS = ["@buxtronix"]
am43_ns = cg.esphome_ns.namespace("am43")
@@ -38,15 +39,15 @@ CONFIG_SCHEMA = (
)
def to_code(config):
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield ble_client.register_ble_node(var, config)
await cg.register_component(var, config)
await ble_client.register_ble_node(var, config)
if CONF_BATTERY_LEVEL in config:
sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL])
sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL])
cg.add(var.set_battery(sens))
if CONF_ILLUMINANCE in config:
sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE])
sens = await sensor.new_sensor(config[CONF_ILLUMINANCE])
cg.add(var.set_illuminance(sens))

View File

@@ -1,6 +1,6 @@
#include "am43.h"
#include "esphome/core/log.h"
#include "am43_sensor.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32

View File

@@ -15,18 +15,24 @@ AnalogThresholdBinarySensor = analog_threshold_ns.class_(
CONF_UPPER = "upper"
CONF_LOWER = "lower"
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(AnalogThresholdBinarySensor),
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
cv.Required(CONF_THRESHOLD): cv.Any(
cv.float_,
cv.Schema(
{cv.Required(CONF_UPPER): cv.float_, cv.Required(CONF_LOWER): cv.float_}
CONFIG_SCHEMA = (
binary_sensor.binary_sensor_schema(AnalogThresholdBinarySensor)
.extend(
{
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
cv.Required(CONF_THRESHOLD): cv.Any(
cv.float_,
cv.Schema(
{
cv.Required(CONF_UPPER): cv.float_,
cv.Required(CONF_LOWER): cv.float_,
}
),
),
),
}
).extend(cv.COMPONENT_SCHEMA)
}
)
.extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):

View File

@@ -76,8 +76,6 @@ async def to_code(config):
pos = 0
for frameIndex in range(frames):
image.seek(frameIndex)
if CONF_RESIZE in config:
image.thumbnail(config[CONF_RESIZE])
frame = image.convert("RGB")
if CONF_RESIZE in config:
frame = frame.resize([width, height])

View File

@@ -4,7 +4,6 @@ from esphome.components import i2c
from esphome.const import CONF_ID
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["sensor", "binary_sensor"]
MULTI_CONF = True
CONF_APDS9960_ID = "apds9960_id"

View File

@@ -116,8 +116,12 @@ void APDS9960::setup() {
APDS9960_WRITE_BYTE(0x80, val);
}
bool APDS9960::is_color_enabled_() const {
return this->red_channel_ != nullptr || this->green_channel_ != nullptr || this->blue_channel_ != nullptr ||
this->clear_channel_ != nullptr;
#ifdef USE_SENSOR
return this->red_sensor_ != nullptr || this->green_sensor_ != nullptr || this->blue_sensor_ != nullptr ||
this->clear_sensor_ != nullptr;
#else
return false;
#endif
}
void APDS9960::dump_config() {
@@ -125,6 +129,15 @@ void APDS9960::dump_config() {
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
#ifdef USE_SENSOR
LOG_SENSOR(" ", "Red channel", this->red_sensor_);
LOG_SENSOR(" ", "Green channel", this->green_sensor_);
LOG_SENSOR(" ", "Blue channel", this->blue_sensor_);
LOG_SENSOR(" ", "Clear channel", this->clear_sensor_);
LOG_SENSOR(" ", "Proximity", this->proximity_sensor_);
#endif
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICATION_FAILED:
@@ -181,17 +194,22 @@ void APDS9960::read_color_data_(uint8_t status) {
float blue_perc = (uint_blue / float(UINT16_MAX)) * 100.0f;
ESP_LOGD(TAG, "Got clear=%.1f%% red=%.1f%% green=%.1f%% blue=%.1f%%", clear_perc, red_perc, green_perc, blue_perc);
if (this->clear_channel_ != nullptr)
this->clear_channel_->publish_state(clear_perc);
if (this->red_channel_ != nullptr)
this->red_channel_->publish_state(red_perc);
if (this->green_channel_ != nullptr)
this->green_channel_->publish_state(green_perc);
if (this->blue_channel_ != nullptr)
this->blue_channel_->publish_state(blue_perc);
#ifdef USE_SENSOR
if (this->clear_sensor_ != nullptr)
this->clear_sensor_->publish_state(clear_perc);
if (this->red_sensor_ != nullptr)
this->red_sensor_->publish_state(red_perc);
if (this->green_sensor_ != nullptr)
this->green_sensor_->publish_state(green_perc);
if (this->blue_sensor_ != nullptr)
this->blue_sensor_->publish_state(blue_perc);
#endif
}
void APDS9960::read_proximity_data_(uint8_t status) {
if (this->proximity_ == nullptr)
#ifndef USE_SENSOR
return;
#else
if (this->proximity_sensor_ == nullptr)
return;
if ((status & 0b10) == 0x00) {
@@ -204,7 +222,8 @@ void APDS9960::read_proximity_data_(uint8_t status) {
float prox_perc = (prox / float(UINT8_MAX)) * 100.0f;
ESP_LOGD(TAG, "Got proximity=%.1f%%", prox_perc);
this->proximity_->publish_state(prox_perc);
this->proximity_sensor_->publish_state(prox_perc);
#endif
}
void APDS9960::read_gesture_data_() {
if (!this->is_gesture_enabled_())
@@ -256,28 +275,29 @@ void APDS9960::read_gesture_data_() {
}
}
void APDS9960::report_gesture_(int gesture) {
#ifdef USE_BINARY_SENSOR
binary_sensor::BinarySensor *bin;
switch (gesture) {
case 1:
bin = this->up_direction_;
bin = this->up_direction_binary_sensor_;
this->gesture_up_started_ = false;
this->gesture_down_started_ = false;
ESP_LOGD(TAG, "Got gesture UP");
break;
case 2:
bin = this->down_direction_;
bin = this->down_direction_binary_sensor_;
this->gesture_up_started_ = false;
this->gesture_down_started_ = false;
ESP_LOGD(TAG, "Got gesture DOWN");
break;
case 3:
bin = this->left_direction_;
bin = this->left_direction_binary_sensor_;
this->gesture_left_started_ = false;
this->gesture_right_started_ = false;
ESP_LOGD(TAG, "Got gesture LEFT");
break;
case 4:
bin = this->right_direction_;
bin = this->right_direction_binary_sensor_;
this->gesture_left_started_ = false;
this->gesture_right_started_ = false;
ESP_LOGD(TAG, "Got gesture RIGHT");
@@ -290,6 +310,7 @@ void APDS9960::report_gesture_(int gesture) {
bin->publish_state(true);
bin->publish_state(false);
}
#endif
}
void APDS9960::process_dataset_(int up, int down, int left, int right) {
/* Algorithm: (see Figure 11 in datasheet)
@@ -365,10 +386,22 @@ void APDS9960::process_dataset_(int up, int down, int left, int right) {
}
}
float APDS9960::get_setup_priority() const { return setup_priority::DATA; }
bool APDS9960::is_proximity_enabled_() const { return this->proximity_ != nullptr || this->is_gesture_enabled_(); }
bool APDS9960::is_proximity_enabled_() const {
return
#ifdef USE_SENSOR
this->proximity_sensor_ != nullptr
#else
false
#endif
|| this->is_gesture_enabled_();
}
bool APDS9960::is_gesture_enabled_() const {
return this->up_direction_ != nullptr || this->left_direction_ != nullptr || this->down_direction_ != nullptr ||
this->right_direction_ != nullptr;
#ifdef USE_BINARY_SENSOR
return this->up_direction_binary_sensor_ != nullptr || this->left_direction_binary_sensor_ != nullptr ||
this->down_direction_binary_sensor_ != nullptr || this->right_direction_binary_sensor_ != nullptr;
#else
return false;
#endif
}
} // namespace apds9960

View File

@@ -1,14 +1,34 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
namespace esphome {
namespace apds9960 {
class APDS9960 : public PollingComponent, public i2c::I2CDevice {
#ifdef USE_SENSOR
SUB_SENSOR(red)
SUB_SENSOR(green)
SUB_SENSOR(blue)
SUB_SENSOR(clear)
SUB_SENSOR(proximity)
#endif
#ifdef USE_BINARY_SENSOR
SUB_BINARY_SENSOR(up_direction)
SUB_BINARY_SENSOR(right_direction)
SUB_BINARY_SENSOR(down_direction)
SUB_BINARY_SENSOR(left_direction)
#endif
public:
void setup() override;
void dump_config() override;
@@ -23,16 +43,6 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice {
void set_gesture_gain(uint8_t gain) { this->gesture_gain_ = gain; }
void set_gesture_wait_time(uint8_t wait_time) { this->gesture_wait_time_ = wait_time; }
void set_red_channel(sensor::Sensor *red_channel) { red_channel_ = red_channel; }
void set_green_channel(sensor::Sensor *green_channel) { green_channel_ = green_channel; }
void set_blue_channel(sensor::Sensor *blue_channel) { blue_channel_ = blue_channel; }
void set_clear_channel(sensor::Sensor *clear_channel) { clear_channel_ = clear_channel; }
void set_up_direction(binary_sensor::BinarySensor *up_direction) { up_direction_ = up_direction; }
void set_right_direction(binary_sensor::BinarySensor *right_direction) { right_direction_ = right_direction; }
void set_down_direction(binary_sensor::BinarySensor *down_direction) { down_direction_ = down_direction; }
void set_left_direction(binary_sensor::BinarySensor *left_direction) { left_direction_ = left_direction; }
void set_proximity(sensor::Sensor *proximity) { proximity_ = proximity; }
protected:
bool is_color_enabled_() const;
bool is_proximity_enabled_() const;
@@ -50,15 +60,6 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice {
uint8_t gesture_gain_;
uint8_t gesture_wait_time_;
sensor::Sensor *red_channel_{nullptr};
sensor::Sensor *green_channel_{nullptr};
sensor::Sensor *blue_channel_{nullptr};
sensor::Sensor *clear_channel_{nullptr};
binary_sensor::BinarySensor *up_direction_{nullptr};
binary_sensor::BinarySensor *right_direction_{nullptr};
binary_sensor::BinarySensor *down_direction_{nullptr};
binary_sensor::BinarySensor *left_direction_{nullptr};
sensor::Sensor *proximity_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,

View File

@@ -6,19 +6,14 @@ from . import APDS9960, CONF_APDS9960_ID
DEPENDENCIES = ["apds9960"]
DIRECTIONS = {
"UP": "set_up_direction",
"DOWN": "set_down_direction",
"LEFT": "set_left_direction",
"RIGHT": "set_right_direction",
}
DIRECTIONS = ["up", "down", "left", "right"]
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
device_class=DEVICE_CLASS_MOVING
).extend(
{
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, lower=True),
}
)
@@ -26,5 +21,5 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
async def to_code(config):
hub = await cg.get_variable(config[CONF_APDS9960_ID])
var = await binary_sensor.new_binary_sensor(config)
func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]])
func = getattr(hub, f"set_{config[CONF_DIRECTION]}_direction_binary_sensor")
cg.add(func(var))

View File

@@ -11,13 +11,7 @@ from . import APDS9960, CONF_APDS9960_ID
DEPENDENCIES = ["apds9960"]
TYPES = {
"CLEAR": "set_clear_channel",
"RED": "set_red_channel",
"GREEN": "set_green_channel",
"BLUE": "set_blue_channel",
"PROXIMITY": "set_proximity",
}
TYPES = ["clear", "red", "green", "blue", "proximity"]
CONFIG_SCHEMA = sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
@@ -26,7 +20,7 @@ CONFIG_SCHEMA = sensor.sensor_schema(
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
cv.Required(CONF_TYPE): cv.one_of(*TYPES, lower=True),
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
}
)
@@ -35,5 +29,5 @@ CONFIG_SCHEMA = sensor.sensor_schema(
async def to_code(config):
hub = await cg.get_variable(config[CONF_APDS9960_ID])
var = await sensor.new_sensor(config)
func = getattr(hub, TYPES[config[CONF_TYPE]])
func = getattr(hub, f"set_{config[CONF_TYPE]}_sensor")
cg.add(func(var))

View File

@@ -53,6 +53,9 @@ service APIConnection {
rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {}
rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {}
rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {}
rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {}
}
@@ -208,6 +211,8 @@ message DeviceInfoResponse {
string manufacturer = 12;
string friendly_name = 13;
uint32 voice_assistant_version = 14;
}
message ListEntitiesRequest {
@@ -283,6 +288,7 @@ message ListEntitiesCoverResponse {
bool disabled_by_default = 9;
string icon = 10;
EntityCategory entity_category = 11;
bool supports_stop = 12;
}
enum LegacyCoverState {
@@ -829,7 +835,7 @@ message ListEntitiesClimateResponse {
repeated ClimateMode supported_modes = 7;
float visual_min_temperature = 8;
float visual_max_temperature = 9;
float visual_temperature_step = 10;
float visual_target_temperature_step = 10;
// for older peer versions - in new system this
// is if CLIMATE_PRESET_AWAY exists is supported_presets
bool legacy_supports_away = 11;
@@ -842,6 +848,7 @@ message ListEntitiesClimateResponse {
bool disabled_by_default = 18;
string icon = 19;
EntityCategory entity_category = 20;
float visual_current_temperature_step = 21;
}
message ClimateStateResponse {
option (id) = 47;
@@ -855,8 +862,7 @@ message ClimateStateResponse {
float target_temperature = 4;
float target_temperature_low = 5;
float target_temperature_high = 6;
// For older peers, equal to preset == CLIMATE_PRESET_AWAY
bool legacy_away = 7;
bool unused_legacy_away = 7;
ClimateAction action = 8;
ClimateFanMode fan_mode = 9;
ClimateSwingMode swing_mode = 10;
@@ -879,9 +885,8 @@ message ClimateCommandRequest {
float target_temperature_low = 7;
bool has_target_temperature_high = 8;
float target_temperature_high = 9;
// legacy, for older peers, newer ones should use CLIMATE_PRESET_AWAY in preset
bool has_legacy_away = 10;
bool legacy_away = 11;
bool unused_has_legacy_away = 10;
bool unused_legacy_away = 11;
bool has_fan_mode = 12;
ClimateFanMode fan_mode = 13;
bool has_swing_mode = 14;
@@ -1124,6 +1129,7 @@ message MediaPlayerCommandRequest {
message SubscribeBluetoothLEAdvertisementsRequest {
option (id) = 66;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
}
message BluetoothServiceData {
@@ -1155,6 +1161,7 @@ enum BluetoothDeviceRequestType {
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6;
}
message BluetoothDeviceRequest {
@@ -1338,3 +1345,91 @@ message BluetoothGATTNotifyResponse {
uint64 address = 1;
uint32 handle = 2;
}
message BluetoothDevicePairingResponse {
option (id) = 85;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool paired = 2;
int32 error = 3;
}
message BluetoothDeviceUnpairingResponse {
option (id) = 86;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool success = 2;
int32 error = 3;
}
message UnsubscribeBluetoothLEAdvertisementsRequest {
option (id) = 87;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
}
message BluetoothDeviceClearCacheResponse {
option (id) = 88;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool success = 2;
int32 error = 3;
}
// ==================== PUSH TO TALK ====================
message SubscribeVoiceAssistantRequest {
option (id) = 89;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
bool subscribe = 1;
}
message VoiceAssistantRequest {
option (id) = 90;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_VOICE_ASSISTANT";
bool start = 1;
}
message VoiceAssistantResponse {
option (id) = 91;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
uint32 port = 1;
bool error = 2;
}
enum VoiceAssistantEvent {
VOICE_ASSISTANT_ERROR = 0;
VOICE_ASSISTANT_RUN_START = 1;
VOICE_ASSISTANT_RUN_END = 2;
VOICE_ASSISTANT_STT_START = 3;
VOICE_ASSISTANT_STT_END = 4;
VOICE_ASSISTANT_INTENT_START = 5;
VOICE_ASSISTANT_INTENT_END = 6;
VOICE_ASSISTANT_TTS_START = 7;
VOICE_ASSISTANT_TTS_END = 8;
}
message VoiceAssistantEventData {
string name = 1;
string value = 2;
}
message VoiceAssistantEventResponse {
option (id) = 92;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
VoiceAssistantEvent event_type = 1;
repeated VoiceAssistantEventData data = 2;
}

View File

@@ -1,5 +1,6 @@
#include "api_connection.h"
#include <cerrno>
#include <cinttypes>
#include "esphome/components/network/util.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/hal.h"
@@ -15,6 +16,9 @@
#ifdef USE_BLUETOOTH_PROXY
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
#endif
#ifdef USE_VOICE_ASSISTANT
#include "esphome/components/voice_assistant/voice_assistant.h"
#endif
namespace esphome {
namespace api {
@@ -180,7 +184,8 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_
ListEntitiesBinarySensorResponse msg;
msg.object_id = binary_sensor->get_object_id();
msg.key = binary_sensor->get_object_id_hash();
msg.name = binary_sensor->get_name();
if (binary_sensor->has_own_name())
msg.name = binary_sensor->get_name();
msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
msg.device_class = binary_sensor->get_device_class();
msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor();
@@ -212,11 +217,13 @@ bool APIConnection::send_cover_info(cover::Cover *cover) {
ListEntitiesCoverResponse msg;
msg.key = cover->get_object_id_hash();
msg.object_id = cover->get_object_id();
msg.name = cover->get_name();
if (cover->has_own_name())
msg.name = cover->get_name();
msg.unique_id = get_default_unique_id("cover", cover);
msg.assumed_state = traits.get_is_assumed_state();
msg.supports_position = traits.get_supports_position();
msg.supports_tilt = traits.get_supports_tilt();
msg.supports_stop = traits.get_supports_stop();
msg.device_class = cover->get_device_class();
msg.disabled_by_default = cover->is_disabled_by_default();
msg.icon = cover->get_icon();
@@ -275,7 +282,8 @@ bool APIConnection::send_fan_info(fan::Fan *fan) {
ListEntitiesFanResponse msg;
msg.key = fan->get_object_id_hash();
msg.object_id = fan->get_object_id();
msg.name = fan->get_name();
if (fan->has_own_name())
msg.name = fan->get_name();
msg.unique_id = get_default_unique_id("fan", fan);
msg.supports_oscillation = traits.supports_oscillation();
msg.supports_speed = traits.supports_speed();
@@ -337,7 +345,8 @@ bool APIConnection::send_light_info(light::LightState *light) {
ListEntitiesLightResponse msg;
msg.key = light->get_object_id_hash();
msg.object_id = light->get_object_id();
msg.name = light->get_name();
if (light->has_own_name())
msg.name = light->get_name();
msg.unique_id = get_default_unique_id("light", light);
msg.disabled_by_default = light->is_disabled_by_default();
@@ -418,7 +427,8 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
ListEntitiesSensorResponse msg;
msg.key = sensor->get_object_id_hash();
msg.object_id = sensor->get_object_id();
msg.name = sensor->get_name();
if (sensor->has_own_name())
msg.name = sensor->get_name();
msg.unique_id = sensor->unique_id();
if (msg.unique_id.empty())
msg.unique_id = get_default_unique_id("sensor", sensor);
@@ -448,7 +458,8 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) {
ListEntitiesSwitchResponse msg;
msg.key = a_switch->get_object_id_hash();
msg.object_id = a_switch->get_object_id();
msg.name = a_switch->get_name();
if (a_switch->has_own_name())
msg.name = a_switch->get_name();
msg.unique_id = get_default_unique_id("switch", a_switch);
msg.icon = a_switch->get_icon();
msg.assumed_state = a_switch->assumed_state();
@@ -520,7 +531,6 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
resp.custom_fan_mode = climate->custom_fan_mode.value();
if (traits.get_supports_presets() && climate->preset.has_value()) {
resp.preset = static_cast<enums::ClimatePreset>(climate->preset.value());
resp.legacy_away = resp.preset == enums::CLIMATE_PRESET_AWAY;
}
if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value())
resp.custom_preset = climate->custom_preset.value();
@@ -533,7 +543,8 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
ListEntitiesClimateResponse msg;
msg.key = climate->get_object_id_hash();
msg.object_id = climate->get_object_id();
msg.name = climate->get_name();
if (climate->has_own_name())
msg.name = climate->get_name();
msg.unique_id = get_default_unique_id("climate", climate);
msg.disabled_by_default = climate->is_disabled_by_default();
@@ -548,7 +559,9 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
msg.visual_min_temperature = traits.get_visual_min_temperature();
msg.visual_max_temperature = traits.get_visual_max_temperature();
msg.visual_temperature_step = traits.get_visual_temperature_step();
msg.visual_target_temperature_step = traits.get_visual_target_temperature_step();
msg.visual_current_temperature_step = traits.get_visual_current_temperature_step();
msg.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
msg.supports_action = traits.get_supports_action();
@@ -578,8 +591,6 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
call.set_target_temperature_low(msg.target_temperature_low);
if (msg.has_target_temperature_high)
call.set_target_temperature_high(msg.target_temperature_high);
if (msg.has_legacy_away)
call.set_preset(msg.legacy_away ? climate::CLIMATE_PRESET_AWAY : climate::CLIMATE_PRESET_HOME);
if (msg.has_fan_mode)
call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
if (msg.has_custom_fan_mode)
@@ -609,7 +620,8 @@ bool APIConnection::send_number_info(number::Number *number) {
ListEntitiesNumberResponse msg;
msg.key = number->get_object_id_hash();
msg.object_id = number->get_object_id();
msg.name = number->get_name();
if (number->has_own_name())
msg.name = number->get_name();
msg.unique_id = get_default_unique_id("number", number);
msg.icon = number->get_icon();
msg.disabled_by_default = number->is_disabled_by_default();
@@ -650,7 +662,8 @@ bool APIConnection::send_select_info(select::Select *select) {
ListEntitiesSelectResponse msg;
msg.key = select->get_object_id_hash();
msg.object_id = select->get_object_id();
msg.name = select->get_name();
if (select->has_own_name())
msg.name = select->get_name();
msg.unique_id = get_default_unique_id("select", select);
msg.icon = select->get_icon();
msg.disabled_by_default = select->is_disabled_by_default();
@@ -677,7 +690,8 @@ bool APIConnection::send_button_info(button::Button *button) {
ListEntitiesButtonResponse msg;
msg.key = button->get_object_id_hash();
msg.object_id = button->get_object_id();
msg.name = button->get_name();
if (button->has_own_name())
msg.name = button->get_name();
msg.unique_id = get_default_unique_id("button", button);
msg.icon = button->get_icon();
msg.disabled_by_default = button->is_disabled_by_default();
@@ -708,7 +722,8 @@ bool APIConnection::send_lock_info(lock::Lock *a_lock) {
ListEntitiesLockResponse msg;
msg.key = a_lock->get_object_id_hash();
msg.object_id = a_lock->get_object_id();
msg.name = a_lock->get_name();
if (a_lock->has_own_name())
msg.name = a_lock->get_name();
msg.unique_id = get_default_unique_id("lock", a_lock);
msg.icon = a_lock->get_icon();
msg.assumed_state = a_lock->traits.get_assumed_state();
@@ -753,7 +768,8 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
ListEntitiesMediaPlayerResponse msg;
msg.key = media_player->get_object_id_hash();
msg.object_id = media_player->get_object_id();
msg.name = media_player->get_name();
if (media_player->has_own_name())
msg.name = media_player->get_name();
msg.unique_id = get_default_unique_id("media_player", media_player);
msg.icon = media_player->get_icon();
msg.disabled_by_default = media_player->is_disabled_by_default();
@@ -797,7 +813,8 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
ListEntitiesCameraResponse msg;
msg.key = camera->get_object_id_hash();
msg.object_id = camera->get_object_id();
msg.name = camera->get_name();
if (camera->has_own_name())
msg.name = camera->get_name();
msg.unique_id = get_default_unique_id("camera", camera);
msg.disabled_by_default = camera->is_disabled_by_default();
msg.icon = camera->get_icon();
@@ -877,6 +894,30 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
}
#endif
#ifdef USE_VOICE_ASSISTANT
bool APIConnection::request_voice_assistant(bool start) {
if (!this->voice_assistant_subscription_)
return false;
VoiceAssistantRequest msg;
msg.start = start;
return this->send_voice_assistant_request(msg);
}
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
if (voice_assistant::global_voice_assistant != nullptr) {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
this->helper_->getpeername((struct sockaddr *) &storage, &len);
voice_assistant::global_voice_assistant->start(&storage, msg.port);
}
};
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
if (voice_assistant::global_voice_assistant != nullptr) {
voice_assistant::global_voice_assistant->on_event(msg);
}
}
#endif
bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level)
return false;
@@ -896,12 +937,12 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
this->helper_->set_log_info(client_info_);
this->client_api_version_major_ = msg.api_version_major;
this->client_api_version_minor_ = msg.api_version_minor;
ESP_LOGV(TAG, "Hello from client: '%s' | API Version %d.%d", this->client_info_.c_str(),
ESP_LOGV(TAG, "Hello from client: '%s' | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(),
this->client_api_version_major_, this->client_api_version_minor_);
HelloResponse resp;
resp.api_version_major = 1;
resp.api_version_minor = 7;
resp.api_version_minor = 8;
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name();
@@ -938,6 +979,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.manufacturer = "Espressif";
#elif defined(USE_RP2040)
resp.manufacturer = "Raspberry Pi";
#elif defined(USE_HOST)
resp.manufacturer = "Host";
#endif
resp.model = ESPHOME_BOARD;
#ifdef USE_DEEP_SLEEP
@@ -951,7 +994,12 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.webserver_port = USE_WEBSERVER_PORT;
#endif
#ifdef USE_BLUETOOTH_PROXY
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active()
? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION
: bluetooth_proxy::PASSIVE_ONLY_VERSION;
#endif
#ifdef USE_VOICE_ASSISTANT
resp.voice_assistant_version = voice_assistant::global_voice_assistant->get_version();
#endif
return resp;
}

View File

@@ -6,6 +6,7 @@
#include "api_server.h"
#include "esphome/core/application.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include <vector>
@@ -97,6 +98,12 @@ class APIConnection : public APIServerConnection {
this->send_homeassistant_service_response(call);
}
#ifdef USE_BLUETOOTH_PROXY
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = true;
}
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = false;
}
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg);
void bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
@@ -117,6 +124,15 @@ class APIConnection : public APIServerConnection {
}
#endif
#ifdef USE_VOICE_ASSISTANT
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override {
this->voice_assistant_subscription_ = msg.subscribe;
}
bool request_voice_assistant(bool start);
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
#endif
void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override {
// we initiated ping
@@ -150,9 +166,7 @@ class APIConnection : public APIServerConnection {
return {};
}
void execute_service(const ExecuteServiceRequest &msg) override;
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = true;
}
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; }
bool is_connection_setup() override {
return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated();
@@ -197,7 +211,12 @@ class APIConnection : public APIServerConnection {
uint32_t last_traffic_;
bool sent_ping_{false};
bool service_call_subscription_{false};
#ifdef USE_BLUETOOTH_PROXY
bool bluetooth_le_advertisement_subscription_{false};
#endif
#ifdef USE_VOICE_ASSISTANT
bool voice_assistant_subscription_{false};
#endif
bool next_close_ = false;
APIServer *parent_;
InitialStateIterator initial_state_iterator_;

View File

@@ -295,7 +295,7 @@ APIError APINoiseFrameHelper::state_action_() {
if (aerr != APIError::OK)
return aerr;
// ignore contents, may be used in future for flags
prologue_.push_back((uint8_t)(frame.msg.size() >> 8));
prologue_.push_back((uint8_t) (frame.msg.size() >> 8));
prologue_.push_back((uint8_t) frame.msg.size());
prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end());
@@ -492,9 +492,9 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload
// tmpbuf[1], tmpbuf[2] to be set later
const uint8_t msg_offset = 3;
const uint8_t payload_offset = msg_offset + 4;
tmpbuf[msg_offset + 0] = (uint8_t)(type >> 8); // type
tmpbuf[msg_offset + 0] = (uint8_t) (type >> 8); // type
tmpbuf[msg_offset + 1] = (uint8_t) type;
tmpbuf[msg_offset + 2] = (uint8_t)(payload_len >> 8); // data_len
tmpbuf[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len
tmpbuf[msg_offset + 3] = (uint8_t) payload_len;
// copy data
std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]);
@@ -512,7 +512,7 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload
}
size_t total_len = 3 + mbuf.size;
tmpbuf[1] = (uint8_t)(mbuf.size >> 8);
tmpbuf[1] = (uint8_t) (mbuf.size >> 8);
tmpbuf[2] = (uint8_t) mbuf.size;
struct iovec iov;
@@ -610,7 +610,7 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
uint8_t header[3];
header[0] = 0x01; // indicator
header[1] = (uint8_t)(len >> 8);
header[1] = (uint8_t) (len >> 8);
header[2] = (uint8_t) len;
struct iovec iov[2];

View File

@@ -10,8 +10,8 @@
#include "noise/protocol.h"
#endif
#include "esphome/components/socket/socket.h"
#include "api_noise_context.h"
#include "esphome/components/socket/socket.h"
namespace esphome {
namespace api {
@@ -67,6 +67,7 @@ class APIFrameHelper {
virtual bool can_write_without_blocking() = 0;
virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0;
virtual std::string getpeername() = 0;
virtual int getpeername(struct sockaddr *addr, socklen_t *addrlen) = 0;
virtual APIError close() = 0;
virtual APIError shutdown(int how) = 0;
// Give this helper a name for logging
@@ -84,7 +85,10 @@ class APINoiseFrameHelper : public APIFrameHelper {
APIError read_packet(ReadPacketBuffer *buffer) override;
bool can_write_without_blocking() override;
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
std::string getpeername() override { return socket_->getpeername(); }
std::string getpeername() override { return this->socket_->getpeername(); }
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
return this->socket_->getpeername(addr, addrlen);
}
APIError close() override;
APIError shutdown(int how) override;
// Give this helper a name for logging
@@ -144,7 +148,10 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
APIError read_packet(ReadPacketBuffer *buffer) override;
bool can_write_without_blocking() override;
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
std::string getpeername() override { return socket_->getpeername(); }
std::string getpeername() override { return this->socket_->getpeername(); }
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
return this->socket_->getpeername(addr, addrlen);
}
APIError close() override;
APIError shutdown(int how) override;
// Give this helper a name for logging

View File

@@ -400,6 +400,34 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE";
default:
return "UNKNOWN";
}
}
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::VoiceAssistantEvent value) {
switch (value) {
case enums::VOICE_ASSISTANT_ERROR:
return "VOICE_ASSISTANT_ERROR";
case enums::VOICE_ASSISTANT_RUN_START:
return "VOICE_ASSISTANT_RUN_START";
case enums::VOICE_ASSISTANT_RUN_END:
return "VOICE_ASSISTANT_RUN_END";
case enums::VOICE_ASSISTANT_STT_START:
return "VOICE_ASSISTANT_STT_START";
case enums::VOICE_ASSISTANT_STT_END:
return "VOICE_ASSISTANT_STT_END";
case enums::VOICE_ASSISTANT_INTENT_START:
return "VOICE_ASSISTANT_INTENT_START";
case enums::VOICE_ASSISTANT_INTENT_END:
return "VOICE_ASSISTANT_INTENT_END";
case enums::VOICE_ASSISTANT_TTS_START:
return "VOICE_ASSISTANT_TTS_START";
case enums::VOICE_ASSISTANT_TTS_END:
return "VOICE_ASSISTANT_TTS_END";
default:
return "UNKNOWN";
}
@@ -592,6 +620,10 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
this->bluetooth_proxy_version = value.as_uint32();
return true;
}
case 14: {
this->voice_assistant_version = value.as_uint32();
return true;
}
default:
return false;
}
@@ -652,6 +684,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(11, this->bluetooth_proxy_version);
buffer.encode_string(12, this->manufacturer);
buffer.encode_string(13, this->friendly_name);
buffer.encode_uint32(14, this->voice_assistant_version);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void DeviceInfoResponse::dump_to(std::string &out) const {
@@ -710,6 +743,11 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
out.append(" friendly_name: ");
out.append("'").append(this->friendly_name).append("'");
out.append("\n");
out.append(" voice_assistant_version: ");
sprintf(buffer, "%u", this->voice_assistant_version);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
@@ -903,6 +941,10 @@ bool ListEntitiesCoverResponse::decode_varint(uint32_t field_id, ProtoVarInt val
this->entity_category = value.as_enum<enums::EntityCategory>();
return true;
}
case 12: {
this->supports_stop = value.as_bool();
return true;
}
default:
return false;
}
@@ -955,6 +997,7 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(9, this->disabled_by_default);
buffer.encode_string(10, this->icon);
buffer.encode_enum<enums::EntityCategory>(11, this->entity_category);
buffer.encode_bool(12, this->supports_stop);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesCoverResponse::dump_to(std::string &out) const {
@@ -1004,6 +1047,10 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const {
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" supports_stop: ");
out.append(YESNO(this->supports_stop));
out.append("\n");
out.append("}");
}
#endif
@@ -3451,7 +3498,11 @@ bool ListEntitiesClimateResponse::decode_32bit(uint32_t field_id, Proto32Bit val
return true;
}
case 10: {
this->visual_temperature_step = value.as_float();
this->visual_target_temperature_step = value.as_float();
return true;
}
case 21: {
this->visual_current_temperature_step = value.as_float();
return true;
}
default:
@@ -3470,7 +3521,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
}
buffer.encode_float(8, this->visual_min_temperature);
buffer.encode_float(9, this->visual_max_temperature);
buffer.encode_float(10, this->visual_temperature_step);
buffer.encode_float(10, this->visual_target_temperature_step);
buffer.encode_bool(11, this->legacy_supports_away);
buffer.encode_bool(12, this->supports_action);
for (auto &it : this->supported_fan_modes) {
@@ -3491,6 +3542,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(18, this->disabled_by_default);
buffer.encode_string(19, this->icon);
buffer.encode_enum<enums::EntityCategory>(20, this->entity_category);
buffer.encode_float(21, this->visual_current_temperature_step);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
@@ -3537,8 +3589,8 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
out.append(buffer);
out.append("\n");
out.append(" visual_temperature_step: ");
sprintf(buffer, "%g", this->visual_temperature_step);
out.append(" visual_target_temperature_step: ");
sprintf(buffer, "%g", this->visual_target_temperature_step);
out.append(buffer);
out.append("\n");
@@ -3591,6 +3643,11 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" visual_current_temperature_step: ");
sprintf(buffer, "%g", this->visual_current_temperature_step);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
@@ -3601,7 +3658,7 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
return true;
}
case 7: {
this->legacy_away = value.as_bool();
this->unused_legacy_away = value.as_bool();
return true;
}
case 8: {
@@ -3671,7 +3728,7 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_float(4, this->target_temperature);
buffer.encode_float(5, this->target_temperature_low);
buffer.encode_float(6, this->target_temperature_high);
buffer.encode_bool(7, this->legacy_away);
buffer.encode_bool(7, this->unused_legacy_away);
buffer.encode_enum<enums::ClimateAction>(8, this->action);
buffer.encode_enum<enums::ClimateFanMode>(9, this->fan_mode);
buffer.encode_enum<enums::ClimateSwingMode>(10, this->swing_mode);
@@ -3712,8 +3769,8 @@ void ClimateStateResponse::dump_to(std::string &out) const {
out.append(buffer);
out.append("\n");
out.append(" legacy_away: ");
out.append(YESNO(this->legacy_away));
out.append(" unused_legacy_away: ");
out.append(YESNO(this->unused_legacy_away));
out.append("\n");
out.append(" action: ");
@@ -3765,11 +3822,11 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
return true;
}
case 10: {
this->has_legacy_away = value.as_bool();
this->unused_has_legacy_away = value.as_bool();
return true;
}
case 11: {
this->legacy_away = value.as_bool();
this->unused_legacy_away = value.as_bool();
return true;
}
case 12: {
@@ -3854,8 +3911,8 @@ void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_float(7, this->target_temperature_low);
buffer.encode_bool(8, this->has_target_temperature_high);
buffer.encode_float(9, this->target_temperature_high);
buffer.encode_bool(10, this->has_legacy_away);
buffer.encode_bool(11, this->legacy_away);
buffer.encode_bool(10, this->unused_has_legacy_away);
buffer.encode_bool(11, this->unused_legacy_away);
buffer.encode_bool(12, this->has_fan_mode);
buffer.encode_enum<enums::ClimateFanMode>(13, this->fan_mode);
buffer.encode_bool(14, this->has_swing_mode);
@@ -3911,12 +3968,12 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
out.append(buffer);
out.append("\n");
out.append(" has_legacy_away: ");
out.append(YESNO(this->has_legacy_away));
out.append(" unused_has_legacy_away: ");
out.append(YESNO(this->unused_has_legacy_away));
out.append("\n");
out.append(" legacy_away: ");
out.append(YESNO(this->legacy_away));
out.append(" unused_legacy_away: ");
out.append(YESNO(this->unused_legacy_away));
out.append("\n");
out.append(" has_fan_mode: ");
@@ -5964,6 +6021,290 @@ void BluetoothGATTNotifyResponse::dump_to(std::string &out) const {
out.append("}");
}
#endif
bool BluetoothDevicePairingResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->paired = value.as_bool();
return true;
}
case 3: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->paired);
buffer.encode_int32(3, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDevicePairingResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDevicePairingResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" paired: ");
out.append(YESNO(this->paired));
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothDeviceUnpairingResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->success = value.as_bool();
return true;
}
case 3: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->success);
buffer.encode_int32(3, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDeviceUnpairingResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" success: ");
out.append(YESNO(this->success));
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
void UnsubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {}
#ifdef HAS_PROTO_MESSAGE_DUMP
void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const {
out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}");
}
#endif
bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->success = value.as_bool();
return true;
}
case 3: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->success);
buffer.encode_int32(3, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDeviceClearCacheResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" success: ");
out.append(YESNO(this->success));
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool SubscribeVoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->subscribe = value.as_bool();
return true;
}
default:
return false;
}
}
void SubscribeVoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->subscribe); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("SubscribeVoiceAssistantRequest {\n");
out.append(" subscribe: ");
out.append(YESNO(this->subscribe));
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->start = value.as_bool();
return true;
}
default:
return false;
}
}
void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantRequest {\n");
out.append(" start: ");
out.append(YESNO(this->start));
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->port = value.as_uint32();
return true;
}
case 2: {
this->error = value.as_bool();
return true;
}
default:
return false;
}
}
void VoiceAssistantResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->port);
buffer.encode_bool(2, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantResponse {\n");
out.append(" port: ");
sprintf(buffer, "%u", this->port);
out.append(buffer);
out.append("\n");
out.append(" error: ");
out.append(YESNO(this->error));
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantEventData::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->name = value.as_string();
return true;
}
case 2: {
this->value = value.as_string();
return true;
}
default:
return false;
}
}
void VoiceAssistantEventData::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->name);
buffer.encode_string(2, this->value);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantEventData::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantEventData {\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" value: ");
out.append("'").append(this->value).append("'");
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->event_type = value.as_enum<enums::VoiceAssistantEvent>();
return true;
}
default:
return false;
}
}
bool VoiceAssistantEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
this->data.push_back(value.as_message<VoiceAssistantEventData>());
return true;
}
default:
return false;
}
}
void VoiceAssistantEventResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_enum<enums::VoiceAssistantEvent>(1, this->event_type);
for (auto &it : this->data) {
buffer.encode_message<VoiceAssistantEventData>(2, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantEventResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantEventResponse {\n");
out.append(" event_type: ");
out.append(proto_enum_to_string<enums::VoiceAssistantEvent>(this->event_type));
out.append("\n");
for (const auto &it : this->data) {
out.append(" data: ");
it.dump_to(out);
out.append("\n");
}
out.append("}");
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -163,6 +163,18 @@ enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6,
};
enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_ERROR = 0,
VOICE_ASSISTANT_RUN_START = 1,
VOICE_ASSISTANT_RUN_END = 2,
VOICE_ASSISTANT_STT_START = 3,
VOICE_ASSISTANT_STT_END = 4,
VOICE_ASSISTANT_INTENT_START = 5,
VOICE_ASSISTANT_INTENT_END = 6,
VOICE_ASSISTANT_TTS_START = 7,
VOICE_ASSISTANT_TTS_END = 8,
};
} // namespace enums
@@ -278,6 +290,7 @@ class DeviceInfoResponse : public ProtoMessage {
uint32_t bluetooth_proxy_version{0};
std::string manufacturer{};
std::string friendly_name{};
uint32_t voice_assistant_version{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -362,6 +375,7 @@ class ListEntitiesCoverResponse : public ProtoMessage {
bool disabled_by_default{false};
std::string icon{};
enums::EntityCategory entity_category{};
bool supports_stop{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -915,7 +929,7 @@ class ListEntitiesClimateResponse : public ProtoMessage {
std::vector<enums::ClimateMode> supported_modes{};
float visual_min_temperature{0.0f};
float visual_max_temperature{0.0f};
float visual_temperature_step{0.0f};
float visual_target_temperature_step{0.0f};
bool legacy_supports_away{false};
bool supports_action{false};
std::vector<enums::ClimateFanMode> supported_fan_modes{};
@@ -926,6 +940,7 @@ class ListEntitiesClimateResponse : public ProtoMessage {
bool disabled_by_default{false};
std::string icon{};
enums::EntityCategory entity_category{};
float visual_current_temperature_step{0.0f};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -944,7 +959,7 @@ class ClimateStateResponse : public ProtoMessage {
float target_temperature{0.0f};
float target_temperature_low{0.0f};
float target_temperature_high{0.0f};
bool legacy_away{false};
bool unused_legacy_away{false};
enums::ClimateAction action{};
enums::ClimateFanMode fan_mode{};
enums::ClimateSwingMode swing_mode{};
@@ -972,8 +987,8 @@ class ClimateCommandRequest : public ProtoMessage {
float target_temperature_low{0.0f};
bool has_target_temperature_high{false};
float target_temperature_high{0.0f};
bool has_legacy_away{false};
bool legacy_away{false};
bool unused_has_legacy_away{false};
bool unused_legacy_away{false};
bool has_fan_mode{false};
enums::ClimateFanMode fan_mode{};
bool has_swing_mode{false};
@@ -1527,6 +1542,113 @@ class BluetoothGATTNotifyResponse : public ProtoMessage {
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothDevicePairingResponse : public ProtoMessage {
public:
uint64_t address{0};
bool paired{false};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothDeviceUnpairingResponse : public ProtoMessage {
public:
uint64_t address{0};
bool success{false};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
public:
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class BluetoothDeviceClearCacheResponse : public ProtoMessage {
public:
uint64_t address{0};
bool success{false};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class SubscribeVoiceAssistantRequest : public ProtoMessage {
public:
bool subscribe{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantRequest : public ProtoMessage {
public:
bool start{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantResponse : public ProtoMessage {
public:
uint32_t port{0};
bool error{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantEventData : public ProtoMessage {
public:
std::string name{};
std::string value{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class VoiceAssistantEventResponse : public ProtoMessage {
public:
enums::VoiceAssistantEvent event_type{};
std::vector<VoiceAssistantEventData> data{};
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;
};
} // namespace api
} // namespace esphome

View File

@@ -329,6 +329,8 @@ bool APIServerConnectionBase::send_media_player_state_response(const MediaPlayer
#ifdef USE_MEDIA_PLAYER
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_le_advertisement_response: %s", msg.dump().c_str());
@@ -425,6 +427,46 @@ bool APIServerConnectionBase::send_bluetooth_gatt_notify_response(const Bluetoot
return this->send_message_<BluetoothGATTNotifyResponse>(msg, 84);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_device_pairing_response(const BluetoothDevicePairingResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_device_pairing_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothDevicePairingResponse>(msg, 85);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_device_unpairing_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothDeviceUnpairingResponse>(msg, 86);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_device_clear_cache_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothDeviceClearCacheResponse>(msg, 88);
}
#endif
#ifdef USE_VOICE_ASSISTANT
#endif
#ifdef USE_VOICE_ASSISTANT
bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantRequest &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_voice_assistant_request: %s", msg.dump().c_str());
#endif
return this->send_message_<VoiceAssistantRequest>(msg, 90);
}
#endif
#ifdef USE_VOICE_ASSISTANT
#endif
#ifdef USE_VOICE_ASSISTANT
#endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) {
case 1: {
@@ -693,12 +735,14 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
break;
}
case 66: {
#ifdef USE_BLUETOOTH_PROXY
SubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_le_advertisements_request(msg);
#endif
break;
}
case 68: {
@@ -786,6 +830,50 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_connections_free_request(msg);
#endif
break;
}
case 87: {
#ifdef USE_BLUETOOTH_PROXY
UnsubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif
this->on_unsubscribe_bluetooth_le_advertisements_request(msg);
#endif
break;
}
case 89: {
#ifdef USE_VOICE_ASSISTANT
SubscribeVoiceAssistantRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_voice_assistant_request(msg);
#endif
break;
}
case 91: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_response(msg);
#endif
break;
}
case 92: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantEventResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_event_response(msg);
#endif
break;
}
@@ -1049,6 +1137,7 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma
this->media_player_command(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {
if (!this->is_connection_setup()) {
@@ -1061,6 +1150,7 @@ void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
}
this->subscribe_bluetooth_le_advertisements(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) {
if (!this->is_connection_setup()) {
@@ -1169,6 +1259,33 @@ void APIServerConnection::on_subscribe_bluetooth_connections_free_request(
}
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->unsubscribe_bluetooth_le_advertisements(msg);
}
#endif
#ifdef USE_VOICE_ASSISTANT
void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->subscribe_voice_assistant(msg);
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -154,8 +154,10 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_MEDIA_PLAYER
virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg);
#endif
@@ -209,6 +211,31 @@ class APIServerConnectionBase : public ProtoService {
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_device_pairing_response(const BluetoothDevicePairingResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg);
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &value){};
#endif
#ifdef USE_VOICE_ASSISTANT
bool send_voice_assistant_request(const VoiceAssistantRequest &msg);
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_response(const VoiceAssistantResponse &value){};
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){};
#endif
protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
@@ -261,7 +288,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_MEDIA_PLAYER
virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_device_request(const BluetoothDeviceRequest &msg) = 0;
#endif
@@ -286,6 +315,12 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BLUETOOTH_PROXY
virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free(
const SubscribeBluetoothConnectionsFreeRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0;
#endif
protected:
void on_hello_request(const HelloRequest &msg) override;
@@ -333,7 +368,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_MEDIA_PLAYER
void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
#endif
@@ -358,6 +395,13 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif
#ifdef USE_VOICE_ASSISTANT
void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override;
#endif
};
} // namespace api

View File

@@ -45,7 +45,7 @@ void APIServer::setup() {
struct sockaddr_storage server;
socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_));
socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_);
if (sl == 0) {
ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
this->mark_failed();
@@ -309,6 +309,39 @@ void APIServer::send_bluetooth_device_connection(uint64_t address, bool connecte
}
}
void APIServer::send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error) {
BluetoothDevicePairingResponse call;
call.address = address;
call.paired = paired;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_pairing_response(call);
}
}
void APIServer::send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error) {
BluetoothDeviceUnpairingResponse call;
call.address = address;
call.success = success;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_unpairing_response(call);
}
}
void APIServer::send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error) {
BluetoothDeviceClearCacheResponse call;
call.address = address;
call.success = success;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_clear_cache_response(call);
}
}
void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) {
BluetoothConnectionsFreeResponse call;
call.free = free;
@@ -394,5 +427,21 @@ void APIServer::on_shutdown() {
delay(10);
}
#ifdef USE_VOICE_ASSISTANT
bool APIServer::start_voice_assistant() {
for (auto &c : this->clients_) {
if (c->request_voice_assistant(true))
return true;
}
return false;
}
void APIServer::stop_voice_assistant() {
for (auto &c : this->clients_) {
if (c->request_voice_assistant(false))
return;
}
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -78,6 +78,9 @@ class APIServer : public Component, public Controller {
#ifdef USE_BLUETOOTH_PROXY
void send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call);
void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK);
void send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK);
void send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK);
void send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK);
void send_bluetooth_connections_free(uint8_t free, uint8_t limit);
void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call);
void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call);
@@ -92,6 +95,11 @@ class APIServer : public Component, public Controller {
void request_time();
#endif
#ifdef USE_VOICE_ASSISTANT
bool start_voice_assistant();
void stop_voice_assistant();
#endif
bool is_connected() const;
struct HomeAssistantStateSubscription {

View File

@@ -1,4 +1,5 @@
#include "proto.h"
#include <cinttypes>
#include "esphome/core/log.h"
namespace esphome {
@@ -13,7 +14,7 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
uint32_t consumed;
auto res = ProtoVarInt::parse(&buffer[i], length - i, &consumed);
if (!res.has_value()) {
ESP_LOGV(TAG, "Invalid field start at %u", i);
ESP_LOGV(TAG, "Invalid field start at %" PRIu32, i);
break;
}
@@ -25,12 +26,12 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
case 0: { // VarInt
res = ProtoVarInt::parse(&buffer[i], length - i, &consumed);
if (!res.has_value()) {
ESP_LOGV(TAG, "Invalid VarInt at %u", i);
ESP_LOGV(TAG, "Invalid VarInt at %" PRIu32, i);
error = true;
break;
}
if (!this->decode_varint(field_id, *res)) {
ESP_LOGV(TAG, "Cannot decode VarInt field %u with value %u!", field_id, res->as_uint32());
ESP_LOGV(TAG, "Cannot decode VarInt field %" PRIu32 " with value %" PRIu32 "!", field_id, res->as_uint32());
}
i += consumed;
break;
@@ -38,38 +39,38 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
case 2: { // Length-delimited
res = ProtoVarInt::parse(&buffer[i], length - i, &consumed);
if (!res.has_value()) {
ESP_LOGV(TAG, "Invalid Length Delimited at %u", i);
ESP_LOGV(TAG, "Invalid Length Delimited at %" PRIu32, i);
error = true;
break;
}
uint32_t field_length = res->as_uint32();
i += consumed;
if (field_length > length - i) {
ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %u", i);
ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %" PRIu32, i);
error = true;
break;
}
if (!this->decode_length(field_id, ProtoLengthDelimited(&buffer[i], field_length))) {
ESP_LOGV(TAG, "Cannot decode Length Delimited field %u!", field_id);
ESP_LOGV(TAG, "Cannot decode Length Delimited field %" PRIu32 "!", field_id);
}
i += field_length;
break;
}
case 5: { // 32-bit
if (length - i < 4) {
ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %u", i);
ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %" PRIu32, i);
error = true;
break;
}
uint32_t val = encode_uint32(buffer[i + 3], buffer[i + 2], buffer[i + 1], buffer[i]);
if (!this->decode_32bit(field_id, Proto32Bit(val))) {
ESP_LOGV(TAG, "Cannot decode 32-bit field %u with value %u!", field_id, val);
ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32 " with value %" PRIu32 "!", field_id, val);
}
i += 4;
break;
}
default:
ESP_LOGV(TAG, "Invalid field type at %u", i);
ESP_LOGV(TAG, "Invalid field type at %" PRIu32, i);
error = true;
break;
}

View File

@@ -12,7 +12,6 @@ from esphome.const import (
CONF_CAPACITANCE,
)
AUTO_LOAD = ["sensor", "binary_sensor"]
MULTI_CONF = True
CONF_AS3935_ID = "as3935_id"

View File

@@ -26,9 +26,13 @@ void AS3935Component::setup() {
void AS3935Component::dump_config() {
ESP_LOGCONFIG(TAG, "AS3935:");
LOG_PIN(" Interrupt Pin: ", this->irq_pin_);
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "Thunder alert", this->thunder_alert_binary_sensor_);
#endif
#ifdef USE_SENSOR
LOG_SENSOR(" ", "Distance", this->distance_sensor_);
LOG_SENSOR(" ", "Lightning energy", this->energy_sensor_);
#endif
}
float AS3935Component::get_setup_priority() const { return setup_priority::DATA; }
@@ -44,16 +48,22 @@ void AS3935Component::loop() {
ESP_LOGI(TAG, "Disturber was detected - try increasing the spike rejection value!");
} else if (int_value == LIGHTNING_INT) {
ESP_LOGI(TAG, "Lightning has been detected!");
if (this->thunder_alert_binary_sensor_ != nullptr)
#ifdef USE_BINARY_SENSOR
if (this->thunder_alert_binary_sensor_ != nullptr) {
this->thunder_alert_binary_sensor_->publish_state(true);
this->set_timeout(10, [this]() { this->thunder_alert_binary_sensor_->publish_state(false); });
}
#endif
#ifdef USE_SENSOR
uint8_t distance = this->get_distance_to_storm_();
if (this->distance_sensor_ != nullptr)
this->distance_sensor_->publish_state(distance);
uint32_t energy = this->get_lightning_energy_();
if (this->energy_sensor_ != nullptr)
this->energy_sensor_->publish_state(energy);
#endif
}
this->thunder_alert_binary_sensor_->publish_state(false);
}
void AS3935Component::write_indoor(bool indoor) {

View File

@@ -1,9 +1,14 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
namespace esphome {
namespace as3935 {
@@ -52,6 +57,15 @@ enum AS3935Values {
};
class AS3935Component : public Component {
#ifdef USE_SENSOR
SUB_SENSOR(distance)
SUB_SENSOR(energy)
#endif
#ifdef USE_BINARY_SENSOR
SUB_BINARY_SENSOR(thunder_alert)
#endif
public:
void setup() override;
void dump_config() override;
@@ -59,11 +73,7 @@ class AS3935Component : public Component {
void loop() override;
void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; }
void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) {
thunder_alert_binary_sensor_ = thunder_alert_binary_sensor;
}
void set_indoor(bool indoor) { indoor_ = indoor; }
void write_indoor(bool indoor);
void set_noise_level(uint8_t noise_level) { noise_level_ = noise_level; }
@@ -92,9 +102,6 @@ class AS3935Component : public Component {
virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0;
sensor::Sensor *distance_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
binary_sensor::BinarySensor *thunder_alert_binary_sensor_{nullptr};
GPIOPin *irq_pin_;
bool indoor_;

View File

View File

@@ -0,0 +1,271 @@
#include "as7341.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace as7341 {
static const char *const TAG = "as7341";
void AS7341Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up AS7341...");
LOG_I2C_DEVICE(this);
// Verify device ID
uint8_t id;
this->read_byte(AS7341_ID, &id);
ESP_LOGCONFIG(TAG, " Read ID: 0x%X", id);
if ((id & 0xFC) != (AS7341_CHIP_ID << 2)) {
this->mark_failed();
return;
}
// Power on (enter IDLE state)
if (!this->enable_power(true)) {
ESP_LOGE(TAG, " Power on failed!");
this->mark_failed();
return;
}
// Set configuration
this->write_byte(AS7341_CONFIG, 0x00);
this->setup_atime(this->atime_);
this->setup_astep(this->astep_);
this->setup_gain(this->gain_);
}
void AS7341Component::dump_config() {
ESP_LOGCONFIG(TAG, "AS7341:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with AS7341 failed!");
}
LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG, " Gain: %u", get_gain());
ESP_LOGCONFIG(TAG, " ATIME: %u", get_atime());
ESP_LOGCONFIG(TAG, " ASTEP: %u", get_astep());
LOG_SENSOR(" ", "F1", this->f1_);
LOG_SENSOR(" ", "F2", this->f2_);
LOG_SENSOR(" ", "F3", this->f3_);
LOG_SENSOR(" ", "F4", this->f4_);
LOG_SENSOR(" ", "F5", this->f5_);
LOG_SENSOR(" ", "F6", this->f6_);
LOG_SENSOR(" ", "F7", this->f7_);
LOG_SENSOR(" ", "F8", this->f8_);
LOG_SENSOR(" ", "Clear", this->clear_);
LOG_SENSOR(" ", "NIR", this->nir_);
}
float AS7341Component::get_setup_priority() const { return setup_priority::DATA; }
void AS7341Component::update() {
this->read_channels(this->channel_readings_);
if (this->f1_ != nullptr) {
this->f1_->publish_state(this->channel_readings_[0]);
}
if (this->f2_ != nullptr) {
this->f2_->publish_state(this->channel_readings_[1]);
}
if (this->f3_ != nullptr) {
this->f3_->publish_state(this->channel_readings_[2]);
}
if (this->f4_ != nullptr) {
this->f4_->publish_state(this->channel_readings_[3]);
}
if (this->f5_ != nullptr) {
this->f5_->publish_state(this->channel_readings_[6]);
}
if (this->f6_ != nullptr) {
this->f6_->publish_state(this->channel_readings_[7]);
}
if (this->f7_ != nullptr) {
this->f7_->publish_state(this->channel_readings_[8]);
}
if (this->f8_ != nullptr) {
this->f8_->publish_state(this->channel_readings_[9]);
}
if (this->clear_ != nullptr) {
this->clear_->publish_state(this->channel_readings_[10]);
}
if (this->nir_ != nullptr) {
this->nir_->publish_state(this->channel_readings_[11]);
}
}
AS7341Gain AS7341Component::get_gain() {
uint8_t data;
this->read_byte(AS7341_CFG1, &data);
return (AS7341Gain) data;
}
uint8_t AS7341Component::get_atime() {
uint8_t data;
this->read_byte(AS7341_ATIME, &data);
return data;
}
uint16_t AS7341Component::get_astep() {
uint16_t data;
this->read_byte_16(AS7341_ASTEP, &data);
return this->swap_bytes(data);
}
bool AS7341Component::setup_gain(AS7341Gain gain) { return this->write_byte(AS7341_CFG1, gain); }
bool AS7341Component::setup_atime(uint8_t atime) { return this->write_byte(AS7341_ATIME, atime); }
bool AS7341Component::setup_astep(uint16_t astep) { return this->write_byte_16(AS7341_ASTEP, swap_bytes(astep)); }
bool AS7341Component::read_channels(uint16_t *data) {
this->set_smux_low_channels(true);
this->enable_spectral_measurement(true);
this->wait_for_data();
bool low_success = this->read_bytes_16(AS7341_CH0_DATA_L, data, 6);
this->set_smux_low_channels(false);
this->enable_spectral_measurement(true);
this->wait_for_data();
bool high_sucess = this->read_bytes_16(AS7341_CH0_DATA_L, &data[6], 6);
return low_success && high_sucess;
}
void AS7341Component::set_smux_low_channels(bool enable) {
this->enable_spectral_measurement(false);
this->set_smux_command(AS7341_SMUX_CMD_WRITE);
if (enable) {
this->configure_smux_low_channels();
} else {
this->configure_smux_high_channels();
}
this->enable_smux();
}
bool AS7341Component::set_smux_command(AS7341SmuxCommand command) {
uint8_t data = command << 3; // Write to bits 4:3 of the register
return this->write_byte(AS7341_CFG6, data);
}
void AS7341Component::configure_smux_low_channels() {
// SMUX Config for F1,F2,F3,F4,NIR,Clear
this->write_byte(0x00, 0x30); // F3 left set to ADC2
this->write_byte(0x01, 0x01); // F1 left set to ADC0
this->write_byte(0x02, 0x00); // Reserved or disabled
this->write_byte(0x03, 0x00); // F8 left disabled
this->write_byte(0x04, 0x00); // F6 left disabled
this->write_byte(0x05, 0x42); // F4 left connected to ADC3/f2 left connected to ADC1
this->write_byte(0x06, 0x00); // F5 left disbled
this->write_byte(0x07, 0x00); // F7 left disbled
this->write_byte(0x08, 0x50); // CLEAR connected to ADC4
this->write_byte(0x09, 0x00); // F5 right disabled
this->write_byte(0x0A, 0x00); // F7 right disabled
this->write_byte(0x0B, 0x00); // Reserved or disabled
this->write_byte(0x0C, 0x20); // F2 right connected to ADC1
this->write_byte(0x0D, 0x04); // F4 right connected to ADC3
this->write_byte(0x0E, 0x00); // F6/F8 right disabled
this->write_byte(0x0F, 0x30); // F3 right connected to AD2
this->write_byte(0x10, 0x01); // F1 right connected to AD0
this->write_byte(0x11, 0x50); // CLEAR right connected to AD4
this->write_byte(0x12, 0x00); // Reserved or disabled
this->write_byte(0x13, 0x06); // NIR connected to ADC5
}
void AS7341Component::configure_smux_high_channels() {
// SMUX Config for F5,F6,F7,F8,NIR,Clear
this->write_byte(0x00, 0x00); // F3 left disable
this->write_byte(0x01, 0x00); // F1 left disable
this->write_byte(0x02, 0x00); // reserved/disable
this->write_byte(0x03, 0x40); // F8 left connected to ADC3
this->write_byte(0x04, 0x02); // F6 left connected to ADC1
this->write_byte(0x05, 0x00); // F4/ F2 disabled
this->write_byte(0x06, 0x10); // F5 left connected to ADC0
this->write_byte(0x07, 0x03); // F7 left connected to ADC2
this->write_byte(0x08, 0x50); // CLEAR Connected to ADC4
this->write_byte(0x09, 0x10); // F5 right connected to ADC0
this->write_byte(0x0A, 0x03); // F7 right connected to ADC2
this->write_byte(0x0B, 0x00); // Reserved or disabled
this->write_byte(0x0C, 0x00); // F2 right disabled
this->write_byte(0x0D, 0x00); // F4 right disabled
this->write_byte(0x0E, 0x24); // F8 right connected to ADC2/ F6 right connected to ADC1
this->write_byte(0x0F, 0x00); // F3 right disabled
this->write_byte(0x10, 0x00); // F1 right disabled
this->write_byte(0x11, 0x50); // CLEAR right connected to AD4
this->write_byte(0x12, 0x00); // Reserved or disabled
this->write_byte(0x13, 0x06); // NIR connected to ADC5
}
bool AS7341Component::enable_smux() {
this->set_register_bit(AS7341_ENABLE, 4);
uint16_t timeout = 1000;
for (uint16_t time = 0; time < timeout; time++) {
// The SMUXEN bit is cleared once the SMUX operation is finished
bool smuxen = this->read_register_bit(AS7341_ENABLE, 4);
if (!smuxen) {
return true;
}
delay(1);
}
return false;
}
bool AS7341Component::wait_for_data() {
uint16_t timeout = 1000;
for (uint16_t time = 0; time < timeout; time++) {
if (this->is_data_ready()) {
return true;
}
delay(1);
}
return false;
}
bool AS7341Component::is_data_ready() { return this->read_register_bit(AS7341_STATUS2, 6); }
bool AS7341Component::enable_power(bool enable) { return this->write_register_bit(AS7341_ENABLE, enable, 0); }
bool AS7341Component::enable_spectral_measurement(bool enable) {
return this->write_register_bit(AS7341_ENABLE, enable, 1);
}
bool AS7341Component::read_register_bit(uint8_t address, uint8_t bit_position) {
uint8_t data;
this->read_byte(address, &data);
bool bit = (data & (1 << bit_position)) > 0;
return bit;
}
bool AS7341Component::write_register_bit(uint8_t address, bool value, uint8_t bit_position) {
if (value) {
return this->set_register_bit(address, bit_position);
}
return this->clear_register_bit(address, bit_position);
}
bool AS7341Component::set_register_bit(uint8_t address, uint8_t bit_position) {
uint8_t data;
this->read_byte(address, &data);
data |= (1 << bit_position);
return this->write_byte(address, data);
}
bool AS7341Component::clear_register_bit(uint8_t address, uint8_t bit_position) {
uint8_t data;
this->read_byte(address, &data);
data &= ~(1 << bit_position);
return this->write_byte(address, data);
}
uint16_t AS7341Component::swap_bytes(uint16_t data) { return (data >> 8) | (data << 8); }
} // namespace as7341
} // namespace esphome

View File

@@ -0,0 +1,144 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace as7341 {
static const uint8_t AS7341_CHIP_ID = 0X09;
static const uint8_t AS7341_CONFIG = 0x70;
static const uint8_t AS7341_LED = 0x74;
static const uint8_t AS7341_ENABLE = 0x80;
static const uint8_t AS7341_ATIME = 0x81;
static const uint8_t AS7341_WTIME = 0x83;
static const uint8_t AS7341_AUXID = 0x90;
static const uint8_t AS7341_REVID = 0x91;
static const uint8_t AS7341_ID = 0x92;
static const uint8_t AS7341_STATUS = 0x93;
static const uint8_t AS7341_CH0_DATA_L = 0x95;
static const uint8_t AS7341_CH0_DATA_H = 0x96;
static const uint8_t AS7341_CH1_DATA_L = 0x97;
static const uint8_t AS7341_CH1_DATA_H = 0x98;
static const uint8_t AS7341_CH2_DATA_L = 0x99;
static const uint8_t AS7341_CH2_DATA_H = 0x9A;
static const uint8_t AS7341_CH3_DATA_L = 0x9B;
static const uint8_t AS7341_CH3_DATA_H = 0x9C;
static const uint8_t AS7341_CH4_DATA_L = 0x9D;
static const uint8_t AS7341_CH4_DATA_H = 0x9E;
static const uint8_t AS7341_CH5_DATA_L = 0x9F;
static const uint8_t AS7341_CH5_DATA_H = 0xA0;
static const uint8_t AS7341_STATUS2 = 0xA3;
static const uint8_t AS7341_CFG1 = 0xAA; ///< Controls ADC Gain
static const uint8_t AS7341_CFG6 = 0xAF; // Stores SMUX command
static const uint8_t AS7341_CFG9 = 0xB2; // Config for system interrupts (SMUX, Flicker detection)
static const uint8_t AS7341_ASTEP = 0xCA; // LSB
static const uint8_t AS7341_ASTEP_MSB = 0xCB; // MSB
enum AS7341AdcChannel {
AS7341_ADC_CHANNEL_0,
AS7341_ADC_CHANNEL_1,
AS7341_ADC_CHANNEL_2,
AS7341_ADC_CHANNEL_3,
AS7341_ADC_CHANNEL_4,
AS7341_ADC_CHANNEL_5,
};
enum AS7341SmuxCommand {
AS7341_SMUX_CMD_ROM_RESET, ///< ROM code initialization of SMUX
AS7341_SMUX_CMD_READ, ///< Read SMUX configuration to RAM from SMUX chain
AS7341_SMUX_CMD_WRITE, ///< Write SMUX configuration from RAM to SMUX chain
};
enum AS7341Gain {
AS7341_GAIN_0_5X,
AS7341_GAIN_1X,
AS7341_GAIN_2X,
AS7341_GAIN_4X,
AS7341_GAIN_8X,
AS7341_GAIN_16X,
AS7341_GAIN_32X,
AS7341_GAIN_64X,
AS7341_GAIN_128X,
AS7341_GAIN_256X,
AS7341_GAIN_512X,
};
class AS7341Component : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void update() override;
void set_f1_sensor(sensor::Sensor *f1_sensor) { this->f1_ = f1_sensor; }
void set_f2_sensor(sensor::Sensor *f2_sensor) { f2_ = f2_sensor; }
void set_f3_sensor(sensor::Sensor *f3_sensor) { f3_ = f3_sensor; }
void set_f4_sensor(sensor::Sensor *f4_sensor) { f4_ = f4_sensor; }
void set_f5_sensor(sensor::Sensor *f5_sensor) { f5_ = f5_sensor; }
void set_f6_sensor(sensor::Sensor *f6_sensor) { f6_ = f6_sensor; }
void set_f7_sensor(sensor::Sensor *f7_sensor) { f7_ = f7_sensor; }
void set_f8_sensor(sensor::Sensor *f8_sensor) { f8_ = f8_sensor; }
void set_clear_sensor(sensor::Sensor *clear_sensor) { clear_ = clear_sensor; }
void set_nir_sensor(sensor::Sensor *nir_sensor) { nir_ = nir_sensor; }
void set_gain(AS7341Gain gain) { gain_ = gain; }
void set_atime(uint8_t atime) { atime_ = atime; }
void set_astep(uint16_t astep) { astep_ = astep; }
AS7341Gain get_gain();
uint8_t get_atime();
uint16_t get_astep();
bool setup_gain(AS7341Gain gain);
bool setup_atime(uint8_t atime);
bool setup_astep(uint16_t astep);
uint16_t read_channel(AS7341AdcChannel channel);
bool read_channels(uint16_t *data);
void set_smux_low_channels(bool enable);
bool set_smux_command(AS7341SmuxCommand command);
void configure_smux_low_channels();
void configure_smux_high_channels();
bool enable_smux();
bool wait_for_data();
bool is_data_ready();
bool enable_power(bool enable);
bool enable_spectral_measurement(bool enable);
bool read_register_bit(uint8_t address, uint8_t bit_position);
bool write_register_bit(uint8_t address, bool value, uint8_t bit_position);
bool set_register_bit(uint8_t address, uint8_t bit_position);
bool clear_register_bit(uint8_t address, uint8_t bit_position);
uint16_t swap_bytes(uint16_t data);
protected:
sensor::Sensor *f1_{nullptr};
sensor::Sensor *f2_{nullptr};
sensor::Sensor *f3_{nullptr};
sensor::Sensor *f4_{nullptr};
sensor::Sensor *f5_{nullptr};
sensor::Sensor *f6_{nullptr};
sensor::Sensor *f7_{nullptr};
sensor::Sensor *f8_{nullptr};
sensor::Sensor *clear_{nullptr};
sensor::Sensor *nir_{nullptr};
uint16_t astep_;
AS7341Gain gain_;
uint8_t atime_;
uint16_t channel_readings_[12];
};
} // namespace as7341
} // namespace esphome

View File

@@ -0,0 +1,112 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_GAIN,
CONF_ID,
DEVICE_CLASS_ILLUMINANCE,
ICON_BRIGHTNESS_5,
STATE_CLASS_MEASUREMENT,
)
CODEOWNERS = ["@mrgnr"]
DEPENDENCIES = ["i2c"]
as7341_ns = cg.esphome_ns.namespace("as7341")
AS7341Component = as7341_ns.class_(
"AS7341Component", cg.PollingComponent, i2c.I2CDevice
)
CONF_ATIME = "atime"
CONF_ASTEP = "astep"
CONF_F1 = "f1"
CONF_F2 = "f2"
CONF_F3 = "f3"
CONF_F4 = "f4"
CONF_F5 = "f5"
CONF_F6 = "f6"
CONF_F7 = "f7"
CONF_F8 = "f8"
CONF_CLEAR = "clear"
CONF_NIR = "nir"
UNIT_COUNTS = "#"
AS7341_GAIN = as7341_ns.enum("AS7341Gain")
GAIN_OPTIONS = {
"X0.5": AS7341_GAIN.AS7341_GAIN_0_5X,
"X1": AS7341_GAIN.AS7341_GAIN_1X,
"X2": AS7341_GAIN.AS7341_GAIN_2X,
"X4": AS7341_GAIN.AS7341_GAIN_4X,
"X8": AS7341_GAIN.AS7341_GAIN_8X,
"X16": AS7341_GAIN.AS7341_GAIN_16X,
"X32": AS7341_GAIN.AS7341_GAIN_32X,
"X64": AS7341_GAIN.AS7341_GAIN_64X,
"X128": AS7341_GAIN.AS7341_GAIN_128X,
"X256": AS7341_GAIN.AS7341_GAIN_256X,
"X512": AS7341_GAIN.AS7341_GAIN_512X,
}
SENSOR_SCHEMA = sensor.sensor_schema(
unit_of_measurement=UNIT_COUNTS,
icon=ICON_BRIGHTNESS_5,
accuracy_decimals=0,
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(AS7341Component),
cv.Optional(CONF_F1): SENSOR_SCHEMA,
cv.Optional(CONF_F2): SENSOR_SCHEMA,
cv.Optional(CONF_F3): SENSOR_SCHEMA,
cv.Optional(CONF_F4): SENSOR_SCHEMA,
cv.Optional(CONF_F5): SENSOR_SCHEMA,
cv.Optional(CONF_F6): SENSOR_SCHEMA,
cv.Optional(CONF_F7): SENSOR_SCHEMA,
cv.Optional(CONF_F8): SENSOR_SCHEMA,
cv.Optional(CONF_CLEAR): SENSOR_SCHEMA,
cv.Optional(CONF_NIR): SENSOR_SCHEMA,
cv.Optional(CONF_GAIN, default="X8"): cv.enum(GAIN_OPTIONS),
cv.Optional(CONF_ATIME, default=29): cv.int_range(min=0, max=255),
cv.Optional(CONF_ASTEP, default=599): cv.int_range(min=0, max=65534),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x39))
)
SENSORS = {
CONF_F1: "set_f1_sensor",
CONF_F2: "set_f2_sensor",
CONF_F3: "set_f3_sensor",
CONF_F4: "set_f4_sensor",
CONF_F5: "set_f5_sensor",
CONF_F6: "set_f6_sensor",
CONF_F7: "set_f7_sensor",
CONF_F8: "set_f8_sensor",
CONF_CLEAR: "set_clear_sensor",
CONF_NIR: "set_nir_sensor",
}
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)
cg.add(var.set_gain(config[CONF_GAIN]))
cg.add(var.set_atime(config[CONF_ATIME]))
cg.add(var.set_astep(config[CONF_ASTEP]))
for conf_id, set_sensor_func in SENSORS.items():
if conf_id in config:
sens = await sensor.new_sensor(config[conf_id])
cg.add(getattr(var, set_sensor_func)(sens))

View File

@@ -18,5 +18,5 @@ async def to_code(config):
# https://github.com/esphome/AsyncTCP/blob/master/library.json
cg.add_library("esphome/AsyncTCP-esphome", "1.2.2")
elif CORE.is_esp8266:
# https://github.com/OttoWinter/ESPAsyncTCP
cg.add_library("ottowinter/ESPAsyncTCP-esphome", "1.2.3")
# https://github.com/esphome/ESPAsyncTCP
cg.add_library("esphome/ESPAsyncTCP-esphome", "1.2.3")

View File

@@ -80,7 +80,7 @@ async def to_code(config):
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
for (config_key, setter) in [
for config_key, setter in [
(CONF_TEMPERATURE, var.set_temperature),
(CONF_HUMIDITY, var.set_humidity),
(CONF_BATTERY_VOLTAGE, var.set_battery_voltage),

View File

@@ -1,3 +1,5 @@
#ifdef USE_ESP32
#include "bedjet_hub.h"
#include "bedjet_child.h"
#include "bedjet_const.h"
@@ -541,3 +543,5 @@ void BedJetHub::register_child(BedJetClient *obj) {
} // namespace bedjet
} // namespace esphome
#endif

View File

@@ -1,4 +1,5 @@
#pragma once
#ifdef USE_ESP32
#include "esphome/components/ble_client/ble_client.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
@@ -14,8 +15,6 @@
#include "esphome/components/time/real_time_clock.h"
#endif
#ifdef USE_ESP32
#include <esp_gattc_api.h>
namespace esphome {
@@ -117,7 +116,7 @@ class BedJetHub : public esphome::ble_client::BLEClientNode, public PollingCompo
void update() override;
void dump_config() override;
void setup() override { this->codec_ = make_unique<BedjetCodec>(); }
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
float get_setup_priority() const override { return setup_priority::BLUETOOTH; }
/** @return The BedJet's configured name, or the MAC address if not discovered yet. */
std::string get_name() {

View File

@@ -27,13 +27,13 @@ from esphome.const import (
CONF_TIMING,
CONF_TRIGGER_ID,
CONF_MQTT_ID,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_BATTERY_CHARGING,
DEVICE_CLASS_CARBON_MONOXIDE,
DEVICE_CLASS_COLD,
DEVICE_CLASS_CONNECTIVITY,
DEVICE_CLASS_DOOR,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_GARAGE_DOOR,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HEAT,
@@ -62,13 +62,13 @@ from esphome.util import Registry
CODEOWNERS = ["@esphome/core"]
DEVICE_CLASSES = [
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_BATTERY_CHARGING,
DEVICE_CLASS_CARBON_MONOXIDE,
DEVICE_CLASS_COLD,
DEVICE_CLASS_CONNECTIVITY,
DEVICE_CLASS_DOOR,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_GARAGE_DOOR,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HEAT,
@@ -393,28 +393,21 @@ def binary_sensor_schema(
entity_category: str = _UNDEF,
device_class: str = _UNDEF,
) -> cv.Schema:
schema = BINARY_SENSOR_SCHEMA
schema = {}
if class_ is not _UNDEF:
schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
if icon is not _UNDEF:
schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
if entity_category is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_ENTITY_CATEGORY, default=entity_category
): cv.entity_category
}
)
if device_class is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_DEVICE_CLASS, default=device_class
): validate_device_class
}
)
return schema
# Not cv.optional
schema[cv.GenerateID()] = cv.declare_id(class_)
for key, default, validator in [
(CONF_ICON, icon, cv.icon),
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
(CONF_DEVICE_CLASS, device_class, validate_device_class),
]:
if default is not _UNDEF:
schema[cv.Optional(key, default=default)] = validator
return BINARY_SENSOR_SCHEMA.extend(schema)
async def setup_binary_sensor_core_(var, config):

View File

@@ -41,17 +41,9 @@ void BinarySensor::send_state_internal(bool state, bool is_initial) {
this->state_callback_.call(state);
}
}
std::string BinarySensor::device_class() { return ""; }
BinarySensor::BinarySensor() : state(false) {}
void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
std::string BinarySensor::get_device_class() {
if (this->device_class_.has_value())
return *this->device_class_;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return this->device_class();
#pragma GCC diagnostic pop
}
void BinarySensor::add_filter(Filter *filter) {
filter->parent_ = this;
if (this->filter_list_ == nullptr) {

View File

@@ -19,13 +19,22 @@ namespace binary_sensor {
} \
}
#define SUB_BINARY_SENSOR(name) \
protected: \
binary_sensor::BinarySensor *name##_binary_sensor_{nullptr}; \
\
public: \
void set_##name##_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { \
this->name##_binary_sensor_ = binary_sensor; \
}
/** Base class for all binary_sensor-type classes.
*
* This class includes a callback that components such as MQTT can subscribe to for state changes.
* The sub classes should notify the front-end of new states via the publish_state() method which
* handles inverted inputs for you.
*/
class BinarySensor : public EntityBase {
class BinarySensor : public EntityBase, public EntityBase_DeviceClass {
public:
explicit BinarySensor();
@@ -51,12 +60,6 @@ class BinarySensor : public EntityBase {
/// The current reported state of the binary sensor.
bool state;
/// Manually set the Home Assistant device class (see binary_sensor::device_class)
void set_device_class(const std::string &device_class);
/// Get the device class for this binary sensor, using the manual override if specified.
std::string get_device_class();
void add_filter(Filter *filter);
void add_filters(const std::vector<Filter *> &filters);
@@ -71,17 +74,8 @@ class BinarySensor : public EntityBase {
virtual bool is_status_binary_sensor() const;
// ========== OVERRIDE METHODS ==========
// (You'll only need this when creating your own custom binary sensor)
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
virtual std::string device_class();
protected:
CallbackManager<void(bool)> state_callback_{};
optional<std::string> device_class_{}; ///< Stores the override of the device class
Filter *filter_list_{nullptr};
bool has_state_{false};
bool publish_initial_state_{false};

View File

@@ -16,6 +16,9 @@ void BinarySensorMap::loop() {
case BINARY_SENSOR_MAP_TYPE_SUM:
this->process_sum_();
break;
case BINARY_SENSOR_MAP_TYPE_BAYESIAN:
this->process_bayesian_();
break;
}
}
@@ -23,69 +26,117 @@ void BinarySensorMap::process_group_() {
float total_current_value = 0.0;
uint8_t num_active_sensors = 0;
uint64_t mask = 0x00;
// check all binary_sensors for its state. when active add its value to total_current_value.
// create a bitmask for the binary_sensor status on all channels
// - check all binary_sensors for its state
// - if active, add its value to total_current_value.
// - creates a bitmask for the binary_sensor states on all channels
for (size_t i = 0; i < this->channels_.size(); i++) {
auto bs = this->channels_[i];
if (bs.binary_sensor->state) {
num_active_sensors++;
total_current_value += bs.sensor_value;
mask |= 1 << i;
total_current_value += bs.parameters.sensor_value;
mask |= 1ULL << i;
}
}
// check if the sensor map was touched
// potentially update state only if a binary_sensor is active
if (mask != 0ULL) {
// did the bit_mask change or is it a new sensor touch
// publish the average if the bitmask has changed
if (this->last_mask_ != mask) {
float publish_value = total_current_value / num_active_sensors;
ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value);
this->publish_state(publish_value);
}
} else if (this->last_mask_ != 0ULL) {
// is this a new sensor release
ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
// no buttons are pressed and the states have changed since last run, so publish NAN
ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
this->publish_state(NAN);
}
this->last_mask_ = mask;
}
void BinarySensorMap::process_sum_() {
float total_current_value = 0.0;
uint64_t mask = 0x00;
// check all binary_sensors for its state. when active add its value to total_current_value.
// create a bitmask for the binary_sensor status on all channels
// - check all binary_sensor states
// - if active, add its value to total_current_value
// - creates a bitmask for the binary_sensor states on all channels
for (size_t i = 0; i < this->channels_.size(); i++) {
auto bs = this->channels_[i];
if (bs.binary_sensor->state) {
total_current_value += bs.sensor_value;
mask |= 1 << i;
total_current_value += bs.parameters.sensor_value;
mask |= 1ULL << i;
}
}
// check if the sensor map was touched
if (mask != 0ULL) {
// did the bit_mask change or is it a new sensor touch
if (this->last_mask_ != mask) {
float publish_value = total_current_value;
ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value);
this->publish_state(publish_value);
}
} else if (this->last_mask_ != 0ULL) {
// is this a new sensor release
ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing 0", this->name_.c_str());
this->publish_state(0.0);
// update state only if any binary_sensor states have changed or if no state has ever been sent on boot
if ((this->last_mask_ != mask) || (!this->has_state())) {
this->publish_state(total_current_value);
}
this->last_mask_ = mask;
}
void BinarySensorMap::process_bayesian_() {
float posterior_probability = this->bayesian_prior_;
uint64_t mask = 0x00;
// - compute the posterior probability by taking the product of the predicate probablities for each observation
// - create a bitmask for the binary_sensor states on all channels/observations
for (size_t i = 0; i < this->channels_.size(); i++) {
auto bs = this->channels_[i];
posterior_probability *=
this->bayesian_predicate_(bs.binary_sensor->state, posterior_probability,
bs.parameters.probabilities.given_true, bs.parameters.probabilities.given_false);
mask |= ((uint64_t) (bs.binary_sensor->state)) << i;
}
// update state only if any binary_sensor states have changed or if no state has ever been sent on boot
if ((this->last_mask_ != mask) || (!this->has_state())) {
this->publish_state(posterior_probability);
}
this->last_mask_ = mask;
}
float BinarySensorMap::bayesian_predicate_(bool sensor_state, float prior, float prob_given_true,
float prob_given_false) {
float prob_state_source_true = prob_given_true;
float prob_state_source_false = prob_given_false;
// if sensor is off, then we use the probabilities for the observation's complement
if (!sensor_state) {
prob_state_source_true = 1 - prob_given_true;
prob_state_source_false = 1 - prob_given_false;
}
return prob_state_source_true / (prior * prob_state_source_true + (1.0 - prior) * prob_state_source_false);
}
void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float value) {
BinarySensorMapChannel sensor_channel{
.binary_sensor = sensor,
.sensor_value = value,
.parameters{
.sensor_value = value,
},
};
this->channels_.push_back(sensor_channel);
}
void BinarySensorMap::set_sensor_type(BinarySensorMapType sensor_type) { this->sensor_type_ = sensor_type; }
void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float prob_given_true, float prob_given_false) {
BinarySensorMapChannel sensor_channel{
.binary_sensor = sensor,
.parameters{
.probabilities{
.given_true = prob_given_true,
.given_false = prob_given_false,
},
},
};
this->channels_.push_back(sensor_channel);
}
} // namespace binary_sensor_map
} // namespace esphome

View File

@@ -12,51 +12,88 @@ namespace binary_sensor_map {
enum BinarySensorMapType {
BINARY_SENSOR_MAP_TYPE_GROUP,
BINARY_SENSOR_MAP_TYPE_SUM,
BINARY_SENSOR_MAP_TYPE_BAYESIAN,
};
struct BinarySensorMapChannel {
binary_sensor::BinarySensor *binary_sensor;
float sensor_value;
union {
float sensor_value;
struct {
float given_true;
float given_false;
} probabilities;
} parameters;
};
/** Class to group binary_sensors to one Sensor.
/** Class to map one or more binary_sensors to one Sensor.
*
* Each binary sensor represents a float value in the group.
* Each binary sensor has configured parameters that each mapping type uses to compute the single numerical result
*/
class BinarySensorMap : public sensor::Sensor, public Component {
public:
void dump_config() override;
/**
* The loop checks all binary_sensor states
* When the binary_sensor reports a true value for its state, then the float value it represents is added to the
* total_current_value
* The loop calls the configured type processing method
*
* Only when the total_current_value changed and at least one sensor reports an active state we publish the sensors
* average value. When the value changed and no sensors ar active we publish NAN.
* */
* The processing method loops through all sensors and calculates the numerical result
* The result is only published if a binary sensor state has changed or, for some types, on initial boot
*/
void loop() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/** Add binary_sensors to the group.
* Each binary_sensor represents a float value when its state is true
/**
* Add binary_sensors to the group when only one parameter is needed for the configured mapping type.
*
* @param *sensor The binary sensor.
* @param value The value this binary_sensor represents
*/
void add_channel(binary_sensor::BinarySensor *sensor, float value);
void set_sensor_type(BinarySensorMapType sensor_type);
/**
* Add binary_sensors to the group when two parameters are needed for the Bayesian mapping type.
*
* @param *sensor The binary sensor.
* @param prob_given_true Probability this observation is on when the Bayesian event is true
* @param prob_given_false Probability this observation is on when the Bayesian event is false
*/
void add_channel(binary_sensor::BinarySensor *sensor, float prob_given_true, float prob_given_false);
void set_sensor_type(BinarySensorMapType sensor_type) { this->sensor_type_ = sensor_type; }
void set_bayesian_prior(float prior) { this->bayesian_prior_ = prior; };
protected:
std::vector<BinarySensorMapChannel> channels_{};
BinarySensorMapType sensor_type_{BINARY_SENSOR_MAP_TYPE_GROUP};
// this gives max 64 channels per binary_sensor_map
// this allows a max of 64 channels/observations in order to keep track of binary_sensor states
uint64_t last_mask_{0x00};
// Bayesian event prior probability before taking into account any observations
float bayesian_prior_{};
/**
* methods to process the types of binary_sensor_maps
* GROUP: process_group_() just map to a value
* Methods to process the binary_sensor_maps types
*
* GROUP: process_group_() averages all the values
* ADD: process_add_() adds all the values
* BAYESIAN: process_bayesian_() computes the predicate probability
* */
void process_group_();
void process_sum_();
void process_bayesian_();
/**
* Computes the Bayesian predicate for a specific observation
* If the sensor state is false, then we use the parameters' probabilities for the observatiosn complement
*
* @param sensor_state State of observation
* @param prior Prior probability before accounting for this observation
* @param prob_given_true Probability this observation is on when the Bayesian event is true
* @param prob_given_false Probability this observation is on when the Bayesian event is false
* */
float bayesian_predicate_(bool sensor_state, float prior, float prob_given_true, float prob_given_false);
};
} // namespace binary_sensor_map

View File

@@ -20,16 +20,29 @@ BinarySensorMap = binary_sensor_map_ns.class_(
)
SensorMapType = binary_sensor_map_ns.enum("SensorMapType")
CONF_BAYESIAN = "bayesian"
CONF_PRIOR = "prior"
CONF_PROB_GIVEN_TRUE = "prob_given_true"
CONF_PROB_GIVEN_FALSE = "prob_given_false"
CONF_OBSERVATIONS = "observations"
SENSOR_MAP_TYPES = {
CONF_GROUP: SensorMapType.BINARY_SENSOR_MAP_TYPE_GROUP,
CONF_SUM: SensorMapType.BINARY_SENSOR_MAP_TYPE_SUM,
CONF_BAYESIAN: SensorMapType.BINARY_SENSOR_MAP_TYPE_BAYESIAN,
}
entry = {
entry_one_parameter = {
cv.Required(CONF_BINARY_SENSOR): cv.use_id(binary_sensor.BinarySensor),
cv.Required(CONF_VALUE): cv.float_,
}
entry_bayesian_parameters = {
cv.Required(CONF_BINARY_SENSOR): cv.use_id(binary_sensor.BinarySensor),
cv.Required(CONF_PROB_GIVEN_TRUE): cv.float_range(min=0, max=1),
cv.Required(CONF_PROB_GIVEN_FALSE): cv.float_range(min=0, max=1),
}
CONFIG_SCHEMA = cv.typed_schema(
{
CONF_GROUP: sensor.sensor_schema(
@@ -39,7 +52,7 @@ CONFIG_SCHEMA = cv.typed_schema(
).extend(
{
cv.Required(CONF_CHANNELS): cv.All(
cv.ensure_list(entry), cv.Length(min=1)
cv.ensure_list(entry_one_parameter), cv.Length(min=1, max=64)
),
}
),
@@ -50,7 +63,18 @@ CONFIG_SCHEMA = cv.typed_schema(
).extend(
{
cv.Required(CONF_CHANNELS): cv.All(
cv.ensure_list(entry), cv.Length(min=1)
cv.ensure_list(entry_one_parameter), cv.Length(min=1, max=64)
),
}
),
CONF_BAYESIAN: sensor.sensor_schema(
BinarySensorMap,
accuracy_decimals=2,
).extend(
{
cv.Required(CONF_PRIOR): cv.float_range(min=0, max=1),
cv.Required(CONF_OBSERVATIONS): cv.All(
cv.ensure_list(entry_bayesian_parameters), cv.Length(min=1, max=64)
),
}
),
@@ -66,6 +90,17 @@ async def to_code(config):
constant = SENSOR_MAP_TYPES[config[CONF_TYPE]]
cg.add(var.set_sensor_type(constant))
for ch in config[CONF_CHANNELS]:
input_var = await cg.get_variable(ch[CONF_BINARY_SENSOR])
cg.add(var.add_channel(input_var, ch[CONF_VALUE]))
if config[CONF_TYPE] == CONF_BAYESIAN:
cg.add(var.set_bayesian_prior(config[CONF_PRIOR]))
for obs in config[CONF_OBSERVATIONS]:
input_var = await cg.get_variable(obs[CONF_BINARY_SENSOR])
cg.add(
var.add_channel(
input_var, obs[CONF_PROB_GIVEN_TRUE], obs[CONF_PROB_GIVEN_FALSE]
)
)
else:
for ch in config[CONF_CHANNELS]:
input_var = await cg.get_variable(ch[CONF_BINARY_SENSOR])
cg.add(var.add_channel(input_var, ch[CONF_VALUE]))

View File

@@ -9,6 +9,7 @@ from esphome.const import (
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_KILOWATT_HOURS,
UNIT_VOLT,
@@ -66,16 +67,19 @@ CONFIG_SCHEMA = (
unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_ENERGY_2): sensor.sensor_schema(
unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_ENERGY_TOTAL): sensor.sensor_schema(
unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
}
)

View File

@@ -29,8 +29,35 @@ BLEClientConnectTrigger = ble_client_ns.class_(
BLEClientDisconnectTrigger = ble_client_ns.class_(
"BLEClientDisconnectTrigger", automation.Trigger.template(BLEClientNodeConstRef)
)
BLEClientPasskeyRequestTrigger = ble_client_ns.class_(
"BLEClientPasskeyRequestTrigger", automation.Trigger.template(BLEClientNodeConstRef)
)
BLEClientPasskeyNotificationTrigger = ble_client_ns.class_(
"BLEClientPasskeyNotificationTrigger",
automation.Trigger.template(BLEClientNodeConstRef, cg.uint32),
)
BLEClientNumericComparisonRequestTrigger = ble_client_ns.class_(
"BLEClientNumericComparisonRequestTrigger",
automation.Trigger.template(BLEClientNodeConstRef, cg.uint32),
)
# Actions
BLEWriteAction = ble_client_ns.class_("BLEClientWriteAction", automation.Action)
BLEPasskeyReplyAction = ble_client_ns.class_(
"BLEClientPasskeyReplyAction", automation.Action
)
BLENumericComparisonReplyAction = ble_client_ns.class_(
"BLEClientNumericComparisonReplyAction", automation.Action
)
BLERemoveBondAction = ble_client_ns.class_(
"BLEClientRemoveBondAction", automation.Action
)
CONF_PASSKEY = "passkey"
CONF_ACCEPT = "accept"
CONF_ON_PASSKEY_REQUEST = "on_passkey_request"
CONF_ON_PASSKEY_NOTIFICATION = "on_passkey_notification"
CONF_ON_NUMERIC_COMPARISON_REQUEST = "on_numeric_comparison_request"
# Espressif platformio framework is built with MAX_BLE_CONN to 3, so
# enforce this in yaml checks.
@@ -56,6 +83,29 @@ CONFIG_SCHEMA = (
),
}
),
cv.Optional(CONF_ON_PASSKEY_REQUEST): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
BLEClientPasskeyRequestTrigger
),
}
),
cv.Optional(CONF_ON_PASSKEY_NOTIFICATION): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
BLEClientPasskeyNotificationTrigger
),
}
),
cv.Optional(
CONF_ON_NUMERIC_COMPARISON_REQUEST
): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
BLEClientNumericComparisonRequestTrigger
),
}
),
}
)
.extend(cv.COMPONENT_SCHEMA)
@@ -85,13 +135,34 @@ BLE_WRITE_ACTION_SCHEMA = cv.Schema(
}
)
BLE_NUMERIC_COMPARISON_REPLY_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
cv.Required(CONF_ACCEPT): cv.templatable(cv.boolean),
}
)
BLE_PASSKEY_REPLY_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
cv.Required(CONF_PASSKEY): cv.templatable(cv.int_range(min=0, max=999999)),
}
)
BLE_REMOVE_BOND_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
}
)
@automation.register_action(
"ble_client.ble_write", BLEWriteAction, BLE_WRITE_ACTION_SCHEMA
)
async def ble_write_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, parent)
value = config[CONF_VALUE]
if cg.is_template(value):
@@ -137,6 +208,54 @@ async def ble_write_to_code(config, action_id, template_arg, args):
return var
@automation.register_action(
"ble_client.numeric_comparison_reply",
BLENumericComparisonReplyAction,
BLE_NUMERIC_COMPARISON_REPLY_ACTION_SCHEMA,
)
async def numeric_comparison_reply_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, parent)
accept = config[CONF_ACCEPT]
if cg.is_template(accept):
templ = await cg.templatable(accept, args, cg.bool_)
cg.add(var.set_value_template(templ))
else:
cg.add(var.set_value_simple(accept))
return var
@automation.register_action(
"ble_client.passkey_reply", BLEPasskeyReplyAction, BLE_PASSKEY_REPLY_ACTION_SCHEMA
)
async def passkey_reply_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, parent)
passkey = config[CONF_PASSKEY]
if cg.is_template(passkey):
templ = await cg.templatable(passkey, args, cg.uint32)
cg.add(var.set_value_template(templ))
else:
cg.add(var.set_value_simple(passkey))
return var
@automation.register_action(
"ble_client.remove_bond",
BLERemoveBondAction,
BLE_REMOVE_BOND_ACTION_SCHEMA,
)
async def remove_bond_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, parent)
return var
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
@@ -148,3 +267,12 @@ async def to_code(config):
for conf in config.get(CONF_ON_DISCONNECT, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_PASSKEY_REQUEST, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_PASSKEY_NOTIFICATION, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(cg.uint32, "passkey")], conf)
for conf in config.get(CONF_ON_NUMERIC_COMPARISON_REQUEST, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(cg.uint32, "passkey")], conf)

View File

@@ -1,3 +1,5 @@
#ifdef USE_ESP32
#include "automation.h"
#include <esp_bt_defs.h>
@@ -73,3 +75,5 @@ void BLEWriterClientNode::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
} // namespace ble_client
} // namespace esphome
#endif

View File

@@ -1,13 +1,13 @@
#pragma once
#ifdef USE_ESP32
#include <utility>
#include <vector>
#include "esphome/core/automation.h"
#include "esphome/components/ble_client/ble_client.h"
#ifdef USE_ESP32
namespace esphome {
namespace ble_client {
class BLEClientConnectTrigger : public Trigger<>, public BLEClientNode {
@@ -37,6 +37,44 @@ class BLEClientDisconnectTrigger : public Trigger<>, public BLEClientNode {
}
};
class BLEClientPasskeyRequestTrigger : public Trigger<>, public BLEClientNode {
public:
explicit BLEClientPasskeyRequestTrigger(BLEClient *parent) { parent->register_ble_node(this); }
void loop() override {}
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override {
if (event == ESP_GAP_BLE_PASSKEY_REQ_EVT &&
memcmp(param->ble_security.auth_cmpl.bd_addr, this->parent_->get_remote_bda(), 6) == 0) {
this->trigger();
}
}
};
class BLEClientPasskeyNotificationTrigger : public Trigger<uint32_t>, public BLEClientNode {
public:
explicit BLEClientPasskeyNotificationTrigger(BLEClient *parent) { parent->register_ble_node(this); }
void loop() override {}
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override {
if (event == ESP_GAP_BLE_PASSKEY_NOTIF_EVT &&
memcmp(param->ble_security.auth_cmpl.bd_addr, this->parent_->get_remote_bda(), 6) == 0) {
uint32_t passkey = param->ble_security.key_notif.passkey;
this->trigger(passkey);
}
}
};
class BLEClientNumericComparisonRequestTrigger : public Trigger<uint32_t>, public BLEClientNode {
public:
explicit BLEClientNumericComparisonRequestTrigger(BLEClient *parent) { parent->register_ble_node(this); }
void loop() override {}
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override {
if (event == ESP_GAP_BLE_NC_REQ_EVT &&
memcmp(param->ble_security.auth_cmpl.bd_addr, this->parent_->get_remote_bda(), 6) == 0) {
uint32_t passkey = param->ble_security.key_notif.passkey;
this->trigger(passkey);
}
}
};
class BLEWriterClientNode : public BLEClientNode {
public:
BLEWriterClientNode(BLEClient *ble_client) {
@@ -94,6 +132,86 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
std::function<std::vector<uint8_t>(Ts...)> value_template_{};
};
template<typename... Ts> class BLEClientPasskeyReplyAction : public Action<Ts...> {
public:
BLEClientPasskeyReplyAction(BLEClient *ble_client) { parent_ = ble_client; }
void play(Ts... x) override {
uint32_t passkey;
if (has_simple_value_) {
passkey = this->value_simple_;
} else {
passkey = this->value_template_(x...);
}
if (passkey > 999999)
return;
esp_bd_addr_t remote_bda;
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
esp_ble_passkey_reply(remote_bda, true, passkey);
}
void set_value_template(std::function<uint32_t(Ts...)> func) {
this->value_template_ = std::move(func);
has_simple_value_ = false;
}
void set_value_simple(const uint32_t &value) {
this->value_simple_ = value;
has_simple_value_ = true;
}
private:
BLEClient *parent_{nullptr};
bool has_simple_value_ = true;
uint32_t value_simple_{0};
std::function<uint32_t(Ts...)> value_template_{};
};
template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Action<Ts...> {
public:
BLEClientNumericComparisonReplyAction(BLEClient *ble_client) { parent_ = ble_client; }
void play(Ts... x) override {
esp_bd_addr_t remote_bda;
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
if (has_simple_value_) {
esp_ble_confirm_reply(remote_bda, this->value_simple_);
} else {
esp_ble_confirm_reply(remote_bda, this->value_template_(x...));
}
}
void set_value_template(std::function<bool(Ts...)> func) {
this->value_template_ = std::move(func);
has_simple_value_ = false;
}
void set_value_simple(const bool &value) {
this->value_simple_ = value;
has_simple_value_ = true;
}
private:
BLEClient *parent_{nullptr};
bool has_simple_value_ = true;
bool value_simple_{false};
std::function<bool(Ts...)> value_template_{};
};
template<typename... Ts> class BLEClientRemoveBondAction : public Action<Ts...> {
public:
BLEClientRemoveBondAction(BLEClient *ble_client) { parent_ = ble_client; }
void play(Ts... x) override {
esp_bd_addr_t remote_bda;
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
esp_ble_remove_bond_device(remote_bda);
}
private:
BLEClient *parent_{nullptr};
};
} // namespace ble_client
} // namespace esphome

View File

@@ -27,7 +27,7 @@ class BLEClient;
class BLEClientNode {
public:
virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) = 0;
esp_ble_gattc_cb_param_t *param){};
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {}
virtual void loop() {}
void set_address(uint64_t address) { address_ = address; }

View File

@@ -158,6 +158,25 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
return true;
}
void BluetoothConnection::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
BLEClientBase::gap_event_handler(event, param);
switch (event) {
case ESP_GAP_BLE_AUTH_CMPL_EVT:
if (memcmp(param->ble_security.auth_cmpl.bd_addr, this->remote_bda_, 6) != 0)
break;
if (param->ble_security.auth_cmpl.success) {
api::global_api_server->send_bluetooth_device_pairing(this->address_, true);
} else {
api::global_api_server->send_bluetooth_device_pairing(this->address_, false,
param->ble_security.auth_cmpl.fail_reason);
}
break;
default:
break;
}
}
esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
if (!this->connected()) {
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not connected.", this->connection_index_,

View File

@@ -13,6 +13,7 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase {
public:
bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
esp_err_t read_characteristic(uint16_t handle);
esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response);

View File

@@ -257,12 +257,7 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
}
if (msg.has_address_type) {
connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
connection->remote_bda_[1] = (msg.address >> 32) & 0xFF;
connection->remote_bda_[2] = (msg.address >> 24) & 0xFF;
connection->remote_bda_[3] = (msg.address >> 16) & 0xFF;
connection->remote_bda_[4] = (msg.address >> 8) & 0xFF;
connection->remote_bda_[5] = (msg.address >> 0) & 0xFF;
uint64_to_bd_addr(msg.address, connection->remote_bda_);
connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
connection->set_state(espbt::ClientState::DISCOVERED);
} else {
@@ -290,9 +285,34 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
}
break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR: {
auto *connection = this->get_connection_(msg.address, false);
if (connection != nullptr) {
if (!connection->is_paired()) {
auto err = connection->pair();
if (err != ESP_OK) {
api::global_api_server->send_bluetooth_device_pairing(msg.address, false, err);
}
} else {
api::global_api_server->send_bluetooth_device_pairing(msg.address, true);
}
}
break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR: {
esp_bd_addr_t address;
uint64_to_bd_addr(msg.address, address);
esp_err_t ret = esp_ble_remove_bond_device(address);
api::global_api_server->send_bluetooth_device_unpairing(msg.address, ret == ESP_OK, ret);
break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: {
esp_bd_addr_t address;
uint64_to_bd_addr(msg.address, address);
esp_err_t ret = esp_ble_gattc_cache_clean(address);
api::global_api_server->send_bluetooth_device_clear_cache(msg.address, ret == ESP_OK, ret);
break;
}
}
}

View File

@@ -44,6 +44,15 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
int get_bluetooth_connections_free();
int get_bluetooth_connections_limit() { return this->connections_.size(); }
static void uint64_to_bd_addr(uint64_t address, esp_bd_addr_t bd_addr) {
bd_addr[0] = (address >> 40) & 0xff;
bd_addr[1] = (address >> 32) & 0xff;
bd_addr[2] = (address >> 24) & 0xff;
bd_addr[3] = (address >> 16) & 0xff;
bd_addr[4] = (address >> 8) & 0xff;
bd_addr[5] = (address >> 0) & 0xff;
}
void set_active(bool active) { this->active_ = active; }
bool has_active() { return this->active_; }
@@ -59,6 +68,14 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
// Version 1: Initial version without active connections
// Version 2: Support for active connections
// Version 3: New connection API
// Version 4: Pairing support
// Version 5: Cache clear support
static const uint32_t ACTIVE_CONNECTIONS_VERSION = 5;
static const uint32_t PASSIVE_ONLY_VERSION = 1;
} // namespace bluetooth_proxy
} // namespace esphome

View File

@@ -1,6 +1,6 @@
#include "bme680.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bme680 {
@@ -117,18 +117,24 @@ void BME680Component::setup() {
this->calibration_.gh2 = cal2[12] << 8 | cal2[13];
this->calibration_.gh3 = cal2[15];
if (!this->read_byte(0x02, &this->calibration_.res_heat_range)) {
uint8_t temp_var = 0;
if (!this->read_byte(0x02, &temp_var)) {
this->mark_failed();
return;
}
if (!this->read_byte(0x00, &this->calibration_.res_heat_val)) {
this->calibration_.res_heat_range = ((temp_var & 0x30) / 16);
if (!this->read_byte(0x00, &temp_var)) {
this->mark_failed();
return;
}
if (!this->read_byte(0x04, &this->calibration_.range_sw_err)) {
this->calibration_.res_heat_val = (int8_t) temp_var;
if (!this->read_byte(0x04, &temp_var)) {
this->mark_failed();
return;
}
this->calibration_.range_sw_err = ((int8_t) temp_var & (int8_t) 0xf0) / 16;
this->calibration_.ambient_temperature = 25; // prime ambient temperature
@@ -181,7 +187,7 @@ void BME680Component::setup() {
return;
}
gas0_control &= ~0b00001000;
gas0_control |= heat_off ? 0b100 : 0b000;
gas0_control |= heat_off << 3;
if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) {
this->mark_failed();
return;
@@ -249,12 +255,12 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
if (temperature > 400)
temperature = 400;
const uint8_t ambient_temperature = this->calibration_.ambient_temperature;
const int8_t ambient_temperature = this->calibration_.ambient_temperature;
const int8_t gh1 = this->calibration_.gh1;
const int16_t gh2 = this->calibration_.gh2;
const int8_t gh3 = this->calibration_.gh3;
const uint8_t res_heat_range = this->calibration_.res_heat_range;
const uint8_t res_heat_val = this->calibration_.res_heat_val;
const int8_t res_heat_val = this->calibration_.res_heat_val;
uint8_t heatr_res;
int32_t var1;
@@ -269,8 +275,8 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
var3 = var1 + (var2 / 2);
var4 = (var3 / (res_heat_range + 4));
var5 = (131 * res_heat_val) + 65536;
heatr_res_x100 = (int32_t)(((var4 / var5) - 250) * 34);
heatr_res = (uint8_t)((heatr_res_x100 + 50) / 100);
heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34);
heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100);
return heatr_res;
}
@@ -293,35 +299,57 @@ uint8_t BME680Component::calc_heater_duration_(uint16_t duration) {
void BME680Component::read_data_() {
uint8_t data[15];
if (!this->read_bytes(BME680_REGISTER_FIELD0, data, 15)) {
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(NAN);
if (this->pressure_sensor_ != nullptr)
this->pressure_sensor_->publish_state(NAN);
if (this->humidity_sensor_ != nullptr)
this->humidity_sensor_->publish_state(NAN);
if (this->gas_resistance_sensor_ != nullptr)
this->gas_resistance_sensor_->publish_state(NAN);
ESP_LOGW(TAG, "Communication with BME680 failed!");
this->status_set_warning();
return;
}
this->status_clear_warning();
uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4);
uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4);
uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]);
uint16_t raw_gas = (uint16_t(data[13]) << 2) | (uint16_t(14) >> 6);
uint16_t raw_gas = (uint16_t) ((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64));
uint8_t gas_range = data[14] & 0x0F;
float temperature = this->calc_temperature_(raw_temperature);
float pressure = this->calc_pressure_(raw_pressure);
float humidity = this->calc_humidity_(raw_humidity);
float gas_resistance = NAN;
if (data[14] & 0x20) {
gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
}
float gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
bool gas_valid = (data[14] >> 5) & 1;
bool heat_stable = (data[14] >> 4) & 1;
if (this->heater_temperature_ == 0 || this->heater_duration_ == 0)
heat_stable = true; // Allow reporting gas resistance when heater is disabled
ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%% gas_resistance=%.1fΩ", temperature, pressure,
humidity, gas_resistance);
if (!gas_valid)
ESP_LOGW(TAG, "Gas measurement unsuccessful, reading invalid!");
if (!heat_stable)
ESP_LOGW(TAG, "Heater unstable, reading invalid! (Normal for a few readings after a power cycle)");
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->pressure_sensor_ != nullptr)
this->pressure_sensor_->publish_state(pressure);
if (this->humidity_sensor_ != nullptr)
this->humidity_sensor_->publish_state(humidity);
if (this->gas_resistance_sensor_ != nullptr)
this->gas_resistance_sensor_->publish_state(gas_resistance);
this->status_clear_warning();
if (this->gas_resistance_sensor_ != nullptr) {
if (gas_valid && heat_stable) {
this->gas_resistance_sensor_->publish_state(gas_resistance);
} else {
this->status_set_warning();
this->gas_resistance_sensor_->publish_state(NAN);
}
}
}
float BME680Component::calc_temperature_(uint32_t raw_temperature) {
@@ -428,20 +456,22 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) {
return calc_hum;
}
uint32_t BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) {
float BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) {
float calc_gas_res;
float var1 = 0;
float var2 = 0;
float var3 = 0;
float raw_gas_f = raw_gas;
float range_f = 1U << range;
const float range_sw_err = this->calibration_.range_sw_err;
var1 = 1340.0f + (5.0f * range_sw_err);
var2 = var1 * (1.0f + BME680_GAS_LOOKUP_TABLE_1[range] / 100.0f);
var3 = 1.0f + (BME680_GAS_LOOKUP_TABLE_2[range] / 100.0f);
calc_gas_res = 1.0f / (var3 * 0.000000125f * float(1 << range) * (((float(raw_gas) - 512.0f) / var2) + 1.0f));
calc_gas_res = 1.0f / (var3 * 0.000000125f * range_f * (((raw_gas_f - 512.0f) / var2) + 1.0f));
return static_cast<uint32_t>(calc_gas_res);
return calc_gas_res;
}
uint32_t BME680Component::calc_meas_duration_() {
uint32_t tph_dur; // Calculate in us

View File

@@ -59,11 +59,11 @@ struct BME680CalibrationData {
int8_t gh3;
uint8_t res_heat_range;
uint8_t res_heat_val;
uint8_t range_sw_err;
int8_t res_heat_val;
int8_t range_sw_err;
float tfine;
uint8_t ambient_temperature;
int8_t ambient_temperature;
};
class BME680Component : public PollingComponent, public i2c::I2CDevice {
@@ -117,7 +117,7 @@ class BME680Component : public PollingComponent, public i2c::I2CDevice {
/// Calculate the relative humidity in % using the provided raw ADC value.
float calc_humidity_(uint16_t raw_humidity);
/// Calculate the gas resistance in Ω using the provided raw ADC value.
uint32_t calc_gas_resistance_(uint16_t raw_gas, uint8_t range);
float calc_gas_resistance_(uint16_t raw_gas, uint8_t range);
/// Calculate how long the sensor will take until we can retrieve data.
uint32_t calc_meas_duration_();

View File

@@ -1,11 +1,12 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
from esphome.components import i2c, esp32
from esphome.const import CONF_ID
CODEOWNERS = ["@trvrnrth"]
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["sensor", "text_sensor"]
MULTI_CONF = True
CONF_BME680_BSEC_ID = "bme680_bsec_id"
CONF_TEMPERATURE_OFFSET = "temperature_offset"
@@ -31,22 +32,31 @@ BME680BSECComponent = bme680_bsec_ns.class_(
"BME680BSECComponent", cg.Component, i2c.I2CDevice
)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(BME680BSECComponent),
cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature,
cv.Optional(CONF_IAQ_MODE, default="STATIC"): cv.enum(
IAQ_MODE_OPTIONS, upper=True
),
cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum(
SAMPLE_RATE_OPTIONS, upper=True
),
cv.Optional(
CONF_STATE_SAVE_INTERVAL, default="6hours"
): cv.positive_time_period_minutes,
},
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BME680BSECComponent),
cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature,
cv.Optional(CONF_IAQ_MODE, default="STATIC"): cv.enum(
IAQ_MODE_OPTIONS, upper=True
),
cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum(
SAMPLE_RATE_OPTIONS, upper=True
),
cv.Optional(
CONF_STATE_SAVE_INTERVAL, default="6hours"
): cv.positive_time_period_minutes,
}
).extend(i2c.i2c_device_schema(0x76)),
cv.only_with_arduino,
).extend(i2c.i2c_device_schema(0x76))
cv.Any(
cv.only_on_esp8266,
cv.All(
cv.only_on_esp32,
esp32.only_on_variant(supported=[esp32.const.VARIANT_ESP32]),
),
),
)
async def to_code(config):
@@ -54,6 +64,7 @@ async def to_code(config):
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
cg.add(var.set_device_id(str(config[CONF_ID])))
cg.add(var.set_temperature_offset(config[CONF_TEMPERATURE_OFFSET]))
cg.add(var.set_iaq_mode(config[CONF_IAQ_MODE]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))

View File

@@ -10,19 +10,24 @@ static const char *const TAG = "bme680_bsec.sensor";
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
BME680BSECComponent *BME680BSECComponent::instance; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<BME680BSECComponent *>
BME680BSECComponent::instances; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
uint8_t BME680BSECComponent::work_buffer_[BSEC_MAX_WORKBUFFER_SIZE] = {0};
void BME680BSECComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up BME680 via BSEC...");
BME680BSECComponent::instance = this;
ESP_LOGCONFIG(TAG, "Setting up BME680(%s) via BSEC...", this->device_id_.c_str());
this->bsec_status_ = bsec_init();
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
return;
}
uint8_t new_idx = BME680BSECComponent::instances.size();
BME680BSECComponent::instances.push_back(this);
this->bme680_.dev_id = this->address_;
this->bsec_state_data_valid_ = false;
// Initialize the bme680_ structure (passed-in to the bme680_* functions) and the BME680 device
this->bme680_.dev_id =
new_idx; // This is a "Place holder to store the id of the device structure" (see bme680_defs.h).
// This will be passed-in as first parameter to the next "read" and "write" function pointers.
// We currently use the index of the object in the BME680BSECComponent::instances vector to identify
// the different devices in the system.
this->bme680_.intf = BME680_I2C_INTF;
this->bme680_.read = BME680BSECComponent::read_bytes_wrapper;
this->bme680_.write = BME680BSECComponent::write_bytes_wrapper;
@@ -35,29 +40,30 @@ void BME680BSECComponent::setup() {
return;
}
if (this->sample_rate_ == SAMPLE_RATE_ULP) {
const uint8_t bsec_config[] = {
#include "config/generic_33v_300s_28d/bsec_iaq.txt"
};
this->set_config_(bsec_config);
} else {
const uint8_t bsec_config[] = {
#include "config/generic_33v_3s_28d/bsec_iaq.txt"
};
this->set_config_(bsec_config);
}
this->update_subscription_();
if (this->bsec_status_ != BSEC_OK) {
// Initialize the BSEC library
if (this->reinit_bsec_lib_() != 0) {
this->mark_failed();
return;
}
// Load the BSEC library state from storage
this->load_state_();
}
void BME680BSECComponent::set_config_(const uint8_t *config) {
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
this->bsec_status_ = bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, work_buffer, sizeof(work_buffer));
void BME680BSECComponent::set_config_() {
if (this->sample_rate_ == SAMPLE_RATE_ULP) {
const uint8_t config[] = {
#include "config/generic_33v_300s_28d/bsec_iaq.txt"
};
this->bsec_status_ =
bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, this->work_buffer_, sizeof(this->work_buffer_));
} else {
const uint8_t config[] = {
#include "config/generic_33v_3s_28d/bsec_iaq.txt"
};
this->bsec_status_ =
bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, this->work_buffer_, sizeof(this->work_buffer_));
}
}
float BME680BSECComponent::calc_sensor_sample_rate_(SampleRate sample_rate) {
@@ -118,10 +124,12 @@ void BME680BSECComponent::update_subscription_() {
uint8_t num_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
this->bsec_status_ =
bsec_update_subscription(virtual_sensors, num_virtual_sensors, sensor_settings, &num_sensor_settings);
ESP_LOGV(TAG, "%s: updating subscription for %d virtual sensors (out=%d sensors)", this->device_id_.c_str(),
num_virtual_sensors, num_sensor_settings);
}
void BME680BSECComponent::dump_config() {
ESP_LOGCONFIG(TAG, "BME680 via BSEC:");
ESP_LOGCONFIG(TAG, "%s via BSEC:", this->device_id_.c_str());
bsec_version_t version;
bsec_get_version(&version);
@@ -185,23 +193,31 @@ void BME680BSECComponent::run_() {
return;
}
ESP_LOGV(TAG, "Performing sensor run");
ESP_LOGV(TAG, "%s: Performing sensor run", this->device_id_.c_str());
bsec_bme_settings_t bme680_settings;
this->bsec_status_ = bsec_sensor_control(curr_time_ns, &bme680_settings);
// Restore BSEC library state
// The reinit_bsec_lib_ method is computationally expensive: it takes 1200÷2900 microseconds on a ESP32.
// It can be skipped entirely when there is only one device (since the BSEC library won't be shared)
if (BME680BSECComponent::instances.size() > 1) {
int res = this->reinit_bsec_lib_();
if (res != 0)
return;
}
this->bsec_status_ = bsec_sensor_control(curr_time_ns, &this->bme680_settings_);
if (this->bsec_status_ < BSEC_OK) {
ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC Error Code %d)", this->bsec_status_);
return;
}
this->next_call_ns_ = bme680_settings.next_call;
this->next_call_ns_ = this->bme680_settings_.next_call;
if (bme680_settings.trigger_measurement) {
this->bme680_.tph_sett.os_temp = bme680_settings.temperature_oversampling;
this->bme680_.tph_sett.os_pres = bme680_settings.pressure_oversampling;
this->bme680_.tph_sett.os_hum = bme680_settings.humidity_oversampling;
this->bme680_.gas_sett.run_gas = bme680_settings.run_gas;
this->bme680_.gas_sett.heatr_temp = bme680_settings.heater_temperature;
this->bme680_.gas_sett.heatr_dur = bme680_settings.heating_duration;
if (this->bme680_settings_.trigger_measurement) {
this->bme680_.tph_sett.os_temp = this->bme680_settings_.temperature_oversampling;
this->bme680_.tph_sett.os_pres = this->bme680_settings_.pressure_oversampling;
this->bme680_.tph_sett.os_hum = this->bme680_settings_.humidity_oversampling;
this->bme680_.gas_sett.run_gas = this->bme680_settings_.run_gas;
this->bme680_.gas_sett.heatr_temp = this->bme680_settings_.heater_temperature;
this->bme680_.gas_sett.heatr_dur = this->bme680_settings_.heating_duration;
this->bme680_.power_mode = BME680_FORCED_MODE;
uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL;
this->bme680_status_ = bme680_set_sensor_settings(desired_settings, &this->bme680_);
@@ -218,19 +234,26 @@ void BME680BSECComponent::run_() {
uint16_t meas_dur = 0;
bme680_get_profile_dur(&meas_dur, &this->bme680_);
// Since we are about to go "out of scope" in the loop, take a snapshot of the state now so we can restore it later
// TODO: it would be interesting to see if this is really needed here, or if it's needed only after each
// bsec_do_steps() call
if (BME680BSECComponent::instances.size() > 1)
this->snapshot_state_();
ESP_LOGV(TAG, "Queueing read in %ums", meas_dur);
this->set_timeout("read", meas_dur,
[this, curr_time_ns, bme680_settings]() { this->read_(curr_time_ns, bme680_settings); });
this->set_timeout("read", meas_dur, [this]() { this->read_(); });
} else {
ESP_LOGV(TAG, "Measurement not required");
this->read_(curr_time_ns, bme680_settings);
this->read_();
}
}
void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings) {
ESP_LOGV(TAG, "Reading data");
void BME680BSECComponent::read_() {
ESP_LOGV(TAG, "%s: Reading data", this->device_id_.c_str());
int64_t curr_time_ns = this->get_time_ns_();
if (bme680_settings.trigger_measurement) {
if (this->bme680_settings_.trigger_measurement) {
while (this->bme680_.power_mode != BME680_SLEEP_MODE) {
this->bme680_status_ = bme680_get_sensor_mode(&this->bme680_);
if (this->bme680_status_ != BME680_OK) {
@@ -239,7 +262,7 @@ void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme
}
}
if (!bme680_settings.process_data) {
if (!this->bme680_settings_.process_data) {
ESP_LOGV(TAG, "Data processing not required");
return;
}
@@ -259,35 +282,35 @@ void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance
uint8_t num_inputs = 0;
if (bme680_settings.process_data & BSEC_PROCESS_TEMPERATURE) {
if (this->bme680_settings_.process_data & BSEC_PROCESS_TEMPERATURE) {
inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
inputs[num_inputs].signal = data.temperature / 100.0f;
inputs[num_inputs].time_stamp = trigger_time_ns;
inputs[num_inputs].time_stamp = curr_time_ns;
num_inputs++;
// Temperature offset from the real temperature due to external heat sources
inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
inputs[num_inputs].signal = this->temperature_offset_;
inputs[num_inputs].time_stamp = trigger_time_ns;
inputs[num_inputs].time_stamp = curr_time_ns;
num_inputs++;
}
if (bme680_settings.process_data & BSEC_PROCESS_HUMIDITY) {
if (this->bme680_settings_.process_data & BSEC_PROCESS_HUMIDITY) {
inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
inputs[num_inputs].signal = data.humidity / 1000.0f;
inputs[num_inputs].time_stamp = trigger_time_ns;
inputs[num_inputs].time_stamp = curr_time_ns;
num_inputs++;
}
if (bme680_settings.process_data & BSEC_PROCESS_PRESSURE) {
if (this->bme680_settings_.process_data & BSEC_PROCESS_PRESSURE) {
inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE;
inputs[num_inputs].signal = data.pressure;
inputs[num_inputs].time_stamp = trigger_time_ns;
inputs[num_inputs].time_stamp = curr_time_ns;
num_inputs++;
}
if (bme680_settings.process_data & BSEC_PROCESS_GAS) {
if (this->bme680_settings_.process_data & BSEC_PROCESS_GAS) {
if (data.status & BME680_GASM_VALID_MSK) {
inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
inputs[num_inputs].signal = data.gas_resistance;
inputs[num_inputs].time_stamp = trigger_time_ns;
inputs[num_inputs].time_stamp = curr_time_ns;
num_inputs++;
} else {
ESP_LOGD(TAG, "BME680 did not report gas data");
@@ -298,6 +321,22 @@ void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme
return;
}
// Restore BSEC library state
// The reinit_bsec_lib_ method is computationally expensive: it takes 1200÷2900 microseconds on a ESP32.
// It can be skipped entirely when there is only one device (since the BSEC library won't be shared)
if (BME680BSECComponent::instances.size() > 1) {
int res = this->reinit_bsec_lib_();
if (res != 0)
return;
// Now that the BSEC library has been re-initialized, bsec_sensor_control *NEEDS* to be called in order to support
// multiple devices with a different set of enabled sensors (even if the bme680_settings_ data is not used)
this->bsec_status_ = bsec_sensor_control(curr_time_ns, &this->bme680_settings_);
if (this->bsec_status_ < BSEC_OK) {
ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC Error Code %d)", this->bsec_status_);
return;
}
}
bsec_output_t outputs[BSEC_NUMBER_OUTPUTS];
uint8_t num_outputs = BSEC_NUMBER_OUTPUTS;
this->bsec_status_ = bsec_do_steps(inputs, num_inputs, outputs, &num_outputs);
@@ -305,6 +344,13 @@ void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme
ESP_LOGW(TAG, "BSEC failed to process signals (BSEC Error Code %d)", this->bsec_status_);
return;
}
ESP_LOGV(TAG, "%s: after bsec_do_steps: num_inputs=%d num_outputs=%d", this->device_id_.c_str(), num_inputs,
num_outputs);
// Since we are about to go "out of scope" in the loop, take a snapshot of the state now so we can restore it later
if (BME680BSECComponent::instances.size() > 1)
this->snapshot_state_();
if (num_outputs < 1) {
ESP_LOGD(TAG, "No signal outputs provided by BSEC");
return;
@@ -314,7 +360,7 @@ void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme
}
void BME680BSECComponent::publish_(const bsec_output_t *outputs, uint8_t num_outputs) {
ESP_LOGV(TAG, "Queuing sensor state publish actions");
ESP_LOGV(TAG, "%s: Queuing sensor state publish actions", this->device_id_.c_str());
for (uint8_t i = 0; i < num_outputs; i++) {
float signal = outputs[i].signal;
switch (outputs[i].sensor_id) {
@@ -376,12 +422,20 @@ void BME680BSECComponent::publish_sensor_(text_sensor::TextSensor *sensor, const
sensor->publish_state(value);
}
int8_t BME680BSECComponent::read_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len) {
return BME680BSECComponent::instance->read_bytes(a_register, data, len) ? 0 : -1;
// Communication function - read
// First parameter is the "dev_id" member of our "bme680_" object, which is passed-back here as-is
int8_t BME680BSECComponent::read_bytes_wrapper(uint8_t devid, uint8_t a_register, uint8_t *data, uint16_t len) {
BME680BSECComponent *inst = instances[devid];
// Use the I2CDevice::read_bytes method to perform the actual I2C register read
return inst->read_bytes(a_register, data, len) ? 0 : -1;
}
int8_t BME680BSECComponent::write_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len) {
return BME680BSECComponent::instance->write_bytes(a_register, data, len) ? 0 : -1;
// Communication function - write
// First parameter is the "dev_id" member of our "bme680_" object, which is passed-back here as-is
int8_t BME680BSECComponent::write_bytes_wrapper(uint8_t devid, uint8_t a_register, uint8_t *data, uint16_t len) {
BME680BSECComponent *inst = instances[devid];
// Use the I2CDevice::write_bytes method to perform the actual I2C register write
return inst->write_bytes(a_register, data, len) ? 0 : -1;
}
void BME680BSECComponent::delay_ms(uint32_t period) {
@@ -389,41 +443,97 @@ void BME680BSECComponent::delay_ms(uint32_t period) {
delay(period);
}
// Fetch the BSEC library state and save it in the bsec_state_data_ member (volatile memory)
// Used to share the library when using more than one sensor
void BME680BSECComponent::snapshot_state_() {
uint32_t num_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
this->bsec_status_ = bsec_get_state(0, this->bsec_state_data_, BSEC_MAX_STATE_BLOB_SIZE, this->work_buffer_,
sizeof(this->work_buffer_), &num_serialized_state);
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "%s: Failed to fetch BSEC library state for snapshot (BSEC Error Code %d)", this->device_id_.c_str(),
this->bsec_status_);
return;
}
this->bsec_state_data_valid_ = true;
}
// Restores the BSEC library state from a snapshot in memory
// Used to share the library when using more than one sensor
void BME680BSECComponent::restore_state_() {
if (!this->bsec_state_data_valid_) {
ESP_LOGV(TAG, "%s: BSEC state data NOT valid, aborting restore_state_()", this->device_id_.c_str());
return;
}
this->bsec_status_ =
bsec_set_state(this->bsec_state_data_, BSEC_MAX_STATE_BLOB_SIZE, this->work_buffer_, sizeof(this->work_buffer_));
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "Failed to restore BSEC library state (BSEC Error Code %d)", this->bsec_status_);
return;
}
}
int BME680BSECComponent::reinit_bsec_lib_() {
this->bsec_status_ = bsec_init();
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
return -1;
}
this->set_config_();
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
return -2;
}
this->restore_state_();
this->update_subscription_();
if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
return -3;
}
return 0;
}
void BME680BSECComponent::load_state_() {
uint32_t hash = fnv1_hash("bme680_bsec_state_" + to_string(this->address_));
uint32_t hash = fnv1_hash("bme680_bsec_state_" + this->device_id_);
this->bsec_state_ = global_preferences->make_preference<uint8_t[BSEC_MAX_STATE_BLOB_SIZE]>(hash, true);
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
if (this->bsec_state_.load(&state)) {
ESP_LOGV(TAG, "Loading state");
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
this->bsec_status_ = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, sizeof(work_buffer));
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "Failed to load state (BSEC Error Code %d)", this->bsec_status_);
}
ESP_LOGI(TAG, "Loaded state");
if (!this->bsec_state_.load(&this->bsec_state_data_)) {
// No saved BSEC library state available
return;
}
ESP_LOGV(TAG, "%s: Loading BSEC library state", this->device_id_.c_str());
this->bsec_status_ =
bsec_set_state(this->bsec_state_data_, BSEC_MAX_STATE_BLOB_SIZE, this->work_buffer_, sizeof(this->work_buffer_));
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "%s: Failed to load BSEC library state (BSEC Error Code %d)", this->device_id_.c_str(),
this->bsec_status_);
return;
}
// All OK: set the BSEC state data as valid
this->bsec_state_data_valid_ = true;
ESP_LOGI(TAG, "%s: Loaded BSEC library state", this->device_id_.c_str());
}
void BME680BSECComponent::save_state_(uint8_t accuracy) {
if (accuracy < 3 || (millis() - this->last_state_save_ms_ < this->state_save_interval_ms_)) {
return;
}
ESP_LOGV(TAG, "Saving state");
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
uint32_t num_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
this->bsec_status_ =
bsec_get_state(0, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, BSEC_MAX_STATE_BLOB_SIZE, &num_serialized_state);
if (this->bsec_status_ != BSEC_OK) {
ESP_LOGW(TAG, "Failed fetch state for save (BSEC Error Code %d)", this->bsec_status_);
return;
if (BME680BSECComponent::instances.size() <= 1) {
// When a single device is in use, no snapshot is taken regularly so one is taken now
// On multiple devices, a snapshot is taken at every loop, so there is no need to take one here
this->snapshot_state_();
}
if (!this->bsec_state_data_valid_)
return;
if (!this->bsec_state_.save(&state)) {
ESP_LOGV(TAG, "%s: Saving state", this->device_id_.c_str());
if (!this->bsec_state_.save(&this->bsec_state_data_)) {
ESP_LOGW(TAG, "Failed to save state");
return;
}

View File

@@ -31,6 +31,7 @@ enum SampleRate {
class BME680BSECComponent : public Component, public i2c::I2CDevice {
public:
void set_device_id(const std::string &devid) { this->device_id_.assign(devid); }
void set_temperature_offset(float offset) { this->temperature_offset_ = offset; }
void set_iaq_mode(IAQMode iaq_mode) { this->iaq_mode_ = iaq_mode; }
void set_state_save_interval(uint32_t interval) { this->state_save_interval_ms_ = interval; }
@@ -50,9 +51,9 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
void set_co2_equivalent_sensor(sensor::Sensor *sensor) { this->co2_equivalent_sensor_ = sensor; }
void set_breath_voc_equivalent_sensor(sensor::Sensor *sensor) { this->breath_voc_equivalent_sensor_ = sensor; }
static BME680BSECComponent *instance;
static int8_t read_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len);
static int8_t write_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len);
static std::vector<BME680BSECComponent *> instances;
static int8_t read_bytes_wrapper(uint8_t devid, uint8_t a_register, uint8_t *data, uint16_t len);
static int8_t write_bytes_wrapper(uint8_t devid, uint8_t a_register, uint8_t *data, uint16_t len);
static void delay_ms(uint32_t period);
void setup() override;
@@ -61,23 +62,33 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
void loop() override;
protected:
void set_config_(const uint8_t *config);
void set_config_();
float calc_sensor_sample_rate_(SampleRate sample_rate);
void update_subscription_();
void run_();
void read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings);
void read_();
void publish_(const bsec_output_t *outputs, uint8_t num_outputs);
int64_t get_time_ns_();
void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only = false);
void publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value);
void load_state_();
void save_state_(uint8_t accuracy);
void snapshot_state_(); // Fetch the current BSEC library state and save it in the bsec_state_data_ member (volatile
// memory)
void restore_state_(); // Push the state contained in the bsec_state_data_ member (volatile memory) to the BSEC
// library
int reinit_bsec_lib_(); // Prepare the BSEC library to be used again after this object returns active
// (as the library may have been used by other objects)
void load_state_(); // Initialize the ESP preferences object; retrieve the BSEC library state from the ESP
// preferences (storage); then save it in the bsec_state_data_ member (volatile memory) and
// push it to the BSEC library
void save_state_(
uint8_t accuracy); // Save the bsec_state_data_ member (volatile memory) to the ESP preferences (storage)
void queue_push_(std::function<void()> &&f) { this->queue_.push(std::move(f)); }
static uint8_t work_buffer_[BSEC_MAX_WORKBUFFER_SIZE];
struct bme680_dev bme680_;
bsec_library_return_t bsec_status_{BSEC_OK};
int8_t bme680_status_{BME680_OK};
@@ -88,10 +99,14 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
std::queue<std::function<void()>> queue_;
bool bsec_state_data_valid_;
uint8_t bsec_state_data_[BSEC_MAX_STATE_BLOB_SIZE]; // This is the current snapshot of the BSEC library state
ESPPreferenceObject bsec_state_;
uint32_t state_save_interval_ms_{21600000}; // 6 hours - 4 times a day
uint32_t last_state_save_ms_ = 0;
bsec_bme_settings_t bme680_settings_;
std::string device_id_;
float temperature_offset_{0};
IAQMode iaq_mode_{IAQ_MODE_STATIC};

View File

@@ -11,16 +11,19 @@ from esphome.const import (
CONF_ON_PRESS,
CONF_TRIGGER_ID,
CONF_MQTT_ID,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.cpp_helpers import setup_entity
from esphome.cpp_generator import MockObjClass
CODEOWNERS = ["@esphome/core"]
IS_PLATFORM_COMPONENT = True
DEVICE_CLASSES = [
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE,
]
@@ -54,30 +57,23 @@ _UNDEF = object()
def button_schema(
class_: MockObjClass,
*,
icon: str = _UNDEF,
entity_category: str = _UNDEF,
device_class: str = _UNDEF,
) -> cv.Schema:
schema = BUTTON_SCHEMA
if icon is not _UNDEF:
schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
if entity_category is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_ENTITY_CATEGORY, default=entity_category
): cv.entity_category
}
)
if device_class is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_DEVICE_CLASS, default=device_class
): validate_device_class
}
)
return schema
schema = {cv.GenerateID(): cv.declare_id(class_)}
for key, default, validator in [
(CONF_ICON, icon, cv.icon),
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
(CONF_DEVICE_CLASS, device_class, validate_device_class),
]:
if default is not _UNDEF:
schema[cv.Optional(key, default=default)] = validator
return BUTTON_SCHEMA.extend(schema)
async def setup_button_core_(var, config):

View File

@@ -6,9 +6,6 @@ namespace button {
static const char *const TAG = "button";
Button::Button(const std::string &name) : EntityBase(name) {}
Button::Button() : Button("") {}
void Button::press() {
ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str());
this->press_action();
@@ -16,8 +13,5 @@ void Button::press() {
}
void Button::add_on_press_callback(std::function<void()> &&callback) { this->press_callback_.add(std::move(callback)); }
void Button::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
std::string Button::get_device_class() { return this->device_class_; }
} // namespace button
} // namespace esphome

View File

@@ -15,15 +15,19 @@ namespace button {
} \
}
#define SUB_BUTTON(name) \
protected: \
button::Button *name##_button_{nullptr}; \
\
public: \
void set_##name##_button(button::Button *button) { this->name##_button_ = button; }
/** Base class for all buttons.
*
* A button is just a momentary switch that does not have a state, only a trigger.
*/
class Button : public EntityBase {
class Button : public EntityBase, public EntityBase_DeviceClass {
public:
explicit Button();
explicit Button(const std::string &name);
/** Press this button. This is called by the front-end.
*
* For implementing buttons, please override press_action.
@@ -36,19 +40,12 @@ class Button : public EntityBase {
*/
void add_on_press_callback(std::function<void()> &&callback);
/// Set the Home Assistant device class (see button::device_class).
void set_device_class(const std::string &device_class);
/// Get the device class for this button.
std::string get_device_class();
protected:
/** You should implement this virtual method if you want to create your own button.
*/
virtual void press_action() = 0;
CallbackManager<void()> press_callback_{};
std::string device_class_{};
};
} // namespace button

View File

@@ -145,8 +145,8 @@ void CCS811Component::send_env_data_() {
// https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142
uint16_t hum_conv = static_cast<uint16_t>(lroundf(humidity * 512.0f + 0.5f));
uint16_t temp_conv = static_cast<uint16_t>(lroundf(temperature * 512.0f + 0.5f));
this->write_bytes(0x05, {(uint8_t)((hum_conv >> 8) & 0xff), (uint8_t)((hum_conv & 0xff)),
(uint8_t)((temp_conv >> 8) & 0xff), (uint8_t)((temp_conv & 0xff))});
this->write_bytes(0x05, {(uint8_t) ((hum_conv >> 8) & 0xff), (uint8_t) ((hum_conv & 0xff)),
(uint8_t) ((temp_conv >> 8) & 0xff), (uint8_t) ((temp_conv & 0xff))});
}
void CCS811Component::dump_config() {
ESP_LOGCONFIG(TAG, "CCS811");

View File

@@ -20,6 +20,7 @@ from esphome.const import (
CONF_MODE,
CONF_MODE_COMMAND_TOPIC,
CONF_MODE_STATE_TOPIC,
CONF_ON_CONTROL,
CONF_ON_STATE,
CONF_PRESET,
CONF_PRESET_COMMAND_TOPIC,
@@ -104,9 +105,40 @@ CLIMATE_SWING_MODES = {
validate_climate_swing_mode = cv.enum(CLIMATE_SWING_MODES, upper=True)
CONF_CURRENT_TEMPERATURE = "current_temperature"
visual_temperature = cv.float_with_unit(
"visual_temperature", "(°C|° C|°|C|° K|° K|K|°F|° F|F)?"
)
def single_visual_temperature(value):
if isinstance(value, dict):
return value
value = visual_temperature(value)
return VISUAL_TEMPERATURE_STEP_SCHEMA(
{
CONF_TARGET_TEMPERATURE: value,
CONF_CURRENT_TEMPERATURE: value,
}
)
# Actions
ControlAction = climate_ns.class_("ControlAction", automation.Action)
StateTrigger = climate_ns.class_("StateTrigger", automation.Trigger.template())
ControlTrigger = climate_ns.class_("ControlTrigger", automation.Trigger.template())
VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Any(
single_visual_temperature,
cv.Schema(
{
cv.Required(CONF_TARGET_TEMPERATURE): visual_temperature,
cv.Required(CONF_CURRENT_TEMPERATURE): visual_temperature,
}
),
)
CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
{
@@ -116,9 +148,7 @@ CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).
{
cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
cv.Optional(CONF_TEMPERATURE_STEP): cv.float_with_unit(
"visual_temperature", "(°C|° C|°|C|° K|° K|K|°F|° F|F)?"
),
cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA,
}
),
cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All(
@@ -175,6 +205,11 @@ CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).
cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic
),
cv.Optional(CONF_ON_CONTROL): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger),
}
),
cv.Optional(CONF_ON_STATE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
@@ -193,7 +228,12 @@ async def setup_climate_core_(var, config):
if CONF_MAX_TEMPERATURE in visual:
cg.add(var.set_visual_max_temperature_override(visual[CONF_MAX_TEMPERATURE]))
if CONF_TEMPERATURE_STEP in visual:
cg.add(var.set_visual_temperature_step_override(visual[CONF_TEMPERATURE_STEP]))
cg.add(
var.set_visual_temperature_step_override(
visual[CONF_TEMPERATURE_STEP][CONF_TARGET_TEMPERATURE],
visual[CONF_TEMPERATURE_STEP][CONF_CURRENT_TEMPERATURE],
)
)
if CONF_MQTT_ID in config:
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
@@ -284,6 +324,10 @@ async def setup_climate_core_(var, config):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_CONTROL, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
async def register_climate(var, config):
if not CORE.has_id(config[CONF_ID]):
@@ -299,7 +343,7 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
cv.Optional(CONF_TARGET_TEMPERATURE): cv.templatable(cv.temperature),
cv.Optional(CONF_TARGET_TEMPERATURE_LOW): cv.templatable(cv.temperature),
cv.Optional(CONF_TARGET_TEMPERATURE_HIGH): cv.templatable(cv.temperature),
cv.Optional(CONF_AWAY): cv.templatable(cv.boolean),
cv.Optional(CONF_AWAY): cv.invalid("Use preset instead"),
cv.Exclusive(CONF_FAN_MODE, "fan_mode"): cv.templatable(
validate_climate_fan_mode
),
@@ -335,9 +379,6 @@ async def climate_control_to_code(config, action_id, template_arg, args):
config[CONF_TARGET_TEMPERATURE_HIGH], args, float
)
cg.add(var.set_target_temperature_high(template_))
if CONF_AWAY in config:
template_ = await cg.templatable(config[CONF_AWAY], args, bool)
cg.add(var.set_away(template_))
if CONF_FAN_MODE in config:
template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode)
cg.add(var.set_fan_mode(template_))

View File

@@ -42,6 +42,13 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
Climate *climate_;
};
class ControlTrigger : public Trigger<> {
public:
ControlTrigger(Climate *climate) {
climate->add_on_control_callback([this]() { this->trigger(); });
}
};
class StateTrigger : public Trigger<> {
public:
StateTrigger(Climate *climate) {

View File

@@ -44,6 +44,7 @@ void ClimateCall::perform() {
if (this->target_temperature_high_.has_value()) {
ESP_LOGD(TAG, " Target Temperature High: %.2f", *this->target_temperature_high_);
}
this->parent_->control_callback_.call();
this->parent_->control(*this);
}
void ClimateCall::validate_() {
@@ -263,25 +264,11 @@ const optional<ClimateMode> &ClimateCall::get_mode() const { return this->mode_;
const optional<float> &ClimateCall::get_target_temperature() const { return this->target_temperature_; }
const optional<float> &ClimateCall::get_target_temperature_low() const { return this->target_temperature_low_; }
const optional<float> &ClimateCall::get_target_temperature_high() const { return this->target_temperature_high_; }
optional<bool> ClimateCall::get_away() const {
if (!this->preset_.has_value())
return {};
return *this->preset_ == ClimatePreset::CLIMATE_PRESET_AWAY;
}
const optional<ClimateFanMode> &ClimateCall::get_fan_mode() const { return this->fan_mode_; }
const optional<std::string> &ClimateCall::get_custom_fan_mode() const { return this->custom_fan_mode_; }
const optional<ClimatePreset> &ClimateCall::get_preset() const { return this->preset_; }
const optional<std::string> &ClimateCall::get_custom_preset() const { return this->custom_preset_; }
const optional<ClimateSwingMode> &ClimateCall::get_swing_mode() const { return this->swing_mode_; }
ClimateCall &ClimateCall::set_away(bool away) {
this->preset_ = away ? CLIMATE_PRESET_AWAY : CLIMATE_PRESET_HOME;
return *this;
}
ClimateCall &ClimateCall::set_away(optional<bool> away) {
if (away.has_value())
this->preset_ = *away ? CLIMATE_PRESET_AWAY : CLIMATE_PRESET_HOME;
return *this;
}
ClimateCall &ClimateCall::set_target_temperature_high(optional<float> target_temperature_high) {
this->target_temperature_high_ = target_temperature_high;
return *this;
@@ -317,6 +304,10 @@ void Climate::add_on_state_callback(std::function<void()> &&callback) {
this->state_callback_.add(std::move(callback));
}
void Climate::add_on_control_callback(std::function<void()> &&callback) {
this->control_callback_.add(std::move(callback));
}
// Random 32bit value; If this changes existing restore preferences are invalidated
static const uint32_t RESTORE_STATE_VERSION = 0x848EA6ADUL;
@@ -430,9 +421,11 @@ ClimateTraits Climate::get_traits() {
if (this->visual_max_temperature_override_.has_value()) {
traits.set_visual_max_temperature(*this->visual_max_temperature_override_);
}
if (this->visual_temperature_step_override_.has_value()) {
traits.set_visual_temperature_step(*this->visual_temperature_step_override_);
if (this->visual_target_temperature_step_override_.has_value()) {
traits.set_visual_target_temperature_step(*this->visual_target_temperature_step_override_);
traits.set_visual_current_temperature_step(*this->visual_current_temperature_step_override_);
}
return traits;
}
@@ -442,15 +435,11 @@ void Climate::set_visual_min_temperature_override(float visual_min_temperature_o
void Climate::set_visual_max_temperature_override(float visual_max_temperature_override) {
this->visual_max_temperature_override_ = visual_max_temperature_override;
}
void Climate::set_visual_temperature_step_override(float visual_temperature_step_override) {
this->visual_temperature_step_override_ = visual_temperature_step_override;
void Climate::set_visual_temperature_step_override(float target, float current) {
this->visual_target_temperature_step_override_ = target;
this->visual_current_temperature_step_override_ = current;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Climate::Climate(const std::string &name) : EntityBase(name) {}
#pragma GCC diagnostic pop
Climate::Climate() : Climate("") {}
ClimateCall Climate::make_call() { return ClimateCall(this); }
ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) {
@@ -541,7 +530,9 @@ void Climate::dump_traits_(const char *tag) {
ESP_LOGCONFIG(tag, " [x] Visual settings:");
ESP_LOGCONFIG(tag, " - Min: %.1f", traits.get_visual_min_temperature());
ESP_LOGCONFIG(tag, " - Max: %.1f", traits.get_visual_max_temperature());
ESP_LOGCONFIG(tag, " - Step: %.1f", traits.get_visual_temperature_step());
ESP_LOGCONFIG(tag, " - Step:");
ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step());
ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step());
if (traits.get_supports_current_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports current temperature");
}

View File

@@ -64,10 +64,6 @@ class ClimateCall {
* For climate devices with two point target temperature control
*/
ClimateCall &set_target_temperature_high(optional<float> target_temperature_high);
ESPDEPRECATED("set_away() is deprecated, please use .set_preset(CLIMATE_PRESET_AWAY) instead", "v1.20")
ClimateCall &set_away(bool away);
ESPDEPRECATED("set_away() is deprecated, please use .set_preset(CLIMATE_PRESET_AWAY) instead", "v1.20")
ClimateCall &set_away(optional<bool> away);
/// Set the fan mode of the climate device.
ClimateCall &set_fan_mode(ClimateFanMode fan_mode);
/// Set the fan mode of the climate device.
@@ -97,8 +93,6 @@ class ClimateCall {
const optional<float> &get_target_temperature() const;
const optional<float> &get_target_temperature_low() const;
const optional<float> &get_target_temperature_high() const;
ESPDEPRECATED("get_away() is deprecated, please use .get_preset() instead", "v1.20")
optional<bool> get_away() const;
const optional<ClimateFanMode> &get_fan_mode() const;
const optional<ClimateSwingMode> &get_swing_mode() const;
const optional<std::string> &get_custom_fan_mode() const;
@@ -166,11 +160,6 @@ struct ClimateDeviceRestoreState {
*/
class Climate : public EntityBase {
public:
/// Construct a climate device with empty name (will be set later).
Climate();
/// Construct a climate device with a name.
Climate(const std::string &name);
/// The active mode of the climate device.
ClimateMode mode{CLIMATE_MODE_OFF};
/// The active state of the climate device.
@@ -189,14 +178,6 @@ class Climate : public EntityBase {
};
};
/** Whether the climate device is in away mode.
*
* Away allows climate devices to have two different target temperature configs:
* one for normal mode and one for away mode.
*/
ESPDEPRECATED("away is deprecated, use preset instead", "v1.20")
bool away{false};
/// The active fan mode of the climate device.
optional<ClimateFanMode> fan_mode;
@@ -219,6 +200,14 @@ class Climate : public EntityBase {
*/
void add_on_state_callback(std::function<void()> &&callback);
/**
* Add a callback for the climate device configuration; each time the configuration parameters of a climate device
* is updated (using perform() of a ClimateCall), this callback will be called, before any on_state callback.
*
* @param callback The callback to call.
*/
void add_on_control_callback(std::function<void()> &&callback);
/** Make a climate device control call, this is used to control the climate device, see the ClimateCall description
* for more info.
* @return A new ClimateCall instance targeting this climate device.
@@ -241,7 +230,7 @@ class Climate : public EntityBase {
void set_visual_min_temperature_override(float visual_min_temperature_override);
void set_visual_max_temperature_override(float visual_max_temperature_override);
void set_visual_temperature_step_override(float visual_temperature_step_override);
void set_visual_temperature_step_override(float target, float current);
protected:
friend ClimateCall;
@@ -285,10 +274,12 @@ class Climate : public EntityBase {
void dump_traits_(const char *tag);
CallbackManager<void()> state_callback_{};
CallbackManager<void()> control_callback_{};
ESPPreferenceObject rtc_;
optional<float> visual_min_temperature_override_{};
optional<float> visual_max_temperature_override_{};
optional<float> visual_temperature_step_override_{};
optional<float> visual_target_temperature_step_override_{};
optional<float> visual_current_temperature_step_override_{};
};
} // namespace climate

View File

@@ -3,8 +3,12 @@
namespace esphome {
namespace climate {
int8_t ClimateTraits::get_temperature_accuracy_decimals() const {
return step_to_accuracy_decimals(this->visual_temperature_step_);
int8_t ClimateTraits::get_target_temperature_accuracy_decimals() const {
return step_to_accuracy_decimals(this->visual_target_temperature_step_);
}
int8_t ClimateTraits::get_current_temperature_accuracy_decimals() const {
return step_to_accuracy_decimals(this->visual_current_temperature_step_);
}
} // namespace climate

View File

@@ -117,15 +117,6 @@ class ClimateTraits {
bool supports_custom_preset(const std::string &custom_preset) const {
return supported_custom_presets_.count(custom_preset);
}
ESPDEPRECATED("This method is deprecated, use set_supported_presets() instead", "v1.20")
void set_supports_away(bool supports) {
if (supports) {
supported_presets_.insert(CLIMATE_PRESET_AWAY);
supported_presets_.insert(CLIMATE_PRESET_HOME);
}
}
ESPDEPRECATED("This method is deprecated, use supports_preset() instead", "v1.20")
bool get_supports_away() const { return supports_preset(CLIMATE_PRESET_AWAY); }
void set_supported_swing_modes(std::set<ClimateSwingMode> modes) { supported_swing_modes_ = std::move(modes); }
void add_supported_swing_mode(ClimateSwingMode mode) { supported_swing_modes_.insert(mode); }
@@ -147,9 +138,20 @@ class ClimateTraits {
void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; }
float get_visual_max_temperature() const { return visual_max_temperature_; }
void set_visual_max_temperature(float visual_max_temperature) { visual_max_temperature_ = visual_max_temperature; }
float get_visual_temperature_step() const { return visual_temperature_step_; }
int8_t get_temperature_accuracy_decimals() const;
void set_visual_temperature_step(float temperature_step) { visual_temperature_step_ = temperature_step; }
float get_visual_target_temperature_step() const { return visual_target_temperature_step_; }
float get_visual_current_temperature_step() const { return visual_current_temperature_step_; }
void set_visual_target_temperature_step(float temperature_step) {
visual_target_temperature_step_ = temperature_step;
}
void set_visual_current_temperature_step(float temperature_step) {
visual_current_temperature_step_ = temperature_step;
}
void set_visual_temperature_step(float temperature_step) {
visual_target_temperature_step_ = temperature_step;
visual_current_temperature_step_ = temperature_step;
}
int8_t get_target_temperature_accuracy_decimals() const;
int8_t get_current_temperature_accuracy_decimals() const;
protected:
void set_mode_support_(climate::ClimateMode mode, bool supported) {
@@ -186,7 +188,8 @@ class ClimateTraits {
float visual_min_temperature_{10};
float visual_max_temperature_{30};
float visual_temperature_step_{0.1};
float visual_target_temperature_step_{0.1};
float visual_current_temperature_step_{0.1};
};
} // namespace climate

View File

@@ -10,23 +10,42 @@ CONF_RED_INT = "red_int"
CONF_GREEN_INT = "green_int"
CONF_BLUE_INT = "blue_int"
CONF_WHITE_INT = "white_int"
CONFIG_SCHEMA = cv.Schema(
{
cv.Required(CONF_ID): cv.declare_id(ColorStruct),
cv.Exclusive(CONF_RED, "red"): cv.percentage,
cv.Exclusive(CONF_RED_INT, "red"): cv.uint8_t,
cv.Exclusive(CONF_GREEN, "green"): cv.percentage,
cv.Exclusive(CONF_GREEN_INT, "green"): cv.uint8_t,
cv.Exclusive(CONF_BLUE, "blue"): cv.percentage,
cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t,
cv.Exclusive(CONF_WHITE, "white"): cv.percentage,
cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t,
}
).extend(cv.COMPONENT_SCHEMA)
CONF_HEX = "hex"
async def to_code(config):
def hex_color(value):
if len(value) != 6:
raise cv.Invalid("Color must have six digits")
try:
return (int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16))
except ValueError as exc:
raise cv.Invalid("Color must be hexadecimal") from exc
CONFIG_SCHEMA = cv.Any(
cv.Schema(
{
cv.Required(CONF_ID): cv.declare_id(ColorStruct),
cv.Exclusive(CONF_RED, "red"): cv.percentage,
cv.Exclusive(CONF_RED_INT, "red"): cv.uint8_t,
cv.Exclusive(CONF_GREEN, "green"): cv.percentage,
cv.Exclusive(CONF_GREEN_INT, "green"): cv.uint8_t,
cv.Exclusive(CONF_BLUE, "blue"): cv.percentage,
cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t,
cv.Exclusive(CONF_WHITE, "white"): cv.percentage,
cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t,
}
).extend(cv.COMPONENT_SCHEMA),
cv.Schema(
{
cv.Required(CONF_ID): cv.declare_id(ColorStruct),
cv.Required(CONF_HEX): hex_color,
}
).extend(cv.COMPONENT_SCHEMA),
)
def from_rgbw(config):
r = 0
if CONF_RED in config:
r = int(config[CONF_RED] * 255)
@@ -51,6 +70,16 @@ async def to_code(config):
elif CONF_WHITE_INT in config:
w = config[CONF_WHITE_INT]
return (r, g, b, w)
async def to_code(config):
if CONF_HEX in config:
r, g, b = config[CONF_HEX]
w = 0
else:
r, g, b, w = from_rgbw(config)
cg.new_variable(
config[CONF_ID],
cg.StructInitializer(ColorStruct, ("r", r), ("g", g), ("b", b), ("w", w)),

View File

@@ -16,10 +16,9 @@ CopyButton = copy_ns.class_("CopyButton", button.Button, cg.Component)
CONFIG_SCHEMA = (
button.button_schema()
button.button_schema(CopyButton)
.extend(
{
cv.GenerateID(): cv.declare_id(CopyButton),
cv.Required(CONF_SOURCE_ID): cv.use_id(button.Button),
}
)

View File

@@ -28,6 +28,7 @@ cover::CoverTraits CopyCover::get_traits() {
// copy traits manually so it doesn't break when new options are added
// but the control() method hasn't implemented them yet.
traits.set_is_assumed_state(base.get_is_assumed_state());
traits.set_supports_stop(base.get_supports_stop());
traits.set_supports_position(base.get_supports_position());
traits.set_supports_tilt(base.get_supports_tilt());
traits.set_supports_toggle(base.get_supports_toggle());

View File

@@ -15,12 +15,15 @@ from .. import copy_ns
CopyNumber = copy_ns.class_("CopyNumber", number.Number, cg.Component)
CONFIG_SCHEMA = number.NUMBER_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(CopyNumber),
cv.Required(CONF_SOURCE_ID): cv.use_id(number.Number),
}
).extend(cv.COMPONENT_SCHEMA)
CONFIG_SCHEMA = (
number.number_schema(CopyNumber)
.extend(
{
cv.Required(CONF_SOURCE_ID): cv.use_id(number.Number),
}
)
.extend(cv.COMPONENT_SCHEMA)
)
FINAL_VALIDATE_SCHEMA = cv.All(
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),

View File

@@ -14,12 +14,15 @@ from .. import copy_ns
CopySelect = copy_ns.class_("CopySelect", select.Select, cg.Component)
CONFIG_SCHEMA = select.SELECT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(CopySelect),
cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select),
}
).extend(cv.COMPONENT_SCHEMA)
CONFIG_SCHEMA = (
select.select_schema(CopySelect)
.extend(
{
cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select),
}
)
.extend(cv.COMPONENT_SCHEMA)
)
FINAL_VALIDATE_SCHEMA = cv.All(
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),

View File

@@ -17,6 +17,17 @@ from esphome.const import (
CONF_STOP,
CONF_MQTT_ID,
CONF_TRIGGER_ID,
DEVICE_CLASS_AWNING,
DEVICE_CLASS_BLIND,
DEVICE_CLASS_CURTAIN,
DEVICE_CLASS_DAMPER,
DEVICE_CLASS_DOOR,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_GARAGE,
DEVICE_CLASS_GATE,
DEVICE_CLASS_SHADE,
DEVICE_CLASS_SHUTTER,
DEVICE_CLASS_WINDOW,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.cpp_helpers import setup_entity
@@ -25,17 +36,17 @@ IS_PLATFORM_COMPONENT = True
CODEOWNERS = ["@esphome/core"]
DEVICE_CLASSES = [
"",
"awning",
"blind",
"curtain",
"damper",
"door",
"garage",
"gate",
"shade",
"shutter",
"window",
DEVICE_CLASS_AWNING,
DEVICE_CLASS_BLIND,
DEVICE_CLASS_CURTAIN,
DEVICE_CLASS_DAMPER,
DEVICE_CLASS_DOOR,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_GARAGE,
DEVICE_CLASS_GATE,
DEVICE_CLASS_SHADE,
DEVICE_CLASS_SHUTTER,
DEVICE_CLASS_WINDOW,
]
cover_ns = cg.esphome_ns.namespace("cover")

View File

@@ -31,7 +31,7 @@ const char *cover_operation_to_str(CoverOperation op) {
}
}
Cover::Cover(const std::string &name) : EntityBase(name), position{COVER_OPEN} {}
Cover::Cover() : position{COVER_OPEN} {}
CoverCall::CoverCall(Cover *parent) : parent_(parent) {}
CoverCall &CoverCall::set_command(const char *command) {
@@ -145,7 +145,7 @@ CoverCall &CoverCall::set_stop(bool stop) {
return *this;
}
bool CoverCall::get_stop() const { return this->stop_; }
void Cover::set_device_class(const std::string &device_class) { this->device_class_override_ = device_class; }
CoverCall Cover::make_call() { return {this}; }
void Cover::open() {
auto call = this->make_call();
@@ -204,18 +204,9 @@ optional<CoverRestoreState> Cover::restore_state_() {
return {};
return recovered;
}
Cover::Cover() : Cover("") {}
std::string Cover::get_device_class() {
if (this->device_class_override_.has_value())
return *this->device_class_override_;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return this->device_class();
#pragma GCC diagnostic pop
}
bool Cover::is_fully_open() const { return this->position == COVER_OPEN; }
bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; }
std::string Cover::device_class() { return ""; }
CoverCall CoverRestoreState::to_call(Cover *cover) {
auto call = cover->make_call();

View File

@@ -108,10 +108,9 @@ const char *cover_operation_to_str(CoverOperation op);
* to control all values of the cover. Also implement get_traits() to return what operations
* the cover supports.
*/
class Cover : public EntityBase {
class Cover : public EntityBase, public EntityBase_DeviceClass {
public:
explicit Cover();
explicit Cover(const std::string &name);
/// The current operation of the cover (idle, opening, closing).
CoverOperation current_operation{COVER_OPERATION_IDLE};
@@ -157,8 +156,6 @@ class Cover : public EntityBase {
void publish_state(bool save = true);
virtual CoverTraits get_traits() = 0;
void set_device_class(const std::string &device_class);
std::string get_device_class();
/// Helper method to check if the cover is fully open. Equivalent to comparing .position against 1.0
bool is_fully_open() const;
@@ -170,16 +167,9 @@ class Cover : public EntityBase {
virtual void control(const CoverCall &call) = 0;
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
virtual std::string device_class();
optional<CoverRestoreState> restore_state_();
CallbackManager<void()> state_callback_{};
optional<std::string> device_class_override_{};
ESPPreferenceObject rtc_;
};

View File

@@ -15,12 +15,15 @@ class CoverTraits {
void set_supports_tilt(bool supports_tilt) { this->supports_tilt_ = supports_tilt; }
bool get_supports_toggle() const { return this->supports_toggle_; }
void set_supports_toggle(bool supports_toggle) { this->supports_toggle_ = supports_toggle; }
bool get_supports_stop() const { return this->supports_stop_; }
void set_supports_stop(bool supports_stop) { this->supports_stop_ = supports_stop; }
protected:
bool is_assumed_state_{false};
bool supports_position_{false};
bool supports_tilt_{false};
bool supports_toggle_{false};
bool supports_stop_{false};
};
} // namespace cover

View File

@@ -305,7 +305,7 @@ bool CS5460AComponent::check_status_() {
voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_);
if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) {
int32_t raw = (int32_t)(raw_energy << 8) >> 8; /* Sign-extend */
int32_t raw = (int32_t) (raw_energy << 8) >> 8; /* Sign-extend */
power_sensor_->publish_state(raw * power_multiplier_);
prev_raw_energy_ = raw_energy;
}

View File

@@ -33,7 +33,10 @@ void CTClampSensor::update() {
const float rms_ac_dc_squared = this->sample_squared_sum_ / this->num_samples_;
const float rms_dc = this->sample_sum_ / this->num_samples_;
const float rms_ac = std::sqrt(rms_ac_dc_squared - rms_dc * rms_dc);
const float rms_ac_squared = rms_ac_dc_squared - rms_dc * rms_dc;
float rms_ac = 0;
if (rms_ac_squared > 0)
rms_ac = std::sqrt(rms_ac_squared);
ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac,
this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_);
this->publish_state(rms_ac);

View File

@@ -12,6 +12,7 @@ using namespace esphome::cover;
CoverTraits CurrentBasedCover::get_traits() {
auto traits = CoverTraits();
traits.set_supports_stop(true);
traits.set_supports_position(true);
traits.set_supports_toggle(true);
traits.set_is_assumed_state(false);

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