mirror of
https://github.com/esphome/esphome.git
synced 2025-08-10 20:29:24 +00:00
Compare commits
272 Commits
2022.9.4
...
2022.12.0b
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4be7cd12a1 | ||
![]() |
dee4d0ccb7 | ||
![]() |
c6885c1bf4 | ||
![]() |
8b8efb57af | ||
![]() |
499e120aa4 | ||
![]() |
6f198a4736 | ||
![]() |
f500f448b1 | ||
![]() |
6ad9baa870 | ||
![]() |
f843925301 | ||
![]() |
4a3b628946 | ||
![]() |
4ffdc38cf5 | ||
![]() |
f83f1bff19 | ||
![]() |
9370ff3dfa | ||
![]() |
2053b02c61 | ||
![]() |
f34e797a0d | ||
![]() |
30a2fc1273 | ||
![]() |
48da5ef1c4 | ||
![]() |
dbbbba3cf8 | ||
![]() |
16e523ca68 | ||
![]() |
3b2bbd306f | ||
![]() |
54caed36f7 | ||
![]() |
dfcccda69e | ||
![]() |
de352c1609 | ||
![]() |
c30068fc97 | ||
![]() |
f28f712827 | ||
![]() |
b63ade298f | ||
![]() |
f117d4f50a | ||
![]() |
6e4267b797 | ||
![]() |
2dd032475b | ||
![]() |
db0ed055dd | ||
![]() |
106c1bfac2 | ||
![]() |
eb2a0f45db | ||
![]() |
2b4fdd6c39 | ||
![]() |
3669320398 | ||
![]() |
d706f40ce1 | ||
![]() |
027284c29c | ||
![]() |
c55e01ff3f | ||
![]() |
a59ce7bfa2 | ||
![]() |
a6196267c9 | ||
![]() |
eb664b99ba | ||
![]() |
8414bb9a7a | ||
![]() |
ccef7c322f | ||
![]() |
120327866f | ||
![]() |
bc5c2d4eb4 | ||
![]() |
d5ff8f6117 | ||
![]() |
ad0d6f6337 | ||
![]() |
873de13b3d | ||
![]() |
56de8e5cc4 | ||
![]() |
73c82862cf | ||
![]() |
75573a3ed1 | ||
![]() |
1166d93805 | ||
![]() |
ac112a32c9 | ||
![]() |
cee45c1221 | ||
![]() |
fb56b5388e | ||
![]() |
ed42cefeee | ||
![]() |
9052947a71 | ||
![]() |
53e0af18fb | ||
![]() |
c5f59fad62 | ||
![]() |
b089a4ea80 | ||
![]() |
555bba7698 | ||
![]() |
294901fbe9 | ||
![]() |
ec576bf9f9 | ||
![]() |
9273e3775b | ||
![]() |
ce5cedb466 | ||
![]() |
b184b01600 | ||
![]() |
81b4078871 | ||
![]() |
d067c8f80b | ||
![]() |
8975b4b3f6 | ||
![]() |
20da03f8c6 | ||
![]() |
ef26677b67 | ||
![]() |
91925b1826 | ||
![]() |
1f33ad037d | ||
![]() |
fef60e335e | ||
![]() |
195c78846f | ||
![]() |
0f9c956c04 | ||
![]() |
7258a82875 | ||
![]() |
c1f696c32a | ||
![]() |
f2b63d9c67 | ||
![]() |
7896a7783b | ||
![]() |
621771e1ee | ||
![]() |
2b032e8606 | ||
![]() |
5e1b724697 | ||
![]() |
e6db61c2f0 | ||
![]() |
c2e198311c | ||
![]() |
d874626662 | ||
![]() |
eead72333e | ||
![]() |
719c212009 | ||
![]() |
65030e1c37 | ||
![]() |
3f88b63920 | ||
![]() |
70f1c71a9f | ||
![]() |
816df5ad47 | ||
![]() |
f7b1602adf | ||
![]() |
7e88eea532 | ||
![]() |
d1cdfd3b72 | ||
![]() |
d6a03d48f5 | ||
![]() |
d453b42b1a | ||
![]() |
7c19b961e2 | ||
![]() |
147b113b62 | ||
![]() |
d924702825 | ||
![]() |
e8784ba383 | ||
![]() |
e3a454d1a6 | ||
![]() |
392dc8b0db | ||
![]() |
2f62426f09 | ||
![]() |
58fda40389 | ||
![]() |
6a73699a38 | ||
![]() |
3bd6456fbe | ||
![]() |
608be4e050 | ||
![]() |
10f590324b | ||
![]() |
cb2d9e4bec | ||
![]() |
9e3ee28744 | ||
![]() |
472dcebf2c | ||
![]() |
39f0f748bf | ||
![]() |
9efe59a984 | ||
![]() |
fcb02af782 | ||
![]() |
9f30f53c6b | ||
![]() |
2f18ae00c5 | ||
![]() |
27a339fa12 | ||
![]() |
3aeef1afd4 | ||
![]() |
a45ee8f4ac | ||
![]() |
31b62d7dca | ||
![]() |
22f81475db | ||
![]() |
cc7cf73d59 | ||
![]() |
9682e60a25 | ||
![]() |
2c2e68123a | ||
![]() |
fcec7d45cb | ||
![]() |
7c8f502e7e | ||
![]() |
dc17c47634 | ||
![]() |
3d927c2f44 | ||
![]() |
0ae61410d2 | ||
![]() |
2455589f61 | ||
![]() |
c6afae0da5 | ||
![]() |
3155f02be6 | ||
![]() |
4fa0e860ad | ||
![]() |
8c122aa372 | ||
![]() |
5a0bf9fee9 | ||
![]() |
dc794918ed | ||
![]() |
02b15dbc4a | ||
![]() |
ed316b1ce3 | ||
![]() |
d7858f16c1 | ||
![]() |
291deb12ad | ||
![]() |
3e110681c9 | ||
![]() |
65fbfa2097 | ||
![]() |
16ebf9da4c | ||
![]() |
2c76381fcd | ||
![]() |
90683223dd | ||
![]() |
de79171815 | ||
![]() |
1554c5700e | ||
![]() |
5cf257b251 | ||
![]() |
04883e14f6 | ||
![]() |
0a649c184f | ||
![]() |
0e66c899ce | ||
![]() |
e7d236f939 | ||
![]() |
fae4d03473 | ||
![]() |
fd8b9fb028 | ||
![]() |
97bd3e7320 | ||
![]() |
dfca2f88d3 | ||
![]() |
8cad93de37 | ||
![]() |
bdf1813b3a | ||
![]() |
45b6c93f5f | ||
![]() |
e5b8dd7f2d | ||
![]() |
a1c8b8092b | ||
![]() |
109ca2406d | ||
![]() |
3a689112fd | ||
![]() |
40e0cd0f03 | ||
![]() |
bf4d3df906 | ||
![]() |
0e30c49e3f | ||
![]() |
e61a01f7bb | ||
![]() |
f8640cf2cd | ||
![]() |
4bcfeb6e33 | ||
![]() |
a5d4ca0f6d | ||
![]() |
85faecb2fd | ||
![]() |
991fc54994 | ||
![]() |
2de891dc32 | ||
![]() |
9865cb7f55 | ||
![]() |
f97252b93a | ||
![]() |
6124531479 | ||
![]() |
b8549d323c | ||
![]() |
01adece673 | ||
![]() |
0220934e4c | ||
![]() |
ca09693efa | ||
![]() |
e96d7483b3 | ||
![]() |
f2c4f018de | ||
![]() |
237c7dd169 | ||
![]() |
b781b8d77d | ||
![]() |
60b7d1c8a1 | ||
![]() |
8161222b33 | ||
![]() |
1000c4466f | ||
![]() |
60717b074e | ||
![]() |
c3fba97b4c | ||
![]() |
d93f35701f | ||
![]() |
702b60ce66 | ||
![]() |
f8ce597918 | ||
![]() |
22e0a944c8 | ||
![]() |
3a134ef009 | ||
![]() |
96e8cb66b6 | ||
![]() |
615288c151 | ||
![]() |
6153bcc6ad | ||
![]() |
e87edcc77a | ||
![]() |
a21c3e8e2d | ||
![]() |
d7576f67e8 | ||
![]() |
138de643a2 | ||
![]() |
f30e54d177 | ||
![]() |
41b5cb06d3 | ||
![]() |
4ac72d7d08 | ||
![]() |
06ac4980ba | ||
![]() |
ccbfa20bb9 | ||
![]() |
58cd754e07 | ||
![]() |
d1263e583b | ||
![]() |
67c911c37f | ||
![]() |
288e3c3e3e | ||
![]() |
a84378c6c2 | ||
![]() |
b6073408f4 | ||
![]() |
b2d91ac5de | ||
![]() |
8bf34e09f4 | ||
![]() |
be914f2c15 | ||
![]() |
8bb670521d | ||
![]() |
225b3c1494 | ||
![]() |
4bf94e0757 | ||
![]() |
3b21d1d81e | ||
![]() |
5ec1588110 | ||
![]() |
71387be72e | ||
![]() |
98171c9f49 | ||
![]() |
a6c999dea0 | ||
![]() |
bf15b1d302 | ||
![]() |
f422fabab4 | ||
![]() |
01b130ec59 | ||
![]() |
48a1797e72 | ||
![]() |
b34d24735a | ||
![]() |
fe38b36c26 | ||
![]() |
03fca8d91e | ||
![]() |
9f9980e338 | ||
![]() |
19900b004b | ||
![]() |
a8ff0a8913 | ||
![]() |
45861456f1 | ||
![]() |
44b335e7e3 | ||
![]() |
de23bbace2 | ||
![]() |
edff9ae322 | ||
![]() |
3c2766448d | ||
![]() |
786c8b6cfe | ||
![]() |
fd57b21aff | ||
![]() |
6087183a0c | ||
![]() |
01b7c4200e | ||
![]() |
7171286c3c | ||
![]() |
d220d41182 | ||
![]() |
c3a8972550 | ||
![]() |
263b603188 | ||
![]() |
584b722e7e | ||
![]() |
05edfd0e82 | ||
![]() |
16249c02a5 | ||
![]() |
e8ff36d1f3 | ||
![]() |
ed443c6153 | ||
![]() |
f4a84765cd | ||
![]() |
106de3530d | ||
![]() |
8095db6715 | ||
![]() |
ce2e161b08 | ||
![]() |
6ef93452f5 | ||
![]() |
68ea59f3ae | ||
![]() |
9a69769a7e | ||
![]() |
3572c62315 | ||
![]() |
1444cddda9 | ||
![]() |
b2db524366 | ||
![]() |
ab8674a5c7 | ||
![]() |
d1c85fc3fa | ||
![]() |
55ad45e3ee | ||
![]() |
f6e5a8cb2a | ||
![]() |
7a91ca9809 | ||
![]() |
917bbc669c | ||
![]() |
0ac4c055de | ||
![]() |
78b55d86e9 | ||
![]() |
aaf50fc2e6 | ||
![]() |
6a8f4e92df | ||
![]() |
88943103a2 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ESPHome Dev",
|
||||
"image": "esphome/esphome-lint:dev",
|
||||
"image": "ghcr.io/esphome/esphome-lint:dev",
|
||||
"postCreateCommand": [
|
||||
"script/devcontainer-post-create"
|
||||
],
|
||||
|
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
||||
# What does this implement/fix?
|
||||
|
||||
Quick description and explanation of changes
|
||||
<!-- Quick description and explanation of changes -->
|
||||
|
||||
## Types of changes
|
||||
|
||||
@@ -18,6 +18,7 @@ Quick description and explanation of changes
|
||||
- [ ] ESP32
|
||||
- [ ] ESP32 IDF
|
||||
- [ ] ESP8266
|
||||
- [ ] RP2040
|
||||
|
||||
## Example entry for `config.yaml`:
|
||||
<!--
|
||||
|
1
.github/workflows/ci-docker.yml
vendored
1
.github/workflows/ci-docker.yml
vendored
@@ -28,6 +28,7 @@ jobs:
|
||||
name: Build docker containers
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [amd64, armv7, aarch64]
|
||||
build_type: ["ha-addon", "docker", "lint"]
|
||||
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -48,6 +48,10 @@ jobs:
|
||||
file: tests/test5.yaml
|
||||
name: Test tests/test5.yaml
|
||||
pio_cache_key: test5
|
||||
- id: test
|
||||
file: tests/test6.yaml
|
||||
name: Test tests/test6.yaml
|
||||
pio_cache_key: test6
|
||||
- id: pytest
|
||||
name: Run pytest
|
||||
- id: clang-format
|
||||
@@ -85,7 +89,7 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
id: python
|
||||
with:
|
||||
python-version: "3.8"
|
||||
python-version: "3.9"
|
||||
|
||||
- name: Cache virtualenv
|
||||
uses: actions/cache@v3
|
||||
@@ -173,7 +177,7 @@ jobs:
|
||||
|
||||
- name: Run yamllint
|
||||
if: matrix.id == 'yamllint'
|
||||
uses: frenck/action-yamllint@v1.3.0
|
||||
uses: frenck/action-yamllint@v1.3.1
|
||||
|
||||
- name: Suggested changes
|
||||
run: script/ci-suggest-changes
|
||||
|
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
- uses: dessant/lock-threads@v4
|
||||
with:
|
||||
pr-inactive-days: "1"
|
||||
pr-lock-reason: ""
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
today="$(date --utc '+%Y%m%d')"
|
||||
TAG="${TAG}${today}"
|
||||
fi
|
||||
echo "::set-output name=tag::${TAG}"
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
# yamllint enable rule:line-length
|
||||
|
||||
deploy-pypi:
|
||||
|
4
.github/workflows/stale.yml
vendored
4
.github/workflows/stale.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
- uses: actions/stale@v6
|
||||
with:
|
||||
days-before-pr-stale: 90
|
||||
days-before-pr-close: 7
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
- uses: actions/stale@v6
|
||||
with:
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
|
@@ -1,8 +0,0 @@
|
||||
---
|
||||
ports:
|
||||
- port: 6052
|
||||
onOpen: open-preview
|
||||
tasks:
|
||||
# yamllint disable-line rule:line-length
|
||||
- before: pyenv local $(pyenv version | grep '^3\.' | cut -d ' ' -f 1) && script/setup
|
||||
command: python -m esphome dashboard config
|
@@ -3,15 +3,15 @@
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/ambv/black
|
||||
rev: 22.6.0
|
||||
rev: 22.10.0
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
- --safe
|
||||
- --quiet
|
||||
files: ^((esphome|script|tests)/.+)?[^/]+\.py$
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 4.0.1
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
@@ -27,7 +27,7 @@ repos:
|
||||
- --branch=release
|
||||
- --branch=beta
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.37.3
|
||||
rev: v3.3.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py38-plus]
|
||||
args: [--py39-plus]
|
||||
|
12
CODEOWNERS
12
CODEOWNERS
@@ -13,6 +13,7 @@ esphome/core/* @esphome/core
|
||||
# Integrations
|
||||
esphome/components/ac_dimmer/* @glmnet
|
||||
esphome/components/adc/* @esphome/core
|
||||
esphome/components/adc128s102/* @DeerMaximum
|
||||
esphome/components/addressable_light/* @justfalter
|
||||
esphome/components/airthings_ble/* @jeromelaban
|
||||
esphome/components/airthings_wave_mini/* @ncareau
|
||||
@@ -57,12 +58,14 @@ esphome/components/cse7761/* @berfenger
|
||||
esphome/components/ct_clamp/* @jesserockz
|
||||
esphome/components/current_based/* @djwmarcx
|
||||
esphome/components/dac7678/* @NickB1
|
||||
esphome/components/daikin_brc/* @hagak
|
||||
esphome/components/daly_bms/* @s1lvi0
|
||||
esphome/components/dashboard_import/* @esphome/core
|
||||
esphome/components/debug/* @OttoWinter
|
||||
esphome/components/delonghi/* @grob6000
|
||||
esphome/components/dfplayer/* @glmnet
|
||||
esphome/components/dht/* @OttoWinter
|
||||
esphome/components/display_menu_base/* @numo68
|
||||
esphome/components/dps310/* @kbx81
|
||||
esphome/components/ds1307/* @badbadc0ffee
|
||||
esphome/components/dsmr/* @glmnet @zuidwijk
|
||||
@@ -76,8 +79,10 @@ esphome/components/esp32_camera_web_server/* @ayufan
|
||||
esphome/components/esp32_can/* @Sympatron
|
||||
esphome/components/esp32_improv/* @jesserockz
|
||||
esphome/components/esp8266/* @esphome/core
|
||||
esphome/components/ethernet_info/* @gtjadsonsantos
|
||||
esphome/components/exposure_notifications/* @OttoWinter
|
||||
esphome/components/ezo/* @ssieb
|
||||
esphome/components/ezo_pmp/* @carlos-sarmiento
|
||||
esphome/components/factory_reset/* @anatoly-savchenkov
|
||||
esphome/components/fastled_base/* @OttoWinter
|
||||
esphome/components/feedback/* @ianchi
|
||||
@@ -106,6 +111,7 @@ esphome/components/integration/* @OttoWinter
|
||||
esphome/components/interval/* @esphome/core
|
||||
esphome/components/json/* @OttoWinter
|
||||
esphome/components/kalman_combinator/* @Cat-Ion
|
||||
esphome/components/lcd_menu/* @numo68
|
||||
esphome/components/ledc/* @OttoWinter
|
||||
esphome/components/light/* @esphome/core
|
||||
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
||||
@@ -180,6 +186,8 @@ esphome/components/rc522_spi/* @glmnet
|
||||
esphome/components/restart/* @esphome/core
|
||||
esphome/components/rf_bridge/* @jesserockz
|
||||
esphome/components/rgbct/* @jesserockz
|
||||
esphome/components/rp2040/* @jesserockz
|
||||
esphome/components/rp2040_pwm/* @jesserockz
|
||||
esphome/components/rtttl/* @glmnet
|
||||
esphome/components/safe_mode/* @jsuanet @paulmonigatti
|
||||
esphome/components/scd4x/* @martgras @sjtrny
|
||||
@@ -200,6 +208,7 @@ esphome/components/sim800l/* @glmnet
|
||||
esphome/components/sm2135/* @BoukeHaarsma23
|
||||
esphome/components/sml/* @alengwenus
|
||||
esphome/components/smt100/* @piechade
|
||||
esphome/components/sn74hc165/* @jesserockz
|
||||
esphome/components/socket/* @esphome/core
|
||||
esphome/components/sonoff_d1/* @anatoly-savchenkov
|
||||
esphome/components/spi/* @esphome/core
|
||||
@@ -254,8 +263,9 @@ esphome/components/wake_on_lan/* @willwill2will54
|
||||
esphome/components/web_server_base/* @OttoWinter
|
||||
esphome/components/whirlpool/* @glmnet
|
||||
esphome/components/whynter/* @aeonsablaze
|
||||
esphome/components/wl_134/* @hobbypunk90
|
||||
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
|
||||
esphome/components/xiaomi_mhoc303/* @drug123
|
||||
esphome/components/xiaomi_mhoc401/* @vevsvevs
|
||||
esphome/components/xiaomi_rtcgq02lm/* @jesserockz
|
||||
esphome/components/xpt2046/* @numo68
|
||||
esphome/components/xpt2046/* @nielsnl68 @numo68
|
||||
|
@@ -6,17 +6,11 @@
|
||||
ARG BASEIMGTYPE=docker
|
||||
|
||||
# https://github.com/hassio-addons/addon-debian-base/releases
|
||||
FROM ghcr.io/hassio-addons/debian-base/amd64:5.3.0 AS base-hassio-amd64
|
||||
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.3.0 AS base-hassio-arm64
|
||||
FROM ghcr.io/hassio-addons/debian-base/armv7:5.3.0 AS base-hassio-armv7
|
||||
FROM ghcr.io/hassio-addons/debian-base:6.1.3 AS base-hassio
|
||||
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
|
||||
FROM debian:bullseye-20220328-slim AS base-docker-amd64
|
||||
FROM debian:bullseye-20220328-slim AS base-docker-arm64
|
||||
FROM debian:bullseye-20220328-slim AS base-docker-armv7
|
||||
FROM debian:bullseye-20221024-slim AS base-docker
|
||||
|
||||
# Use TARGETARCH/TARGETVARIANT defined by docker
|
||||
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
|
||||
FROM base-${BASEIMGTYPE}-${TARGETARCH}${TARGETVARIANT} AS base
|
||||
FROM base-${BASEIMGTYPE} AS base
|
||||
|
||||
RUN \
|
||||
apt-get update \
|
||||
@@ -29,8 +23,8 @@ RUN \
|
||||
python3-cryptography=3.3.2-1 \
|
||||
iputils-ping=3:20210202-1 \
|
||||
git=1:2.30.2-1 \
|
||||
curl=7.74.0-1.3+deb11u1 \
|
||||
openssh-client=1:8.4p1-5 \
|
||||
curl=7.74.0-1.3+deb11u3 \
|
||||
openssh-client=1:8.4p1-5+deb11u1 \
|
||||
&& rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
@@ -46,7 +40,7 @@ RUN \
|
||||
# Ubuntu python3-pip is missing wheel
|
||||
pip3 install --no-cache-dir \
|
||||
wheel==0.37.1 \
|
||||
platformio==6.0.2 \
|
||||
platformio==6.1.5 \
|
||||
# Change some platformio settings
|
||||
&& platformio settings set enable_telemetry No \
|
||||
&& platformio settings set check_platformio_interval 1000000 \
|
||||
@@ -94,7 +88,7 @@ RUN \
|
||||
apt-get update \
|
||||
# Use pinned versions so that we get updates with build caching
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
nginx-light=1.18.0-6.1+deb11u2 \
|
||||
nginx-light=1.18.0-6.1+deb11u3 \
|
||||
&& rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
|
0
docker/ha-addon-rootfs/etc/cont-init.d/30-dirs.sh
Normal file → Executable file
0
docker/ha-addon-rootfs/etc/cont-init.d/30-dirs.sh
Normal file → Executable file
@@ -3,7 +3,13 @@
|
||||
# Community Hass.io Add-ons: ESPHome
|
||||
# Take down the S6 supervision tree when ESPHome fails
|
||||
# ==============================================================================
|
||||
if -n { s6-test $# -ne 0 }
|
||||
if -n { s6-test ${1} -eq 256 }
|
||||
|
||||
s6-svscanctl -t /var/run/s6/services
|
||||
declare APP_EXIT_CODE=${1}
|
||||
|
||||
if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
|
||||
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
|
||||
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "Service restart after closing"
|
||||
|
@@ -22,6 +22,14 @@ if bashio::config.has_value 'relative_url'; then
|
||||
export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'default_compile_process_limit'; then
|
||||
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=$(bashio::config 'default_compile_process_limit')
|
||||
else
|
||||
if grep -q 'Raspberry Pi 3' /proc/cpuinfo; then
|
||||
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1;
|
||||
fi
|
||||
fi
|
||||
|
||||
pio_cache_base=/data/cache/platformio
|
||||
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
|
||||
# setting `core_dir` would therefore prevent pio from accessing
|
||||
|
@@ -3,7 +3,13 @@
|
||||
# Community Hass.io Add-ons: ESPHome
|
||||
# Take down the S6 supervision tree when NGINX fails
|
||||
# ==============================================================================
|
||||
if -n { s6-test $# -ne 0 }
|
||||
if -n { s6-test ${1} -eq 256 }
|
||||
|
||||
s6-svscanctl -t /var/run/s6/services
|
||||
declare APP_EXIT_CODE=${1}
|
||||
|
||||
if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
|
||||
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
|
||||
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
|
||||
exec /run/s6/basedir/bin/halt
|
||||
fi
|
||||
|
||||
bashio::log.info "Service restart after closing"
|
||||
|
@@ -4,6 +4,7 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from esphome import const, writer, yaml_util
|
||||
@@ -22,6 +23,9 @@ from esphome.const import (
|
||||
CONF_ESPHOME,
|
||||
CONF_PLATFORMIO_OPTIONS,
|
||||
CONF_SUBSTITUTIONS,
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
PLATFORM_RP2040,
|
||||
SECRETS_FILES,
|
||||
)
|
||||
from esphome.core import CORE, EsphomeError, coroutine
|
||||
@@ -101,11 +105,11 @@ def run_miniterm(config, port):
|
||||
|
||||
if CONF_LOGGER not in config:
|
||||
_LOGGER.info("Logger is not enabled. Not starting UART logs.")
|
||||
return
|
||||
return 1
|
||||
baud_rate = config["logger"][CONF_BAUD_RATE]
|
||||
if baud_rate == 0:
|
||||
_LOGGER.info("UART logging is disabled (baud_rate=0). Not starting UART logs.")
|
||||
return
|
||||
return 1
|
||||
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
|
||||
|
||||
backtrace_state = False
|
||||
@@ -119,25 +123,34 @@ def run_miniterm(config, port):
|
||||
ser.dtr = False
|
||||
ser.rts = False
|
||||
|
||||
with ser:
|
||||
while True:
|
||||
try:
|
||||
raw = ser.readline()
|
||||
except serial.SerialException:
|
||||
_LOGGER.error("Serial port closed!")
|
||||
return
|
||||
line = (
|
||||
raw.replace(b"\r", b"")
|
||||
.replace(b"\n", b"")
|
||||
.decode("utf8", "backslashreplace")
|
||||
)
|
||||
time = datetime.now().time().strftime("[%H:%M:%S]")
|
||||
message = time + line
|
||||
safe_print(message)
|
||||
tries = 0
|
||||
while tries < 5:
|
||||
try:
|
||||
with ser:
|
||||
while True:
|
||||
try:
|
||||
raw = ser.readline()
|
||||
except serial.SerialException:
|
||||
_LOGGER.error("Serial port closed!")
|
||||
return 0
|
||||
line = (
|
||||
raw.replace(b"\r", b"")
|
||||
.replace(b"\n", b"")
|
||||
.decode("utf8", "backslashreplace")
|
||||
)
|
||||
time_str = datetime.now().time().strftime("[%H:%M:%S]")
|
||||
message = time_str + line
|
||||
safe_print(message)
|
||||
|
||||
backtrace_state = platformio_api.process_stacktrace(
|
||||
config, line, backtrace_state=backtrace_state
|
||||
)
|
||||
backtrace_state = platformio_api.process_stacktrace(
|
||||
config, line, backtrace_state=backtrace_state
|
||||
)
|
||||
except serial.SerialException:
|
||||
tries += 1
|
||||
time.sleep(1)
|
||||
if tries >= 5:
|
||||
_LOGGER.error("Could not connect to serial port %s", port)
|
||||
return 1
|
||||
|
||||
|
||||
def wrap_to_code(name, comp):
|
||||
@@ -241,8 +254,7 @@ def upload_using_esptool(config, port):
|
||||
if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
|
||||
import esptool
|
||||
|
||||
# pylint: disable=protected-access
|
||||
return run_external_command(esptool._main, *cmd)
|
||||
return run_external_command(esptool.main, *cmd) # pylint: disable=no-member
|
||||
|
||||
return run_external_process(*cmd)
|
||||
|
||||
@@ -258,9 +270,21 @@ def upload_using_esptool(config, port):
|
||||
|
||||
|
||||
def upload_program(config, args, host):
|
||||
# if upload is to a serial port use platformio, otherwise assume ota
|
||||
if get_port_type(host) == "SERIAL":
|
||||
return upload_using_esptool(config, host)
|
||||
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
|
||||
return upload_using_esptool(config, host)
|
||||
|
||||
if CORE.target_platform in (PLATFORM_RP2040):
|
||||
from esphome import platformio_api
|
||||
|
||||
upload_args = ["-t", "upload"]
|
||||
if args.device is not None:
|
||||
upload_args += ["--upload-port", args.device]
|
||||
return platformio_api.run_platformio_cli_run(
|
||||
config, CORE.verbose, *upload_args
|
||||
)
|
||||
|
||||
return 1 # Unknown target platform
|
||||
|
||||
from esphome import espota2
|
||||
|
||||
@@ -273,6 +297,8 @@ def upload_program(config, args, host):
|
||||
ota_conf = config[CONF_OTA]
|
||||
remote_port = ota_conf[CONF_PORT]
|
||||
password = ota_conf.get(CONF_PASSWORD, "")
|
||||
if getattr(args, "file", None) is not None:
|
||||
return espota2.run_ota(host, remote_port, password, args.file)
|
||||
return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
|
||||
|
||||
|
||||
@@ -280,8 +306,7 @@ def show_logs(config, args, port):
|
||||
if "logger" not in config:
|
||||
raise EsphomeError("Logger is not configured!")
|
||||
if get_port_type(port) == "SERIAL":
|
||||
run_miniterm(config, port)
|
||||
return 0
|
||||
return run_miniterm(config, port)
|
||||
if get_port_type(port) == "NETWORK" and "api" in config:
|
||||
from esphome.components.api.client import run_logs
|
||||
|
||||
@@ -663,6 +688,10 @@ def parse_args(argv):
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--file",
|
||||
help="Manually specify the binary file to upload.",
|
||||
)
|
||||
|
||||
parser_logs = subparsers.add_parser(
|
||||
"logs",
|
||||
|
@@ -22,6 +22,7 @@ from esphome.cpp_generator import ( # noqa
|
||||
static_const_array,
|
||||
statement,
|
||||
variable,
|
||||
with_local_variable,
|
||||
new_variable,
|
||||
Pvariable,
|
||||
new_Pvariable,
|
||||
|
@@ -11,6 +11,10 @@ ADC_MODE(ADC_VCC)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_RP2040
|
||||
#include <hardware/adc.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
@@ -32,9 +36,13 @@ static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 b
|
||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
||||
#endif
|
||||
|
||||
void ADCSensor::setup() {
|
||||
#ifdef USE_RP2040
|
||||
extern "C"
|
||||
#endif
|
||||
void
|
||||
ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||
#ifndef USE_ADC_SENSOR_VCC
|
||||
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
|
||||
pin_->setup();
|
||||
#endif
|
||||
|
||||
@@ -63,6 +71,16 @@ void ADCSensor::setup() {
|
||||
}
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
adc_init();
|
||||
initialized = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str());
|
||||
}
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
@@ -98,6 +116,13 @@ void ADCSensor::dump_config() {
|
||||
}
|
||||
}
|
||||
#endif // USE_ESP32
|
||||
#ifdef USE_RP2040
|
||||
if (this->is_temperature_) {
|
||||
ESP_LOGCONFIG(TAG, " Pin: Temperature");
|
||||
} else {
|
||||
LOG_PIN(" Pin: ", pin_);
|
||||
}
|
||||
#endif
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
@@ -175,6 +200,29 @@ float ADCSensor::sample() {
|
||||
}
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
float ADCSensor::sample() {
|
||||
if (this->is_temperature_) {
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
delay(1);
|
||||
adc_select_input(4);
|
||||
} else {
|
||||
uint8_t pin = this->pin_->get_pin();
|
||||
adc_gpio_init(pin);
|
||||
adc_select_input(pin - 26);
|
||||
}
|
||||
|
||||
int raw = adc_read();
|
||||
if (this->is_temperature_) {
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
}
|
||||
if (output_raw_) {
|
||||
return raw;
|
||||
}
|
||||
return raw * 3.3f / 4096.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
||||
#endif
|
||||
|
@@ -38,10 +38,18 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
std::string unique_id() override;
|
||||
#endif
|
||||
|
||||
#ifdef USE_RP2040
|
||||
void set_is_temperature() { is_temperature_ = true; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
InternalGPIOPin *pin_;
|
||||
bool output_raw_{false};
|
||||
|
||||
#ifdef USE_RP2040
|
||||
bool is_temperature_{false};
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32
|
||||
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
||||
adc1_channel_t channel_{};
|
||||
|
@@ -94,6 +94,9 @@ def validate_adc_pin(value):
|
||||
if str(value).upper() == "VCC":
|
||||
return cv.only_on_esp8266("VCC")
|
||||
|
||||
if str(value).upper() == "TEMPERATURE":
|
||||
return cv.only_on_rp2040("TEMPERATURE")
|
||||
|
||||
if CORE.is_esp32:
|
||||
value = pins.internal_gpio_input_pin_number(value)
|
||||
variant = get_esp32_variant()
|
||||
@@ -117,6 +120,12 @@ def validate_adc_pin(value):
|
||||
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
||||
)(value)
|
||||
|
||||
if CORE.is_rp2040:
|
||||
value = pins.internal_gpio_input_pin_number(value)
|
||||
if value not in (26, 27, 28, 29):
|
||||
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
|
||||
return pins.internal_gpio_input_pin_schema(value)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@@ -160,6 +169,8 @@ async def to_code(config):
|
||||
|
||||
if config[CONF_PIN] == "VCC":
|
||||
cg.add_define("USE_ADC_SENSOR_VCC")
|
||||
elif config[CONF_PIN] == "TEMPERATURE":
|
||||
cg.add(var.set_is_temperature())
|
||||
else:
|
||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||
cg.add(var.set_pin(pin))
|
||||
|
23
esphome/components/adc128s102/__init__.py
Normal file
23
esphome/components/adc128s102/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import spi
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
DEPENDENCIES = ["spi"]
|
||||
MULTI_CONF = True
|
||||
CODEOWNERS = ["@DeerMaximum"]
|
||||
|
||||
adc128s102_ns = cg.esphome_ns.namespace("adc128s102")
|
||||
ADC128S102 = adc128s102_ns.class_("ADC128S102", cg.Component, spi.SPIDevice)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ADC128S102),
|
||||
}
|
||||
).extend(spi.spi_device_schema(cs_pin_required=True))
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await spi.register_spi_device(var, config)
|
35
esphome/components/adc128s102/adc128s102.cpp
Normal file
35
esphome/components/adc128s102/adc128s102.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "adc128s102.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
|
||||
static const char *const TAG = "adc128s102";
|
||||
|
||||
float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
void ADC128S102::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up adc128s102");
|
||||
this->spi_setup();
|
||||
}
|
||||
|
||||
void ADC128S102::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ADC128S102:");
|
||||
LOG_PIN(" CS Pin:", this->cs_);
|
||||
}
|
||||
|
||||
uint16_t ADC128S102::read_data(uint8_t channel) {
|
||||
uint8_t control = channel << 3;
|
||||
|
||||
this->enable();
|
||||
uint8_t adc_primary_byte = this->transfer_byte(control);
|
||||
uint8_t adc_secondary_byte = this->transfer_byte(0x00);
|
||||
this->disable();
|
||||
|
||||
uint16_t digital_value = adc_primary_byte << 8 | adc_secondary_byte;
|
||||
|
||||
return digital_value;
|
||||
}
|
||||
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
23
esphome/components/adc128s102/adc128s102.h
Normal file
23
esphome/components/adc128s102/adc128s102.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
|
||||
class ADC128S102 : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||
spi::DATA_RATE_10MHZ> {
|
||||
public:
|
||||
ADC128S102() = default;
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
uint16_t read_data(uint8_t channel);
|
||||
};
|
||||
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
35
esphome/components/adc128s102/sensor/__init__.py
Normal file
35
esphome/components/adc128s102/sensor/__init__.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.const import CONF_ID, CONF_CHANNEL
|
||||
|
||||
from .. import adc128s102_ns, ADC128S102
|
||||
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
DEPENDENCIES = ["adc128s102"]
|
||||
|
||||
ADC128S102Sensor = adc128s102_ns.class_(
|
||||
"ADC128S102Sensor",
|
||||
sensor.Sensor,
|
||||
cg.PollingComponent,
|
||||
voltage_sampler.VoltageSampler,
|
||||
)
|
||||
CONF_ADC128S102_ID = "adc128s102_id"
|
||||
|
||||
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ADC128S102Sensor),
|
||||
cv.GenerateID(CONF_ADC128S102_ID): cv.use_id(ADC128S102),
|
||||
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
|
||||
}
|
||||
).extend(cv.polling_component_schema("60s"))
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
config[CONF_CHANNEL],
|
||||
)
|
||||
await cg.register_parented(var, config[CONF_ADC128S102_ID])
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
24
esphome/components/adc128s102/sensor/adc128s102_sensor.cpp
Normal file
24
esphome/components/adc128s102/sensor/adc128s102_sensor.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "adc128s102_sensor.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
|
||||
static const char *const TAG = "adc128s102.sensor";
|
||||
|
||||
ADC128S102Sensor::ADC128S102Sensor(uint8_t channel) : channel_(channel) {}
|
||||
|
||||
float ADC128S102Sensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
void ADC128S102Sensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC128S102 Sensor", this);
|
||||
ESP_LOGCONFIG(TAG, " Pin: %u", this->channel_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADC128S102Sensor::sample() { return this->parent_->read_data(this->channel_); }
|
||||
void ADC128S102Sensor::update() { this->publish_state(this->sample()); }
|
||||
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
29
esphome/components/adc128s102/sensor/adc128s102_sensor.h
Normal file
29
esphome/components/adc128s102/sensor/adc128s102_sensor.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
#include "../adc128s102.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
|
||||
class ADC128S102Sensor : public PollingComponent,
|
||||
public Parented<ADC128S102>,
|
||||
public sensor::Sensor,
|
||||
public voltage_sampler::VoltageSampler {
|
||||
public:
|
||||
ADC128S102Sensor(uint8_t channel);
|
||||
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
float sample() override;
|
||||
|
||||
protected:
|
||||
uint8_t channel_;
|
||||
};
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
@@ -5,6 +5,8 @@
|
||||
#include "esphome/components/display/display_buffer.h"
|
||||
#include "esphome/components/light/addressable_light.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace addressable_light {
|
||||
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953 {
|
||||
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1115 {
|
||||
|
||||
|
@@ -122,8 +122,9 @@ void AHT10Component::update() {
|
||||
this->temperature_sensor_->publish_state(temperature);
|
||||
}
|
||||
if (this->humidity_sensor_ != nullptr) {
|
||||
if (std::isnan(humidity))
|
||||
if (std::isnan(humidity)) {
|
||||
ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
|
||||
}
|
||||
this->humidity_sensor_->publish_state(humidity);
|
||||
}
|
||||
this->status_clear_warning();
|
||||
|
@@ -104,8 +104,9 @@ void Am43::update() {
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||
}
|
||||
}
|
||||
this->current_sensor_++;
|
||||
}
|
||||
|
@@ -56,8 +56,9 @@ void Am43Component::control(const CoverCall &call) {
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
|
||||
}
|
||||
}
|
||||
if (call.get_position().has_value()) {
|
||||
auto pos = *call.get_position();
|
||||
@@ -68,8 +69,9 @@ void Am43Component::control(const CoverCall &call) {
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,18 +128,21 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||
this->char_handle_, packet->length, packet->data,
|
||||
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_)
|
||||
if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) {
|
||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
|
||||
}
|
||||
|
||||
if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_)
|
||||
if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) {
|
||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
DEPENDENCIES = ["display"]
|
||||
MULTI_CONF = True
|
||||
|
||||
Animation_ = display.display_ns.class_("Animation")
|
||||
Animation_ = display.display_ns.class_("Animation", espImage.Image_)
|
||||
|
||||
ANIMATION_SCHEMA = cv.Schema(
|
||||
{
|
||||
|
@@ -37,16 +37,18 @@ void Anova::control(const ClimateCall &call) {
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||
}
|
||||
}
|
||||
if (call.get_target_temperature().has_value()) {
|
||||
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +145,9 @@ void Anova::update() {
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status)
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||
}
|
||||
this->current_request_++;
|
||||
}
|
||||
}
|
||||
|
@@ -204,6 +204,8 @@ message DeviceInfoResponse {
|
||||
uint32 webserver_port = 10;
|
||||
|
||||
uint32 bluetooth_proxy_version = 11;
|
||||
|
||||
string manufacturer = 12;
|
||||
}
|
||||
|
||||
message ListEntitiesRequest {
|
||||
@@ -913,6 +915,7 @@ message ListEntitiesNumberResponse {
|
||||
EntityCategory entity_category = 10;
|
||||
string unit_of_measurement = 11;
|
||||
NumberMode mode = 12;
|
||||
string device_class = 13;
|
||||
}
|
||||
message NumberStateResponse {
|
||||
option (id) = 50;
|
||||
@@ -1138,6 +1141,8 @@ message BluetoothLEAdvertisementResponse {
|
||||
repeated string service_uuids = 4;
|
||||
repeated BluetoothServiceData service_data = 5;
|
||||
repeated BluetoothServiceData manufacturer_data = 6;
|
||||
|
||||
uint32 address_type = 7;
|
||||
}
|
||||
|
||||
enum BluetoothDeviceRequestType {
|
||||
@@ -1145,6 +1150,8 @@ enum BluetoothDeviceRequestType {
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
|
||||
}
|
||||
|
||||
message BluetoothDeviceRequest {
|
||||
@@ -1154,6 +1161,8 @@ message BluetoothDeviceRequest {
|
||||
|
||||
uint64 address = 1;
|
||||
BluetoothDeviceRequestType request_type = 2;
|
||||
bool has_address_type = 3;
|
||||
uint32 address_type = 4;
|
||||
}
|
||||
|
||||
message BluetoothDeviceConnectionResponse {
|
||||
@@ -1298,3 +1307,31 @@ message BluetoothConnectionsFreeResponse {
|
||||
uint32 free = 1;
|
||||
uint32 limit = 2;
|
||||
}
|
||||
|
||||
message BluetoothGATTErrorResponse {
|
||||
option (id) = 82;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
int32 error = 3;
|
||||
}
|
||||
|
||||
message BluetoothGATTWriteResponse {
|
||||
option (id) = 83;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
}
|
||||
|
||||
message BluetoothGATTNotifyResponse {
|
||||
option (id) = 84;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
}
|
||||
|
@@ -616,6 +616,7 @@ bool APIConnection::send_number_info(number::Number *number) {
|
||||
msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
|
||||
msg.unit_of_measurement = number->traits.get_unit_of_measurement();
|
||||
msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
|
||||
msg.device_class = number->traits.get_device_class();
|
||||
|
||||
msg.min_value = number->traits.get_min_value();
|
||||
msg.max_value = number->traits.get_max_value();
|
||||
@@ -932,6 +933,11 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
||||
resp.mac_address = get_mac_address_pretty();
|
||||
resp.esphome_version = ESPHOME_VERSION;
|
||||
resp.compilation_time = App.get_compilation_time();
|
||||
#if defined(USE_ESP8266) || defined(USE_ESP32)
|
||||
resp.manufacturer = "Espressif";
|
||||
#elif defined(USE_RP2040)
|
||||
resp.manufacturer = "Raspberry Pi";
|
||||
#endif
|
||||
resp.model = ESPHOME_BOARD;
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
|
||||
@@ -944,7 +950,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
||||
resp.webserver_port = USE_WEBSERVER_PORT;
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 2 : 1;
|
||||
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
|
||||
#endif
|
||||
return resp;
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
|
@@ -6,6 +6,7 @@
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
|
||||
switch (value) {
|
||||
case enums::ENTITY_CATEGORY_NONE:
|
||||
@@ -18,6 +19,8 @@ template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::Entity
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::LegacyCoverState value) {
|
||||
switch (value) {
|
||||
case enums::LEGACY_COVER_STATE_OPEN:
|
||||
@@ -28,6 +31,8 @@ template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::Lega
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverOperation value) {
|
||||
switch (value) {
|
||||
case enums::COVER_OPERATION_IDLE:
|
||||
@@ -40,6 +45,8 @@ template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverO
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::LegacyCoverCommand value) {
|
||||
switch (value) {
|
||||
case enums::LEGACY_COVER_COMMAND_OPEN:
|
||||
@@ -52,6 +59,8 @@ template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::Le
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed value) {
|
||||
switch (value) {
|
||||
case enums::FAN_SPEED_LOW:
|
||||
@@ -64,6 +73,8 @@ template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed val
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirection value) {
|
||||
switch (value) {
|
||||
case enums::FAN_DIRECTION_FORWARD:
|
||||
@@ -74,6 +85,8 @@ template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirec
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode value) {
|
||||
switch (value) {
|
||||
case enums::COLOR_MODE_UNKNOWN:
|
||||
@@ -100,6 +113,8 @@ template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode v
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) {
|
||||
switch (value) {
|
||||
case enums::STATE_CLASS_NONE:
|
||||
@@ -114,6 +129,8 @@ template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::Sens
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::SensorLastResetType value) {
|
||||
switch (value) {
|
||||
case enums::LAST_RESET_NONE:
|
||||
@@ -126,6 +143,8 @@ template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::S
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
|
||||
switch (value) {
|
||||
case enums::LOG_LEVEL_NONE:
|
||||
@@ -148,6 +167,8 @@ template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel val
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) {
|
||||
switch (value) {
|
||||
case enums::SERVICE_ARG_TYPE_BOOL:
|
||||
@@ -170,6 +191,8 @@ template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::Servic
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_MODE_OFF:
|
||||
@@ -190,6 +213,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::ClimateFanMode value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_FAN_ON:
|
||||
@@ -214,6 +239,8 @@ template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::Climat
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::ClimateSwingMode value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_SWING_OFF:
|
||||
@@ -228,6 +255,8 @@ template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::Clim
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::ClimateAction value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_ACTION_OFF:
|
||||
@@ -246,6 +275,8 @@ template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::Climate
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_PRESET_NONE:
|
||||
@@ -268,6 +299,8 @@ template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::Climate
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) {
|
||||
switch (value) {
|
||||
case enums::NUMBER_MODE_AUTO:
|
||||
@@ -280,6 +313,8 @@ template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) {
|
||||
switch (value) {
|
||||
case enums::LOCK_STATE_NONE:
|
||||
@@ -298,6 +333,8 @@ template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState v
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) {
|
||||
switch (value) {
|
||||
case enums::LOCK_UNLOCK:
|
||||
@@ -310,6 +347,8 @@ template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockComma
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::MediaPlayerState value) {
|
||||
switch (value) {
|
||||
case enums::MEDIA_PLAYER_STATE_NONE:
|
||||
@@ -324,6 +363,8 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::Medi
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::MediaPlayerCommand value) {
|
||||
switch (value) {
|
||||
case enums::MEDIA_PLAYER_COMMAND_PLAY:
|
||||
@@ -340,6 +381,8 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
template<>
|
||||
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
|
||||
switch (value) {
|
||||
@@ -351,10 +394,15 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
|
||||
return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
|
||||
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
|
||||
return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR";
|
||||
case enums::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:
|
||||
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 2: {
|
||||
@@ -576,6 +624,10 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
|
||||
this->project_version = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->manufacturer = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -592,6 +644,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(9, this->project_version);
|
||||
buffer.encode_uint32(10, this->webserver_port);
|
||||
buffer.encode_uint32(11, this->bluetooth_proxy_version);
|
||||
buffer.encode_string(12, this->manufacturer);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
@@ -642,6 +695,10 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
sprintf(buffer, "%u", this->bluetooth_proxy_version);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" manufacturer: ");
|
||||
out.append("'").append(this->manufacturer).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -3933,6 +3990,10 @@ bool ListEntitiesNumberResponse::decode_length(uint32_t field_id, ProtoLengthDel
|
||||
this->unit_of_measurement = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 13: {
|
||||
this->device_class = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -3972,6 +4033,7 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_enum<enums::EntityCategory>(10, this->entity_category);
|
||||
buffer.encode_string(11, this->unit_of_measurement);
|
||||
buffer.encode_enum<enums::NumberMode>(12, this->mode);
|
||||
buffer.encode_string(13, this->device_class);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesNumberResponse::dump_to(std::string &out) const {
|
||||
@@ -4028,6 +4090,10 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const {
|
||||
out.append(" mode: ");
|
||||
out.append(proto_enum_to_string<enums::NumberMode>(this->mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -4975,6 +5041,10 @@ bool BluetoothLEAdvertisementResponse::decode_varint(uint32_t field_id, ProtoVar
|
||||
this->rssi = value.as_sint32();
|
||||
return true;
|
||||
}
|
||||
case 7: {
|
||||
this->address_type = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5014,6 +5084,7 @@ void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
for (auto &it : this->manufacturer_data) {
|
||||
buffer.encode_message<BluetoothServiceData>(6, it, true);
|
||||
}
|
||||
buffer.encode_uint32(7, this->address_type);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
|
||||
@@ -5050,6 +5121,11 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
out.append(" address_type: ");
|
||||
sprintf(buffer, "%u", this->address_type);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -5063,6 +5139,14 @@ bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
|
||||
this->request_type = value.as_enum<enums::BluetoothDeviceRequestType>();
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->has_address_type = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 4: {
|
||||
this->address_type = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5070,6 +5154,8 @@ bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
|
||||
void BluetoothDeviceRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint64(1, this->address);
|
||||
buffer.encode_enum<enums::BluetoothDeviceRequestType>(2, this->request_type);
|
||||
buffer.encode_bool(3, this->has_address_type);
|
||||
buffer.encode_uint32(4, this->address_type);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void BluetoothDeviceRequest::dump_to(std::string &out) const {
|
||||
@@ -5083,6 +5169,15 @@ void BluetoothDeviceRequest::dump_to(std::string &out) const {
|
||||
out.append(" request_type: ");
|
||||
out.append(proto_enum_to_string<enums::BluetoothDeviceRequestType>(this->request_type));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_address_type: ");
|
||||
out.append(YESNO(this->has_address_type));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" address_type: ");
|
||||
sprintf(buffer, "%u", this->address_type);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -5746,6 +5841,118 @@ void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const {
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
bool BluetoothGATTErrorResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->address = value.as_uint64();
|
||||
return true;
|
||||
}
|
||||
case 2: {
|
||||
this->handle = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->error = value.as_int32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void BluetoothGATTErrorResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint64(1, this->address);
|
||||
buffer.encode_uint32(2, this->handle);
|
||||
buffer.encode_int32(3, this->error);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void BluetoothGATTErrorResponse::dump_to(std::string &out) const {
|
||||
__attribute__((unused)) char buffer[64];
|
||||
out.append("BluetoothGATTErrorResponse {\n");
|
||||
out.append(" address: ");
|
||||
sprintf(buffer, "%llu", this->address);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" handle: ");
|
||||
sprintf(buffer, "%u", this->handle);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" error: ");
|
||||
sprintf(buffer, "%d", this->error);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
bool BluetoothGATTWriteResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->address = value.as_uint64();
|
||||
return true;
|
||||
}
|
||||
case 2: {
|
||||
this->handle = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void BluetoothGATTWriteResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint64(1, this->address);
|
||||
buffer.encode_uint32(2, this->handle);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void BluetoothGATTWriteResponse::dump_to(std::string &out) const {
|
||||
__attribute__((unused)) char buffer[64];
|
||||
out.append("BluetoothGATTWriteResponse {\n");
|
||||
out.append(" address: ");
|
||||
sprintf(buffer, "%llu", this->address);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" handle: ");
|
||||
sprintf(buffer, "%u", this->handle);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
bool BluetoothGATTNotifyResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->address = value.as_uint64();
|
||||
return true;
|
||||
}
|
||||
case 2: {
|
||||
this->handle = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void BluetoothGATTNotifyResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint64(1, this->address);
|
||||
buffer.encode_uint32(2, this->handle);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void BluetoothGATTNotifyResponse::dump_to(std::string &out) const {
|
||||
__attribute__((unused)) char buffer[64];
|
||||
out.append("BluetoothGATTNotifyResponse {\n");
|
||||
out.append(" address: ");
|
||||
sprintf(buffer, "%llu", this->address);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" handle: ");
|
||||
sprintf(buffer, "%u", this->handle);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -160,6 +160,8 @@ enum BluetoothDeviceRequestType : uint32_t {
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4,
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
|
||||
};
|
||||
|
||||
} // namespace enums
|
||||
@@ -273,6 +275,7 @@ class DeviceInfoResponse : public ProtoMessage {
|
||||
std::string project_version{};
|
||||
uint32_t webserver_port{0};
|
||||
uint32_t bluetooth_proxy_version{0};
|
||||
std::string manufacturer{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
@@ -1003,6 +1006,7 @@ class ListEntitiesNumberResponse : public ProtoMessage {
|
||||
enums::EntityCategory entity_category{};
|
||||
std::string unit_of_measurement{};
|
||||
enums::NumberMode mode{};
|
||||
std::string device_class{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
@@ -1255,6 +1259,7 @@ class BluetoothLEAdvertisementResponse : public ProtoMessage {
|
||||
std::vector<std::string> service_uuids{};
|
||||
std::vector<BluetoothServiceData> service_data{};
|
||||
std::vector<BluetoothServiceData> manufacturer_data{};
|
||||
uint32_t address_type{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
@@ -1268,6 +1273,8 @@ class BluetoothDeviceRequest : public ProtoMessage {
|
||||
public:
|
||||
uint64_t address{0};
|
||||
enums::BluetoothDeviceRequestType request_type{};
|
||||
bool has_address_type{false};
|
||||
uint32_t address_type{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
@@ -1481,6 +1488,43 @@ class BluetoothConnectionsFreeResponse : public ProtoMessage {
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||
};
|
||||
class BluetoothGATTErrorResponse : public ProtoMessage {
|
||||
public:
|
||||
uint64_t address{0};
|
||||
uint32_t handle{0};
|
||||
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 BluetoothGATTWriteResponse : public ProtoMessage {
|
||||
public:
|
||||
uint64_t address{0};
|
||||
uint32_t handle{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 BluetoothGATTNotifyResponse : public ProtoMessage {
|
||||
public:
|
||||
uint64_t address{0};
|
||||
uint32_t handle{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -401,6 +401,30 @@ bool APIServerConnectionBase::send_bluetooth_connections_free_response(const Blu
|
||||
return this->send_message_<BluetoothConnectionsFreeResponse>(msg, 81);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool APIServerConnectionBase::send_bluetooth_gatt_error_response(const BluetoothGATTErrorResponse &msg) {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "send_bluetooth_gatt_error_response: %s", msg.dump().c_str());
|
||||
#endif
|
||||
return this->send_message_<BluetoothGATTErrorResponse>(msg, 82);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool APIServerConnectionBase::send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &msg) {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "send_bluetooth_gatt_write_response: %s", msg.dump().c_str());
|
||||
#endif
|
||||
return this->send_message_<BluetoothGATTWriteResponse>(msg, 83);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool APIServerConnectionBase::send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &msg) {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "send_bluetooth_gatt_notify_response: %s", msg.dump().c_str());
|
||||
#endif
|
||||
return this->send_message_<BluetoothGATTNotifyResponse>(msg, 84);
|
||||
}
|
||||
#endif
|
||||
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
|
||||
switch (msg_type) {
|
||||
case 1: {
|
||||
|
@@ -200,6 +200,15 @@ class APIServerConnectionBase : public ProtoService {
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool send_bluetooth_connections_free_response(const BluetoothConnectionsFreeResponse &msg);
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool send_bluetooth_gatt_error_response(const BluetoothGATTErrorResponse &msg);
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &msg);
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
bool send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &msg);
|
||||
#endif
|
||||
protected:
|
||||
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
|
||||
|
@@ -324,11 +324,21 @@ void APIServer::send_bluetooth_gatt_read_response(const BluetoothGATTReadRespons
|
||||
client->send_bluetooth_gatt_read_response(call);
|
||||
}
|
||||
}
|
||||
void APIServer::send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call) {
|
||||
for (auto &client : this->clients_) {
|
||||
client->send_bluetooth_gatt_write_response(call);
|
||||
}
|
||||
}
|
||||
void APIServer::send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call) {
|
||||
for (auto &client : this->clients_) {
|
||||
client->send_bluetooth_gatt_notify_data_response(call);
|
||||
}
|
||||
}
|
||||
void APIServer::send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &call) {
|
||||
for (auto &client : this->clients_) {
|
||||
client->send_bluetooth_gatt_notify_response(call);
|
||||
}
|
||||
}
|
||||
void APIServer::send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call) {
|
||||
for (auto &client : this->clients_) {
|
||||
client->send_bluetooth_gatt_get_services_response(call);
|
||||
@@ -342,6 +352,17 @@ void APIServer::send_bluetooth_gatt_services_done(uint64_t address) {
|
||||
client->send_bluetooth_gatt_get_services_done_response(call);
|
||||
}
|
||||
}
|
||||
void APIServer::send_bluetooth_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) {
|
||||
BluetoothGATTErrorResponse call;
|
||||
call.address = address;
|
||||
call.handle = handle;
|
||||
call.error = error;
|
||||
|
||||
for (auto &client : this->clients_) {
|
||||
client->send_bluetooth_gatt_error_response(call);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
APIServer::APIServer() { global_api_server = this; }
|
||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
|
@@ -12,6 +12,8 @@
|
||||
#include "user_services.h"
|
||||
#include "api_noise_context.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
@@ -75,12 +77,15 @@ class APIServer : public Component, public Controller {
|
||||
void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
void send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call);
|
||||
void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu, 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_connections_free(uint8_t free, uint8_t limit);
|
||||
void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call);
|
||||
void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call);
|
||||
void send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call);
|
||||
void send_bluetooth_gatt_notify_response(const BluetoothGATTNotifyResponse &call);
|
||||
void send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call);
|
||||
void send_bluetooth_gatt_services_done(uint64_t address);
|
||||
void send_bluetooth_gatt_error(uint64_t address, uint16_t handle, esp_err_t error);
|
||||
#endif
|
||||
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
|
||||
#ifdef USE_HOMEASSISTANT_TIME
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include "api_pb2.h"
|
||||
#include "api_server.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
#define HAS_PROTO_MESSAGE_DUMP
|
||||
#endif
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
@@ -8,6 +8,7 @@ CODEOWNERS = ["@OttoWinter"]
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema({}),
|
||||
cv.only_with_arduino,
|
||||
cv.only_on(["esp32", "esp8266"]),
|
||||
)
|
||||
|
||||
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
|
@@ -8,6 +8,8 @@
|
||||
#include "bedjet_child.h"
|
||||
#include "bedjet_codec.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/binary_sensor/filter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
namespace binary_sensor {
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
namespace binary_sensor {
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace binary_sensor_map {
|
||||
|
||||
|
@@ -66,7 +66,7 @@ CONF_BLE_CLIENT_ID = "ble_client_id"
|
||||
|
||||
BLE_CLIENT_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_BLE_CLIENT_ID): cv.use_id(BLEClient),
|
||||
cv.GenerateID(CONF_BLE_CLIENT_ID): cv.use_id(BLEClient),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -78,7 +78,7 @@ async def register_ble_node(var, config):
|
||||
|
||||
BLE_WRITE_ACTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(BLEClient),
|
||||
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
|
||||
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Required(CONF_VALUE): cv.templatable(cv.ensure_list(cv.hex_uint8_t)),
|
||||
@@ -100,12 +100,40 @@ async def ble_write_to_code(config, action_id, template_arg, args):
|
||||
else:
|
||||
cg.add(var.set_value_simple(value))
|
||||
|
||||
serv_uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID])
|
||||
cg.add(var.set_service_uuid128(serv_uuid128))
|
||||
char_uuid128 = esp32_ble_tracker.as_reversed_hex_array(
|
||||
config[CONF_CHARACTERISTIC_UUID]
|
||||
)
|
||||
cg.add(var.set_char_uuid128(char_uuid128))
|
||||
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||
cg.add(
|
||||
var.set_service_uuid16(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
||||
)
|
||||
elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid32_format):
|
||||
cg.add(
|
||||
var.set_service_uuid32(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
||||
)
|
||||
elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid128_format):
|
||||
uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID])
|
||||
cg.add(var.set_service_uuid128(uuid128))
|
||||
|
||||
if len(config[CONF_CHARACTERISTIC_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||
cg.add(
|
||||
var.set_char_uuid16(
|
||||
esp32_ble_tracker.as_hex(config[CONF_CHARACTERISTIC_UUID])
|
||||
)
|
||||
)
|
||||
elif len(config[CONF_CHARACTERISTIC_UUID]) == len(
|
||||
esp32_ble_tracker.bt_uuid32_format
|
||||
):
|
||||
cg.add(
|
||||
var.set_char_uuid32(
|
||||
esp32_ble_tracker.as_hex(config[CONF_CHARACTERISTIC_UUID])
|
||||
)
|
||||
)
|
||||
elif len(config[CONF_CHARACTERISTIC_UUID]) == len(
|
||||
esp32_ble_tracker.bt_uuid128_format
|
||||
):
|
||||
uuid128 = esp32_ble_tracker.as_reversed_hex_array(
|
||||
config[CONF_CHARACTERISTIC_UUID]
|
||||
)
|
||||
cg.add(var.set_char_uuid128(uuid128))
|
||||
|
||||
return var
|
||||
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/ble_client/ble_client.h"
|
||||
@@ -46,10 +47,14 @@ class BLEWriterClientNode : public BLEClientNode {
|
||||
// Attempts to write the contents of value to char_uuid_.
|
||||
void write(const std::vector<uint8_t> &value);
|
||||
|
||||
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
|
||||
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
|
||||
void set_char_uuid16(uint16_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||
void set_char_uuid32(uint32_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
|
||||
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) override;
|
||||
|
||||
|
@@ -47,11 +47,12 @@ void BLEClient::set_enabled(bool enabled) {
|
||||
this->enabled = enabled;
|
||||
}
|
||||
|
||||
void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if,
|
||||
bool BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) {
|
||||
bool all_established = this->all_nodes_established_();
|
||||
|
||||
BLEClientBase::gattc_event_handler(event, esp_gattc_if, param);
|
||||
if (!BLEClientBase::gattc_event_handler(event, esp_gattc_if, param))
|
||||
return false;
|
||||
|
||||
for (auto *node : this->nodes_)
|
||||
node->gattc_event_handler(event, esp_gattc_if, param);
|
||||
@@ -62,6 +63,14 @@ void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t es
|
||||
delete svc; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
this->services_.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BLEClient::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
||||
BLEClientBase::gap_event_handler(event, param);
|
||||
|
||||
for (auto *node : this->nodes_)
|
||||
node->gap_event_handler(event, param);
|
||||
}
|
||||
|
||||
void BLEClient::set_state(espbt::ClientState state) {
|
||||
|
@@ -7,12 +7,13 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gattc_api.h>
|
||||
#include <esp_bt_defs.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gatt_common_api.h>
|
||||
#include <esp_gattc_api.h>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ble_client {
|
||||
@@ -27,7 +28,8 @@ class BLEClientNode {
|
||||
public:
|
||||
virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) = 0;
|
||||
virtual void loop(){};
|
||||
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {}
|
||||
virtual void loop() {}
|
||||
void set_address(uint64_t address) { address_ = address; }
|
||||
espbt::ESPBTClient *client;
|
||||
// This should be transitioned to Established once the node no longer needs
|
||||
@@ -49,8 +51,10 @@ class BLEClient : public BLEClientBase {
|
||||
void dump_config() override;
|
||||
void loop() override;
|
||||
|
||||
void 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;
|
||||
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
|
||||
bool parse_device(const espbt::ESPBTDevice &device) override;
|
||||
|
||||
void set_enabled(bool enabled);
|
||||
|
@@ -5,7 +5,11 @@ from esphome.const import (
|
||||
CONF_CHARACTERISTIC_UUID,
|
||||
CONF_LAMBDA,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_TYPE,
|
||||
CONF_SERVICE_UUID,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_DECIBEL_MILLIWATT,
|
||||
)
|
||||
from esphome import automation
|
||||
from .. import ble_client_ns
|
||||
@@ -16,6 +20,8 @@ CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
||||
|
||||
CONF_NOTIFY = "notify"
|
||||
CONF_ON_NOTIFY = "on_notify"
|
||||
TYPE_CHARACTERISTIC = "characteristic"
|
||||
TYPE_RSSI = "rssi"
|
||||
|
||||
adv_data_t = cg.std_vector.template(cg.uint8)
|
||||
adv_data_t_const_ref = adv_data_t.operator("ref").operator("const")
|
||||
@@ -27,33 +33,67 @@ BLESensorNotifyTrigger = ble_client_ns.class_(
|
||||
"BLESensorNotifyTrigger", automation.Trigger.template(cg.float_)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.sensor_schema(
|
||||
BLESensor,
|
||||
accuracy_decimals=0,
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_NOTIFY, default=False): cv.boolean,
|
||||
cv.Optional(CONF_ON_NOTIFY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
BLESensorNotifyTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(ble_client.BLE_CLIENT_SCHEMA)
|
||||
BLEClientRssiSensor = ble_client_ns.class_(
|
||||
"BLEClientRSSISensor", sensor.Sensor, cg.PollingComponent, ble_client.BLEClientNode
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
def checkType(value):
|
||||
if CONF_TYPE not in value and CONF_SERVICE_UUID in value:
|
||||
raise cv.Invalid(
|
||||
"Looks like you're trying to create a ble characteristic sensor. Please add `type: characteristic` to your sensor config."
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
checkType,
|
||||
cv.typed_schema(
|
||||
{
|
||||
TYPE_CHARACTERISTIC: sensor.sensor_schema(
|
||||
BLESensor,
|
||||
accuracy_decimals=0,
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(ble_client.BLE_CLIENT_SCHEMA)
|
||||
.extend(
|
||||
{
|
||||
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_NOTIFY, default=False): cv.boolean,
|
||||
cv.Optional(CONF_ON_NOTIFY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
BLESensorNotifyTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
}
|
||||
),
|
||||
TYPE_RSSI: sensor.sensor_schema(
|
||||
BLEClientRssiSensor,
|
||||
accuracy_decimals=0,
|
||||
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
|
||||
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(ble_client.BLE_CLIENT_SCHEMA),
|
||||
},
|
||||
lower=True,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def rssi_sensor_to_code(config):
|
||||
var = await sensor.new_sensor(config)
|
||||
await cg.register_component(var, config)
|
||||
await ble_client.register_ble_node(var, config)
|
||||
|
||||
|
||||
async def characteristic_sensor_to_code(config):
|
||||
var = await sensor.new_sensor(config)
|
||||
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||
cg.add(
|
||||
@@ -125,3 +165,10 @@ async def to_code(config):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await ble_client.register_ble_node(trigger, config)
|
||||
await automation.build_automation(trigger, [(float, "x")], conf)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
if config[CONF_TYPE] == TYPE_RSSI:
|
||||
await rssi_sensor_to_code(config)
|
||||
elif config[CONF_TYPE] == TYPE_CHARACTERISTIC:
|
||||
await characteristic_sensor_to_code(config)
|
||||
|
78
esphome/components/ble_client/sensor/ble_rssi_sensor.cpp
Normal file
78
esphome/components/ble_client/sensor/ble_rssi_sensor.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "ble_rssi_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace ble_client {
|
||||
|
||||
static const char *const TAG = "ble_rssi_sensor";
|
||||
|
||||
void BLEClientRSSISensor::loop() {}
|
||||
|
||||
void BLEClientRSSISensor::dump_config() {
|
||||
LOG_SENSOR("", "BLE Client RSSI Sensor", this);
|
||||
ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent()->address_str().c_str());
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void BLEClientRSSISensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) {
|
||||
switch (event) {
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
if (param->open.status == ESP_GATT_OK) {
|
||||
ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
ESP_LOGW(TAG, "[%s] Disconnected!", this->get_name().c_str());
|
||||
this->status_set_warning();
|
||||
this->publish_state(NAN);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT:
|
||||
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BLEClientRSSISensor::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
||||
switch (event) {
|
||||
// server response on RSSI request:
|
||||
case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
|
||||
if (param->read_rssi_cmpl.status == ESP_BT_STATUS_SUCCESS) {
|
||||
int8_t rssi = param->read_rssi_cmpl.rssi;
|
||||
ESP_LOGI(TAG, "ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT RSSI: %d", rssi);
|
||||
this->publish_state(rssi);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BLEClientRSSISensor::update() {
|
||||
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "requesting rssi from %s", this->parent()->address_str().c_str());
|
||||
auto status = esp_ble_gap_read_rssi(this->parent()->get_remote_bda());
|
||||
if (status != ESP_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gap_read_rssi error, address=%s, status=%d", this->parent()->address_str().c_str(), status);
|
||||
this->status_set_warning();
|
||||
this->publish_state(NAN);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ble_client
|
||||
} // namespace esphome
|
||||
#endif
|
31
esphome/components/ble_client/sensor/ble_rssi_sensor.h
Normal file
31
esphome/components/ble_client/sensor/ble_rssi_sensor.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/ble_client/ble_client.h"
|
||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace ble_client {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
class BLEClientRSSISensor : public sensor::Sensor, public PollingComponent, public BLEClientNode {
|
||||
public:
|
||||
void loop() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
|
||||
|
||||
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) override;
|
||||
};
|
||||
|
||||
} // namespace ble_client
|
||||
} // namespace esphome
|
||||
#endif
|
@@ -5,6 +5,8 @@
|
||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
|
@@ -58,7 +58,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
|
||||
case MATCH_BY_SERVICE_UUID:
|
||||
for (auto uuid : device.get_service_uuids()) {
|
||||
if (this->uuid_ == uuid) {
|
||||
this->publish_state(device.get_rssi());
|
||||
this->publish_state(true);
|
||||
this->found_ = true;
|
||||
return true;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
|
||||
return false;
|
||||
}
|
||||
|
||||
this->publish_state(device.get_rssi());
|
||||
this->publish_state(true);
|
||||
this->found_ = true;
|
||||
return true;
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ from esphome.const import (
|
||||
CONF_MAC_ADDRESS,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_DECIBEL,
|
||||
UNIT_DECIBEL_MILLIWATT,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["esp32_ble_tracker"]
|
||||
@@ -31,7 +31,7 @@ def _validate(config):
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.sensor_schema(
|
||||
BLERSSISensor,
|
||||
unit_of_measurement=UNIT_DECIBEL,
|
||||
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
|
@@ -4,22 +4,59 @@ import esphome.codegen as cg
|
||||
from esphome.const import CONF_ACTIVE, CONF_ID
|
||||
|
||||
AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
|
||||
DEPENDENCIES = ["esp32"]
|
||||
DEPENDENCIES = ["api", "esp32"]
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
CONF_CONNECTIONS = "connections"
|
||||
MAX_CONNECTIONS = 3
|
||||
|
||||
bluetooth_proxy_ns = cg.esphome_ns.namespace("bluetooth_proxy")
|
||||
|
||||
BluetoothProxy = bluetooth_proxy_ns.class_(
|
||||
"BluetoothProxy", esp32_ble_client.BLEClientBase
|
||||
"BluetoothProxy", esp32_ble_tracker.ESPBTDeviceListener, cg.Component
|
||||
)
|
||||
BluetoothConnection = bluetooth_proxy_ns.class_(
|
||||
"BluetoothConnection", esp32_ble_client.BLEClientBase
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
CONNECTION_SCHEMA = esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BluetoothProxy),
|
||||
cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
|
||||
cv.GenerateID(): cv.declare_id(BluetoothConnection),
|
||||
}
|
||||
).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def validate_connections(config):
|
||||
if CONF_CONNECTIONS in config:
|
||||
if not config[CONF_ACTIVE]:
|
||||
raise cv.Invalid(
|
||||
"Connections can only be used if the proxy is set to active"
|
||||
)
|
||||
else:
|
||||
if config[CONF_ACTIVE]:
|
||||
conf = config.copy()
|
||||
conf[CONF_CONNECTIONS] = [
|
||||
CONNECTION_SCHEMA({}) for _ in range(MAX_CONNECTIONS)
|
||||
]
|
||||
return conf
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BluetoothProxy),
|
||||
cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_CONNECTIONS): cv.All(
|
||||
cv.ensure_list(CONNECTION_SCHEMA),
|
||||
cv.Length(min=1, max=MAX_CONNECTIONS),
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
|
||||
.extend(cv.COMPONENT_SCHEMA),
|
||||
validate_connections,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
@@ -27,7 +64,12 @@ async def to_code(config):
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_active(config[CONF_ACTIVE]))
|
||||
await esp32_ble_tracker.register_ble_device(var, config)
|
||||
|
||||
await esp32_ble_tracker.register_client(var, config)
|
||||
for connection_conf in config.get(CONF_CONNECTIONS, []):
|
||||
connection_var = cg.new_Pvariable(connection_conf[CONF_ID])
|
||||
await cg.register_component(connection_var, connection_conf)
|
||||
cg.add(var.register_connection(connection_var))
|
||||
await esp32_ble_tracker.register_client(connection_var, connection_conf)
|
||||
|
||||
cg.add_define("USE_BLUETOOTH_PROXY")
|
||||
|
270
esphome/components/bluetooth_proxy/bluetooth_connection.cpp
Normal file
270
esphome/components/bluetooth_proxy/bluetooth_connection.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
#include "bluetooth_connection.h"
|
||||
|
||||
#include "esphome/components/api/api_server.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "bluetooth_proxy.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace bluetooth_proxy {
|
||||
|
||||
static const char *const TAG = "bluetooth_proxy.connection";
|
||||
|
||||
bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) {
|
||||
if (!BLEClientBase::gattc_event_handler(event, gattc_if, param))
|
||||
return false;
|
||||
|
||||
switch (event) {
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, false, 0, param->disconnect.reason);
|
||||
this->set_address(0);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
||||
this->proxy_->get_bluetooth_connections_limit());
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
if (param->open.conn_id != this->conn_id_)
|
||||
break;
|
||||
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, false, 0, param->open.status);
|
||||
this->set_address(0);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
||||
this->proxy_->get_bluetooth_connections_limit());
|
||||
} else if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
||||
this->proxy_->get_bluetooth_connections_limit());
|
||||
}
|
||||
this->seen_mtu_or_services_ = false;
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_CFG_MTU_EVT: {
|
||||
if (param->cfg_mtu.conn_id != this->conn_id_)
|
||||
break;
|
||||
if (!this->seen_mtu_or_services_) {
|
||||
// We don't know if we will get the MTU or the services first, so
|
||||
// only send the device connection true if we have already received
|
||||
// the services.
|
||||
this->seen_mtu_or_services_ = true;
|
||||
break;
|
||||
}
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
||||
this->proxy_->get_bluetooth_connections_limit());
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
if (param->search_cmpl.conn_id != this->conn_id_)
|
||||
break;
|
||||
if (!this->seen_mtu_or_services_) {
|
||||
// We don't know if we will get the MTU or the services first, so
|
||||
// only send the device connection true if we have already received
|
||||
// the mtu.
|
||||
this->seen_mtu_or_services_ = true;
|
||||
break;
|
||||
}
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
|
||||
this->proxy_->get_bluetooth_connections_limit());
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_READ_DESCR_EVT:
|
||||
case ESP_GATTC_READ_CHAR_EVT: {
|
||||
if (param->read.conn_id != this->conn_id_)
|
||||
break;
|
||||
if (param->read.status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error reading char/descriptor at handle 0x%2X, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->read.handle, param->read.status);
|
||||
api::global_api_server->send_bluetooth_gatt_error(this->address_, param->read.handle, param->read.status);
|
||||
break;
|
||||
}
|
||||
api::BluetoothGATTReadResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->read.handle;
|
||||
resp.data.reserve(param->read.value_len);
|
||||
for (uint16_t i = 0; i < param->read.value_len; i++) {
|
||||
resp.data.push_back(param->read.value[i]);
|
||||
}
|
||||
api::global_api_server->send_bluetooth_gatt_read_response(resp);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_WRITE_CHAR_EVT:
|
||||
case ESP_GATTC_WRITE_DESCR_EVT: {
|
||||
if (param->write.conn_id != this->conn_id_)
|
||||
break;
|
||||
if (param->write.status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error writing char/descriptor at handle 0x%2X, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->write.handle, param->write.status);
|
||||
api::global_api_server->send_bluetooth_gatt_error(this->address_, param->write.handle, param->write.status);
|
||||
break;
|
||||
}
|
||||
api::BluetoothGATTWriteResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->write.handle;
|
||||
api::global_api_server->send_bluetooth_gatt_write_response(resp);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
|
||||
if (param->unreg_for_notify.status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d",
|
||||
this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle,
|
||||
param->unreg_for_notify.status);
|
||||
api::global_api_server->send_bluetooth_gatt_error(this->address_, param->unreg_for_notify.handle,
|
||||
param->unreg_for_notify.status);
|
||||
break;
|
||||
}
|
||||
api::BluetoothGATTNotifyResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->unreg_for_notify.handle;
|
||||
api::global_api_server->send_bluetooth_gatt_notify_response(resp);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||
if (param->reg_for_notify.status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status);
|
||||
api::global_api_server->send_bluetooth_gatt_error(this->address_, param->reg_for_notify.handle,
|
||||
param->reg_for_notify.status);
|
||||
break;
|
||||
}
|
||||
api::BluetoothGATTNotifyResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->reg_for_notify.handle;
|
||||
api::global_api_server->send_bluetooth_gatt_notify_response(resp);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_NOTIFY_EVT: {
|
||||
if (param->notify.conn_id != this->conn_id_)
|
||||
break;
|
||||
ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_NOTIFY_EVT: handle=0x%2X", this->connection_index_, this->address_str_.c_str(),
|
||||
param->notify.handle);
|
||||
api::BluetoothGATTNotifyDataResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->notify.handle;
|
||||
resp.data.reserve(param->notify.value_len);
|
||||
for (uint16_t i = 0; i < param->notify.value_len; i++) {
|
||||
resp.data.push_back(param->notify.value[i]);
|
||||
}
|
||||
api::global_api_server->send_bluetooth_gatt_notify_data_response(resp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
|
||||
if (!this->connected()) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[%d] [%s] Reading GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
handle);
|
||||
|
||||
esp_err_t err = esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const std::string &data, bool response) {
|
||||
if (!this->connected()) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT characteristic, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
handle);
|
||||
|
||||
esp_err_t err =
|
||||
esp_ble_gattc_write_char(this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
|
||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
|
||||
if (!this->connected()) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT descriptor, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%d] [%s] Reading GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
handle);
|
||||
|
||||
esp_err_t err = esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char_descr error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data, bool response) {
|
||||
if (!this->connected()) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
handle);
|
||||
|
||||
esp_err_t err = esp_ble_gattc_write_char_descr(
|
||||
this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
|
||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enable) {
|
||||
if (!this->connected()) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot notify GATT characteristic, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ESP_LOGV(TAG, "[%d] [%s] Registering for GATT characteristic notifications handle %d", this->connection_index_,
|
||||
this->address_str_.c_str(), handle);
|
||||
esp_err_t err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_register_for_notify failed, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications handle %d", this->connection_index_,
|
||||
this->address_str_.c_str(), handle);
|
||||
esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_unregister_for_notify failed, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
} // namespace bluetooth_proxy
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32
|
35
esphome/components/bluetooth_proxy/bluetooth_connection.h
Normal file
35
esphome/components/bluetooth_proxy/bluetooth_connection.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/components/esp32_ble_client/ble_client_base.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace bluetooth_proxy {
|
||||
|
||||
class BluetoothProxy;
|
||||
|
||||
class BluetoothConnection : public esp32_ble_client::BLEClientBase {
|
||||
public:
|
||||
bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) override;
|
||||
|
||||
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 read_descriptor(uint16_t handle);
|
||||
esp_err_t write_descriptor(uint16_t handle, const std::string &data, bool response);
|
||||
|
||||
esp_err_t notify_characteristic(uint16_t handle, bool enable);
|
||||
|
||||
protected:
|
||||
friend class BluetoothProxy;
|
||||
bool seen_mtu_or_services_{false};
|
||||
|
||||
int16_t send_service_{-2};
|
||||
BluetoothProxy *proxy_;
|
||||
};
|
||||
|
||||
} // namespace bluetooth_proxy
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32
|
@@ -4,45 +4,42 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#ifdef USE_API
|
||||
#include "esphome/components/api/api_server.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace bluetooth_proxy {
|
||||
|
||||
static const char *const TAG = "bluetooth_proxy";
|
||||
static const int DONE_SENDING_SERVICES = -2;
|
||||
|
||||
BluetoothProxy::BluetoothProxy() {
|
||||
global_bluetooth_proxy = this;
|
||||
this->address_ = 0;
|
||||
std::vector<uint64_t> get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) {
|
||||
esp_bt_uuid_t uuid = espbt::ESPBTUUID::from_uuid(uuid_source).as_128bit().get_uuid();
|
||||
return std::vector<uint64_t>{((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) |
|
||||
((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) |
|
||||
((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) |
|
||||
((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]),
|
||||
((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) |
|
||||
((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) |
|
||||
((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) |
|
||||
((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0])};
|
||||
}
|
||||
|
||||
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
|
||||
|
||||
bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
|
||||
if (!api::global_api_server->is_connected())
|
||||
return false;
|
||||
ESP_LOGV(TAG, "Proxying packet from %s - %s. RSSI: %d dB", device.get_name().c_str(), device.address_str().c_str(),
|
||||
device.get_rssi());
|
||||
this->send_api_packet_(device);
|
||||
|
||||
this->address_type_map_[device.address_uint64()] = device.get_address_type();
|
||||
|
||||
if (this->address_ == 0)
|
||||
return true;
|
||||
|
||||
if (this->state_ == espbt::ClientState::DISCOVERED) {
|
||||
ESP_LOGV(TAG, "Connecting to address %s", this->address_str().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
BLEClientBase::parse_device(device);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) {
|
||||
#ifndef USE_API
|
||||
return;
|
||||
#else
|
||||
api::BluetoothLEAdvertisementResponse resp;
|
||||
resp.address = device.address_uint64();
|
||||
resp.address_type = device.get_address_type();
|
||||
if (!device.get_name().empty())
|
||||
resp.name = device.get_name();
|
||||
resp.rssi = device.get_rssi();
|
||||
@@ -62,152 +59,234 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi
|
||||
resp.manufacturer_data.push_back(std::move(manufacturer_data));
|
||||
}
|
||||
api::global_api_server->send_bluetooth_le_advertisement(resp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BluetoothProxy::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) {
|
||||
BLEClientBase::gattc_event_handler(event, gattc_if, param);
|
||||
switch (event) {
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
#ifdef USE_API
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, false, this->mtu_,
|
||||
param->disconnect.reason);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||
this->get_bluetooth_connections_limit());
|
||||
#endif
|
||||
this->address_ = 0;
|
||||
}
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
|
||||
#ifdef USE_API
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, false, this->mtu_, param->open.status);
|
||||
void BluetoothProxy::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Bluetooth Proxy:");
|
||||
ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_));
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
int BluetoothProxy::get_bluetooth_connections_free() {
|
||||
int free = 0;
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->address_ == 0) {
|
||||
free++;
|
||||
ESP_LOGV(TAG, "[%d] Free connection", connection->get_connection_index());
|
||||
} else {
|
||||
ESP_LOGV(TAG, "[%d] Used connection by [%s]", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
}
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
#ifdef USE_API
|
||||
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||
this->get_bluetooth_connections_limit());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_READ_DESCR_EVT:
|
||||
case ESP_GATTC_READ_CHAR_EVT: {
|
||||
if (param->read.conn_id != this->conn_id_)
|
||||
break;
|
||||
if (param->read.status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "Error reading char/descriptor at handle %d, status=%d", param->read.handle, param->read.status);
|
||||
break;
|
||||
}
|
||||
#ifdef USE_API
|
||||
api::BluetoothGATTReadResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->read.handle;
|
||||
resp.data.reserve(param->read.value_len);
|
||||
for (uint16_t i = 0; i < param->read.value_len; i++) {
|
||||
resp.data.push_back(param->read.value[i]);
|
||||
}
|
||||
api::global_api_server->send_bluetooth_gatt_read_response(resp);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_NOTIFY_EVT: {
|
||||
if (param->notify.conn_id != this->conn_id_)
|
||||
break;
|
||||
ESP_LOGV(TAG, "ESP_GATTC_NOTIFY_EVT: handle=0x%x", param->notify.handle);
|
||||
#ifdef USE_API
|
||||
api::BluetoothGATTNotifyDataResponse resp;
|
||||
resp.address = this->address_;
|
||||
resp.handle = param->notify.handle;
|
||||
resp.data.reserve(param->notify.value_len);
|
||||
for (uint16_t i = 0; i < param->notify.value_len; i++) {
|
||||
resp.data.push_back(param->notify.value[i]);
|
||||
}
|
||||
api::global_api_server->send_bluetooth_gatt_notify_data_response(resp);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
void BluetoothProxy::dump_config() { ESP_LOGCONFIG(TAG, "Bluetooth Proxy:"); }
|
||||
|
||||
void BluetoothProxy::loop() {
|
||||
BLEClientBase::loop();
|
||||
#ifdef USE_API
|
||||
if (this->state_ != espbt::ClientState::IDLE && !api::global_api_server->is_connected()) {
|
||||
ESP_LOGI(TAG, "[%s] Disconnecting.", this->address_str().c_str());
|
||||
auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_close error, address=%s err=%d", this->address_str().c_str(), err);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->send_service_ == this->services_.size()) {
|
||||
this->send_service_ = -1;
|
||||
api::global_api_server->send_bluetooth_gatt_services_done(this->address_);
|
||||
} else if (this->send_service_ >= 0) {
|
||||
auto &service = this->services_[this->send_service_];
|
||||
api::BluetoothGATTGetServicesResponse resp;
|
||||
resp.address = this->address_;
|
||||
api::BluetoothGATTService service_resp;
|
||||
service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()};
|
||||
service_resp.handle = service->start_handle;
|
||||
for (auto &characteristic : service->characteristics) {
|
||||
api::BluetoothGATTCharacteristic characteristic_resp;
|
||||
characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()};
|
||||
characteristic_resp.handle = characteristic->handle;
|
||||
characteristic_resp.properties = characteristic->properties;
|
||||
for (auto &descriptor : characteristic->descriptors) {
|
||||
api::BluetoothGATTDescriptor descriptor_resp;
|
||||
descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()};
|
||||
descriptor_resp.handle = descriptor->handle;
|
||||
characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
|
||||
if (!api::global_api_server->is_connected()) {
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->get_address() != 0) {
|
||||
connection->disconnect();
|
||||
}
|
||||
service_resp.characteristics.push_back(std::move(characteristic_resp));
|
||||
}
|
||||
resp.services.push_back(std::move(service_resp));
|
||||
api::global_api_server->send_bluetooth_gatt_services(resp);
|
||||
this->send_service_++;
|
||||
return;
|
||||
}
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->send_service_ == connection->service_count_) {
|
||||
connection->send_service_ = DONE_SENDING_SERVICES;
|
||||
api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
|
||||
if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
||||
connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
|
||||
connection->release_services();
|
||||
}
|
||||
} else if (connection->send_service_ >= 0) {
|
||||
esp_gattc_service_elem_t service_result;
|
||||
uint16_t service_count = 1;
|
||||
esp_gatt_status_t service_status =
|
||||
esp_ble_gattc_get_service(connection->get_gattc_if(), connection->get_conn_id(), nullptr, &service_result,
|
||||
&service_count, connection->send_service_);
|
||||
connection->send_service_++;
|
||||
if (service_status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service error at offset=%d, status=%d",
|
||||
connection->get_connection_index(), connection->address_str().c_str(), connection->send_service_ - 1,
|
||||
service_status);
|
||||
continue;
|
||||
}
|
||||
if (service_count == 0) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service missing, service_count=%d",
|
||||
connection->get_connection_index(), connection->address_str().c_str(), service_count);
|
||||
continue;
|
||||
}
|
||||
api::BluetoothGATTGetServicesResponse resp;
|
||||
resp.address = connection->get_address();
|
||||
api::BluetoothGATTService service_resp;
|
||||
service_resp.uuid = get_128bit_uuid_vec(service_result.uuid);
|
||||
service_resp.handle = service_result.start_handle;
|
||||
uint16_t char_offset = 0;
|
||||
esp_gattc_char_elem_t char_result;
|
||||
while (true) { // characteristics
|
||||
uint16_t char_count = 1;
|
||||
esp_gatt_status_t char_status = esp_ble_gattc_get_all_char(
|
||||
connection->get_gattc_if(), connection->get_conn_id(), service_result.start_handle,
|
||||
service_result.end_handle, &char_result, &char_count, char_offset);
|
||||
if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (char_status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", connection->get_connection_index(),
|
||||
connection->address_str().c_str(), char_status);
|
||||
break;
|
||||
}
|
||||
if (char_count == 0) {
|
||||
break;
|
||||
}
|
||||
api::BluetoothGATTCharacteristic characteristic_resp;
|
||||
characteristic_resp.uuid = get_128bit_uuid_vec(char_result.uuid);
|
||||
characteristic_resp.handle = char_result.char_handle;
|
||||
characteristic_resp.properties = char_result.properties;
|
||||
char_offset++;
|
||||
uint16_t desc_offset = 0;
|
||||
esp_gattc_descr_elem_t desc_result;
|
||||
while (true) { // descriptors
|
||||
uint16_t desc_count = 1;
|
||||
esp_gatt_status_t desc_status =
|
||||
esp_ble_gattc_get_all_descr(connection->get_gattc_if(), connection->get_conn_id(),
|
||||
char_result.char_handle, &desc_result, &desc_count, desc_offset);
|
||||
if (desc_status == ESP_GATT_INVALID_OFFSET || desc_status == ESP_GATT_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (desc_status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", connection->get_connection_index(),
|
||||
connection->address_str().c_str(), desc_status);
|
||||
break;
|
||||
}
|
||||
if (desc_count == 0) {
|
||||
break;
|
||||
}
|
||||
api::BluetoothGATTDescriptor descriptor_resp;
|
||||
descriptor_resp.uuid = get_128bit_uuid_vec(desc_result.uuid);
|
||||
descriptor_resp.handle = desc_result.handle;
|
||||
characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
|
||||
desc_offset++;
|
||||
}
|
||||
service_resp.characteristics.push_back(std::move(characteristic_resp));
|
||||
}
|
||||
resp.services.push_back(std::move(service_resp));
|
||||
api::global_api_server->send_bluetooth_gatt_services(resp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_API
|
||||
BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool reserve) {
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->get_address() == address)
|
||||
return connection;
|
||||
}
|
||||
|
||||
if (!reserve)
|
||||
return nullptr;
|
||||
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->get_address() == 0) {
|
||||
connection->send_service_ = DONE_SENDING_SERVICES;
|
||||
connection->set_address(address);
|
||||
// All connections must start at INIT
|
||||
// We only set the state if we allocate the connection
|
||||
// to avoid a race where multiple connection attempts
|
||||
// are made.
|
||||
connection->set_state(espbt::ClientState::INIT);
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
|
||||
switch (msg.request_type) {
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
|
||||
this->address_ = msg.address;
|
||||
if (this->address_type_map_.find(this->address_) != this->address_type_map_.end()) {
|
||||
// Utilise the address type cache
|
||||
this->remote_addr_type_ = this->address_type_map_[this->address_];
|
||||
} else {
|
||||
this->remote_addr_type_ = BLE_ADDR_TYPE_PUBLIC;
|
||||
auto *connection = this->get_connection_(msg.address, true);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "No free connections available");
|
||||
api::global_api_server->send_bluetooth_device_connection(msg.address, false);
|
||||
return;
|
||||
}
|
||||
this->remote_bda_[0] = (this->address_ >> 40) & 0xFF;
|
||||
this->remote_bda_[1] = (this->address_ >> 32) & 0xFF;
|
||||
this->remote_bda_[2] = (this->address_ >> 24) & 0xFF;
|
||||
this->remote_bda_[3] = (this->address_ >> 16) & 0xFF;
|
||||
this->remote_bda_[4] = (this->address_ >> 8) & 0xFF;
|
||||
this->remote_bda_[5] = (this->address_ >> 0) & 0xFF;
|
||||
this->set_state(espbt::ClientState::DISCOVERED);
|
||||
esp_ble_gap_stop_scanning();
|
||||
if (connection->state() == espbt::ClientState::CONNECTED ||
|
||||
connection->state() == espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection already established", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
api::global_api_server->send_bluetooth_device_connection(msg.address, true);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||
this->get_bluetooth_connections_limit());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::SEARCHING) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::DISCOVERED) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device already discovered",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::READY_TO_CONNECT) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, waiting in line to connect",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::CONNECTING) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already connecting", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device is disconnecting",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() != espbt::ClientState::INIT) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
return;
|
||||
}
|
||||
if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE) {
|
||||
connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 with cache", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
} else if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE) {
|
||||
connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 without cache", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
} else {
|
||||
connection->set_connection_type(espbt::ConnectionType::V1);
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
|
||||
}
|
||||
if (msg.has_address_type) {
|
||||
connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
|
||||
connection->remote_bda_[1] = (msg.address >> 32) & 0xFF;
|
||||
connection->remote_bda_[2] = (msg.address >> 24) & 0xFF;
|
||||
connection->remote_bda_[3] = (msg.address >> 16) & 0xFF;
|
||||
connection->remote_bda_[4] = (msg.address >> 8) & 0xFF;
|
||||
connection->remote_bda_[5] = (msg.address >> 0) & 0xFF;
|
||||
connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
|
||||
connection->set_state(espbt::ClientState::DISCOVERED);
|
||||
} else {
|
||||
connection->set_state(espbt::ClientState::SEARCHING);
|
||||
}
|
||||
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||
this->get_bluetooth_connections_limit());
|
||||
break;
|
||||
}
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT: {
|
||||
if (this->state() != espbt::ClientState::IDLE) {
|
||||
ESP_LOGI(TAG, "[%s] Disconnecting.", this->address_str().c_str());
|
||||
auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_close error, address=%s err=%d", this->address_str().c_str(), err);
|
||||
}
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
api::global_api_server->send_bluetooth_device_connection(msg.address, false);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||
this->get_bluetooth_connections_limit());
|
||||
return;
|
||||
}
|
||||
if (connection->state() != espbt::ClientState::IDLE) {
|
||||
connection->disconnect();
|
||||
} else {
|
||||
connection->set_address(0);
|
||||
api::global_api_server->send_bluetooth_device_connection(msg.address, false);
|
||||
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
|
||||
this->get_bluetooth_connections_limit());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -218,141 +297,92 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg) {
|
||||
if (this->state_ != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "Cannot read GATT characteristic, not connected.");
|
||||
return;
|
||||
}
|
||||
if (this->address_ != msg.address) {
|
||||
ESP_LOGW(TAG, "Address mismatch for read GATT characteristic request");
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot read GATT characteristic, not connected");
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *characteristic = this->get_characteristic(msg.handle);
|
||||
if (characteristic == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot read GATT characteristic, not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Reading GATT characteristic %s", characteristic->uuid.to_string().c_str());
|
||||
|
||||
esp_err_t err =
|
||||
esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, characteristic->handle, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_read_char error, err=%d", err);
|
||||
auto err = connection->read_characteristic(msg.handle);
|
||||
if (err != ESP_OK) {
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg) {
|
||||
if (this->state_ != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "Cannot write GATT characteristic, not connected.");
|
||||
return;
|
||||
}
|
||||
if (this->address_ != msg.address) {
|
||||
ESP_LOGW(TAG, "Address mismatch for write GATT characteristic request");
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot write GATT characteristic, not connected");
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *characteristic = this->get_characteristic(msg.handle);
|
||||
if (characteristic == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot write GATT characteristic, not found.");
|
||||
return;
|
||||
auto err = connection->write_characteristic(msg.handle, msg.data, msg.response);
|
||||
if (err != ESP_OK) {
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Writing GATT characteristic %s", characteristic->uuid.to_string().c_str());
|
||||
characteristic->write_value((uint8_t *) msg.data.data(), msg.data.size(),
|
||||
msg.response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP);
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg) {
|
||||
if (this->state_ != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "Cannot read GATT characteristic descriptor, not connected.");
|
||||
return;
|
||||
}
|
||||
if (this->address_ != msg.address) {
|
||||
ESP_LOGW(TAG, "Address mismatch for read GATT characteristic descriptor request");
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot read GATT descriptor, not connected");
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *descriptor = this->get_descriptor(msg.handle);
|
||||
if (descriptor == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot read GATT characteristic descriptor, not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Reading GATT characteristic descriptor %s -> %s", descriptor->characteristic->uuid.to_string().c_str(),
|
||||
descriptor->uuid.to_string().c_str());
|
||||
|
||||
esp_err_t err =
|
||||
esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_read_char error, err=%d", err);
|
||||
auto err = connection->read_descriptor(msg.handle);
|
||||
if (err != ESP_OK) {
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg) {
|
||||
if (this->state_ != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "Cannot write GATT characteristic descriptor, not connected.");
|
||||
return;
|
||||
}
|
||||
if (this->address_ != msg.address) {
|
||||
ESP_LOGW(TAG, "Address mismatch for write GATT characteristic descriptor request");
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot write GATT descriptor, not connected");
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *descriptor = this->get_descriptor(msg.handle);
|
||||
if (descriptor == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot write GATT characteristic descriptor, not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Writing GATT characteristic descriptor %s -> %s", descriptor->characteristic->uuid.to_string().c_str(),
|
||||
descriptor->uuid.to_string().c_str());
|
||||
|
||||
esp_err_t err =
|
||||
esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, msg.data.size(),
|
||||
(uint8_t *) msg.data.data(), ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_write_char_descr error, err=%d", err);
|
||||
auto err = connection->write_descriptor(msg.handle, msg.data, true);
|
||||
if (err != ESP_OK) {
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg) {
|
||||
if (this->address_ != msg.address) {
|
||||
ESP_LOGW(TAG, "Address mismatch for service list request");
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr || !connection->connected()) {
|
||||
ESP_LOGW(TAG, "Cannot get GATT services, not connected");
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
this->send_service_ = 0;
|
||||
if (!connection->service_count_) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
|
||||
api::global_api_server->send_bluetooth_gatt_services_done(msg.address);
|
||||
return;
|
||||
}
|
||||
if (connection->send_service_ ==
|
||||
DONE_SENDING_SERVICES) // Only start sending services if we're not already sending them
|
||||
connection->send_service_ = 0;
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg) {
|
||||
if (this->address_ != msg.address) {
|
||||
ESP_LOGW(TAG, "Address mismatch for notify");
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot notify GATT characteristic, not connected");
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *characteristic = this->get_characteristic(msg.handle);
|
||||
|
||||
if (characteristic == nullptr) {
|
||||
ESP_LOGW(TAG, "Cannot notify GATT characteristic, not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err;
|
||||
if (msg.enable) {
|
||||
err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, err=%d", err);
|
||||
}
|
||||
} else {
|
||||
err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_unregister_for_notify failed, err=%d", err);
|
||||
}
|
||||
auto err = connection->notify_characteristic(msg.handle, msg.enable);
|
||||
if (err != ESP_OK) {
|
||||
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BluetoothProxy *global_bluetooth_proxy = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
} // namespace bluetooth_proxy
|
||||
|
@@ -3,35 +3,36 @@
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/components/api/api_pb2.h"
|
||||
#include "esphome/components/esp32_ble_client/ble_client_base.h"
|
||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#ifdef USE_API
|
||||
#include "esphome/components/api/api_pb2.h"
|
||||
#endif // USE_API
|
||||
#include "bluetooth_connection.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace bluetooth_proxy {
|
||||
|
||||
static const esp_err_t ESP_GATT_NOT_CONNECTED = -1;
|
||||
|
||||
using namespace esp32_ble_client;
|
||||
|
||||
class BluetoothProxy : public BLEClientBase {
|
||||
class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Component {
|
||||
public:
|
||||
BluetoothProxy();
|
||||
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
||||
void dump_config() override;
|
||||
void loop() override;
|
||||
|
||||
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) override;
|
||||
void register_connection(BluetoothConnection *connection) {
|
||||
this->connections_.push_back(connection);
|
||||
connection->proxy_ = this;
|
||||
}
|
||||
|
||||
#ifdef USE_API
|
||||
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg);
|
||||
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg);
|
||||
void bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg);
|
||||
@@ -39,10 +40,9 @@ class BluetoothProxy : public BLEClientBase {
|
||||
void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg);
|
||||
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg);
|
||||
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg);
|
||||
#endif
|
||||
|
||||
int get_bluetooth_connections_free() { return this->state_ == espbt::ClientState::IDLE ? 1 : 0; }
|
||||
int get_bluetooth_connections_limit() { return 1; }
|
||||
int get_bluetooth_connections_free();
|
||||
int get_bluetooth_connections_limit() { return this->connections_.size(); }
|
||||
|
||||
void set_active(bool active) { this->active_ = active; }
|
||||
bool has_active() { return this->active_; }
|
||||
@@ -50,9 +50,11 @@ class BluetoothProxy : public BLEClientBase {
|
||||
protected:
|
||||
void send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device);
|
||||
|
||||
std::map<uint64_t, esp_ble_addr_type_t> address_type_map_;
|
||||
int16_t send_service_{-1};
|
||||
BluetoothConnection *get_connection_(uint64_t address, bool reserve);
|
||||
|
||||
bool active_;
|
||||
|
||||
std::vector<BluetoothConnection *> connections_{};
|
||||
};
|
||||
|
||||
extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/optional.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace canbus {
|
||||
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "esphome/components/output/binary_output.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace cap1188 {
|
||||
|
||||
|
@@ -22,6 +22,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.only_with_arduino,
|
||||
cv.only_on(["esp32", "esp8266"]),
|
||||
)
|
||||
|
||||
|
||||
|
@@ -113,7 +113,9 @@ CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).
|
||||
{
|
||||
cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
|
||||
cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
|
||||
cv.Optional(CONF_TEMPERATURE_STEP): cv.temperature,
|
||||
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(
|
||||
|
@@ -540,12 +540,15 @@ void Climate::dump_traits_(const char *tag) {
|
||||
ESP_LOGCONFIG(tag, " - Min: %.1f", traits.get_visual_min_temperature());
|
||||
ESP_LOGCONFIG(tag, " - Max: %.1f", traits.get_visual_max_temperature());
|
||||
ESP_LOGCONFIG(tag, " - Step: %.1f", traits.get_visual_temperature_step());
|
||||
if (traits.get_supports_current_temperature())
|
||||
if (traits.get_supports_current_temperature()) {
|
||||
ESP_LOGCONFIG(tag, " [x] Supports current temperature");
|
||||
if (traits.get_supports_two_point_target_temperature())
|
||||
}
|
||||
if (traits.get_supports_two_point_target_temperature()) {
|
||||
ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature");
|
||||
if (traits.get_supports_action())
|
||||
}
|
||||
if (traits.get_supports_action()) {
|
||||
ESP_LOGCONFIG(tag, " [x] Supports action");
|
||||
}
|
||||
if (!traits.get_supported_modes().empty()) {
|
||||
ESP_LOGCONFIG(tag, " [x] Supported modes:");
|
||||
for (ClimateMode m : traits.get_supported_modes())
|
||||
|
@@ -13,6 +13,7 @@ using namespace esphome::cover;
|
||||
CoverTraits CurrentBasedCover::get_traits() {
|
||||
auto traits = CoverTraits();
|
||||
traits.set_supports_position(true);
|
||||
traits.set_supports_toggle(true);
|
||||
traits.set_is_assumed_state(false);
|
||||
return traits;
|
||||
}
|
||||
@@ -20,6 +21,20 @@ void CurrentBasedCover::control(const CoverCall &call) {
|
||||
if (call.get_stop()) {
|
||||
this->direction_idle_();
|
||||
}
|
||||
if (call.get_toggle().has_value()) {
|
||||
if (this->current_operation != COVER_OPERATION_IDLE) {
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->publish_state();
|
||||
} else {
|
||||
if (this->position == COVER_CLOSED || this->last_operation_ == COVER_OPERATION_CLOSING) {
|
||||
this->target_position_ = COVER_OPEN;
|
||||
this->start_direction_(COVER_OPERATION_OPENING);
|
||||
} else {
|
||||
this->target_position_ = COVER_CLOSED;
|
||||
this->start_direction_(COVER_OPERATION_CLOSING);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (call.get_position().has_value()) {
|
||||
auto pos = *call.get_position();
|
||||
if (pos == this->position) {
|
||||
@@ -164,7 +179,7 @@ bool CurrentBasedCover::is_closing_blocked_() const {
|
||||
if (this->close_obstacle_current_threshold_ == FLT_MAX) {
|
||||
return false;
|
||||
}
|
||||
return this->open_sensor_->get_state() > this->open_obstacle_current_threshold_;
|
||||
return this->close_sensor_->get_state() > this->close_obstacle_current_threshold_;
|
||||
}
|
||||
bool CurrentBasedCover::is_initial_delay_finished_() const {
|
||||
return millis() - this->start_dir_time_ > this->start_sensing_delay_;
|
||||
@@ -202,9 +217,11 @@ void CurrentBasedCover::start_direction_(CoverOperation dir) {
|
||||
trig = this->stop_trigger_;
|
||||
break;
|
||||
case COVER_OPERATION_OPENING:
|
||||
this->last_operation_ = dir;
|
||||
trig = this->open_trigger_;
|
||||
break;
|
||||
case COVER_OPERATION_CLOSING:
|
||||
this->last_operation_ = dir;
|
||||
trig = this->close_trigger_;
|
||||
break;
|
||||
default:
|
||||
|
@@ -89,6 +89,8 @@ class CurrentBasedCover : public cover::Cover, public Component {
|
||||
uint32_t start_dir_time_{0};
|
||||
uint32_t last_publish_time_{0};
|
||||
float target_position_{0};
|
||||
|
||||
cover::CoverOperation last_operation_{cover::COVER_OPERATION_OPENING};
|
||||
};
|
||||
|
||||
} // namespace current_based
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/climate/climate.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "esphome/components/cover/cover.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/light/light_output.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#include "esphome/components/output/binary_output.h"
|
||||
#include "esphome/components/output/float_output.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom {
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace custom_component {
|
||||
|
||||
|
@@ -29,8 +29,9 @@ void DAC7678Output::setup() {
|
||||
ESP_LOGE(TAG, "Reset failed");
|
||||
this->mark_failed();
|
||||
return;
|
||||
} else
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Reset succeeded");
|
||||
}
|
||||
|
||||
delayMicroseconds(1000);
|
||||
|
||||
@@ -40,16 +41,18 @@ void DAC7678Output::setup() {
|
||||
ESP_LOGE(TAG, "Set internal reference failed");
|
||||
this->mark_failed();
|
||||
return;
|
||||
} else
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Internal reference enabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DAC7678Output::dump_config() {
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Setting up DAC7678 failed!");
|
||||
} else
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, "DAC7678 initialised");
|
||||
}
|
||||
}
|
||||
|
||||
void DAC7678Output::register_channel(DAC7678Channel *channel) {
|
||||
|
1
esphome/components/daikin_brc/__init__.py
Normal file
1
esphome/components/daikin_brc/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
CODEOWNERS = ["@hagak"]
|
24
esphome/components/daikin_brc/climate.py
Normal file
24
esphome/components/daikin_brc/climate.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate_ir
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ["climate_ir"]
|
||||
|
||||
daikin_brc_ns = cg.esphome_ns.namespace("daikin_brc")
|
||||
DaikinBrcClimate = daikin_brc_ns.class_("DaikinBrcClimate", climate_ir.ClimateIR)
|
||||
|
||||
CONF_USE_FAHRENHEIT = "use_fahrenheit"
|
||||
|
||||
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DaikinBrcClimate),
|
||||
cv.Optional(CONF_USE_FAHRENHEIT, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await climate_ir.register_climate_ir(var, config)
|
||||
cg.add(var.set_fahrenheit(config[CONF_USE_FAHRENHEIT]))
|
273
esphome/components/daikin_brc/daikin_brc.cpp
Normal file
273
esphome/components/daikin_brc/daikin_brc.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
#include "daikin_brc.h"
|
||||
#include "esphome/components/remote_base/remote_base.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace daikin_brc {
|
||||
|
||||
static const char *const TAG = "daikin_brc.climate";
|
||||
|
||||
void DaikinBrcClimate::control(const climate::ClimateCall &call) {
|
||||
this->mode_button_ = 0x00;
|
||||
if (call.get_mode().has_value()) {
|
||||
// Need to determine if this is call due to Mode button pressed so that we can set the Mode button byte
|
||||
this->mode_button_ = DAIKIN_BRC_IR_MODE_BUTTON;
|
||||
}
|
||||
ClimateIR::control(call);
|
||||
}
|
||||
|
||||
void DaikinBrcClimate::transmit_state() {
|
||||
uint8_t remote_state[DAIKIN_BRC_TRANSMIT_FRAME_SIZE] = {0x11, 0xDA, 0x17, 0x18, 0x04, 0x00, 0x1E, 0x11,
|
||||
0xDA, 0x17, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00};
|
||||
|
||||
remote_state[12] = this->alt_mode_();
|
||||
remote_state[13] = this->mode_button_;
|
||||
remote_state[14] = this->operation_mode_();
|
||||
remote_state[17] = this->temperature_();
|
||||
remote_state[18] = this->fan_speed_swing_();
|
||||
|
||||
// Calculate checksum
|
||||
for (int i = DAIKIN_BRC_PREAMBLE_SIZE; i < DAIKIN_BRC_TRANSMIT_FRAME_SIZE - 1; i++) {
|
||||
remote_state[DAIKIN_BRC_TRANSMIT_FRAME_SIZE - 1] += remote_state[i];
|
||||
}
|
||||
|
||||
auto transmit = this->transmitter_->transmit();
|
||||
auto *data = transmit.get_data();
|
||||
data->set_carrier_frequency(DAIKIN_BRC_IR_FREQUENCY);
|
||||
|
||||
data->mark(DAIKIN_BRC_HEADER_MARK);
|
||||
data->space(DAIKIN_BRC_HEADER_SPACE);
|
||||
for (int i = 0; i < DAIKIN_BRC_PREAMBLE_SIZE; i++) {
|
||||
for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask
|
||||
data->mark(DAIKIN_BRC_BIT_MARK);
|
||||
bool bit = remote_state[i] & mask;
|
||||
data->space(bit ? DAIKIN_BRC_ONE_SPACE : DAIKIN_BRC_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
data->mark(DAIKIN_BRC_BIT_MARK);
|
||||
data->space(DAIKIN_BRC_MESSAGE_SPACE);
|
||||
data->mark(DAIKIN_BRC_HEADER_MARK);
|
||||
data->space(DAIKIN_BRC_HEADER_SPACE);
|
||||
|
||||
for (int i = DAIKIN_BRC_PREAMBLE_SIZE; i < DAIKIN_BRC_TRANSMIT_FRAME_SIZE; i++) {
|
||||
for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask
|
||||
data->mark(DAIKIN_BRC_BIT_MARK);
|
||||
bool bit = remote_state[i] & mask;
|
||||
data->space(bit ? DAIKIN_BRC_ONE_SPACE : DAIKIN_BRC_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
data->mark(DAIKIN_BRC_BIT_MARK);
|
||||
data->space(0);
|
||||
|
||||
transmit.perform();
|
||||
}
|
||||
|
||||
uint8_t DaikinBrcClimate::alt_mode_() {
|
||||
uint8_t alt_mode = 0x00;
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_DRY:
|
||||
alt_mode = 0x23;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_FAN_ONLY:
|
||||
alt_mode = 0x63;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_HEAT_COOL:
|
||||
case climate::CLIMATE_MODE_COOL:
|
||||
case climate::CLIMATE_MODE_HEAT:
|
||||
default:
|
||||
alt_mode = 0x73;
|
||||
break;
|
||||
}
|
||||
return alt_mode;
|
||||
}
|
||||
|
||||
uint8_t DaikinBrcClimate::operation_mode_() {
|
||||
uint8_t operating_mode = DAIKIN_BRC_MODE_ON;
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_COOL:
|
||||
operating_mode |= DAIKIN_BRC_MODE_COOL;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_DRY:
|
||||
operating_mode |= DAIKIN_BRC_MODE_DRY;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_HEAT:
|
||||
operating_mode |= DAIKIN_BRC_MODE_HEAT;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_HEAT_COOL:
|
||||
operating_mode |= DAIKIN_BRC_MODE_AUTO;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_FAN_ONLY:
|
||||
operating_mode |= DAIKIN_BRC_MODE_FAN;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_OFF:
|
||||
default:
|
||||
operating_mode = DAIKIN_BRC_MODE_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
return operating_mode;
|
||||
}
|
||||
|
||||
uint8_t DaikinBrcClimate::fan_speed_swing_() {
|
||||
uint16_t fan_speed;
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_LOW:
|
||||
fan_speed = DAIKIN_BRC_FAN_1;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_MEDIUM:
|
||||
fan_speed = DAIKIN_BRC_FAN_2;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
fan_speed = DAIKIN_BRC_FAN_3;
|
||||
break;
|
||||
default:
|
||||
fan_speed = DAIKIN_BRC_FAN_1;
|
||||
}
|
||||
|
||||
// If swing is enabled switch first 4 bits to 1111
|
||||
switch (this->swing_mode) {
|
||||
case climate::CLIMATE_SWING_BOTH:
|
||||
fan_speed |= DAIKIN_BRC_IR_SWING_ON;
|
||||
break;
|
||||
default:
|
||||
fan_speed |= DAIKIN_BRC_IR_SWING_OFF;
|
||||
break;
|
||||
}
|
||||
return fan_speed;
|
||||
}
|
||||
|
||||
uint8_t DaikinBrcClimate::temperature_() {
|
||||
// Force special temperatures depending on the mode
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_FAN_ONLY:
|
||||
case climate::CLIMATE_MODE_DRY:
|
||||
if (this->fahrenheit_) {
|
||||
return DAIKIN_BRC_IR_DRY_FAN_TEMP_F;
|
||||
}
|
||||
return DAIKIN_BRC_IR_DRY_FAN_TEMP_C;
|
||||
case climate::CLIMATE_MODE_HEAT_COOL:
|
||||
default:
|
||||
uint8_t temperature;
|
||||
// Temperature in remote is in F
|
||||
if (this->fahrenheit_) {
|
||||
temperature = (uint8_t) roundf(
|
||||
clamp<float>(((this->target_temperature * 1.8) + 32), DAIKIN_BRC_TEMP_MIN_F, DAIKIN_BRC_TEMP_MAX_F));
|
||||
} else {
|
||||
temperature = ((uint8_t) roundf(this->target_temperature) - 9) << 1;
|
||||
}
|
||||
return temperature;
|
||||
}
|
||||
}
|
||||
|
||||
bool DaikinBrcClimate::parse_state_frame_(const uint8_t frame[]) {
|
||||
uint8_t checksum = 0;
|
||||
for (int i = 0; i < (DAIKIN_BRC_STATE_FRAME_SIZE - 1); i++) {
|
||||
checksum += frame[i];
|
||||
}
|
||||
if (frame[DAIKIN_BRC_STATE_FRAME_SIZE - 1] != checksum) {
|
||||
ESP_LOGCONFIG(TAG, "Bad CheckSum %x", checksum);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t mode = frame[7];
|
||||
if (mode & DAIKIN_BRC_MODE_ON) {
|
||||
switch (mode & 0xF0) {
|
||||
case DAIKIN_BRC_MODE_COOL:
|
||||
this->mode = climate::CLIMATE_MODE_COOL;
|
||||
break;
|
||||
case DAIKIN_BRC_MODE_DRY:
|
||||
this->mode = climate::CLIMATE_MODE_DRY;
|
||||
break;
|
||||
case DAIKIN_BRC_MODE_HEAT:
|
||||
this->mode = climate::CLIMATE_MODE_HEAT;
|
||||
break;
|
||||
case DAIKIN_BRC_MODE_AUTO:
|
||||
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
|
||||
break;
|
||||
case DAIKIN_BRC_MODE_FAN:
|
||||
this->mode = climate::CLIMATE_MODE_FAN_ONLY;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this->mode = climate::CLIMATE_MODE_OFF;
|
||||
}
|
||||
|
||||
uint8_t temperature = frame[10];
|
||||
float temperature_c;
|
||||
if (this->fahrenheit_) {
|
||||
temperature_c = clamp<float>(((temperature - 32) / 1.8), DAIKIN_BRC_TEMP_MIN_C, DAIKIN_BRC_TEMP_MAX_C);
|
||||
} else {
|
||||
temperature_c = (temperature >> 1) + 9;
|
||||
}
|
||||
|
||||
this->target_temperature = temperature_c;
|
||||
|
||||
uint8_t fan_mode = frame[11];
|
||||
uint8_t swing_mode = frame[11];
|
||||
switch (swing_mode & 0xF) {
|
||||
case DAIKIN_BRC_IR_SWING_ON:
|
||||
this->swing_mode = climate::CLIMATE_SWING_BOTH;
|
||||
break;
|
||||
case DAIKIN_BRC_IR_SWING_OFF:
|
||||
this->swing_mode = climate::CLIMATE_SWING_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (fan_mode & 0xF0) {
|
||||
case DAIKIN_BRC_FAN_1:
|
||||
this->fan_mode = climate::CLIMATE_FAN_LOW;
|
||||
break;
|
||||
case DAIKIN_BRC_FAN_2:
|
||||
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
|
||||
break;
|
||||
case DAIKIN_BRC_FAN_3:
|
||||
this->fan_mode = climate::CLIMATE_FAN_HIGH;
|
||||
break;
|
||||
}
|
||||
this->publish_state();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DaikinBrcClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
uint8_t state_frame[DAIKIN_BRC_STATE_FRAME_SIZE] = {};
|
||||
if (!data.expect_item(DAIKIN_BRC_HEADER_MARK, DAIKIN_BRC_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
for (uint8_t pos = 0; pos < DAIKIN_BRC_STATE_FRAME_SIZE; pos++) {
|
||||
uint8_t byte = 0;
|
||||
for (int8_t bit = 0; bit < 8; bit++) {
|
||||
if (data.expect_item(DAIKIN_BRC_BIT_MARK, DAIKIN_BRC_ONE_SPACE)) {
|
||||
byte |= 1 << bit;
|
||||
} else if (!data.expect_item(DAIKIN_BRC_BIT_MARK, DAIKIN_BRC_ZERO_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state_frame[pos] = byte;
|
||||
if (pos == 0) {
|
||||
// frame header
|
||||
if (byte != 0x11)
|
||||
return false;
|
||||
} else if (pos == 1) {
|
||||
// frame header
|
||||
if (byte != 0xDA)
|
||||
return false;
|
||||
} else if (pos == 2) {
|
||||
// frame header
|
||||
if (byte != 0x17)
|
||||
return false;
|
||||
} else if (pos == 3) {
|
||||
// frame header
|
||||
if (byte != 0x18)
|
||||
return false;
|
||||
} else if (pos == 4) {
|
||||
// frame type
|
||||
if (byte != 0x00)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this->parse_state_frame_(state_frame);
|
||||
}
|
||||
|
||||
} // namespace daikin_brc
|
||||
} // namespace esphome
|
82
esphome/components/daikin_brc/daikin_brc.h
Normal file
82
esphome/components/daikin_brc/daikin_brc.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/climate_ir/climate_ir.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace daikin_brc {
|
||||
|
||||
// Values for Daikin BRC4CXXX IR Controllers
|
||||
// Temperature
|
||||
const uint8_t DAIKIN_BRC_TEMP_MIN_F = 60; // fahrenheit
|
||||
const uint8_t DAIKIN_BRC_TEMP_MAX_F = 90; // fahrenheit
|
||||
const float DAIKIN_BRC_TEMP_MIN_C = (DAIKIN_BRC_TEMP_MIN_F - 32) / 1.8; // fahrenheit
|
||||
const float DAIKIN_BRC_TEMP_MAX_C = (DAIKIN_BRC_TEMP_MAX_F - 32) / 1.8; // fahrenheit
|
||||
|
||||
// Modes
|
||||
const uint8_t DAIKIN_BRC_MODE_AUTO = 0x30;
|
||||
const uint8_t DAIKIN_BRC_MODE_COOL = 0x20;
|
||||
const uint8_t DAIKIN_BRC_MODE_HEAT = 0x10;
|
||||
const uint8_t DAIKIN_BRC_MODE_DRY = 0x70;
|
||||
const uint8_t DAIKIN_BRC_MODE_FAN = 0x00;
|
||||
const uint8_t DAIKIN_BRC_MODE_OFF = 0x00;
|
||||
const uint8_t DAIKIN_BRC_MODE_ON = 0x01;
|
||||
|
||||
// Fan Speed
|
||||
const uint8_t DAIKIN_BRC_FAN_1 = 0x10;
|
||||
const uint8_t DAIKIN_BRC_FAN_2 = 0x30;
|
||||
const uint8_t DAIKIN_BRC_FAN_3 = 0x50;
|
||||
const uint8_t DAIKIN_BRC_FAN_AUTO = 0xA0;
|
||||
|
||||
// IR Transmission
|
||||
const uint32_t DAIKIN_BRC_IR_FREQUENCY = 38000;
|
||||
const uint32_t DAIKIN_BRC_HEADER_MARK = 5070;
|
||||
const uint32_t DAIKIN_BRC_HEADER_SPACE = 2140;
|
||||
const uint32_t DAIKIN_BRC_BIT_MARK = 370;
|
||||
const uint32_t DAIKIN_BRC_ONE_SPACE = 1780;
|
||||
const uint32_t DAIKIN_BRC_ZERO_SPACE = 710;
|
||||
const uint32_t DAIKIN_BRC_MESSAGE_SPACE = 29410;
|
||||
|
||||
const uint8_t DAIKIN_BRC_IR_DRY_FAN_TEMP_F = 72; // Dry/Fan mode is always 17 Celsius.
|
||||
const uint8_t DAIKIN_BRC_IR_DRY_FAN_TEMP_C = (17 - 9) * 2; // Dry/Fan mode is always 17 Celsius.
|
||||
const uint8_t DAIKIN_BRC_IR_SWING_ON = 0x5;
|
||||
const uint8_t DAIKIN_BRC_IR_SWING_OFF = 0x6;
|
||||
const uint8_t DAIKIN_BRC_IR_MODE_BUTTON = 0x4; // This is set after a mode action
|
||||
|
||||
// State Frame size
|
||||
const uint8_t DAIKIN_BRC_STATE_FRAME_SIZE = 15;
|
||||
// Preamble size
|
||||
const uint8_t DAIKIN_BRC_PREAMBLE_SIZE = 7;
|
||||
// Transmit Frame size - includes a preamble
|
||||
const uint8_t DAIKIN_BRC_TRANSMIT_FRAME_SIZE = DAIKIN_BRC_PREAMBLE_SIZE + DAIKIN_BRC_STATE_FRAME_SIZE;
|
||||
|
||||
class DaikinBrcClimate : public climate_ir::ClimateIR {
|
||||
public:
|
||||
DaikinBrcClimate()
|
||||
: climate_ir::ClimateIR(DAIKIN_BRC_TEMP_MIN_C, DAIKIN_BRC_TEMP_MAX_C, 0.5f, true, true,
|
||||
{climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH},
|
||||
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH}) {}
|
||||
|
||||
/// Set use of Fahrenheit units
|
||||
void set_fahrenheit(bool value) {
|
||||
this->fahrenheit_ = value;
|
||||
this->temperature_step_ = value ? 0.5f : 1.0f;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t mode_button_ = 0x00;
|
||||
// Capture if the MODE was changed
|
||||
void control(const climate::ClimateCall &call) override;
|
||||
// Transmit via IR the state of this climate controller.
|
||||
void transmit_state() override;
|
||||
uint8_t alt_mode_();
|
||||
uint8_t operation_mode_();
|
||||
uint8_t fan_speed_swing_();
|
||||
uint8_t temperature_();
|
||||
// Handle received IR Buffer
|
||||
bool on_receive(remote_base::RemoteReceiveData data) override;
|
||||
bool parse_state_frame_(const uint8_t frame[]);
|
||||
bool fahrenheit_{false};
|
||||
};
|
||||
|
||||
} // namespace daikin_brc
|
||||
} // namespace esphome
|
@@ -4,6 +4,8 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esp_one_wire.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace dallas {
|
||||
|
||||
|
@@ -85,9 +85,7 @@ bool HOT IRAM_ATTR ESPOneWire::read_bit() {
|
||||
// whereas on esp-idf it already happens during the pin_mode(OUTPUT)
|
||||
// manually correct for this with these constants.
|
||||
|
||||
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
|
||||
uint32_t timing_constant = 14;
|
||||
#elif defined(USE_ESP32_FRAMEWORK_ESP_IDF)
|
||||
#ifdef USE_ESP32
|
||||
uint32_t timing_constant = 12;
|
||||
#else
|
||||
uint32_t timing_constant = 14;
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace daly_bms {
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
from pathlib import Path
|
||||
import requests
|
||||
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
@@ -6,6 +7,7 @@ from esphome.components.packages import validate_source_shorthand
|
||||
from esphome.const import CONF_WIFI
|
||||
from esphome.wizard import wizard_file
|
||||
from esphome.yaml_util import dump
|
||||
from esphome import git
|
||||
|
||||
|
||||
dashboard_import_ns = cg.esphome_ns.namespace("dashboard_import")
|
||||
@@ -25,9 +27,12 @@ def validate_import_url(value):
|
||||
|
||||
|
||||
CONF_PACKAGE_IMPORT_URL = "package_import_url"
|
||||
CONF_IMPORT_FULL_CONFIG = "import_full_config"
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_PACKAGE_IMPORT_URL): validate_import_url,
|
||||
cv.Optional(CONF_IMPORT_FULL_CONFIG, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -41,6 +46,9 @@ wifi:
|
||||
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_DASHBOARD_IMPORT")
|
||||
url = config[CONF_PACKAGE_IMPORT_URL]
|
||||
if config[CONF_IMPORT_FULL_CONFIG]:
|
||||
url += "?full_config"
|
||||
cg.add(dashboard_import_ns.set_package_import_url(config[CONF_PACKAGE_IMPORT_URL]))
|
||||
|
||||
|
||||
@@ -64,17 +72,30 @@ def import_config(
|
||||
encoding="utf8",
|
||||
)
|
||||
else:
|
||||
config = {
|
||||
"substitutions": {"name": name},
|
||||
"packages": {project_name: import_url},
|
||||
"esphome": {
|
||||
"name": "${name}",
|
||||
"name_add_mac_suffix": False,
|
||||
},
|
||||
}
|
||||
output = dump(config)
|
||||
git_file = git.GitFile.from_shorthand(import_url)
|
||||
|
||||
if network == CONF_WIFI:
|
||||
output += WIFI_CONFIG
|
||||
if git_file.query and "full_config" in git_file.query:
|
||||
url = git_file.raw_url
|
||||
try:
|
||||
req = requests.get(url, timeout=30)
|
||||
req.raise_for_status()
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise ValueError(f"Error while fetching {url}: {e}") from e
|
||||
|
||||
p.write_text(output, encoding="utf8")
|
||||
p.write_text(req.text, encoding="utf8")
|
||||
|
||||
else:
|
||||
config = {
|
||||
"substitutions": {"name": name},
|
||||
"packages": {project_name: import_url},
|
||||
"esphome": {
|
||||
"name": "${name}",
|
||||
"name_add_mac_suffix": False,
|
||||
},
|
||||
}
|
||||
output = dump(config)
|
||||
|
||||
if network == CONF_WIFI:
|
||||
output += WIFI_CONFIG
|
||||
|
||||
p.write_text(output, encoding="utf8")
|
||||
|
@@ -1,11 +1,15 @@
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
import esphome.final_validate as fv
|
||||
from esphome.components import logger
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_DEVICE,
|
||||
CONF_FREE,
|
||||
CONF_FRAGMENTATION,
|
||||
CONF_BLOCK,
|
||||
CONF_DEVICE,
|
||||
CONF_FRAGMENTATION,
|
||||
CONF_FREE,
|
||||
CONF_ID,
|
||||
CONF_LEVEL,
|
||||
CONF_LOGGER,
|
||||
CONF_LOOP_TIME,
|
||||
)
|
||||
|
||||
@@ -39,6 +43,18 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
).extend(cv.polling_component_schema("60s"))
|
||||
|
||||
|
||||
def _final_validate(_):
|
||||
logger_conf = fv.full_config.get()[CONF_LOGGER]
|
||||
severity = logger.LOG_LEVEL_SEVERITY.index(logger_conf[CONF_LEVEL])
|
||||
if severity < logger.LOG_LEVEL_SEVERITY.index("DEBUG"):
|
||||
raise cv.Invalid(
|
||||
"The debug component requires the logger to be at least at DEBUG level"
|
||||
)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
|
@@ -38,14 +38,9 @@ static uint32_t get_free_heap() {
|
||||
|
||||
void DebugComponent::dump_config() {
|
||||
std::string device_info;
|
||||
std::string reset_reason;
|
||||
device_info.reserve(256);
|
||||
|
||||
#ifndef ESPHOME_LOG_HAS_DEBUG
|
||||
ESP_LOGE(TAG, "Debug Component requires debug log level!");
|
||||
this->status_set_error();
|
||||
return;
|
||||
#endif
|
||||
|
||||
ESP_LOGCONFIG(TAG, "Debug component:");
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
LOG_TEXT_SENSOR(" ", "Device info", this->device_info_);
|
||||
@@ -146,7 +141,6 @@ void DebugComponent::dump_config() {
|
||||
device_info += "|EFuse MAC: ";
|
||||
device_info += mac;
|
||||
|
||||
const char *reset_reason;
|
||||
switch (rtc_get_reset_reason(0)) {
|
||||
case POWERON_RESET:
|
||||
reset_reason = "Power On Reset";
|
||||
@@ -196,7 +190,7 @@ void DebugComponent::dump_config() {
|
||||
default:
|
||||
reset_reason = "Unknown Reset Reason";
|
||||
}
|
||||
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason);
|
||||
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
|
||||
device_info += "|Reset: ";
|
||||
device_info += reset_reason;
|
||||
|
||||
@@ -270,6 +264,8 @@ void DebugComponent::dump_config() {
|
||||
device_info += ESP.getResetReason().c_str();
|
||||
device_info += "|";
|
||||
device_info += ESP.getResetInfo().c_str();
|
||||
|
||||
reset_reason = ESP.getResetReason().c_str();
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
@@ -278,6 +274,9 @@ void DebugComponent::dump_config() {
|
||||
device_info.resize(255);
|
||||
this->device_info_->publish_state(device_info);
|
||||
}
|
||||
if (this->reset_reason_ != nullptr) {
|
||||
this->reset_reason_->publish_state(reset_reason);
|
||||
}
|
||||
#endif // USE_TEXT_SENSOR
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ class DebugComponent : public PollingComponent {
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
void set_device_info_sensor(text_sensor::TextSensor *device_info) { device_info_ = device_info; }
|
||||
void set_reset_reason_sensor(text_sensor::TextSensor *reset_reason) { reset_reason_ = reset_reason; }
|
||||
#endif // USE_TEXT_SENSOR
|
||||
#ifdef USE_SENSOR
|
||||
void set_free_sensor(sensor::Sensor *free_sensor) { free_sensor_ = free_sensor; }
|
||||
@@ -50,6 +51,7 @@ class DebugComponent : public PollingComponent {
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
text_sensor::TextSensor *device_info_{nullptr};
|
||||
text_sensor::TextSensor *reset_reason_{nullptr};
|
||||
#endif // USE_TEXT_SENSOR
|
||||
};
|
||||
|
||||
|
@@ -1,18 +1,29 @@
|
||||
from esphome.components import text_sensor
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_DEVICE, ENTITY_CATEGORY_DIAGNOSTIC
|
||||
from esphome.const import (
|
||||
CONF_DEVICE,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
ICON_CHIP,
|
||||
ICON_RESTART,
|
||||
)
|
||||
|
||||
from . import CONF_DEBUG_ID, DebugComponent
|
||||
|
||||
DEPENDENCIES = ["debug"]
|
||||
|
||||
|
||||
CONF_RESET_REASON = "reset_reason"
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent),
|
||||
cv.Optional(CONF_DEVICE): text_sensor.text_sensor_schema(
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||
icon=ICON_CHIP,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
),
|
||||
cv.Optional(CONF_RESET_REASON): text_sensor.text_sensor_schema(
|
||||
icon=ICON_RESTART,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
),
|
||||
}
|
||||
)
|
||||
@@ -24,3 +35,6 @@ async def to_code(config):
|
||||
if CONF_DEVICE in config:
|
||||
sens = await text_sensor.new_text_sensor(config[CONF_DEVICE])
|
||||
cg.add(debug_component.set_device_info_sensor(sens))
|
||||
if CONF_RESET_REASON in config:
|
||||
sens = await text_sensor.new_text_sensor(config[CONF_RESET_REASON])
|
||||
cg.add(debug_component.set_reset_reason_sensor(sens))
|
||||
|
@@ -114,9 +114,9 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Beginning Deep Sleep");
|
||||
if (this->sleep_duration_.has_value())
|
||||
if (this->sleep_duration_.has_value()) {
|
||||
ESP_LOGI(TAG, "Sleeping for %" PRId64 "us", *this->sleep_duration_);
|
||||
|
||||
}
|
||||
App.run_safe_shutdown_hooks();
|
||||
|
||||
#if defined(USE_ESP32)
|
||||
@@ -147,7 +147,7 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
||||
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
|
||||
level = !level;
|
||||
}
|
||||
esp_deep_sleep_enable_gpio_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()),
|
||||
esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
|
||||
static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
|
||||
}
|
||||
#endif
|
||||
|
@@ -77,14 +77,16 @@ void DFPlayer::loop() {
|
||||
case 0x3A:
|
||||
if (argument == 1) {
|
||||
ESP_LOGI(TAG, "USB loaded");
|
||||
} else if (argument == 2)
|
||||
} else if (argument == 2) {
|
||||
ESP_LOGI(TAG, "TF Card loaded");
|
||||
}
|
||||
break;
|
||||
case 0x3B:
|
||||
if (argument == 1) {
|
||||
ESP_LOGI(TAG, "USB unloaded");
|
||||
} else if (argument == 2)
|
||||
} else if (argument == 2) {
|
||||
ESP_LOGI(TAG, "TF Card unloaded");
|
||||
}
|
||||
break;
|
||||
case 0x3F:
|
||||
if (argument == 1) {
|
||||
|
@@ -4,7 +4,9 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "display_color_utils.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user