Compare commits

...

265 Commits

Author SHA1 Message Date
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
63db42a1d4 Merge pull request #4536 from esphome/bump-2023.3.0b1
2023.3.0b1
2023-03-09 10:43:40 +13:00
Jesse Hills
f58ffe41f8 Bump version to 2023.3.0b1 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
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
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
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
Jesse Hills
7665e9b076 Merge pull request #4433 from esphome/bump-2023.2.0b5
2023.2.0b5
2023-02-14 14:51:00 +13:00
Jesse Hills
227d94f38d Bump version to 2023.2.0b5 2023-02-14 13:59:49 +13:00
Sergey Dudanov
b724ae9e0e Fix setting wrong traits on midea climate component (#4425)
* Fix issue3914

* Remove also default presets and modes

* Fix traits after autoconf
2023-02-14 13:59:49 +13:00
Jesse Hills
df6cc14201 Bump esphome-dashboard to 20230214.0 (#4431) 2023-02-14 13:59:49 +13:00
Jesse Hills
d981d7859d Handle uart.write in json-config endpoint (#4430) 2023-02-14 13:59:49 +13:00
Jesse Hills
0f1ec515c1 Add version api endpoint (#4429) 2023-02-14 13:59:49 +13:00
WitchKing
78e18256f7 Ledc fix (#4338) 2023-02-14 13:59:49 +13: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
Jesse Hills
4899dfe642 Merge pull request #4423 from esphome/bump-2023.2.0b4
2023.2.0b4
2023-02-13 15:17:05 +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
Jesse Hills
d6b6e94059 Bump version to 2023.2.0b4 2023-02-13 11:54:27 +13:00
NP v/d Spek
310355a00b Fix check for empty clipping array (#4421) 2023-02-13 11:54:26 +13:00
NP v/d Spek
8cf26d6f3c 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-13 11:54:26 +13:00
Patrick Collins
b15a10f905 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-13 11:54:26 +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
5dcf1debd7 Merge pull request #4406 from esphome/bump-2023.2.0b3
2023.2.0b3
2023-02-09 18:04:35 +13:00
Jesse Hills
9b57e1ac1d Bump version to 2023.2.0b3 2023-02-09 17:38:54 +13:00
Jesse Hills
68683e3a50 Fix release workflow (#4405) 2023-02-09 17:38:54 +13:00
Jesse Hills
4d192c7387 Fix release workflow (#4405) 2023-02-09 17:37:55 +13:00
Jesse Hills
d83324c4dc Merge pull request #4404 from esphome/bump-2023.2.0b2
2023.2.0b2
2023-02-09 16:55:48 +13:00
Jesse Hills
ecde4c1d2d Bump version to 2023.2.0b2 2023-02-09 16:27:25 +13:00
Jesse Hills
bd8e470726 Bump curl version in docker (#4403) 2023-02-09 16:27:24 +13:00
Jesse Hills
9dd01b30bd Bump curl version in docker (#4403) 2023-02-09 16:26:06 +13:00
Jesse Hills
d2913fe627 Merge pull request #4402 from esphome/bump-2023.2.0b1
2023.2.0b1
2023-02-09 15:59:06 +13:00
Jesse Hills
881cd535b9 Bump version to 2023.3.0-dev 2023-02-09 15:33:02 +13:00
Jesse Hills
43acc7dc2c Bump version to 2023.2.0b1 2023-02-09 15:33:02 +13:00
Jesse Hills
e2a16d758b Merge branch 'dev' into bump-2023.2.0b1 2023-02-09 15:33:01 +13:00
Paulus Schoutsen
17ea0efb08 Verify rel_path output is relative (#4247) 2023-02-08 20:20:30 -05:00
Paulus Schoutsen
2fbd33267e Convert secrets constant to a tuple (#4245) 2023-02-09 14:00:58 +13:00
Jesse Hills
cf3977f088 Use the github-script action to call the workflow (#4400) 2023-02-08 19:51:24 -05:00
Paulus Schoutsen
d20d4947ac Remove unused manifest handler (#4169)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-09 13:41:59 +13:00
Eric van Blokland
7810ad40d7 Added CanalSat and CanalSatLD protocol support (#3513)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-09 13:22:05 +13:00
jmichiel
7e1e799b3a add MQTT preset support for Climate components (#4379)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Michiel, Jeroen <jeroen.michiel@teledyneflir.com>
2023-02-09 12:46:01 +13:00
Michael Muré
dfafc41ce6 climate: add support for quiet fan mode (#3609) 2023-02-09 11:28:16 +13:00
Bob Perciaccante
e460792c43 Add support for Lippert LP sensors in mopeka_pro_check component (#4118)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
fixes https://github.com/esphome/feature-requests/issues/1988
2023-02-09 11:07:41 +13:00
Jesse Hills
a9dc491a54 Dont keep logging on improv start (#4401) 2023-02-09 10:25:57 +13:00
Jesse Hills
ac6693f177 mDNS updates (#4399) 2023-02-09 10:25:44 +13:00
Jesse Hills
c6742117d3 Update log for mics4514 to state 3 minute start time. (#4396) 2023-02-09 07:30:19 +13:00
Jesse Hills
b5c47b9669 Update ld2410 logging (#4395) 2023-02-09 07:30:00 +13:00
Quentin Smith
40df3aa55e Merge components in packages (#3555)
Co-authored-by: Paul Monigatti <pm@paul.pm>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-07 14:08:40 +13:00
tomaszduda23
393ca64d70 adds gpio INPUT_OUTPUT_OPEN_DRAIN (#4360)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-07 12:55:35 +13:00
Michał Obrembski
d3627f0972 Added Ethernet Component for ESP IDF with JL1101 PHY driver (#4009)
Co-authored-by: Michał Obrembski <michal@obrembski.com>
2023-02-07 12:54:59 +13:00
Trevor North
124ab31f22 Fix shelly dimmer current sensor device class (#4385)
fixes https://github.com/esphome/issues/issues/4086
2023-02-07 12:46:06 +13:00
Jesse Hills
1b66fa5004 Remove unneeded validation for esp32 gpio pins (#4394) 2023-02-07 12:43:30 +13:00
alexd321
9494c27ad8 modify SGP4X integration to report device_class as air quality index (#4327) 2023-02-07 12:35:09 +13:00
Jesse Hills
3facfa5c21 Allow dashboard import to specify if api encryption key should be generated (#4393) 2023-02-07 12:27:07 +13:00
Samuel Sieb
93ddce2e79 add Resol VBus support (#3976)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
fixes https://github.com/esphome/feature-requests/issues/1949
2023-02-07 12:17:17 +13:00
sebcaps
0bf6e21e1a Add Ld2410 Support (#3919)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-07 11:47:50 +13:00
Florian Trück
6b7b076875 SCD30 Added support for manual calibration (#4362)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-02-03 21:13:27 +13:00
Florian idB
8d6ffb9169 Update sim800l.cpp (#4223) 2023-02-03 07:53:46 +13:00
Jesse Hills
e95d6041d8 Allow final validate of uart stop bits and parity (#4376) 2023-02-02 19:34:25 +13:00
Joakim Plate
0554b06b7e Allow mdns services to be exposed by config (#4202) 2023-02-02 17:18:58 +13:00
Carlos Garcia Saura
e3d9c44bdc Fix pressure compensation in SCD4X (#4357) 2023-02-02 13:22:23 +13:00
Jesse Hills
e847766514 Dump full parsed config to json-config api call (#4373) 2023-02-01 16:59:51 +13:00
Jesse Hills
d4a8df04b8 Bump version to 2023.2.0-dev 2023-02-01 15:57:45 +13:00
Mat931
034b47c23a Fix "BLE server / advertising always on" (#4353) 2023-01-27 08:09:22 +13:00
Franck Nijhof
3e017efa30 Add Home Assistant integration discovery (#4328) 2023-01-26 17:48:04 +01:00
WitchKing
aca56fcdcc Added support for ADS1015 (#4281)
Co-authored-by: vilrexa-at-412611259294 <pdzBdl8EkgUikpOWsRCKzTVHMEX2wLnZJRdLhK38oNk=>
2023-01-26 17:20:45 +13:00
melyux
e778a445d9 Add a soft reset in setup() for bmp280 (#4329)
fixes https://github.com/esphome/issues/issues/3383
2023-01-26 12:11:10 +13:00
Alex
ded86493c2 Fix BME280 initialization before wifi setup (#4190)
fixes https://github.com/esphome/issues/issues/3530
2023-01-26 12:09:38 +13:00
Stephan Martin
4d72eb42a5 rename esp32 CAN to TWAI, so it compiles again (#4334)
fixes https://github.com/esphome/issues/issues/4023
2023-01-26 12:08:55 +13:00
Denis Bodor (aka Lefinnois)
267f0587c6 fix stepper jump back with small steps (#4339) 2023-01-26 12:06:46 +13:00
Jesse Hills
4a374a466a Fix in ble client base address parsing (#4347) 2023-01-26 12:02:53 +13:00
Joakim Sørensen
b27a328d1e Add "content" to deploy-ha-addon-repo dispatch (#4349) 2023-01-26 11:55:06 +13:00
Jesse Hills
d94e9d92ca Fix esp32_ble_tracker setup priority (#4346) 2023-01-26 07:56:36 +13:00
Jesse Hills
36c2e770bf Remove state class from uptime sensor (#4345) 2023-01-25 15:58:47 +13:00
Jesse Hills
79040c116d Add next_url to improv serial component config (#4343) 2023-01-25 14:37:01 +13:00
Jesse Hills
4aac76c549 Refactor esp32_ble_tracker to use esp32_ble core ble setup code (#4173) 2023-01-25 14:36:30 +13:00
Jesse Hills
0ea97df1af Add MICS-4514 gas sensor (#4316) 2023-01-25 09:58:44 +13:00
Jesse Hills
92e66a2764 Dont fail workflows if lint building fails (#4336) 2023-01-24 12:51:14 +13:00
J. Nick Koston
615d591367 Always send the MTU request for BLE v3 cached connections (#4322)
closes https://github.com/esphome/esphome/pull/4321
fixes https://github.com/esphome/issues/issues/4041
fixes https://github.com/esphome/issues/issues/3951
2023-01-20 18:31:00 +13:00
Jesse Hills
e236c53f05 Fix missing s 2023-01-20 14:06:47 +13:00
Jesse Hills
10c7055b41 Move from docker manifest command to buildx with platforms (#4320) 2023-01-20 14:01:29 +13:00
functionpointer
a127e60e1b Hydreon: Use new device classes water and precipitation_intensity (#3993)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-01-20 13:56:26 +13:00
Jesse Hills
66a3361e9d Bump esphome-dashboard to 20230120.0 (#4319) 2023-01-20 11:29:37 +13:00
Paulus Schoutsen
13cfe11a19 Add upload dashboard api (#4318) 2023-01-20 09:28:28 +13:00
Stroe Andrei Catalin
6d65671f92 Add friendly name in MDNS records if it is not empty (#4317) 2023-01-20 09:13:18 +13:00
Jesse Hills
f2eafa8fbe Add macro for sub sensor defining (#4315) 2023-01-19 17:36:43 +13:00
Jesse Hills
e4ca3b18cc Format docker/build.py (#4313) 2023-01-19 12:04:51 +13:00
Franck Nijhof
84698ae888 Refactor NGINX configuration of Home Assistant Add-on (#4312) 2023-01-18 19:54:27 +01:00
Franck Nijhof
fd6d6cfb6c Migrate old-style S6 scripts to s6-rc.d (#4311) 2023-01-18 18:22:35 +01:00
Franck Nijhof
8cad9dfc83 Upgrades add-on base image to 6.2.0 (#4310) 2023-01-18 17:23:35 +01:00
Samuel Sieb
5e2f33fde5 add Wiegand reader component (#4288)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-01-18 14:37:54 +13:00
Dan Jackson
029ac75a04 set_retry: add retries remaining parameter to the provided function (#4251) 2023-01-18 14:26:32 +13:00
Valentin Ochs
3aa5953cd9 Implement a slow sigma-delta modulation based output (#4132) 2023-01-18 13:42:32 +13:00
Stanislav Habich
582d90ad72 PCA9685, fix reset device and add option EXTCLK (#3845)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-01-18 13:00:35 +13:00
Mathias Stock
bbb0105c2f Add support for TEE501 (#3773) 2023-01-18 10:43:16 +13:00
Mathias Stock
37d17feecf Add support for HTE501 (#3772) 2023-01-18 10:42:47 +13:00
Mathias Stock
4bf5faf808 Add support for EE895 (#3771) 2023-01-18 10:42:43 +13:00
Z3LIFF
ddedc1cd76 Tsl2591 gain publish (#4291)
fixes https://github.com/esphome/issues/issues/4031
2023-01-18 10:17:31 +13:00
Samuel Sieb
1bb90f304c add key collector component (#4242)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-01-17 17:18:34 +13:00
Jesse Hills
efc6a8df35 Dont default CORE.friendly_name (#4305) 2023-01-17 13:15:47 +13:00
Reuben
e35f90d6e4 Allow 0xA8 ID for APDS9960 (#4287)
fixes https://github.com/esphome/issues/issues/736
2023-01-17 13:14:45 +13:00
Gil Peeters
11518364a1 Display the configured esphome:comment on the WebServer (#4246) 2023-01-17 13:02:54 +13:00
dependabot[bot]
05420291ce Bump aioesphomeapi from 13.0.2 to 13.1.0 (#4301)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-17 12:08:11 +13:00
dependabot[bot]
442faf92c6 Bump pytest from 7.2.0 to 7.2.1 (#4300)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-17 10:37:03 +13:00
Samuel Sieb
62c68f4d60 allow multiple dsmr (#4299)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
fixes https://github.com/esphome/feature-requests/issues/2062
2023-01-17 10:36:44 +13:00
Jesse Hills
c301ae3645 Add friendly_name to device (#4296) 2023-01-17 10:28:09 +13:00
Jesse Hills
3d2d681a7b Remove baud check in tuya dump_config (#4298) 2023-01-16 17:32:15 +13:00
tradeJmark
a45646af1b Calculate PWM wrap dynamically whenever the frequency is changed (#4294)
fixes https://github.com/esphome/issues/issues/3841
2023-01-16 14:17:57 +13:00
Paulus Schoutsen
27185265f6 Clean up dashboard ping result post-rename/delete (#4170) 2023-01-16 13:31:03 +13:00
Joe
a9b7d98194 Fix off-by-one bedjet fan speed (#3873) (#4292)
fixes https://github.com/esphome/issues/issues/3873
2023-01-16 13:27:34 +13:00
J. Nick Koston
ed4a7210d3 Ensure we never write zero bytes (#4284) 2023-01-16 13:24:32 +13:00
Adam Liddell
351ea04517 Fix use of dangling pointers in esp-idf MQTT backend (#4239)
fixes https://github.com/esphome/issues/issues/3406
2023-01-11 16:31:04 +13:00
NP v/d Spek
86a8e1f4a6 small DisplayBuffer images and font update (#4044)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-01-11 14:55:02 +13:00
EtienneMD
1cf3424ebe Add X9C Potentiometer component (#4183)
fixes https://github.com/esphome/feature-requests/issues/1270
2023-01-11 14:51:50 +13:00
Garret Buell
a19f0c0db0 Fix HttpRequestResponseTrigger again (#4285)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
fixes https://github.com/esphome/issues/issues/4010
2023-01-11 14:50:01 +13:00
Garret Buell
530df91044 Fix HttpRequestResponseTrigger (#4270)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
fixes https://github.com/esphome/issues/issues/4010
2023-01-11 12:27:30 +13:00
Stas
c16c0b11cb http_request: add request duration logging (#4272) 2023-01-10 17:40:42 +13:00
Tom Keller
74556b28a8 fix: json compilation error on rp2040 (#4273)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-01-10 17:40:04 +13:00
Joscha Wagner
48340d41d6 Fix frequency limit for MCP9600 (#4276) 2023-01-10 17:39:04 +13:00
dependabot[bot]
6306348379 Bump pylint from 2.15.8 to 2.15.10 (#4278)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 16:46:13 +13:00
Robin Pronk
b1f1329cee Correct decimals in Growatt energy reporting (#4277)
fixes https://github.com/esphome/issues/issues/3888
2023-01-10 16:21:55 +13:00
Fabio Todaro
75dff1e102 Fix Template Switch restore_mode support (#4280)
fixes https://github.com/esphome/issues/issues/4020
2023-01-10 16:20:16 +13:00
Samuel Sieb
fe55f3a43d Add support for matrix keypads (#4241)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-01-10 16:06:54 +13:00
Samuel Sieb
657fd9d0d5 Don't match words containing "id" (#4265)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
fixes https://github.com/esphome/issues/issues/3507
2023-01-10 13:54:15 +13:00
J. Nick Koston
1511a6ebcd Bump zeroconf to 0.47.1 (#4268) 2023-01-09 14:14:06 +13:00
Paulus Schoutsen
ecac26aeba Bump dashboard to 20221231.0 (#4248) 2022-12-31 14:40:50 -05:00
Kuba Szczodrzyński
19bf9b1e36 Add API for dashboard to get boards list by platform (#4168)
* Add API for dashboard to get boards list by platform

* Dashboard API: add board list for ESP32 S2/S3/C3

* Dashboard API: remove endpoint for all boards

* Dashboard API: hide group titles for all platforms

* Dashboard API: fix Python lint

* Dashboard API: refactor /boards to use list output

* Dashboard API: filter boards for selected platform

* Dashboard API: do not duplicate esp32 boards

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2022-12-31 14:02:56 -05:00
brogon
119a6920f2 PCF85063 RTC chip (#3873)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-12-23 12:33:31 +13:00
cstaahl
8237e13c44 Fix broken PULSE_METER (#4199)
fixes https://github.com/esphome/issues/issues/3730
2022-12-23 11:07:45 +13:00
Cossid
53b60ac817 Add support for SM2235 and SM2335 LED drivers (#3924) 2022-12-23 11:04:21 +13:00
Cossid
a18ab748fd Add support for BP1658CJ LED driver (#4020) 2022-12-23 10:39:44 +13:00
Cossid
917488bbc3 Add support for BP5758D LED driver (#4021) 2022-12-23 10:24:46 +13:00
Jesse Hills
7e376ae952 Add precipitation device class (#4219) 2022-12-22 21:18:58 +13:00
myhomeiot
57a1c207c2 Fix saving light state for restore modes LIGHT_RESTORE_AND_OFF/ON (#4131) 2022-12-22 20:57:53 +13:00
tomaszduda23
50e8e92f0b Fix race condition in web_server scheduler on ESP32 (#3951) 2022-12-22 20:51:24 +13:00
Dan Jackson
ff4fd497c4 Component::set_retry updates (#3305) 2022-12-22 20:48:15 +13:00
Martin Flasskamp
33b1a853b9 calc LEDC PWM Resolution with LEDC_TIMER_BIT_MAX (#3820)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
fixes https://github.com/esphome/issues/issues/3128
2022-12-22 20:21:44 +13:00
Jan Grewe
f2df542cb1 Allow ignoring of failed Modbus response CRC (#3930)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-12-22 20:14:11 +13:00
Dave T
ecbbf2d3f4 Ili9341 8bit indexed mode pt2 (#2502) 2022-12-22 19:53:53 +13:00
Matthew Donoughe
b76c7a0131 Use NAN values for TSL2591 saturation (#3931)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-12-22 19:50:37 +13:00
dependabot[bot]
0b0984f9a0 Bump black from 22.10.0 to 22.12.0 (#4167)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-12-22 19:42:49 +13:00
Francisco J. Solis
9767856784 feat: set a wider range for jpeg quality (#3872)
fixes https://github.com/esphome/issues/issues/3570
2022-12-22 19:34:00 +13:00
Maurice Makaay
c1f09684e6 Handle deprecated sdkconfig option (#4204)
Co-authored-by: Maurice Makaay <maurice@h2b.nl>
fixes https://github.com/mmakaay/esphome-xiaomi_bslamp2/issues/104
2022-12-22 19:27:47 +13:00
Jesse Hills
22b384363b Bump nano version in lint docker image (#4218) 2022-12-22 19:07:39 +13:00
dependabot[bot]
5b23331751 Bump pytest-asyncio from 0.20.2 to 0.20.3 (#4164)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-22 18:44:41 +13:00
dependabot[bot]
7a2bb32843 Bump aioesphomeapi from 13.0.1 to 13.0.2 (#4188)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-22 18:40:00 +13:00
Steve Rodgers
c0a4e07e5a Add Pca9554 component (#4192) 2022-12-22 18:39:25 +13:00
dependabot[bot]
322158cccb Bump actions/stale from 6 to 7 (#4217)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-22 16:55:47 +13:00
Jesse Hills
8db3b59e0f Fix gpio pin mode for ISR pins (#4216) 2022-12-21 14:03:00 +13:00
Jesse Hills
0d50caa179 Fix ESP32 GPIO when using INPUT PULLUP mode (#4213) 2022-12-20 23:09:33 +13:00
Deun Lee
8b06135b41 Fix UUID displaying incorrectly in BLE Tracker logs (#4187) 2022-12-19 20:36:16 -08:00
J. Nick Koston
573ea55187 Handle zero padding anywhere in the combined adv data (#4208)
fixes https://github.com/esphome/issues/issues/3913
2022-12-20 10:40:01 +13:00
Jesse Hills
b48b5d6cc7 Fix import_full_config for adoption configs (#4197)
* Fix git raw url

* Fix setting full config query param

* Force dashboard import urls to have a branch or tag reference for full import
2022-12-16 19:46:56 +13:00
Jesse Hills
39af967433 Fix i2s_audio media_player compiling for esp32-s2 (#4195) 2022-12-16 10:38:52 +13:00
Jesse Hills
83b5e01a28 Mark ESP32-S2 as not having Bluetooth (#4194) 2022-12-16 10:09:07 +13:00
Stefan Agner
1eacbd50fa Support non-multiarch toolchains on 32-bit ARM (#4191)
fixes https://github.com/esphome/issues/issues/3904
2022-12-16 09:27:59 +13:00
Jesse Hills
cb520c00a5 Merge pull request #4185 from esphome/bump-2022.12.0b6
2022.12.0b6
2022-12-14 12:24:25 +13:00
Jesse Hills
2f24138345 Bump version to 2022.12.0b6 2022-12-14 12:03:03 +13:00
Jesse Hills
96512b80cc Revert camera config change for esp-idf (#4182) 2022-12-14 12:03:03 +13:00
Jesse Hills
fcb9b51978 Remove warnings when falling through switch cases on purpose (#4181) 2022-12-14 12:03:03 +13:00
Jesse Hills
9bf7c97775 Revert camera config change for esp-idf (#4182) 2022-12-14 11:45:51 +13:00
Jesse Hills
24bf3674f3 Remove warnings when falling through switch cases on purpose (#4181) 2022-12-14 11:45:43 +13:00
Jesse Hills
f408f1a368 Merge pull request #4180 from esphome/bump-2022.12.0b5
2022.12.0b5
2022-12-13 19:42:18 +13:00
Jesse Hills
7d8d563c62 Bump version to 2022.12.0b5 2022-12-13 13:58:44 +13:00
J. Nick Koston
0a1f705fda Speed up bluetooth proxy connections when using esp-idf (#4171) 2022-12-13 13:58:44 +13:00
Jesse Hills
1952c1880b Remove internal pin restriction from cd74hc4067 (#4179) 2022-12-13 13:58:44 +13:00
J. Nick Koston
c47dc09d34 Speed up bluetooth proxy connections when using esp-idf (#4171) 2022-12-13 13:57:12 +13:00
Jesse Hills
db3096c6e1 Remove internal pin restriction from cd74hc4067 (#4179) 2022-12-13 13:44:52 +13:00
Jesse Hills
b03967dac1 Merge pull request #4178 from esphome/bump-2022.12.0b4
2022.12.0b4
2022-12-13 10:14:08 +13:00
Jesse Hills
bcae2596a6 Bump version to 2022.12.0b4 2022-12-13 09:13:28 +13:00
Jesse Hills
fc0347c86c Bump esphome-dashboard to 20221213.0 (#4176) 2022-12-13 09:13:28 +13:00
Jesse Hills
eef578f4b8 Bump esphome-dashboard to 20221213.0 (#4176) 2022-12-13 08:14:18 +13:00
Jesse Hills
d4e232f267 Increase watchdog timeout when starting OTA (#4172) 2022-12-12 16:16:24 +13:00
Björn Stenberg
cc45945fcf climate: Add features to generic Toshiba model (#3912)
Add fan speed modes, dry and fan-only operation modes.
This reduce differences between generic and PT14111 models.
2022-12-08 14:13:10 -06:00
Jesse Hills
0c24d951ff Fix ble parsing with zero padded advertisements (#4162) 2022-12-08 13:39:33 +13:00
John Britton
92e44b8238 Expose lambda action to reset a cycle in slow_pwm (#4158) 2022-12-07 19:27:14 +13:00
Jesse Hills
34387adbcd Bump version to 2023.1.0-dev 2022-12-07 17:00:11 +13:00
443 changed files with 15764 additions and 2909 deletions

View File

@@ -23,6 +23,11 @@ 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
@@ -52,6 +53,10 @@ jobs:
file: tests/test6.yaml
name: Test tests/test6.yaml
pio_cache_key: test6
- id: test
file: tests/test7.yaml
name: Test tests/test7.yaml
pio_cache_key: test7
- id: pytest
name: Run pytest
- id: clang-format
@@ -177,9 +182,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

@@ -30,6 +30,10 @@ jobs:
TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
today="$(date --utc '+%Y%m%d')"
TAG="${TAG}${today}"
BRANCH=${GITHUB_REF#refs/heads/}
if [[ "$BRANCH" != "dev" ]]; then
TAG="${TAG}-${BRANCH}"
fi
fi
echo "tag=${TAG}" >> $GITHUB_OUTPUT
# yamllint enable rule:line-length
@@ -57,17 +61,30 @@ jobs:
run: twine upload dist/*
deploy-docker:
name: Build and publish docker containers
name: Build and publish ESPHome ${{ matrix.image.title}}
if: github.repository == 'esphome/esphome'
permissions:
contents: read
packages: write
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.image.title == 'lint' }}
needs: [init]
strategy:
fail-fast: false
matrix:
arch: [amd64, armv7, aarch64]
build_type: ["ha-addon", "docker", "lint"]
image:
- title: "ha-addon"
suffix: "hassio"
target: "hassio"
baseimg: "hassio"
- title: "docker"
suffix: ""
target: "docker"
baseimg: "docker"
- title: "lint"
suffix: "lint"
target: "lint"
baseimg: "docker"
steps:
- uses: actions/checkout@v3
- name: Set up Python
@@ -92,69 +109,47 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate short tags
id: tags
run: |
docker/generate_tags.py \
--tag "${{ needs.init.outputs.tag }}" \
--suffix "${{ matrix.image.suffix }}"
- name: Build and push
run: |
docker/build.py \
--tag "${{ needs.init.outputs.tag }}" \
--arch "${{ matrix.arch }}" \
--build-type "${{ matrix.build_type }}" \
build \
--push
deploy-docker-manifest:
if: github.repository == 'esphome/esphome'
permissions:
contents: read
packages: write
runs-on: ubuntu-latest
needs: [init, deploy-docker]
strategy:
matrix:
build_type: ["ha-addon", "docker", "lint"]
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
uses: docker/build-push-action@v3
with:
python-version: "3.9"
- name: Enable experimental manifest support
run: |
mkdir -p ~/.docker
echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
- name: Log in to docker hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run manifest
run: |
docker/build.py \
--tag "${{ needs.init.outputs.tag }}" \
--build-type "${{ matrix.build_type }}" \
manifest
context: .
file: ./docker/Dockerfile
platforms: linux/amd64,linux/arm/v7,linux/arm64
target: ${{ matrix.image.target }}
push: true
# yamllint disable rule:line-length
cache-from: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }}
cache-to: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }},mode=max
# yamllint enable rule:line-length
tags: ${{ steps.tags.outputs.tags }}
build-args: |
BASEIMGTYPE=${{ matrix.image.baseimg }}
BUILD_VERSION=${{ needs.init.outputs.tag }}
deploy-ha-addon-repo:
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
runs-on: ubuntu-latest
needs: [deploy-docker]
steps:
- env:
TOKEN: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
# yamllint disable rule:line-length
run: |
TAG="${GITHUB_REF#refs/tags/}"
curl \
-u ":$TOKEN" \
-X POST \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/esphome/home-assistant-addon/actions/workflows/bump-version.yml/dispatches \
-d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}"
# yamllint enable rule:line-length
- name: Trigger Workflow
uses: actions/github-script@v6
with:
github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
script: |
github.rest.actions.createWorkflowDispatch({
owner: "esphome",
repo: "home-assistant-addon",
workflow_id: "bump-version.yml",
ref: "main",
inputs: {
version: "${{ github.event.release.tag_name }}",
content: ${{ toJSON(github.event.release.body) }}
}
})

View File

@@ -18,7 +18,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
- uses: actions/stale@v7
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@v6
- uses: actions/stale@v7
with:
days-before-pr-stale: -1
days-before-pr-close: -1

2
.gitignore vendored
View File

@@ -128,3 +128,5 @@ tests/.esphome/
sdkconfig.*
!sdkconfig.defaults
.tests/

View File

@@ -3,7 +3,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/ambv/black
rev: 22.10.0
rev: 23.1.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.1
hooks:
- id: pyupgrade
args: [--py39-plus]

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
@@ -24,6 +25,7 @@ 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
@@ -41,6 +43,8 @@ esphome/components/ble_client/* @buxtronix
esphome/components/bluetooth_proxy/* @jesserockz
esphome/components/bme680_bsec/* @trvrnrth
esphome/components/bmp3xx/* @martgras
esphome/components/bp1658cj/* @Cossid
esphome/components/bp5758d/* @Cossid
esphome/components/button/* @esphome/core
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @MrEditor97
@@ -69,6 +73,7 @@ esphome/components/display_menu_base/* @numo68
esphome/components/dps310/* @kbx81
esphome/components/ds1307/* @badbadc0ffee
esphome/components/dsmr/* @glmnet @zuidwijk
esphome/components/ee895/* @Stock-M
esphome/components/ektf2232/* @jesserockz
esphome/components/ens210/* @itn3rd77
esphome/components/esp32/* @esphome/core
@@ -87,11 +92,13 @@ 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/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
@@ -100,24 +107,33 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/homeassistant/* @OttoWinter
esphome/components/honeywellabp/* @RubyBailey
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/hte501/* @Stock-M
esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/i2c/* @esphome/core
esphome/components/i2s_audio/* @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
esphome/components/light/* @esphome/core
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core
esphome/components/ltr390/* @sjtrny
esphome/components/matrix_keypad/* @ssieb
esphome/components/max31865/* @DAVe3283
esphome/components/max44009/* @berfenger
esphome/components/max7219digit/* @rspaargaren
@@ -138,6 +154,7 @@ esphome/components/mcp9808/* @k7hpn
esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core
esphome/components/media_player/* @jesserockz
esphome/components/mics_4514/* @jesserockz
esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov
esphome/components/mitsubishi/* @RubyBailey
@@ -150,8 +167,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
@@ -164,6 +182,8 @@ esphome/components/nfc/* @jesserockz
esphome/components/number/* @esphome/core
esphome/components/ota/* @esphome/core
esphome/components/output/* @esphome/core
esphome/components/pca9554/* @hwstar
esphome/components/pcf85063/* @brogon
esphome/components/pid/* @OttoWinter
esphome/components/pipsolar/* @andreashergert1984
esphome/components/pm1006/* @habbie
@@ -196,6 +216,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
@@ -204,8 +225,12 @@ esphome/components/sgp4x/* @SenexCrenshaw @martgras
esphome/components/shelly_dimmer/* @edge90 @rnauber
esphome/components/sht4x/* @sjtrny
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/sm2235/* @Cossid
esphome/components/sm2335/* @Cossid
esphome/components/sml/* @alengwenus
esphome/components/smt100/* @piechade
esphome/components/sn74hc165/* @jesserockz
@@ -234,6 +259,7 @@ esphome/components/switch/* @esphome/core
esphome/components/t6615/* @tylermenezes
esphome/components/tca9548a/* @andreashergert1984
esphome/components/tcl112/* @glmnet
esphome/components/tee501/* @Stock-M
esphome/components/teleinfo/* @0hax
esphome/components/thermostat/* @kbx81
esphome/components/time/* @OttoWinter
@@ -258,12 +284,15 @@ esphome/components/uart/* @esphome/core
esphome/components/ufire_ec/* @pvizeli
esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter
esphome/components/vbus/* @ssieb
esphome/components/version/* @esphome/core
esphome/components/wake_on_lan/* @willwill2will54
esphome/components/web_server_base/* @OttoWinter
esphome/components/whirlpool/* @glmnet
esphome/components/whynter/* @aeonsablaze
esphome/components/wiegand/* @ssieb
esphome/components/wl_134/* @hobbypunk90
esphome/components/x9c/* @EtienneMD
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
esphome/components/xiaomi_mhoc303/* @drug123
esphome/components/xiaomi_mhoc401/* @vevsvevs

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,12 +6,15 @@
ARG BASEIMGTYPE=docker
# https://github.com/hassio-addons/addon-debian-base/releases
FROM ghcr.io/hassio-addons/debian-base:6.1.3 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
ARG TARGETARCH
ARG TARGETVARIANT
RUN \
apt-get update \
# Use pinned versions so that we get updates with build caching
@@ -23,7 +26,7 @@ RUN \
python3-cryptography=3.3.2-1 \
iputils-ping=3:20210202-1 \
git=1:2.30.2-1 \
curl=7.74.0-1.3+deb11u3 \
curl=7.74.0-1.3+deb11u7 \
openssh-client=1:8.4p1-5+deb11u1 \
&& rm -rf \
/tmp/* \
@@ -36,11 +39,19 @@ ENV \
# Store globally installed pio libs in /piolibs
PLATFORMIO_GLOBALLIB_DIR=/piolibs
# Support legacy binaries on Debian multiarch system. There is no "correct" way
# to do this, other than using properly built toolchains...
# See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian
RUN \
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
ln -s /lib/arm-linux-gnueabihf/ld-linux.so.3 /lib/ld-linux.so.3; \
fi
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 \
@@ -128,7 +139,7 @@ RUN \
clang-tidy-11=1:11.0.1-2 \
patch=2.7.6-7 \
software-properties-common=0.96.20.2-2.1 \
nano=5.4-2+deb11u1 \
nano=5.4-2+deb11u2 \
build-essential=12.9 \
python3-dev=3.9.2-3 \
&& rm -rf \

View File

@@ -8,32 +8,49 @@ import re
import sys
CHANNEL_DEV = 'dev'
CHANNEL_BETA = 'beta'
CHANNEL_RELEASE = 'release'
CHANNEL_DEV = "dev"
CHANNEL_BETA = "beta"
CHANNEL_RELEASE = "release"
CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
ARCH_AMD64 = 'amd64'
ARCH_ARMV7 = 'armv7'
ARCH_AARCH64 = 'aarch64'
ARCH_AMD64 = "amd64"
ARCH_ARMV7 = "armv7"
ARCH_AARCH64 = "aarch64"
ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
TYPE_DOCKER = 'docker'
TYPE_HA_ADDON = 'ha-addon'
TYPE_LINT = 'lint'
TYPE_DOCKER = "docker"
TYPE_HA_ADDON = "ha-addon"
TYPE_LINT = "lint"
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
parser = argparse.ArgumentParser()
parser.add_argument("--tag", type=str, required=True, help="The main docker tag to push to. If a version number also adds latest and/or beta tag")
parser.add_argument("--arch", choices=ARCHS, required=False, help="The architecture to build for")
parser.add_argument("--build-type", choices=TYPES, required=True, help="The type of build to run")
parser.add_argument("--dry-run", action="store_true", help="Don't run any commands, just print them")
subparsers = parser.add_subparsers(help="Action to perform", dest="command", required=True)
parser.add_argument(
"--tag",
type=str,
required=True,
help="The main docker tag to push to. If a version number also adds latest and/or beta tag",
)
parser.add_argument(
"--arch", choices=ARCHS, required=False, help="The architecture to build for"
)
parser.add_argument(
"--build-type", choices=TYPES, required=True, help="The type of build to run"
)
parser.add_argument(
"--dry-run", action="store_true", help="Don't run any commands, just print them"
)
subparsers = parser.add_subparsers(
help="Action to perform", dest="command", required=True
)
build_parser = subparsers.add_parser("build", help="Build the image")
build_parser.add_argument("--push", help="Also push the images", action="store_true")
build_parser.add_argument("--load", help="Load the docker image locally", action="store_true")
manifest_parser = subparsers.add_parser("manifest", help="Create a manifest from already pushed images")
build_parser.add_argument(
"--load", help="Load the docker image locally", action="store_true"
)
manifest_parser = subparsers.add_parser(
"manifest", help="Create a manifest from already pushed images"
)
@dataclass(frozen=True)
@@ -49,7 +66,7 @@ class DockerParams:
prefix = {
TYPE_DOCKER: "esphome/esphome",
TYPE_HA_ADDON: "esphome/esphome-hassio",
TYPE_LINT: "esphome/esphome-lint"
TYPE_LINT: "esphome/esphome-lint",
}[build_type]
build_to = f"{prefix}-{arch}"
baseimgtype = {
@@ -128,13 +145,21 @@ def main():
# 3. build
cmd = [
"docker", "buildx", "build",
"--build-arg", f"BASEIMGTYPE={params.baseimgtype}",
"--build-arg", f"BUILD_VERSION={args.tag}",
"--cache-from", f"type=registry,ref={cache_img}",
"--file", "docker/Dockerfile",
"--platform", params.platform,
"--target", params.target,
"docker",
"buildx",
"build",
"--build-arg",
f"BASEIMGTYPE={params.baseimgtype}",
"--build-arg",
f"BUILD_VERSION={args.tag}",
"--cache-from",
f"type=registry,ref={cache_img}",
"--file",
"docker/Dockerfile",
"--platform",
params.platform,
"--target",
params.target,
]
for img in imgs:
cmd += ["--tag", img]
@@ -160,9 +185,7 @@ def main():
run_command(*cmd)
# 2. Push manifests
for target in targets:
run_command(
"docker", "manifest", "push", target
)
run_command("docker", "manifest", "push", target)
if __name__ == "__main__":

68
docker/generate_tags.py Executable file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python3
import re
import os
import argparse
import json
CHANNEL_DEV = "dev"
CHANNEL_BETA = "beta"
CHANNEL_RELEASE = "release"
parser = argparse.ArgumentParser()
parser.add_argument(
"--tag",
type=str,
required=True,
help="The main docker tag to push to. If a version number also adds latest and/or beta tag",
)
parser.add_argument(
"--suffix",
type=str,
required=True,
help="The suffix of the tag.",
)
def main():
args = parser.parse_args()
# detect channel from tag
match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
major_minor_version = None
if match is None:
channel = CHANNEL_DEV
elif match.group(2) is None:
major_minor_version = match.group(1)
channel = CHANNEL_RELEASE
else:
channel = CHANNEL_BETA
tags_to_push = [args.tag]
if channel == CHANNEL_DEV:
tags_to_push.append("dev")
elif channel == CHANNEL_BETA:
tags_to_push.append("beta")
elif channel == CHANNEL_RELEASE:
# Additionally push to beta
tags_to_push.append("beta")
tags_to_push.append("latest")
if major_minor_version:
tags_to_push.append("stable")
tags_to_push.append(major_minor_version)
suffix = f"-{args.suffix}" if args.suffix else ""
with open(os.environ["GITHUB_OUTPUT"], "w") as f:
print(f"channel={channel}", file=f)
print(f"image=esphome/esphome{suffix}", file=f)
full_tags = []
for tag in tags_to_push:
full_tags += [f"ghcr.io/esphome/esphome{suffix}:{tag}"]
full_tags += [f"esphome/esphome{suffix}:{tag}"]
print(f"tags={','.join(full_tags)}", file=f)
if __name__ == "__main__":
main()

View File

@@ -1,41 +0,0 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# This files check if all user configuration requirements are met
# ==============================================================================
# Check SSL requirements, if enabled
if bashio::config.true 'ssl'; then
if ! bashio::config.has_value 'certfile'; then
bashio::log.fatal 'SSL is enabled, but no certfile was specified.'
bashio::exit.nok
fi
if ! bashio::config.has_value 'keyfile'; then
bashio::log.fatal 'SSL is enabled, but no keyfile was specified'
bashio::exit.nok
fi
certfile="/ssl/$(bashio::config 'certfile')"
keyfile="/ssl/$(bashio::config 'keyfile')"
if ! bashio::fs.file_exists "${certfile}"; then
if ! bashio::fs.file_exists "${keyfile}"; then
# Both files are missing, let's print a friendlier error message
bashio::log.fatal 'You enabled encrypted connections using the "ssl": true option.'
bashio::log.fatal "However, the SSL files '${certfile}' and '${keyfile}'"
bashio::log.fatal "were not found. If you're using Hass.io on your local network and don't want"
bashio::log.fatal 'to encrypt connections to the ESPHome dashboard, you can manually disable'
bashio::log.fatal 'SSL by setting "ssl" to false."'
bashio::exit.nok
fi
bashio::log.fatal "The configured certfile '${certfile}' was not found."
bashio::exit.nok
fi
if ! bashio::fs.file_exists "/ssl/$(bashio::config 'keyfile')"; then
bashio::log.fatal "The configured keyfile '${keyfile}' was not found."
bashio::exit.nok
fi
fi

View File

@@ -1,34 +0,0 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Configures NGINX for use with ESPHome
# ==============================================================================
declare certfile
declare keyfile
declare direct_port
declare ingress_interface
declare ingress_port
mkdir -p /var/log/nginx
direct_port=$(bashio::addon.port 6052)
if bashio::var.has_value "${direct_port}"; then
if bashio::config.true 'ssl'; then
certfile=$(bashio::config 'certfile')
keyfile=$(bashio::config 'keyfile')
mv /etc/nginx/servers/direct-ssl.disabled /etc/nginx/servers/direct.conf
sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/servers/direct.conf
sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/servers/direct.conf
else
mv /etc/nginx/servers/direct.disabled /etc/nginx/servers/direct.conf
fi
sed -i "s/%%port%%/${direct_port}/g" /etc/nginx/servers/direct.conf
fi
ingress_port=$(bashio::addon.ingress_port)
ingress_interface=$(bashio::addon.ip_address)
sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf

View File

@@ -1,9 +0,0 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# This files creates all directories used by esphome
# ==============================================================================
pio_cache_base=/data/cache/platformio
mkdir -p "${pio_cache_base}"

View File

@@ -1,9 +1,9 @@
proxy_http_version 1.1;
proxy_ignore_client_abort off;
proxy_read_timeout 86400s;
proxy_redirect off;
proxy_send_timeout 86400s;
proxy_max_temp_file_size 0;
proxy_http_version 1.1;
proxy_ignore_client_abort off;
proxy_read_timeout 86400s;
proxy_redirect off;
proxy_send_timeout 86400s;
proxy_max_temp_file_size 0;
proxy_set_header Accept-Encoding "";
proxy_set_header Connection $connection_upgrade;

View File

@@ -1,5 +1,7 @@
root /dev/null;
server_name $hostname;
root /dev/null;
server_name $hostname;
client_max_body_size 512m;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

View File

@@ -1,7 +1,6 @@
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
ssl_ecdh_curve secp384r1;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

View File

@@ -0,0 +1,3 @@
upstream esphome {
server unix:/var/run/esphome.sock;
}

View File

@@ -2,7 +2,6 @@ daemon off;
user root;
pid /var/run/nginx.pid;
worker_processes 1;
# Hass.io addon log
error_log /proc/1/fd/1 error;
events {
worker_connections 1024;
@@ -10,24 +9,22 @@ events {
http {
include /etc/nginx/includes/mime.types;
access_log stdout;
default_type application/octet-stream;
gzip on;
keepalive_timeout 65;
sendfile on;
server_tokens off;
access_log off;
default_type application/octet-stream;
gzip on;
keepalive_timeout 65;
sendfile on;
server_tokens off;
tcp_nodelay on;
tcp_nopush on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Use Hass.io supervisor as resolver
resolver 172.30.32.2;
upstream esphome {
server unix:/var/run/esphome.sock;
}
include /etc/nginx/includes/upstream.conf;
include /etc/nginx/servers/*.conf;
}

View File

@@ -0,0 +1 @@
Without requirements or design, programming is the art of adding bugs to an empty text file. (Louis Srygley)

View File

@@ -1,12 +0,0 @@
server {
listen %%port%% default_server;
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
# Clear Hass.io Ingress header
proxy_set_header X-HA-Ingress "";
location / {
proxy_pass http://esphome;
}
}

View File

@@ -1,20 +1,26 @@
server {
listen %%port%% default_server ssl http2;
{{ if not .ssl }}
listen 6052 default_server;
{{ else }}
listen 6052 default_server ssl http2;
{{ end }}
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
{{ if .ssl }}
include /etc/nginx/includes/ssl_params.conf;
ssl on;
ssl_certificate /ssl/%%certfile%%;
ssl_certificate_key /ssl/%%keyfile%%;
# Clear Hass.io Ingress header
proxy_set_header X-HA-Ingress "";
ssl_certificate /ssl/{{ .certfile }};
ssl_certificate_key /ssl/{{ .keyfile }};
# Redirect http requests to https on the same port.
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
error_page 497 https://$http_host$request_uri;
{{ end }}
# Clear Home Assistant Ingress header
proxy_set_header X-HA-Ingress "";
location / {
proxy_pass http://esphome;

View File

@@ -1,14 +1,16 @@
server {
listen %%interface%%:%%port%% default_server;
listen 127.0.0.1:{{ .port }} default_server;
listen {{ .interface }}:{{ .port }} default_server;
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
# Set Home Assistant Ingress header
proxy_set_header X-HA-Ingress "YES";
location / {
# Only allow from Hass.io supervisor
allow 172.30.32.2;
allow 127.0.0.1;
deny all;
proxy_pass http://esphome;

View File

@@ -0,0 +1,32 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Home Assistant Add-on: ESPHome
# Sends discovery information to Home Assistant.
# ==============================================================================
declare config
declare port
# We only disable it when disabled explicitly
if bashio::config.false 'home_assistant_dashboard_integration';
then
bashio::log.info "Home Assistant discovery is disabled for this add-on."
bashio::exit.ok
fi
port=$(bashio::addon.ingress_port)
# Wait for NGINX to become available
bashio::net.wait_for "${port}" "127.0.0.1" 300
config=$(\
bashio::var.json \
host "127.0.0.1" \
port "^${port}" \
)
if bashio::discovery "esphome" "${config}" > /dev/null; then
bashio::log.info "Successfully send discovery information to Home Assistant."
else
bashio::log.error "Discovery message to Home Assistant failed!"
fi

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/discovery/run

View File

@@ -0,0 +1,26 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Home Assistant Community Add-on: ESPHome
# Take down the S6 supervision tree when ESPHome dashboard fails
# ==============================================================================
declare exit_code
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
bashio::log.info \
"Service ESPHome dashboard exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt
fi

View File

@@ -1,10 +1,19 @@
#!/usr/bin/with-contenv bashio
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Runs the ESPHome dashboard
# ==============================================================================
readonly pio_cache_base=/data/cache/platformio
export ESPHOME_IS_HA_ADDON=true
export PLATFORMIO_GLOBALLIB_DIR=/piolibs
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
# setting `core_dir` would therefore prevent pio from accessing
export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
if bashio::config.true 'leave_front_door_open'; then
export DISABLE_HA_AUTHENTICATION=true
@@ -30,14 +39,7 @@ else
fi
fi
pio_cache_base=/data/cache/platformio
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
# setting `core_dir` would therefore prevent pio from accessing
export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
export PLATFORMIO_GLOBALLIB_DIR=/piolibs
mkdir -p "${pio_cache_base}"
bashio::log.info "Starting ESPHome dashboard..."
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon

View File

@@ -0,0 +1 @@
longrun

View File

@@ -0,0 +1,27 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Configures NGINX for use with ESPHome
# ==============================================================================
mkdir -p /var/log/nginx
# Generate Ingress configuration
bashio::var.json \
interface "$(bashio::addon.ip_address)" \
port "^$(bashio::addon.ingress_port)" \
| tempio \
-template /etc/nginx/templates/ingress.gtpl \
-out /etc/nginx/servers/ingress.conf
# Generate direct access configuration, if enabled.
if bashio::var.has_value "$(bashio::addon.port 6052)"; then
bashio::config.require.ssl
bashio::var.json \
certfile "$(bashio::config 'certfile')" \
keyfile "$(bashio::config 'keyfile')" \
ssl "^$(bashio::config 'ssl')" \
| tempio \
-template /etc/nginx/templates/direct.gtpl \
-out /etc/nginx/servers/direct.conf
fi

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-nginx/run

View File

@@ -0,0 +1,25 @@
#!/command/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when NGINX fails
# ==============================================================================
declare exit_code
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
bashio::log.info \
"Service NGINX exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt
fi

View File

@@ -1,10 +1,11 @@
#!/usr/bin/with-contenv bashio
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Runs the NGINX proxy
# ==============================================================================
bashio::log.info "Waiting for dashboard to come up..."
bashio::log.info "Waiting for ESPHome dashboard to come up..."
while [[ ! -S /var/run/esphome.sock ]]; do
sleep 0.5

View File

@@ -0,0 +1 @@
longrun

View File

@@ -1,15 +0,0 @@
#!/usr/bin/execlineb -S0
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when ESPHome fails
# ==============================================================================
declare APP_EXIT_CODE=${1}
if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
exec /run/s6/basedir/bin/halt
fi
bashio::log.info "Service restart after closing"

View File

@@ -1,15 +0,0 @@
#!/usr/bin/execlineb -S0
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when NGINX fails
# ==============================================================================
declare APP_EXIT_CODE=${1}
if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
exec /run/s6/basedir/bin/halt
fi
bashio::log.info "Service restart after closing"

View File

@@ -339,7 +339,7 @@ def command_config(args, config):
_LOGGER.info("Configuration is valid!")
if not CORE.verbose:
config = strip_default_ids(config)
safe_print(yaml_util.dump(config))
safe_print(yaml_util.dump(config, args.show_secrets))
return 0
@@ -665,6 +665,9 @@ def parse_args(argv):
parser_config.add_argument(
"configuration", help="Your YAML configuration file(s).", nargs="+"
)
parser_config.add_argument(
"--show-secrets", help="Show secrets in output.", action="store_true"
)
parser_compile = subparsers.add_parser(
"compile", help="Read the configuration and compile a program."

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

@@ -46,6 +46,7 @@ void A4988::loop() {
return;
this->dir_pin_->digital_write(dir == 1);
delayMicroseconds(50);
this->step_pin_->digital_write(true);
delayMicroseconds(5);
this->step_pin_->digital_write(false);

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

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

@@ -9,7 +9,7 @@ static const char *const TAG = "ads1115";
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111;
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; // 3300_SPS for ADS1015
void ADS1115Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
@@ -18,6 +18,9 @@ void ADS1115Component::setup() {
this->mark_failed();
return;
}
ESP_LOGCONFIG(TAG, "Configuring ADS1115...");
uint16_t config = 0;
// Clear single-shot bit
// 0b0xxxxxxxxxxxxxxx
@@ -77,6 +80,7 @@ void ADS1115Component::dump_config() {
LOG_SENSOR(" ", "Sensor", sensor);
ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer());
ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain());
ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution());
}
}
float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
@@ -127,27 +131,45 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
this->status_set_warning();
return NAN;
}
if (sensor->get_resolution() == ADS1015_12_BITS) {
bool negative = (raw_conversion >> 15) == 1;
// shift raw_conversion as it's only 12-bits, left justified
raw_conversion = raw_conversion >> (16 - ADS1015_12_BITS);
// check if number was negative in order to keep the sign
if (negative) {
// the number was negative
// 1) set the negative bit back
raw_conversion |= 0x8000;
// 2) reset the former (shifted) negative bit
raw_conversion &= 0xF7FF;
}
}
auto signed_conversion = static_cast<int16_t>(raw_conversion);
float millivolts;
float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f;
switch (sensor->get_gain()) {
case ADS1115_GAIN_6P144:
millivolts = signed_conversion * 0.187500f;
millivolts = (signed_conversion * 6144) / divider;
break;
case ADS1115_GAIN_4P096:
millivolts = signed_conversion * 0.125000f;
millivolts = (signed_conversion * 4096) / divider;
break;
case ADS1115_GAIN_2P048:
millivolts = signed_conversion * 0.062500f;
millivolts = (signed_conversion * 2048) / divider;
break;
case ADS1115_GAIN_1P024:
millivolts = signed_conversion * 0.031250f;
millivolts = (signed_conversion * 1024) / divider;
break;
case ADS1115_GAIN_0P512:
millivolts = signed_conversion * 0.015625f;
millivolts = (signed_conversion * 512) / divider;
break;
case ADS1115_GAIN_0P256:
millivolts = signed_conversion * 0.007813f;
millivolts = (signed_conversion * 256) / divider;
break;
default:
millivolts = NAN;

View File

@@ -30,6 +30,11 @@ enum ADS1115Gain {
ADS1115_GAIN_0P256 = 0b101,
};
enum ADS1115Resolution {
ADS1115_16_BITS = 16,
ADS1015_12_BITS = 12,
};
class ADS1115Sensor;
class ADS1115Component : public Component, public i2c::I2CDevice {
@@ -58,15 +63,17 @@ class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public vol
void update() override;
void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; }
void set_gain(ADS1115Gain gain) { gain_ = gain; }
void set_resolution(ADS1115Resolution resolution) { resolution_ = resolution; }
float sample() override;
uint8_t get_multiplexer() const { return multiplexer_; }
uint8_t get_gain() const { return gain_; }
uint8_t get_resolution() const { return resolution_; }
protected:
ADS1115Component *parent_;
ADS1115Multiplexer multiplexer_;
ADS1115Gain gain_;
ADS1115Resolution resolution_;
};
} // namespace ads1115

View File

@@ -4,6 +4,7 @@ from esphome.components import sensor, voltage_sampler
from esphome.const import (
CONF_GAIN,
CONF_MULTIPLEXER,
CONF_RESOLUTION,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
UNIT_VOLT,
@@ -35,6 +36,12 @@ GAIN = {
"0.256": ADS1115Gain.ADS1115_GAIN_0P256,
}
ADS1115Resolution = ads1115_ns.enum("ADS1115Resolution")
RESOLUTION = {
"16_BITS": ADS1115Resolution.ADS1115_16_BITS,
"12_BITS": ADS1115Resolution.ADS1015_12_BITS,
}
def validate_gain(value):
if isinstance(value, float):
@@ -63,6 +70,9 @@ CONFIG_SCHEMA = (
cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
cv.Required(CONF_GAIN): validate_gain,
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
RESOLUTION, upper=True, space="_"
),
}
)
.extend(cv.polling_component_schema("60s"))
@@ -77,5 +87,6 @@ async def to_code(config):
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
cg.add(var.set_gain(config[CONF_GAIN]))
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
cg.add(paren.register_sensor(var))

View File

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

@@ -117,7 +117,7 @@ async def to_code(config):
data[pos] = rgb & 255
pos += 1
elif config[CONF_TYPE] == "BINARY":
elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
width8 = ((width + 7) // 8) * 8
data = [0 for _ in range((height * width8 // 8) * frames)]
for frameIndex in range(frames):

View File

@@ -23,7 +23,7 @@ void APDS9960::setup() {
return;
}
if (id != 0xAB && id != 0x9C) { // APDS9960 all should have one of these IDs
if (id != 0xAB && id != 0x9C && id != 0xA8) { // APDS9960 all should have one of these IDs
this->error_code_ = WRONG_ID;
this->mark_failed();
return;

View File

@@ -206,6 +206,8 @@ message DeviceInfoResponse {
uint32 bluetooth_proxy_version = 11;
string manufacturer = 12;
string friendly_name = 13;
}
message ListEntitiesRequest {
@@ -785,6 +787,7 @@ enum ClimateFanMode {
CLIMATE_FAN_MIDDLE = 6;
CLIMATE_FAN_FOCUS = 7;
CLIMATE_FAN_DIFFUSE = 8;
CLIMATE_FAN_QUIET = 9;
}
enum ClimateSwingMode {
CLIMATE_SWING_OFF = 0;
@@ -826,7 +829,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;
@@ -839,6 +842,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;
@@ -1335,3 +1339,23 @@ 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;
}

View File

@@ -548,7 +548,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();
@@ -930,6 +932,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
DeviceInfoResponse resp{};
resp.uses_password = this->parent_->uses_password();
resp.name = App.get_name();
resp.friendly_name = App.get_friendly_name();
resp.mac_address = get_mac_address_pretty();
resp.esphome_version = ESPHOME_VERSION;
resp.compilation_time = App.get_compilation_time();
@@ -950,7 +953,7 @@ 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() ? 4 : 1;
#endif
return resp;
}

View File

@@ -616,6 +616,9 @@ APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
struct iovec iov[2];
iov[0].iov_base = header;
iov[0].iov_len = 3;
if (len == 0) {
return write_raw_(iov, 1);
}
iov[1].iov_base = const_cast<uint8_t *>(data);
iov[1].iov_len = len;
@@ -913,6 +916,9 @@ APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *pay
struct iovec iov[2];
iov[0].iov_base = &header[0];
iov[0].iov_len = header.size();
if (payload_len == 0) {
return write_raw_(iov, 1);
}
iov[1].iov_base = const_cast<uint8_t *>(payload);
iov[1].iov_len = payload_len;

View File

@@ -235,6 +235,8 @@ template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::Climat
return "CLIMATE_FAN_FOCUS";
case enums::CLIMATE_FAN_DIFFUSE:
return "CLIMATE_FAN_DIFFUSE";
case enums::CLIMATE_FAN_QUIET:
return "CLIMATE_FAN_QUIET";
default:
return "UNKNOWN";
}
@@ -628,6 +630,10 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
this->manufacturer = value.as_string();
return true;
}
case 13: {
this->friendly_name = value.as_string();
return true;
}
default:
return false;
}
@@ -645,6 +651,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(10, this->webserver_port);
buffer.encode_uint32(11, this->bluetooth_proxy_version);
buffer.encode_string(12, this->manufacturer);
buffer.encode_string(13, this->friendly_name);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void DeviceInfoResponse::dump_to(std::string &out) const {
@@ -699,6 +706,10 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
out.append(" manufacturer: ");
out.append("'").append(this->manufacturer).append("'");
out.append("\n");
out.append(" friendly_name: ");
out.append("'").append(this->friendly_name).append("'");
out.append("\n");
out.append("}");
}
#endif
@@ -3440,7 +3451,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:
@@ -3459,7 +3474,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) {
@@ -3480,6 +3495,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 {
@@ -3526,8 +3542,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");
@@ -3580,6 +3596,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
@@ -5953,6 +5974,92 @@ 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
} // namespace api
} // namespace esphome

View File

@@ -99,6 +99,7 @@ enum ClimateFanMode : uint32_t {
CLIMATE_FAN_MIDDLE = 6,
CLIMATE_FAN_FOCUS = 7,
CLIMATE_FAN_DIFFUSE = 8,
CLIMATE_FAN_QUIET = 9,
};
enum ClimateSwingMode : uint32_t {
CLIMATE_SWING_OFF = 0,
@@ -276,6 +277,7 @@ class DeviceInfoResponse : public ProtoMessage {
uint32_t webserver_port{0};
uint32_t bluetooth_proxy_version{0};
std::string manufacturer{};
std::string friendly_name{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -913,7 +915,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{};
@@ -924,6 +926,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;
@@ -1525,6 +1528,32 @@ 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;
};
} // namespace api
} // namespace esphome

View File

@@ -425,6 +425,22 @@ 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
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) {
case 1: {

View File

@@ -209,6 +209,12 @@ 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
protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;

View File

@@ -309,6 +309,28 @@ 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_connections_free(uint8_t free, uint8_t limit) {
BluetoothConnectionsFreeResponse call;
call.free = free;

View File

@@ -78,6 +78,8 @@ 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_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);

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

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

View File

@@ -37,9 +37,13 @@ void BedJetFan::control(const fan::FanCall &call) {
// ignore speed changes if not on or turning on
if (this->state && call.get_speed().has_value()) {
this->speed = *call.get_speed();
this->parent_->set_fan_index(this->speed);
did_change = true;
auto speed = *call.get_speed();
if (speed >= 1) {
this->speed = speed;
// Fan.speed is 1-20, but Bedjet expects 0-19, so subtract 1
this->parent_->set_fan_index(this->speed - 1);
did_change = true;
}
}
if (did_change) {
@@ -57,8 +61,9 @@ void BedJetFan::on_status(const BedjetStatusPacket *data) {
did_change = true;
}
if (data->fan_step != this->speed) {
this->speed = data->fan_step;
// BedjetStatusPacket.fan_step is in range 0-19, but Fan.speed wants 1-20.
if (data->fan_step + 1 != this->speed) {
this->speed = data->fan_step + 1;
did_change = true;
}

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

@@ -19,6 +19,15 @@ 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.

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

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

View File

@@ -2,11 +2,13 @@ from esphome.components import esp32_ble_tracker, esp32_ble_client
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ACTIVE, CONF_ID
from esphome.components.esp32 import add_idf_sdkconfig_option
AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
DEPENDENCIES = ["api", "esp32"]
CODEOWNERS = ["@jesserockz"]
CONF_CACHE_SERVICES = "cache_services"
CONF_CONNECTIONS = "connections"
MAX_CONNECTIONS = 3
@@ -47,6 +49,9 @@ CONFIG_SCHEMA = cv.All(
{
cv.GenerateID(): cv.declare_id(BluetoothProxy),
cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
cv.SplitDefault(CONF_CACHE_SERVICES, esp32_idf=True): cv.All(
cv.only_with_esp_idf, cv.boolean
),
cv.Optional(CONF_CONNECTIONS): cv.All(
cv.ensure_list(CONNECTION_SCHEMA),
cv.Length(min=1, max=MAX_CONNECTIONS),
@@ -72,4 +77,7 @@ async def to_code(config):
cg.add(var.register_connection(connection_var))
await esp32_ble_tracker.register_client(connection_var, connection_conf)
if config.get(CONF_CACHE_SERVICES):
add_idf_sdkconfig_option("CONFIG_BT_GATTC_CACHE_NVS_FLASH", True)
cg.add_define("USE_BLUETOOTH_PROXY")

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,27 @@ 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;
}
}
}

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

View File

@@ -88,7 +88,10 @@ void BME280Component::setup() {
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
// and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component.
this->component_state_ &= ~COMPONENT_STATE_FAILED;
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
this->component_state_ &= ~COMPONENT_STATE_MASK;
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
}
if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) {
this->error_code_ = COMMUNICATION_FAILED;

View File

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

@@ -6,6 +6,7 @@ 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"
@@ -54,6 +55,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

@@ -1,4 +1,5 @@
#include "bmp280.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome {
@@ -11,8 +12,11 @@ static const uint8_t BMP280_REGISTER_CONTROL = 0xF4;
static const uint8_t BMP280_REGISTER_CONFIG = 0xF5;
static const uint8_t BMP280_REGISTER_PRESSUREDATA = 0xF7;
static const uint8_t BMP280_REGISTER_TEMPDATA = 0xFA;
static const uint8_t BMP280_REGISTER_RESET = 0xE0;
static const uint8_t BMP280_MODE_FORCED = 0b01;
static const uint8_t BMP280_SOFT_RESET = 0xB6;
static const uint8_t BMP280_STATUS_IM_UPDATE = 0b01;
inline uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); }
@@ -66,6 +70,28 @@ void BMP280Component::setup() {
return;
}
// Send a soft reset.
if (!this->write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET)) {
this->mark_failed();
return;
}
// Wait until the NVM data has finished loading.
uint8_t status;
uint8_t retry = 5;
do {
delay(2);
if (!this->read_byte(BMP280_REGISTER_STATUS, &status)) {
ESP_LOGW(TAG, "Error reading status register.");
this->mark_failed();
return;
}
} while ((status & BMP280_STATUS_IM_UPDATE) && (--retry));
if (status & BMP280_STATUS_IM_UPDATE) {
ESP_LOGW(TAG, "Timeout loading NVM.");
this->mark_failed();
return;
}
// Read calibration
this->calibration_.t1 = this->read_u16_le_(0x88);
this->calibration_.t2 = this->read_s16_le_(0x8A);

View File

@@ -0,0 +1,44 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.const import (
CONF_CLOCK_PIN,
CONF_DATA_PIN,
CONF_ID,
)
CODEOWNERS = ["@Cossid"]
MULTI_CONF = True
CONF_MAX_POWER_COLOR_CHANNELS = "max_power_color_channels"
CONF_MAX_POWER_WHITE_CHANNELS = "max_power_white_channels"
AUTO_LOAD = ["output"]
bp1658cj_ns = cg.esphome_ns.namespace("bp1658cj")
BP1658CJ = bp1658cj_ns.class_("BP1658CJ", cg.Component)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(BP1658CJ),
cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_MAX_POWER_COLOR_CHANNELS, default=2): cv.int_range(
min=0, max=15
),
cv.Optional(CONF_MAX_POWER_WHITE_CHANNELS, default=4): cv.int_range(
min=0, max=15
),
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
data = await cg.gpio_pin_expression(config[CONF_DATA_PIN])
cg.add(var.set_data_pin(data))
clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN])
cg.add(var.set_clock_pin(clock))
cg.add(var.set_max_power_color_channels(config[CONF_MAX_POWER_COLOR_CHANNELS]))
cg.add(var.set_max_power_white_channels(config[CONF_MAX_POWER_WHITE_CHANNELS]))

View File

@@ -0,0 +1,110 @@
#include "bp1658cj.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bp1658cj {
static const char *const TAG = "bp1658cj";
static const uint8_t BP1658CJ_MODEL_ID = 0x80;
static const uint8_t BP1658CJ_ADDR_STANDBY = 0x0;
static const uint8_t BP1658CJ_ADDR_START_3CH = 0x10;
static const uint8_t BP1658CJ_ADDR_START_2CH = 0x20;
static const uint8_t BP1658CJ_ADDR_START_5CH = 0x30;
void BP1658CJ::setup() {
ESP_LOGCONFIG(TAG, "Setting up BP1658CJ Output Component...");
this->data_pin_->setup();
this->data_pin_->digital_write(false);
this->clock_pin_->setup();
this->clock_pin_->digital_write(false);
this->pwm_amounts_.resize(5, 0);
}
void BP1658CJ::dump_config() {
ESP_LOGCONFIG(TAG, "BP1658CJ:");
LOG_PIN(" Data Pin: ", this->data_pin_);
LOG_PIN(" Clock Pin: ", this->clock_pin_);
ESP_LOGCONFIG(TAG, " Color Channels Max Power: %u", this->max_power_color_channels_);
ESP_LOGCONFIG(TAG, " White Channels Max Power: %u", this->max_power_white_channels_);
}
void BP1658CJ::loop() {
if (!this->update_)
return;
uint8_t data[12];
if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
// Off / Sleep
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
for (int i = 1; i < 12; i++)
data[i] = 0;
this->write_buffer_(data, 12);
} else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
(this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
// Only data on white channels
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_2CH;
data[1] = 0 << 4 | this->max_power_white_channels_;
for (int i = 2, j = 0; i < 12; i += 2, j++) {
data[i] = this->pwm_amounts_[j] & 0x1F;
data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
}
this->write_buffer_(data, 12);
} else if ((this->pwm_amounts_[0] > 0 || this->pwm_amounts_[1] > 0 || this->pwm_amounts_[2] > 0) &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
// Only data on RGB channels
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_3CH;
data[1] = this->max_power_color_channels_ << 4 | 0;
for (int i = 2, j = 0; i < 12; i += 2, j++) {
data[i] = this->pwm_amounts_[j] & 0x1F;
data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
}
this->write_buffer_(data, 12);
} else {
// All channels
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH;
data[1] = this->max_power_color_channels_ << 4 | this->max_power_white_channels_;
for (int i = 2, j = 0; i < 12; i += 2, j++) {
data[i] = this->pwm_amounts_[j] & 0x1F;
data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
}
this->write_buffer_(data, 12);
}
this->update_ = false;
}
void BP1658CJ::set_channel_value_(uint8_t channel, uint16_t value) {
if (this->pwm_amounts_[channel] != value) {
this->update_ = true;
this->update_channel_ = channel;
}
this->pwm_amounts_[channel] = value;
}
void BP1658CJ::write_bit_(bool value) {
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(value);
this->clock_pin_->digital_write(true);
}
void BP1658CJ::write_byte_(uint8_t data) {
for (uint8_t mask = 0x80; mask; mask >>= 1) {
this->write_bit_(data & mask);
}
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(true);
this->clock_pin_->digital_write(true);
}
void BP1658CJ::write_buffer_(uint8_t *buffer, uint8_t size) {
this->data_pin_->digital_write(false);
for (uint32_t i = 0; i < size; i++) {
this->write_byte_(buffer[i]);
}
this->clock_pin_->digital_write(false);
this->clock_pin_->digital_write(true);
this->data_pin_->digital_write(true);
}
} // namespace bp1658cj
} // namespace esphome

View File

@@ -0,0 +1,64 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/output/float_output.h"
#include <vector>
namespace esphome {
namespace bp1658cj {
class BP1658CJ : public Component {
public:
class Channel;
void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; }
void set_clock_pin(GPIOPin *clock_pin) { clock_pin_ = clock_pin; }
void set_max_power_color_channels(uint8_t max_power_color_channels) {
max_power_color_channels_ = max_power_color_channels;
}
void set_max_power_white_channels(uint8_t max_power_white_channels) {
max_power_white_channels_ = max_power_white_channels;
}
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
/// Send new values if they were updated.
void loop() override;
class Channel : public output::FloatOutput {
public:
void set_parent(BP1658CJ *parent) { parent_ = parent; }
void set_channel(uint8_t channel) { channel_ = channel; }
protected:
void write_state(float state) override {
auto amount = static_cast<uint16_t>(state * 0x3FF);
this->parent_->set_channel_value_(this->channel_, amount);
}
BP1658CJ *parent_;
uint8_t channel_;
};
protected:
void set_channel_value_(uint8_t channel, uint16_t value);
void write_bit_(bool value);
void write_byte_(uint8_t data);
void write_buffer_(uint8_t *buffer, uint8_t size);
GPIOPin *data_pin_;
GPIOPin *clock_pin_;
uint8_t max_power_color_channels_{4};
uint8_t max_power_white_channels_{6};
uint8_t update_channel_;
std::vector<uint16_t> pwm_amounts_;
bool update_{true};
};
} // namespace bp1658cj
} // namespace esphome

View File

@@ -0,0 +1,27 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_CHANNEL, CONF_ID
from . import BP1658CJ
DEPENDENCIES = ["bp1658cj"]
Channel = BP1658CJ.class_("Channel", output.FloatOutput)
CONF_BP1658CJ_ID = "bp1658cj_id"
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
{
cv.GenerateID(CONF_BP1658CJ_ID): cv.use_id(BP1658CJ),
cv.Required(CONF_ID): cv.declare_id(Channel),
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=65535),
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await output.register_output(var, config)
parent = await cg.get_variable(config[CONF_BP1658CJ_ID])
cg.add(var.set_parent(parent))
cg.add(var.set_channel(config[CONF_CHANNEL]))

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