1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-06 18:11:49 +00:00

Compare commits

..

66 Commits

Author SHA1 Message Date
Jesse Hills
1447536906 Merge pull request #4441 from esphome/bump-2023.2.0
2023.2.0
2023-02-15 22:33:31 +13:00
Jesse Hills
27ec517084 Remove dup line 2023-02-15 21:39:17 +13:00
Jesse Hills
ce1f034bac Bump version to 2023.2.0 2023-02-15 19:29:02 +13:00
Jesse Hills
f1f96f16e9 Merge branch 'beta' into bump-2023.2.0 2023-02-15 19:29:02 +13:00
Jesse Hills
4af4649e23 Merge pull request #4355 from esphome/bump-2022.12.8
2022.12.8
2023-01-27 10:04:29 +13:00
Jesse Hills
8bcddef39d Bump version to 2022.12.8 2023-01-27 09:44:41 +13:00
Franck Nijhof
4ac96ccea2 Add Home Assistant integration discovery (#4328) 2023-01-27 09:44:41 +13:00
Franck Nijhof
3c5de77ae9 Refactor NGINX configuration of Home Assistant Add-on (#4312) 2023-01-27 09:44:41 +13:00
Franck Nijhof
a2925b1d37 Migrate old-style S6 scripts to s6-rc.d (#4311) 2023-01-27 09:44:41 +13:00
Franck Nijhof
73748e9e20 Upgrades add-on base image to 6.2.0 (#4310) 2023-01-27 09:44:40 +13:00
Jesse Hills
75c9823899 Merge pull request #4350 from esphome/bump-2022.12.7
2022.12.7
2023-01-26 15:50:03 +13:00
Jesse Hills
c8c0bd3351 Bump version to 2022.12.7 2023-01-26 15:00:18 +13:00
melyux
e1cdeb7c8f Add a soft reset in setup() for bmp280 (#4329)
fixes https://github.com/esphome/issues/issues/3383
2023-01-26 15:00:17 +13:00
Alex
7f97f42552 Fix BME280 initialization before wifi setup (#4190)
fixes https://github.com/esphome/issues/issues/3530
2023-01-26 15:00:17 +13:00
Stephan Martin
aa7f3569ec rename esp32 CAN to TWAI, so it compiles again (#4334)
fixes https://github.com/esphome/issues/issues/4023
2023-01-26 15:00:17 +13:00
Denis Bodor (aka Lefinnois)
2d0a08442e fix stepper jump back with small steps (#4339) 2023-01-26 15:00:17 +13:00
Joakim Sørensen
d2380756b2 Add "content" to deploy-ha-addon-repo dispatch (#4349) 2023-01-26 15:00:17 +13:00
Jesse Hills
925e3cb6c9 Fix missing s 2023-01-23 20:34:31 +00:00
Jesse Hills
6757acba56 Merge pull request #4342 from esphome/bump-2022.12.6
2022.12.6
2023-01-24 08:58:45 +13:00
Jesse Hills
5cc91cdd95 Bump version to 2022.12.6 2023-01-24 08:30:42 +13:00
Jesse Hills
2b41886819 Move from docker manifest command to buildx with platforms (#4320) 2023-01-24 08:30:42 +13:00
Jesse Hills
72c6efd6a0 Merge pull request #4335 from esphome/bump-2022.12.5
2022.12.5
2023-01-23 09:27:18 +13:00
Jesse Hills
a1f1804112 Bump version to 2022.12.5 2023-01-23 09:06:20 +13:00
Jesse Hills
a8b1ceb4e9 Bump nano version in lint docker image (#4218) 2023-01-23 09:06:20 +13:00
Jesse Hills
4fb0f7f8c6 Merge pull request #4323 from esphome/bump-2022.12.4
2022.12.4
2023-01-21 16:17:57 +13:00
Jesse Hills
958cadeca8 Bump version to 2022.12.4 2023-01-20 18:33:09 +13:00
J. Nick Koston
00f2655f1a 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:33:09 +13:00
Jesse Hills
074f5029eb Fix gpio pin mode for ISR pins (#4216) 2023-01-20 18:33:09 +13:00
Jesse Hills
1691976587 Merge pull request #4214 from esphome/bump-2022.12.3
2022.12.3
2022-12-20 23:34:01 +13:00
Jesse Hills
60e6b4d21e Bump version to 2022.12.3 2022-12-20 23:15:39 +13:00
Jesse Hills
5750591df2 Fix ESP32 GPIO when using INPUT PULLUP mode (#4213) 2022-12-20 23:15:39 +13:00
Jesse Hills
a75da54455 Merge pull request #4212 from esphome/bump-2022.12.2
2022.12.2
2022-12-20 11:06:34 +13:00
Jesse Hills
de7f6c3f5f Bump version to 2022.12.2 2022-12-20 10:49:36 +13:00
J. Nick Koston
4245480656 Handle zero padding anywhere in the combined adv data (#4208)
fixes https://github.com/esphome/issues/issues/3913
2022-12-20 10:49:35 +13:00
Jesse Hills
1824c8131e 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-20 10:49:35 +13:00
Jesse Hills
4e9606d2e0 Merge pull request #4196 from esphome/bump-2022.12.1
2022.12.1
2022-12-16 14:05:24 +13:00
Jesse Hills
78500fa933 Bump version to 2022.12.1 2022-12-16 13:36:11 +13:00
Jesse Hills
9c69b98a49 Fix i2s_audio media_player compiling for esp32-s2 (#4195) 2022-12-16 13:36:10 +13:00
Jesse Hills
e6d8ef98d3 Mark ESP32-S2 as not having Bluetooth (#4194) 2022-12-16 13:36:10 +13:00
Stefan Agner
3f1af1690b Support non-multiarch toolchains on 32-bit ARM (#4191)
fixes https://github.com/esphome/issues/issues/3904
2022-12-16 13:36:10 +13:00
Jesse Hills
84374b6b1e Merge pull request #4186 from esphome/bump-2022.12.0
2022.12.0
2022-12-14 17:06:24 +13:00
Jesse Hills
391316c9b5 Bump version to 2022.12.0 2022-12-14 16:37:39 +13:00
Jesse Hills
705c62ebd7 Merge branch 'beta' into bump-2022.12.0 2022-12-14 16:37:39 +13:00
Jesse Hills
7209dd8bae Merge pull request #4152 from esphome/bump-2022.11.5
2022.11.5
2022-12-06 13:12:57 +13:00
Jesse Hills
ab736c89bb Bump version to 2022.11.5 2022-12-06 12:52:48 +13:00
Jesse Hills
6911639617 Fix board pin alias lookup (#4147) 2022-12-06 12:52:48 +13:00
Jesse Hills
b9720d0715 Merge pull request #4130 from esphome/bump-2022.11.4
2022.11.4
2022-12-01 15:38:52 +13:00
Jesse Hills
47b3267ed4 Bump version to 2022.11.4 2022-12-01 13:47:50 +13:00
Jesse Hills
e16ba2adb5 Fix queuing scripts not compiling (#4077) 2022-12-01 13:47:50 +13:00
Nicolas Graziano
0a19b1e32c Dashboard, after login use relative url. (#4103) 2022-12-01 13:47:49 +13:00
Jesse Hills
bae9a950c0 current-based cover fix copy paste mistake (#4124) 2022-12-01 13:47:49 +13:00
Jesse Hills
72b2943332 Merge pull request #4083 from esphome/bump-2022.11.3
2022.11.3
2022-11-25 07:23:08 +13:00
Jesse Hills
4ec0ef7548 Bump version to 2022.11.3 2022-11-24 17:01:52 +13:00
Jesse Hills
25bc6761f6 Don't convert climate temperature step (#4082) 2022-11-24 17:01:52 +13:00
Brian Kaufman
81b6562c25 Fix units for refresh: never (#4048) 2022-11-24 17:01:52 +13:00
Samuel Sieb
ae74189fc2 fix missing library (#4051) 2022-11-24 17:01:51 +13:00
Jesse Hills
9e516efe10 Merge pull request #4074 from esphome/bump-2022.11.2
2022.11.2
2022-11-23 16:06:34 +13:00
Jesse Hills
366e29439e Bump version to 2022.11.2 2022-11-23 13:04:21 +13:00
J. Nick Koston
1c9c700d7f Avoid creating a new espbt::ESPBTUUID each loop when registering for notify (#4069) 2022-11-23 13:04:21 +13:00
J. Nick Koston
b2e6b9d31f Avoid 128bit uuid loop for 16/32 bit uuids (#4068) 2022-11-23 13:04:21 +13:00
Jesse Hills
7623f63846 rp2040_pwm frequency is per pair of pins (#4061) 2022-11-23 13:04:21 +13:00
Jesse Hills
2bfaf9dce3 Update web_server index (#4060) 2022-11-23 13:04:20 +13:00
Jesse Hills
5c2c1560bb Fix rp2040 pwm to use pico-sdk, not mbed (#4059) 2022-11-23 13:04:20 +13:00
Jesse Hills
f7096ab78e Merge pull request #4041 from esphome/bump-2022.11.1
2022.11.1
2022-11-17 15:40:51 +13:00
Jesse Hills
98f8feb625 Bump version to 2022.11.1 2022-11-17 13:52:15 +13:00
Jesse Hills
9944ca414e Support ADC on RP2040 (#4040) 2022-11-17 13:52:15 +13:00
385 changed files with 3019 additions and 10507 deletions

View File

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

View File

@@ -23,11 +23,6 @@ permissions:
contents: read contents: read
packages: 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: jobs:
check-docker: check-docker:
name: Build docker containers name: Build docker containers

View File

@@ -7,7 +7,6 @@ on:
branches: [dev, beta, release] branches: [dev, beta, release]
pull_request: pull_request:
merge_group:
permissions: permissions:
contents: read contents: read
@@ -41,10 +40,6 @@ jobs:
file: tests/test3.yaml file: tests/test3.yaml
name: Test tests/test3.yaml name: Test tests/test3.yaml
pio_cache_key: test3 pio_cache_key: test3
- id: test
file: tests/test3.1.yaml
name: Test tests/test3.1.yaml
pio_cache_key: test3.1
- id: test - id: test
file: tests/test4.yaml file: tests/test4.yaml
name: Test tests/test4.yaml name: Test tests/test4.yaml
@@ -133,7 +128,7 @@ jobs:
- name: Install clang tools - name: Install clang tools
run: | run: |
sudo apt-get install \ sudo apt-get install \
clang-format-13 \ clang-format-11 \
clang-tidy-11 clang-tidy-11
if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format' if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format'
@@ -186,22 +181,9 @@ jobs:
- name: Run yamllint - name: Run yamllint
if: matrix.id == 'yamllint' if: matrix.id == 'yamllint'
uses: frenck/action-yamllint@v1.4.0 uses: frenck/action-yamllint@v1.3.1
- name: Suggested changes - name: Suggested changes
run: script/ci-suggest-changes run: script/ci-suggest-changes
# yamllint disable-line rule:line-length # yamllint disable-line rule:line-length
if: always() && (matrix.id == 'clang-tidy' || matrix.id == 'clang-format' || matrix.id == 'lint-python') 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

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

View File

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

View File

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

15
.vscode/tasks.json vendored
View File

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

View File

@@ -11,7 +11,6 @@ esphome/*.py @esphome/core
esphome/core/* @esphome/core esphome/core/* @esphome/core
# Integrations # Integrations
esphome/components/absolute_humidity/* @DAVe3283
esphome/components/ac_dimmer/* @glmnet esphome/components/ac_dimmer/* @glmnet
esphome/components/adc/* @esphome/core esphome/components/adc/* @esphome/core
esphome/components/adc128s102/* @DeerMaximum esphome/components/adc128s102/* @DeerMaximum
@@ -25,7 +24,6 @@ esphome/components/analog_threshold/* @ianchi
esphome/components/animation/* @syndlex esphome/components/animation/* @syndlex
esphome/components/anova/* @buxtronix esphome/components/anova/* @buxtronix
esphome/components/api/* @OttoWinter esphome/components/api/* @OttoWinter
esphome/components/as7341/* @mrgnr
esphome/components/async_tcp/* @OttoWinter esphome/components/async_tcp/* @OttoWinter
esphome/components/atc_mithermometer/* @ahpohl esphome/components/atc_mithermometer/* @ahpohl
esphome/components/b_parasite/* @rbaron esphome/components/b_parasite/* @rbaron
@@ -92,13 +90,11 @@ esphome/components/factory_reset/* @anatoly-savchenkov
esphome/components/fastled_base/* @OttoWinter esphome/components/fastled_base/* @OttoWinter
esphome/components/feedback/* @ianchi esphome/components/feedback/* @ianchi
esphome/components/fingerprint_grow/* @OnFreund @loongyh esphome/components/fingerprint_grow/* @OnFreund @loongyh
esphome/components/fs3000/* @kahrendt
esphome/components/globals/* @esphome/core esphome/components/globals/* @esphome/core
esphome/components/gpio/* @esphome/core esphome/components/gpio/* @esphome/core
esphome/components/gps/* @coogle esphome/components/gps/* @coogle
esphome/components/graph/* @synco esphome/components/graph/* @synco
esphome/components/growatt_solar/* @leeuwte esphome/components/growatt_solar/* @leeuwte
esphome/components/haier/* @Yarikx
esphome/components/havells_solar/* @sourabhjaiswal esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann esphome/components/hbridge/light/* @DotNetDann
@@ -111,22 +107,17 @@ esphome/components/hte501/* @Stock-M
esphome/components/hydreon_rgxx/* @functionpointer esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/i2c/* @esphome/core esphome/components/i2c/* @esphome/core
esphome/components/i2s_audio/* @jesserockz esphome/components/i2s_audio/* @jesserockz
esphome/components/i2s_audio/media_player/* @jesserockz
esphome/components/i2s_audio/microphone/* @jesserockz
esphome/components/ili9xxx/* @nielsnl68
esphome/components/improv_base/* @esphome/core esphome/components/improv_base/* @esphome/core
esphome/components/improv_serial/* @esphome/core esphome/components/improv_serial/* @esphome/core
esphome/components/ina260/* @MrEditor97 esphome/components/ina260/* @MrEditor97
esphome/components/inkbird_ibsth1_mini/* @fkirill esphome/components/inkbird_ibsth1_mini/* @fkirill
esphome/components/inkplate6/* @jesserockz esphome/components/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter esphome/components/integration/* @OttoWinter
esphome/components/internal_temperature/* @Mat931
esphome/components/interval/* @esphome/core esphome/components/interval/* @esphome/core
esphome/components/json/* @OttoWinter esphome/components/json/* @OttoWinter
esphome/components/kalman_combinator/* @Cat-Ion esphome/components/kalman_combinator/* @Cat-Ion
esphome/components/key_collector/* @ssieb esphome/components/key_collector/* @ssieb
esphome/components/key_provider/* @ssieb esphome/components/key_provider/* @ssieb
esphome/components/kuntze/* @ssieb
esphome/components/lcd_menu/* @numo68 esphome/components/lcd_menu/* @numo68
esphome/components/ld2410/* @sebcaps esphome/components/ld2410/* @sebcaps
esphome/components/ledc/* @OttoWinter esphome/components/ledc/* @OttoWinter
@@ -156,13 +147,11 @@ esphome/components/mcp9808/* @k7hpn
esphome/components/md5/* @esphome/core esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core esphome/components/mdns/* @esphome/core
esphome/components/media_player/* @jesserockz esphome/components/media_player/* @jesserockz
esphome/components/microphone/* @jesserockz
esphome/components/mics_4514/* @jesserockz esphome/components/mics_4514/* @jesserockz
esphome/components/midea/* @dudanov esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov esphome/components/midea_ir/* @dudanov
esphome/components/mitsubishi/* @RubyBailey esphome/components/mitsubishi/* @RubyBailey
esphome/components/mlx90393/* @functionpointer esphome/components/mlx90393/* @functionpointer
esphome/components/mmc5603/* @benhoff
esphome/components/modbus_controller/* @martgras esphome/components/modbus_controller/* @martgras
esphome/components/modbus_controller/binary_sensor/* @martgras esphome/components/modbus_controller/binary_sensor/* @martgras
esphome/components/modbus_controller/number/* @martgras esphome/components/modbus_controller/number/* @martgras
@@ -171,9 +160,8 @@ esphome/components/modbus_controller/select/* @martgras @stegm
esphome/components/modbus_controller/sensor/* @martgras esphome/components/modbus_controller/sensor/* @martgras
esphome/components/modbus_controller/switch/* @martgras esphome/components/modbus_controller/switch/* @martgras
esphome/components/modbus_controller/text_sensor/* @martgras esphome/components/modbus_controller/text_sensor/* @martgras
esphome/components/mopeka_ble/* @Fabian-Schmidt @spbrogan esphome/components/mopeka_ble/* @spbrogan
esphome/components/mopeka_pro_check/* @spbrogan esphome/components/mopeka_pro_check/* @spbrogan
esphome/components/mopeka_std_check/* @Fabian-Schmidt
esphome/components/mpl3115a2/* @kbickar esphome/components/mpl3115a2/* @kbickar
esphome/components/mpu6886/* @fabaff esphome/components/mpu6886/* @fabaff
esphome/components/network/* @esphome/core esphome/components/network/* @esphome/core
@@ -220,7 +208,6 @@ esphome/components/sdm_meter/* @jesserockz @polyfaces
esphome/components/sdp3x/* @Azimath esphome/components/sdp3x/* @Azimath
esphome/components/selec_meter/* @sourabhjaiswal esphome/components/selec_meter/* @sourabhjaiswal
esphome/components/select/* @esphome/core esphome/components/select/* @esphome/core
esphome/components/sen21231/* @shreyaskarnik
esphome/components/sen5x/* @martgras esphome/components/sen5x/* @martgras
esphome/components/sensirion_common/* @martgras esphome/components/sensirion_common/* @martgras
esphome/components/sensor/* @esphome/core esphome/components/sensor/* @esphome/core
@@ -290,7 +277,6 @@ esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter esphome/components/ultrasonic/* @OttoWinter
esphome/components/vbus/* @ssieb esphome/components/vbus/* @ssieb
esphome/components/version/* @esphome/core esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz
esphome/components/wake_on_lan/* @willwill2will54 esphome/components/wake_on_lan/* @willwill2will54
esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_base/* @OttoWinter
esphome/components/whirlpool/* @glmnet esphome/components/whirlpool/* @glmnet

View File

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

View File

@@ -6,9 +6,9 @@
ARG BASEIMGTYPE=docker ARG BASEIMGTYPE=docker
# https://github.com/hassio-addons/addon-debian-base/releases # https://github.com/hassio-addons/addon-debian-base/releases
FROM ghcr.io/hassio-addons/debian-base:6.2.3 AS base-hassio FROM ghcr.io/hassio-addons/debian-base:6.2.0 AS base-hassio
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye # https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
FROM debian:bullseye-20230208-slim AS base-docker FROM debian:bullseye-20221024-slim AS base-docker
FROM base-${BASEIMGTYPE} AS base FROM base-${BASEIMGTYPE} AS base
@@ -26,7 +26,7 @@ RUN \
python3-cryptography=3.3.2-1 \ python3-cryptography=3.3.2-1 \
iputils-ping=3:20210202-1 \ iputils-ping=3:20210202-1 \
git=1:2.30.2-1 \ git=1:2.30.2-1 \
curl=7.74.0-1.3+deb11u7 \ curl=7.74.0-1.3+deb11u5 \
openssh-client=1:8.4p1-5+deb11u1 \ openssh-client=1:8.4p1-5+deb11u1 \
&& rm -rf \ && rm -rf \
/tmp/* \ /tmp/* \
@@ -51,7 +51,7 @@ RUN \
# Ubuntu python3-pip is missing wheel # Ubuntu python3-pip is missing wheel
pip3 install --no-cache-dir \ pip3 install --no-cache-dir \
wheel==0.37.1 \ wheel==0.37.1 \
platformio==6.1.6 \ platformio==6.1.5 \
# Change some platformio settings # Change some platformio settings
&& platformio settings set enable_telemetry No \ && platformio settings set enable_telemetry No \
&& platformio settings set check_platformio_interval 1000000 \ && platformio settings set check_platformio_interval 1000000 \
@@ -135,7 +135,7 @@ RUN \
apt-get update \ apt-get update \
# Use pinned versions so that we get updates with build caching # Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
clang-format-13=1:13.0.1-6~deb11u1 \ clang-format-11=1:11.0.1-2 \
clang-tidy-11=1:11.0.1-2 \ clang-tidy-11=1:11.0.1-2 \
patch=2.7.6-7 \ patch=2.7.6-7 \
software-properties-common=0.96.20.2-2.1 \ software-properties-common=0.96.20.2-2.1 \

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,182 +0,0 @@
#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

@@ -1,76 +0,0 @@
#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

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

View File

@@ -65,7 +65,7 @@ void Am43Component::control(const CoverCall &call) {
if (this->invert_position_) if (this->invert_position_)
pos = 1 - pos; pos = 1 - pos;
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t) (pos * 100)); auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);

View File

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

View File

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

View File

@@ -53,9 +53,6 @@ service APIConnection {
rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {} rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {}
rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {} rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {}
rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {} rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {}
rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {}
} }
@@ -211,8 +208,6 @@ message DeviceInfoResponse {
string manufacturer = 12; string manufacturer = 12;
string friendly_name = 13; string friendly_name = 13;
uint32 voice_assistant_version = 14;
} }
message ListEntitiesRequest { message ListEntitiesRequest {
@@ -834,7 +829,7 @@ message ListEntitiesClimateResponse {
repeated ClimateMode supported_modes = 7; repeated ClimateMode supported_modes = 7;
float visual_min_temperature = 8; float visual_min_temperature = 8;
float visual_max_temperature = 9; float visual_max_temperature = 9;
float visual_target_temperature_step = 10; float visual_temperature_step = 10;
// for older peer versions - in new system this // for older peer versions - in new system this
// is if CLIMATE_PRESET_AWAY exists is supported_presets // is if CLIMATE_PRESET_AWAY exists is supported_presets
bool legacy_supports_away = 11; bool legacy_supports_away = 11;
@@ -847,7 +842,6 @@ message ListEntitiesClimateResponse {
bool disabled_by_default = 18; bool disabled_by_default = 18;
string icon = 19; string icon = 19;
EntityCategory entity_category = 20; EntityCategory entity_category = 20;
float visual_current_temperature_step = 21;
} }
message ClimateStateResponse { message ClimateStateResponse {
option (id) = 47; option (id) = 47;
@@ -1130,7 +1124,6 @@ message MediaPlayerCommandRequest {
message SubscribeBluetoothLEAdvertisementsRequest { message SubscribeBluetoothLEAdvertisementsRequest {
option (id) = 66; option (id) = 66;
option (source) = SOURCE_CLIENT; option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
} }
message BluetoothServiceData { message BluetoothServiceData {
@@ -1162,7 +1155,6 @@ enum BluetoothDeviceRequestType {
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3; BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4; BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5; BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6;
} }
message BluetoothDeviceRequest { message BluetoothDeviceRequest {
@@ -1346,91 +1338,3 @@ message BluetoothGATTNotifyResponse {
uint64 address = 1; uint64 address = 1;
uint32 handle = 2; uint32 handle = 2;
} }
message BluetoothDevicePairingResponse {
option (id) = 85;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool paired = 2;
int32 error = 3;
}
message BluetoothDeviceUnpairingResponse {
option (id) = 86;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool success = 2;
int32 error = 3;
}
message UnsubscribeBluetoothLEAdvertisementsRequest {
option (id) = 87;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
}
message BluetoothDeviceClearCacheResponse {
option (id) = 88;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool success = 2;
int32 error = 3;
}
// ==================== PUSH TO TALK ====================
message SubscribeVoiceAssistantRequest {
option (id) = 89;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
bool subscribe = 1;
}
message VoiceAssistantRequest {
option (id) = 90;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_VOICE_ASSISTANT";
bool start = 1;
}
message VoiceAssistantResponse {
option (id) = 91;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
uint32 port = 1;
bool error = 2;
}
enum VoiceAssistantEvent {
VOICE_ASSISTANT_ERROR = 0;
VOICE_ASSISTANT_RUN_START = 1;
VOICE_ASSISTANT_RUN_END = 2;
VOICE_ASSISTANT_STT_START = 3;
VOICE_ASSISTANT_STT_END = 4;
VOICE_ASSISTANT_INTENT_START = 5;
VOICE_ASSISTANT_INTENT_END = 6;
VOICE_ASSISTANT_TTS_START = 7;
VOICE_ASSISTANT_TTS_END = 8;
}
message VoiceAssistantEventData {
string name = 1;
string value = 2;
}
message VoiceAssistantEventResponse {
option (id) = 92;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
VoiceAssistantEvent event_type = 1;
repeated VoiceAssistantEventData data = 2;
}

View File

@@ -1,6 +1,5 @@
#include "api_connection.h" #include "api_connection.h"
#include <cerrno> #include <cerrno>
#include <cinttypes>
#include "esphome/components/network/util.h" #include "esphome/components/network/util.h"
#include "esphome/core/entity_base.h" #include "esphome/core/entity_base.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
@@ -16,9 +15,6 @@
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h" #include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
#endif #endif
#ifdef USE_VOICE_ASSISTANT
#include "esphome/components/voice_assistant/voice_assistant.h"
#endif
namespace esphome { namespace esphome {
namespace api { namespace api {
@@ -184,8 +180,7 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_
ListEntitiesBinarySensorResponse msg; ListEntitiesBinarySensorResponse msg;
msg.object_id = binary_sensor->get_object_id(); msg.object_id = binary_sensor->get_object_id();
msg.key = binary_sensor->get_object_id_hash(); msg.key = binary_sensor->get_object_id_hash();
if (binary_sensor->has_own_name()) msg.name = binary_sensor->get_name();
msg.name = binary_sensor->get_name();
msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor); msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
msg.device_class = binary_sensor->get_device_class(); msg.device_class = binary_sensor->get_device_class();
msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor();
@@ -217,8 +212,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) {
ListEntitiesCoverResponse msg; ListEntitiesCoverResponse msg;
msg.key = cover->get_object_id_hash(); msg.key = cover->get_object_id_hash();
msg.object_id = cover->get_object_id(); msg.object_id = cover->get_object_id();
if (cover->has_own_name()) msg.name = cover->get_name();
msg.name = cover->get_name();
msg.unique_id = get_default_unique_id("cover", cover); msg.unique_id = get_default_unique_id("cover", cover);
msg.assumed_state = traits.get_is_assumed_state(); msg.assumed_state = traits.get_is_assumed_state();
msg.supports_position = traits.get_supports_position(); msg.supports_position = traits.get_supports_position();
@@ -281,8 +275,7 @@ bool APIConnection::send_fan_info(fan::Fan *fan) {
ListEntitiesFanResponse msg; ListEntitiesFanResponse msg;
msg.key = fan->get_object_id_hash(); msg.key = fan->get_object_id_hash();
msg.object_id = fan->get_object_id(); msg.object_id = fan->get_object_id();
if (fan->has_own_name()) msg.name = fan->get_name();
msg.name = fan->get_name();
msg.unique_id = get_default_unique_id("fan", fan); msg.unique_id = get_default_unique_id("fan", fan);
msg.supports_oscillation = traits.supports_oscillation(); msg.supports_oscillation = traits.supports_oscillation();
msg.supports_speed = traits.supports_speed(); msg.supports_speed = traits.supports_speed();
@@ -344,8 +337,7 @@ bool APIConnection::send_light_info(light::LightState *light) {
ListEntitiesLightResponse msg; ListEntitiesLightResponse msg;
msg.key = light->get_object_id_hash(); msg.key = light->get_object_id_hash();
msg.object_id = light->get_object_id(); msg.object_id = light->get_object_id();
if (light->has_own_name()) msg.name = light->get_name();
msg.name = light->get_name();
msg.unique_id = get_default_unique_id("light", light); msg.unique_id = get_default_unique_id("light", light);
msg.disabled_by_default = light->is_disabled_by_default(); msg.disabled_by_default = light->is_disabled_by_default();
@@ -426,8 +418,7 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
ListEntitiesSensorResponse msg; ListEntitiesSensorResponse msg;
msg.key = sensor->get_object_id_hash(); msg.key = sensor->get_object_id_hash();
msg.object_id = sensor->get_object_id(); msg.object_id = sensor->get_object_id();
if (sensor->has_own_name()) msg.name = sensor->get_name();
msg.name = sensor->get_name();
msg.unique_id = sensor->unique_id(); msg.unique_id = sensor->unique_id();
if (msg.unique_id.empty()) if (msg.unique_id.empty())
msg.unique_id = get_default_unique_id("sensor", sensor); msg.unique_id = get_default_unique_id("sensor", sensor);
@@ -457,8 +448,7 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) {
ListEntitiesSwitchResponse msg; ListEntitiesSwitchResponse msg;
msg.key = a_switch->get_object_id_hash(); msg.key = a_switch->get_object_id_hash();
msg.object_id = a_switch->get_object_id(); msg.object_id = a_switch->get_object_id();
if (a_switch->has_own_name()) msg.name = a_switch->get_name();
msg.name = a_switch->get_name();
msg.unique_id = get_default_unique_id("switch", a_switch); msg.unique_id = get_default_unique_id("switch", a_switch);
msg.icon = a_switch->get_icon(); msg.icon = a_switch->get_icon();
msg.assumed_state = a_switch->assumed_state(); msg.assumed_state = a_switch->assumed_state();
@@ -543,8 +533,7 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
ListEntitiesClimateResponse msg; ListEntitiesClimateResponse msg;
msg.key = climate->get_object_id_hash(); msg.key = climate->get_object_id_hash();
msg.object_id = climate->get_object_id(); msg.object_id = climate->get_object_id();
if (climate->has_own_name()) msg.name = climate->get_name();
msg.name = climate->get_name();
msg.unique_id = get_default_unique_id("climate", climate); msg.unique_id = get_default_unique_id("climate", climate);
msg.disabled_by_default = climate->is_disabled_by_default(); msg.disabled_by_default = climate->is_disabled_by_default();
@@ -559,9 +548,7 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
msg.visual_min_temperature = traits.get_visual_min_temperature(); msg.visual_min_temperature = traits.get_visual_min_temperature();
msg.visual_max_temperature = traits.get_visual_max_temperature(); msg.visual_max_temperature = traits.get_visual_max_temperature();
msg.visual_target_temperature_step = traits.get_visual_target_temperature_step(); msg.visual_temperature_step = traits.get_visual_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.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
msg.supports_action = traits.get_supports_action(); msg.supports_action = traits.get_supports_action();
@@ -622,8 +609,7 @@ bool APIConnection::send_number_info(number::Number *number) {
ListEntitiesNumberResponse msg; ListEntitiesNumberResponse msg;
msg.key = number->get_object_id_hash(); msg.key = number->get_object_id_hash();
msg.object_id = number->get_object_id(); msg.object_id = number->get_object_id();
if (number->has_own_name()) msg.name = number->get_name();
msg.name = number->get_name();
msg.unique_id = get_default_unique_id("number", number); msg.unique_id = get_default_unique_id("number", number);
msg.icon = number->get_icon(); msg.icon = number->get_icon();
msg.disabled_by_default = number->is_disabled_by_default(); msg.disabled_by_default = number->is_disabled_by_default();
@@ -664,8 +650,7 @@ bool APIConnection::send_select_info(select::Select *select) {
ListEntitiesSelectResponse msg; ListEntitiesSelectResponse msg;
msg.key = select->get_object_id_hash(); msg.key = select->get_object_id_hash();
msg.object_id = select->get_object_id(); msg.object_id = select->get_object_id();
if (select->has_own_name()) msg.name = select->get_name();
msg.name = select->get_name();
msg.unique_id = get_default_unique_id("select", select); msg.unique_id = get_default_unique_id("select", select);
msg.icon = select->get_icon(); msg.icon = select->get_icon();
msg.disabled_by_default = select->is_disabled_by_default(); msg.disabled_by_default = select->is_disabled_by_default();
@@ -692,8 +677,7 @@ bool APIConnection::send_button_info(button::Button *button) {
ListEntitiesButtonResponse msg; ListEntitiesButtonResponse msg;
msg.key = button->get_object_id_hash(); msg.key = button->get_object_id_hash();
msg.object_id = button->get_object_id(); msg.object_id = button->get_object_id();
if (button->has_own_name()) msg.name = button->get_name();
msg.name = button->get_name();
msg.unique_id = get_default_unique_id("button", button); msg.unique_id = get_default_unique_id("button", button);
msg.icon = button->get_icon(); msg.icon = button->get_icon();
msg.disabled_by_default = button->is_disabled_by_default(); msg.disabled_by_default = button->is_disabled_by_default();
@@ -724,8 +708,7 @@ bool APIConnection::send_lock_info(lock::Lock *a_lock) {
ListEntitiesLockResponse msg; ListEntitiesLockResponse msg;
msg.key = a_lock->get_object_id_hash(); msg.key = a_lock->get_object_id_hash();
msg.object_id = a_lock->get_object_id(); msg.object_id = a_lock->get_object_id();
if (a_lock->has_own_name()) msg.name = a_lock->get_name();
msg.name = a_lock->get_name();
msg.unique_id = get_default_unique_id("lock", a_lock); msg.unique_id = get_default_unique_id("lock", a_lock);
msg.icon = a_lock->get_icon(); msg.icon = a_lock->get_icon();
msg.assumed_state = a_lock->traits.get_assumed_state(); msg.assumed_state = a_lock->traits.get_assumed_state();
@@ -770,8 +753,7 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
ListEntitiesMediaPlayerResponse msg; ListEntitiesMediaPlayerResponse msg;
msg.key = media_player->get_object_id_hash(); msg.key = media_player->get_object_id_hash();
msg.object_id = media_player->get_object_id(); msg.object_id = media_player->get_object_id();
if (media_player->has_own_name()) msg.name = media_player->get_name();
msg.name = media_player->get_name();
msg.unique_id = get_default_unique_id("media_player", media_player); msg.unique_id = get_default_unique_id("media_player", media_player);
msg.icon = media_player->get_icon(); msg.icon = media_player->get_icon();
msg.disabled_by_default = media_player->is_disabled_by_default(); msg.disabled_by_default = media_player->is_disabled_by_default();
@@ -815,8 +797,7 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
ListEntitiesCameraResponse msg; ListEntitiesCameraResponse msg;
msg.key = camera->get_object_id_hash(); msg.key = camera->get_object_id_hash();
msg.object_id = camera->get_object_id(); msg.object_id = camera->get_object_id();
if (camera->has_own_name()) msg.name = camera->get_name();
msg.name = camera->get_name();
msg.unique_id = get_default_unique_id("camera", camera); msg.unique_id = get_default_unique_id("camera", camera);
msg.disabled_by_default = camera->is_disabled_by_default(); msg.disabled_by_default = camera->is_disabled_by_default();
msg.icon = camera->get_icon(); msg.icon = camera->get_icon();
@@ -896,30 +877,6 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
} }
#endif #endif
#ifdef USE_VOICE_ASSISTANT
bool APIConnection::request_voice_assistant(bool start) {
if (!this->voice_assistant_subscription_)
return false;
VoiceAssistantRequest msg;
msg.start = start;
return this->send_voice_assistant_request(msg);
}
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
if (voice_assistant::global_voice_assistant != nullptr) {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
this->helper_->getpeername((struct sockaddr *) &storage, &len);
voice_assistant::global_voice_assistant->start(&storage, msg.port);
}
};
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
if (voice_assistant::global_voice_assistant != nullptr) {
voice_assistant::global_voice_assistant->on_event(msg);
}
}
#endif
bool APIConnection::send_log_message(int level, const char *tag, const char *line) { bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level) if (this->log_subscription_ < level)
return false; return false;
@@ -939,7 +896,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
this->helper_->set_log_info(client_info_); this->helper_->set_log_info(client_info_);
this->client_api_version_major_ = msg.api_version_major; this->client_api_version_major_ = msg.api_version_major;
this->client_api_version_minor_ = msg.api_version_minor; this->client_api_version_minor_ = msg.api_version_minor;
ESP_LOGV(TAG, "Hello from client: '%s' | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(), ESP_LOGV(TAG, "Hello from client: '%s' | API Version %d.%d", this->client_info_.c_str(),
this->client_api_version_major_, this->client_api_version_minor_); this->client_api_version_major_, this->client_api_version_minor_);
HelloResponse resp; HelloResponse resp;
@@ -994,12 +951,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.webserver_port = USE_WEBSERVER_PORT; resp.webserver_port = USE_WEBSERVER_PORT;
#endif #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION
: bluetooth_proxy::PASSIVE_ONLY_VERSION;
#endif
#ifdef USE_VOICE_ASSISTANT
resp.voice_assistant_version = 1;
#endif #endif
return resp; return resp;
} }

View File

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

View File

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

View File

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

View File

@@ -400,34 +400,6 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE"; return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE"; return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE";
default:
return "UNKNOWN";
}
}
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::VoiceAssistantEvent value) {
switch (value) {
case enums::VOICE_ASSISTANT_ERROR:
return "VOICE_ASSISTANT_ERROR";
case enums::VOICE_ASSISTANT_RUN_START:
return "VOICE_ASSISTANT_RUN_START";
case enums::VOICE_ASSISTANT_RUN_END:
return "VOICE_ASSISTANT_RUN_END";
case enums::VOICE_ASSISTANT_STT_START:
return "VOICE_ASSISTANT_STT_START";
case enums::VOICE_ASSISTANT_STT_END:
return "VOICE_ASSISTANT_STT_END";
case enums::VOICE_ASSISTANT_INTENT_START:
return "VOICE_ASSISTANT_INTENT_START";
case enums::VOICE_ASSISTANT_INTENT_END:
return "VOICE_ASSISTANT_INTENT_END";
case enums::VOICE_ASSISTANT_TTS_START:
return "VOICE_ASSISTANT_TTS_START";
case enums::VOICE_ASSISTANT_TTS_END:
return "VOICE_ASSISTANT_TTS_END";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
@@ -620,10 +592,6 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
this->bluetooth_proxy_version = value.as_uint32(); this->bluetooth_proxy_version = value.as_uint32();
return true; return true;
} }
case 14: {
this->voice_assistant_version = value.as_uint32();
return true;
}
default: default:
return false; return false;
} }
@@ -684,7 +652,6 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(11, this->bluetooth_proxy_version); buffer.encode_uint32(11, this->bluetooth_proxy_version);
buffer.encode_string(12, this->manufacturer); buffer.encode_string(12, this->manufacturer);
buffer.encode_string(13, this->friendly_name); buffer.encode_string(13, this->friendly_name);
buffer.encode_uint32(14, this->voice_assistant_version);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void DeviceInfoResponse::dump_to(std::string &out) const { void DeviceInfoResponse::dump_to(std::string &out) const {
@@ -743,11 +710,6 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
out.append(" friendly_name: "); out.append(" friendly_name: ");
out.append("'").append(this->friendly_name).append("'"); out.append("'").append(this->friendly_name).append("'");
out.append("\n"); out.append("\n");
out.append(" voice_assistant_version: ");
sprintf(buffer, "%u", this->voice_assistant_version);
out.append(buffer);
out.append("\n");
out.append("}"); out.append("}");
} }
#endif #endif
@@ -3489,11 +3451,7 @@ bool ListEntitiesClimateResponse::decode_32bit(uint32_t field_id, Proto32Bit val
return true; return true;
} }
case 10: { case 10: {
this->visual_target_temperature_step = value.as_float(); this->visual_temperature_step = value.as_float();
return true;
}
case 21: {
this->visual_current_temperature_step = value.as_float();
return true; return true;
} }
default: default:
@@ -3512,7 +3470,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
} }
buffer.encode_float(8, this->visual_min_temperature); buffer.encode_float(8, this->visual_min_temperature);
buffer.encode_float(9, this->visual_max_temperature); buffer.encode_float(9, this->visual_max_temperature);
buffer.encode_float(10, this->visual_target_temperature_step); buffer.encode_float(10, this->visual_temperature_step);
buffer.encode_bool(11, this->legacy_supports_away); buffer.encode_bool(11, this->legacy_supports_away);
buffer.encode_bool(12, this->supports_action); buffer.encode_bool(12, this->supports_action);
for (auto &it : this->supported_fan_modes) { for (auto &it : this->supported_fan_modes) {
@@ -3533,7 +3491,6 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(18, this->disabled_by_default); buffer.encode_bool(18, this->disabled_by_default);
buffer.encode_string(19, this->icon); buffer.encode_string(19, this->icon);
buffer.encode_enum<enums::EntityCategory>(20, this->entity_category); buffer.encode_enum<enums::EntityCategory>(20, this->entity_category);
buffer.encode_float(21, this->visual_current_temperature_step);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesClimateResponse::dump_to(std::string &out) const { void ListEntitiesClimateResponse::dump_to(std::string &out) const {
@@ -3580,8 +3537,8 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
out.append(buffer); out.append(buffer);
out.append("\n"); out.append("\n");
out.append(" visual_target_temperature_step: "); out.append(" visual_temperature_step: ");
sprintf(buffer, "%g", this->visual_target_temperature_step); sprintf(buffer, "%g", this->visual_temperature_step);
out.append(buffer); out.append(buffer);
out.append("\n"); out.append("\n");
@@ -3634,11 +3591,6 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
out.append(" entity_category: "); out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category)); out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n"); 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("}"); out.append("}");
} }
#endif #endif
@@ -6012,290 +5964,6 @@ void BluetoothGATTNotifyResponse::dump_to(std::string &out) const {
out.append("}"); out.append("}");
} }
#endif #endif
bool BluetoothDevicePairingResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->paired = value.as_bool();
return true;
}
case 3: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->paired);
buffer.encode_int32(3, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDevicePairingResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDevicePairingResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" paired: ");
out.append(YESNO(this->paired));
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothDeviceUnpairingResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->success = value.as_bool();
return true;
}
case 3: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->success);
buffer.encode_int32(3, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDeviceUnpairingResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" success: ");
out.append(YESNO(this->success));
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
void UnsubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {}
#ifdef HAS_PROTO_MESSAGE_DUMP
void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const {
out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}");
}
#endif
bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->success = value.as_bool();
return true;
}
case 3: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->success);
buffer.encode_int32(3, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDeviceClearCacheResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" success: ");
out.append(YESNO(this->success));
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool SubscribeVoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->subscribe = value.as_bool();
return true;
}
default:
return false;
}
}
void SubscribeVoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->subscribe); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("SubscribeVoiceAssistantRequest {\n");
out.append(" subscribe: ");
out.append(YESNO(this->subscribe));
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->start = value.as_bool();
return true;
}
default:
return false;
}
}
void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantRequest {\n");
out.append(" start: ");
out.append(YESNO(this->start));
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->port = value.as_uint32();
return true;
}
case 2: {
this->error = value.as_bool();
return true;
}
default:
return false;
}
}
void VoiceAssistantResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->port);
buffer.encode_bool(2, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantResponse {\n");
out.append(" port: ");
sprintf(buffer, "%u", this->port);
out.append(buffer);
out.append("\n");
out.append(" error: ");
out.append(YESNO(this->error));
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantEventData::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->name = value.as_string();
return true;
}
case 2: {
this->value = value.as_string();
return true;
}
default:
return false;
}
}
void VoiceAssistantEventData::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->name);
buffer.encode_string(2, this->value);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantEventData::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantEventData {\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" value: ");
out.append("'").append(this->value).append("'");
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->event_type = value.as_enum<enums::VoiceAssistantEvent>();
return true;
}
default:
return false;
}
}
bool VoiceAssistantEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
this->data.push_back(value.as_message<VoiceAssistantEventData>());
return true;
}
default:
return false;
}
}
void VoiceAssistantEventResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_enum<enums::VoiceAssistantEvent>(1, this->event_type);
for (auto &it : this->data) {
buffer.encode_message<VoiceAssistantEventData>(2, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantEventResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantEventResponse {\n");
out.append(" event_type: ");
out.append(proto_enum_to_string<enums::VoiceAssistantEvent>(this->event_type));
out.append("\n");
for (const auto &it : this->data) {
out.append(" data: ");
it.dump_to(out);
out.append("\n");
}
out.append("}");
}
#endif
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

View File

@@ -163,18 +163,6 @@ enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3, BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6,
};
enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_ERROR = 0,
VOICE_ASSISTANT_RUN_START = 1,
VOICE_ASSISTANT_RUN_END = 2,
VOICE_ASSISTANT_STT_START = 3,
VOICE_ASSISTANT_STT_END = 4,
VOICE_ASSISTANT_INTENT_START = 5,
VOICE_ASSISTANT_INTENT_END = 6,
VOICE_ASSISTANT_TTS_START = 7,
VOICE_ASSISTANT_TTS_END = 8,
}; };
} // namespace enums } // namespace enums
@@ -290,7 +278,6 @@ class DeviceInfoResponse : public ProtoMessage {
uint32_t bluetooth_proxy_version{0}; uint32_t bluetooth_proxy_version{0};
std::string manufacturer{}; std::string manufacturer{};
std::string friendly_name{}; std::string friendly_name{};
uint32_t voice_assistant_version{0};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
@@ -928,7 +915,7 @@ class ListEntitiesClimateResponse : public ProtoMessage {
std::vector<enums::ClimateMode> supported_modes{}; std::vector<enums::ClimateMode> supported_modes{};
float visual_min_temperature{0.0f}; float visual_min_temperature{0.0f};
float visual_max_temperature{0.0f}; float visual_max_temperature{0.0f};
float visual_target_temperature_step{0.0f}; float visual_temperature_step{0.0f};
bool legacy_supports_away{false}; bool legacy_supports_away{false};
bool supports_action{false}; bool supports_action{false};
std::vector<enums::ClimateFanMode> supported_fan_modes{}; std::vector<enums::ClimateFanMode> supported_fan_modes{};
@@ -939,7 +926,6 @@ class ListEntitiesClimateResponse : public ProtoMessage {
bool disabled_by_default{false}; bool disabled_by_default{false};
std::string icon{}; std::string icon{};
enums::EntityCategory entity_category{}; enums::EntityCategory entity_category{};
float visual_current_temperature_step{0.0f};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
@@ -1541,113 +1527,6 @@ class BluetoothGATTNotifyResponse : public ProtoMessage {
protected: protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
class BluetoothDevicePairingResponse : public ProtoMessage {
public:
uint64_t address{0};
bool paired{false};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothDeviceUnpairingResponse : public ProtoMessage {
public:
uint64_t address{0};
bool success{false};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
public:
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class BluetoothDeviceClearCacheResponse : public ProtoMessage {
public:
uint64_t address{0};
bool success{false};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class SubscribeVoiceAssistantRequest : public ProtoMessage {
public:
bool subscribe{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantRequest : public ProtoMessage {
public:
bool start{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantResponse : public ProtoMessage {
public:
uint32_t port{0};
bool error{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantEventData : public ProtoMessage {
public:
std::string name{};
std::string value{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class VoiceAssistantEventResponse : public ProtoMessage {
public:
enums::VoiceAssistantEvent event_type{};
std::vector<VoiceAssistantEventData> data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,271 +0,0 @@
#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

@@ -1,144 +0,0 @@
#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

@@ -1,112 +0,0 @@
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)) 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_TEMPERATURE, var.set_temperature),
(CONF_HUMIDITY, var.set_humidity), (CONF_HUMIDITY, var.set_humidity),
(CONF_BATTERY_VOLTAGE, var.set_battery_voltage), (CONF_BATTERY_VOLTAGE, var.set_battery_voltage),

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,15 +19,6 @@ 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. /** Base class for all binary_sensor-type classes.
* *
* This class includes a callback that components such as MQTT can subscribe to for state changes. * This class includes a callback that components such as MQTT can subscribe to for state changes.
@@ -80,6 +71,14 @@ class BinarySensor : public EntityBase {
virtual bool is_status_binary_sensor() const; virtual bool is_status_binary_sensor() const;
// ========== OVERRIDE METHODS ==========
// (You'll only need this when creating your own custom binary sensor)
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
virtual std::string device_class();
protected: protected:
CallbackManager<void(bool)> state_callback_{}; CallbackManager<void(bool)> state_callback_{};
optional<std::string> device_class_{}; ///< Stores the override of the device class optional<std::string> device_class_{}; ///< Stores the override of the device class

View File

@@ -30,7 +30,7 @@ void BinarySensorMap::process_group_() {
if (bs.binary_sensor->state) { if (bs.binary_sensor->state) {
num_active_sensors++; num_active_sensors++;
total_current_value += bs.sensor_value; total_current_value += bs.sensor_value;
mask |= 1ULL << i; mask |= 1 << i;
} }
} }
// check if the sensor map was touched // check if the sensor map was touched
@@ -38,11 +38,12 @@ void BinarySensorMap::process_group_() {
// did the bit_mask change or is it a new sensor touch // did the bit_mask change or is it a new sensor touch
if (this->last_mask_ != mask) { if (this->last_mask_ != mask) {
float publish_value = total_current_value / num_active_sensors; float publish_value = total_current_value / num_active_sensors;
ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value);
this->publish_state(publish_value); this->publish_state(publish_value);
} }
} else if (this->last_mask_ != 0ULL) { } else if (this->last_mask_ != 0ULL) {
// is this a new sensor release // is this a new sensor release
ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str()); ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
this->publish_state(NAN); this->publish_state(NAN);
} }
this->last_mask_ = mask; this->last_mask_ = mask;
@@ -51,22 +52,28 @@ void BinarySensorMap::process_group_() {
void BinarySensorMap::process_sum_() { void BinarySensorMap::process_sum_() {
float total_current_value = 0.0; float total_current_value = 0.0;
uint64_t mask = 0x00; uint64_t mask = 0x00;
// - check all binary_sensor states // check all binary_sensors for its state. when active add its value to total_current_value.
// - if active, add its value to total_current_value // create a bitmask for the binary_sensor status on all channels
// - creates a bitmask for the binary_sensor status on all channels
for (size_t i = 0; i < this->channels_.size(); i++) { for (size_t i = 0; i < this->channels_.size(); i++) {
auto bs = this->channels_[i]; auto bs = this->channels_[i];
if (bs.binary_sensor->state) { if (bs.binary_sensor->state) {
total_current_value += bs.sensor_value; total_current_value += bs.sensor_value;
mask |= 1ULL << i; mask |= 1 << i;
} }
} }
// check if the sensor map was touched
// update state only if the binary sensor states have changed or if no state has ever been sent on boot if (mask != 0ULL) {
if ((this->last_mask_ != mask) || (!this->has_state())) { // did the bit_mask change or is it a new sensor touch
this->publish_state(total_current_value); if (this->last_mask_ != mask) {
float publish_value = total_current_value;
ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value);
this->publish_state(publish_value);
}
} else if (this->last_mask_ != 0ULL) {
// is this a new sensor release
ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing 0", this->name_.c_str());
this->publish_state(0.0);
} }
this->last_mask_ = mask; this->last_mask_ = mask;
} }

View File

@@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.typed_schema(
).extend( ).extend(
{ {
cv.Required(CONF_CHANNELS): cv.All( cv.Required(CONF_CHANNELS): cv.All(
cv.ensure_list(entry), cv.Length(min=1, max=64) cv.ensure_list(entry), cv.Length(min=1)
), ),
} }
), ),
@@ -50,7 +50,7 @@ CONFIG_SCHEMA = cv.typed_schema(
).extend( ).extend(
{ {
cv.Required(CONF_CHANNELS): cv.All( cv.Required(CONF_CHANNELS): cv.All(
cv.ensure_list(entry), cv.Length(min=1, max=64) cv.ensure_list(entry), cv.Length(min=1)
), ),
} }
), ),

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
#pragma once #pragma once
#ifdef USE_ESP32
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "esphome/components/ble_client/ble_client.h" #include "esphome/components/ble_client/ble_client.h"
#ifdef USE_ESP32
namespace esphome { namespace esphome {
namespace ble_client { namespace ble_client {
class BLEClientConnectTrigger : public Trigger<>, public BLEClientNode { class BLEClientConnectTrigger : public Trigger<>, public BLEClientNode {

View File

@@ -158,25 +158,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
return true; 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) { esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
if (!this->connected()) { if (!this->connected()) {
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not connected.", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not connected.", this->connection_index_,

View File

@@ -13,7 +13,6 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase {
public: public:
bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; 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 read_characteristic(uint16_t handle);
esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response); esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response);

View File

@@ -257,7 +257,12 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str()); ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
} }
if (msg.has_address_type) { if (msg.has_address_type) {
uint64_to_bd_addr(msg.address, connection->remote_bda_); 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;
connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type)); connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
connection->set_state(espbt::ClientState::DISCOVERED); connection->set_state(espbt::ClientState::DISCOVERED);
} else { } else {
@@ -285,34 +290,9 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
} }
break; break;
} }
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR: { case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR:
auto *connection = this->get_connection_(msg.address, false); case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
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; break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR: {
esp_bd_addr_t address;
uint64_to_bd_addr(msg.address, address);
esp_err_t ret = esp_ble_remove_bond_device(address);
api::global_api_server->send_bluetooth_device_unpairing(msg.address, ret == ESP_OK, ret);
break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: {
esp_bd_addr_t address;
uint64_to_bd_addr(msg.address, address);
esp_err_t ret = esp_ble_gattc_cache_clean(address);
api::global_api_server->send_bluetooth_device_clear_cache(msg.address, ret == ESP_OK, ret);
break;
}
} }
} }

View File

@@ -44,15 +44,6 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
int get_bluetooth_connections_free(); int get_bluetooth_connections_free();
int get_bluetooth_connections_limit() { return this->connections_.size(); } 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; } void set_active(bool active) { this->active_ = active; }
bool has_active() { return this->active_; } bool has_active() { return this->active_; }
@@ -68,14 +59,6 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
// Version 1: Initial version without active connections
// Version 2: Support for active connections
// Version 3: New connection API
// Version 4: Pairing support
// Version 5: Cache clear support
static const uint32_t ACTIVE_CONNECTIONS_VERSION = 5;
static const uint32_t PASSIVE_ONLY_VERSION = 1;
} // namespace bluetooth_proxy } // namespace bluetooth_proxy
} // namespace esphome } // namespace esphome

View File

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

View File

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

View File

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

View File

@@ -10,24 +10,19 @@ static const char *const TAG = "bme680_bsec.sensor";
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"}; static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
std::vector<BME680BSECComponent *> BME680BSECComponent *BME680BSECComponent::instance; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
BME680BSECComponent::instances; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
uint8_t BME680BSECComponent::work_buffer_[BSEC_MAX_WORKBUFFER_SIZE] = {0};
void BME680BSECComponent::setup() { void BME680BSECComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up BME680(%s) via BSEC...", this->device_id_.c_str()); ESP_LOGCONFIG(TAG, "Setting up BME680 via BSEC...");
BME680BSECComponent::instance = this;
uint8_t new_idx = BME680BSECComponent::instances.size(); this->bsec_status_ = bsec_init();
BME680BSECComponent::instances.push_back(this); if (this->bsec_status_ != BSEC_OK) {
this->mark_failed();
return;
}
this->bsec_state_data_valid_ = false; this->bme680_.dev_id = this->address_;
// 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_.intf = BME680_I2C_INTF;
this->bme680_.read = BME680BSECComponent::read_bytes_wrapper; this->bme680_.read = BME680BSECComponent::read_bytes_wrapper;
this->bme680_.write = BME680BSECComponent::write_bytes_wrapper; this->bme680_.write = BME680BSECComponent::write_bytes_wrapper;
@@ -40,30 +35,29 @@ void BME680BSECComponent::setup() {
return; return;
} }
// Initialize the BSEC library if (this->sample_rate_ == SAMPLE_RATE_ULP) {
if (this->reinit_bsec_lib_() != 0) { 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) {
this->mark_failed(); this->mark_failed();
return; return;
} }
// Load the BSEC library state from storage
this->load_state_(); this->load_state_();
} }
void BME680BSECComponent::set_config_() { void BME680BSECComponent::set_config_(const uint8_t *config) {
if (this->sample_rate_ == SAMPLE_RATE_ULP) { uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
const uint8_t config[] = { this->bsec_status_ = bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, work_buffer, sizeof(work_buffer));
#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) { float BME680BSECComponent::calc_sensor_sample_rate_(SampleRate sample_rate) {
@@ -124,12 +118,10 @@ void BME680BSECComponent::update_subscription_() {
uint8_t num_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR; uint8_t num_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
this->bsec_status_ = this->bsec_status_ =
bsec_update_subscription(virtual_sensors, num_virtual_sensors, sensor_settings, &num_sensor_settings); 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() { void BME680BSECComponent::dump_config() {
ESP_LOGCONFIG(TAG, "%s via BSEC:", this->device_id_.c_str()); ESP_LOGCONFIG(TAG, "BME680 via BSEC:");
bsec_version_t version; bsec_version_t version;
bsec_get_version(&version); bsec_get_version(&version);
@@ -193,31 +185,23 @@ void BME680BSECComponent::run_() {
return; return;
} }
ESP_LOGV(TAG, "%s: Performing sensor run", this->device_id_.c_str()); ESP_LOGV(TAG, "Performing sensor run");
// Restore BSEC library state bsec_bme_settings_t bme680_settings;
// The reinit_bsec_lib_ method is computationally expensive: it takes 1200÷2900 microseconds on a ESP32. this->bsec_status_ = bsec_sensor_control(curr_time_ns, &bme680_settings);
// 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) { if (this->bsec_status_ < BSEC_OK) {
ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC Error Code %d)", this->bsec_status_); ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC Error Code %d)", this->bsec_status_);
return; return;
} }
this->next_call_ns_ = this->bme680_settings_.next_call; this->next_call_ns_ = bme680_settings.next_call;
if (this->bme680_settings_.trigger_measurement) { if (bme680_settings.trigger_measurement) {
this->bme680_.tph_sett.os_temp = this->bme680_settings_.temperature_oversampling; this->bme680_.tph_sett.os_temp = bme680_settings.temperature_oversampling;
this->bme680_.tph_sett.os_pres = this->bme680_settings_.pressure_oversampling; this->bme680_.tph_sett.os_pres = bme680_settings.pressure_oversampling;
this->bme680_.tph_sett.os_hum = this->bme680_settings_.humidity_oversampling; this->bme680_.tph_sett.os_hum = bme680_settings.humidity_oversampling;
this->bme680_.gas_sett.run_gas = this->bme680_settings_.run_gas; this->bme680_.gas_sett.run_gas = bme680_settings.run_gas;
this->bme680_.gas_sett.heatr_temp = this->bme680_settings_.heater_temperature; this->bme680_.gas_sett.heatr_temp = bme680_settings.heater_temperature;
this->bme680_.gas_sett.heatr_dur = this->bme680_settings_.heating_duration; this->bme680_.gas_sett.heatr_dur = bme680_settings.heating_duration;
this->bme680_.power_mode = BME680_FORCED_MODE; this->bme680_.power_mode = BME680_FORCED_MODE;
uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL; 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_); this->bme680_status_ = bme680_set_sensor_settings(desired_settings, &this->bme680_);
@@ -234,26 +218,19 @@ void BME680BSECComponent::run_() {
uint16_t meas_dur = 0; uint16_t meas_dur = 0;
bme680_get_profile_dur(&meas_dur, &this->bme680_); 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); ESP_LOGV(TAG, "Queueing read in %ums", meas_dur);
this->set_timeout("read", meas_dur, [this]() { this->read_(); }); this->set_timeout("read", meas_dur,
[this, curr_time_ns, bme680_settings]() { this->read_(curr_time_ns, bme680_settings); });
} else { } else {
ESP_LOGV(TAG, "Measurement not required"); ESP_LOGV(TAG, "Measurement not required");
this->read_(); this->read_(curr_time_ns, bme680_settings);
} }
} }
void BME680BSECComponent::read_() { void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings) {
ESP_LOGV(TAG, "%s: Reading data", this->device_id_.c_str()); ESP_LOGV(TAG, "Reading data");
int64_t curr_time_ns = this->get_time_ns_();
if (this->bme680_settings_.trigger_measurement) { if (bme680_settings.trigger_measurement) {
while (this->bme680_.power_mode != BME680_SLEEP_MODE) { while (this->bme680_.power_mode != BME680_SLEEP_MODE) {
this->bme680_status_ = bme680_get_sensor_mode(&this->bme680_); this->bme680_status_ = bme680_get_sensor_mode(&this->bme680_);
if (this->bme680_status_ != BME680_OK) { if (this->bme680_status_ != BME680_OK) {
@@ -262,7 +239,7 @@ void BME680BSECComponent::read_() {
} }
} }
if (!this->bme680_settings_.process_data) { if (!bme680_settings.process_data) {
ESP_LOGV(TAG, "Data processing not required"); ESP_LOGV(TAG, "Data processing not required");
return; return;
} }
@@ -282,35 +259,35 @@ void BME680BSECComponent::read_() {
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance
uint8_t num_inputs = 0; uint8_t num_inputs = 0;
if (this->bme680_settings_.process_data & BSEC_PROCESS_TEMPERATURE) { if (bme680_settings.process_data & BSEC_PROCESS_TEMPERATURE) {
inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE; inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
inputs[num_inputs].signal = data.temperature / 100.0f; inputs[num_inputs].signal = data.temperature / 100.0f;
inputs[num_inputs].time_stamp = curr_time_ns; inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++; num_inputs++;
// Temperature offset from the real temperature due to external heat sources // Temperature offset from the real temperature due to external heat sources
inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE; inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
inputs[num_inputs].signal = this->temperature_offset_; inputs[num_inputs].signal = this->temperature_offset_;
inputs[num_inputs].time_stamp = curr_time_ns; inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++; num_inputs++;
} }
if (this->bme680_settings_.process_data & BSEC_PROCESS_HUMIDITY) { if (bme680_settings.process_data & BSEC_PROCESS_HUMIDITY) {
inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY; inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
inputs[num_inputs].signal = data.humidity / 1000.0f; inputs[num_inputs].signal = data.humidity / 1000.0f;
inputs[num_inputs].time_stamp = curr_time_ns; inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++; num_inputs++;
} }
if (this->bme680_settings_.process_data & BSEC_PROCESS_PRESSURE) { if (bme680_settings.process_data & BSEC_PROCESS_PRESSURE) {
inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE; inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE;
inputs[num_inputs].signal = data.pressure; inputs[num_inputs].signal = data.pressure;
inputs[num_inputs].time_stamp = curr_time_ns; inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++; num_inputs++;
} }
if (this->bme680_settings_.process_data & BSEC_PROCESS_GAS) { if (bme680_settings.process_data & BSEC_PROCESS_GAS) {
if (data.status & BME680_GASM_VALID_MSK) { if (data.status & BME680_GASM_VALID_MSK) {
inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR; inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
inputs[num_inputs].signal = data.gas_resistance; inputs[num_inputs].signal = data.gas_resistance;
inputs[num_inputs].time_stamp = curr_time_ns; inputs[num_inputs].time_stamp = trigger_time_ns;
num_inputs++; num_inputs++;
} else { } else {
ESP_LOGD(TAG, "BME680 did not report gas data"); ESP_LOGD(TAG, "BME680 did not report gas data");
@@ -321,22 +298,6 @@ void BME680BSECComponent::read_() {
return; 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]; bsec_output_t outputs[BSEC_NUMBER_OUTPUTS];
uint8_t num_outputs = BSEC_NUMBER_OUTPUTS; uint8_t num_outputs = BSEC_NUMBER_OUTPUTS;
this->bsec_status_ = bsec_do_steps(inputs, num_inputs, outputs, &num_outputs); this->bsec_status_ = bsec_do_steps(inputs, num_inputs, outputs, &num_outputs);
@@ -344,13 +305,6 @@ void BME680BSECComponent::read_() {
ESP_LOGW(TAG, "BSEC failed to process signals (BSEC Error Code %d)", this->bsec_status_); ESP_LOGW(TAG, "BSEC failed to process signals (BSEC Error Code %d)", this->bsec_status_);
return; 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) { if (num_outputs < 1) {
ESP_LOGD(TAG, "No signal outputs provided by BSEC"); ESP_LOGD(TAG, "No signal outputs provided by BSEC");
return; return;
@@ -360,7 +314,7 @@ void BME680BSECComponent::read_() {
} }
void BME680BSECComponent::publish_(const bsec_output_t *outputs, uint8_t num_outputs) { void BME680BSECComponent::publish_(const bsec_output_t *outputs, uint8_t num_outputs) {
ESP_LOGV(TAG, "%s: Queuing sensor state publish actions", this->device_id_.c_str()); ESP_LOGV(TAG, "Queuing sensor state publish actions");
for (uint8_t i = 0; i < num_outputs; i++) { for (uint8_t i = 0; i < num_outputs; i++) {
float signal = outputs[i].signal; float signal = outputs[i].signal;
switch (outputs[i].sensor_id) { switch (outputs[i].sensor_id) {
@@ -422,20 +376,12 @@ void BME680BSECComponent::publish_sensor_(text_sensor::TextSensor *sensor, const
sensor->publish_state(value); sensor->publish_state(value);
} }
// Communication function - read int8_t BME680BSECComponent::read_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len) {
// First parameter is the "dev_id" member of our "bme680_" object, which is passed-back here as-is return BME680BSECComponent::instance->read_bytes(a_register, data, len) ? 0 : -1;
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;
} }
// Communication function - write int8_t BME680BSECComponent::write_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len) {
// First parameter is the "dev_id" member of our "bme680_" object, which is passed-back here as-is return BME680BSECComponent::instance->write_bytes(a_register, data, len) ? 0 : -1;
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) { void BME680BSECComponent::delay_ms(uint32_t period) {
@@ -443,97 +389,41 @@ void BME680BSECComponent::delay_ms(uint32_t period) {
delay(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_() { void BME680BSECComponent::load_state_() {
uint32_t hash = fnv1_hash("bme680_bsec_state_" + this->device_id_); uint32_t hash = fnv1_hash("bme680_bsec_state_" + to_string(this->address_));
this->bsec_state_ = global_preferences->make_preference<uint8_t[BSEC_MAX_STATE_BLOB_SIZE]>(hash, true); this->bsec_state_ = global_preferences->make_preference<uint8_t[BSEC_MAX_STATE_BLOB_SIZE]>(hash, true);
if (!this->bsec_state_.load(&this->bsec_state_data_)) { uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
// No saved BSEC library state available if (this->bsec_state_.load(&state)) {
return; 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");
} }
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) { void BME680BSECComponent::save_state_(uint8_t accuracy) {
if (accuracy < 3 || (millis() - this->last_state_save_ms_ < this->state_save_interval_ms_)) { if (accuracy < 3 || (millis() - this->last_state_save_ms_ < this->state_save_interval_ms_)) {
return; return;
} }
if (BME680BSECComponent::instances.size() <= 1) {
// When a single device is in use, no snapshot is taken regularly so one is taken now ESP_LOGV(TAG, "Saving state");
// On multiple devices, a snapshot is taken at every loop, so there is no need to take one here
this->snapshot_state_(); uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
} uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
if (!this->bsec_state_data_valid_) 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; return;
}
ESP_LOGV(TAG, "%s: Saving state", this->device_id_.c_str()); if (!this->bsec_state_.save(&state)) {
if (!this->bsec_state_.save(&this->bsec_state_data_)) {
ESP_LOGW(TAG, "Failed to save state"); ESP_LOGW(TAG, "Failed to save state");
return; return;
} }

View File

@@ -31,7 +31,6 @@ enum SampleRate {
class BME680BSECComponent : public Component, public i2c::I2CDevice { class BME680BSECComponent : public Component, public i2c::I2CDevice {
public: 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_temperature_offset(float offset) { this->temperature_offset_ = offset; }
void set_iaq_mode(IAQMode iaq_mode) { this->iaq_mode_ = iaq_mode; } 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; } void set_state_save_interval(uint32_t interval) { this->state_save_interval_ms_ = interval; }
@@ -51,9 +50,9 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
void set_co2_equivalent_sensor(sensor::Sensor *sensor) { this->co2_equivalent_sensor_ = sensor; } 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; } void set_breath_voc_equivalent_sensor(sensor::Sensor *sensor) { this->breath_voc_equivalent_sensor_ = sensor; }
static std::vector<BME680BSECComponent *> instances; static BME680BSECComponent *instance;
static int8_t read_bytes_wrapper(uint8_t devid, uint8_t a_register, uint8_t *data, uint16_t len); 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 devid, 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 void delay_ms(uint32_t period); static void delay_ms(uint32_t period);
void setup() override; void setup() override;
@@ -62,33 +61,23 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
void loop() override; void loop() override;
protected: protected:
void set_config_(); void set_config_(const uint8_t *config);
float calc_sensor_sample_rate_(SampleRate sample_rate); float calc_sensor_sample_rate_(SampleRate sample_rate);
void update_subscription_(); void update_subscription_();
void run_(); void run_();
void read_(); void read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings);
void publish_(const bsec_output_t *outputs, uint8_t num_outputs); void publish_(const bsec_output_t *outputs, uint8_t num_outputs);
int64_t get_time_ns_(); int64_t get_time_ns_();
void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only = false); void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only = false);
void publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value); void publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value);
void snapshot_state_(); // Fetch the current BSEC library state and save it in the bsec_state_data_ member (volatile void load_state_();
// memory) void save_state_(uint8_t accuracy);
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)); } 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_; struct bme680_dev bme680_;
bsec_library_return_t bsec_status_{BSEC_OK}; bsec_library_return_t bsec_status_{BSEC_OK};
int8_t bme680_status_{BME680_OK}; int8_t bme680_status_{BME680_OK};
@@ -99,14 +88,10 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
std::queue<std::function<void()>> queue_; 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_; ESPPreferenceObject bsec_state_;
uint32_t state_save_interval_ms_{21600000}; // 6 hours - 4 times a day uint32_t state_save_interval_ms_{21600000}; // 6 hours - 4 times a day
uint32_t last_state_save_ms_ = 0; uint32_t last_state_save_ms_ = 0;
bsec_bme_settings_t bme680_settings_;
std::string device_id_;
float temperature_offset_{0}; float temperature_offset_{0};
IAQMode iaq_mode_{IAQ_MODE_STATIC}; IAQMode iaq_mode_{IAQ_MODE_STATIC};

View File

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

View File

@@ -6,6 +6,9 @@ namespace button {
static const char *const TAG = "button"; static const char *const TAG = "button";
Button::Button(const std::string &name) : EntityBase(name) {}
Button::Button() : Button("") {}
void Button::press() { void Button::press() {
ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str()); ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str());
this->press_action(); this->press_action();

View File

@@ -15,19 +15,15 @@ namespace button {
} \ } \
} }
#define SUB_BUTTON(name) \
protected: \
button::Button *name##_button_{nullptr}; \
\
public: \
void set_##name##_button(button::Button *button) { this->name##_button_ = button; }
/** Base class for all buttons. /** Base class for all buttons.
* *
* A button is just a momentary switch that does not have a state, only a trigger. * A button is just a momentary switch that does not have a state, only a trigger.
*/ */
class Button : public EntityBase { class Button : public EntityBase {
public: public:
explicit Button();
explicit Button(const std::string &name);
/** Press this button. This is called by the front-end. /** Press this button. This is called by the front-end.
* *
* For implementing buttons, please override press_action. * For implementing buttons, please override press_action.

View File

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

View File

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

View File

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

View File

@@ -44,7 +44,6 @@ void ClimateCall::perform() {
if (this->target_temperature_high_.has_value()) { if (this->target_temperature_high_.has_value()) {
ESP_LOGD(TAG, " Target Temperature High: %.2f", *this->target_temperature_high_); ESP_LOGD(TAG, " Target Temperature High: %.2f", *this->target_temperature_high_);
} }
this->parent_->control_callback_.call();
this->parent_->control(*this); this->parent_->control(*this);
} }
void ClimateCall::validate_() { void ClimateCall::validate_() {
@@ -318,10 +317,6 @@ void Climate::add_on_state_callback(std::function<void()> &&callback) {
this->state_callback_.add(std::move(callback)); this->state_callback_.add(std::move(callback));
} }
void Climate::add_on_control_callback(std::function<void()> &&callback) {
this->control_callback_.add(std::move(callback));
}
// Random 32bit value; If this changes existing restore preferences are invalidated // Random 32bit value; If this changes existing restore preferences are invalidated
static const uint32_t RESTORE_STATE_VERSION = 0x848EA6ADUL; static const uint32_t RESTORE_STATE_VERSION = 0x848EA6ADUL;
@@ -435,11 +430,9 @@ ClimateTraits Climate::get_traits() {
if (this->visual_max_temperature_override_.has_value()) { if (this->visual_max_temperature_override_.has_value()) {
traits.set_visual_max_temperature(*this->visual_max_temperature_override_); traits.set_visual_max_temperature(*this->visual_max_temperature_override_);
} }
if (this->visual_target_temperature_step_override_.has_value()) { if (this->visual_temperature_step_override_.has_value()) {
traits.set_visual_target_temperature_step(*this->visual_target_temperature_step_override_); traits.set_visual_temperature_step(*this->visual_temperature_step_override_);
traits.set_visual_current_temperature_step(*this->visual_current_temperature_step_override_);
} }
return traits; return traits;
} }
@@ -449,11 +442,15 @@ void Climate::set_visual_min_temperature_override(float visual_min_temperature_o
void Climate::set_visual_max_temperature_override(float visual_max_temperature_override) { void Climate::set_visual_max_temperature_override(float visual_max_temperature_override) {
this->visual_max_temperature_override_ = visual_max_temperature_override; this->visual_max_temperature_override_ = visual_max_temperature_override;
} }
void Climate::set_visual_temperature_step_override(float target, float current) { void Climate::set_visual_temperature_step_override(float visual_temperature_step_override) {
this->visual_target_temperature_step_override_ = target; this->visual_temperature_step_override_ = visual_temperature_step_override;
this->visual_current_temperature_step_override_ = current;
} }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Climate::Climate(const std::string &name) : EntityBase(name) {}
#pragma GCC diagnostic pop
Climate::Climate() : Climate("") {}
ClimateCall Climate::make_call() { return ClimateCall(this); } ClimateCall Climate::make_call() { return ClimateCall(this); }
ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) { ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) {
@@ -544,9 +541,7 @@ void Climate::dump_traits_(const char *tag) {
ESP_LOGCONFIG(tag, " [x] Visual settings:"); ESP_LOGCONFIG(tag, " [x] Visual settings:");
ESP_LOGCONFIG(tag, " - Min: %.1f", traits.get_visual_min_temperature()); ESP_LOGCONFIG(tag, " - Min: %.1f", traits.get_visual_min_temperature());
ESP_LOGCONFIG(tag, " - Max: %.1f", traits.get_visual_max_temperature()); ESP_LOGCONFIG(tag, " - Max: %.1f", traits.get_visual_max_temperature());
ESP_LOGCONFIG(tag, " - Step:"); ESP_LOGCONFIG(tag, " - Step: %.1f", traits.get_visual_temperature_step());
ESP_LOGCONFIG(tag, " Target: %.1f", traits.get_visual_target_temperature_step());
ESP_LOGCONFIG(tag, " Current: %.1f", traits.get_visual_current_temperature_step());
if (traits.get_supports_current_temperature()) { if (traits.get_supports_current_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports current temperature"); ESP_LOGCONFIG(tag, " [x] Supports current temperature");
} }

View File

@@ -166,6 +166,11 @@ struct ClimateDeviceRestoreState {
*/ */
class Climate : public EntityBase { class Climate : public EntityBase {
public: public:
/// Construct a climate device with empty name (will be set later).
Climate();
/// Construct a climate device with a name.
Climate(const std::string &name);
/// The active mode of the climate device. /// The active mode of the climate device.
ClimateMode mode{CLIMATE_MODE_OFF}; ClimateMode mode{CLIMATE_MODE_OFF};
/// The active state of the climate device. /// The active state of the climate device.
@@ -214,14 +219,6 @@ class Climate : public EntityBase {
*/ */
void add_on_state_callback(std::function<void()> &&callback); void add_on_state_callback(std::function<void()> &&callback);
/**
* Add a callback for the climate device configuration; each time the configuration parameters of a climate device
* is updated (using perform() of a ClimateCall), this callback will be called, before any on_state callback.
*
* @param callback The callback to call.
*/
void add_on_control_callback(std::function<void()> &&callback);
/** Make a climate device control call, this is used to control the climate device, see the ClimateCall description /** Make a climate device control call, this is used to control the climate device, see the ClimateCall description
* for more info. * for more info.
* @return A new ClimateCall instance targeting this climate device. * @return A new ClimateCall instance targeting this climate device.
@@ -244,7 +241,7 @@ class Climate : public EntityBase {
void set_visual_min_temperature_override(float visual_min_temperature_override); void set_visual_min_temperature_override(float visual_min_temperature_override);
void set_visual_max_temperature_override(float visual_max_temperature_override); void set_visual_max_temperature_override(float visual_max_temperature_override);
void set_visual_temperature_step_override(float target, float current); void set_visual_temperature_step_override(float visual_temperature_step_override);
protected: protected:
friend ClimateCall; friend ClimateCall;
@@ -288,12 +285,10 @@ class Climate : public EntityBase {
void dump_traits_(const char *tag); void dump_traits_(const char *tag);
CallbackManager<void()> state_callback_{}; CallbackManager<void()> state_callback_{};
CallbackManager<void()> control_callback_{};
ESPPreferenceObject rtc_; ESPPreferenceObject rtc_;
optional<float> visual_min_temperature_override_{}; optional<float> visual_min_temperature_override_{};
optional<float> visual_max_temperature_override_{}; optional<float> visual_max_temperature_override_{};
optional<float> visual_target_temperature_step_override_{}; optional<float> visual_temperature_step_override_{};
optional<float> visual_current_temperature_step_override_{};
}; };
} // namespace climate } // namespace climate

View File

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

View File

@@ -147,20 +147,9 @@ class ClimateTraits {
void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; } void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; }
float get_visual_max_temperature() const { return visual_max_temperature_; } float get_visual_max_temperature() const { return visual_max_temperature_; }
void set_visual_max_temperature(float visual_max_temperature) { visual_max_temperature_ = visual_max_temperature; } void set_visual_max_temperature(float visual_max_temperature) { visual_max_temperature_ = visual_max_temperature; }
float get_visual_target_temperature_step() const { return visual_target_temperature_step_; } float get_visual_temperature_step() const { return visual_temperature_step_; }
float get_visual_current_temperature_step() const { return visual_current_temperature_step_; } int8_t get_temperature_accuracy_decimals() const;
void set_visual_target_temperature_step(float temperature_step) { void set_visual_temperature_step(float temperature_step) { visual_temperature_step_ = temperature_step; }
visual_target_temperature_step_ = temperature_step;
}
void set_visual_current_temperature_step(float temperature_step) {
visual_current_temperature_step_ = temperature_step;
}
void set_visual_temperature_step(float temperature_step) {
visual_target_temperature_step_ = temperature_step;
visual_current_temperature_step_ = temperature_step;
}
int8_t get_target_temperature_accuracy_decimals() const;
int8_t get_current_temperature_accuracy_decimals() const;
protected: protected:
void set_mode_support_(climate::ClimateMode mode, bool supported) { void set_mode_support_(climate::ClimateMode mode, bool supported) {
@@ -197,8 +186,7 @@ class ClimateTraits {
float visual_min_temperature_{10}; float visual_min_temperature_{10};
float visual_max_temperature_{30}; float visual_max_temperature_{30};
float visual_target_temperature_step_{0.1}; float visual_temperature_step_{0.1};
float visual_current_temperature_step_{0.1};
}; };
} // namespace climate } // namespace climate

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -111,6 +111,7 @@ const char *cover_operation_to_str(CoverOperation op);
class Cover : public EntityBase { class Cover : public EntityBase {
public: public:
explicit Cover(); explicit Cover();
explicit Cover(const std::string &name);
/// The current operation of the cover (idle, opening, closing). /// The current operation of the cover (idle, opening, closing).
CoverOperation current_operation{COVER_OPERATION_IDLE}; CoverOperation current_operation{COVER_OPERATION_IDLE};
@@ -169,6 +170,12 @@ class Cover : public EntityBase {
virtual void control(const CoverCall &call) = 0; virtual void control(const CoverCall &call) = 0;
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
virtual std::string device_class();
optional<CoverRestoreState> restore_state_(); optional<CoverRestoreState> restore_state_();
CallbackManager<void()> state_callback_{}; CallbackManager<void()> state_callback_{};

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(): cv.declare_id(CustomSensorConstructor), cv.GenerateID(): cv.declare_id(CustomSensorConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda, cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_SENSORS): cv.ensure_list(sensor.sensor_schema()), cv.Required(CONF_SENSORS): cv.ensure_list(sensor.SENSOR_SCHEMA),
} }
) )

View File

@@ -61,8 +61,8 @@ void DalyBmsComponent::request_data_(uint8_t data_id) {
request_message[9] = 0x00; // | request_message[9] = 0x00; // |
request_message[10] = 0x00; // | request_message[10] = 0x00; // |
request_message[11] = 0x00; // Empty Data request_message[11] = 0x00; // Empty Data
request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] + request_message[12] = (uint8_t)(request_message[0] + request_message[1] + request_message[2] +
request_message[3]); // Checksum (Lower byte of the other bytes sum) request_message[3]); // Checksum (Lower byte of the other bytes sum)
this->write_array(request_message, sizeof(request_message)); this->write_array(request_message, sizeof(request_message));
this->flush(); this->flush();

View File

@@ -83,30 +83,11 @@ def import_config(
raise FileExistsError raise FileExistsError
if project_name == "esphome.web": if project_name == "esphome.web":
if "esp32c3" in import_url:
board = "esp32-c3-devkitm-1"
platform = "ESP32"
elif "esp32s2" in import_url:
board = "esp32-s2-saola-1"
platform = "ESP32"
elif "esp32s3" in import_url:
board = "esp32-s3-devkitc-1"
platform = "ESP32"
elif "esp32" in import_url:
board = "esp32dev"
platform = "ESP32"
elif "esp8266" in import_url:
board = "esp01_1m"
platform = "ESP8266"
elif "pico-w" in import_url:
board = "pico-w"
platform = "RP2040"
kwargs = { kwargs = {
"name": name, "name": name,
"friendly_name": friendly_name, "friendly_name": friendly_name,
"platform": platform, "platform": "ESP32" if "esp32" in import_url else "ESP8266",
"board": board, "board": "esp32dev" if "esp32" in import_url else "esp01_1m",
"ssid": "!secret wifi_ssid", "ssid": "!secret wifi_ssid",
"psk": "!secret wifi_password", "psk": "!secret wifi_password",
} }

View File

@@ -21,7 +21,6 @@ from esphome.components.esp32.const import (
VARIANT_ESP32, VARIANT_ESP32,
VARIANT_ESP32C3, VARIANT_ESP32C3,
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3,
) )
WAKEUP_PINS = { WAKEUP_PINS = {
@@ -70,30 +69,6 @@ WAKEUP_PINS = {
20, 20,
21, 21,
], ],
VARIANT_ESP32S3: [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
],
} }

View File

@@ -284,10 +284,9 @@ CONFIG_SCHEMA = cv.Schema(
}, },
], ],
): [ ): [
number.number_schema(DemoNumber) number.NUMBER_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend(
.extend(cv.COMPONENT_SCHEMA)
.extend(
{ {
cv.GenerateID(): cv.declare_id(DemoNumber),
cv.Required(CONF_TYPE): cv.enum(NUMBER_TYPES, int=True), cv.Required(CONF_TYPE): cv.enum(NUMBER_TYPES, int=True),
cv.Required(CONF_MIN_VALUE): cv.float_, cv.Required(CONF_MIN_VALUE): cv.float_,
cv.Required(CONF_MAX_VALUE): cv.float_, cv.Required(CONF_MAX_VALUE): cv.float_,

View File

@@ -19,7 +19,7 @@ void DFPlayer::play_folder(uint16_t folder, uint16_t file) {
} }
void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) { void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) {
uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t) (argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef}; uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t)(argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef};
uint16_t checksum = 0; uint16_t checksum = 0;
for (uint8_t i = 1; i < 7; i++) for (uint8_t i = 1; i < 7; i++)
checksum += buffer[i]; checksum += buffer[i];

View File

@@ -32,11 +32,9 @@ void Rect::extend(Rect rect) {
this->h = rect.h; this->h = rect.h;
} else { } else {
if (this->x > rect.x) { if (this->x > rect.x) {
this->w = this->w + (this->x - rect.x);
this->x = rect.x; this->x = rect.x;
} }
if (this->y > rect.y) { if (this->y > rect.y) {
this->h = this->h + (this->y - rect.y);
this->y = rect.y; this->y = rect.y;
} }
if (this->x2() < rect.x2()) { if (this->x2() < rect.x2()) {
@@ -51,35 +49,29 @@ void Rect::shrink(Rect rect) {
if (!this->inside(rect)) { if (!this->inside(rect)) {
(*this) = Rect(); (*this) = Rect();
} else { } else {
if (this->x < rect.x) {
this->x = rect.x;
}
if (this->y < rect.y) {
this->y = rect.y;
}
if (this->x2() > rect.x2()) { if (this->x2() > rect.x2()) {
this->w = rect.x2() - this->x; this->w = rect.x2() - this->x;
} }
if (this->x < rect.x) {
this->w = this->w + (this->x - rect.x);
this->x = rect.x;
}
if (this->y2() > rect.y2()) { if (this->y2() > rect.y2()) {
this->h = rect.y2() - this->y; this->h = rect.y2() - this->y;
} }
if (this->y < rect.y) {
this->h = this->h + (this->y - rect.y);
this->y = rect.y;
}
} }
} }
bool Rect::equal(Rect rect) { bool Rect::inside(int16_t x, int16_t y, bool absolute) { // NOLINT
return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h);
}
bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT
if (!this->is_set()) { if (!this->is_set()) {
return true; return true;
} }
if (absolute) { if (absolute) {
return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2())); return ((x >= 0) && (x <= this->w) && (y >= 0) && (y <= this->h));
} else { } else {
return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h)); return ((x >= this->x) && (x <= this->x2()) && (y >= this->y) && (y <= this->y2()));
} }
} }
@@ -88,16 +80,15 @@ bool Rect::inside(Rect rect, bool absolute) {
return true; return true;
} }
if (absolute) { if (absolute) {
return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y));
} else {
return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0));
} else {
return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y));
} }
} }
void Rect::info(const std::string &prefix) { void Rect::info(const std::string &prefix) {
if (this->is_set()) { if (this->is_set()) {
ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(), ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d]", prefix.c_str(), this->x, this->y, this->w, this->h);
this->y2());
} else } else
ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str()); ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str());
} }
@@ -612,10 +603,10 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in
*x_offset = min_x; *x_offset = min_x;
*width = x - min_x; *width = x - min_x;
} }
const std::vector<Glyph> &Font::get_glyphs() const { return this->glyphs_; }
Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) {
glyphs_.reserve(data_nr);
for (int i = 0; i < data_nr; ++i) for (int i = 0; i < data_nr; ++i)
glyphs_.emplace_back(&data[i]); glyphs_.emplace_back(data + i);
} }
bool Image::get_pixel(int x, int y) const { bool Image::get_pixel(int x, int y) const {
@@ -664,7 +655,7 @@ bool Animation::get_pixel(int x, int y) const {
return false; return false;
const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
const uint32_t frame_index = this->height_ * width_8 * this->current_frame_; const uint32_t frame_index = this->height_ * width_8 * this->current_frame_;
if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
return false; return false;
const uint32_t pos = x + y * width_8 + frame_index; const uint32_t pos = x + y * width_8 + frame_index;
return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
@@ -673,7 +664,7 @@ Color Animation::get_color_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK; return Color::BLACK;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
return Color::BLACK; return Color::BLACK;
const uint32_t pos = (x + y * this->width_ + frame_index) * 3; const uint32_t pos = (x + y * this->width_ + frame_index) * 3;
const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) | const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) |
@@ -685,7 +676,7 @@ Color Animation::get_rgb565_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK; return Color::BLACK;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
return Color::BLACK; return Color::BLACK;
const uint32_t pos = (x + y * this->width_ + frame_index) * 2; const uint32_t pos = (x + y * this->width_ + frame_index) * 2;
uint16_t rgb565 = uint16_t rgb565 =
@@ -699,7 +690,7 @@ Color Animation::get_grayscale_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK; return Color::BLACK;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
return Color::BLACK; return Color::BLACK;
const uint32_t pos = (x + y * this->width_ + frame_index); const uint32_t pos = (x + y * this->width_ + frame_index);
const uint8_t gray = progmem_read_byte(this->data_start_ + pos); const uint8_t gray = progmem_read_byte(this->data_start_ + pos);

View File

@@ -120,9 +120,8 @@ class Rect {
void extend(Rect rect); void extend(Rect rect);
void shrink(Rect rect); void shrink(Rect rect);
bool inside(Rect rect, bool absolute = true); bool inside(Rect rect, bool absolute = false);
bool inside(int16_t test_x, int16_t test_y, bool absolute = true); bool inside(int16_t x, int16_t y, bool absolute = false);
bool equal(Rect rect);
void info(const std::string &prefix = "rect info:"); void info(const std::string &prefix = "rect info:");
}; };
@@ -527,10 +526,10 @@ class Font {
inline int get_baseline() { return this->baseline_; } inline int get_baseline() { return this->baseline_; }
inline int get_height() { return this->height_; } inline int get_height() { return this->height_; }
const std::vector<Glyph, ExternalRAMAllocator<Glyph>> &get_glyphs() const { return glyphs_; } const std::vector<Glyph> &get_glyphs() const;
protected: protected:
std::vector<Glyph, ExternalRAMAllocator<Glyph>> glyphs_; std::vector<Glyph> glyphs_;
int baseline_; int baseline_;
int height_; int height_;
}; };

View File

@@ -168,7 +168,7 @@ void ENS210Component::update() {
return; return;
} }
// Pack bytes for humidity // Pack bytes for humidity
h_val_data = (uint32_t) ((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]); h_val_data = (uint32_t)((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]);
// Extract humidity data and update the status // Extract humidity data and update the status
extract_measurement_(h_val_data, &humidity_data, &humidity_status); extract_measurement_(h_val_data, &humidity_data, &humidity_status);
@@ -183,7 +183,7 @@ void ENS210Component::update() {
return; return;
} }
// Pack bytes for temperature // Pack bytes for temperature
t_val_data = (uint32_t) ((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]); t_val_data = (uint32_t)((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]);
// Extract temperature data and update the status // Extract temperature data and update the status
extract_measurement_(t_val_data, &temperature_data, &temperature_status); extract_measurement_(t_val_data, &temperature_data, &temperature_status);

View File

@@ -4,43 +4,29 @@ from pathlib import Path
import logging import logging
import os import os
from esphome.helpers import copy_file_if_changed, write_file_if_changed, mkdir_p from esphome.helpers import copy_file_if_changed, write_file_if_changed
from esphome.const import ( from esphome.const import (
CONF_BOARD, CONF_BOARD,
CONF_COMPONENTS,
CONF_FRAMEWORK, CONF_FRAMEWORK,
CONF_NAME,
CONF_SOURCE, CONF_SOURCE,
CONF_TYPE, CONF_TYPE,
CONF_VARIANT, CONF_VARIANT,
CONF_VERSION, CONF_VERSION,
CONF_ADVANCED, CONF_ADVANCED,
CONF_REFRESH,
CONF_PATH,
CONF_URL,
CONF_REF,
CONF_IGNORE_EFUSE_MAC_CRC, CONF_IGNORE_EFUSE_MAC_CRC,
KEY_CORE, KEY_CORE,
KEY_FRAMEWORK_VERSION, KEY_FRAMEWORK_VERSION,
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
TYPE_GIT,
TYPE_LOCAL,
__version__, __version__,
) )
from esphome.core import CORE, HexInt, TimePeriod from esphome.core import CORE, HexInt
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome import git
from .const import ( # noqa from .const import ( # noqa
KEY_BOARD, KEY_BOARD,
KEY_COMPONENTS,
KEY_ESP32, KEY_ESP32,
KEY_PATH,
KEY_REF,
KEY_REFRESH,
KEY_REPO,
KEY_SDKCONFIG_OPTIONS, KEY_SDKCONFIG_OPTIONS,
KEY_VARIANT, KEY_VARIANT,
VARIANT_ESP32C3, VARIANT_ESP32C3,
@@ -65,7 +51,6 @@ def set_core_data(config):
if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF:
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "esp-idf" CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "esp-idf"
CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS] = {} CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS] = {}
CORE.data[KEY_ESP32][KEY_COMPONENTS] = {}
elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO: elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO:
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino" CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino"
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse(
@@ -119,21 +104,6 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType):
CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS][name] = value CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS][name] = value
def add_idf_component(
name: str, repo: str, ref: str = None, path: str = None, refresh: TimePeriod = None
):
"""Add an esp-idf component to the project."""
if not CORE.using_esp_idf:
raise ValueError("Not an esp-idf project")
if name not in CORE.data[KEY_ESP32][KEY_COMPONENTS]:
CORE.data[KEY_ESP32][KEY_COMPONENTS][name] = {
KEY_REPO: repo,
KEY_REF: ref,
KEY_PATH: path,
KEY_REFRESH: refresh,
}
def _format_framework_arduino_version(ver: cv.Version) -> str: def _format_framework_arduino_version(ver: cv.Version) -> str:
# format the given arduino (https://github.com/espressif/arduino-esp32/releases) version to # format the given arduino (https://github.com/espressif/arduino-esp32/releases) version to
# a PIO platformio/framework-arduinoespressif32 value # a PIO platformio/framework-arduinoespressif32 value
@@ -168,18 +138,18 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 2, 0)
# The default/recommended esp-idf framework version # The default/recommended esp-idf framework version
# - https://github.com/espressif/esp-idf/releases # - https://github.com/espressif/esp-idf/releases
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 4) RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 2)
# The platformio/espressif32 version to use for esp-idf frameworks # The platformio/espressif32 version to use for esp-idf frameworks
# - https://github.com/platformio/platform-espressif32/releases # - https://github.com/platformio/platform-espressif32/releases
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
ESP_IDF_PLATFORM_VERSION = cv.Version(5, 3, 0) ESP_IDF_PLATFORM_VERSION = cv.Version(5, 2, 0)
def _arduino_check_versions(value): def _arduino_check_versions(value):
value = value.copy() value = value.copy()
lookups = { lookups = {
"dev": (cv.Version(2, 1, 0), "https://github.com/espressif/arduino-esp32.git"), "dev": (cv.Version(2, 0, 5), "https://github.com/espressif/arduino-esp32.git"),
"latest": (cv.Version(2, 0, 7), None), "latest": (cv.Version(2, 0, 5), None),
"recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None),
} }
@@ -213,8 +183,8 @@ def _arduino_check_versions(value):
def _esp_idf_check_versions(value): def _esp_idf_check_versions(value):
value = value.copy() value = value.copy()
lookups = { lookups = {
"dev": (cv.Version(5, 1, 0), "https://github.com/espressif/esp-idf.git"), "dev": (cv.Version(5, 0, 0), "https://github.com/espressif/esp-idf.git"),
"latest": (cv.Version(5, 0, 1), None), "latest": (cv.Version(4, 4, 2), None),
"recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None), "recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None),
} }
@@ -300,18 +270,6 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean, cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean,
} }
), ),
cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list(
cv.Schema(
{
cv.Required(CONF_NAME): cv.string_strict,
cv.Required(CONF_SOURCE): cv.SOURCE_SCHEMA,
cv.Optional(CONF_PATH): cv.string,
cv.Optional(CONF_REFRESH, default="1d"): cv.All(
cv.string, cv.source_refresh
),
}
)
),
} }
), ),
_esp_idf_check_versions, _esp_idf_check_versions,
@@ -414,19 +372,6 @@ async def to_code(config):
), ),
) )
for component in conf[CONF_COMPONENTS]:
source = component[CONF_SOURCE]
if source[CONF_TYPE] == TYPE_GIT:
add_idf_component(
name=component[CONF_NAME],
repo=source[CONF_URL],
ref=source.get(CONF_REF),
path=component.get(CONF_PATH),
refresh=component[CONF_REFRESH],
)
elif source[CONF_TYPE] == TYPE_LOCAL:
_LOGGER.warning("Local components are not implemented yet.")
elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO: elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO:
cg.add_platformio_option("framework", "arduino") cg.add_platformio_option("framework", "arduino")
cg.add_build_flag("-DUSE_ARDUINO") cg.add_build_flag("-DUSE_ARDUINO")
@@ -523,32 +468,6 @@ def copy_files():
__version__, __version__,
) )
import shutil
shutil.rmtree(CORE.relative_build_path("components"), ignore_errors=True)
if CORE.data[KEY_ESP32][KEY_COMPONENTS]:
components: dict = CORE.data[KEY_ESP32][KEY_COMPONENTS]
for name, component in components.items():
repo_dir, _ = git.clone_or_update(
url=component[KEY_REPO],
ref=component[KEY_REF],
refresh=component[KEY_REFRESH],
domain="idf_components",
)
mkdir_p(CORE.relative_build_path("components"))
component_dir = repo_dir
if component[KEY_PATH] is not None:
component_dir = component_dir / component[KEY_PATH]
shutil.copytree(
component_dir,
CORE.relative_build_path(f"components/{name}"),
dirs_exist_ok=True,
ignore=shutil.ignore_patterns(".git", ".github"),
)
dir = os.path.dirname(__file__) dir = os.path.dirname(__file__)
post_build_file = os.path.join(dir, "post_build.py.script") post_build_file = os.path.join(dir, "post_build.py.script")
copy_file_if_changed( copy_file_if_changed(

View File

@@ -4,11 +4,6 @@ KEY_ESP32 = "esp32"
KEY_BOARD = "board" KEY_BOARD = "board"
KEY_VARIANT = "variant" KEY_VARIANT = "variant"
KEY_SDKCONFIG_OPTIONS = "sdkconfig_options" KEY_SDKCONFIG_OPTIONS = "sdkconfig_options"
KEY_COMPONENTS = "components"
KEY_REPO = "repo"
KEY_REF = "ref"
KEY_REFRESH = "refresh"
KEY_PATH = "path"
VARIANT_ESP32 = "ESP32" VARIANT_ESP32 = "ESP32"
VARIANT_ESP32S2 = "ESP32S2" VARIANT_ESP32S2 = "ESP32S2"

View File

@@ -23,7 +23,7 @@ void loop();
namespace esphome { namespace esphome {
void IRAM_ATTR HOT yield() { vPortYield(); } void IRAM_ATTR HOT yield() { vPortYield(); }
uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); } uint32_t IRAM_ATTR HOT millis() { return (uint32_t)(esp_timer_get_time() / 1000ULL); }
void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); } uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); }
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); } void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }

View File

@@ -2,7 +2,6 @@
#include "gpio.h" #include "gpio.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace esp32 { namespace esp32 {
@@ -75,7 +74,7 @@ void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpi
std::string ESP32InternalGPIOPin::dump_summary() const { std::string ESP32InternalGPIOPin::dump_summary() const {
char buffer[32]; char buffer[32];
snprintf(buffer, sizeof(buffer), "GPIO%" PRIu32, static_cast<uint32_t>(pin_)); snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast<uint32_t>(pin_));
return buffer; return buffer;
} }

View File

@@ -1,25 +1,15 @@
# Source https://github.com/letscontrolit/ESPEasy/pull/3845#issuecomment-1005864664 # Source https://github.com/letscontrolit/ESPEasy/pull/3845#issuecomment-1005864664
# pylint: disable=E0602
Import("env") # noqa
import os import os
import shutil
if os.environ.get("ESPHOME_USE_SUBPROCESS") is None: if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
try: import esptool
import esptool
except ImportError:
env.Execute("$PYTHONEXE -m pip install esptool")
else: else:
import subprocess import subprocess
from SCons.Script import ARGUMENTS from SCons.Script import ARGUMENTS
# Copy over the default sdkconfig. # pylint: disable=E0602
from os import path Import("env") # noqa
if path.exists("./sdkconfig.defaults"):
os.makedirs(".temp", exist_ok=True)
shutil.copy("./sdkconfig.defaults", "./.temp/sdkconfig-esp32-idf")
def esp32_create_combined_bin(source, target, env): def esp32_create_combined_bin(source, target, env):
verbose = bool(int(ARGUMENTS.get("PIOVERBOSE", "0"))) verbose = bool(int(ARGUMENTS.get("PIOVERBOSE", "0")))

View File

@@ -5,7 +5,6 @@
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <nvs_flash.h> #include <nvs_flash.h>
#include <cstring> #include <cstring>
#include <cinttypes>
#include <vector> #include <vector>
#include <string> #include <string>
@@ -102,7 +101,7 @@ class ESP32Preferences : public ESPPreferences {
pref->nvs_handle = nvs_handle; pref->nvs_handle = nvs_handle;
uint32_t keyval = type; uint32_t keyval = type;
pref->key = str_sprintf("%" PRIu32, keyval); pref->key = str_sprintf("%u", keyval);
return ESPPreferenceObject(pref); return ESPPreferenceObject(pref);
} }

View File

@@ -12,6 +12,8 @@ CONF_BLE_ID = "ble_id"
NO_BLUTOOTH_VARIANTS = [const.VARIANT_ESP32S2] NO_BLUTOOTH_VARIANTS = [const.VARIANT_ESP32S2]
NO_BLUTOOTH_VARIANTS = [const.VARIANT_ESP32S2]
esp32_ble_ns = cg.esphome_ns.namespace("esp32_ble") esp32_ble_ns = cg.esphome_ns.namespace("esp32_ble")
ESP32BLE = esp32_ble_ns.class_("ESP32BLE", cg.Component) ESP32BLE = esp32_ble_ns.class_("ESP32BLE", cg.Component)

View File

@@ -6,7 +6,6 @@
#include <esp_bt.h> #include <esp_bt.h>
#include <esp_bt_main.h> #include <esp_bt_main.h>
#include <esp_bt_device.h>
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/FreeRTOSConfig.h> #include <freertos/FreeRTOSConfig.h>
@@ -212,16 +211,7 @@ void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if
float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; } float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; }
void ESP32BLE::dump_config() { void ESP32BLE::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE:"); }
const uint8_t *mac_address = esp_bt_dev_get_address();
if (mac_address) {
ESP_LOGCONFIG(TAG, "ESP32 BLE:");
ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2],
mac_address[3], mac_address[4], mac_address[5]);
} else {
ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
}
}
ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

View File

@@ -62,7 +62,6 @@ bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
void BLEClientBase::connect() { void BLEClientBase::connect() {
ESP_LOGI(TAG, "[%d] [%s] 0x%02x Attempting BLE connection", this->connection_index_, this->address_str_.c_str(), ESP_LOGI(TAG, "[%d] [%s] 0x%02x Attempting BLE connection", this->connection_index_, this->address_str_.c_str(),
this->remote_addr_type_); this->remote_addr_type_);
this->paired_ = false;
auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true); auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true);
if (ret) { if (ret) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_open error, status=%d", this->connection_index_, this->address_str_.c_str(), ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_open error, status=%d", this->connection_index_, this->address_str_.c_str(),
@@ -73,8 +72,6 @@ void BLEClientBase::connect() {
} }
} }
esp_err_t BLEClientBase::pair() { return esp_ble_set_encryption(this->remote_bda_, ESP_BLE_SEC_ENCRYPT); }
void BLEClientBase::disconnect() { void BLEClientBase::disconnect() {
if (this->state_ == espbt::ClientState::IDLE || this->state_ == espbt::ClientState::DISCONNECTING) if (this->state_ == espbt::ClientState::IDLE || this->state_ == espbt::ClientState::DISCONNECTING)
return; return;
@@ -250,15 +247,11 @@ void BLEClientBase::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_
switch (event) { switch (event) {
// This event is sent by the server when it requests security // This event is sent by the server when it requests security
case ESP_GAP_BLE_SEC_REQ_EVT: case ESP_GAP_BLE_SEC_REQ_EVT:
if (memcmp(param->ble_security.auth_cmpl.bd_addr, this->remote_bda_, 6) != 0)
break;
ESP_LOGV(TAG, "[%d] [%s] ESP_GAP_BLE_SEC_REQ_EVT %x", this->connection_index_, this->address_str_.c_str(), event); ESP_LOGV(TAG, "[%d] [%s] ESP_GAP_BLE_SEC_REQ_EVT %x", this->connection_index_, this->address_str_.c_str(), event);
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break; break;
// This event is sent once authentication has completed // This event is sent once authentication has completed
case ESP_GAP_BLE_AUTH_CMPL_EVT: case ESP_GAP_BLE_AUTH_CMPL_EVT:
if (memcmp(param->ble_security.auth_cmpl.bd_addr, this->remote_bda_, 6) != 0)
break;
esp_bd_addr_t bd_addr; esp_bd_addr_t bd_addr;
memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t)); memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
ESP_LOGI(TAG, "[%d] [%s] auth complete. remote BD_ADDR: %s", this->connection_index_, this->address_str_.c_str(), ESP_LOGI(TAG, "[%d] [%s] auth complete. remote BD_ADDR: %s", this->connection_index_, this->address_str_.c_str(),
@@ -267,7 +260,6 @@ void BLEClientBase::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_
ESP_LOGE(TAG, "[%d] [%s] auth fail reason = 0x%x", this->connection_index_, this->address_str_.c_str(), ESP_LOGE(TAG, "[%d] [%s] auth fail reason = 0x%x", this->connection_index_, this->address_str_.c_str(),
param->ble_security.auth_cmpl.fail_reason); param->ble_security.auth_cmpl.fail_reason);
} else { } else {
this->paired_ = true;
ESP_LOGV(TAG, "[%d] [%s] auth success. address type = %d auth mode = %d", this->connection_index_, ESP_LOGV(TAG, "[%d] [%s] auth success. address type = %d auth mode = %d", this->connection_index_,
this->address_str_.c_str(), param->ble_security.auth_cmpl.addr_type, this->address_str_.c_str(), param->ble_security.auth_cmpl.addr_type,
param->ble_security.auth_cmpl.auth_mode); param->ble_security.auth_cmpl.auth_mode);
@@ -316,18 +308,18 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
case 0xD: // int12. case 0xD: // int12.
case 0xE: // int16. case 0xE: // int16.
if (length > 2) { if (length > 2) {
return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]); return (float) ((int16_t)(value[1] << 8) + (int16_t) value[2]);
} }
// fall through // fall through
case 0xF: // int24. case 0xF: // int24.
if (length > 3) { if (length > 3) {
return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3])); return (float) ((int32_t)(value[1] << 16) + (int32_t)(value[2] << 8) + (int32_t)(value[3]));
} }
// fall through // fall through
case 0x10: // int32. case 0x10: // int32.
if (length > 4) { if (length > 4) {
return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) + return (float) ((int32_t)(value[1] << 24) + (int32_t)(value[2] << 16) + (int32_t)(value[3] << 8) +
(int32_t) (value[4])); (int32_t)(value[4]));
} }
} }
ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_,

View File

@@ -33,7 +33,6 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
esp_ble_gattc_cb_param_t *param) override; 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; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
void connect() override; void connect() override;
esp_err_t pair();
void disconnect(); void disconnect();
void release_services(); void release_services();
@@ -45,11 +44,10 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
memset(this->remote_bda_, 0, sizeof(this->remote_bda_)); memset(this->remote_bda_, 0, sizeof(this->remote_bda_));
this->address_str_ = ""; this->address_str_ = "";
} else { } else {
this->address_str_ = this->address_str_ = str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t)(this->address_ >> 40) & 0xff,
str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t) (this->address_ >> 40) & 0xff, (uint8_t)(this->address_ >> 32) & 0xff, (uint8_t)(this->address_ >> 24) & 0xff,
(uint8_t) (this->address_ >> 32) & 0xff, (uint8_t) (this->address_ >> 24) & 0xff, (uint8_t)(this->address_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff,
(uint8_t) (this->address_ >> 16) & 0xff, (uint8_t) (this->address_ >> 8) & 0xff, (uint8_t)(this->address_ >> 0) & 0xff);
(uint8_t) (this->address_ >> 0) & 0xff);
} }
} }
std::string address_str() const { return this->address_str_; } std::string address_str() const { return this->address_str_; }
@@ -73,7 +71,6 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
void set_remote_addr_type(esp_ble_addr_type_t address_type) { this->remote_addr_type_ = address_type; } void set_remote_addr_type(esp_ble_addr_type_t address_type) { this->remote_addr_type_ = address_type; }
uint16_t get_conn_id() const { return this->conn_id_; } uint16_t get_conn_id() const { return this->conn_id_; }
uint64_t get_address() const { return this->address_; } uint64_t get_address() const { return this->address_; }
bool is_paired() const { return this->paired_; }
uint8_t get_connection_index() const { return this->connection_index_; } uint8_t get_connection_index() const { return this->connection_index_; }
@@ -89,7 +86,6 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
uint8_t connection_index_; uint8_t connection_index_;
int16_t service_count_{0}; int16_t service_count_{0};
uint16_t mtu_{23}; uint16_t mtu_{23};
bool paired_{false};
espbt::ConnectionType connection_type_{espbt::ConnectionType::V1}; espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};
std::vector<BLEService *> services_; std::vector<BLEService *> services_;

View File

@@ -148,44 +148,44 @@ bool BLECharacteristic::is_failed() {
void BLECharacteristic::set_broadcast_property(bool value) { void BLECharacteristic::set_broadcast_property(bool value) {
if (value) { if (value) {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST);
} else { } else {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST);
} }
} }
void BLECharacteristic::set_indicate_property(bool value) { void BLECharacteristic::set_indicate_property(bool value) {
if (value) { if (value) {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE);
} else { } else {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE);
} }
} }
void BLECharacteristic::set_notify_property(bool value) { void BLECharacteristic::set_notify_property(bool value) {
if (value) { if (value) {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY);
} else { } else {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY);
} }
} }
void BLECharacteristic::set_read_property(bool value) { void BLECharacteristic::set_read_property(bool value) {
if (value) { if (value) {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ);
} else { } else {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ);
} }
} }
void BLECharacteristic::set_write_property(bool value) { void BLECharacteristic::set_write_property(bool value) {
if (value) { if (value) {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE);
} else { } else {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE);
} }
} }
void BLECharacteristic::set_write_no_response_property(bool value) { void BLECharacteristic::set_write_no_response_property(bool value) {
if (value) { if (value) {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
} else { } else {
this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
} }
} }

View File

@@ -53,14 +53,6 @@ void ESP32BLETracker::setup() {
ESP_LOGE(TAG, "BLE Tracker was marked failed by ESP32BLE"); ESP_LOGE(TAG, "BLE Tracker was marked failed by ESP32BLE");
return; return;
} }
ExternalRAMAllocator<esp_ble_gap_cb_param_t::ble_scan_result_evt_param> allocator(
ExternalRAMAllocator<esp_ble_gap_cb_param_t::ble_scan_result_evt_param>::ALLOW_FAILURE);
this->scan_result_buffer_ = allocator.allocate(ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE);
if (this->scan_result_buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate buffer for BLE Tracker!");
this->mark_failed();
}
global_esp32_ble_tracker = this; global_esp32_ble_tracker = this;
this->scan_result_lock_ = xSemaphoreCreateMutex(); this->scan_result_lock_ = xSemaphoreCreateMutex();
@@ -115,7 +107,7 @@ void ESP32BLETracker::loop() {
xSemaphoreTake(this->scan_result_lock_, 5L / portTICK_PERIOD_MS)) { xSemaphoreTake(this->scan_result_lock_, 5L / portTICK_PERIOD_MS)) {
uint32_t index = this->scan_result_index_; uint32_t index = this->scan_result_index_;
if (index) { if (index) {
if (index >= ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE) { if (index >= 16) {
ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up.");
} }
for (size_t i = 0; i < index; i++) { for (size_t i = 0; i < index; i++) {
@@ -330,7 +322,7 @@ void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_
void ESP32BLETracker::gap_scan_result_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param) { void ESP32BLETracker::gap_scan_result_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param) {
if (param.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) { if (param.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
if (xSemaphoreTake(this->scan_result_lock_, 0L)) { if (xSemaphoreTake(this->scan_result_lock_, 0L)) {
if (this->scan_result_index_ < ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE) { if (this->scan_result_index_ < 16) {
this->scan_result_buffer_[this->scan_result_index_++] = param; this->scan_result_buffer_[this->scan_result_index_++] = param;
} }
xSemaphoreGive(this->scan_result_lock_); xSemaphoreGive(this->scan_result_lock_);

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