Compare commits

..

109 Commits

Author SHA1 Message Date
Jesse Hills
7fa4a68a27 Merge pull request #2704 from esphome/bump-2021.11.0b3
2021.11.0b3
2021-11-12 17:21:58 +13:00
Jesse Hills
f1c5e2ef81 Bump version to 2021.11.0b3 2021-11-12 16:12:31 +13:00
lcavalli
b526155cce Update device classes for binary sensors (#2703) 2021-11-12 16:12:31 +13:00
Jesse Hills
62c3f301e7 Only allow prometheus when using arduino (#2697) 2021-11-12 16:12:31 +13:00
Jesse Hills
38cb988809 Remove my.ha links from improv (#2695) 2021-11-12 16:12:31 +13:00
Jesse Hills
b976ac54c8 Merge pull request #2693 from esphome/bump-2021.11.0b2
2021.11.0b2
2021-11-11 12:52:35 +13:00
Jesse Hills
78026e766f Bump version to 2021.11.0b2 2021-11-11 12:25:41 +13:00
Oxan van Leeuwen
b4cd8d21a5 Enable addressable light power supply based on raw values (#2690) 2021-11-11 12:25:41 +13:00
Maurice Makaay
7552893311 Uart debugging support (#2478)
Co-authored-by: Maurice Makaay <mmakaay1@xs4all.net>
Co-authored-by: Maurice Makaay <account-github@makaay.nl>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2021-11-11 12:25:41 +13:00
Carlos Garcia Saura
21c896d8f8 [remote_transmitter] accurate pulse timing for ESP8266 (#2476) 2021-11-11 12:25:40 +13:00
Jesse Hills
4b7fe202ec Fix template number initial value being NaN (#2692) 2021-11-11 12:25:40 +13:00
Jesse Hills
9f4519210f Merge pull request #2691 from esphome/bump-2021.11.0b1
2021.11.0b1
2021-11-11 11:05:45 +13:00
Jesse Hills
b0506afa5b Merge branch 'beta' into bump-2021.11.0b1 2021-11-11 10:48:23 +13:00
Jesse Hills
8cbb379898 Remove import (not sure how it got there) 2021-11-11 10:35:18 +13:00
Jesse Hills
b226215593 Bump version to 2021.11.0b1 2021-11-11 10:10:05 +13:00
Jesse Hills
19970729a9 Merge branch 'dev' into bump-2021.11.0b1 2021-11-11 10:10:04 +13:00
Jesse Hills
d2ebfd2833 Merge pull request #2634 from esphome/bump-2021.10.3
2021.10.3
2021-10-27 11:21:08 +13:00
Jesse Hills
bd782fc828 Bump version to 2021.10.3 2021-10-27 10:49:11 +13:00
Jesse Hills
23560e608c Fix select.set using lambda (#2633) 2021-10-27 10:49:10 +13:00
Jan Čermák
f1377b560e Fix pin number validation for sn74hc595 (#2621) 2021-10-27 10:49:10 +13:00
Martin
72108684ea fix modbus output (#2630) 2021-10-27 10:49:10 +13:00
Jesse Hills
c6adaaea97 Remove power and energy from sensors that are not true power (#2628) 2021-10-27 10:49:10 +13:00
Otto Winter
91999a38ca Fix glue code missing micros() (#2623) 2021-10-27 10:49:10 +13:00
0hax
b34eed125d Teleinfo ptec (#2599)
* teleinfo: handle historical mode correctly.

In historical mode, tags like PTEC leads to an issue where we detect a
timestamp wheras this is not possible in historical mode.

PTEC teleinfo tag looks like:
    PTEC HP..
Instead of the usual format
    IINST1 001 I

This make our data parsing fails.

While at here, make sure we continue parsing other tags even if parsing
one of the tag fails.

Signed-off-by: 0hax <0hax@protonmail.com>

* teleinfo: fix compilation with loglevel set to debug.

Signed-off-by: 0hax <0hax@protonmail.com>
2021-10-27 10:49:10 +13:00
Stefan Agner
2abe09529a Autodetect flash size (#2615) 2021-10-27 10:49:10 +13:00
Otto Winter
9aaaf4dd4b Bump platform-espressif8266 from 2.6.2 to 2.6.3 (#2620) 2021-10-27 10:49:09 +13:00
Andreas Hergert
cbfbcf7f1b fixed dependency for pca9685 component (#2614)
Co-authored-by: Otto Winter <otto@otto-winter.com>
Co-authored-by: Andreas <andreas.hergert@otrs.com>
2021-10-27 10:49:09 +13:00
Otto Winter
c7651dc40d Merge pull request #2613 from esphome/bump-2021.10.2
2021.10.2
2021-10-22 18:35:28 +02:00
Otto winter
eda1c471ad Bump version to 2021.10.2 2021-10-22 18:26:24 +02:00
Andreas Hergert
c7ef18fbc4 Bugfix tca9548a and idf refactor anh (#2612)
Co-authored-by: Andreas Hergert <andreas.hergert@otrs.com>
2021-10-22 18:26:23 +02:00
Otto Winter
901ec918b1 Fix ESP8266 OTA compression only starting framework v2.7.0 (#2610) 2021-10-22 18:26:23 +02:00
Otto Winter
6bdae55ee1 Fix compiler warnings and update platformio line filter (#2607) 2021-10-22 18:26:23 +02:00
Otto Winter
dfb96e4b7f Add owner to all libraries used (#2604) 2021-10-22 18:26:22 +02:00
Otto Winter
ff2c316b18 Re-raise keyboardinterrupt (#2603) 2021-10-22 18:26:22 +02:00
Otto Winter
5be52f71f9 Add OTA upload compression for ESP8266 (#2601) 2021-10-22 18:26:22 +02:00
Otto Winter
42873dd37c Bump noise-c from 0.1.3 to 0.1.4 (#2602) 2021-10-22 18:26:21 +02:00
Otto Winter
f93e7d4e3a Fix socket connection closed not detected (#2587) 2021-10-22 18:26:21 +02:00
Oxan van Leeuwen
bbcd523967 Fix validation of addressable light IDs (#2588) 2021-10-22 18:26:21 +02:00
dependabot[bot]
68cbe58d00 Bump esphome-dashboard from 20211021.0 to 20211021.1 (#2594)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-22 18:26:12 +02:00
Oxan van Leeuwen
115bca98f1 Fix old-style arduino_version on ESP8266 and with magic values (#2591) 2021-10-22 18:24:48 +02:00
Oxan van Leeuwen
ed0b34b2fe Fix pin/component switchup in SX1509 pin configuration (#2593) 2021-10-22 18:24:48 +02:00
Oxan van Leeuwen
ab34401421 Fix PlatformIO version for latest Arduino framework (#2590) 2021-10-22 18:24:48 +02:00
Otto Winter
eed0c18d65 Fix HeatpumpIR pin (#2585) 2021-10-22 18:24:47 +02:00
Otto Winter
e5a38ce748 Merge pull request #2580 from esphome/bump-2021.10.1
2021.10.1
2021-10-21 15:31:26 +02:00
Otto Winter
7d9d9fcf36 Fix platformio_install_deps no longer installing all lib_deps (#2584) 2021-10-21 15:29:53 +02:00
Otto Winter
f0aba6ceb2 Fix platformio version in Dockerfile doesn't match requirements (#2582) 2021-10-21 14:53:22 +02:00
Otto Winter
ab07ee57c6 Fix ESP8266 dallas GPIO16 INPUT_PULLUP (#2581) 2021-10-21 14:39:55 +02:00
Otto winter
eae3d72a4d Bump version to 2021.10.1 2021-10-21 14:23:08 +02:00
Otto Winter
7b8d826704 Fix ESP8266 OTA adds unnecessary Update library (#2579) 2021-10-21 14:23:07 +02:00
Otto Winter
e7baa42e63 Arduino global delay/millis/... symbols workaround (#2575) 2021-10-21 14:23:07 +02:00
Otto Winter
2f32833a22 Fix wifi ble coexistence check (#2573) 2021-10-21 14:23:07 +02:00
Otto Winter
f6935a4b4b Fix ESP8266 GPIO0 Pullup Validation (#2572) 2021-10-21 14:23:06 +02:00
Maurice Makaay
332c9e891b Fix MDNS for ESP8266 devices (#2571)
Co-authored-by: Maurice Makaay <account-github@makaay.nl>
Co-authored-by: Otto winter <otto@otto-winter.com>
Co-authored-by: Maurice Makaay <mmakaay1@xs4all.net>
2021-10-21 14:23:06 +02:00
Jesse Hills
b91ee4847f Merge pull request #2570 from esphome/bump-2021.10.0
2021.10.0
2021-10-21 08:37:26 +13:00
Jesse Hills
625463d871 Bump version to 2021.10.0 2021-10-21 07:57:10 +13:00
Jesse Hills
6433a01e07 Merge pull request #2567 from esphome/bump-2021.10.0b11
2021.10.0b11
2021-10-21 07:47:22 +13:00
Jesse Hills
56cc31e8e7 Bump version to 2021.10.0b11 2021-10-21 07:32:27 +13:00
Otto Winter
3af297aa76 Revert nextion clang-tidy changes (#2566) 2021-10-21 07:32:27 +13:00
Otto Winter
996ec59d28 Move running process log line to debug level (#2565) 2021-10-21 07:32:26 +13:00
Jesse Hills
95593eeeab Bump esphome-dashboard to 20211021.0 (#2564) 2021-10-21 07:32:20 +13:00
Jesse Hills
dad244fb7a A few esp32_ble_server/improv fixes (#2562) 2021-10-21 07:31:55 +13:00
Jesse Hills
adb5d27d95 Merge pull request #2561 from esphome/bump-2021.10.0b10
2021.10.0b10
2021-10-20 17:28:37 +13:00
Jesse Hills
8456a8cecb Bump version to 2021.10.0b10 2021-10-20 16:39:24 +13:00
Jesse Hills
b9f66373c1 Bump esphome-dashboard to 20211020.1 (#2559) 2021-10-20 16:39:16 +13:00
Jesse Hills
9ac365feef Fix HA addon so it does not have logout button (#2558) 2021-10-20 16:38:46 +13:00
Jesse Hills
43bbd58a44 Merge pull request #2557 from esphome/bump-2021.10.0b9
2021.10.0b9
2021-10-20 11:18:40 +13:00
Jesse Hills
7feffa64f3 Bump version to 2021.10.0b9 2021-10-20 11:00:02 +13:00
Jesse Hills
ea0977abb4 Bump dashboard to 20211020.0 (#2556) 2021-10-20 10:59:53 +13:00
Jesse Hills
4c83dc7c28 Merge pull request #2555 from esphome/bump-2021.10.0b8
2021.10.0b8
2021-10-20 10:30:59 +13:00
Jesse Hills
e10ab1da78 Bump version to 2021.10.0b8 2021-10-20 10:14:30 +13:00
Martin
1b0e60374b ignore exception when not waiting for a response (#2552) 2021-10-20 10:14:30 +13:00
Oxan van Leeuwen
3a760fbb44 Fix ADC pin validation on ESP32-C3 (#2551) 2021-10-20 10:14:30 +13:00
Jesse Hills
6ef57a2973 Merge pull request #2550 from esphome/bump-2021.10.0b7
2021.10.0b7
2021-10-19 16:22:29 +13:00
Jesse Hills
3e9c7f2e9f Bump version to 2021.10.0b7 2021-10-19 15:47:31 +13:00
Jesse Hills
430598b7a1 Bump dashboard to 20211019.0 (#2549) 2021-10-19 15:47:26 +13:00
Jesse Hills
91611b09b4 Merge pull request #2545 from esphome/bump-2021.10.0b6
2021.10.0b6
2021-10-18 21:41:22 +13:00
Jesse Hills
ecd115851f Bump version to 2021.10.0b6 2021-10-18 21:26:36 +13:00
Maurice Makaay
4a1e50fed1 OTA firmware MD5 check + password support for esp-idf (#2507)
Co-authored-by: Maurice Makaay <account-github@makaay.nl>
2021-10-18 21:26:36 +13:00
Jesse Hills
d6d037047b Merge pull request #2544 from esphome/bump-2021.10.0b5
2021.10.0b5
2021-10-18 16:37:43 +13:00
Jesse Hills
b5734c2b20 Bump version to 2021.10.0b5 2021-10-18 15:31:01 +13:00
Oxan van Leeuwen
723fb7eaac Autodetect ESP32 variant (#2530)
Co-authored-by: Otto winter <otto@otto-winter.com>
2021-10-18 15:31:01 +13:00
Jesse Hills
63a9acaa19 Fix Bluetooth setup_priorities (#2458)
Co-authored-by: Otto Winter <otto@otto-winter.com>
2021-10-18 15:31:00 +13:00
Jesse Hills
0524f8c677 Fix const used for IDF recommended version (#2542) 2021-10-18 15:31:00 +13:00
Otto Winter
70b62f272e Only show timestamp for dashboard access logs (#2540) 2021-10-18 15:31:00 +13:00
Jesse Hills
f0089b7940 Merge pull request #2539 from esphome/bump-2021.10.0b4
2021.10.0b4
2021-10-17 21:17:54 +13:00
Jesse Hills
4b44280d53 Bump version to 2021.10.0b4 2021-10-17 20:34:07 +13:00
Paulus Schoutsen
f045382d20 Bump dashboard to 20211015.0 (#2525)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2021-10-17 20:34:03 +13:00
Jesse Hills
db3fa1ade7 Allow downloading all bin files from backend in dashboard (#2514)
Co-authored-by: Otto Winter <otto@otto-winter.com>
2021-10-17 20:28:43 +13:00
Oxan van Leeuwen
f83950fd75 Fix bitshift on read in ADE7953 (#2537) 2021-10-17 20:28:43 +13:00
Oxan van Leeuwen
4dd1bf920d Replace framework version_hint with source option (#2529) 2021-10-17 20:28:43 +13:00
Martin
98755f3621 Fix bug in register name definition (#2526) 2021-10-17 20:28:43 +13:00
Keith Burzinski
c3a8a044b9 Fix Nextion HTTPClient error for ESP32 (#2524) 2021-10-17 20:28:42 +13:00
Martin
15b5ea43a7 Add pressure compensation during runtime (#2493)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
2021-10-17 20:28:42 +13:00
Jesse Hills
ec683fc227 Merge pull request #2523 from esphome/bump-2021.10.0b3
2021.10.0b3
2021-10-15 10:15:26 +13:00
Jesse Hills
d4e65eb82a Bump version to 2021.10.0b3 2021-10-15 09:42:44 +13:00
Paul Monigatti
10c6601b0a Revert "Added test for bme680_bsec" (#2518)
This reverts commit 7f6a50d291b14935b17802b4dce52135fad1e49e due to BSEC library license restrictions.
2021-10-15 09:42:44 +13:00
Oxan van Leeuwen
73940bc1bd Don't define UART_SELECTION_UART2 when UART2 is unavailable (#2512) 2021-10-15 09:42:43 +13:00
Paul Monigatti
9b7fb829f9 Fix: Color modes not being correctly used in light partitions (#2513) 2021-10-15 09:42:43 +13:00
Dmitriy Lopatko
c51d8c9021 add missing include in sgp30 (#2517) 2021-10-15 09:42:43 +13:00
Paul Monigatti
d8a6dfe5ce Fix BME680_BSEC compilation issue with ESP32 (#2516) 2021-10-15 09:42:43 +13:00
Oxan van Leeuwen
5f7cef0b06 Disallow using UART2 for logger on ESP-32 variants that lack it (#2510) 2021-10-15 09:42:43 +13:00
Paul Monigatti
48ff2ffc68 Fix: Light flash not restoring previous LightState (#2383)
* Update light state when transformer has finished

* Revert writing direct to output

* Correct handling of zero-length light transformers

* Allow transformers to handle zero-length transitions, and check more boundary conditions when transitioning back to start state

* Removed log.h

* Fixed race condition between LightFlashTransformer.apply() and is_finished()

* clang-format

* Step progress from 0.0f to 1.0f at t=start_time for zero-length transforms to avoid divide-by-zero
2021-10-15 09:42:43 +13:00
Oxan van Leeuwen
b3b9ccd314 Fix light state remaining on after turn off with transition (#2509) 2021-10-15 09:42:43 +13:00
Jesse Hills
e63c7b483b Merge pull request #2505 from esphome/bump-2021.10.0b2
2021.10.0b2
2021-10-13 22:45:29 +13:00
Jesse Hills
f57980b069 Bump version to 2021.10.0b2 2021-10-13 22:30:29 +13:00
Jesse Hills
7006aa0d2a Merge branch 'dev' into beta 2021-10-13 22:11:53 +13:00
Jesse Hills
8051c1ca99 Merge pull request #2504 from esphome/bump-2021.10.0b1
2021.10.0b1
2021-10-13 21:38:41 +13:00
Jesse Hills
a779592414 Bump version to 2021.10.0b1 2021-10-13 16:40:46 +13:00
Jesse Hills
112215848d Merge branch 'dev' into bump-2021.10.0b1 2021-10-13 16:40:46 +13:00
480 changed files with 2971 additions and 10598 deletions

View File

@@ -5,8 +5,11 @@ Checks: >-
-altera-*,
-android-*,
-boost-*,
-bugprone-branch-clone,
-bugprone-easily-swappable-parameters,
-bugprone-narrowing-conversions,
-bugprone-signed-char-misuse,
-bugprone-too-small-loop-variable,
-cert-dcl50-cpp,
-cert-err58-cpp,
-cert-oop57-cpp,
@@ -16,10 +19,12 @@ Checks: >-
-clang-diagnostic-delete-abstract-non-virtual-dtor,
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
-clang-diagnostic-shadow-field,
-clang-diagnostic-sign-compare,
-clang-diagnostic-unused-variable,
-clang-diagnostic-unused-const-variable,
-clang-diagnostic-unused-parameter,
-concurrency-*,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-init-variables,
-cppcoreguidelines-macro-usage,
@@ -36,6 +41,7 @@ Checks: >-
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-special-member-functions,
-fuchsia-default-arguments,
-fuchsia-multiple-inheritance,
-fuchsia-overloaded-operator,
-fuchsia-statically-constructed-objects,
@@ -45,7 +51,6 @@ Checks: >-
-google-explicit-constructor,
-google-readability-braces-around-statements,
-google-readability-casting,
-google-readability-namespace-comments,
-google-readability-todo,
-google-runtime-references,
-hicpp-*,
@@ -92,11 +97,9 @@ CheckOptions:
value: '1'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-runtime-int.TypeSuffix
value: '_t'
- key: llvm-namespace-comment.ShortNamespaceLines
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: llvm-namespace-comment.SpacesBeforeComments
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: modernize-loop-convert.MaxCopySize
value: '16'

View File

@@ -1,3 +1,5 @@
# THESE JOBS ARE COPIED IN release.yml and release-dev.yml
# PLEASE ALSO UPDATE THOSE FILES WHEN CHANGING LINES HERE
name: CI
on:
@@ -9,10 +11,6 @@ on:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
ci:
name: ${{ matrix.name }}
@@ -36,7 +34,7 @@ jobs:
- id: test
file: tests/test3.yaml
name: Test tests/test3.yaml
pio_cache_key: test3
pio_cache_key: test1
- id: test
file: tests/test4.yaml
name: Test tests/test4.yaml
@@ -51,26 +49,26 @@ jobs:
name: Run script/clang-format
- id: clang-tidy
name: Run script/clang-tidy for ESP8266
options: --environment esp8266-arduino-tidy --grep USE_ESP8266
options: --environment esp8266-tidy --grep USE_ESP8266
pio_cache_key: tidyesp8266
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 1/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 1
name: Run script/clang-tidy for ESP32 1/4
options: --environment esp32-tidy --split-num 4 --split-at 1
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 2/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 2
name: Run script/clang-tidy for ESP32 2/4
options: --environment esp32-tidy --split-num 4 --split-at 2
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 3/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 3
name: Run script/clang-tidy for ESP32 3/4
options: --environment esp32-tidy --split-num 4 --split-at 3
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 4/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 4
name: Run script/clang-tidy for ESP32 4/4
options: --environment esp32-tidy --split-num 4 --split-at 4
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF
name: Run script/clang-tidy for ESP32 esp-idf
options: --environment esp32-idf-tidy --grep USE_ESP_IDF
pio_cache_key: tidyesp32-idf
@@ -82,23 +80,18 @@ jobs:
with:
python-version: '3.7'
- name: Cache virtualenv
- name: Cache pip modules
uses: actions/cache@v2
with:
path: .venv
key: venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements*.txt') }}
path: ~/.cache/pip
key: pip-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements*.txt') }}
restore-keys: |
venv-${{ steps.python.outputs.python-version }}-
pip-${{ steps.python.outputs.python-version }}-
- name: Set up virtualenv
- name: Set up python environment
run: |
python -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
pip install -e .
echo "$GITHUB_WORKSPACE/.venv/bin" >> $GITHUB_PATH
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> $GITHUB_ENV
pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
pip3 install -e .
# Use per check platformio cache because checks use different parts
- name: Cache platformio

View File

@@ -4,7 +4,7 @@
"owner": "ci-custom",
"pattern": [
{
"regexp": "^(.*):(\\d+):(\\d+):\\s+lint:\\s+(.*)$",
"regexp": "^ERROR (.*):(\\d+):(\\d+) - (.*)$",
"file": 1,
"line": 2,
"column": 3,

View File

@@ -5,7 +5,7 @@
"severity": "error",
"pattern": [
{
"regexp": "^src/(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"regexp": "^(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,

View File

@@ -1,22 +1,11 @@
{
"problemMatcher": [
{
"owner": "black",
"severity": "error",
"pattern": [
{
"regexp": "^(.*): (Please format this file with the black formatter)",
"file": 1,
"message": 2
}
]
},
{
"owner": "flake8",
"severity": "error",
"pattern": [
{
"regexp": "^(.*):(\\d+): ([EFCDNW]\\d{3}.*)$",
"regexp": "^(.*):(\\d+) - ([EFCDNW]\\d{3}.*)$",
"file": 1,
"line": 2,
"message": 3
@@ -28,7 +17,7 @@
"severity": "error",
"pattern": [
{
"regexp": "^(.*):(\\d+): (\\[[EFCRW]\\d{4}\\(.*\\),.*\\].*)$",
"regexp": "^(.*):(\\d+) - (\\[[EFCRW]\\d{4}\\(.*\\),.*\\].*)$",
"file": 1,
"line": 2,
"message": 3

View File

@@ -3,4 +3,4 @@ ports:
onOpen: open-preview
tasks:
- before: pyenv local $(pyenv version | grep '^3\.' | cut -d ' ' -f 1) && script/setup
command: python -m esphome dashboard config
command: python -m esphome config dashboard

View File

@@ -28,16 +28,12 @@ esphome/components/b_parasite/* @rbaron
esphome/components/ballu/* @bazuchan
esphome/components/bang_bang/* @OttoWinter
esphome/components/binary_sensor/* @esphome/core
esphome/components/bl0940/* @tobias-
esphome/components/ble_client/* @buxtronix
esphome/components/bme680_bsec/* @trvrnrth
esphome/components/bmp3xx/* @martgras
esphome/components/button/* @esphome/core
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @MrEditor97
esphome/components/captive_portal/* @OttoWinter
esphome/components/ccs811/* @habbie
esphome/components/cd74hc4067/* @asoehlke
esphome/components/climate/* @esphome/core
esphome/components/climate_ir/* @glmnet
esphome/components/color_temperature/* @jesserockz
@@ -56,10 +52,8 @@ esphome/components/ds1307/* @badbadc0ffee
esphome/components/dsmr/* @glmnet @zuidwijk
esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @jesserockz
esphome/components/esp32_ble_controller/* @jesserockz
esphome/components/esp32_ble_server/* @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp8266/* @esphome/core
esphome/components/exposure_notifications/* @OttoWinter
@@ -70,7 +64,6 @@ esphome/components/globals/* @esphome/core
esphome/components/gpio/* @esphome/core
esphome/components/gps/* @coogle
esphome/components/graph/* @synco
esphome/components/growatt_solar/* @leeuwte
esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann
@@ -79,14 +72,13 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/homeassistant/* @OttoWinter
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/i2c/* @esphome/core
esphome/components/improv/* @jesserockz
esphome/components/improv_serial/* @esphome/core
esphome/components/ina260/* @MrEditor97
esphome/components/inkbird_ibsth1_mini/* @fkirill
esphome/components/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter
esphome/components/interval/* @esphome/core
esphome/components/json/* @OttoWinter
esphome/components/kalman_combinator/* @Cat-Ion
esphome/components/ledc/* @OttoWinter
esphome/components/light/* @esphome/core
esphome/components/logger/* @esphome/core
@@ -100,13 +92,10 @@ esphome/components/mcp23x08_base/* @jesserockz
esphome/components/mcp23x17_base/* @jesserockz
esphome/components/mcp23xxx_base/* @jesserockz
esphome/components/mcp2515/* @danielschramm @mvturnho
esphome/components/mcp3204/* @rsumner
esphome/components/mcp47a1/* @jesserockz
esphome/components/mcp9808/* @k7hpn
esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core
esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov
esphome/components/mitsubishi/* @RubyBailey
esphome/components/modbus_controller/* @martgras
esphome/components/modbus_controller/binary_sensor/* @martgras
@@ -134,7 +123,6 @@ esphome/components/pn532_i2c/* @OttoWinter @jesserockz
esphome/components/pn532_spi/* @OttoWinter @jesserockz
esphome/components/power_supply/* @esphome/core
esphome/components/preferences/* @esphome/core
esphome/components/psram/* @esphome/core
esphome/components/pulse_meter/* @stevebaxter
esphome/components/pvvx_mithermometer/* @pasiz
esphome/components/rc522/* @glmnet
@@ -144,7 +132,7 @@ esphome/components/restart/* @esphome/core
esphome/components/rf_bridge/* @jesserockz
esphome/components/rgbct/* @jesserockz
esphome/components/rtttl/* @glmnet
esphome/components/safe_mode/* @jsuanet @paulmonigatti
esphome/components/safe_mode/* @paulmonigatti
esphome/components/scd4x/* @sjtrny
esphome/components/script/* @esphome/core
esphome/components/sdm_meter/* @jesserockz @polyfaces
@@ -154,7 +142,7 @@ esphome/components/select/* @esphome/core
esphome/components/sensor/* @esphome/core
esphome/components/sgp40/* @SenexCrenshaw
esphome/components/sht4x/* @sjtrny
esphome/components/shutdown/* @esphome/core @jsuanet
esphome/components/shutdown/* @esphome/core
esphome/components/sim800l/* @glmnet
esphome/components/sm2135/* @BoukeHaarsma23
esphome/components/socket/* @esphome/core
@@ -191,10 +179,8 @@ esphome/components/toshiba/* @kbx81
esphome/components/tsl2591/* @wjcarpenter
esphome/components/tuya/binary_sensor/* @jesserockz
esphome/components/tuya/climate/* @jesserockz
esphome/components/tuya/number/* @frankiboy1
esphome/components/tuya/sensor/* @jesserockz
esphome/components/tuya/switch/* @jesserockz
esphome/components/tuya/text_sensor/* @dentra
esphome/components/uart/* @esphome/core
esphome/components/ultrasonic/* @OttoWinter
esphome/components/version/* @esphome/core

View File

@@ -5,12 +5,12 @@
# One of "docker", "hassio"
ARG BASEIMGTYPE=docker
FROM ghcr.io/hassio-addons/debian-base/amd64:5.2.3 AS base-hassio-amd64
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.2.3 AS base-hassio-arm64
FROM ghcr.io/hassio-addons/debian-base/armv7:5.2.3 AS base-hassio-armv7
FROM debian:bullseye-20211220-slim AS base-docker-amd64
FROM debian:bullseye-20211220-slim AS base-docker-arm64
FROM debian:bullseye-20211220-slim AS base-docker-armv7
FROM ghcr.io/hassio-addons/debian-base/amd64:5.1.1 AS base-hassio-amd64
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.1.1 AS base-hassio-arm64
FROM ghcr.io/hassio-addons/debian-base/armv7:5.1.1 AS base-hassio-armv7
FROM debian:bullseye-20211011-slim AS base-docker-amd64
FROM debian:bullseye-20211011-slim AS base-docker-arm64
FROM debian:bullseye-20211011-slim AS base-docker-armv7
# Use TARGETARCH/TARGETVARIANT defined by docker
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
@@ -27,7 +27,7 @@ RUN \
python3-cryptography=3.3.2-1 \
iputils-ping=3:20210202-1 \
git=1:2.30.2-1 \
curl=7.74.0-1.3+deb11u1 \
curl=7.74.0-1.3+b1 \
&& rm -rf \
/tmp/* \
/var/{cache,log}/* \
@@ -42,8 +42,8 @@ ENV \
RUN \
# Ubuntu python3-pip is missing wheel
pip3 install --no-cache-dir \
wheel==0.37.1 \
platformio==5.2.4 \
wheel==0.36.2 \
platformio==5.2.2 \
# Change some platformio settings
&& platformio settings set enable_telemetry No \
&& platformio settings set check_libraries_interval 1000000 \
@@ -64,7 +64,7 @@ RUN \
# Copy esphome and install
COPY . /esphome
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
RUN pip3 install --no-cache-dir -e /esphome
# Settings for dashboard
ENV USERNAME="" PASSWORD=""
@@ -112,7 +112,7 @@ RUN \
# Copy esphome and install
COPY . /esphome
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
RUN pip3 install --no-cache-dir -e /esphome
# Labels
LABEL \
@@ -147,9 +147,9 @@ RUN \
/var/{cache,log}/* \
/var/lib/apt/lists/*
COPY requirements.txt requirements_optional.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini /
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
RUN \
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt -r /requirements_test.txt \
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
&& /platformio_install_deps.py /platformio.ini
VOLUME ["/esphome"]

View File

@@ -32,7 +32,6 @@ parser.add_argument("--dry-run", action="store_true", help="Don't run any comman
subparsers = parser.add_subparsers(help="Action to perform", dest="command", required=True)
build_parser = subparsers.add_parser("build", help="Build the image")
build_parser.add_argument("--push", help="Also push the images", action="store_true")
build_parser.add_argument("--load", help="Load the docker image locally", action="store_true")
manifest_parser = subparsers.add_parser("manifest", help="Create a manifest from already pushed images")
@@ -133,8 +132,6 @@ def main():
cmd += ["--tag", img]
if args.push:
cmd += ["--push", "--cache-to", f"type=registry,ref={cache_img},mode=max"]
if args.load:
cmd += ["--load"]
run_command(*cmd, ".")
elif args.command == "manifest":

View File

@@ -18,7 +18,6 @@ from esphome.const import (
CONF_PORT,
CONF_ESPHOME,
CONF_PLATFORMIO_OPTIONS,
SECRETS_FILES,
)
from esphome.core import CORE, EsphomeError, coroutine
from esphome.helpers import indent
@@ -145,8 +144,6 @@ def wrap_to_code(name, comp):
if comp.config_schema is not None:
conf_str = yaml_util.dump(conf)
conf_str = conf_str.replace("//", "")
# remove tailing \ to avoid multi-line comment warning
conf_str = conf_str.replace("\\\n", "\n")
cg.add(cg.LineComment(indent(conf_str)))
await coro(conf)
@@ -203,7 +200,8 @@ def upload_using_esptool(config, port):
firmware_offset = "0x10000" if CORE.is_esp32 else "0x0"
flash_images = [
platformio_api.FlashImage(
path=idedata.firmware_bin_path, offset=firmware_offset
path=idedata.firmware_bin_path,
offset=firmware_offset,
),
*idedata.extra_flash_images,
]
@@ -609,7 +607,10 @@ def parse_args(argv):
"wizard",
help="A helpful setup wizard that will guide you through setting up ESPHome.",
)
parser_wizard.add_argument("configuration", help="Your YAML configuration file.")
parser_wizard.add_argument(
"configuration",
help="Your YAML configuration file.",
)
parser_fingerprint = subparsers.add_parser(
"mqtt-fingerprint", help="Get the SSL fingerprint from a MQTT broker."
@@ -631,7 +632,8 @@ def parse_args(argv):
"dashboard", help="Create a simple web server for a dashboard."
)
parser_dashboard.add_argument(
"configuration", help="Your YAML configuration file directory."
"configuration",
help="Your YAML configuration file directory.",
)
parser_dashboard.add_argument(
"--port",
@@ -639,12 +641,6 @@ def parse_args(argv):
type=int,
default=6052,
)
parser_dashboard.add_argument(
"--address",
help="The address to bind to.",
type=str,
default="0.0.0.0",
)
parser_dashboard.add_argument(
"--username",
help="The optional username to require for authentication.",
@@ -793,10 +789,6 @@ def run_esphome(argv):
return 1
for conf_path in args.configuration:
if any(os.path.basename(conf_path) == x for x in SECRETS_FILES):
_LOGGER.warning("Skipping secrets file %s", conf_path)
continue
CORE.config_path = conf_path
CORE.dashboard = args.dashboard

View File

@@ -75,7 +75,8 @@ from esphome.cpp_types import ( # noqa
optional,
arduino_json_ns,
JsonObject,
JsonObjectConst,
JsonObjectRef,
JsonObjectConstRef,
Controller,
GPIOPin,
InternalGPIOPin,

View File

@@ -25,7 +25,7 @@ void AdalightLightEffect::stop() {
AddressableLightEffect::stop();
}
unsigned int AdalightLightEffect::get_frame_size_(int led_count) const {
int AdalightLightEffect::get_frame_size_(int led_count) const {
// 3 bytes: Ada
// 2 bytes: LED count
// 1 byte: checksum

View File

@@ -25,7 +25,7 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U
CONSUMED,
};
unsigned int get_frame_size_(int led_count) const;
int get_frame_size_(int led_count) const;
void reset_frame_(light::AddressableLight &it);
void blank_all_leds_(light::AddressableLight &it);
Frame parse_frame_(light::AddressableLight &it);

View File

@@ -91,7 +91,7 @@ void ADCSensor::dump_config() {
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
void ADCSensor::update() {
float value_v = this->sample();
ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
ESP_LOGD(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
this->publish_state(value_v);
}

View File

@@ -73,6 +73,13 @@ void AHT10Component::update() {
bool success = false;
for (int i = 0; i < AHT10_ATTEMPTS; ++i) {
ESP_LOGVV(TAG, "Attempt %d at %6u", i, millis());
delayMicroseconds(4);
uint8_t reg = 0;
if (this->write(&reg, 1) != i2c::ERROR_OK) {
ESP_LOGD(TAG, "Communication with AHT10 failed, waiting...");
continue;
}
delay(delay_ms);
if (this->read(data, 6) != i2c::ERROR_OK) {
ESP_LOGD(TAG, "Communication with AHT10 failed, waiting...");
@@ -110,12 +117,12 @@ void AHT10Component::update() {
uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4;
float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f;
float temperature = ((200.0 * (float) raw_temperature) / 1048576.0) - 50.0;
float humidity;
if (raw_humidity == 0) { // unrealistic value
humidity = NAN;
} else {
humidity = (float) raw_humidity * 100.0f / 1048576.0f;
humidity = (float) raw_humidity * 100.0 / 1048576.0;
}
if (this->temperature_sensor_ != nullptr) {

View File

@@ -38,9 +38,9 @@ void AM2320Component::update() {
return;
}
float temperature = (((data[4] & 0x7F) << 8) + data[5]) / 10.0f;
float temperature = (((data[4] & 0x7F) << 8) + data[5]) / 10.0;
temperature = (data[4] & 0x80) ? -temperature : temperature;
float humidity = ((data[2] << 8) + data[3]) / 10.0f;
float humidity = ((data[2] << 8) + data[3]) / 10.0;
ESP_LOGD(TAG, "Got temperature=%.1f°C humidity=%.1f%%", temperature, humidity);
if (this->temperature_sensor_ != nullptr)

View File

@@ -44,9 +44,8 @@ async def to_code(config):
width, height = image.size
frames = image.n_frames
if CONF_RESIZE in config:
new_width_max, new_height_max = config[CONF_RESIZE]
ratio = min(new_width_max / width, new_height_max / height)
width, height = int(width * ratio), int(height * ratio)
image.thumbnail(config[CONF_RESIZE])
width, height = image.size
else:
if width > 500 or height > 500:
_LOGGER.warning(
@@ -60,13 +59,7 @@ async def to_code(config):
for frameIndex in range(frames):
image.seek(frameIndex)
frame = image.convert("L", dither=Image.NONE)
if CONF_RESIZE in config:
frame = frame.resize([width, height])
pixels = list(frame.getdata())
if len(pixels) != height * width:
raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
)
for pix in pixels:
data[pos] = pix
pos += 1
@@ -77,13 +70,7 @@ async def to_code(config):
for frameIndex in range(frames):
image.seek(frameIndex)
frame = image.convert("RGB")
if CONF_RESIZE in config:
frame = frame.resize([width, height])
pixels = list(frame.getdata())
if len(pixels) != height * width:
raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
)
for pix in pixels:
data[pos] = pix[0]
pos += 1
@@ -98,8 +85,6 @@ async def to_code(config):
for frameIndex in range(frames):
image.seek(frameIndex)
frame = image.convert("1", dither=Image.NONE)
if CONF_RESIZE in config:
frame = frame.resize([width, height])
for y in range(height):
for x in range(width):
if frame.getpixel((x, y)):

View File

@@ -30,7 +30,7 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode
climate::ClimateTraits traits() override {
auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(true);
traits.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::ClimateMode::CLIMATE_MODE_HEAT});
traits.set_supports_heat_mode(true);
traits.set_visual_min_temperature(25.0);
traits.set_visual_max_temperature(100.0);
traits.set_visual_temperature_step(0.1);

View File

@@ -73,46 +73,51 @@ AnovaPacket *AnovaCodec::get_stop_request() {
}
void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
char buf[32];
memset(buf, 0, sizeof(buf));
strncpy(buf, (char *) data, std::min<uint16_t>(length, sizeof(buf) - 1));
memset(this->buf_, 0, 32);
strncpy(this->buf_, (char *) data, length);
this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false;
switch (this->current_query_) {
case READ_DEVICE_STATUS: {
if (!strncmp(buf, "stopped", 7)) {
if (!strncmp(this->buf_, "stopped", 7)) {
this->has_running_ = true;
this->running_ = false;
}
if (!strncmp(buf, "running", 7)) {
if (!strncmp(this->buf_, "running", 7)) {
this->has_running_ = true;
this->running_ = true;
}
break;
}
case START: {
if (!strncmp(buf, "start", 5)) {
if (!strncmp(this->buf_, "start", 5)) {
this->has_running_ = true;
this->running_ = true;
}
break;
}
case STOP: {
if (!strncmp(buf, "stop", 4)) {
if (!strncmp(this->buf_, "stop", 4)) {
this->has_running_ = true;
this->running_ = false;
}
break;
}
case READ_TARGET_TEMPERATURE:
case READ_TARGET_TEMPERATURE: {
this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
if (this->fahrenheit_)
this->target_temp_ = ftoc(this->target_temp_);
this->has_target_temp_ = true;
break;
}
case SET_TARGET_TEMPERATURE: {
this->target_temp_ = parse_number<float>(str_until(buf, '\r')).value_or(0.0f);
this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
if (this->fahrenheit_)
this->target_temp_ = ftoc(this->target_temp_);
this->has_target_temp_ = true;
break;
}
case READ_CURRENT_TEMPERATURE: {
this->current_temp_ = parse_number<float>(str_until(buf, '\r')).value_or(0.0f);
this->current_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
if (this->fahrenheit_)
this->current_temp_ = ftoc(this->current_temp_);
this->has_current_temp_ = true;
@@ -120,8 +125,8 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
}
case SET_UNIT:
case READ_UNIT: {
this->unit_ = buf[0];
this->fahrenheit_ = buf[0] == 'f';
this->unit_ = this->buf_[0];
this->fahrenheit_ = this->buf_[0] == 'f';
this->has_unit_ = true;
break;
}

View File

@@ -70,6 +70,7 @@ class AnovaCodec {
bool has_current_temp_;
bool has_unit_;
bool has_running_;
char buf_[32];
bool fahrenheit_;
CurrentQuery current_query_;

View File

@@ -40,7 +40,6 @@ service APIConnection {
rpc climate_command (ClimateCommandRequest) returns (void) {}
rpc number_command (NumberCommandRequest) returns (void) {}
rpc select_command (SelectCommandRequest) returns (void) {}
rpc button_command (ButtonCommandRequest) returns (void) {}
}
@@ -869,11 +868,6 @@ message ClimateCommandRequest {
}
// ==================== NUMBER ====================
enum NumberMode {
NUMBER_MODE_AUTO = 0;
NUMBER_MODE_BOX = 1;
NUMBER_MODE_SLIDER = 2;
}
message ListEntitiesNumberResponse {
option (id) = 49;
option (source) = SOURCE_SERVER;
@@ -890,8 +884,6 @@ message ListEntitiesNumberResponse {
float step = 8;
bool disabled_by_default = 9;
EntityCategory entity_category = 10;
string unit_of_measurement = 11;
NumberMode mode = 12;
}
message NumberStateResponse {
option (id) = 50;
@@ -952,28 +944,3 @@ message SelectCommandRequest {
fixed32 key = 1;
string state = 2;
}
// ==================== BUTTON ====================
message ListEntitiesButtonResponse {
option (id) = 61;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BUTTON";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
bool disabled_by_default = 6;
EntityCategory entity_category = 7;
string device_class = 8;
}
message ButtonCommandRequest {
option (id) = 62;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BUTTON";
option (no_delay) = true;
fixed32 key = 1;
}

View File

@@ -20,7 +20,6 @@ namespace esphome {
namespace api {
static const char *const TAG = "api.connection";
static const int ESP32_CAMERA_STOP_STREAM = 5000;
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
: parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) {
@@ -133,7 +132,7 @@ void APIConnection::loop() {
if (state_subs_at_ != -1) {
const auto &subs = this->parent_->get_state_subs();
if (state_subs_at_ >= (int) subs.size()) {
if (state_subs_at_ >= subs.size()) {
state_subs_at_ = -1;
} else {
auto &it = subs[state_subs_at_];
@@ -620,8 +619,6 @@ bool APIConnection::send_number_info(number::Number *number) {
msg.icon = number->get_icon();
msg.disabled_by_default = number->is_disabled_by_default();
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.min_value = number->traits.get_min_value();
msg.max_value = number->traits.get_max_value();
@@ -677,37 +674,13 @@ void APIConnection::select_command(const SelectCommandRequest &msg) {
}
#endif
#ifdef USE_BUTTON
bool APIConnection::send_button_info(button::Button *button) {
ListEntitiesButtonResponse msg;
msg.key = button->get_object_id_hash();
msg.object_id = button->get_object_id();
msg.name = button->get_name();
msg.unique_id = get_default_unique_id("button", button);
msg.icon = button->get_icon();
msg.disabled_by_default = button->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(button->get_entity_category());
msg.device_class = button->get_device_class();
return this->send_list_entities_button_response(msg);
}
void APIConnection::button_command(const ButtonCommandRequest &msg) {
button::Button *button = App.get_button_by_key(msg.key);
if (button == nullptr)
return;
button->press();
}
#endif
#ifdef USE_ESP32_CAMERA
void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
if (!this->state_subscription_)
return;
if (this->image_reader_.available())
return;
if (image->was_requested_by(esphome::esp32_camera::API_REQUESTER) ||
image->was_requested_by(esphome::esp32_camera::IDLE))
this->image_reader_.set_image(std::move(image));
this->image_reader_.set_image(std::move(image));
}
bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
ListEntitiesCameraResponse msg;
@@ -725,14 +698,9 @@ void APIConnection::camera_image(const CameraImageRequest &msg) {
return;
if (msg.single)
esp32_camera::global_esp32_camera->request_image(esphome::esp32_camera::API_REQUESTER);
if (msg.stream) {
esp32_camera::global_esp32_camera->start_stream(esphome::esp32_camera::API_REQUESTER);
App.scheduler.set_timeout(this->parent_, "api_esp32_camera_stop_stream", ESP32_CAMERA_STOP_STREAM, []() {
esp32_camera::global_esp32_camera->stop_stream(esphome::esp32_camera::API_REQUESTER);
});
}
esp32_camera::global_esp32_camera->request_image();
if (msg.stream)
esp32_camera::global_esp32_camera->request_stream();
}
#endif

View File

@@ -73,10 +73,6 @@ class APIConnection : public APIServerConnection {
bool send_select_state(select::Select *select, std::string state);
bool send_select_info(select::Select *select);
void select_command(const SelectCommandRequest &msg) override;
#endif
#ifdef USE_BUTTON
bool send_button_info(button::Button *button);
void button_command(const ButtonCommandRequest &msg) override;
#endif
bool send_log_message(int level, const char *tag, const char *line);
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {

View File

@@ -1,7 +1,6 @@
#include "api_frame_helper.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "proto.h"
#include <cstring>
@@ -175,6 +174,9 @@ APIError APINoiseFrameHelper::loop() {
* errno API_ERROR_HANDSHAKE_PACKET_LEN: Packet too big for this phase.
*/
APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
int err;
APIError aerr;
if (frame == nullptr) {
HELPER_LOG("Bad argument for try_read_frame_");
return APIError::BAD_ARG;
@@ -198,7 +200,7 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
return APIError::CONNECTION_CLOSED;
}
rx_header_buf_len_ += received;
if ((size_t) received != to_read) {
if (received != to_read) {
// not a full read
return APIError::WOULD_BLOCK;
}
@@ -245,7 +247,7 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
return APIError::CONNECTION_CLOSED;
}
rx_buf_len_ += received;
if ((size_t) received != to_read) {
if (received != to_read) {
// not all read
return APIError::WOULD_BLOCK;
}
@@ -253,7 +255,7 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
// uncomment for even more debugging
#ifdef HELPER_LOG_PACKETS
ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(rx_buf_).c_str());
ESP_LOGVV(TAG, "Received frame: %s", hexencode(rx_buf_).c_str());
#endif
frame->msg = std::move(rx_buf_);
// consume msg
@@ -542,13 +544,13 @@ APIError APINoiseFrameHelper::try_send_tx_buf_() {
APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
if (iovcnt == 0)
return APIError::OK;
int err;
APIError aerr;
size_t total_write_len = 0;
for (int i = 0; i < iovcnt; i++) {
#ifdef HELPER_LOG_PACKETS
ESP_LOGVV(TAG, "Sending raw: %s",
format_hex_pretty(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
ESP_LOGVV(TAG, "Sending raw: %s", hexencode(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
#endif
total_write_len += iov[i].iov_len;
}
@@ -582,7 +584,7 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
state_ = State::FAILED;
HELPER_LOG("Socket write failed with errno %d", errno);
return APIError::SOCKET_WRITE_FAILED;
} else if ((size_t) sent != total_write_len) {
} else if (sent != total_write_len) {
// partially sent, add end to tx_buf
size_t to_consume = sent;
for (int i = 0; i < iovcnt; i++) {
@@ -722,12 +724,7 @@ APIError APINoiseFrameHelper::shutdown(int how) {
}
extern "C" {
// declare how noise generates random bytes (here with a good HWRNG based on the RF system)
void noise_rand_bytes(void *output, size_t len) {
if (!esphome::random_bytes(reinterpret_cast<uint8_t *>(output), len)) {
ESP_LOGE(TAG, "Failed to acquire random bytes, rebooting!");
arch_restart();
}
}
void noise_rand_bytes(void *output, size_t len) { esphome::fill_random(reinterpret_cast<uint8_t *>(output), len); }
}
#endif // USE_API_NOISE
@@ -781,6 +778,9 @@ APIError APIPlaintextFrameHelper::loop() {
* error API_ERROR_BAD_INDICATOR: Bad indicator byte at start of frame.
*/
APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
int err;
APIError aerr;
if (frame == nullptr) {
HELPER_LOG("Bad argument for try_read_frame_");
return APIError::BAD_ARG;
@@ -854,7 +854,7 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
return APIError::CONNECTION_CLOSED;
}
rx_buf_len_ += received;
if ((size_t) received != to_read) {
if (received != to_read) {
// not all read
return APIError::WOULD_BLOCK;
}
@@ -862,7 +862,7 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
// uncomment for even more debugging
#ifdef HELPER_LOG_PACKETS
ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(rx_buf_).c_str());
ESP_LOGVV(TAG, "Received frame: %s", hexencode(rx_buf_).c_str());
#endif
frame->msg = std::move(rx_buf_);
// consume msg
@@ -874,6 +874,7 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
}
APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
int err;
APIError aerr;
if (state_ != State::DATA) {
@@ -893,6 +894,9 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
}
bool APIPlaintextFrameHelper::can_write_without_blocking() { return state_ == State::DATA && tx_buf_.empty(); }
APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *payload, size_t payload_len) {
int err;
APIError aerr;
if (state_ != State::DATA) {
return APIError::BAD_STATE;
}
@@ -936,13 +940,13 @@ APIError APIPlaintextFrameHelper::try_send_tx_buf_() {
APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
if (iovcnt == 0)
return APIError::OK;
int err;
APIError aerr;
size_t total_write_len = 0;
for (int i = 0; i < iovcnt; i++) {
#ifdef HELPER_LOG_PACKETS
ESP_LOGVV(TAG, "Sending raw: %s",
format_hex_pretty(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
ESP_LOGVV(TAG, "Sending raw: %s", hexencode(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
#endif
total_write_len += iov[i].iov_len;
}
@@ -976,7 +980,7 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt
state_ = State::FAILED;
HELPER_LOG("Socket write failed with errno %d", errno);
return APIError::SOCKET_WRITE_FAILED;
} else if ((size_t) sent != total_write_len) {
} else if (sent != total_write_len) {
// partially sent, add end to tx_buf
size_t to_consume = sent;
for (int i = 0; i < iovcnt; i++) {

View File

@@ -266,18 +266,6 @@ template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::Climate
return "UNKNOWN";
}
}
template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) {
switch (value) {
case enums::NUMBER_MODE_AUTO:
return "NUMBER_MODE_AUTO";
case enums::NUMBER_MODE_BOX:
return "NUMBER_MODE_BOX";
case enums::NUMBER_MODE_SLIDER:
return "NUMBER_MODE_SLIDER";
default:
return "UNKNOWN";
}
}
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
@@ -291,7 +279,7 @@ bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value)
void HelloRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->client_info); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void HelloRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("HelloRequest {\n");
out.append(" client_info: ");
out.append("'").append(this->client_info).append("'");
@@ -330,7 +318,7 @@ void HelloResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void HelloResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("HelloResponse {\n");
out.append(" api_version_major: ");
sprintf(buffer, "%u", this->api_version_major);
@@ -361,7 +349,7 @@ bool ConnectRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value
void ConnectRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->password); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void ConnectRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ConnectRequest {\n");
out.append(" password: ");
out.append("'").append(this->password).append("'");
@@ -382,7 +370,7 @@ bool ConnectResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
void ConnectResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->invalid_password); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void ConnectResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ConnectResponse {\n");
out.append(" invalid_password: ");
out.append(YESNO(this->invalid_password));
@@ -476,7 +464,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void DeviceInfoResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("DeviceInfoResponse {\n");
out.append(" uses_password: ");
out.append(YESNO(this->uses_password));
@@ -600,7 +588,7 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesBinarySensorResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -672,7 +660,7 @@ void BinarySensorStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BinarySensorStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("BinarySensorStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -766,7 +754,7 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesCoverResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesCoverResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -856,7 +844,7 @@ void CoverStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void CoverStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("CoverStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -939,7 +927,7 @@ void CoverCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void CoverCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("CoverCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -1055,7 +1043,7 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesFanResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesFanResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -1151,7 +1139,7 @@ void FanStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void FanStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("FanStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -1252,7 +1240,7 @@ void FanCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void FanCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("FanCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -1403,7 +1391,7 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesLightResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesLightResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -1561,7 +1549,7 @@ void LightStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void LightStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("LightStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -1784,7 +1772,7 @@ void LightCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void LightCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("LightCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -1995,7 +1983,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesSensorResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesSensorResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -2084,7 +2072,7 @@ void SensorStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SensorStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SensorStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -2164,7 +2152,7 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesSwitchResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesSwitchResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -2227,7 +2215,7 @@ void SwitchStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SwitchStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SwitchStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -2266,7 +2254,7 @@ void SwitchCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SwitchCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SwitchCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -2336,7 +2324,7 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesTextSensorResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesTextSensorResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -2406,7 +2394,7 @@ void TextSensorStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void TextSensorStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("TextSensorStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -2443,7 +2431,7 @@ void SubscribeLogsRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeLogsRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SubscribeLogsRequest {\n");
out.append(" level: ");
out.append(proto_enum_to_string<enums::LogLevel>(this->level));
@@ -2486,7 +2474,7 @@ void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeLogsResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SubscribeLogsResponse {\n");
out.append(" level: ");
out.append(proto_enum_to_string<enums::LogLevel>(this->level));
@@ -2528,7 +2516,7 @@ void HomeassistantServiceMap::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void HomeassistantServiceMap::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("HomeassistantServiceMap {\n");
out.append(" key: ");
out.append("'").append(this->key).append("'");
@@ -2587,7 +2575,7 @@ void HomeassistantServiceResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void HomeassistantServiceResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("HomeassistantServiceResponse {\n");
out.append(" service: ");
out.append("'").append(this->service).append("'");
@@ -2643,7 +2631,7 @@ void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SubscribeHomeAssistantStateResponse {\n");
out.append(" entity_id: ");
out.append("'").append(this->entity_id).append("'");
@@ -2680,7 +2668,7 @@ void HomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void HomeAssistantStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("HomeAssistantStateResponse {\n");
out.append(" entity_id: ");
out.append("'").append(this->entity_id).append("'");
@@ -2713,7 +2701,7 @@ bool GetTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
void GetTimeResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->epoch_seconds); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void GetTimeResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("GetTimeResponse {\n");
out.append(" epoch_seconds: ");
sprintf(buffer, "%u", this->epoch_seconds);
@@ -2748,7 +2736,7 @@ void ListEntitiesServicesArgument::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesServicesArgument::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesServicesArgument {\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
@@ -2793,7 +2781,7 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesServicesResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesServicesResponse {\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
@@ -2887,7 +2875,7 @@ void ExecuteServiceArgument::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ExecuteServiceArgument::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ExecuteServiceArgument {\n");
out.append(" bool_: ");
out.append(YESNO(this->bool_));
@@ -2968,7 +2956,7 @@ void ExecuteServiceRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ExecuteServiceRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ExecuteServiceRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -3040,7 +3028,7 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesCameraResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesCameraResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -3110,7 +3098,7 @@ void CameraImageResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void CameraImageResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("CameraImageResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -3147,7 +3135,7 @@ void CameraImageRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void CameraImageRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("CameraImageRequest {\n");
out.append(" single: ");
out.append(YESNO(this->single));
@@ -3293,7 +3281,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesClimateResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -3480,7 +3468,7 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ClimateStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ClimateStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -3668,7 +3656,7 @@ void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ClimateCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ClimateCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -3770,10 +3758,6 @@ bool ListEntitiesNumberResponse::decode_varint(uint32_t field_id, ProtoVarInt va
this->entity_category = value.as_enum<enums::EntityCategory>();
return true;
}
case 12: {
this->mode = value.as_enum<enums::NumberMode>();
return true;
}
default:
return false;
}
@@ -3796,10 +3780,6 @@ bool ListEntitiesNumberResponse::decode_length(uint32_t field_id, ProtoLengthDel
this->icon = value.as_string();
return true;
}
case 11: {
this->unit_of_measurement = value.as_string();
return true;
}
default:
return false;
}
@@ -3837,12 +3817,10 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_float(8, this->step);
buffer.encode_bool(9, this->disabled_by_default);
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);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesNumberResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesNumberResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -3887,14 +3865,6 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const {
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" unit_of_measurement: ");
out.append("'").append(this->unit_of_measurement).append("'");
out.append("\n");
out.append(" mode: ");
out.append(proto_enum_to_string<enums::NumberMode>(this->mode));
out.append("\n");
out.append("}");
}
#endif
@@ -3929,7 +3899,7 @@ void NumberStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void NumberStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("NumberStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -3967,7 +3937,7 @@ void NumberCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void NumberCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("NumberCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -4045,7 +4015,7 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesSelectResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesSelectResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -4121,7 +4091,7 @@ void SelectStateResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SelectStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SelectStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -4164,7 +4134,7 @@ void SelectCommandRequest::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SelectCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("SelectCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
@@ -4177,127 +4147,6 @@ void SelectCommandRequest::dump_to(std::string &out) const {
out.append("}");
}
#endif
bool ListEntitiesButtonResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 6: {
this->disabled_by_default = value.as_bool();
return true;
}
case 7: {
this->entity_category = value.as_enum<enums::EntityCategory>();
return true;
}
default:
return false;
}
}
bool ListEntitiesButtonResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->object_id = value.as_string();
return true;
}
case 3: {
this->name = value.as_string();
return true;
}
case 4: {
this->unique_id = value.as_string();
return true;
}
case 5: {
this->icon = value.as_string();
return true;
}
case 8: {
this->device_class = value.as_string();
return true;
}
default:
return false;
}
}
bool ListEntitiesButtonResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 2: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void ListEntitiesButtonResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->object_id);
buffer.encode_fixed32(2, this->key);
buffer.encode_string(3, this->name);
buffer.encode_string(4, this->unique_id);
buffer.encode_string(5, this->icon);
buffer.encode_bool(6, this->disabled_by_default);
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
buffer.encode_string(8, this->device_class);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesButtonResponse::dump_to(std::string &out) const {
char buffer[64];
out.append("ListEntitiesButtonResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
out.append("\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
out.append(buffer);
out.append("\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" unique_id: ");
out.append("'").append(this->unique_id).append("'");
out.append("\n");
out.append(" icon: ");
out.append("'").append(this->icon).append("'");
out.append("\n");
out.append(" disabled_by_default: ");
out.append(YESNO(this->disabled_by_default));
out.append("\n");
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" device_class: ");
out.append("'").append(this->device_class).append("'");
out.append("\n");
out.append("}");
}
#endif
bool ButtonCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void ButtonCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void ButtonCommandRequest::dump_to(std::string &out) const {
char buffer[64];
out.append("ButtonCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -123,11 +123,6 @@ enum ClimatePreset : uint32_t {
CLIMATE_PRESET_SLEEP = 6,
CLIMATE_PRESET_ACTIVITY = 7,
};
enum NumberMode : uint32_t {
NUMBER_MODE_AUTO = 0,
NUMBER_MODE_BOX = 1,
NUMBER_MODE_SLIDER = 2,
};
} // namespace enums
@@ -962,8 +957,6 @@ class ListEntitiesNumberResponse : public ProtoMessage {
float step{0.0f};
bool disabled_by_default{false};
enums::EntityCategory entity_category{};
std::string unit_of_measurement{};
enums::NumberMode mode{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1048,37 +1041,6 @@ class SelectCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class ListEntitiesButtonResponse : public ProtoMessage {
public:
std::string object_id{};
uint32_t key{0};
std::string name{};
std::string unique_id{};
std::string icon{};
bool disabled_by_default{false};
enums::EntityCategory entity_category{};
std::string device_class{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class ButtonCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
};
} // namespace api
} // namespace esphome

View File

@@ -282,16 +282,6 @@ bool APIServerConnectionBase::send_select_state_response(const SelectStateRespon
#endif
#ifdef USE_SELECT
#endif
#ifdef USE_BUTTON
bool APIServerConnectionBase::send_list_entities_button_response(const ListEntitiesButtonResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_button_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesButtonResponse>(msg, 61);
}
#endif
#ifdef USE_BUTTON
#endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) {
case 1: {
@@ -523,17 +513,6 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str());
#endif
this->on_select_command_request(msg);
#endif
break;
}
case 62: {
#ifdef USE_BUTTON
ButtonCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_button_command_request: %s", msg.dump().c_str());
#endif
this->on_button_command_request(msg);
#endif
break;
}
@@ -758,19 +737,6 @@ void APIServerConnection::on_select_command_request(const SelectCommandRequest &
this->select_command(msg);
}
#endif
#ifdef USE_BUTTON
void APIServerConnection::on_button_command_request(const ButtonCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->button_command(msg);
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -129,12 +129,6 @@ class APIServerConnectionBase : public ProtoService {
#endif
#ifdef USE_SELECT
virtual void on_select_command_request(const SelectCommandRequest &value){};
#endif
#ifdef USE_BUTTON
bool send_list_entities_button_response(const ListEntitiesButtonResponse &msg);
#endif
#ifdef USE_BUTTON
virtual void on_button_command_request(const ButtonCommandRequest &value){};
#endif
protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
@@ -177,9 +171,6 @@ class APIServerConnection : public APIServerConnectionBase {
#endif
#ifdef USE_SELECT
virtual void select_command(const SelectCommandRequest &msg) = 0;
#endif
#ifdef USE_BUTTON
virtual void button_command(const ButtonCommandRequest &msg) = 0;
#endif
protected:
void on_hello_request(const HelloRequest &msg) override;
@@ -218,9 +209,6 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_SELECT
void on_select_command_request(const SelectCommandRequest &msg) override;
#endif
#ifdef USE_BUTTON
void on_button_command_request(const ButtonCommandRequest &msg) override;
#endif
};
} // namespace api

View File

@@ -12,10 +12,10 @@ template<typename... X> class TemplatableStringValue : public TemplatableValue<s
public:
TemplatableStringValue() : TemplatableValue<std::string, X...>() {}
template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0>
template<typename F, enable_if_t<!is_callable<F, X...>::value, int> = 0>
TemplatableStringValue(F value) : TemplatableValue<std::string, X...>(value) {}
template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0>
template<typename F, enable_if_t<is_callable<F, X...>::value, int> = 0>
TemplatableStringValue(F f)
: TemplatableValue<std::string, X...>([f](X... x) -> std::string { return to_string(f(x...)); }) {}
};

View File

@@ -27,9 +27,6 @@ bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) { return this->clie
#ifdef USE_SWITCH
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { return this->client_->send_switch_info(a_switch); }
#endif
#ifdef USE_BUTTON
bool ListEntitiesIterator::on_button(button::Button *button) { return this->client_->send_button_info(button); }
#endif
#ifdef USE_TEXT_SENSOR
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
return this->client_->send_text_sensor_info(text_sensor);

View File

@@ -30,9 +30,6 @@ class ListEntitiesIterator : public ComponentIterator {
#ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override;
#endif
#ifdef USE_BUTTON
bool on_button(button::Button *button) override;
#endif
#ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
#endif

View File

@@ -31,9 +31,6 @@ class InitialStateIterator : public ComponentIterator {
#ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override;
#endif
#ifdef USE_BUTTON
bool on_button(button::Button *button) override { return true; };
#endif
#ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
#endif

View File

@@ -116,21 +116,6 @@ void ComponentIterator::advance() {
}
break;
#endif
#ifdef USE_BUTTON
case IteratorState::BUTTON:
if (this->at_ >= App.get_buttons().size()) {
advance_platform = true;
} else {
auto *button = App.get_buttons()[this->at_];
if (button->is_internal()) {
success = true;
break;
} else {
success = this->on_button(button);
}
}
break;
#endif
#ifdef USE_TEXT_SENSOR
case IteratorState::TEXT_SENSOR:
if (this->at_ >= App.get_text_sensors().size()) {

View File

@@ -38,9 +38,6 @@ class ComponentIterator {
#ifdef USE_SWITCH
virtual bool on_switch(switch_::Switch *a_switch) = 0;
#endif
#ifdef USE_BUTTON
virtual bool on_button(button::Button *button) = 0;
#endif
#ifdef USE_TEXT_SENSOR
virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0;
#endif
@@ -81,9 +78,6 @@ class ComponentIterator {
#ifdef USE_SWITCH
SWITCH,
#endif
#ifdef USE_BUTTON
BUTTON,
#endif
#ifdef USE_TEXT_SENSOR
TEXT_SENSOR,
#endif

View File

@@ -45,8 +45,6 @@ bool ATCMiThermometer::parse_device(const esp32_ble_tracker::ESPBTDevice &device
this->battery_voltage_->publish_state(*res->battery_voltage);
success = true;
}
if (this->signal_strength_ != nullptr)
this->signal_strength_->publish_state(device.get_rssi());
return success;
}

View File

@@ -28,7 +28,6 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
void set_signal_strength(sensor::Sensor *signal_strength) { signal_strength_ = signal_strength; }
protected:
uint64_t address_;
@@ -36,7 +35,6 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
sensor::Sensor *humidity_{nullptr};
sensor::Sensor *battery_level_{nullptr};
sensor::Sensor *battery_voltage_{nullptr};
sensor::Sensor *signal_strength_{nullptr};
optional<ParseResult> parse_header_(const esp32_ble_tracker::ServiceData &service_data);
bool parse_message_(const std::vector<uint8_t> &message, ParseResult &result);

View File

@@ -6,18 +6,15 @@ from esphome.const import (
CONF_BATTERY_VOLTAGE,
CONF_MAC_ADDRESS,
CONF_HUMIDITY,
CONF_SIGNAL_STRENGTH,
CONF_TEMPERATURE,
CONF_ID,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
ENTITY_CATEGORY_DIAGNOSTIC,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_DECIBEL_MILLIWATT,
UNIT_PERCENT,
UNIT_VOLT,
)
@@ -62,13 +59,6 @@ CONFIG_SCHEMA = (
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
cv.Optional(CONF_SIGNAL_STRENGTH): sensor.sensor_schema(
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
}
)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
@@ -95,6 +85,3 @@ async def to_code(config):
if CONF_BATTERY_VOLTAGE in config:
sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
cg.add(var.set_battery_voltage(sens))
if CONF_SIGNAL_STRENGTH in config:
sens = await sensor.new_sensor(config[CONF_SIGNAL_STRENGTH])
cg.add(var.set_signal_strength(sens))

View File

@@ -80,23 +80,21 @@ void BangBangClimate::compute_state_() {
climate::ClimateAction target_action;
if (too_cold) {
// too cold -> enable heating if possible and enabled, else idle
if (this->supports_heat_ &&
(this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_HEAT))
// too cold -> enable heating if possible, else idle
if (this->supports_heat_)
target_action = climate::CLIMATE_ACTION_HEATING;
else
target_action = climate::CLIMATE_ACTION_IDLE;
} else if (too_hot) {
// too hot -> enable cooling if possible and enabled, else idle
if (this->supports_cool_ &&
(this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_COOL))
// too hot -> enable cooling if possible, else idle
if (this->supports_cool_)
target_action = climate::CLIMATE_ACTION_COOLING;
else
target_action = climate::CLIMATE_ACTION_IDLE;
} else {
// neither too hot nor too cold -> in range
if (this->supports_cool_ && this->supports_heat_ && this->mode == climate::CLIMATE_MODE_HEAT_COOL) {
// if supports both ends and both cooling and heating enabled, go to idle action
if (this->supports_cool_ && this->supports_heat_) {
// if supports both ends, go to idle action
target_action = climate::CLIMATE_ACTION_IDLE;
} else {
// else use current mode and don't change (hysteresis)

View File

@@ -49,7 +49,6 @@ from esphome.const import (
DEVICE_CLASS_SMOKE,
DEVICE_CLASS_SOUND,
DEVICE_CLASS_TAMPER,
DEVICE_CLASS_UPDATE,
DEVICE_CLASS_VIBRATION,
DEVICE_CLASS_WINDOW,
)
@@ -83,7 +82,6 @@ DEVICE_CLASSES = [
DEVICE_CLASS_SMOKE,
DEVICE_CLASS_SOUND,
DEVICE_CLASS_TAMPER,
DEVICE_CLASS_UPDATE,
DEVICE_CLASS_VIBRATION,
DEVICE_CLASS_WINDOW,
]

View File

@@ -48,10 +48,7 @@ void BinarySensor::set_device_class(const std::string &device_class) { this->dev
std::string BinarySensor::get_device_class() {
if (this->device_class_.has_value())
return *this->device_class_;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return this->device_class();
#pragma GCC diagnostic pop
}
void BinarySensor::add_filter(Filter *filter) {
filter->parent_ = this;

View File

@@ -74,10 +74,7 @@ class BinarySensor : public EntityBase {
// ========== OVERRIDE METHODS ==========
// (You'll only need this when creating your own custom binary sensor)
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
/// Get the default device class for this sensor, or empty string for no default.
virtual std::string device_class();
protected:

View File

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

View File

@@ -1,137 +0,0 @@
#include "bl0940.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bl0940 {
static const char *const TAG = "bl0940";
static const uint8_t BL0940_READ_COMMAND = 0x50; // 0x58 according to documentation
static const uint8_t BL0940_FULL_PACKET = 0xAA;
static const uint8_t BL0940_PACKET_HEADER = 0x55; // 0x58 according to documentation
static const uint8_t BL0940_WRITE_COMMAND = 0xA0; // 0xA8 according to documentation
static const uint8_t BL0940_REG_I_FAST_RMS_CTRL = 0x10;
static const uint8_t BL0940_REG_MODE = 0x18;
static const uint8_t BL0940_REG_SOFT_RESET = 0x19;
static const uint8_t BL0940_REG_USR_WRPROT = 0x1A;
static const uint8_t BL0940_REG_TPS_CTRL = 0x1B;
const uint8_t BL0940_INIT[5][6] = {
// Reset to default
{BL0940_WRITE_COMMAND, BL0940_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38},
// Enable User Operation Write
{BL0940_WRITE_COMMAND, BL0940_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0},
// 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
{BL0940_WRITE_COMMAND, BL0940_REG_MODE, 0x00, 0x10, 0x00, 0x37},
// 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
{BL0940_WRITE_COMMAND, BL0940_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE},
// 0x181C = Half cycle, Fast RMS threshold 6172
{BL0940_WRITE_COMMAND, BL0940_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}};
void BL0940::loop() {
DataPacket buffer;
if (!this->available()) {
return;
}
if (read_array((uint8_t *) &buffer, sizeof(buffer))) {
if (validate_checksum(&buffer)) {
received_package_(&buffer);
}
} else {
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
while (read() >= 0)
;
}
}
bool BL0940::validate_checksum(const DataPacket *data) {
uint8_t checksum = BL0940_READ_COMMAND;
// Whole package but checksum
for (uint32_t i = 0; i < sizeof(data->raw) - 1; i++) {
checksum += data->raw[i];
}
checksum ^= 0xFF;
if (checksum != data->checksum) {
ESP_LOGW(TAG, "BL0940 invalid checksum! 0x%02X != 0x%02X", checksum, data->checksum);
}
return checksum == data->checksum;
}
void BL0940::update() {
this->flush();
this->write_byte(BL0940_READ_COMMAND);
this->write_byte(BL0940_FULL_PACKET);
}
void BL0940::setup() {
for (auto i : BL0940_INIT) {
this->write_array(i, 6);
delay(1);
}
this->flush();
}
float BL0940::update_temp_(sensor::Sensor *sensor, ube16_t temperature) const {
auto tb = (float) (temperature.h << 8 | temperature.l);
float converted_temp = ((float) 170 / 448) * (tb / 2 - 32) - 45;
if (sensor != nullptr) {
if (sensor->has_state() && std::abs(converted_temp - sensor->get_state()) > max_temperature_diff_) {
ESP_LOGD("bl0940", "Invalid temperature change. Sensor: '%s', Old temperature: %f, New temperature: %f",
sensor->get_name().c_str(), sensor->get_state(), converted_temp);
return 0.0f;
}
sensor->publish_state(converted_temp);
}
return converted_temp;
}
void BL0940::received_package_(const DataPacket *data) const {
// Bad header
if (data->frame_header != BL0940_PACKET_HEADER) {
ESP_LOGI("bl0940", "Invalid data. Header mismatch: %d", data->frame_header);
return;
}
float v_rms = (float) to_uint32_t(data->v_rms) / voltage_reference_;
float i_rms = (float) to_uint32_t(data->i_rms) / current_reference_;
float watt = (float) to_int32_t(data->watt) / power_reference_;
uint32_t cf_cnt = to_uint32_t(data->cf_cnt);
float total_energy_consumption = (float) cf_cnt / energy_reference_;
float tps1 = update_temp_(internal_temperature_sensor_, data->tps1);
float tps2 = update_temp_(external_temperature_sensor_, data->tps2);
if (voltage_sensor_ != nullptr) {
voltage_sensor_->publish_state(v_rms);
}
if (current_sensor_ != nullptr) {
current_sensor_->publish_state(i_rms);
}
if (power_sensor_ != nullptr) {
power_sensor_->publish_state(watt);
}
if (energy_sensor_ != nullptr) {
energy_sensor_->publish_state(total_energy_consumption);
}
ESP_LOGV("bl0940", "BL0940: U %fV, I %fA, P %fW, Cnt %d, ∫P %fkWh, T1 %f°C, T2 %f°C", v_rms, i_rms, watt, cf_cnt,
total_energy_consumption, tps1, tps2);
}
void BL0940::dump_config() { // NOLINT(readability-function-cognitive-complexity)
ESP_LOGCONFIG(TAG, "BL0940:");
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
LOG_SENSOR("", "Current", this->current_sensor_);
LOG_SENSOR("", "Power", this->power_sensor_);
LOG_SENSOR("", "Energy", this->energy_sensor_);
LOG_SENSOR("", "Internal temperature", this->internal_temperature_sensor_);
LOG_SENSOR("", "External temperature", this->external_temperature_sensor_);
}
uint32_t BL0940::to_uint32_t(ube24_t input) { return input.h << 16 | input.m << 8 | input.l; }
int32_t BL0940::to_int32_t(sbe24_t input) { return input.h << 16 | input.m << 8 | input.l; }
} // namespace bl0940
} // namespace esphome

View File

@@ -1,109 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/sensor/sensor.h"
namespace esphome {
namespace bl0940 {
static const float BL0940_PREF = 1430;
static const float BL0940_UREF = 33000;
static const float BL0940_IREF = 275000; // 2750 from tasmota. Seems to generate values 100 times too high
// Measured to 297J per click according to power consumption of 5 minutes
// Converted to kWh (3.6MJ per kwH). Used to be 256 * 1638.4
static const float BL0940_EREF = 3.6e6 / 297;
struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l;
uint8_t m;
uint8_t h;
} __attribute__((packed));
struct ube16_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l;
uint8_t h;
} __attribute__((packed));
struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l;
uint8_t m;
int8_t h;
} __attribute__((packed));
// Caveat: All these values are big endian (low - middle - high)
union DataPacket { // NOLINT(altera-struct-pack-align)
uint8_t raw[35];
struct {
uint8_t frame_header; // value of 0x58 according to docs. 0x55 according to Tasmota real world tests. Reality wins.
ube24_t i_fast_rms; // 0x00
ube24_t i_rms; // 0x04
ube24_t RESERVED0; // reserved
ube24_t v_rms; // 0x06
ube24_t RESERVED1; // reserved
sbe24_t watt; // 0x08
ube24_t RESERVED2; // reserved
ube24_t cf_cnt; // 0x0A
ube24_t RESERVED3; // reserved
ube16_t tps1; // 0x0c
uint8_t RESERVED4; // value of 0x00
ube16_t tps2; // 0x0c
uint8_t RESERVED5; // value of 0x00
uint8_t checksum; // checksum
};
} __attribute__((packed));
class BL0940 : public PollingComponent, public uart::UARTDevice {
public:
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void set_internal_temperature_sensor(sensor::Sensor *internal_temperature_sensor) {
internal_temperature_sensor_ = internal_temperature_sensor;
}
void set_external_temperature_sensor(sensor::Sensor *external_temperature_sensor) {
external_temperature_sensor_ = external_temperature_sensor;
}
void loop() override;
void update() override;
void setup() override;
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
// NB This may be negative as the circuits is seemingly able to measure
// power in both directions
sensor::Sensor *power_sensor_;
sensor::Sensor *energy_sensor_;
sensor::Sensor *internal_temperature_sensor_;
sensor::Sensor *external_temperature_sensor_;
// Max difference between two measurements of the temperature. Used to avoid noise.
float max_temperature_diff_{0};
// Divide by this to turn into Watt
float power_reference_ = BL0940_PREF;
// Divide by this to turn into Volt
float voltage_reference_ = BL0940_UREF;
// Divide by this to turn into Ampere
float current_reference_ = BL0940_IREF;
// Divide by this to turn into kWh
float energy_reference_ = BL0940_EREF;
float update_temp_(sensor::Sensor *sensor, ube16_t packed_temperature) const;
static uint32_t to_uint32_t(ube24_t input);
static int32_t to_int32_t(sbe24_t input);
static bool validate_checksum(const DataPacket *data);
void received_package_(const DataPacket *data) const;
};
} // namespace bl0940
} // namespace esphome

View File

@@ -1,106 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, uart
from esphome.const import (
CONF_CURRENT,
CONF_ENERGY,
CONF_ID,
CONF_POWER,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_TEMPERATURE,
ICON_EMPTY,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_AMPERE,
UNIT_CELSIUS,
UNIT_KILOWATT_HOURS,
UNIT_VOLT,
UNIT_WATT,
)
DEPENDENCIES = ["uart"]
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
bl0940_ns = cg.esphome_ns.namespace("bl0940")
BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BL0940),
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
),
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
UNIT_AMPERE,
ICON_EMPTY,
2,
DEVICE_CLASS_CURRENT,
STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_POWER): sensor.sensor_schema(
UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
),
cv.Optional(CONF_ENERGY): sensor.sensor_schema(
UNIT_KILOWATT_HOURS,
ICON_EMPTY,
0,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
),
cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema(
UNIT_CELSIUS,
ICON_EMPTY,
0,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_NONE,
),
cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
UNIT_CELSIUS,
ICON_EMPTY,
0,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_NONE,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(uart.UART_DEVICE_SCHEMA)
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
if CONF_VOLTAGE in config:
conf = config[CONF_VOLTAGE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_voltage_sensor(sens))
if CONF_CURRENT in config:
conf = config[CONF_CURRENT]
sens = await sensor.new_sensor(conf)
cg.add(var.set_current_sensor(sens))
if CONF_POWER in config:
conf = config[CONF_POWER]
sens = await sensor.new_sensor(conf)
cg.add(var.set_power_sensor(sens))
if CONF_ENERGY in config:
conf = config[CONF_ENERGY]
sens = await sensor.new_sensor(conf)
cg.add(var.set_energy_sensor(sens))
if CONF_INTERNAL_TEMPERATURE in config:
conf = config[CONF_INTERNAL_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_internal_temperature_sensor(sens))
if CONF_EXTERNAL_TEMPERATURE in config:
conf = config[CONF_EXTERNAL_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_external_temperature_sensor(sens))

View File

@@ -388,15 +388,6 @@ BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid));
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) {
auto client = this->service->client;
auto status = esp_ble_gattc_write_char(client->gattc_if, client->conn_id, this->handle, new_val_size, new_val,
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending write value to BLE gattc server, status=%d", status);
}
}
} // namespace ble_client
} // namespace esphome

View File

@@ -59,7 +59,7 @@ class BLECharacteristic {
void parse_descriptors();
BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid);
BLEDescriptor *get_descriptor(uint16_t uuid);
void write_value(uint8_t *new_val, int16_t new_val_size);
BLEService *service;
};

View File

@@ -1,67 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output, ble_client, esp32_ble_tracker
from esphome.const import CONF_ID, CONF_SERVICE_UUID
from .. import ble_client_ns
DEPENDENCIES = ["ble_client"]
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
BLEBinaryOutput = ble_client_ns.class_(
"BLEBinaryOutput", output.BinaryOutput, ble_client.BLEClientNode, cg.Component
)
CONFIG_SCHEMA = cv.All(
output.BINARY_OUTPUT_SCHEMA.extend(
{
cv.Required(CONF_ID): cv.declare_id(BLEBinaryOutput),
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(ble_client.BLE_CLIENT_SCHEMA)
)
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
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))
yield output.register_output(var, config)
yield ble_client.register_ble_node(var, config)
yield cg.register_component(var, config)

View File

@@ -1,71 +0,0 @@
#include "ble_binary_output.h"
#include "esphome/core/log.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_binary_output";
void BLEBinaryOutput::dump_config() {
ESP_LOGCONFIG(TAG, "BLE Binary Output:");
ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent_->address_str().c_str());
ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str());
ESP_LOGCONFIG(TAG, " Characteristic UUID: %s", this->char_uuid_.to_string().c_str());
LOG_BINARY_OUTPUT(this);
}
void BLEBinaryOutput::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) {
switch (event) {
case ESP_GATTC_OPEN_EVT:
this->client_state_ = espbt::ClientState::ESTABLISHED;
ESP_LOGW(TAG, "[%s] Connected successfully!", this->char_uuid_.to_string().c_str());
break;
case ESP_GATTC_DISCONNECT_EVT:
ESP_LOGW(TAG, "[%s] Disconnected", this->char_uuid_.to_string().c_str());
this->client_state_ = espbt::ClientState::IDLE;
break;
case ESP_GATTC_WRITE_CHAR_EVT: {
if (param->write.status == 0) {
break;
}
auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] Characteristic not found.", this->char_uuid_.to_string().c_str());
break;
}
if (param->write.handle == chr->handle) {
ESP_LOGW(TAG, "[%s] Write error, status=%d", this->char_uuid_.to_string().c_str(), param->write.status);
}
break;
}
default:
break;
}
}
void BLEBinaryOutput::write_state(bool state) {
if (this->client_state_ != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "[%s] Not connected to BLE client. State update can not be written.",
this->char_uuid_.to_string().c_str());
return;
}
auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] Characteristic not found. State update can not be written.",
this->char_uuid_.to_string().c_str());
return;
}
uint8_t state_as_uint = (uint8_t) state;
ESP_LOGV(TAG, "[%s] Write State: %d", this->char_uuid_.to_string().c_str(), state_as_uint);
chr->write_value(&state_as_uint, sizeof(state_as_uint));
}
} // namespace ble_client
} // namespace esphome
#endif

View File

@@ -1,39 +0,0 @@
#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/output/binary_output.h"
#ifdef USE_ESP32
#include <esp_gattc_api.h>
namespace esphome {
namespace ble_client {
namespace espbt = esphome::esp32_ble_tracker;
class BLEBinaryOutput : public output::BinaryOutput, public BLEClientNode, public Component {
public:
void dump_config() override;
void loop() override {}
float get_setup_priority() const override { return setup_priority::DATA; }
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;
protected:
void write_state(bool state) override;
espbt::ESPBTUUID service_uuid_;
espbt::ESPBTUUID char_uuid_;
espbt::ClientState client_state_;
};
} // namespace ble_client
} // namespace esphome
#endif

View File

@@ -67,7 +67,7 @@ async def to_code(config):
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])
uuid128 = esp32_ble_tracker.as_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):
@@ -87,9 +87,7 @@ async def to_code(config):
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]
)
uuid128 = esp32_ble_tracker.as_hex_array(config[CONF_CHARACTERISTIC_UUID])
cg.add(var.set_char_uuid128(uuid128))
if CONF_DESCRIPTOR_UUID in config:
@@ -110,9 +108,7 @@ async def to_code(config):
elif len(config[CONF_DESCRIPTOR_UUID]) == len(
esp32_ble_tracker.bt_uuid128_format
):
uuid128 = esp32_ble_tracker.as_reversed_hex_array(
config[CONF_DESCRIPTOR_UUID]
)
uuid128 = esp32_ble_tracker.as_hex_array(config[CONF_DESCRIPTOR_UUID])
cg.add(var.set_descr_uuid128(uuid128))
if CONF_LAMBDA in config:

View File

@@ -33,7 +33,6 @@ static const uint8_t BME280_REGISTER_CONTROLHUMID = 0xF2;
static const uint8_t BME280_REGISTER_STATUS = 0xF3;
static const uint8_t BME280_REGISTER_CONTROL = 0xF4;
static const uint8_t BME280_REGISTER_CONFIG = 0xF5;
static const uint8_t BME280_REGISTER_MEASUREMENTS = 0xF7;
static const uint8_t BME280_REGISTER_PRESSUREDATA = 0xF7;
static const uint8_t BME280_REGISTER_TEMPDATA = 0xFA;
static const uint8_t BME280_REGISTER_HUMIDDATA = 0xFD;
@@ -179,29 +178,23 @@ void BME280Component::update() {
return;
}
float meas_time = 1.5f;
float meas_time = 1.5;
meas_time += 2.3f * oversampling_to_time(this->temperature_oversampling_);
meas_time += 2.3f * oversampling_to_time(this->pressure_oversampling_) + 0.575f;
meas_time += 2.3f * oversampling_to_time(this->humidity_oversampling_) + 0.575f;
this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
uint8_t data[8];
if (!this->read_bytes(BME280_REGISTER_MEASUREMENTS, data, 8)) {
ESP_LOGW(TAG, "Error reading registers.");
this->status_set_warning();
return;
}
int32_t t_fine = 0;
float temperature = this->read_temperature_(data, &t_fine);
float temperature = this->read_temperature_(&t_fine);
if (std::isnan(temperature)) {
ESP_LOGW(TAG, "Invalid temperature, cannot read pressure & humidity values.");
this->status_set_warning();
return;
}
float pressure = this->read_pressure_(data, t_fine);
float humidity = this->read_humidity_(data, t_fine);
float pressure = this->read_pressure_(t_fine);
float humidity = this->read_humidity_(t_fine);
ESP_LOGV(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%%", temperature, pressure, humidity);
ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%%", temperature, pressure, humidity);
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->pressure_sensor_ != nullptr)
@@ -211,8 +204,11 @@ void BME280Component::update() {
this->status_clear_warning();
});
}
float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) {
int32_t adc = ((data[3] & 0xFF) << 16) | ((data[4] & 0xFF) << 8) | (data[5] & 0xFF);
float BME280Component::read_temperature_(int32_t *t_fine) {
uint8_t data[3];
if (!this->read_bytes(BME280_REGISTER_TEMPDATA, data, 3))
return NAN;
int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
adc >>= 4;
if (adc == 0x80000)
// temperature was disabled
@@ -230,7 +226,10 @@ float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) {
return temperature / 100.0f;
}
float BME280Component::read_pressure_(const uint8_t *data, int32_t t_fine) {
float BME280Component::read_pressure_(int32_t t_fine) {
uint8_t data[3];
if (!this->read_bytes(BME280_REGISTER_PRESSUREDATA, data, 3))
return NAN;
int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
adc >>= 4;
if (adc == 0x80000)
@@ -266,9 +265,9 @@ float BME280Component::read_pressure_(const uint8_t *data, int32_t t_fine) {
return (p / 256.0f) / 100.0f;
}
float BME280Component::read_humidity_(const uint8_t *data, int32_t t_fine) {
uint16_t raw_adc = ((data[6] & 0xFF) << 8) | (data[7] & 0xFF);
if (raw_adc == 0x8000)
float BME280Component::read_humidity_(int32_t t_fine) {
uint16_t raw_adc;
if (!this->read_byte_16(BME280_REGISTER_HUMIDDATA, &raw_adc) || raw_adc == 0x8000)
return NAN;
int32_t adc = raw_adc;

View File

@@ -82,11 +82,11 @@ class BME280Component : public PollingComponent, public i2c::I2CDevice {
protected:
/// Read the temperature value and store the calculated ambient temperature in t_fine.
float read_temperature_(const uint8_t *data, int32_t *t_fine);
float read_temperature_(int32_t *t_fine);
/// Read the pressure value in hPa using the provided t_fine value.
float read_pressure_(const uint8_t *data, int32_t t_fine);
float read_pressure_(int32_t t_fine);
/// Read the humidity value in % using the provided t_fine value.
float read_humidity_(const uint8_t *data, int32_t t_fine);
float read_humidity_(int32_t t_fine);
uint8_t read_u8_(uint8_t a_register);
uint16_t read_u16_le_(uint8_t a_register);
int16_t read_s16_le_(uint8_t a_register);

View File

@@ -1,388 +0,0 @@
/*
based on BMP388_DEV by Martin Lindupp
under MIT License (MIT)
Copyright (C) Martin Lindupp 2020
http://github.com/MartinL1/BMP388_DEV
*/
#include "bmp3xx.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace bmp3xx {
static const char *const TAG = "bmp3xx.sensor";
static const LogString *chip_type_to_str(uint8_t chip_type) {
switch (chip_type) {
case BMP388_ID:
return LOG_STR("BMP 388");
case BMP390_ID:
return LOG_STR("BMP 390");
default:
return LOG_STR("Unknown Chip Type");
}
}
static const LogString *oversampling_to_str(Oversampling oversampling) {
switch (oversampling) {
case Oversampling::OVERSAMPLING_NONE:
return LOG_STR("None");
case Oversampling::OVERSAMPLING_X2:
return LOG_STR("2x");
case Oversampling::OVERSAMPLING_X4:
return LOG_STR("4x");
case Oversampling::OVERSAMPLING_X8:
return LOG_STR("8x");
case Oversampling::OVERSAMPLING_X16:
return LOG_STR("16x");
case Oversampling::OVERSAMPLING_X32:
return LOG_STR("32x");
default:
return LOG_STR("");
}
}
static const LogString *iir_filter_to_str(IIRFilter filter) {
switch (filter) {
case IIRFilter::IIR_FILTER_OFF:
return LOG_STR("OFF");
case IIRFilter::IIR_FILTER_2:
return LOG_STR("2x");
case IIRFilter::IIR_FILTER_4:
return LOG_STR("4x");
case IIRFilter::IIR_FILTER_8:
return LOG_STR("8x");
case IIRFilter::IIR_FILTER_16:
return LOG_STR("16x");
case IIRFilter::IIR_FILTER_32:
return LOG_STR("32x");
case IIRFilter::IIR_FILTER_64:
return LOG_STR("64x");
case IIRFilter::IIR_FILTER_128:
return LOG_STR("128x");
default:
return LOG_STR("");
}
}
void BMP3XXComponent::setup() {
this->error_code_ = NONE;
ESP_LOGCONFIG(TAG, "Setting up BMP3XX...");
// Call the Device base class "initialise" function
if (!reset()) {
ESP_LOGE(TAG, "Failed to reset BMP3XX...");
this->error_code_ = ERROR_SENSOR_RESET;
this->mark_failed();
}
if (!read_byte(BMP388_CHIP_ID, &this->chip_id_.reg)) {
ESP_LOGE(TAG, "Can't read chip id");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
ESP_LOGCONFIG(TAG, "Chip %s Id 0x%X", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
if (chip_id_.reg != BMP388_ID && chip_id_.reg != BMP390_ID) {
ESP_LOGE(TAG, "Unknown chip id - is this really a BMP388 or BMP390?");
this->error_code_ = ERROR_WRONG_CHIP_ID;
this->mark_failed();
return;
}
// set sensor in sleep mode
stop_conversion();
// Read the calibration parameters into the params structure
if (!read_bytes(BMP388_TRIM_PARAMS, (uint8_t *) &compensation_params_, sizeof(compensation_params_))) {
ESP_LOGE(TAG, "Can't read calibration data");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
compensation_float_params_.param_T1 =
(float) compensation_params_.param_T1 / powf(2.0f, -8.0f); // Calculate the floating point trim parameters
compensation_float_params_.param_T2 = (float) compensation_params_.param_T2 / powf(2.0f, 30.0f);
compensation_float_params_.param_T3 = (float) compensation_params_.param_T3 / powf(2.0f, 48.0f);
compensation_float_params_.param_P1 = ((float) compensation_params_.param_P1 - powf(2.0f, 14.0f)) / powf(2.0f, 20.0f);
compensation_float_params_.param_P2 = ((float) compensation_params_.param_P2 - powf(2.0f, 14.0f)) / powf(2.0f, 29.0f);
compensation_float_params_.param_P3 = (float) compensation_params_.param_P3 / powf(2.0f, 32.0f);
compensation_float_params_.param_P4 = (float) compensation_params_.param_P4 / powf(2.0f, 37.0f);
compensation_float_params_.param_P5 = (float) compensation_params_.param_P5 / powf(2.0f, -3.0f);
compensation_float_params_.param_P6 = (float) compensation_params_.param_P6 / powf(2.0f, 6.0f);
compensation_float_params_.param_P7 = (float) compensation_params_.param_P7 / powf(2.0f, 8.0f);
compensation_float_params_.param_P8 = (float) compensation_params_.param_P8 / powf(2.0f, 15.0f);
compensation_float_params_.param_P9 = (float) compensation_params_.param_P9 / powf(2.0f, 48.0f);
compensation_float_params_.param_P10 = (float) compensation_params_.param_P10 / powf(2.0f, 48.0f);
compensation_float_params_.param_P11 = (float) compensation_params_.param_P11 / powf(2.0f, 65.0f);
// Initialise the BMP388 IIR filter register
if (!set_iir_filter(this->iir_filter_)) {
ESP_LOGE(TAG, "Failed to set IIR filter");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
// Set power control registers
pwr_ctrl_.bit.press_en = 1;
pwr_ctrl_.bit.temp_en = 1;
// Disable pressure if no sensor defined
// keep temperature enabled since it's needed for compensation
if (this->pressure_sensor_ == nullptr) {
pwr_ctrl_.bit.press_en = 0;
this->pressure_oversampling_ = OVERSAMPLING_NONE;
}
// just disable oeversampling for temp if not used
if (this->temperature_sensor_ == nullptr) {
this->temperature_oversampling_ = OVERSAMPLING_NONE;
}
// Initialise the BMP388 oversampling register
if (!set_oversampling_register(this->pressure_oversampling_, this->temperature_oversampling_)) {
ESP_LOGE(TAG, "Failed to set oversampling register");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
}
void BMP3XXComponent::dump_config() {
ESP_LOGCONFIG(TAG, "BMP3XX:");
ESP_LOGCONFIG(TAG, " Type: %s (0x%X)", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
LOG_I2C_DEVICE(this);
switch (this->error_code_) {
case NONE:
break;
case ERROR_COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Communication with BMP3XX failed!");
break;
case ERROR_WRONG_CHIP_ID:
ESP_LOGE(
TAG,
"BMP3XX has wrong chip ID (reported id: 0x%X) - please check if you are really using a BMP 388 or BMP 390",
this->chip_id_.reg);
break;
case ERROR_SENSOR_RESET:
ESP_LOGE(TAG, "BMP3XX failed to reset");
break;
default:
ESP_LOGE(TAG, "BMP3XX error code %d", (int) this->error_code_);
break;
}
ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_filter_)));
LOG_UPDATE_INTERVAL(this);
if (this->temperature_sensor_) {
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_)));
}
if (this->pressure_sensor_) {
LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_)));
}
}
float BMP3XXComponent::get_setup_priority() const { return setup_priority::DATA; }
inline uint8_t oversampling_to_time(Oversampling over_sampling) { return (1 << uint8_t(over_sampling)); }
void BMP3XXComponent::update() {
// Enable sensor
ESP_LOGV(TAG, "Sending conversion request...");
float meas_time = 1.0f;
// Ref: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf 3.9.2
meas_time += 2.02f * oversampling_to_time(this->temperature_oversampling_) + 0.163f;
meas_time += 2.02f * oversampling_to_time(this->pressure_oversampling_) + 0.392f;
meas_time += 0.234f;
if (!set_mode(FORCED_MODE)) {
ESP_LOGE(TAG, "Failed start forced mode");
this->mark_failed();
return;
}
ESP_LOGVV(TAG, "measurement time %d", uint32_t(ceilf(meas_time)));
this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
float temperature = 0.0f;
float pressure = 0.0f;
if (this->pressure_sensor_ != nullptr) {
if (!get_measurements(temperature, pressure)) {
ESP_LOGW(TAG, "Failed to read pressure and temperature - skipping update");
this->status_set_warning();
return;
}
ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa", temperature, pressure);
} else {
if (!get_temperature(temperature)) {
ESP_LOGW(TAG, "Failed to read temperature - skipping update");
this->status_set_warning();
return;
}
ESP_LOGD(TAG, "Got temperature=%.1f°C", temperature);
}
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->pressure_sensor_ != nullptr)
this->pressure_sensor_->publish_state(pressure);
this->status_clear_warning();
set_mode(SLEEP_MODE);
});
}
// Reset the BMP3XX
uint8_t BMP3XXComponent::reset() {
write_byte(BMP388_CMD, RESET_CODE); // Write the reset code to the command register
// Wait for 10ms
delay(10);
this->read_byte(BMP388_EVENT, &event_.reg); // Read the BMP388's event register
return event_.bit.por_detected; // Return if device reset is complete
}
// Start a one shot measurement in FORCED_MODE
bool BMP3XXComponent::start_forced_conversion() {
// Only set FORCED_MODE if we're already in SLEEP_MODE
if (pwr_ctrl_.bit.mode == SLEEP_MODE) {
return set_mode(FORCED_MODE);
}
return true;
}
// Stop the conversion and return to SLEEP_MODE
bool BMP3XXComponent::stop_conversion() { return set_mode(SLEEP_MODE); }
// Set the pressure oversampling rate
bool BMP3XXComponent::set_pressure_oversampling(Oversampling oversampling) {
osr_.bit.osr_p = oversampling;
return this->write_byte(BMP388_OSR, osr_.reg);
}
// Set the temperature oversampling rate
bool BMP3XXComponent::set_temperature_oversampling(Oversampling oversampling) {
osr_.bit.osr_t = oversampling;
return this->write_byte(BMP388_OSR, osr_.reg);
}
// Set the IIR filter setting
bool BMP3XXComponent::set_iir_filter(IIRFilter iir_filter) {
config_.bit.iir_filter = iir_filter;
return this->write_byte(BMP388_CONFIG, config_.reg);
}
// Get temperature
bool BMP3XXComponent::get_temperature(float &temperature) {
// Check if a measurement is ready
if (!data_ready()) {
return false;
}
uint8_t data[3];
// Read the temperature
if (!this->read_bytes(BMP388_DATA_3, &data[0], 3)) {
ESP_LOGE(TAG, "Failed to read temperature");
return false;
}
// Copy the temperature data into the adc variables
int32_t adc_temp = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0];
// Temperature compensation (function from BMP388 datasheet)
temperature = bmp388_compensate_temperature_((float) adc_temp);
return true;
}
// Get the pressure
bool BMP3XXComponent::get_pressure(float &pressure) {
float temperature;
return get_measurements(temperature, pressure);
}
// Get temperature and pressure
bool BMP3XXComponent::get_measurements(float &temperature, float &pressure) {
// Check if a measurement is ready
if (!data_ready()) {
ESP_LOGD(TAG, "BMP3XX Get measurement - data not ready skipping update");
return false;
}
uint8_t data[6];
// Read the temperature and pressure data
if (!this->read_bytes(BMP388_DATA_0, &data[0], 6)) {
ESP_LOGE(TAG, "Failed to read measurements");
return false;
}
// Copy the temperature and pressure data into the adc variables
int32_t adc_pres = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0];
int32_t adc_temp = (int32_t) data[5] << 16 | (int32_t) data[4] << 8 | (int32_t) data[3];
// Temperature compensation (function from BMP388 datasheet)
temperature = bmp388_compensate_temperature_((float) adc_temp);
// Pressure compensation (function from BMP388 datasheet)
pressure = bmp388_compensate_pressure_((float) adc_pres, temperature);
// Calculate the pressure in millibar/hPa
pressure /= 100.0f;
return true;
}
// Set the BMP388's mode in the power control register
bool BMP3XXComponent::set_mode(OperationMode mode) {
pwr_ctrl_.bit.mode = mode;
return this->write_byte(BMP388_PWR_CTRL, pwr_ctrl_.reg);
}
// Set the BMP388 oversampling register
bool BMP3XXComponent::set_oversampling_register(Oversampling pressure_oversampling,
Oversampling temperature_oversampling) {
osr_.reg = temperature_oversampling << 3 | pressure_oversampling;
return this->write_byte(BMP388_OSR, osr_.reg);
}
// Check if measurement data is ready
bool BMP3XXComponent::data_ready() {
// If we're in SLEEP_MODE return immediately
if (pwr_ctrl_.bit.mode == SLEEP_MODE) {
ESP_LOGD(TAG, "Not ready - sensor is in sleep mode");
return false;
}
// Read the interrupt status register
uint8_t status;
if (!this->read_byte(BMP388_INT_STATUS, &status)) {
ESP_LOGE(TAG, "Failed to read status register");
return false;
}
int_status_.reg = status;
ESP_LOGVV(TAG, "data ready status %d", status);
// If we're in FORCED_MODE switch back to SLEEP_MODE
if (int_status_.bit.drdy) {
if (pwr_ctrl_.bit.mode == FORCED_MODE) {
pwr_ctrl_.bit.mode = SLEEP_MODE;
}
return true; // The measurement is ready
}
return false; // The measurement is still pending
}
////////////////////////////////////////////////////////////////////////////////
// Bosch BMP3XXComponent (Private) Member Functions
////////////////////////////////////////////////////////////////////////////////
float BMP3XXComponent::bmp388_compensate_temperature_(float uncomp_temp) {
float partial_data1 = uncomp_temp - compensation_float_params_.param_T1;
float partial_data2 = partial_data1 * compensation_float_params_.param_T2;
return partial_data2 + partial_data1 * partial_data1 * compensation_float_params_.param_T3;
}
float BMP3XXComponent::bmp388_compensate_pressure_(float uncomp_press, float t_lin) {
float partial_data1 = compensation_float_params_.param_P6 * t_lin;
float partial_data2 = compensation_float_params_.param_P7 * t_lin * t_lin;
float partial_data3 = compensation_float_params_.param_P8 * t_lin * t_lin * t_lin;
float partial_out1 = compensation_float_params_.param_P5 + partial_data1 + partial_data2 + partial_data3;
partial_data1 = compensation_float_params_.param_P2 * t_lin;
partial_data2 = compensation_float_params_.param_P3 * t_lin * t_lin;
partial_data3 = compensation_float_params_.param_P4 * t_lin * t_lin * t_lin;
float partial_out2 =
uncomp_press * (compensation_float_params_.param_P1 + partial_data1 + partial_data2 + partial_data3);
partial_data1 = uncomp_press * uncomp_press;
partial_data2 = compensation_float_params_.param_P9 + compensation_float_params_.param_P10 * t_lin;
partial_data3 = partial_data1 * partial_data2;
float partial_data4 =
partial_data3 + uncomp_press * uncomp_press * uncomp_press * compensation_float_params_.param_P11;
return partial_out1 + partial_out2 + partial_data4;
}
} // namespace bmp3xx
} // namespace esphome

View File

@@ -1,237 +0,0 @@
/*
based on BMP388_DEV by Martin Lindupp
under MIT License (MIT)
Copyright (C) Martin Lindupp 2020
http://github.com/MartinL1/BMP388_DEV
*/
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace bmp3xx {
static const uint8_t BMP388_ID = 0x50; // The BMP388 device ID
static const uint8_t BMP390_ID = 0x60; // The BMP390 device ID
static const uint8_t RESET_CODE = 0xB6; // The BMP388 reset code
/// BMP388_DEV Registers
enum {
BMP388_CHIP_ID = 0x00, // Chip ID register sub-address
BMP388_ERR_REG = 0x02, // Error register sub-address
BMP388_STATUS = 0x03, // Status register sub-address
BMP388_DATA_0 = 0x04, // Pressure eXtended Least Significant Byte (XLSB) register sub-address
BMP388_DATA_1 = 0x05, // Pressure Least Significant Byte (LSB) register sub-address
BMP388_DATA_2 = 0x06, // Pressure Most Significant Byte (MSB) register sub-address
BMP388_DATA_3 = 0x07, // Temperature eXtended Least Significant Byte (XLSB) register sub-address
BMP388_DATA_4 = 0x08, // Temperature Least Significant Byte (LSB) register sub-address
BMP388_DATA_5 = 0x09, // Temperature Most Significant Byte (MSB) register sub-address
BMP388_SENSORTIME_0 = 0x0C, // Sensor time register 0 sub-address
BMP388_SENSORTIME_1 = 0x0D, // Sensor time register 1 sub-address
BMP388_SENSORTIME_2 = 0x0E, // Sensor time register 2 sub-address
BMP388_EVENT = 0x10, // Event register sub-address
BMP388_INT_STATUS = 0x11, // Interrupt Status register sub-address
BMP388_INT_CTRL = 0x19, // Interrupt Control register sub-address
BMP388_IF_CONFIG = 0x1A, // Interface Configuration register sub-address
BMP388_PWR_CTRL = 0x1B, // Power Control register sub-address
BMP388_OSR = 0x1C, // Oversampling register sub-address
BMP388_ODR = 0x1D, // Output Data Rate register sub-address
BMP388_CONFIG = 0x1F, // Configuration register sub-address
BMP388_TRIM_PARAMS = 0x31, // Trim parameter registers' base sub-address
BMP388_CMD = 0x7E // Command register sub-address
};
/// Device mode bitfield in the control and measurement register
enum OperationMode { SLEEP_MODE = 0x00, FORCED_MODE = 0x01, NORMAL_MODE = 0x03 };
/// Oversampling bit fields in the control and measurement register
enum Oversampling {
OVERSAMPLING_NONE = 0x00,
OVERSAMPLING_X2 = 0x01,
OVERSAMPLING_X4 = 0x02,
OVERSAMPLING_X8 = 0x03,
OVERSAMPLING_X16 = 0x04,
OVERSAMPLING_X32 = 0x05
};
/// Infinite Impulse Response (IIR) filter bit field in the configuration register
enum IIRFilter {
IIR_FILTER_OFF = 0x00,
IIR_FILTER_2 = 0x01,
IIR_FILTER_4 = 0x02,
IIR_FILTER_8 = 0x03,
IIR_FILTER_16 = 0x04,
IIR_FILTER_32 = 0x05,
IIR_FILTER_64 = 0x06,
IIR_FILTER_128 = 0x07
};
/// This class implements support for the BMP3XX Temperature+Pressure i2c sensor.
class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void update() override;
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
/// Set the oversampling value for the temperature sensor. Default is 16x.
void set_temperature_oversampling_config(Oversampling temperature_oversampling) {
this->temperature_oversampling_ = temperature_oversampling;
}
/// Set the oversampling value for the pressure sensor. Default is 16x.
void set_pressure_oversampling_config(Oversampling pressure_oversampling) {
this->pressure_oversampling_ = pressure_oversampling;
}
/// Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
void set_iir_filter_config(IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
/// Soft reset the sensor
uint8_t reset();
/// Start continuous measurement in NORMAL_MODE
bool start_normal_conversion();
/// Start a one shot measurement in FORCED_MODE
bool start_forced_conversion();
/// Stop the conversion and return to SLEEP_MODE
bool stop_conversion();
/// Set the pressure oversampling: OFF, X1, X2, X4, X8, X16, X32
bool set_pressure_oversampling(Oversampling pressure_oversampling);
/// Set the temperature oversampling: OFF, X1, X2, X4, X8, X16, X32
bool set_temperature_oversampling(Oversampling temperature_oversampling);
/// Set the IIR filter setting: OFF, 2, 3, 8, 16, 32
bool set_iir_filter(IIRFilter iir_filter);
/// Get a temperature measurement
bool get_temperature(float &temperature);
/// Get a pressure measurement
bool get_pressure(float &pressure);
/// Get a temperature and pressure measurement
bool get_measurements(float &temperature, float &pressure);
/// Get a temperature and pressure measurement
bool get_measurement();
/// Set the barometer mode
bool set_mode(OperationMode mode);
/// Set the BMP388 oversampling register
bool set_oversampling_register(Oversampling pressure_oversampling, Oversampling temperature_oversampling);
/// Checks if a measurement is ready
bool data_ready();
protected:
Oversampling temperature_oversampling_{OVERSAMPLING_X16};
Oversampling pressure_oversampling_{OVERSAMPLING_X16};
IIRFilter iir_filter_{IIR_FILTER_OFF};
OperationMode operation_mode_{FORCED_MODE};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
enum ErrorCode {
NONE = 0,
ERROR_COMMUNICATION_FAILED,
ERROR_WRONG_CHIP_ID,
ERROR_SENSOR_STATUS,
ERROR_SENSOR_RESET,
} error_code_{NONE};
struct { // The BMP388 compensation trim parameters (coefficients)
uint16_t param_T1;
uint16_t param_T2;
int8_t param_T3;
int16_t param_P1;
int16_t param_P2;
int8_t param_P3;
int8_t param_P4;
uint16_t param_P5;
uint16_t param_P6;
int8_t param_P7;
int8_t param_P8;
int16_t param_P9;
int8_t param_P10;
int8_t param_P11;
} __attribute__((packed)) compensation_params_;
struct FloatParams { // The BMP388 float point compensation trim parameters
float param_T1;
float param_T2;
float param_T3;
float param_P1;
float param_P2;
float param_P3;
float param_P4;
float param_P5;
float param_P6;
float param_P7;
float param_P8;
float param_P9;
float param_P10;
float param_P11;
} compensation_float_params_;
union { // Copy of the BMP388's chip id register
struct {
uint8_t chip_id_nvm : 4;
uint8_t chip_id_fixed : 4;
} bit;
uint8_t reg;
} chip_id_ = {.reg = 0};
union { // Copy of the BMP388's event register
struct {
uint8_t por_detected : 1;
} bit;
uint8_t reg;
} event_ = {.reg = 0};
union { // Copy of the BMP388's interrupt status register
struct {
uint8_t fwm_int : 1;
uint8_t ffull_int : 1;
uint8_t : 1;
uint8_t drdy : 1;
} bit;
uint8_t reg;
} int_status_ = {.reg = 0};
union { // Copy of the BMP388's power control register
struct {
uint8_t press_en : 1;
uint8_t temp_en : 1;
uint8_t : 2;
uint8_t mode : 2;
} bit;
uint8_t reg;
} pwr_ctrl_ = {.reg = 0};
union { // Copy of the BMP388's oversampling register
struct {
uint8_t osr_p : 3;
uint8_t osr_t : 3;
} bit;
uint8_t reg;
} osr_ = {.reg = 0};
union { // Copy of the BMP388's output data rate register
struct {
uint8_t odr_sel : 5;
} bit;
uint8_t reg;
} odr_ = {.reg = 0};
union { // Copy of the BMP388's configuration register
struct {
uint8_t : 1;
uint8_t iir_filter : 3;
} bit;
uint8_t reg;
} config_ = {.reg = 0};
// Bosch temperature compensation function
float bmp388_compensate_temperature_(float uncomp_temp);
// Bosch pressure compensation function
float bmp388_compensate_pressure_(float uncomp_press, float t_lin);
};
} // namespace bmp3xx
} // namespace esphome

View File

@@ -1,100 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
CONF_IIR_FILTER,
CONF_OVERSAMPLING,
CONF_PRESSURE,
CONF_TEMPERATURE,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_HECTOPASCAL,
)
CODEOWNERS = ["@martgras"]
DEPENDENCIES = ["i2c"]
bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx")
Oversampling = bmp3xx_ns.enum("Oversampling")
OVERSAMPLING_OPTIONS = {
"NONE": Oversampling.OVERSAMPLING_NONE,
"2X": Oversampling.OVERSAMPLING_X2,
"4X": Oversampling.OVERSAMPLING_X4,
"8X": Oversampling.OVERSAMPLING_X8,
"16X": Oversampling.OVERSAMPLING_X16,
"32x": Oversampling.OVERSAMPLING_X32,
}
IIRFilter = bmp3xx_ns.enum("IIRFilter")
IIR_FILTER_OPTIONS = {
"OFF": IIRFilter.IIR_FILTER_OFF,
"2X": IIRFilter.IIR_FILTER_2,
"4X": IIRFilter.IIR_FILTER_4,
"8X": IIRFilter.IIR_FILTER_8,
"16X": IIRFilter.IIR_FILTER_16,
"32X": IIRFilter.IIR_FILTER_32,
"64X": IIRFilter.IIR_FILTER_64,
"128X": IIRFilter.IIR_FILTER_128,
}
BMP3XXComponent = bmp3xx_ns.class_(
"BMP3XXComponent", cg.PollingComponent, i2c.I2CDevice
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BMP3XXComponent),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="2X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
unit_of_measurement=UNIT_HECTOPASCAL,
accuracy_decimals=1,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
IIR_FILTER_OPTIONS, upper=True
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x77))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER]))
if CONF_TEMPERATURE in config:
conf = config[CONF_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_temperature_sensor(sens))
cg.add(var.set_temperature_oversampling_config(conf[CONF_OVERSAMPLING]))
if CONF_PRESSURE in config:
conf = config[CONF_PRESSURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_pressure_sensor(sens))
cg.add(var.set_pressure_oversampling_config(conf[CONF_OVERSAMPLING]))

View File

@@ -1,127 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.automation import maybe_simple_id
from esphome.components import mqtt
from esphome.const import (
CONF_DEVICE_CLASS,
CONF_ENTITY_CATEGORY,
CONF_ICON,
CONF_ID,
CONF_ON_PRESS,
CONF_TRIGGER_ID,
CONF_MQTT_ID,
DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.cpp_helpers import setup_entity
CODEOWNERS = ["@esphome/core"]
IS_PLATFORM_COMPONENT = True
DEVICE_CLASSES = [
DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE,
]
button_ns = cg.esphome_ns.namespace("button")
Button = button_ns.class_("Button", cg.EntityBase)
ButtonPtr = Button.operator("ptr")
PressAction = button_ns.class_("PressAction", automation.Action)
ButtonPressTrigger = button_ns.class_(
"ButtonPressTrigger", automation.Trigger.template()
)
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
BUTTON_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
{
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent),
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
cv.Optional(CONF_ON_PRESS): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger),
}
),
}
)
_UNDEF = object()
def button_schema(
icon: str = _UNDEF,
entity_category: str = _UNDEF,
device_class: str = _UNDEF,
) -> cv.Schema:
schema = BUTTON_SCHEMA
if icon is not _UNDEF:
schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
if entity_category is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_ENTITY_CATEGORY, default=entity_category
): cv.entity_category
}
)
if device_class is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_DEVICE_CLASS, default=device_class
): validate_device_class
}
)
return schema
async def setup_button_core_(var, config):
await setup_entity(var, config)
for conf in config.get(CONF_ON_PRESS, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
if CONF_DEVICE_CLASS in config:
cg.add(var.set_device_class(config[CONF_DEVICE_CLASS]))
if CONF_MQTT_ID in config:
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
await mqtt.register_mqtt_component(mqtt_, config)
async def register_button(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_button(var))
await setup_button_core_(var, config)
async def new_button(config):
var = cg.new_Pvariable(config[CONF_ID])
await register_button(var, config)
return var
BUTTON_PRESS_SCHEMA = maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(Button),
}
)
@automation.register_action("button.press", PressAction, BUTTON_PRESS_SCHEMA)
async def button_press_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@coroutine_with_priority(100.0)
async def to_code(config):
cg.add_global(button_ns.using)
cg.add_define("USE_BUTTON")

View File

@@ -1,28 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
namespace esphome {
namespace button {
template<typename... Ts> class PressAction : public Action<Ts...> {
public:
explicit PressAction(Button *button) : button_(button) {}
void play(Ts... x) override { this->button_->press(); }
protected:
Button *button_;
};
class ButtonPressTrigger : public Trigger<> {
public:
ButtonPressTrigger(Button *button) {
button->add_on_press_callback([this]() { this->trigger(); });
}
};
} // namespace button
} // namespace esphome

View File

@@ -1,28 +0,0 @@
#include "button.h"
#include "esphome/core/log.h"
namespace esphome {
namespace button {
static const char *const TAG = "button";
Button::Button(const std::string &name) : EntityBase(name) {}
Button::Button() : Button("") {}
void Button::press() {
ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str());
this->press_action();
this->press_callback_.call();
}
void Button::add_on_press_callback(std::function<void()> &&callback) { this->press_callback_.add(std::move(callback)); }
uint32_t Button::hash_base() { return 1495763804UL; }
void Button::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
std::string Button::get_device_class() {
if (this->device_class_.has_value())
return *this->device_class_;
return "";
}
} // namespace button
} // namespace esphome

View File

@@ -1,57 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace button {
#define LOG_BUTTON(prefix, type, obj) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
} \
}
/** Base class for all buttons.
*
* A button is just a momentary switch that does not have a state, only a trigger.
*/
class Button : public EntityBase {
public:
explicit Button();
explicit Button(const std::string &name);
/** Press this button. This is called by the front-end.
*
* For implementing buttons, please override press_action.
*/
void press();
/** Set callback for state changes.
*
* @param callback The void() callback.
*/
void add_on_press_callback(std::function<void()> &&callback);
/// Set the Home Assistant device class (see button::device_class).
void set_device_class(const std::string &device_class);
/// Get the device class for this button.
std::string get_device_class();
protected:
/** You should implement this virtual method if you want to create your own button.
*/
virtual void press_action(){};
uint32_t hash_base() override;
CallbackManager<void()> press_callback_{};
optional<std::string> device_class_{};
};
} // namespace button
} // namespace esphome

View File

@@ -85,7 +85,14 @@ void CaptivePortal::start() {
this->dns_server_->start(53, "*", (uint32_t) ip);
this->base_->get_server()->onNotFound([this](AsyncWebServerRequest *req) {
if (!this->active_ || req->host().c_str() == wifi::global_wifi_component->wifi_soft_ap_ip().str()) {
bool not_found = false;
if (!this->active_) {
not_found = true;
} else if (req->host().c_str() == wifi::global_wifi_component->wifi_soft_ap_ip().str()) {
not_found = true;
}
if (not_found) {
req->send(404, "text/html", "File not found");
return;
}

View File

@@ -1,53 +0,0 @@
import esphome.codegen as cg
from esphome import pins
import esphome.config_validation as cv
from esphome.const import (
CONF_DELAY,
CONF_ID,
)
CODEOWNERS = ["@asoehlke"]
AUTO_LOAD = ["sensor", "voltage_sampler"]
cd74hc4067_ns = cg.esphome_ns.namespace("cd74hc4067")
CD74HC4067Component = cd74hc4067_ns.class_(
"CD74HC4067Component", cg.Component, cg.PollingComponent
)
CONF_PIN_S0 = "pin_s0"
CONF_PIN_S1 = "pin_s1"
CONF_PIN_S2 = "pin_s2"
CONF_PIN_S3 = "pin_s3"
DEFAULT_DELAY = "2ms"
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CD74HC4067Component),
cv.Required(CONF_PIN_S0): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_PIN_S1): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_PIN_S2): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_PIN_S3): pins.internal_gpio_output_pin_schema,
cv.Optional(
CONF_DELAY, default=DEFAULT_DELAY
): cv.positive_time_period_milliseconds,
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
pin_s0 = await cg.gpio_pin_expression(config[CONF_PIN_S0])
cg.add(var.set_pin_s0(pin_s0))
pin_s1 = await cg.gpio_pin_expression(config[CONF_PIN_S1])
cg.add(var.set_pin_s1(pin_s1))
pin_s2 = await cg.gpio_pin_expression(config[CONF_PIN_S2])
cg.add(var.set_pin_s2(pin_s2))
pin_s3 = await cg.gpio_pin_expression(config[CONF_PIN_S3])
cg.add(var.set_pin_s3(pin_s3))
cg.add(var.set_switch_delay(config[CONF_DELAY]))

View File

@@ -1,86 +0,0 @@
#include "cd74hc4067.h"
#include "esphome/core/log.h"
namespace esphome {
namespace cd74hc4067 {
static const char *const TAG = "cd74hc4067";
float CD74HC4067Component::get_setup_priority() const { return setup_priority::DATA; }
void CD74HC4067Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up CD74HC4067...");
this->pin_s0_->setup();
this->pin_s1_->setup();
this->pin_s2_->setup();
this->pin_s3_->setup();
// set other pin, so that activate_pin will really switch
this->active_pin_ = 1;
this->activate_pin(0);
}
void CD74HC4067Component::dump_config() {
ESP_LOGCONFIG(TAG, "CD74HC4067 Multiplexer:");
LOG_PIN(" S0 Pin: ", this->pin_s0_);
LOG_PIN(" S1 Pin: ", this->pin_s1_);
LOG_PIN(" S2 Pin: ", this->pin_s2_);
LOG_PIN(" S3 Pin: ", this->pin_s3_);
ESP_LOGCONFIG(TAG, "switch delay: %d", this->switch_delay_);
}
void CD74HC4067Component::activate_pin(uint8_t pin) {
if (this->active_pin_ != pin) {
ESP_LOGD(TAG, "switch to input %d", pin);
static int mux_channel[16][4] = {
{0, 0, 0, 0}, // channel 0
{1, 0, 0, 0}, // channel 1
{0, 1, 0, 0}, // channel 2
{1, 1, 0, 0}, // channel 3
{0, 0, 1, 0}, // channel 4
{1, 0, 1, 0}, // channel 5
{0, 1, 1, 0}, // channel 6
{1, 1, 1, 0}, // channel 7
{0, 0, 0, 1}, // channel 8
{1, 0, 0, 1}, // channel 9
{0, 1, 0, 1}, // channel 10
{1, 1, 0, 1}, // channel 11
{0, 0, 1, 1}, // channel 12
{1, 0, 1, 1}, // channel 13
{0, 1, 1, 1}, // channel 14
{1, 1, 1, 1} // channel 15
};
this->pin_s0_->digital_write(mux_channel[pin][0]);
this->pin_s1_->digital_write(mux_channel[pin][1]);
this->pin_s2_->digital_write(mux_channel[pin][2]);
this->pin_s3_->digital_write(mux_channel[pin][3]);
// small delay is needed to let the multiplexer switch
delay(this->switch_delay_);
this->active_pin_ = pin;
}
}
CD74HC4067Sensor::CD74HC4067Sensor(CD74HC4067Component *parent) : parent_(parent) {}
void CD74HC4067Sensor::update() {
float value_v = this->sample();
this->publish_state(value_v);
}
float CD74HC4067Sensor::get_setup_priority() const { return this->parent_->get_setup_priority() - 1.0f; }
float CD74HC4067Sensor::sample() {
this->parent_->activate_pin(this->pin_);
return this->source_->sample();
}
void CD74HC4067Sensor::dump_config() {
LOG_SENSOR(TAG, "CD74HC4067 Sensor", this);
ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_);
LOG_UPDATE_INTERVAL(this);
}
} // namespace cd74hc4067
} // namespace esphome

View File

@@ -1,65 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
namespace esphome {
namespace cd74hc4067 {
class CD74HC4067Component : public Component {
public:
/// Set up the internal sensor array.
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
/// setting pin active by setting the right combination of the four multiplexer input pins
void activate_pin(uint8_t pin);
/// set the pin connected to multiplexer control pin 0
void set_pin_s0(InternalGPIOPin *pin) { this->pin_s0_ = pin; }
/// set the pin connected to multiplexer control pin 1
void set_pin_s1(InternalGPIOPin *pin) { this->pin_s1_ = pin; }
/// set the pin connected to multiplexer control pin 2
void set_pin_s2(InternalGPIOPin *pin) { this->pin_s2_ = pin; }
/// set the pin connected to multiplexer control pin 3
void set_pin_s3(InternalGPIOPin *pin) { this->pin_s3_ = pin; }
/// set the delay needed after an input switch
void set_switch_delay(uint32_t switch_delay) { this->switch_delay_ = switch_delay; }
private:
InternalGPIOPin *pin_s0_;
InternalGPIOPin *pin_s1_;
InternalGPIOPin *pin_s2_;
InternalGPIOPin *pin_s3_;
/// the currently active pin
uint8_t active_pin_;
uint32_t switch_delay_;
};
class CD74HC4067Sensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
public:
CD74HC4067Sensor(CD74HC4067Component *parent);
void update() override;
void dump_config() override;
/// `HARDWARE_LATE` setup priority.
float get_setup_priority() const override;
void set_pin(uint8_t pin) { this->pin_ = pin; }
void set_source(voltage_sampler::VoltageSampler *source) { this->source_ = source; }
float sample() override;
protected:
CD74HC4067Component *parent_;
/// The sampling source to read values from.
voltage_sampler::VoltageSampler *source_;
uint8_t pin_;
};
} // namespace cd74hc4067
} // namespace esphome

View File

@@ -1,55 +0,0 @@
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_SENSOR,
CONF_NUMBER,
ICON_FLASH,
UNIT_VOLT,
STATE_CLASS_MEASUREMENT,
DEVICE_CLASS_VOLTAGE,
)
from . import cd74hc4067_ns, CD74HC4067Component
DEPENDENCIES = ["cd74hc4067"]
CD74HC4067Sensor = cd74hc4067_ns.class_(
"CD74HC4067Sensor",
sensor.Sensor,
cg.PollingComponent,
voltage_sampler.VoltageSampler,
)
CONF_CD74HC4067_ID = "cd74hc4067_id"
CONFIG_SCHEMA = (
sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=3,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICON_FLASH,
)
.extend(
{
cv.GenerateID(): cv.declare_id(CD74HC4067Sensor),
cv.GenerateID(CONF_CD74HC4067_ID): cv.use_id(CD74HC4067Component),
cv.Required(CONF_NUMBER): cv.int_range(0, 15),
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
}
)
.extend(cv.polling_component_schema("60s"))
)
async def to_code(config):
parent = await cg.get_variable(config[CONF_CD74HC4067_ID])
var = cg.new_Pvariable(config[CONF_ID], parent)
await cg.register_component(var, config)
await sensor.register_sensor(var, config)
cg.add(var.set_pin(config[CONF_NUMBER]))
sens = await cg.get_variable(config[CONF_SENSOR])
cg.add(var.set_source(sens))

View File

@@ -20,7 +20,6 @@ from esphome.const import (
CONF_MODE,
CONF_MODE_COMMAND_TOPIC,
CONF_MODE_STATE_TOPIC,
CONF_ON_STATE,
CONF_PRESET,
CONF_SWING_MODE,
CONF_SWING_MODE_COMMAND_TOPIC,
@@ -35,7 +34,6 @@ from esphome.const import (
CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC,
CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC,
CONF_TEMPERATURE_STEP,
CONF_TRIGGER_ID,
CONF_VISUAL,
CONF_MQTT_ID,
)
@@ -103,7 +101,6 @@ validate_climate_swing_mode = cv.enum(CLIMATE_SWING_MODES, upper=True)
# Actions
ControlAction = climate_ns.class_("ControlAction", automation.Action)
StateTrigger = climate_ns.class_("StateTrigger", automation.Trigger.template())
CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
{
@@ -164,11 +161,6 @@ CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).
cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic
),
cv.Optional(CONF_ON_STATE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
}
),
}
)
@@ -213,7 +205,7 @@ async def setup_climate_core_(var, config):
if CONF_MODE_COMMAND_TOPIC in config:
cg.add(mqtt_.set_custom_mode_command_topic(config[CONF_MODE_COMMAND_TOPIC]))
if CONF_MODE_STATE_TOPIC in config:
cg.add(mqtt_.set_custom_mode_state_topic(config[CONF_MODE_STATE_TOPIC]))
cg.add(mqtt_.set_custom_state_topic(config[CONF_MODE_STATE_TOPIC]))
if CONF_SWING_MODE_COMMAND_TOPIC in config:
cg.add(
@@ -264,10 +256,6 @@ async def setup_climate_core_(var, config):
)
)
for conf in config.get(CONF_ON_STATE, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
async def register_climate(var, config):
if not CORE.has_id(config[CONF_ID]):

View File

@@ -42,12 +42,5 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
Climate *climate_;
};
class StateTrigger : public Trigger<> {
public:
StateTrigger(Climate *climate) {
climate->add_on_state_callback([this]() { this->trigger(); });
}
};
} // namespace climate
} // namespace esphome

View File

@@ -10,22 +10,21 @@ climate::ClimateTraits ClimateIR::traits() {
auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(this->sensor_ != nullptr);
traits.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_HEAT_COOL});
if (this->supports_cool_)
if (supports_cool_)
traits.add_supported_mode(climate::CLIMATE_MODE_COOL);
if (this->supports_heat_)
if (supports_heat_)
traits.add_supported_mode(climate::CLIMATE_MODE_HEAT);
if (this->supports_dry_)
if (supports_dry_)
traits.add_supported_mode(climate::CLIMATE_MODE_DRY);
if (this->supports_fan_only_)
if (supports_fan_only_)
traits.add_supported_mode(climate::CLIMATE_MODE_FAN_ONLY);
traits.set_supports_two_point_target_temperature(false);
traits.set_visual_min_temperature(this->minimum_temperature_);
traits.set_visual_max_temperature(this->maximum_temperature_);
traits.set_visual_temperature_step(this->temperature_step_);
traits.set_supported_fan_modes(this->fan_modes_);
traits.set_supported_swing_modes(this->swing_modes_);
traits.set_supported_presets(this->presets_);
traits.set_supported_fan_modes(fan_modes_);
traits.set_supported_swing_modes(swing_modes_);
return traits;
}
@@ -51,7 +50,6 @@ void ClimateIR::setup() {
roundf(clamp(this->current_temperature, this->minimum_temperature_, this->maximum_temperature_));
this->fan_mode = climate::CLIMATE_FAN_AUTO;
this->swing_mode = climate::CLIMATE_SWING_OFF;
this->preset = climate::CLIMATE_PRESET_NONE;
}
// Never send nan to HA
if (std::isnan(this->target_temperature))
@@ -67,8 +65,6 @@ void ClimateIR::control(const climate::ClimateCall &call) {
this->fan_mode = *call.get_fan_mode();
if (call.get_swing_mode().has_value())
this->swing_mode = *call.get_swing_mode();
if (call.get_preset().has_value())
this->preset = *call.get_preset();
this->transmit_state();
this->publish_state();
}

View File

@@ -22,7 +22,7 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
public:
ClimateIR(float minimum_temperature, float maximum_temperature, float temperature_step = 1.0f,
bool supports_dry = false, bool supports_fan_only = false, std::set<climate::ClimateFanMode> fan_modes = {},
std::set<climate::ClimateSwingMode> swing_modes = {}, std::set<climate::ClimatePreset> presets = {}) {
std::set<climate::ClimateSwingMode> swing_modes = {}) {
this->minimum_temperature_ = minimum_temperature;
this->maximum_temperature_ = maximum_temperature;
this->temperature_step_ = temperature_step;
@@ -30,7 +30,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
this->supports_fan_only_ = supports_fan_only;
this->fan_modes_ = std::move(fan_modes);
this->swing_modes_ = std::move(swing_modes);
this->presets_ = std::move(presets);
}
void setup() override;
@@ -62,7 +61,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
bool supports_fan_only_{false};
std::set<climate::ClimateFanMode> fan_modes_ = {};
std::set<climate::ClimateSwingMode> swing_modes_ = {};
std::set<climate::ClimatePreset> presets_ = {};
remote_transmitter::RemoteTransmitterComponent *transmitter_;
sensor::Sensor *sensor_{nullptr};

View File

@@ -1,5 +1,4 @@
#include "coolix.h"
#include "esphome/components/remote_base/coolix_protocol.h"
#include "esphome/core/log.h"
namespace esphome {
@@ -7,29 +6,29 @@ namespace coolix {
static const char *const TAG = "coolix.climate";
static const uint32_t COOLIX_OFF = 0xB27BE0;
static const uint32_t COOLIX_SWING = 0xB26BE0;
static const uint32_t COOLIX_LED = 0xB5F5A5;
static const uint32_t COOLIX_SILENCE_FP = 0xB5F5B6;
const uint32_t COOLIX_OFF = 0xB27BE0;
const uint32_t COOLIX_SWING = 0xB26BE0;
const uint32_t COOLIX_LED = 0xB5F5A5;
const uint32_t COOLIX_SILENCE_FP = 0xB5F5B6;
// On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore.
static const uint8_t COOLIX_COOL = 0b0000;
static const uint8_t COOLIX_DRY_FAN = 0b0100;
static const uint8_t COOLIX_AUTO = 0b1000;
static const uint8_t COOLIX_HEAT = 0b1100;
static const uint32_t COOLIX_MODE_MASK = 0b1100;
static const uint32_t COOLIX_FAN_MASK = 0xF000;
static const uint32_t COOLIX_FAN_MODE_AUTO_DRY = 0x1000;
static const uint32_t COOLIX_FAN_AUTO = 0xB000;
static const uint32_t COOLIX_FAN_MIN = 0x9000;
static const uint32_t COOLIX_FAN_MED = 0x5000;
static const uint32_t COOLIX_FAN_MAX = 0x3000;
const uint8_t COOLIX_COOL = 0b0000;
const uint8_t COOLIX_DRY_FAN = 0b0100;
const uint8_t COOLIX_AUTO = 0b1000;
const uint8_t COOLIX_HEAT = 0b1100;
const uint32_t COOLIX_MODE_MASK = 0b1100;
const uint32_t COOLIX_FAN_MASK = 0xF000;
const uint32_t COOLIX_FAN_MODE_AUTO_DRY = 0x1000;
const uint32_t COOLIX_FAN_AUTO = 0xB000;
const uint32_t COOLIX_FAN_MIN = 0x9000;
const uint32_t COOLIX_FAN_MED = 0x5000;
const uint32_t COOLIX_FAN_MAX = 0x3000;
// Temperature
static const uint8_t COOLIX_TEMP_RANGE = COOLIX_TEMP_MAX - COOLIX_TEMP_MIN + 1;
static const uint8_t COOLIX_FAN_TEMP_CODE = 0b11100000; // Part of Fan Mode.
static const uint32_t COOLIX_TEMP_MASK = 0b11110000;
static const uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE] = {
const uint8_t COOLIX_TEMP_RANGE = COOLIX_TEMP_MAX - COOLIX_TEMP_MIN + 1;
const uint8_t COOLIX_FAN_TEMP_CODE = 0b11100000; // Part of Fan Mode.
const uint32_t COOLIX_TEMP_MASK = 0b11110000;
const uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE] = {
0b00000000, // 17C
0b00010000, // 18c
0b00110000, // 19C
@@ -46,6 +45,17 @@ static const uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE] = {
0b10110000 // 30C
};
// Constants
static const uint32_t BIT_MARK_US = 660;
static const uint32_t HEADER_MARK_US = 560 * 8;
static const uint32_t HEADER_SPACE_US = 560 * 8;
static const uint32_t BIT_ONE_SPACE_US = 1500;
static const uint32_t BIT_ZERO_SPACE_US = 450;
static const uint32_t FOOTER_MARK_US = BIT_MARK_US;
static const uint32_t FOOTER_SPACE_US = HEADER_SPACE_US;
const uint16_t COOLIX_BITS = 24;
void CoolixClimate::transmit_state() {
uint32_t remote_state = 0xB20F00;
@@ -101,60 +111,119 @@ void CoolixClimate::transmit_state() {
}
}
}
ESP_LOGV(TAG, "Sending coolix code: 0x%06X", remote_state);
ESP_LOGV(TAG, "Sending coolix code: 0x%02X", remote_state);
auto transmit = this->transmitter_->transmit();
auto data = transmit.get_data();
remote_base::CoolixProtocol().encode(data, remote_state);
data->set_carrier_frequency(38000);
uint16_t repeat = 1;
for (uint16_t r = 0; r <= repeat; r++) {
// Header
data->mark(HEADER_MARK_US);
data->space(HEADER_SPACE_US);
// Data
// Break data into bytes, starting at the Most Significant
// Byte. Each byte then being sent normal, then followed inverted.
for (uint16_t i = 8; i <= COOLIX_BITS; i += 8) {
// Grab a bytes worth of data.
uint8_t byte = (remote_state >> (COOLIX_BITS - i)) & 0xFF;
// Normal
for (uint64_t mask = 1ULL << 7; mask; mask >>= 1) {
data->mark(BIT_MARK_US);
data->space((byte & mask) ? BIT_ONE_SPACE_US : BIT_ZERO_SPACE_US);
}
// Inverted
for (uint64_t mask = 1ULL << 7; mask; mask >>= 1) {
data->mark(BIT_MARK_US);
data->space(!(byte & mask) ? BIT_ONE_SPACE_US : BIT_ZERO_SPACE_US);
}
}
// Footer
data->mark(BIT_MARK_US);
data->space(FOOTER_SPACE_US); // Pause before repeating
}
transmit.perform();
}
bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteReceiveData data) {
auto decoded = remote_base::CoolixProtocol().decode(data);
if (!decoded.has_value())
return false;
bool CoolixClimate::on_receive(remote_base::RemoteReceiveData data) {
// Decoded remote state y 3 bytes long code.
uint32_t remote_state = *decoded;
ESP_LOGV(TAG, "Decoded 0x%06X", remote_state);
if ((remote_state & 0xFF0000) != 0xB20000)
uint32_t remote_state = 0;
// The protocol sends the data twice, read here
uint32_t loop_read;
for (uint16_t loop = 1; loop <= 2; loop++) {
if (!data.expect_item(HEADER_MARK_US, HEADER_SPACE_US))
return false;
loop_read = 0;
for (uint8_t a_byte = 0; a_byte < 3; a_byte++) {
uint8_t byte = 0;
for (int8_t a_bit = 7; a_bit >= 0; a_bit--) {
if (data.expect_item(BIT_MARK_US, BIT_ONE_SPACE_US))
byte |= 1 << a_bit;
else if (!data.expect_item(BIT_MARK_US, BIT_ZERO_SPACE_US))
return false;
}
// Need to see this segment inverted
for (int8_t a_bit = 7; a_bit >= 0; a_bit--) {
bool bit = byte & (1 << a_bit);
if (!data.expect_item(BIT_MARK_US, bit ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US))
return false;
}
// Receiving MSB first: reorder bytes
loop_read |= byte << ((2 - a_byte) * 8);
}
// Footer Mark
if (!data.expect_mark(BIT_MARK_US))
return false;
if (loop == 1) {
// Back up state on first loop
remote_state = loop_read;
if (!data.expect_space(FOOTER_SPACE_US))
return false;
}
}
ESP_LOGV(TAG, "Decoded 0x%02X", remote_state);
if (remote_state != loop_read || (remote_state & 0xFF0000) != 0xB20000)
return false;
if (remote_state == COOLIX_OFF) {
parent->mode = climate::CLIMATE_MODE_OFF;
this->mode = climate::CLIMATE_MODE_OFF;
} else if (remote_state == COOLIX_SWING) {
parent->swing_mode =
parent->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF;
this->swing_mode =
this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF;
} else {
if ((remote_state & COOLIX_MODE_MASK) == COOLIX_HEAT)
parent->mode = climate::CLIMATE_MODE_HEAT;
this->mode = climate::CLIMATE_MODE_HEAT;
else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_AUTO)
parent->mode = climate::CLIMATE_MODE_HEAT_COOL;
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_DRY_FAN) {
if ((remote_state & COOLIX_FAN_MASK) == COOLIX_FAN_MODE_AUTO_DRY)
parent->mode = climate::CLIMATE_MODE_DRY;
this->mode = climate::CLIMATE_MODE_DRY;
else
parent->mode = climate::CLIMATE_MODE_FAN_ONLY;
this->mode = climate::CLIMATE_MODE_FAN_ONLY;
} else
parent->mode = climate::CLIMATE_MODE_COOL;
this->mode = climate::CLIMATE_MODE_COOL;
// Fan Speed
if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || parent->mode == climate::CLIMATE_MODE_HEAT_COOL ||
parent->mode == climate::CLIMATE_MODE_DRY)
parent->fan_mode = climate::CLIMATE_FAN_AUTO;
if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || this->mode == climate::CLIMATE_MODE_HEAT_COOL ||
this->mode == climate::CLIMATE_MODE_DRY)
this->fan_mode = climate::CLIMATE_FAN_AUTO;
else if ((remote_state & COOLIX_FAN_MIN) == COOLIX_FAN_MIN)
parent->fan_mode = climate::CLIMATE_FAN_LOW;
this->fan_mode = climate::CLIMATE_FAN_LOW;
else if ((remote_state & COOLIX_FAN_MED) == COOLIX_FAN_MED)
parent->fan_mode = climate::CLIMATE_FAN_MEDIUM;
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
else if ((remote_state & COOLIX_FAN_MAX) == COOLIX_FAN_MAX)
parent->fan_mode = climate::CLIMATE_FAN_HIGH;
this->fan_mode = climate::CLIMATE_FAN_HIGH;
// Temperature
uint8_t temperature_code = remote_state & COOLIX_TEMP_MASK;
for (uint8_t i = 0; i < COOLIX_TEMP_RANGE; i++)
if (COOLIX_TEMP_MAP[i] == temperature_code)
parent->target_temperature = i + COOLIX_TEMP_MIN;
this->target_temperature = i + COOLIX_TEMP_MIN;
}
parent->publish_state();
this->publish_state();
return true;
}

View File

@@ -26,15 +26,11 @@ class CoolixClimate : public climate_ir::ClimateIR {
climate_ir::ClimateIR::control(call);
}
/// This static method can be used in other climate components that accept the Coolix protocol. See midea_ir for
/// example.
static bool on_coolix(climate::Climate *parent, remote_base::RemoteReceiveData data);
protected:
/// Transmit via IR the state of this climate controller.
void transmit_state() override;
/// Handle received IR Buffer
bool on_receive(remote_base::RemoteReceiveData data) override { return CoolixClimate::on_coolix(this, data); }
bool on_receive(remote_base::RemoteReceiveData data) override;
bool send_swing_cmd_{false};
};

View File

@@ -210,10 +210,7 @@ Cover::Cover() : Cover("") {}
std::string Cover::get_device_class() {
if (this->device_class_override_.has_value())
return *this->device_class_override_;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return this->device_class();
#pragma GCC diagnostic pop
}
bool Cover::is_fully_open() const { return this->position == COVER_OPEN; }
bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; }

View File

@@ -169,11 +169,6 @@ class Cover : public EntityBase {
friend CoverCall;
virtual void control(const CoverCall &call) = 0;
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
virtual std::string device_class();
optional<CoverRestoreState> restore_state_();

View File

@@ -102,6 +102,8 @@ void CS5460AComponent::hw_init_() {
/* Doesn't reset the register values etc., just restarts the "computation cycle" */
void CS5460AComponent::restart_() {
int cnt;
this->enable();
/* Stop running conversion, wake up if needed */
this->write_byte(CMD_POWER_UP);

View File

@@ -90,7 +90,6 @@ void CSE7766Component::parse_data_() {
uint32_t power_cycle = this->get_24_bit_uint_(17);
uint8_t adj = this->raw_data_[20];
uint32_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22];
bool power_ok = true;
bool voltage_ok = true;
@@ -128,18 +127,6 @@ void CSE7766Component::parse_data_() {
power = power_calib / float(power_cycle);
this->power_acc_ += power;
this->power_counts_ += 1;
uint32_t difference;
if (this->cf_pulses_last_ == 0)
this->cf_pulses_last_ = cf_pulses;
if (cf_pulses < this->cf_pulses_last_) {
difference = cf_pulses + (0x10000 - this->cf_pulses_last_);
} else {
difference = cf_pulses - this->cf_pulses_last_;
}
this->cf_pulses_last_ = cf_pulses;
this->energy_total_ += difference * float(power_calib) / 1000000.0 / 3600.0;
}
if ((adj & 0x20) == 0x20 && current_ok && voltage_ok && power != 0.0) {
@@ -149,9 +136,9 @@ void CSE7766Component::parse_data_() {
}
}
void CSE7766Component::update() {
float voltage = this->voltage_counts_ > 0 ? this->voltage_acc_ / this->voltage_counts_ : 0.0f;
float current = this->current_counts_ > 0 ? this->current_acc_ / this->current_counts_ : 0.0f;
float power = this->power_counts_ > 0 ? this->power_acc_ / this->power_counts_ : 0.0f;
float voltage = this->voltage_counts_ > 0 ? this->voltage_acc_ / this->voltage_counts_ : 0.0;
float current = this->current_counts_ > 0 ? this->current_acc_ / this->current_counts_ : 0.0;
float power = this->power_counts_ > 0 ? this->power_acc_ / this->power_counts_ : 0.0;
ESP_LOGV(TAG, "Got voltage_acc=%.2f current_acc=%.2f power_acc=%.2f", this->voltage_acc_, this->current_acc_,
this->power_acc_);
@@ -165,8 +152,6 @@ void CSE7766Component::update() {
this->current_sensor_->publish_state(current);
if (this->power_sensor_ != nullptr)
this->power_sensor_->publish_state(power);
if (this->energy_sensor_ != nullptr)
this->energy_sensor_->publish_state(this->energy_total_);
this->voltage_acc_ = 0.0f;
this->current_acc_ = 0.0f;
@@ -187,7 +172,6 @@ void CSE7766Component::dump_config() {
LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
LOG_SENSOR(" ", "Current", this->current_sensor_);
LOG_SENSOR(" ", "Power", this->power_sensor_);
LOG_SENSOR(" ", "Energy", this->energy_sensor_);
this->check_uart_settings(4800);
}

View File

@@ -12,7 +12,6 @@ class CSE7766Component : public PollingComponent, public uart::UARTDevice {
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void loop() override;
float get_setup_priority() const override;
@@ -30,12 +29,9 @@ class CSE7766Component : public PollingComponent, public uart::UARTDevice {
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
float voltage_acc_{0.0f};
float current_acc_{0.0f};
float power_acc_{0.0f};
float energy_total_{0.0f};
uint32_t cf_pulses_last_{0};
uint32_t voltage_counts_{0};
uint32_t current_counts_{0};
uint32_t power_counts_{0};

View File

@@ -3,20 +3,16 @@ import esphome.config_validation as cv
from esphome.components import sensor, uart
from esphome.const import (
CONF_CURRENT,
CONF_ENERGY,
CONF_ID,
CONF_POWER,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
UNIT_WATT_HOURS,
)
DEPENDENCIES = ["uart"]
@@ -48,12 +44,6 @@ CONFIG_SCHEMA = (
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_ENERGY): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT_HOURS,
accuracy_decimals=3,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
}
)
.extend(cv.polling_component_schema("60s"))
@@ -81,7 +71,3 @@ async def to_code(config):
conf = config[CONF_POWER]
sens = await sensor.new_sensor(conf)
cg.add(var.set_power_sensor(sens))
if CONF_ENERGY in config:
conf = config[CONF_ENERGY]
sens = await sensor.new_sensor(conf)
cg.add(var.set_energy_sensor(sens))

View File

@@ -231,7 +231,7 @@ bool DaikinClimate::on_receive(remote_base::RemoteReceiveData data) {
// frame header
if (byte != 0x27)
return false;
} else if (pos == 3) { // NOLINT(bugprone-branch-clone)
} else if (pos == 3) {
// frame header
if (byte != 0x00)
return false;

View File

@@ -38,9 +38,10 @@ void DallasComponent::setup() {
raw_sensors = this->one_wire_->search_vec();
for (auto &address : raw_sensors) {
std::string s = uint64_to_string(address);
auto *address8 = reinterpret_cast<uint8_t *>(&address);
if (crc8(address8, 7) != address8[7]) {
ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex(address).c_str());
ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", s.c_str());
continue;
}
if (address8[0] != DALLAS_MODEL_DS18S20 && address8[0] != DALLAS_MODEL_DS1822 &&
@@ -76,7 +77,8 @@ void DallasComponent::dump_config() {
} else {
ESP_LOGD(TAG, " Found sensors:");
for (auto &address : this->found_sensors_) {
ESP_LOGD(TAG, " 0x%s", format_hex(address).c_str());
std::string s = uint64_to_string(address);
ESP_LOGD(TAG, " 0x%s", s.c_str());
}
}
@@ -145,7 +147,7 @@ void DallasTemperatureSensor::set_index(uint8_t index) { this->index_ = index; }
uint8_t *DallasTemperatureSensor::get_address8() { return reinterpret_cast<uint8_t *>(&this->address_); }
const std::string &DallasTemperatureSensor::get_address_name() {
if (this->address_name_.empty()) {
this->address_name_ = std::string("0x") + format_hex(this->address_);
this->address_name_ = std::string("0x") + uint64_to_string(this->address_);
}
return this->address_name_;
@@ -235,7 +237,7 @@ float DallasTemperatureSensor::get_temp_c() {
return temp / 128.0f;
}
std::string DallasTemperatureSensor::unique_id() { return "dallas-" + str_upper_case(format_hex(this->address_)); }
std::string DallasTemperatureSensor::unique_id() { return "dallas-" + uint64_to_string(this->address_); }
} // namespace dallas
} // namespace esphome

View File

@@ -3,7 +3,6 @@ from pathlib import Path
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components.packages import validate_source_shorthand
from esphome.wizard import wizard_file
from esphome.yaml_util import dump
@@ -30,11 +29,12 @@ CONFIG_SCHEMA = cv.Schema(
}
)
WIFI_CONFIG = """
WIFI_MESSAGE = """
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Do not forget to add your own wifi configuration before installing this configuration
# wifi:
# ssid: !secret wifi_ssid
# password: !secret wifi_password
"""
@@ -49,24 +49,12 @@ def import_config(path: str, name: str, project_name: str, import_url: str) -> N
if p.exists():
raise FileExistsError
if project_name == "esphome.web":
p.write_text(
wizard_file(
name=name,
platform="ESP32" if "esp32" in import_url else "ESP8266",
board="esp32dev" if "esp32" in import_url else "esp01_1m",
ssid="!secret wifi_ssid",
psk="!secret wifi_password",
),
encoding="utf8",
)
else:
config = {
"substitutions": {"name": name},
"packages": {project_name: import_url},
"esphome": {"name_add_mac_suffix": False},
}
p.write_text(
dump(config) + WIFI_CONFIG,
encoding="utf8",
)
config = {
"substitutions": {"name": name},
"packages": {project_name: import_url},
"esphome": {"name_add_mac_suffix": False},
}
p.write_text(
dump(config) + WIFI_MESSAGE,
encoding="utf8",
)

View File

@@ -4,23 +4,20 @@
#include "esphome/core/defines.h"
#include "esphome/core/version.h"
#ifdef USE_ESP_IDF
#include <esp_heap_caps.h>
#include <esp_system.h>
#endif
#ifdef USE_ESP32
#if ESP_IDF_VERSION_MAJOR >= 4
#include <esp32/rom/rtc.h>
#else
#include <rom/rtc.h>
#endif
#include <esp_idf_version.h>
#endif
#ifdef USE_ARDUINO
#include <Esp.h>
#endif
#ifdef USE_ESP_IDF
#include <esp_heap_caps.h>
#include <esp_system.h>
#endif
namespace esphome {
namespace debug {
@@ -101,7 +98,7 @@ void DebugComponent::dump_config() {
info.features &= ~CHIP_FEATURE_BT;
}
if (info.features)
features += "Other:" + format_hex(info.features);
features += "Other:" + uint64_to_string(info.features);
ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
info.revision);

View File

@@ -41,30 +41,15 @@ EXT1_WAKEUP_MODES = {
"ALL_LOW": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ALL_LOW,
"ANY_HIGH": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ANY_HIGH,
}
WakeupCauseToRunDuration = deep_sleep_ns.struct("WakeupCauseToRunDuration")
CONF_WAKEUP_PIN_MODE = "wakeup_pin_mode"
CONF_ESP32_EXT1_WAKEUP = "esp32_ext1_wakeup"
CONF_TOUCH_WAKEUP = "touch_wakeup"
CONF_DEFAULT = "default"
CONF_GPIO_WAKEUP_REASON = "gpio_wakeup_reason"
CONF_TOUCH_WAKEUP_REASON = "touch_wakeup_reason"
WAKEUP_CAUSES_SCHEMA = cv.Schema(
{
cv.Required(CONF_DEFAULT): cv.positive_time_period_milliseconds,
cv.Optional(CONF_TOUCH_WAKEUP_REASON): cv.positive_time_period_milliseconds,
cv.Optional(CONF_GPIO_WAKEUP_REASON): cv.positive_time_period_milliseconds,
}
)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(DeepSleepComponent),
cv.Optional(CONF_RUN_DURATION): cv.Any(
cv.All(cv.only_on_esp32, WAKEUP_CAUSES_SCHEMA),
cv.positive_time_period_milliseconds,
),
cv.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_WAKEUP_PIN): cv.All(
cv.only_on_esp32, pins.internal_gpio_input_pin_schema, validate_pin_number
@@ -100,28 +85,7 @@ async def to_code(config):
if CONF_WAKEUP_PIN_MODE in config:
cg.add(var.set_wakeup_pin_mode(config[CONF_WAKEUP_PIN_MODE]))
if CONF_RUN_DURATION in config:
run_duration_config = config[CONF_RUN_DURATION]
if not isinstance(run_duration_config, dict):
cg.add(var.set_run_duration(config[CONF_RUN_DURATION]))
else:
default_run_duration = run_duration_config[CONF_DEFAULT]
wakeup_cause_to_run_duration = cg.StructInitializer(
WakeupCauseToRunDuration,
("default_cause", default_run_duration),
(
"touch_cause",
run_duration_config.get(
CONF_TOUCH_WAKEUP_REASON, default_run_duration
),
),
(
"gpio_cause",
run_duration_config.get(
CONF_GPIO_WAKEUP_REASON, default_run_duration
),
),
)
cg.add(var.set_run_duration(wakeup_cause_to_run_duration))
cg.add(var.set_run_duration(config[CONF_RUN_DURATION]))
if CONF_ESP32_EXT1_WAKEUP in config:
conf = config[CONF_ESP32_EXT1_WAKEUP]

View File

@@ -13,35 +13,12 @@ static const char *const TAG = "deep_sleep";
bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
optional<uint32_t> DeepSleepComponent::get_run_duration_() const {
#ifdef USE_ESP32
if (this->wakeup_cause_to_run_duration_.has_value()) {
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
switch (wakeup_cause) {
case ESP_SLEEP_WAKEUP_EXT0:
case ESP_SLEEP_WAKEUP_EXT1:
return this->wakeup_cause_to_run_duration_->gpio_cause;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
return this->wakeup_cause_to_run_duration_->touch_cause;
default:
return this->wakeup_cause_to_run_duration_->default_cause;
}
}
#endif
return this->run_duration_;
}
void DeepSleepComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
global_has_deep_sleep = true;
const optional<uint32_t> run_duration = get_run_duration_();
if (run_duration.has_value()) {
ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %u ms", *run_duration);
this->set_timeout(*run_duration, [this]() { this->begin_sleep(); });
} else {
ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
}
if (this->run_duration_.has_value())
this->set_timeout(*this->run_duration_, [this]() { this->begin_sleep(); });
}
void DeepSleepComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
@@ -56,11 +33,6 @@ void DeepSleepComponent::dump_config() {
if (wakeup_pin_ != nullptr) {
LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_);
}
if (this->wakeup_cause_to_run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->default_cause);
ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->touch_cause);
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->gpio_cause);
}
#endif
}
void DeepSleepComponent::loop() {
@@ -77,9 +49,6 @@ void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) {
}
void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; }
void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) {
wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration;
}
#endif
void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; }
void DeepSleepComponent::begin_sleep(bool manual) {
@@ -108,8 +77,8 @@ void DeepSleepComponent::begin_sleep(bool manual) {
if (this->sleep_duration_.has_value())
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
if (this->wakeup_pin_ != nullptr) {
bool level = !this->wakeup_pin_->is_inverted();
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
bool level = this->wakeup_pin_->is_inverted();
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && !this->wakeup_pin_->digital_read()) {
level = !level;
}
esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level);

View File

@@ -32,15 +32,6 @@ struct Ext1Wakeup {
esp_sleep_ext1_wakeup_mode_t wakeup_mode;
};
struct WakeupCauseToRunDuration {
// Run duration if woken up by timer or any other reason besides those below.
uint32_t default_cause;
// Run duration if woken up by touch pads.
uint32_t touch_cause;
// Run duration if woken up by GPIO pins.
uint32_t gpio_cause;
};
#endif
template<typename... Ts> class EnterDeepSleepAction;
@@ -68,11 +59,6 @@ class DeepSleepComponent : public Component {
void set_ext1_wakeup(Ext1Wakeup ext1_wakeup);
void set_touch_wakeup(bool touch_wakeup);
// Set the duration in ms for how long the code should run before entering
// deep sleep mode, according to the cause the ESP32 has woken.
void set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration);
#endif
/// Set a duration in ms for how long the code should run before entering deep sleep mode.
void set_run_duration(uint32_t time_ms);
@@ -89,17 +75,12 @@ class DeepSleepComponent : public Component {
void prevent_deep_sleep();
protected:
// Returns nullopt if no run duration is set. Otherwise, returns the run
// duration before entering deep sleep.
optional<uint32_t> get_run_duration_() const;
optional<uint64_t> sleep_duration_;
#ifdef USE_ESP32
InternalGPIOPin *wakeup_pin_;
WakeupPinMode wakeup_pin_mode_{WAKEUP_PIN_MODE_IGNORE};
optional<Ext1Wakeup> ext1_wakeup_;
optional<bool> touch_wakeup_;
optional<WakeupCauseToRunDuration> wakeup_cause_to_run_duration_;
#endif
optional<uint32_t> run_duration_;
bool next_enter_deep_sleep_{false};

View File

@@ -33,7 +33,7 @@ DHT = dht_ns.class_("DHT", cg.PollingComponent)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(DHT),
cv.Required(CONF_PIN): pins.internal_gpio_input_pin_schema,
cv.Required(CONF_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,

View File

@@ -5,7 +5,6 @@
#include "esphome/core/color.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace display {
@@ -16,8 +15,7 @@ const Color COLOR_OFF(0, 0, 0, 0);
const Color COLOR_ON(255, 255, 255, 255);
void DisplayBuffer::init_internal_(uint32_t buffer_length) {
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
this->buffer_ = allocator.allocate(buffer_length);
this->buffer_ = new (std::nothrow) uint8_t[buffer_length]; // NOLINT
if (this->buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate buffer for display!");
return;
@@ -498,7 +496,7 @@ bool Animation::get_pixel(int x, int y) const {
return false;
const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
const uint32_t frame_index = this->height_ * width_8 * this->current_frame_;
if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_)
return false;
const uint32_t pos = x + y * width_8 + frame_index;
return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
@@ -507,7 +505,7 @@ Color Animation::get_color_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_)
return Color::BLACK;
const uint32_t pos = (x + y * this->width_ + frame_index) * 3;
const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) |
@@ -519,7 +517,7 @@ Color Animation::get_grayscale_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return Color::BLACK;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_)
return Color::BLACK;
const uint32_t pos = (x + y * this->width_ + frame_index);
const uint8_t gray = progmem_read_byte(this->data_start_ + pos);

View File

@@ -42,7 +42,7 @@ class ColorUtil {
? esp_scale(((colorcode >> third_bits) & ((1 << second_bits) - 1)), ((1 << second_bits) - 1))
: esp_scale(((colorcode >> 8) & 0xFF), ((1 << second_bits) - 1));
third_color = (right_bit_aligned ? esp_scale(((colorcode >> 0) & ((1 << third_bits) - 1)), ((1 << third_bits) - 1))
third_color = (right_bit_aligned ? esp_scale(((colorcode >> 0) & 0xFF), ((1 << third_bits) - 1))
: esp_scale(((colorcode >> 0) & 0xFF), (1 << third_bits) - 1));
Color color_return;

View File

@@ -1,11 +1,9 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import uart
from esphome.const import (
CONF_ID,
CONF_UART_ID,
CONF_RECEIVE_TIMEOUT,
)
CODEOWNERS = ["@glmnet", "@zuidwijk"]
@@ -13,13 +11,10 @@ CODEOWNERS = ["@glmnet", "@zuidwijk"]
DEPENDENCIES = ["uart"]
AUTO_LOAD = ["sensor", "text_sensor"]
CONF_CRC_CHECK = "crc_check"
CONF_DECRYPTION_KEY = "decryption_key"
CONF_DSMR_ID = "dsmr_id"
CONF_DECRYPTION_KEY = "decryption_key"
CONF_CRC_CHECK = "crc_check"
CONF_GAS_MBUS_ID = "gas_mbus_id"
CONF_MAX_TELEGRAM_LENGTH = "max_telegram_length"
CONF_REQUEST_INTERVAL = "request_interval"
CONF_REQUEST_PIN = "request_pin"
# Hack to prevent compile error due to ambiguity with lib namespace
dsmr_ns = cg.esphome_ns.namespace("esphome::dsmr")
@@ -51,14 +46,6 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_DECRYPTION_KEY): _validate_key,
cv.Optional(CONF_CRC_CHECK, default=True): cv.boolean,
cv.Optional(CONF_GAS_MBUS_ID, default=1): cv.int_,
cv.Optional(CONF_MAX_TELEGRAM_LENGTH, default=1500): cv.int_,
cv.Optional(CONF_REQUEST_PIN): pins.gpio_output_pin_schema,
cv.Optional(
CONF_REQUEST_INTERVAL, default="0ms"
): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_RECEIVE_TIMEOUT, default="200ms"
): cv.positive_time_period_milliseconds,
}
).extend(uart.UART_DEVICE_SCHEMA),
cv.only_with_arduino,
@@ -68,17 +55,10 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
uart_component = await cg.get_variable(config[CONF_UART_ID])
var = cg.new_Pvariable(config[CONF_ID], uart_component, config[CONF_CRC_CHECK])
cg.add(var.set_max_telegram_length(config[CONF_MAX_TELEGRAM_LENGTH]))
if CONF_DECRYPTION_KEY in config:
cg.add(var.set_decryption_key(config[CONF_DECRYPTION_KEY]))
await cg.register_component(var, config)
if CONF_REQUEST_PIN in config:
request_pin = await cg.gpio_pin_expression(config[CONF_REQUEST_PIN])
cg.add(var.set_request_pin(request_pin))
cg.add(var.set_request_interval(config[CONF_REQUEST_INTERVAL].total_milliseconds))
cg.add(var.set_receive_timeout(config[CONF_RECEIVE_TIMEOUT].total_milliseconds))
cg.add_define("DSMR_GAS_MBUS_ID", config[CONF_GAS_MBUS_ID])
# DSMR Parser

View File

@@ -12,275 +12,171 @@ namespace dsmr {
static const char *const TAG = "dsmr";
void Dsmr::setup() {
this->telegram_ = new char[this->max_telegram_len_]; // NOLINT
if (this->request_pin_ != nullptr) {
this->request_pin_->setup();
}
}
void Dsmr::loop() {
if (this->ready_to_request_data_()) {
if (this->decryption_key_.empty()) {
this->receive_telegram_();
} else {
this->receive_encrypted_telegram_();
}
}
if (this->decryption_key_.empty())
this->receive_telegram_();
else
this->receive_encrypted_();
}
bool Dsmr::ready_to_request_data_() {
// When using a request pin, then wait for the next request interval.
if (this->request_pin_ != nullptr) {
if (!this->requesting_data_ && this->request_interval_reached_()) {
this->start_requesting_data_();
}
}
// Otherwise, sink serial data until next request interval.
else {
if (this->request_interval_reached_()) {
this->start_requesting_data_();
}
if (!this->requesting_data_) {
while (this->available()) {
this->read();
}
}
}
return this->requesting_data_;
}
bool Dsmr::request_interval_reached_() {
if (this->last_request_time_ == 0) {
return true;
}
return millis() - this->last_request_time_ > this->request_interval_;
}
bool Dsmr::receive_timeout_reached_() { return millis() - this->last_read_time_ > this->receive_timeout_; }
bool Dsmr::available_within_timeout_() {
// Data are available for reading on the UART bus?
// Then we can start reading right away.
if (this->available()) {
this->last_read_time_ = millis();
return true;
}
// When we're not in the process of reading a telegram, then there is
// no need to actively wait for new data to come in.
if (!header_found_) {
return false;
}
// A telegram is being read. The smart meter might not deliver a telegram
// in one go, but instead send it in chunks with small pauses in between.
// When the UART RX buffer cannot hold a full telegram, then make sure
// that the UART read buffer does not overflow while other components
// perform their work in their loop. Do this by not returning control to
// the main loop, until the read timeout is reached.
if (this->parent_->get_rx_buffer_size() < this->max_telegram_len_) {
while (!this->receive_timeout_reached_()) {
delay(5);
if (this->available()) {
this->last_read_time_ = millis();
return true;
}
uint8_t tries = READ_TIMEOUT_MS / 5;
while (tries--) {
delay(5);
if (available()) {
return true;
}
}
// No new data has come in during the read timeout? Then stop reading the
// telegram and start waiting for the next one to arrive.
if (this->receive_timeout_reached_()) {
ESP_LOGW(TAG, "Timeout while reading data for telegram");
this->reset_telegram_();
}
return false;
}
void Dsmr::start_requesting_data_() {
if (!this->requesting_data_) {
if (this->request_pin_ != nullptr) {
ESP_LOGV(TAG, "Start requesting data from P1 port");
this->request_pin_->digital_write(true);
} else {
ESP_LOGV(TAG, "Start reading data from P1 port");
}
this->requesting_data_ = true;
this->last_request_time_ = millis();
}
}
void Dsmr::stop_requesting_data_() {
if (this->requesting_data_) {
if (this->request_pin_ != nullptr) {
ESP_LOGV(TAG, "Stop requesting data from P1 port");
this->request_pin_->digital_write(false);
} else {
ESP_LOGV(TAG, "Stop reading data from P1 port");
}
while (this->available()) {
this->read();
}
this->requesting_data_ = false;
}
}
void Dsmr::reset_telegram_() {
this->header_found_ = false;
this->footer_found_ = false;
this->bytes_read_ = 0;
this->crypt_bytes_read_ = 0;
this->crypt_telegram_len_ = 0;
this->last_read_time_ = 0;
}
void Dsmr::receive_telegram_() {
while (this->available_within_timeout_()) {
const char c = this->read();
while (true) {
if (!available()) {
if (!header_found_ || !available_within_timeout_()) {
return;
}
}
const char c = read();
// Find a new telegram header, i.e. forward slash.
if (c == '/') {
ESP_LOGV(TAG, "Header of telegram found");
this->reset_telegram_();
this->header_found_ = true;
header_found_ = true;
footer_found_ = false;
telegram_len_ = 0;
}
if (!this->header_found_)
if (!header_found_)
continue;
// Check for buffer overflow.
if (this->bytes_read_ >= this->max_telegram_len_) {
this->reset_telegram_();
ESP_LOGE(TAG, "Error: telegram larger than buffer (%d bytes)", this->max_telegram_len_);
if (telegram_len_ >= MAX_TELEGRAM_LENGTH) {
header_found_ = false;
footer_found_ = false;
ESP_LOGE(TAG, "Error: telegram larger than buffer (%d bytes)", MAX_TELEGRAM_LENGTH);
return;
}
// Some v2.2 or v3 meters will send a new value which starts with '('
// in a new line, while the value belongs to the previous ObisId. For
// proper parsing, remove these new line characters.
if (c == '(') {
while (true) {
auto previous_char = this->telegram_[this->bytes_read_ - 1];
if (previous_char == '\n' || previous_char == '\r') {
this->bytes_read_--;
} else {
break;
}
}
}
// in a new line while the value belongs to the previous ObisId. For
// proper parsing remove these new line characters
while (c == '(' && (telegram_[telegram_len_ - 1] == '\n' || telegram_[telegram_len_ - 1] == '\r'))
telegram_len_--;
// Store the byte in the buffer.
this->telegram_[this->bytes_read_] = c;
this->bytes_read_++;
telegram_[telegram_len_] = c;
telegram_len_++;
// Check for a footer, i.e. exlamation mark, followed by a hex checksum.
if (c == '!') {
ESP_LOGV(TAG, "Footer of telegram found");
this->footer_found_ = true;
footer_found_ = true;
continue;
}
// Check for the end of the hex checksum, i.e. a newline.
if (this->footer_found_ && c == '\n') {
if (footer_found_ && c == '\n') {
// Parse the telegram and publish sensor values.
this->parse_telegram();
this->reset_telegram_();
parse_telegram();
header_found_ = false;
return;
}
}
}
void Dsmr::receive_encrypted_telegram_() {
while (this->available_within_timeout_()) {
const char c = this->read();
void Dsmr::receive_encrypted_() {
// Encrypted buffer
uint8_t buffer[MAX_TELEGRAM_LENGTH];
size_t buffer_length = 0;
size_t packet_size = 0;
while (true) {
if (!available()) {
if (!header_found_) {
return;
}
if (!available_within_timeout_()) {
ESP_LOGW(TAG, "Timeout while reading data for encrypted telegram");
return;
}
}
const char c = read();
// Find a new telegram start byte.
if (!this->header_found_) {
if (!header_found_) {
if ((uint8_t) c != 0xDB) {
continue;
}
ESP_LOGV(TAG, "Start byte 0xDB of encrypted telegram found");
this->reset_telegram_();
this->header_found_ = true;
header_found_ = true;
}
// Check for buffer overflow.
if (this->crypt_bytes_read_ >= this->max_telegram_len_) {
this->reset_telegram_();
ESP_LOGE(TAG, "Error: encrypted telegram larger than buffer (%d bytes)", this->max_telegram_len_);
if (buffer_length >= MAX_TELEGRAM_LENGTH) {
header_found_ = false;
ESP_LOGE(TAG, "Error: encrypted telegram larger than buffer (%d bytes)", MAX_TELEGRAM_LENGTH);
return;
}
// Store the byte in the buffer.
this->crypt_telegram_[this->crypt_bytes_read_] = c;
this->crypt_bytes_read_++;
buffer[buffer_length++] = c;
// Read the length of the incoming encrypted telegram.
if (this->crypt_telegram_len_ == 0 && this->crypt_bytes_read_ > 20) {
if (packet_size == 0 && buffer_length > 20) {
// Complete header + data bytes
this->crypt_telegram_len_ = 13 + (this->crypt_telegram_[11] << 8 | this->crypt_telegram_[12]);
ESP_LOGV(TAG, "Encrypted telegram length: %d bytes", this->crypt_telegram_len_);
packet_size = 13 + (buffer[11] << 8 | buffer[12]);
ESP_LOGV(TAG, "Encrypted telegram size: %d bytes", packet_size);
}
if (buffer_length == packet_size && packet_size > 0) {
ESP_LOGV(TAG, "End of encrypted telegram found");
GCM<AES128> *gcmaes128{new GCM<AES128>()};
gcmaes128->setKey(this->decryption_key_.data(), gcmaes128->keySize());
// the iv is 8 bytes of the system title + 4 bytes frame counter
// system title is at byte 2 and frame counter at byte 15
for (int i = 10; i < 14; i++)
buffer[i] = buffer[i + 4];
constexpr uint16_t iv_size{12};
gcmaes128->setIV(&buffer[2], iv_size);
gcmaes128->decrypt(reinterpret_cast<uint8_t *>(this->telegram_),
// the ciphertext start at byte 18
&buffer[18],
// cipher size
buffer_length - 17);
delete gcmaes128; // NOLINT(cppcoreguidelines-owning-memory)
// Check for the end of the encrypted telegram.
if (this->crypt_telegram_len_ == 0 || this->crypt_bytes_read_ != this->crypt_telegram_len_) {
continue;
telegram_len_ = strnlen(this->telegram_, sizeof(this->telegram_));
ESP_LOGV(TAG, "Decrypted telegram size: %d bytes", telegram_len_);
ESP_LOGVV(TAG, "Decrypted telegram: %s", this->telegram_);
parse_telegram();
header_found_ = false;
telegram_len_ = 0;
return;
}
ESP_LOGV(TAG, "End of encrypted telegram found");
// Decrypt the encrypted telegram.
GCM<AES128> *gcmaes128{new GCM<AES128>()};
gcmaes128->setKey(this->decryption_key_.data(), gcmaes128->keySize());
// the iv is 8 bytes of the system title + 4 bytes frame counter
// system title is at byte 2 and frame counter at byte 15
for (int i = 10; i < 14; i++)
this->crypt_telegram_[i] = this->crypt_telegram_[i + 4];
constexpr uint16_t iv_size{12};
gcmaes128->setIV(&this->crypt_telegram_[2], iv_size);
gcmaes128->decrypt(reinterpret_cast<uint8_t *>(this->telegram_),
// the ciphertext start at byte 18
&this->crypt_telegram_[18],
// cipher size
this->crypt_bytes_read_ - 17);
delete gcmaes128; // NOLINT(cppcoreguidelines-owning-memory)
this->bytes_read_ = strnlen(this->telegram_, this->max_telegram_len_);
ESP_LOGV(TAG, "Decrypted telegram size: %d bytes", this->bytes_read_);
ESP_LOGVV(TAG, "Decrypted telegram: %s", this->telegram_);
// Parse the decrypted telegram and publish sensor values.
this->parse_telegram();
this->reset_telegram_();
return;
}
}
bool Dsmr::parse_telegram() {
MyData data;
ESP_LOGV(TAG, "Trying to parse telegram");
this->stop_requesting_data_();
::dsmr::ParseResult<void> res =
::dsmr::P1Parser::parse(&data, this->telegram_, this->bytes_read_, false,
::dsmr::P1Parser::parse(&data, telegram_, telegram_len_, false,
this->crc_check_); // Parse telegram according to data definition. Ignore unknown values.
if (res.err) {
// Parsing error, show it
auto err_str = res.fullError(this->telegram_, this->telegram_ + this->bytes_read_);
auto err_str = res.fullError(telegram_, telegram_ + telegram_len_);
ESP_LOGE(TAG, "%s", err_str.c_str());
return false;
} else {
this->status_clear_warning();
this->publish_sensors(data);
publish_sensors(data);
return true;
}
}
void Dsmr::dump_config() {
ESP_LOGCONFIG(TAG, "DSMR:");
ESP_LOGCONFIG(TAG, " Max telegram length: %d", this->max_telegram_len_);
ESP_LOGCONFIG(TAG, " Receive timeout: %.1fs", this->receive_timeout_ / 1e3f);
if (this->request_pin_ != nullptr) {
LOG_PIN(" Request Pin: ", this->request_pin_);
}
if (this->request_interval_ > 0) {
ESP_LOGCONFIG(TAG, " Request Interval: %.1fs", this->request_interval_ / 1e3f);
}
#define DSMR_LOG_SENSOR(s) LOG_SENSOR(" ", #s, this->s_##s##_);
DSMR_SENSOR_LIST(DSMR_LOG_SENSOR, )
@@ -293,10 +189,6 @@ void Dsmr::set_decryption_key(const std::string &decryption_key) {
if (decryption_key.length() == 0) {
ESP_LOGI(TAG, "Disabling decryption");
this->decryption_key_.clear();
if (this->crypt_telegram_ != nullptr) {
delete[] this->crypt_telegram_;
this->crypt_telegram_ = nullptr;
}
return;
}
@@ -313,11 +205,7 @@ void Dsmr::set_decryption_key(const std::string &decryption_key) {
char temp[3] = {0};
for (int i = 0; i < 16; i++) {
strncpy(temp, &(decryption_key.c_str()[i * 2]), 2);
this->decryption_key_.push_back(std::strtoul(temp, nullptr, 16));
}
if (this->crypt_telegram_ == nullptr) {
this->crypt_telegram_ = new uint8_t[this->max_telegram_len_]; // NOLINT
decryption_key_.push_back(std::strtoul(temp, nullptr, 16));
}
}

View File

@@ -16,6 +16,9 @@
namespace esphome {
namespace dsmr {
static constexpr uint32_t MAX_TELEGRAM_LENGTH = 1500;
static constexpr uint32_t READ_TIMEOUT_MS = 200;
using namespace ::dsmr::fields;
// DSMR_**_LIST generated by ESPHome and written in esphome/core/defines
@@ -49,7 +52,6 @@ class Dsmr : public Component, public uart::UARTDevice {
public:
Dsmr(uart::UARTComponent *uart, bool crc_check) : uart::UARTDevice(uart), crc_check_(crc_check) {}
void setup() override;
void loop() override;
bool parse_telegram();
@@ -69,10 +71,6 @@ class Dsmr : public Component, public uart::UARTDevice {
void dump_config() override;
void set_decryption_key(const std::string &decryption_key);
void set_max_telegram_length(size_t length) { this->max_telegram_len_ = length; }
void set_request_pin(GPIOPin *request_pin) { this->request_pin_ = request_pin; }
void set_request_interval(uint32_t interval) { this->request_interval_ = interval; }
void set_receive_timeout(uint32_t timeout) { this->receive_timeout_ = timeout; }
// Sensor setters
#define DSMR_SET_SENSOR(s) \
@@ -85,8 +83,7 @@ class Dsmr : public Component, public uart::UARTDevice {
protected:
void receive_telegram_();
void receive_encrypted_telegram_();
void reset_telegram_();
void receive_encrypted_();
/// Wait for UART data to become available within the read timeout.
///
@@ -99,26 +96,11 @@ class Dsmr : public Component, public uart::UARTDevice {
/// lost in the process.
bool available_within_timeout_();
// Request telegram
uint32_t request_interval_;
bool request_interval_reached_();
GPIOPin *request_pin_{nullptr};
uint32_t last_request_time_{0};
bool requesting_data_{false};
bool ready_to_request_data_();
void start_requesting_data_();
void stop_requesting_data_();
// Telegram buffer
char telegram_[MAX_TELEGRAM_LENGTH];
int telegram_len_{0};
// Read telegram
uint32_t receive_timeout_;
bool receive_timeout_reached_();
size_t max_telegram_len_;
char *telegram_{nullptr};
size_t bytes_read_{0};
uint8_t *crypt_telegram_{nullptr};
size_t crypt_telegram_len_{0};
size_t crypt_bytes_read_{0};
uint32_t last_read_time_{0};
// Serial parser
bool header_found_{false};
bool footer_found_{false};

View File

@@ -23,24 +23,22 @@ void DutyCycleSensor::dump_config() {
}
void DutyCycleSensor::update() {
const uint32_t now = micros();
const uint32_t last_interrupt = this->store_.last_interrupt; // Read the measurement taken by the interrupt
uint32_t on_time = this->store_.on_time;
this->store_.on_time = 0; // Start new measurement, exactly aligned with the micros() reading
this->store_.last_interrupt = now;
if (this->last_update_ != 0) {
const bool level = this->store_.last_level;
const uint32_t last_interrupt = this->store_.last_interrupt;
uint32_t on_time = this->store_.on_time;
if (level)
on_time += now - last_interrupt;
const float total_time = float(now - this->last_update_);
const float value = (on_time * 100.0f) / total_time;
const float value = (on_time / total_time) * 100.0f;
ESP_LOGD(TAG, "'%s' Got duty cycle=%.1f%%", this->get_name().c_str(), value);
this->publish_state(value);
}
this->store_.on_time = 0;
this->store_.last_interrupt = now;
this->last_update_ = now;
}

View File

@@ -2,9 +2,8 @@ from dataclasses import dataclass
from typing import Union
from pathlib import Path
import logging
import os
from esphome.helpers import copy_file_if_changed, write_file_if_changed
from esphome.helpers import write_file_if_changed
from esphome.const import (
CONF_BOARD,
CONF_FRAMEWORK,
@@ -296,8 +295,6 @@ async def to_code(config):
conf = config[CONF_FRAMEWORK]
cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION])
cg.add_platformio_option("extra_scripts", ["post:post_build.py"])
if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF:
cg.add_platformio_option("framework", "espidf")
cg.add_build_flag("-DUSE_ESP_IDF")
@@ -314,16 +311,9 @@ async def to_code(config):
)
add_idf_sdkconfig_option("CONFIG_COMPILER_OPTIMIZATION_DEFAULT", False)
add_idf_sdkconfig_option("CONFIG_COMPILER_OPTIMIZATION_SIZE", True)
# Increase freertos tick speed from 100Hz to 1kHz so that delay() resolution is 1ms
add_idf_sdkconfig_option("CONFIG_FREERTOS_HZ", 1000)
# Setup watchdog
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT", True)
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_PANIC", True)
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0", False)
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1", False)
cg.add_platformio_option("board_build.partitions", "partitions.csv")
for name, value in conf[CONF_SDKCONFIG_OPTIONS].items():
@@ -415,10 +405,3 @@ def copy_files():
CORE.relative_build_path("partitions.csv"),
IDF_PARTITIONS_CSV,
)
dir = os.path.dirname(__file__)
post_build_file = os.path.join(dir, "post_build.py.script")
copy_file_if_changed(
post_build_file,
CORE.relative_build_path("post_build.py"),
)

View File

@@ -261,37 +261,6 @@ ESP32_BOARD_PINS = {
"SS": 33,
"TX": 17,
},
"featheresp32-s2": {
"SDA": 3,
"SCL": 4,
"SS": 42,
"MOSI": 35,
"SCK": 36,
"MISO": 37,
"A0": 18,
"A1": 17,
"A10": 27,
"A11": 12,
"A12": 13,
"A13": 35,
"A2": 16,
"A3": 15,
"A4": 14,
"A5": 8,
"LED": 13,
"TX": 39,
"RX": 38,
"T5": 5,
"T8": 8,
"T9": 9,
"T10": 10,
"T11": 11,
"T12": 12,
"T13": 13,
"T14": 14,
"DAC1": 17,
"DAC2": 18,
},
"firebeetle32": {"LED": 2},
"fm-devkit": {
"D0": 34,

View File

@@ -6,17 +6,12 @@
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_idf_version.h>
#include <esp_task_wdt.h>
#include <soc/rtc.h>
#if ESP_IDF_VERSION_MAJOR >= 4
#include <hal/cpu_hal.h>
#endif
#ifdef USE_ARDUINO
#include <esp32-hal.h>
#endif
void setup();
void loop();
@@ -34,24 +29,24 @@ void arch_restart() {
yield();
}
}
void IRAM_ATTR HOT arch_feed_wdt() {
#ifdef USE_ARDUINO
#if CONFIG_ARDUINO_RUNNING_CORE == 0
#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
// ESP32 uses "Task Watchdog" which is hooked to the FreeRTOS idle task.
// To cause the Watchdog to be triggered we need to put the current task
// to sleep to get the idle task scheduled.
delay(1);
#endif
#endif
#endif // USE_ARDUINO
void arch_init() {
// Enable the task watchdog only on the loop task (from which we're currently running)
#if defined(USE_ESP_IDF)
esp_task_wdt_add(nullptr);
// Idle task watchdog is disabled on ESP-IDF
#elif defined(USE_ARDUINO)
enableLoopWDT();
// Disable idle task watchdog on the core we're using (Arduino pins the task to a core)
#if defined(CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0) && CONFIG_ARDUINO_RUNNING_CORE == 0
disableCore0WDT();
#endif
#if defined(CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1) && CONFIG_ARDUINO_RUNNING_CORE == 1
disableCore1WDT();
#endif
#ifdef USE_ESP_IDF
#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
delay(1);
#endif
#endif // USE_ESP_IDF
}
void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); }
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
uint32_t arch_get_cpu_cycle_count() {

View File

@@ -18,7 +18,7 @@ _ESP_SDIO_PINS = {
11: "Flash Command",
}
_ESP32_STRAPPING_PINS = {0, 2, 4, 12, 15}
_ESP32_STRAPPING_PINS = {0, 2, 4, 15}
_LOGGER = logging.getLogger(__name__)

View File

@@ -1,43 +0,0 @@
# Source https://github.com/letscontrolit/ESPEasy/pull/3845#issuecomment-1005864664
import esptool
# pylint: disable=E0602
Import("env") # noqa
def esp32_create_combined_bin(source, target, env):
print("Generating combined binary for serial flashing")
app_offset = 0x10000
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}-factory.bin")
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
chip = env.get("BOARD_MCU")
flash_size = env.BoardConfig().get("upload.flash_size")
cmd = [
"--chip",
chip,
"merge_bin",
"-o",
new_file_name,
"--flash_size",
flash_size,
]
print(" Offset | File")
for section in sections:
sect_adr, sect_file = section.split(" ", 1)
print(f" - {sect_adr} | {sect_file}")
cmd += [sect_adr, sect_file]
print(f" - {hex(app_offset)} | {firmware_name}")
cmd += [hex(app_offset), firmware_name]
print()
print(f"Using esptool.py arguments: {' '.join(cmd)}")
print()
esptool.main(cmd)
# pylint: disable=E0602
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin) # noqa

View File

@@ -76,7 +76,6 @@ class ESP32Preferences : public ESPPreferences {
uint32_t current_offset = 0;
void open() {
nvs_flash_init();
esp_err_t err = nvs_open("esphome", NVS_READWRITE, &nvs_handle);
if (err == 0)
return;

View File

@@ -1,60 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import esp32_ble_server, logger
from esphome.const import (
CONF_BLE_SERVER_ID,
CONF_ID,
CONF_LEVEL,
CONF_LOGGER,
ESP_PLATFORM_ESP32,
)
AUTO_LOAD = ["esp32_ble_server"]
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
CODEOWNERS = ["@jesserockz"]
CONFLICTS_WITH = ["esp32_ble_tracker", "esp32_ble_beacon"]
CONF_LOG_LEVEL = "log_level"
esp32_ble_controller_ns = cg.esphome_ns.namespace("esp32_ble_controller")
BLEController = esp32_ble_controller_ns.class_(
"BLEController",
cg.Component,
cg.Controller,
esp32_ble_server.BLEServiceComponent,
)
def validate(config, item_config):
global_level = config[CONF_LOGGER][CONF_LEVEL]
level = item_config.get(CONF_LOG_LEVEL, "DEBUG")
if logger.LOG_LEVEL_SEVERITY.index(level) > logger.LOG_LEVEL_SEVERITY.index(
global_level
):
raise ValueError(
"The esp32_ble_controller log level {} must be less severe than the "
"global log level {}.".format(level, global_level)
)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(BLEController),
cv.GenerateID(CONF_BLE_SERVER_ID): cv.use_id(esp32_ble_server.BLEServer),
cv.Optional(CONF_LOG_LEVEL): cv.All(
cv.requires_component("logger"),
logger.is_log_level,
),
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
ble_server = await cg.get_variable(config[CONF_BLE_SERVER_ID])
cg.add(ble_server.register_service_component(var))
if CONF_LOG_LEVEL in config:
cg.add(var.set_log_level(logger.LOG_LEVELS[config[CONF_LOG_LEVEL]]))

View File

@@ -1,387 +0,0 @@
#include "ble_controller.h"
#include "esphome/core/application.h"
#include "esphome/components/esp32_ble_server/ble_2901.h"
#include "esphome/components/esp32_ble_server/ble_2902.h"
#ifdef USE_LOGGER
#include "esphome/components/logger/logger.h"
#endif
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace esp32_ble_controller {
static const char *const ESPHOME_SERVICE_UUID = "03774663-d394-496e-8dcd-000000000000";
static const char *const LOGGER_CHARACTERISTIC_UUID = "03774663-d394-496e-8dcd-000000000001";
static const char *const BINARY_SENSOR_SERVICE_UUID = "03774663-d394-496e-8dcd-000100000000";
static const char *const COVER_SERVICE_UUID = "03774663-d394-496e-8dcd-000200000000";
static const char *const FAN_SERVICE_UUID = "03774663-d394-496e-8dcd-000300000000";
static const char *const LIGHT_SERVICE_UUID = "03774663-d394-496e-8dcd-000400000000";
static const char *const SENSOR_SERVICE_UUID = "03774663-d394-496e-8dcd-000500000000";
static const char *const SWITCH_SERVICE_UUID = "03774663-d394-496e-8dcd-000600000000";
static const char *const TEXT_SENSOR_SERVICE_UUID = "03774663-d394-496e-8dcd-000700000000";
static const char *const CLIMATE_SERVICE_UUID = "03774663-d394-496e-8dcd-000800000000";
static const char *const TAG = "esp32_ble_controller";
void BLEController::setup() {
ESP_LOGD(TAG, "Setting up BLE controller");
this->esphome_service_ = global_ble_server->create_service(ESPHOME_SERVICE_UUID);
#ifdef USE_LOGGER
{
this->logger_characteristic_ = this->esphome_service_->create_characteristic(
LOGGER_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor *logger_name = new BLE2901("Logger");
this->logger_characteristic_->add_descriptor(logger_name);
BLEDescriptor *descriptor_2902 = new BLE2902();
this->logger_characteristic_->add_descriptor(descriptor_2902);
}
#endif
#ifdef USE_BINARY_SENSOR
{
auto binary_sensors = App.get_binary_sensors();
if (!binary_sensors.empty()) {
this->binary_sensor_service_ = global_ble_server->create_service(BINARY_SENSOR_SERVICE_UUID);
for (auto *obj : binary_sensors) {
std::string uuid = std::string(BINARY_SENSOR_SERVICE_UUID).substr(0, 28);
uuid += uint32_to_string(obj->get_object_id_hash());
BLECharacteristic *characteristic = this->binary_sensor_service_->create_characteristic(
uuid, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor *name = new BLE2901(obj->get_name());
characteristic->add_descriptor(name);
BLEDescriptor *descriptor = new BLE2902();
characteristic->add_descriptor(descriptor);
this->characteristics_.insert(
std::pair<uint32_t, BLECharacteristic *>(obj->get_object_id_hash(), characteristic));
}
}
}
#endif
#ifdef USE_COVER
if (!App.get_covers().empty()) {
this->cover_service_ = global_ble_server->create_service(COVER_SERVICE_UUID);
}
#endif
#ifdef USE_FAN
if (!App.get_fans().empty()) {
this->fan_service_ = global_ble_server->create_service(FAN_SERVICE_UUID);
}
#endif
#ifdef USE_LIGHT
if (!App.get_lights().empty()) {
this->light_service_ = global_ble_server->create_service(LIGHT_SERVICE_UUID);
}
#endif
#ifdef USE_SENSOR
{
auto sensors = App.get_sensors();
if (!sensors.empty()) {
this->sensor_service_ = global_ble_server->create_service(SENSOR_SERVICE_UUID);
for (auto *obj : sensors) {
std::string uuid = std::string(SENSOR_SERVICE_UUID).substr(0, 28);
uuid += uint32_to_string(obj->get_object_id_hash());
BLECharacteristic *characteristic = this->sensor_service_->create_characteristic(
uuid, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor *name = new BLE2901(obj->get_name());
characteristic->add_descriptor(name);
BLEDescriptor *descriptor = new BLE2902();
characteristic->add_descriptor(descriptor);
this->characteristics_.insert(
std::pair<uint32_t, BLECharacteristic *>(obj->get_object_id_hash(), characteristic));
}
}
}
#endif
#ifdef USE_SWITCH
{
auto switches = App.get_switches();
if (!switches.empty()) {
this->switch_service_ = global_ble_server->create_service(SWITCH_SERVICE_UUID);
for (auto *obj : switches) {
std::string uuid = std::string(SWITCH_SERVICE_UUID).substr(0, 28);
uuid += uint32_to_string(obj->get_object_id_hash());
BLECharacteristic *characteristic = this->switch_service_->create_characteristic(
uuid,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_WRITE);
BLEDescriptor *name = new BLE2901(obj->get_name());
characteristic->add_descriptor(name);
BLEDescriptor *descriptor = new BLE2902();
characteristic->add_descriptor(descriptor);
this->characteristics_.insert(
std::pair<uint32_t, BLECharacteristic *>(obj->get_object_id_hash(), characteristic));
characteristic->on_write([obj](std::vector<uint8_t> data) {
if (data[0])
obj->turn_on();
else
obj->turn_off();
});
}
}
}
#endif
#ifdef USE_TEXT_SENSOR
{
auto text_sensors = App.get_text_sensors();
if (!text_sensors.empty()) {
this->text_sensor_service_ = global_ble_server->create_service(TEXT_SENSOR_SERVICE_UUID);
for (auto *obj : text_sensors) {
std::string uuid = std::string(TEXT_SENSOR_SERVICE_UUID).substr(0, 28);
uuid += uint32_to_string(obj->get_object_id_hash());
BLECharacteristic *characteristic = this->text_sensor_service_->create_characteristic(
uuid, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor *name = new BLE2901(obj->get_name());
characteristic->add_descriptor(name);
BLEDescriptor *descriptor = new BLE2902();
characteristic->add_descriptor(descriptor);
this->characteristics_.insert(
std::pair<uint32_t, BLECharacteristic *>(obj->get_object_id_hash(), characteristic));
}
}
}
#endif
#ifdef USE_CLIMATE
if (!App.get_climates().empty()) {
this->cover_service_ = global_ble_server->create_service(COVER_SERVICE_UUID);
}
#endif
this->state_ = CREATING;
this->setup_controller();
}
void BLEController::loop() {
switch (this->state_) {
case CREATING: {
bool all_created = true;
all_created &= this->esphome_service_->is_created();
#ifdef USE_BINARY_SENSOR
all_created &= this->binary_sensor_service_ == nullptr || this->binary_sensor_service_->is_created();
#endif
#ifdef USE_COVER
all_created &= this->cover_service_ == nullptr || this->cover_service_->is_created();
#endif
#ifdef USE_FAN
all_created &= this->fan_service_ == nullptr || this->fan_service_->is_created();
#endif
#ifdef USE_LIGHT
all_created &= this->light_service_ == nullptr || this->light_service_->is_created();
#endif
#ifdef USE_SENSOR
all_created &= this->sensor_service_ == nullptr || this->sensor_service_->is_created();
#endif
#ifdef USE_SWITCH
all_created &= this->switch_service_ == nullptr || this->switch_service_->is_created();
#endif
#ifdef USE_TEXT_SENSOR
all_created &= this->text_sensor_service_ == nullptr || this->text_sensor_service_->is_created();
#endif
#ifdef USE_CLIMATE
all_created &= this->climate_service_ == nullptr || this->climate_service_->is_created();
#endif
if (all_created) {
ESP_LOGI(TAG, "All services created");
this->state_ = STARTING;
}
break;
}
case STARTING: {
bool all_running = true;
all_running &= this->esphome_service_->is_running();
#ifdef USE_BINARY_SENSOR
all_running &= this->binary_sensor_service_ == nullptr || this->binary_sensor_service_->is_running();
#endif
#ifdef USE_COVER
all_running &= this->cover_service_ == nullptr || this->cover_service_->is_running();
#endif
#ifdef USE_FAN
all_running &= this->fan_service_ == nullptr || this->fan_service_->is_running();
#endif
#ifdef USE_LIGHT
all_running &= this->light_service_ == nullptr || this->light_service_->is_running();
#endif
#ifdef USE_SENSOR
all_running &= this->sensor_service_ == nullptr || this->sensor_service_->is_running();
#endif
#ifdef USE_SWITCH
all_running &= this->switch_service_ == nullptr || this->switch_service_->is_running();
#endif
#ifdef USE_TEXT_SENSOR
all_running &= this->text_sensor_service_ == nullptr || this->text_sensor_service_->is_running();
#endif
#ifdef USE_CLIMATE
all_running &= this->climate_service_ == nullptr || this->climate_service_->is_running();
#endif
if (all_running) {
ESP_LOGD(TAG, "BLE Controller started");
this->state_ = RUNNING;
#ifdef USE_LOGGER
logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
if (level > this->log_level_)
return;
std::string log;
log += "[";
log += tag;
log += "] ";
log += message;
this->logger_characteristic_->set_value(log);
this->logger_characteristic_->notify();
});
#endif
} else {
this->esphome_service_->start();
#ifdef USE_BINARY_SENSOR
this->binary_sensor_service_->start();
#endif
#ifdef USE_COVER
this->cover_service_->start();
#endif
#ifdef USE_FAN
this->fan_service_->start();
#endif
#ifdef USE_LIGHT
this->light_service_->start();
#endif
#ifdef USE_SENSOR
this->sensor_service_->start();
#endif
#ifdef USE_SWITCH
this->switch_service_->start();
#endif
#ifdef USE_TEXT_SENSOR
this->text_sensor_service_->start();
#endif
#ifdef USE_CLIMATE
this->climate_service_->start();
#endif
}
break;
}
case RUNNING:
case INIT:
break;
default:
break;
}
}
void BLEController::start() {
if (this->state_ == RUNNING)
return;
this->state_ = STARTING;
}
void BLEController::stop() {
this->esphome_service_->stop();
#ifdef USE_BINARY_SENSOR
this->binary_sensor_service_->stop();
#endif
#ifdef USE_COVER
this->cover_service_->stop();
#endif
#ifdef USE_FAN
this->fan_service_->stop();
#endif
#ifdef USE_LIGHT
this->light_service_->stop();
#endif
#ifdef USE_SENSOR
this->sensor_service_->stop();
#endif
#ifdef USE_SWITCH
this->switch_service_->stop();
#endif
#ifdef USE_TEXT_SENSOR
this->text_sensor_service_->stop();
#endif
#ifdef USE_CLIMATE
this->climate_service_->stop();
#endif
}
float BLEController::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; }
#ifdef USE_BINARY_SENSOR
void BLEController::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
if (obj->is_internal())
return;
auto *characteristic = this->characteristics_[obj->get_object_id_hash()];
characteristic->set_value(state);
characteristic->notify();
}
#endif
#ifdef USE_COVER
void BLEController::on_cover_update(cover::Cover *obj) {
if (obj->is_internal())
return;
}
#endif
#ifdef USE_FAN
void BLEController::on_fan_update(fan::FanState *obj) {
if (obj->is_internal())
return;
}
#endif
#ifdef USE_LIGHT
void BLEController::on_light_update(light::LightState *obj) {
if (obj->is_internal())
return;
}
#endif
#ifdef USE_SENSOR
void BLEController::on_sensor_update(sensor::Sensor *obj, float state) {
if (obj->is_internal())
return;
auto *characteristic = this->characteristics_[obj->get_object_id_hash()];
characteristic->set_value(state);
characteristic->notify();
}
#endif
#ifdef USE_SWITCH
void BLEController::on_switch_update(switch_::Switch *obj, bool state) {
if (obj->is_internal())
return;
auto *characteristic = this->characteristics_[obj->get_object_id_hash()];
characteristic->set_value(state);
characteristic->notify();
}
#endif
#ifdef USE_TEXT_SENSOR
void BLEController::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) {
if (obj->is_internal())
return;
auto *characteristic = this->characteristics_[obj->get_object_id_hash()];
characteristic->set_value(state);
characteristic->notify();
}
#endif
#ifdef USE_CLIMATE
void BLEController::on_climate_update(climate::Climate *obj) {
if (obj->is_internal())
return;
}
#endif
} // namespace esp32_ble_controller
} // namespace esphome
#endif

View File

@@ -1,106 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/controller.h"
#include "esphome/components/esp32_ble_server/ble_2901.h"
#include "esphome/components/esp32_ble_server/ble_2902.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include <map>
#ifdef USE_LOGGER
#include "esphome/core/log.h"
#endif
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace esp32_ble_controller {
using namespace esp32_ble_server;
class BLEController : public Component, public Controller, public esp32_ble_server::BLEServiceComponent {
public:
void loop() override;
void setup() override;
void start() override;
void stop() override;
float get_setup_priority() const override;
#ifdef USE_LOGGER
void set_log_level(int level) { this->log_level_ = level; }
#endif
#ifdef USE_BINARY_SENSOR
void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override;
#endif
#ifdef USE_COVER
void on_cover_update(cover::Cover *obj) override;
#endif
#ifdef USE_FAN
void on_fan_update(fan::FanState *obj) override;
#endif
#ifdef USE_LIGHT
void on_light_update(light::LightState *obj) override;
#endif
#ifdef USE_SENSOR
void on_sensor_update(sensor::Sensor *obj, float state) override;
#endif
#ifdef USE_SWITCH
void on_switch_update(switch_::Switch *obj, bool state) override;
#endif
#ifdef USE_TEXT_SENSOR
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override;
#endif
#ifdef USE_CLIMATE
void on_climate_update(climate::Climate *obj) override;
#endif
protected:
enum State : uint8_t {
FAILED = 0x00,
INIT,
CREATING,
STARTING,
RUNNING,
} state_{INIT};
std::map<uint32_t, BLECharacteristic *> characteristics_;
BLEService *esphome_service_;
#ifdef USE_LOGGER
BLECharacteristic *logger_characteristic_;
int log_level_{ESPHOME_LOG_LEVEL_DEBUG};
#endif
#ifdef USE_BINARY_SENSOR
BLEService *binary_sensor_service_;
#endif
#ifdef USE_COVER
BLEService *cover_service_;
#endif
#ifdef USE_FAN
BLEService *fan_service_;
#endif
#ifdef USE_LIGHT
BLEService *light_service_;
#endif
#ifdef USE_SENSOR
BLEService *sensor_service_;
#endif
#ifdef USE_SWITCH
BLEService *switch_service_;
#endif
#ifdef USE_TEXT_SENSOR
BLEService *text_sensor_service_;
#endif
#ifdef USE_CLIMATE
BLEService *climate_service_;
#endif
};
} // namespace esp32_ble_controller
} // namespace esphome
#endif

View File

@@ -61,11 +61,14 @@ void BLEServer::loop() {
break;
}
case STARTING_SERVICE: {
if (!this->device_information_service_->is_created()) {
break;
}
if (this->device_information_service_->is_running()) {
this->state_ = RUNNING;
this->can_proceed_ = true;
ESP_LOGD(TAG, "BLE server setup successfully");
} else if (this->device_information_service_->is_created() && !this->device_information_service_->is_starting()) {
} else if (!this->device_information_service_->is_starting()) {
this->device_information_service_->start();
}
break;

View File

@@ -72,14 +72,9 @@ bool BLEService::do_create_characteristics_() {
}
void BLEService::start() {
if (this->running_state_ == RUNNING)
return;
if (this->do_create_characteristics_())
return;
ESP_LOGD(TAG, "Starting BLE service %s", this->uuid_.to_string().c_str());
esp_err_t err = esp_ble_gatts_start_service(this->handle_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ble_gatts_start_service failed: %d", err);
@@ -117,14 +112,12 @@ void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t g
if (this->uuid_ == ESPBTUUID::from_uuid(param->create.service_id.id.uuid) &&
this->inst_id_ == param->create.service_id.id.inst_id) {
this->handle_ = param->create.service_handle;
ESP_LOGI(TAG, "Service %s created", this->uuid_.to_string().c_str());
this->init_state_ = CREATED;
}
break;
}
case ESP_GATTS_START_EVT: {
if (param->start.service_handle == this->handle_) {
ESP_LOGI(TAG, "Service %s started", this->uuid_.to_string().c_str());
this->running_state_ = RUNNING;
}
break;

View File

@@ -483,7 +483,6 @@ optional<ESPBLEiBeacon> ESPBLEiBeacon::from_manufacturer_data(const ServiceData
}
void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param) {
this->scan_result_ = param;
for (uint8_t i = 0; i < ESP_BD_ADDR_LEN; i++)
this->address_[i] = param.bda[i];
this->address_type_ = param.ble_addr_type;
@@ -525,7 +524,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
ESP_LOGVV(TAG, " Service UUID: %s", uuid.to_string().c_str());
}
for (auto &data : this->manufacturer_datas_) {
ESP_LOGVV(TAG, " Manufacturer data: %s", format_hex_pretty(data.data).c_str());
ESP_LOGVV(TAG, " Manufacturer data: %s", hexencode(data.data).c_str());
if (this->get_ibeacon().has_value()) {
auto ibeacon = this->get_ibeacon().value();
ESP_LOGVV(TAG, " iBeacon data:");
@@ -538,10 +537,10 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
for (auto &data : this->service_datas_) {
ESP_LOGVV(TAG, " Service data:");
ESP_LOGVV(TAG, " UUID: %s", data.uuid.to_string().c_str());
ESP_LOGVV(TAG, " Data: %s", format_hex_pretty(data.data).c_str());
ESP_LOGVV(TAG, " Data: %s", hexencode(data.data).c_str());
}
ESP_LOGVV(TAG, "Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str());
ESP_LOGVV(TAG, "Adv data: %s", hexencode(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str());
#endif
}
void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param) {

View File

@@ -97,8 +97,6 @@ class ESPBTDevice {
const std::vector<ServiceData> &get_service_datas() const { return service_datas_; }
const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &get_scan_result() const { return scan_result_; }
optional<ESPBLEiBeacon> get_ibeacon() const {
for (auto &it : this->manufacturer_datas_) {
auto res = ESPBLEiBeacon::from_manufacturer_data(it);
@@ -123,7 +121,6 @@ class ESPBTDevice {
std::vector<ESPBTUUID> service_uuids_;
std::vector<ServiceData> manufacturer_datas_{};
std::vector<ServiceData> service_datas_{};
esp_ble_gap_cb_param_t::ble_scan_result_evt_param scan_result_{};
};
class ESP32BLETracker;

View File

@@ -19,8 +19,6 @@ from esphome.cpp_helpers import setup_entity
DEPENDENCIES = ["esp32"]
AUTO_LOAD = ["psram"]
esp32_camera_ns = cg.esphome_ns.namespace("esp32_camera")
ESP32Camera = esp32_camera_ns.class_("ESP32Camera", cg.PollingComponent, cg.EntityBase)
ESP32CameraFrameSize = esp32_camera_ns.enum("ESP32CameraFrameSize")
@@ -59,9 +57,6 @@ CONF_IDLE_FRAMERATE = "idle_framerate"
CONF_JPEG_QUALITY = "jpeg_quality"
CONF_VERTICAL_FLIP = "vertical_flip"
CONF_HORIZONTAL_MIRROR = "horizontal_mirror"
CONF_AEC2 = "aec2"
CONF_AE_LEVEL = "ae_level"
CONF_AEC_VALUE = "aec_value"
CONF_SATURATION = "saturation"
CONF_TEST_PATTERN = "test_pattern"
@@ -107,9 +102,6 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
cv.Optional(CONF_SATURATION, default=0): camera_range_param,
cv.Optional(CONF_VERTICAL_FLIP, default=True): cv.boolean,
cv.Optional(CONF_HORIZONTAL_MIRROR, default=True): cv.boolean,
cv.Optional(CONF_AEC2, default=False): cv.boolean,
cv.Optional(CONF_AE_LEVEL, default=0): camera_range_param,
cv.Optional(CONF_AEC_VALUE, default=300): cv.int_range(min=0, max=1200),
cv.Optional(CONF_TEST_PATTERN, default=False): cv.boolean,
}
).extend(cv.COMPONENT_SCHEMA)
@@ -124,9 +116,6 @@ SETTERS = {
CONF_JPEG_QUALITY: "set_jpeg_quality",
CONF_VERTICAL_FLIP: "set_vertical_flip",
CONF_HORIZONTAL_MIRROR: "set_horizontal_mirror",
CONF_AEC2: "set_aec2",
CONF_AE_LEVEL: "set_ae_level",
CONF_AEC_VALUE: "set_aec_value",
CONF_CONTRAST: "set_contrast",
CONF_BRIGHTNESS: "set_brightness",
CONF_SATURATION: "set_saturation",
@@ -155,7 +144,9 @@ async def to_code(config):
cg.add(var.set_frame_size(config[CONF_RESOLUTION]))
cg.add_define("USE_ESP32_CAMERA")
cg.add_build_flag("-DBOARD_HAS_PSRAM")
if CORE.using_esp_idf:
cg.add_library("espressif/esp32-camera", "1.0.0")
add_idf_sdkconfig_option("CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC", True)
add_idf_sdkconfig_option("CONFIG_ESP32_SPIRAM_SUPPORT", True)

View File

@@ -26,9 +26,6 @@ void ESP32Camera::setup() {
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, this->vertical_flip_);
s->set_hmirror(s, this->horizontal_mirror_);
s->set_aec2(s, this->aec2_); // 0 = disable , 1 = enable
s->set_ae_level(s, this->ae_level_); // -2 to 2
s->set_aec_value(s, this->aec_value_); // 0 to 1200
s->set_contrast(s, this->contrast_);
s->set_brightness(s, this->brightness_);
s->set_saturation(s, this->saturation_);
@@ -49,6 +46,9 @@ void ESP32Camera::dump_config() {
ESP_LOGCONFIG(TAG, "ESP32 Camera:");
ESP_LOGCONFIG(TAG, " Name: %s", this->name_.c_str());
ESP_LOGCONFIG(TAG, " Internal: %s", YESNO(this->internal_));
#ifdef USE_ARDUINO
ESP_LOGCONFIG(TAG, " Board Has PSRAM: %s", YESNO(psramFound()));
#endif // USE_ARDUINO
ESP_LOGCONFIG(TAG, " Data Pins: D0:%d D1:%d D2:%d D3:%d D4:%d D5:%d D6:%d D7:%d", conf.pin_d0, conf.pin_d1,
conf.pin_d2, conf.pin_d3, conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7);
ESP_LOGCONFIG(TAG, " VSYNC Pin: %d", conf.pin_vsync);
@@ -111,9 +111,9 @@ void ESP32Camera::dump_config() {
// ESP_LOGCONFIG(TAG, " Auto White Balance: %u", st.awb);
// ESP_LOGCONFIG(TAG, " Auto White Balance Gain: %u", st.awb_gain);
// ESP_LOGCONFIG(TAG, " Auto Exposure Control: %u", st.aec);
ESP_LOGCONFIG(TAG, " Auto Exposure Control 2: %u", st.aec2);
ESP_LOGCONFIG(TAG, " Auto Exposure Level: %d", st.ae_level);
ESP_LOGCONFIG(TAG, " Auto Exposure Value: %u", st.aec_value);
// ESP_LOGCONFIG(TAG, " Auto Exposure Control 2: %u", st.aec2);
// ESP_LOGCONFIG(TAG, " Auto Exposure Level: %d", st.ae_level);
// ESP_LOGCONFIG(TAG, " Auto Exposure Value: %u", st.aec_value);
// ESP_LOGCONFIG(TAG, " AGC: %u", st.agc);
// ESP_LOGCONFIG(TAG, " AGC Gain: %u", st.agc_gain);
// ESP_LOGCONFIG(TAG, " Gain Ceiling: %u", st.gainceiling);
@@ -133,13 +133,6 @@ void ESP32Camera::loop() {
this->current_image_.reset();
}
// request idle image every idle_update_interval
const uint32_t now = millis();
if (this->idle_update_interval_ != 0 && now - this->last_idle_request_ > this->idle_update_interval_) {
this->last_idle_request_ = now;
this->request_image(IDLE);
}
// Check if we should fetch a new image
if (!this->has_requested_image_())
return;
@@ -147,6 +140,7 @@ void ESP32Camera::loop() {
// image is still in use
return;
}
const uint32_t now = millis();
if (now - this->last_update_ <= this->max_update_interval_)
return;
@@ -163,12 +157,12 @@ void ESP32Camera::loop() {
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
return;
}
this->current_image_ = std::make_shared<CameraImage>(fb, this->single_requesters_ | this->stream_requesters_);
this->current_image_ = std::make_shared<CameraImage>(fb);
ESP_LOGD(TAG, "Got Image: len=%u", fb->len);
this->new_image_callback_.call(this->current_image_);
this->last_update_ = now;
this->single_requesters_ = 0;
this->single_requester_ = false;
}
void ESP32Camera::framebuffer_task(void *pv) {
while (true) {
@@ -256,18 +250,29 @@ void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<CameraIm
}
void ESP32Camera::set_vertical_flip(bool vertical_flip) { this->vertical_flip_ = vertical_flip; }
void ESP32Camera::set_horizontal_mirror(bool horizontal_mirror) { this->horizontal_mirror_ = horizontal_mirror; }
void ESP32Camera::set_aec2(bool aec2) { this->aec2_ = aec2; }
void ESP32Camera::set_ae_level(int ae_level) { this->ae_level_ = ae_level; }
void ESP32Camera::set_aec_value(uint32_t aec_value) { this->aec_value_ = aec_value; }
void ESP32Camera::set_contrast(int contrast) { this->contrast_ = contrast; }
void ESP32Camera::set_brightness(int brightness) { this->brightness_ = brightness; }
void ESP32Camera::set_saturation(int saturation) { this->saturation_ = saturation; }
float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; }
uint32_t ESP32Camera::hash_base() { return 3010542557UL; }
void ESP32Camera::request_image(CameraRequester requester) { this->single_requesters_ |= 1 << requester; }
void ESP32Camera::start_stream(CameraRequester requester) { this->stream_requesters_ |= 1 << requester; }
void ESP32Camera::stop_stream(CameraRequester requester) { this->stream_requesters_ &= ~(1 << requester); }
bool ESP32Camera::has_requested_image_() const { return this->single_requesters_ || this->stream_requesters_; }
void ESP32Camera::request_image() { this->single_requester_ = true; }
void ESP32Camera::request_stream() { this->last_stream_request_ = millis(); }
bool ESP32Camera::has_requested_image_() const {
if (this->single_requester_)
// single request
return true;
uint32_t now = millis();
if (now - this->last_stream_request_ < 5000)
// stream request
return true;
if (this->idle_update_interval_ != 0 && now - this->last_update_ > this->idle_update_interval_)
// idle update
return true;
return false;
}
bool ESP32Camera::can_return_image_() const { return this->current_image_.use_count() == 1; }
void ESP32Camera::set_max_update_interval(uint32_t max_update_interval) {
this->max_update_interval_ = max_update_interval;
@@ -296,10 +301,7 @@ uint8_t *CameraImageReader::peek_data_buffer() { return this->image_->get_data_b
camera_fb_t *CameraImage::get_raw_buffer() { return this->buffer_; }
uint8_t *CameraImage::get_data_buffer() { return this->buffer_->buf; }
size_t CameraImage::get_data_length() { return this->buffer_->len; }
bool CameraImage::was_requested_by(CameraRequester requester) const {
return (this->requesters_ & (1 << requester)) != 0;
}
CameraImage::CameraImage(camera_fb_t *buffer, uint8_t requesters) : buffer_(buffer), requesters_(requesters) {}
CameraImage::CameraImage(camera_fb_t *buffer) : buffer_(buffer) {}
} // namespace esp32_camera
} // namespace esphome

View File

@@ -14,19 +14,15 @@ namespace esp32_camera {
class ESP32Camera;
enum CameraRequester { IDLE, API_REQUESTER, WEB_REQUESTER };
class CameraImage {
public:
CameraImage(camera_fb_t *buffer, uint8_t requester);
CameraImage(camera_fb_t *buffer);
camera_fb_t *get_raw_buffer();
uint8_t *get_data_buffer();
size_t get_data_length();
bool was_requested_by(CameraRequester requester) const;
protected:
camera_fb_t *buffer_;
uint8_t requesters_;
};
class CameraImageReader {
@@ -71,9 +67,6 @@ class ESP32Camera : public Component, public EntityBase {
void set_power_down_pin(uint8_t pin);
void set_vertical_flip(bool vertical_flip);
void set_horizontal_mirror(bool horizontal_mirror);
void set_aec2(bool aec2);
void set_ae_level(int ae_level);
void set_aec_value(uint32_t aec_value);
void set_contrast(int contrast);
void set_brightness(int brightness);
void set_saturation(int saturation);
@@ -85,9 +78,8 @@ class ESP32Camera : public Component, public EntityBase {
void dump_config() override;
void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&f);
float get_setup_priority() const override;
void start_stream(CameraRequester requester);
void stop_stream(CameraRequester requester);
void request_image(CameraRequester requester);
void request_stream();
void request_image();
protected:
uint32_t hash_base() override;
@@ -99,9 +91,6 @@ class ESP32Camera : public Component, public EntityBase {
camera_config_t config_{};
bool vertical_flip_{true};
bool horizontal_mirror_{true};
bool aec2_{false};
int ae_level_{0};
uint32_t aec_value_{300};
int contrast_{0};
int brightness_{0};
int saturation_{0};
@@ -109,14 +98,13 @@ class ESP32Camera : public Component, public EntityBase {
esp_err_t init_error_{ESP_OK};
std::shared_ptr<CameraImage> current_image_;
uint8_t single_requesters_{0};
uint8_t stream_requesters_{0};
uint32_t last_stream_request_{0};
bool single_requester_{false};
QueueHandle_t framebuffer_get_queue_;
QueueHandle_t framebuffer_return_queue_;
CallbackManager<void(std::shared_ptr<CameraImage>)> new_image_callback_;
uint32_t max_update_interval_{1000};
uint32_t idle_update_interval_{15000};
uint32_t last_idle_request_{0};
uint32_t last_update_{0};
};

View File

@@ -14,26 +14,19 @@
namespace esphome {
namespace esp32_camera_web_server {
static const int IMAGE_REQUEST_TIMEOUT = 5000;
static const int IMAGE_REQUEST_TIMEOUT = 2000;
static const char *const TAG = "esp32_camera_web_server";
#define PART_BOUNDARY "123456789000000000000987654321"
#define CONTENT_TYPE "image/jpeg"
#define CONTENT_LENGTH "Content-Length"
static const char *const STREAM_HEADER = "HTTP/1.0 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Connection: close\r\n"
"Content-Type: multipart/x-mixed-replace;boundary=" PART_BOUNDARY "\r\n"
"\r\n"
"--" PART_BOUNDARY "\r\n";
static const char *const STREAM_ERROR = "Content-Type: text/plain\r\n"
"\r\n"
"No frames send.\r\n"
"--" PART_BOUNDARY "\r\n";
static const char *const STREAM_HEADER =
"HTTP/1.1 200\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: multipart/x-mixed-replace;boundary=" PART_BOUNDARY
"\r\n";
static const char *const STREAM_500 = "HTTP/1.1 500\r\nContent-Type: text/plain\r\n\r\nNo frames send.\r\n";
static const char *const STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char *const STREAM_PART = "Content-Type: " CONTENT_TYPE "\r\n" CONTENT_LENGTH ": %u\r\n\r\n";
static const char *const STREAM_BOUNDARY = "\r\n"
"--" PART_BOUNDARY "\r\n";
CameraWebServer::CameraWebServer() {}
@@ -52,7 +45,6 @@ void CameraWebServer::setup() {
config.ctrl_port = this->port_;
config.max_open_sockets = 1;
config.backlog_conn = 2;
config.lru_purge_enable = true;
if (httpd_start(&this->httpd_, &config) != ESP_OK) {
mark_failed();
@@ -68,7 +60,7 @@ void CameraWebServer::setup() {
httpd_register_uri_handler(this->httpd_, &uri);
esp32_camera::global_esp32_camera->add_image_callback([this](std::shared_ptr<esp32_camera::CameraImage> image) {
if (this->running_ && image->was_requested_by(esp32_camera::WEB_REQUESTER)) {
if (this->running_) {
this->image_ = std::move(image);
xSemaphoreGive(this->semaphore_);
}
@@ -169,15 +161,20 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
uint32_t last_frame = millis();
uint32_t frames = 0;
esp32_camera::global_esp32_camera->start_stream(esphome::esp32_camera::WEB_REQUESTER);
while (res == ESP_OK && this->running_) {
if (esp32_camera::global_esp32_camera != nullptr) {
esp32_camera::global_esp32_camera->request_stream();
}
auto image = this->wait_for_image_();
if (!image) {
ESP_LOGW(TAG, "STREAM: failed to acquire frame");
res = ESP_FAIL;
}
if (res == ESP_OK) {
res = httpd_send_all(req, STREAM_BOUNDARY, strlen(STREAM_BOUNDARY));
}
if (res == ESP_OK) {
size_t hlen = snprintf(part_buf, 64, STREAM_PART, image->get_data_length());
res = httpd_send_all(req, part_buf, hlen);
@@ -185,9 +182,6 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
if (res == ESP_OK) {
res = httpd_send_all(req, (const char *) image->get_data_buffer(), image->get_data_length());
}
if (res == ESP_OK) {
res = httpd_send_all(req, STREAM_BOUNDARY, strlen(STREAM_BOUNDARY));
}
if (res == ESP_OK) {
frames++;
int64_t frame_time = millis() - last_frame;
@@ -199,11 +193,9 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
}
if (!frames) {
res = httpd_send_all(req, STREAM_ERROR, strlen(STREAM_ERROR));
res = httpd_send_all(req, STREAM_500, strlen(STREAM_500));
}
esp32_camera::global_esp32_camera->stop_stream(esphome::esp32_camera::WEB_REQUESTER);
ESP_LOGI(TAG, "STREAM: closed. Frames: %u", frames);
return res;
@@ -212,7 +204,9 @@ esp_err_t CameraWebServer::streaming_handler_(struct httpd_req *req) {
esp_err_t CameraWebServer::snapshot_handler_(struct httpd_req *req) {
esp_err_t res = ESP_OK;
esp32_camera::global_esp32_camera->request_image(esphome::esp32_camera::WEB_REQUESTER);
if (esp32_camera::global_esp32_camera != nullptr) {
esp32_camera::global_esp32_camera->request_image();
}
auto image = this->wait_for_image_();
@@ -231,6 +225,9 @@ esp_err_t CameraWebServer::snapshot_handler_(struct httpd_req *req) {
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
if (res == ESP_OK) {
res = httpd_resp_set_hdr(req, CONTENT_LENGTH, esphome::to_string(image->get_data_length()).c_str());
}
if (res == ESP_OK) {
res = httpd_resp_send(req, (const char *) image->get_data_buffer(), image->get_data_length());
}

View File

@@ -1,39 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import canbus
from esphome.const import CONF_ID, CONF_RX_PIN, CONF_TX_PIN
from esphome.components.canbus import CanbusComponent, CanSpeed, CONF_BIT_RATE
CODEOWNERS = ["@Sympatron"]
DEPENDENCIES = ["esp32"]
esp32_can_ns = cg.esphome_ns.namespace("esp32_can")
esp32_can = esp32_can_ns.class_("ESP32Can", CanbusComponent)
# Currently the driver only supports a subset of the bit rates defined in canbus
CAN_SPEEDS = {
"50KBPS": CanSpeed.CAN_50KBPS,
"100KBPS": CanSpeed.CAN_100KBPS,
"125KBPS": CanSpeed.CAN_125KBPS,
"250KBPS": CanSpeed.CAN_250KBPS,
"500KBPS": CanSpeed.CAN_500KBPS,
"1000KBPS": CanSpeed.CAN_1000KBPS,
}
CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(esp32_can),
cv.Optional(CONF_BIT_RATE, default="125KBPS"): cv.enum(CAN_SPEEDS, upper=True),
cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number,
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number,
}
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await canbus.register_canbus(var, config)
cg.add(var.set_rx(config[CONF_RX_PIN]))
cg.add(var.set_tx(config[CONF_TX_PIN]))

View File

@@ -1,123 +0,0 @@
#ifdef USE_ESP32
#include "esp32_can.h"
#include "esphome/core/log.h"
#include <driver/can.h>
// WORKAROUND, because CAN_IO_UNUSED is just defined as (-1) in this version
// of the framework which does not work with -fpermissive
#undef CAN_IO_UNUSED
#define CAN_IO_UNUSED ((gpio_num_t) -1)
namespace esphome {
namespace esp32_can {
static const char *const TAG = "esp32_can";
static bool get_bitrate(canbus::CanSpeed bitrate, can_timing_config_t *t_config) {
switch (bitrate) {
case canbus::CAN_50KBPS:
*t_config = (can_timing_config_t) CAN_TIMING_CONFIG_50KBITS();
return true;
case canbus::CAN_100KBPS:
*t_config = (can_timing_config_t) CAN_TIMING_CONFIG_100KBITS();
return true;
case canbus::CAN_125KBPS:
*t_config = (can_timing_config_t) CAN_TIMING_CONFIG_125KBITS();
return true;
case canbus::CAN_250KBPS:
*t_config = (can_timing_config_t) CAN_TIMING_CONFIG_250KBITS();
return true;
case canbus::CAN_500KBPS:
*t_config = (can_timing_config_t) CAN_TIMING_CONFIG_500KBITS();
return true;
case canbus::CAN_1000KBPS:
*t_config = (can_timing_config_t) CAN_TIMING_CONFIG_1MBITS();
return true;
default:
return false;
}
}
bool ESP32Can::setup_internal() {
can_general_config_t g_config =
CAN_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, CAN_MODE_NORMAL);
can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
can_timing_config_t t_config;
if (!get_bitrate(this->bit_rate_, &t_config)) {
// invalid bit rate
this->mark_failed();
return false;
}
// Install CAN driver
if (can_driver_install(&g_config, &t_config, &f_config) != ESP_OK) {
// Failed to install driver
this->mark_failed();
return false;
}
// Start CAN driver
if (can_start() != ESP_OK) {
// Failed to start driver
this->mark_failed();
return false;
}
return true;
}
canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) {
return canbus::ERROR_FAILTX;
}
uint32_t flags = CAN_MSG_FLAG_NONE;
if (frame->use_extended_id) {
flags |= CAN_MSG_FLAG_EXTD;
}
if (frame->remote_transmission_request) {
flags |= CAN_MSG_FLAG_RTR;
}
can_message_t message = {
.flags = flags,
.identifier = frame->can_id,
.data_length_code = frame->can_data_length_code,
};
if (!frame->remote_transmission_request) {
memcpy(message.data, frame->data, frame->can_data_length_code);
}
if (can_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
return canbus::ERROR_OK;
} else {
return canbus::ERROR_ALLTXBUSY;
}
}
canbus::Error ESP32Can::read_message(struct canbus::CanFrame *frame) {
can_message_t message;
if (can_receive(&message, 0) != ESP_OK) {
return canbus::ERROR_NOMSG;
}
frame->can_id = message.identifier;
frame->use_extended_id = message.flags & CAN_MSG_FLAG_EXTD;
frame->remote_transmission_request = message.flags & CAN_MSG_FLAG_RTR;
frame->can_data_length_code = message.data_length_code;
if (!frame->remote_transmission_request) {
size_t dlc =
message.data_length_code < canbus::CAN_MAX_DATA_LENGTH ? message.data_length_code : canbus::CAN_MAX_DATA_LENGTH;
memcpy(frame->data, message.data, dlc);
}
return canbus::ERROR_OK;
}
} // namespace esp32_can
} // namespace esphome
#endif

View File

@@ -1,29 +0,0 @@
#pragma once
#ifdef USE_ESP32
#include "esphome/components/canbus/canbus.h"
#include "esphome/core/component.h"
namespace esphome {
namespace esp32_can {
class ESP32Can : public canbus::Canbus {
public:
void set_rx(int rx) { rx_ = rx; }
void set_tx(int tx) { tx_ = tx; }
ESP32Can(){};
protected:
bool setup_internal() override;
canbus::Error send_message(struct canbus::CanFrame *frame) override;
canbus::Error read_message(struct canbus::CanFrame *frame) override;
int rx_{-1};
int tx_{-1};
};
} // namespace esp32_can
} // namespace esphome
#endif

View File

@@ -1,16 +1,17 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor, output, esp32_ble_server
from esphome.const import CONF_BLE_SERVER_ID, CONF_ID
from esphome.const import CONF_ID
AUTO_LOAD = ["binary_sensor", "output", "esp32_ble_server"]
AUTO_LOAD = ["binary_sensor", "output", "improv", "esp32_ble_server"]
CODEOWNERS = ["@jesserockz"]
CONFLICTS_WITH = ["esp32_ble_tracker", "esp32_ble_beacon"]
DEPENDENCIES = ["wifi", "esp32"]
CONF_AUTHORIZED_DURATION = "authorized_duration"
CONF_AUTHORIZER = "authorizer"
CONF_BLE_SERVER_ID = "ble_server_id"
CONF_IDENTIFY_DURATION = "identify_duration"
CONF_STATUS_INDICATOR = "status_indicator"
CONF_WIFI_TIMEOUT = "wifi_timeout"
@@ -55,7 +56,6 @@ async def to_code(config):
cg.add(ble_server.register_service_component(var))
cg.add_define("USE_IMPROV")
cg.add_library("esphome/Improv", "1.0.0")
cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION]))
cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION]))

View File

@@ -219,7 +219,7 @@ void ESP32ImprovComponent::dump_config() {
void ESP32ImprovComponent::process_incoming_data_() {
uint8_t length = this->incoming_data_[1];
ESP_LOGD(TAG, "Processing bytes - %s", format_hex_pretty(this->incoming_data_).c_str());
ESP_LOGD(TAG, "Processing bytes - %s", hexencode(this->incoming_data_).c_str());
if (this->incoming_data_.size() - 3 == length) {
this->set_error_(improv::ERROR_NONE);
improv::ImprovCommand command = improv::parse_improv_data(this->incoming_data_);

View File

@@ -1,8 +1,9 @@
#pragma once
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/improv/improv.h"
#include "esphome/components/output/binary_output.h"
#include "esphome/components/wifi/wifi_component.h"
#include "esphome/core/component.h"
@@ -11,8 +12,6 @@
#ifdef USE_ESP32
#include <improv.h>
namespace esphome {
namespace esp32_improv {

View File

@@ -1,7 +1,6 @@
#ifdef USE_ESP32
#include "esp32_touch.h"
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
@@ -94,6 +93,7 @@ void ESP32TouchComponent::dump_config() {
if (this->iir_filter_enabled_()) {
ESP_LOGCONFIG(TAG, " IIR Filter: %ums", this->iir_filter_);
touch_pad_filter_start(this->iir_filter_);
} else {
ESP_LOGCONFIG(TAG, " IIR Filter DISABLED");
}
@@ -125,8 +125,6 @@ void ESP32TouchComponent::loop() {
if (should_print) {
ESP_LOGD(TAG, "Touch Pad '%s' (T%u): %u", child->get_name().c_str(), child->get_touch_pad(), value);
}
App.feed_wdt();
}
if (should_print) {

View File

@@ -1,5 +1,4 @@
import logging
import os
from esphome.const import (
CONF_BOARD,
@@ -15,7 +14,6 @@ from esphome.const import (
from esphome.core import CORE, coroutine_with_priority
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.helpers import copy_file_if_changed
from .const import CONF_RESTORE_FROM_FLASH, KEY_BOARD, KEY_ESP8266, esp8266_ns
from .boards import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS
@@ -160,8 +158,6 @@ async def to_code(config):
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
cg.add_define("ESPHOME_VARIANT", "ESP8266")
cg.add_platformio_option("extra_scripts", ["post:post_build.py"])
conf = config[CONF_FRAMEWORK]
cg.add_platformio_option("framework", "arduino")
cg.add_build_flag("-DUSE_ARDUINO")
@@ -214,14 +210,3 @@ async def to_code(config):
if ld_script is not None:
cg.add_platformio_option("board_build.ldscript", ld_script)
# Called by writer.py
def copy_files():
dir = os.path.dirname(__file__)
post_build_file = os.path.join(dir, "post_build.py.script")
copy_file_if_changed(
post_build_file,
CORE.relative_build_path("post_build.py"),
)

View File

@@ -206,3 +206,61 @@ ESP8266_BOARD_PINS = {
"wio_node": {"LED": 2, "GROVE": 15, "D0": 3, "D1": 5, "BUTTON": 0},
"xinabox_cw01": {"SDA": 2, "SCL": 14, "LED": 5, "LED_RED": 12, "LED_GREEN": 13},
}
FLASH_SIZE_1_MB = 2 ** 20
FLASH_SIZE_512_KB = FLASH_SIZE_1_MB // 2
FLASH_SIZE_2_MB = 2 * FLASH_SIZE_1_MB
FLASH_SIZE_4_MB = 4 * FLASH_SIZE_1_MB
FLASH_SIZE_16_MB = 16 * FLASH_SIZE_1_MB
ESP8266_FLASH_SIZES = {
"d1": FLASH_SIZE_4_MB,
"d1_mini": FLASH_SIZE_4_MB,
"d1_mini_lite": FLASH_SIZE_1_MB,
"d1_mini_pro": FLASH_SIZE_16_MB,
"esp01": FLASH_SIZE_512_KB,
"esp01_1m": FLASH_SIZE_1_MB,
"esp07": FLASH_SIZE_4_MB,
"esp12e": FLASH_SIZE_4_MB,
"esp210": FLASH_SIZE_4_MB,
"esp8285": FLASH_SIZE_1_MB,
"esp_wroom_02": FLASH_SIZE_2_MB,
"espduino": FLASH_SIZE_4_MB,
"espectro": FLASH_SIZE_4_MB,
"espino": FLASH_SIZE_4_MB,
"espinotee": FLASH_SIZE_4_MB,
"espmxdevkit": FLASH_SIZE_1_MB,
"espresso_lite_v1": FLASH_SIZE_4_MB,
"espresso_lite_v2": FLASH_SIZE_4_MB,
"gen4iod": FLASH_SIZE_512_KB,
"heltec_wifi_kit_8": FLASH_SIZE_4_MB,
"huzzah": FLASH_SIZE_4_MB,
"inventone": FLASH_SIZE_4_MB,
"modwifi": FLASH_SIZE_2_MB,
"nodemcu": FLASH_SIZE_4_MB,
"nodemcuv2": FLASH_SIZE_4_MB,
"oak": FLASH_SIZE_4_MB,
"phoenix_v1": FLASH_SIZE_4_MB,
"phoenix_v2": FLASH_SIZE_4_MB,
"sonoff_basic": FLASH_SIZE_1_MB,
"sonoff_s20": FLASH_SIZE_1_MB,
"sonoff_sv": FLASH_SIZE_1_MB,
"sonoff_th": FLASH_SIZE_1_MB,
"sparkfunBlynk": FLASH_SIZE_4_MB,
"thing": FLASH_SIZE_512_KB,
"thingdev": FLASH_SIZE_512_KB,
"wifi_slot": FLASH_SIZE_1_MB,
"wifiduino": FLASH_SIZE_4_MB,
"wifinfo": FLASH_SIZE_1_MB,
"wio_link": FLASH_SIZE_4_MB,
"wio_node": FLASH_SIZE_4_MB,
"xinabox_cw01": FLASH_SIZE_4_MB,
}
ESP8266_LD_SCRIPTS = {
FLASH_SIZE_512_KB: ("eagle.flash.512k0.ld", "eagle.flash.512k.ld"),
FLASH_SIZE_1_MB: ("eagle.flash.1m0.ld", "eagle.flash.1m.ld"),
FLASH_SIZE_2_MB: ("eagle.flash.2m.ld", "eagle.flash.2m.ld"),
FLASH_SIZE_4_MB: ("eagle.flash.4m.ld", "eagle.flash.4m.ld"),
FLASH_SIZE_16_MB: ("eagle.flash.16m.ld", "eagle.flash.16m14m.ld"),
}

View File

@@ -20,7 +20,6 @@ void arch_restart() {
yield();
}
}
void arch_init() {}
void IRAM_ATTR HOT arch_feed_wdt() {
ESP.wdtFeed(); // NOLINT(readability-static-accessed-through-instance)
}
@@ -28,7 +27,7 @@ void IRAM_ATTR HOT arch_feed_wdt() {
uint8_t progmem_read_byte(const uint8_t *addr) {
return pgm_read_byte(addr); // NOLINT
}
uint32_t IRAM_ATTR HOT arch_get_cpu_cycle_count() {
uint32_t arch_get_cpu_cycle_count() {
return ESP.getCycleCount(); // NOLINT(readability-static-accessed-through-instance)
}
uint32_t arch_get_cpu_freq_hz() { return F_CPU; }

View File

@@ -9,7 +9,7 @@ namespace esp8266 {
static const char *const TAG = "esp8266";
static int IRAM_ATTR flags_to_mode(gpio::Flags flags, uint8_t pin) {
if (flags == gpio::FLAG_INPUT) { // NOLINT(bugprone-branch-clone)
if (flags == gpio::FLAG_INPUT) {
return INPUT;
} else if (flags == gpio::FLAG_OUTPUT) {
return OUTPUT;

View File

@@ -1,15 +0,0 @@
import shutil
# pylint: disable=E0602
Import("env") # noqa
def esp8266_copy_factory_bin(source, target, env):
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}-factory.bin")
shutil.copyfile(firmware_name, new_file_name)
# pylint: disable=E0602
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp8266_copy_factory_bin) # noqa

View File

@@ -55,7 +55,7 @@ static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) {
extern "C" uint32_t _SPIFFS_end; // NOLINT
static uint32_t get_esp8266_flash_sector() {
static const uint32_t get_esp8266_flash_sector() {
union {
uint32_t *ptr;
uint32_t uint;
@@ -63,7 +63,7 @@ static uint32_t get_esp8266_flash_sector() {
data.ptr = &_SPIFFS_end;
return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
}
static uint32_t get_esp8266_flash_address() { return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
static const uint32_t get_esp8266_flash_address() { return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
template<class It> uint32_t calculate_crc(It first, It last, uint32_t type) {
uint32_t crc = type;

View File

@@ -184,9 +184,7 @@ void EthernetComponent::start_connect_() {
}
err = tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_ETH);
if (err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) {
ESPHL_ERROR_CHECK(err, "DHCPC stop error");
}
ESPHL_ERROR_CHECK(err, "DHCPC stop error");
err = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &info);
ESPHL_ERROR_CHECK(err, "DHCPC set IP info error");

View File

@@ -12,8 +12,6 @@ from esphome.const import (
CONF_TYPE,
CONF_EXTERNAL_COMPONENTS,
CONF_PATH,
CONF_USERNAME,
CONF_PASSWORD,
)
from esphome.core import CORE
from esphome import git, loader
@@ -29,8 +27,6 @@ TYPE_LOCAL = "local"
GIT_SCHEMA = {
cv.Required(CONF_URL): cv.url,
cv.Optional(CONF_REF): cv.git_ref,
cv.Optional(CONF_USERNAME): cv.string,
cv.Optional(CONF_PASSWORD): cv.string,
}
LOCAL_SCHEMA = {
cv.Required(CONF_PATH): cv.directory,
@@ -103,8 +99,6 @@ def _process_git_config(config: dict, refresh) -> str:
ref=config.get(CONF_REF),
refresh=refresh,
domain=DOMAIN,
username=config.get(CONF_USERNAME),
password=config.get(CONF_PASSWORD),
)
if (repo_dir / "esphome" / "components").is_dir():

View File

@@ -32,7 +32,7 @@ void EZOSensor::update() {
}
void EZOSensor::loop() {
uint8_t buf[21];
uint8_t buf[20];
if (!(this->state_ & EZO_STATE_WAIT)) {
if (this->state_ & EZO_STATE_SEND_TEMP) {
int len = sprintf((char *) buf, "T,%0.3f", this->tempcomp_);
@@ -74,12 +74,7 @@ void EZOSensor::loop() {
if (buf[0] != 1)
return;
// some sensors return multiple comma-separated values, terminate string after first one
for (size_t i = 1; i < sizeof(buf) - 1; i++)
if (buf[i] == ',')
buf[i] = '\0';
float val = parse_number<float>((char *) &buf[1]).value_or(0);
float val = parse_number<float>((char *) &buf[1], sizeof(buf) - 1).value_or(0);
this->publish_state(val);
}

View File

@@ -86,7 +86,7 @@ void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Colo
// Look back in trace data to best-fit into local range
float mx = NAN;
float mn = NAN;
for (uint32_t i = 0; i < this->width_; i++) {
for (int16_t i = 0; i < this->width_; i++) {
for (auto *trace : traces_) {
float v = trace->get_tracedata()->get_value(i);
if (!std::isnan(v)) {
@@ -132,7 +132,7 @@ void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Colo
if (!std::isnan(this->gridspacing_y_)) {
for (int y = yn; y <= ym; y++) {
int16_t py = (int16_t) roundf((this->height_ - 1) * (1.0 - (float) (y - yn) / (ym - yn)));
for (uint32_t x = 0; x < this->width_; x += 2) {
for (int x = 0; x < this->width_; x += 2) {
buff->draw_pixel_at(x_offset + x, y_offset + py, color);
}
}
@@ -147,7 +147,7 @@ void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Colo
ESP_LOGW(TAG, "Graphing reducing x-scale to prevent too many gridlines");
}
for (int i = 0; i <= n; i++) {
for (uint32_t y = 0; y < this->height_; y += 2) {
for (int y = 0; y < this->height_; y += 2) {
buff->draw_pixel_at(x_offset + i * (this->width_ - 1) / n, y_offset + y, color);
}
}
@@ -158,14 +158,14 @@ void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Colo
for (auto *trace : traces_) {
Color c = trace->get_line_color();
uint16_t thick = trace->get_line_thickness();
for (uint32_t i = 0; i < this->width_; i++) {
for (int16_t i = 0; i < this->width_; i++) {
float v = (trace->get_tracedata()->get_value(i) - ymin) / yrange;
if (!std::isnan(v) && (thick > 0)) {
int16_t x = this->width_ - 1 - i;
uint8_t b = (i % (thick * LineType::PATTERN_LENGTH)) / thick;
if (((uint8_t) trace->get_line_type() & (1 << b)) == (1 << b)) {
int16_t y = (int16_t) roundf((this->height_ - 1) * (1.0 - v)) - thick / 2;
for (uint16_t t = 0; t < thick; t++) {
for (int16_t t = 0; t < thick; t++) {
buff->draw_pixel_at(x_offset + x, y_offset + y + t, c);
}
}
@@ -179,8 +179,8 @@ void GraphLegend::init(Graph *g) {
parent_ = g;
// Determine maximum expected text and value width / height
int txtw = 0, txth = 0;
int valw = 0, valh = 0;
int txtw = 0, txtos = 0, txtbl = 0, txth = 0;
int valw = 0, valos = 0, valbl = 0, valh = 0;
int lt = 0;
for (auto *trace : g->traces_) {
std::string txtstr = trace->get_name();
@@ -320,7 +320,7 @@ void Graph::draw_legend(display::DisplayBuffer *buff, uint16_t x_offset, uint16_
if (legend_->lines_) {
uint16_t thick = trace->get_line_thickness();
for (int i = 0; i < legend_->x0_ * 4 / 3; i++) {
for (int16_t i = 0; i < legend_->x0_ * 4 / 3; i++) {
uint8_t b = (i % (thick * LineType::PATTERN_LENGTH)) / thick;
if (((uint8_t) trace->get_line_type() & (1 << b)) == (1 << b)) {
buff->vertical_line(x - legend_->x0_ * 2 / 3 + i, y + legend_->yl_ - thick / 2, thick,

View File

@@ -1,69 +0,0 @@
#include "growatt_solar.h"
#include "esphome/core/log.h"
namespace esphome {
namespace growatt_solar {
static const char *const TAG = "growatt_solar";
static const uint8_t MODBUS_CMD_READ_IN_REGISTERS = 0x04;
static const uint8_t MODBUS_REGISTER_COUNT = 33;
void GrowattSolar::update() { this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT); }
void GrowattSolar::on_modbus_data(const std::vector<uint8_t> &data) {
auto publish_1_reg_sensor_state = [&](sensor::Sensor *sensor, size_t i, float unit) -> void {
if (sensor == nullptr)
return;
float value = encode_uint16(data[i * 2], data[i * 2 + 1]) * unit;
sensor->publish_state(value);
};
auto publish_2_reg_sensor_state = [&](sensor::Sensor *sensor, size_t reg1, size_t reg2, float unit) -> void {
float value = ((encode_uint16(data[reg1 * 2], data[reg1 * 2 + 1]) << 16) +
encode_uint16(data[reg2 * 2], data[reg2 * 2 + 1])) *
unit;
if (sensor != nullptr)
sensor->publish_state(value);
};
publish_1_reg_sensor_state(this->inverter_status_, 0, 1);
publish_2_reg_sensor_state(this->pv_active_power_sensor_, 1, 2, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->pvs_[0].voltage_sensor_, 3, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->pvs_[0].current_sensor_, 4, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->pvs_[0].active_power_sensor_, 5, 6, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->pvs_[1].voltage_sensor_, 7, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->pvs_[1].current_sensor_, 8, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->pvs_[1].active_power_sensor_, 9, 10, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->grid_active_power_sensor_, 11, 12, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->grid_frequency_sensor_, 13, TWO_DEC_UNIT);
publish_1_reg_sensor_state(this->phases_[0].voltage_sensor_, 14, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->phases_[0].current_sensor_, 15, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->phases_[0].active_power_sensor_, 16, 17, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->phases_[1].voltage_sensor_, 18, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->phases_[1].current_sensor_, 19, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->phases_[1].active_power_sensor_, 20, 21, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->phases_[2].voltage_sensor_, 22, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->phases_[2].current_sensor_, 23, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->phases_[2].active_power_sensor_, 24, 25, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->today_production_, 26, 27, ONE_DEC_UNIT);
publish_2_reg_sensor_state(this->total_energy_production_, 28, 29, ONE_DEC_UNIT);
publish_1_reg_sensor_state(this->inverter_module_temp_, 32, ONE_DEC_UNIT);
}
void GrowattSolar::dump_config() {
ESP_LOGCONFIG(TAG, "GROWATT Solar:");
ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_);
}
} // namespace growatt_solar
} // namespace esphome

View File

@@ -1,73 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/modbus/modbus.h"
namespace esphome {
namespace growatt_solar {
static const float TWO_DEC_UNIT = 0.01;
static const float ONE_DEC_UNIT = 0.1;
class GrowattSolar : public PollingComponent, public modbus::ModbusDevice {
public:
void update() override;
void on_modbus_data(const std::vector<uint8_t> &data) override;
void dump_config() override;
void set_inverter_status_sensor(sensor::Sensor *sensor) { this->inverter_status_ = sensor; }
void set_grid_frequency_sensor(sensor::Sensor *sensor) { this->grid_frequency_sensor_ = sensor; }
void set_grid_active_power_sensor(sensor::Sensor *sensor) { this->grid_active_power_sensor_ = sensor; }
void set_pv_active_power_sensor(sensor::Sensor *sensor) { this->pv_active_power_sensor_ = sensor; }
void set_today_production_sensor(sensor::Sensor *sensor) { this->today_production_ = sensor; }
void set_total_energy_production_sensor(sensor::Sensor *sensor) { this->total_energy_production_ = sensor; }
void set_inverter_module_temp_sensor(sensor::Sensor *sensor) { this->inverter_module_temp_ = sensor; }
void set_voltage_sensor(uint8_t phase, sensor::Sensor *voltage_sensor) {
this->phases_[phase].voltage_sensor_ = voltage_sensor;
}
void set_current_sensor(uint8_t phase, sensor::Sensor *current_sensor) {
this->phases_[phase].current_sensor_ = current_sensor;
}
void set_active_power_sensor(uint8_t phase, sensor::Sensor *active_power_sensor) {
this->phases_[phase].active_power_sensor_ = active_power_sensor;
}
void set_voltage_sensor_pv(uint8_t pv, sensor::Sensor *voltage_sensor) {
this->pvs_[pv].voltage_sensor_ = voltage_sensor;
}
void set_current_sensor_pv(uint8_t pv, sensor::Sensor *current_sensor) {
this->pvs_[pv].current_sensor_ = current_sensor;
}
void set_active_power_sensor_pv(uint8_t pv, sensor::Sensor *active_power_sensor) {
this->pvs_[pv].active_power_sensor_ = active_power_sensor;
}
protected:
struct GrowattPhase {
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *active_power_sensor_{nullptr};
} phases_[3];
struct GrowattPV {
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *active_power_sensor_{nullptr};
} pvs_[2];
sensor::Sensor *inverter_status_{nullptr};
sensor::Sensor *grid_frequency_sensor_{nullptr};
sensor::Sensor *grid_active_power_sensor_{nullptr};
sensor::Sensor *pv_active_power_sensor_{nullptr};
sensor::Sensor *today_production_{nullptr};
sensor::Sensor *total_energy_production_{nullptr};
sensor::Sensor *inverter_module_temp_{nullptr};
};
} // namespace growatt_solar
} // namespace esphome

View File

@@ -1,201 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, modbus
from esphome.const import (
CONF_ACTIVE_POWER,
CONF_CURRENT,
CONF_FREQUENCY,
CONF_ID,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
ICON_CURRENT_AC,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_AMPERE,
UNIT_CELSIUS,
UNIT_HERTZ,
UNIT_VOLT,
UNIT_WATT,
)
CONF_PHASE_A = "phase_a"
CONF_PHASE_B = "phase_b"
CONF_PHASE_C = "phase_c"
CONF_ENERGY_PRODUCTION_DAY = "energy_production_day"
CONF_TOTAL_ENERGY_PRODUCTION = "total_energy_production"
CONF_TOTAL_GENERATION_TIME = "total_generation_time"
CONF_TODAY_GENERATION_TIME = "today_generation_time"
CONF_PV1 = "pv1"
CONF_PV2 = "pv2"
UNIT_KILOWATT_HOURS = "kWh"
UNIT_HOURS = "h"
UNIT_KOHM = ""
UNIT_MILLIAMPERE = "mA"
CONF_INVERTER_STATUS = "inverter_status"
CONF_PV_ACTIVE_POWER = "pv_active_power"
CONF_INVERTER_MODULE_TEMP = "inverter_module_temp"
AUTO_LOAD = ["modbus"]
CODEOWNERS = ["@leeuwte"]
growatt_solar_ns = cg.esphome_ns.namespace("growatt_solar")
GrowattSolar = growatt_solar_ns.class_(
"GrowattSolar", cg.PollingComponent, modbus.ModbusDevice
)
PHASE_SENSORS = {
CONF_VOLTAGE: sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_VOLTAGE,
),
CONF_CURRENT: sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=2,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
CONF_ACTIVE_POWER: sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
}
PV_SENSORS = {
CONF_VOLTAGE: sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_VOLTAGE,
),
CONF_CURRENT: sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=2,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
CONF_ACTIVE_POWER: sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
}
PHASE_SCHEMA = cv.Schema(
{cv.Optional(sensor): schema for sensor, schema in PHASE_SENSORS.items()}
)
PV_SCHEMA = cv.Schema(
{cv.Optional(sensor): schema for sensor, schema in PV_SENSORS.items()}
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(GrowattSolar),
cv.Optional(CONF_PHASE_A): PHASE_SCHEMA,
cv.Optional(CONF_PHASE_B): PHASE_SCHEMA,
cv.Optional(CONF_PHASE_C): PHASE_SCHEMA,
cv.Optional(CONF_PV1): PV_SCHEMA,
cv.Optional(CONF_PV2): PV_SCHEMA,
cv.Optional(CONF_INVERTER_STATUS): sensor.sensor_schema(),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
unit_of_measurement=UNIT_HERTZ,
icon=ICON_CURRENT_AC,
accuracy_decimals=2,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_ACTIVE_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_PV_ACTIVE_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_ENERGY_PRODUCTION_DAY): sensor.sensor_schema(
unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=2,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_TOTAL_ENERGY_PRODUCTION): sensor.sensor_schema(
unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=0,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_INVERTER_MODULE_TEMP): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
state_class=STATE_CLASS_MEASUREMENT,
),
}
)
.extend(cv.polling_component_schema("10s"))
.extend(modbus.modbus_device_schema(0x01))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await modbus.register_modbus_device(var, config)
if CONF_INVERTER_STATUS in config:
sens = await sensor.new_sensor(config[CONF_INVERTER_STATUS])
cg.add(var.set_inverter_status_sensor(sens))
if CONF_FREQUENCY in config:
sens = await sensor.new_sensor(config[CONF_FREQUENCY])
cg.add(var.set_grid_frequency_sensor(sens))
if CONF_ACTIVE_POWER in config:
sens = await sensor.new_sensor(config[CONF_ACTIVE_POWER])
cg.add(var.set_grid_active_power_sensor(sens))
if CONF_PV_ACTIVE_POWER in config:
sens = await sensor.new_sensor(config[CONF_PV_ACTIVE_POWER])
cg.add(var.set_pv_active_power_sensor(sens))
if CONF_ENERGY_PRODUCTION_DAY in config:
sens = await sensor.new_sensor(config[CONF_ENERGY_PRODUCTION_DAY])
cg.add(var.set_today_production_sensor(sens))
if CONF_TOTAL_ENERGY_PRODUCTION in config:
sens = await sensor.new_sensor(config[CONF_TOTAL_ENERGY_PRODUCTION])
cg.add(var.set_total_energy_production_sensor(sens))
if CONF_INVERTER_MODULE_TEMP in config:
sens = await sensor.new_sensor(config[CONF_INVERTER_MODULE_TEMP])
cg.add(var.set_inverter_module_temp_sensor(sens))
for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]):
if phase not in config:
continue
phase_config = config[phase]
for sensor_type in PHASE_SENSORS:
if sensor_type in phase_config:
sens = await sensor.new_sensor(phase_config[sensor_type])
cg.add(getattr(var, f"set_{sensor_type}_sensor")(i, sens))
for i, pv in enumerate([CONF_PV1, CONF_PV2]):
if pv not in config:
continue
pv_config = config[pv]
for sensor_type in pv_config:
if sensor_type in pv_config:
sens = await sensor.new_sensor(pv_config[sensor_type])
cg.add(getattr(var, f"set_{sensor_type}_sensor_pv")(i, sens))

View File

@@ -21,9 +21,7 @@ void HDC1080Component::setup() {
};
if (!this->write_bytes(HDC1080_CMD_CONFIGURATION, data, 2)) {
// as instruction is same as powerup defaults (for now), interpret as warning if this fails
ESP_LOGW(TAG, "HDC1080 initial config instruction error");
this->status_set_warning();
this->mark_failed();
return;
}
}

View File

@@ -30,7 +30,6 @@ PROTOCOLS = {
"gree": Protocol.PROTOCOL_GREE,
"greeya": Protocol.PROTOCOL_GREEYAA,
"greeyan": Protocol.PROTOCOL_GREEYAN,
"greeyac": Protocol.PROTOCOL_GREEYAC,
"hisense_aud": Protocol.PROTOCOL_HISENSE_AUD,
"hitachi": Protocol.PROTOCOL_HITACHI,
"hyundai": Protocol.PROTOCOL_HYUNDAI,
@@ -109,9 +108,7 @@ def to_code(config):
cg.add(var.set_protocol(config[CONF_PROTOCOL]))
cg.add(var.set_horizontal_default(config[CONF_HORIZONTAL_DEFAULT]))
cg.add(var.set_vertical_default(config[CONF_VERTICAL_DEFAULT]))
cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE]))
cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE]))
cg.add(var.set_max_temperature(config[CONF_MIN_TEMPERATURE]))
cg.add(var.set_min_temperature(config[CONF_MAX_TEMPERATURE]))
# PIO isn't updating releases, so referencing the release tag directly. See:
# https://github.com/ToniA/arduino-heatpumpir/commit/0948c619d86407a4e50e8db2f3c193e0576c86fd
cg.add_library("", "", "https://github.com/ToniA/arduino-heatpumpir.git#1.0.18")
cg.add_library("tonia/HeatpumpIR", "1.0.15")

View File

@@ -25,7 +25,6 @@ const std::map<Protocol, std::function<HeatpumpIR *()>> PROTOCOL_CONSTRUCTOR_MAP
{PROTOCOL_GREE, []() { return new GreeGenericHeatpumpIR(); }}, // NOLINT
{PROTOCOL_GREEYAA, []() { return new GreeYAAHeatpumpIR(); }}, // NOLINT
{PROTOCOL_GREEYAN, []() { return new GreeYANHeatpumpIR(); }}, // NOLINT
{PROTOCOL_GREEYAC, []() { return new GreeYACHeatpumpIR(); }}, // NOLINT
{PROTOCOL_HISENSE_AUD, []() { return new HisenseHeatpumpIR(); }}, // NOLINT
{PROTOCOL_HITACHI, []() { return new HitachiHeatpumpIR(); }}, // NOLINT
{PROTOCOL_HYUNDAI, []() { return new HyundaiHeatpumpIR(); }}, // NOLINT
@@ -62,19 +61,6 @@ void HeatpumpIRClimate::setup() {
}
this->heatpump_ir_ = protocol_constructor->second();
climate_ir::ClimateIR::setup();
if (this->sensor_) {
this->sensor_->add_on_state_callback([this](float state) {
this->current_temperature = state;
IRSenderESPHome esp_sender(this->transmitter_);
this->heatpump_ir_->send(esp_sender, uint8_t(lround(this->current_temperature + 0.5)));
// current temperature changed, publish state
this->publish_state();
});
this->current_temperature = this->sensor_->state;
} else
this->current_temperature = NAN;
}
void HeatpumpIRClimate::transmit_state() {
@@ -185,7 +171,8 @@ void HeatpumpIRClimate::transmit_state() {
temperature_cmd = (uint8_t) clamp(this->target_temperature, this->min_temperature_, this->max_temperature_);
IRSenderESPHome esp_sender(this->transmitter_);
IRSenderESPHome esp_sender(0, this->transmitter_);
heatpump_ir_->send(esp_sender, power_mode_cmd, operating_mode_cmd, fan_speed_cmd, temperature_cmd, swing_v_cmd,
swing_h_cmd);
}

View File

@@ -25,7 +25,6 @@ enum Protocol {
PROTOCOL_GREE,
PROTOCOL_GREEYAA,
PROTOCOL_GREEYAN,
PROTOCOL_GREEYAC,
PROTOCOL_HISENSE_AUD,
PROTOCOL_HITACHI,
PROTOCOL_HYUNDAI,

View File

@@ -11,8 +11,8 @@ namespace heatpumpir {
class IRSenderESPHome : public IRSender {
public:
IRSenderESPHome(remote_transmitter::RemoteTransmitterComponent *transmitter)
: IRSender(0), transmit_(transmitter->transmit()){};
IRSenderESPHome(uint8_t pin, remote_transmitter::RemoteTransmitterComponent *transmitter)
: IRSender(pin), transmit_(transmitter->transmit()){};
void setFrequency(int frequency) override; // NOLINT(readability-identifier-naming)
void space(int space_length) override;
void mark(int mark_length) override;

View File

@@ -299,7 +299,9 @@ bool HitachiClimate::parse_swing_(const uint8_t remote_state[]) {
GETBITS8(remote_state[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE);
ESP_LOGV(TAG, "SwingH: %02X %02X", remote_state[HITACHI_AC344_SWINGH_BYTE], swing_modeh);
if ((swing_modeh & 0x3) == 0x3) {
if ((swing_modeh & 0x7) == 0x0) {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
} else if ((swing_modeh & 0x3) == 0x3) {
this->swing_mode = climate::CLIMATE_SWING_OFF;
} else {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;

View File

@@ -300,7 +300,9 @@ bool HitachiClimate::parse_swing_(const uint8_t remote_state[]) {
HITACHI_AC424_SWINGH_SIZE);
ESP_LOGV(TAG, "SwingH: %02X %02X", remote_state[HITACHI_AC424_SWINGH_BYTE], swing_modeh);
if ((swing_modeh & 0x3) == 0x3) {
if ((swing_modeh & 0x7) == 0x0) {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
} else if ((swing_modeh & 0x3) == 0x3) {
this->swing_mode = climate::CLIMATE_SWING_OFF;
} else {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;

View File

@@ -1,5 +1,6 @@
#pragma once
#ifdef USE_ARDUINO
#include <cstdint>
namespace esphome {
@@ -12,3 +13,5 @@ class AbstractAQICalculator {
} // namespace hm3301
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,5 +1,7 @@
#pragma once
#ifdef USE_ARDUINO
#include "abstract_aqi_calculator.h"
namespace esphome {
@@ -31,7 +33,7 @@ class AQICalculator : public AbstractAQICalculator {
int conc_lo = array[grid_index][0];
int conc_hi = array[grid_index][1];
return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
return ((aqi_hi - aqi_lo) / (conc_hi - conc_lo)) * (value - conc_lo) + aqi_lo;
}
int get_grid_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
@@ -46,3 +48,5 @@ class AQICalculator : public AbstractAQICalculator {
} // namespace hm3301
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,5 +1,7 @@
#pragma once
#ifdef USE_ARDUINO
#include "caqi_calculator.h"
#include "aqi_calculator.h"
@@ -27,3 +29,5 @@ class AQICalculatorFactory {
} // namespace hm3301
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,5 +1,7 @@
#pragma once
#ifdef USE_ARDUINO
#include "esphome/core/log.h"
#include "abstract_aqi_calculator.h"
@@ -35,7 +37,9 @@ class CAQICalculator : public AbstractAQICalculator {
int conc_lo = array[grid_index][0];
int conc_hi = array[grid_index][1];
return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
int aqi = ((aqi_hi - aqi_lo) / (conc_hi - conc_lo)) * (value - conc_lo) + aqi_lo;
return aqi;
}
int get_grid_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
@@ -50,3 +54,5 @@ class CAQICalculator : public AbstractAQICalculator {
} // namespace hm3301
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,3 +1,5 @@
#ifdef USE_ARDUINO
#include "esphome/core/log.h"
#include "hm3301.h"
@@ -12,8 +14,9 @@ static const uint8_t PM_10_0_VALUE_INDEX = 7;
void HM3301Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up HM3301...");
if (i2c::ERROR_OK != this->write(&SELECT_COMM_CMD, 1)) {
error_code_ = ERROR_COMM;
hm3301_ = make_unique<HM330X>();
error_code_ = hm3301_->init();
if (error_code_ != NO_ERROR) {
this->mark_failed();
return;
}
@@ -35,7 +38,7 @@ void HM3301Component::dump_config() {
float HM3301Component::get_setup_priority() const { return setup_priority::DATA; }
void HM3301Component::update() {
if (this->read(data_buffer_, 29) != i2c::ERROR_OK) {
if (!this->read_sensor_value_(data_buffer_)) {
ESP_LOGW(TAG, "Read result failed");
this->status_set_warning();
return;
@@ -84,6 +87,8 @@ void HM3301Component::update() {
this->status_clear_warning();
}
bool HM3301Component::read_sensor_value_(uint8_t *data) { return !hm3301_->read_sensor_value(data, 29); }
bool HM3301Component::validate_checksum_(const uint8_t *data) {
uint8_t sum = 0;
for (int i = 0; i < 28; i++) {
@@ -99,3 +104,5 @@ uint16_t HM3301Component::get_sensor_value_(const uint8_t *data, uint8_t i) {
} // namespace hm3301
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,15 +1,17 @@
#pragma once
#ifdef USE_ARDUINO
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
#include "aqi_calculator_factory.h"
#include <Seeed_HM330X.h>
namespace esphome {
namespace hm3301 {
static const uint8_t SELECT_COMM_CMD = 0X88;
class HM3301Component : public PollingComponent, public i2c::I2CDevice {
public:
HM3301Component() = default;
@@ -27,12 +29,9 @@ class HM3301Component : public PollingComponent, public i2c::I2CDevice {
void update() override;
protected:
enum {
NO_ERROR = 0,
ERROR_PARAM = -1,
ERROR_COMM = -2,
ERROR_OTHERS = -128,
} error_code_{NO_ERROR};
std::unique_ptr<HM330X> hm3301_;
HM330XErrorCode error_code_{NO_ERROR};
uint8_t data_buffer_[30];
@@ -44,9 +43,12 @@ class HM3301Component : public PollingComponent, public i2c::I2CDevice {
AQICalculatorType aqi_calc_type_;
AQICalculatorFactory aqi_calculator_factory_ = AQICalculatorFactory();
bool read_sensor_value_(uint8_t *);
bool validate_checksum_(const uint8_t *);
uint16_t get_sensor_value_(const uint8_t *, uint8_t);
};
} // namespace hm3301
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -84,6 +84,7 @@ CONFIG_SCHEMA = cv.All(
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x40)),
_validate,
cv.only_with_arduino,
)
@@ -108,3 +109,6 @@ async def to_code(config):
sens = await sensor.new_sensor(config[CONF_AQI])
cg.add(var.set_aqi_sensor(sens))
cg.add(var.set_aqi_calculation_type(config[CONF_AQI][CONF_CALCULATION_TYPE]))
# https://platformio.org/lib/show/6306/Grove%20-%20Laser%20PM2.5%20Sensor%20HM3301
cg.add_library("seeed-studio/Grove - Laser PM2.5 Sensor HM3301", "1.0.3")

View File

@@ -114,8 +114,8 @@ CONFIG_SCHEMA = (
def auto_data_rate(config):
interval_msec = config[CONF_UPDATE_INTERVAL].total_milliseconds
interval_hz = 1000.0 / interval_msec
interval_sec = config[CONF_UPDATE_INTERVAL].seconds
interval_hz = 1.0 / interval_sec
for datarate in sorted(HMC5883LDatarates.keys()):
if float(datarate) >= interval_hz:
return HMC5883LDatarates[datarate]

View File

@@ -172,7 +172,7 @@ async def http_request_action_to_code(config, action_id, template_arg, args):
if CONF_JSON in config:
json_ = config[CONF_JSON]
if isinstance(json_, Lambda):
args_ = args + [(cg.JsonObject, "root")]
args_ = args + [(cg.JsonObjectRef, "root")]
lambda_ = await cg.process_lambda(json_, args_, return_type=cg.void)
cg.add(var.set_json(lambda_))
else:

View File

@@ -115,11 +115,8 @@ void HttpRequestComponent::close() {
}
const char *HttpRequestComponent::get_string() {
// The static variable is here because HTTPClient::getString() returns a String on ESP32, and we need something to
// to keep a buffer alive.
static std::string str;
str = this->client_.getString().c_str();
return str.c_str();
static const String STR = this->client_.getString();
return STR.c_str();
}
} // namespace http_request

View File

@@ -78,7 +78,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
void add_json(const char *key, TemplatableValue<std::string, Ts...> value) { this->json_.insert({key, value}); }
void set_json(std::function<void(Ts..., JsonObject)> json_func) { this->json_func_ = json_func; }
void set_json(std::function<void(Ts..., JsonObject &)> json_func) { this->json_func_ = json_func; }
void register_response_trigger(HttpRequestResponseTrigger *trigger) { this->response_triggers_.push_back(trigger); }
@@ -118,17 +118,17 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
}
protected:
void encode_json_(Ts... x, JsonObject root) {
void encode_json_(Ts... x, JsonObject &root) {
for (const auto &item : this->json_) {
auto val = item.second;
root[item.first] = val.value(x...);
}
}
void encode_json_func_(Ts... x, JsonObject root) { this->json_func_(x..., root); }
void encode_json_func_(Ts... x, JsonObject &root) { this->json_func_(x..., root); }
HttpRequestComponent *parent_;
std::map<const char *, TemplatableValue<const char *, Ts...>> headers_{};
std::map<const char *, TemplatableValue<std::string, Ts...>> json_{};
std::function<void(Ts..., JsonObject)> json_func_{nullptr};
std::function<void(Ts..., JsonObject &)> json_func_{nullptr};
std::vector<HttpRequestResponseTrigger *> response_triggers_;
};

View File

@@ -1,8 +1,6 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <utility>
#include <vector>
namespace esphome {
namespace i2c {
@@ -42,20 +40,6 @@ class I2CBus {
return writev(address, &buf, 1);
}
virtual ErrorCode writev(uint8_t address, WriteBuffer *buffers, size_t cnt) = 0;
protected:
void i2c_scan_() {
for (uint8_t address = 8; address < 120; address++) {
auto err = writev(address, nullptr, 0);
if (err == ERROR_OK) {
scan_results_.emplace_back(address, true);
} else if (err == ERROR_UNKNOWN) {
scan_results_.emplace_back(address, false);
}
}
}
std::vector<std::pair<uint8_t, bool>> scan_results_;
bool scan_{false};
};
} // namespace i2c

View File

@@ -2,7 +2,6 @@
#include "i2c_bus_arduino.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include <Arduino.h>
#include <cstring>
@@ -25,13 +24,9 @@ void ArduinoI2CBus::setup() {
wire_ = &Wire; // NOLINT(cppcoreguidelines-prefer-member-initializer)
#endif
wire_->begin(static_cast<int>(sda_pin_), static_cast<int>(scl_pin_));
wire_->begin(sda_pin_, scl_pin_);
wire_->setClock(frequency_);
initialized_ = true;
if (this->scan_) {
ESP_LOGV(TAG, "Scanning i2c bus for active devices...");
this->i2c_scan_();
}
}
void ArduinoI2CBus::dump_config() {
ESP_LOGCONFIG(TAG, "I2C Bus:");
@@ -50,20 +45,22 @@ void ArduinoI2CBus::dump_config() {
break;
}
if (this->scan_) {
ESP_LOGI(TAG, "Results from i2c bus scan:");
if (scan_results_.empty()) {
ESP_LOGI(TAG, "Found no i2c devices!");
} else {
for (const auto &s : scan_results_) {
if (s.second)
ESP_LOGI(TAG, "Found i2c device at address 0x%02X", s.first);
else
ESP_LOGE(TAG, "Unknown error at address 0x%02X", s.first);
ESP_LOGI(TAG, "Scanning i2c bus for active devices...");
uint8_t found = 0;
for (uint8_t address = 8; address < 120; address++) {
auto err = writev(address, nullptr, 0);
if (err == ERROR_OK) {
ESP_LOGI(TAG, "Found i2c device at address 0x%02X", address);
found++;
} else if (err == ERROR_UNKNOWN) {
ESP_LOGI(TAG, "Unknown error at address 0x%02X", address);
}
}
if (found == 0) {
ESP_LOGI(TAG, "Found no i2c devices!");
}
}
}
ErrorCode ArduinoI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) {
// logging is only enabled with vv level, if warnings are shown the caller
// should log them

View File

@@ -34,6 +34,7 @@ class ArduinoI2CBus : public I2CBus, public Component {
protected:
TwoWire *wire_;
bool scan_;
uint8_t sda_pin_;
uint8_t scl_pin_;
uint32_t frequency_;

View File

@@ -3,7 +3,6 @@
#include "i2c_bus_esp_idf.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include <cstring>
namespace esphome {
@@ -38,10 +37,6 @@ void IDFI2CBus::setup() {
return;
}
initialized_ = true;
if (this->scan_) {
ESP_LOGV(TAG, "Scanning i2c bus for active devices...");
this->i2c_scan_();
}
}
void IDFI2CBus::dump_config() {
ESP_LOGCONFIG(TAG, "I2C Bus:");
@@ -60,20 +55,23 @@ void IDFI2CBus::dump_config() {
break;
}
if (this->scan_) {
ESP_LOGI(TAG, "Results from i2c bus scan:");
if (scan_results_.empty()) {
ESP_LOGI(TAG, "Found no i2c devices!");
} else {
for (const auto &s : scan_results_) {
if (s.second)
ESP_LOGI(TAG, "Found i2c device at address 0x%02X", s.first);
else
ESP_LOGE(TAG, "Unknown error at address 0x%02X", s.first);
ESP_LOGI(TAG, "Scanning i2c bus for active devices...");
uint8_t found = 0;
for (uint8_t address = 8; address < 120; address++) {
auto err = writev(address, nullptr, 0);
if (err == ERROR_OK) {
ESP_LOGI(TAG, "Found i2c device at address 0x%02X", address);
found++;
} else if (err == ERROR_UNKNOWN) {
ESP_LOGI(TAG, "Unknown error at address 0x%02X", address);
}
}
if (found == 0) {
ESP_LOGI(TAG, "Found no i2c devices!");
}
}
}
ErrorCode IDFI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) {
// logging is only enabled with vv level, if warnings are shown the caller
// should log them

View File

@@ -36,6 +36,7 @@ class IDFI2CBus : public I2CBus, public Component {
protected:
i2c_port_t port_;
bool scan_;
uint8_t sda_pin_;
bool sda_pullup_enabled_;
uint8_t scl_pin_;

View File

@@ -86,8 +86,8 @@ void ILI9341Display::update() {
void ILI9341Display::display_() {
// we will only update the changed window to the display
uint16_t w = this->x_high_ - this->x_low_ + 1;
uint16_t h = this->y_high_ - this->y_low_ + 1;
int w = this->x_high_ - this->x_low_ + 1;
int h = this->y_high_ - this->y_low_ + 1;
set_addr_window_(this->x_low_, this->y_low_, w, h);
this->start_data_();

View File

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

View File

@@ -0,0 +1,93 @@
#include "improv.h"
namespace improv {
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data) {
return parse_improv_data(data.data(), data.size());
}
ImprovCommand parse_improv_data(const uint8_t *data, size_t length) {
ImprovCommand improv_command;
Command command = (Command) data[0];
uint8_t data_length = data[1];
if (data_length != length - 3) {
improv_command.command = UNKNOWN;
return improv_command;
}
uint8_t checksum = data[length - 1];
uint32_t calculated_checksum = 0;
for (uint8_t i = 0; i < length - 1; i++) {
calculated_checksum += data[i];
}
if ((uint8_t) calculated_checksum != checksum) {
improv_command.command = BAD_CHECKSUM;
return improv_command;
}
if (command == WIFI_SETTINGS) {
uint8_t ssid_length = data[2];
uint8_t ssid_start = 3;
size_t ssid_end = ssid_start + ssid_length;
uint8_t pass_length = data[ssid_end];
size_t pass_start = ssid_end + 1;
size_t pass_end = pass_start + pass_length;
std::string ssid(data + ssid_start, data + ssid_end);
std::string password(data + pass_start, data + pass_end);
return {.command = command, .ssid = ssid, .password = password};
}
improv_command.command = command;
return improv_command;
}
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<std::string> &datum) {
std::vector<uint8_t> out;
uint32_t length = 0;
out.push_back(command);
for (auto str : datum) {
uint8_t len = str.length();
length += len;
out.push_back(len);
out.insert(out.end(), str.begin(), str.end());
}
out.insert(out.begin() + 1, length);
uint32_t calculated_checksum = 0;
for (uint8_t byte : out) {
calculated_checksum += byte;
}
out.push_back(calculated_checksum);
return out;
}
#ifdef USE_ARDUINO
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<String> &datum) {
std::vector<uint8_t> out;
uint32_t length = 0;
out.push_back(command);
for (auto str : datum) {
uint8_t len = str.length();
length += len;
out.push_back(len);
out.insert(out.end(), str.begin(), str.end());
}
out.insert(out.begin() + 1, length);
uint32_t calculated_checksum = 0;
for (uint8_t byte : out) {
calculated_checksum += byte;
}
out.push_back(calculated_checksum);
return out;
}
#endif // USE_ARDUINO
} // namespace improv

View File

@@ -0,0 +1,62 @@
#pragma once
#ifdef ARDUINO
#include "WString.h"
#endif // ARDUINO
#include <cstdint>
#include <string>
#include <vector>
namespace improv {
static const char *const SERVICE_UUID = "00467768-6228-2272-4663-277478268000";
static const char *const STATUS_UUID = "00467768-6228-2272-4663-277478268001";
static const char *const ERROR_UUID = "00467768-6228-2272-4663-277478268002";
static const char *const RPC_COMMAND_UUID = "00467768-6228-2272-4663-277478268003";
static const char *const RPC_RESULT_UUID = "00467768-6228-2272-4663-277478268004";
static const char *const CAPABILITIES_UUID = "00467768-6228-2272-4663-277478268005";
enum Error : uint8_t {
ERROR_NONE = 0x00,
ERROR_INVALID_RPC = 0x01,
ERROR_UNKNOWN_RPC = 0x02,
ERROR_UNABLE_TO_CONNECT = 0x03,
ERROR_NOT_AUTHORIZED = 0x04,
ERROR_UNKNOWN = 0xFF,
};
enum State : uint8_t {
STATE_STOPPED = 0x00,
STATE_AWAITING_AUTHORIZATION = 0x01,
STATE_AUTHORIZED = 0x02,
STATE_PROVISIONING = 0x03,
STATE_PROVISIONED = 0x04,
};
enum Command : uint8_t {
UNKNOWN = 0x00,
WIFI_SETTINGS = 0x01,
IDENTIFY = 0x02,
GET_CURRENT_STATE = 0x02,
GET_DEVICE_INFO = 0x03,
BAD_CHECKSUM = 0xFF,
};
static const uint8_t CAPABILITY_IDENTIFY = 0x01;
struct ImprovCommand {
Command command;
std::string ssid;
std::string password;
};
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data);
ImprovCommand parse_improv_data(const uint8_t *data, size_t length);
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<std::string> &datum);
#ifdef ARDUINO
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<String> &datum);
#endif // ARDUINO
} // namespace improv

View File

@@ -5,6 +5,7 @@ import esphome.final_validate as fv
CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["logger", "wifi"]
AUTO_LOAD = ["improv"]
improv_serial_ns = cg.esphome_ns.namespace("improv_serial")
@@ -30,4 +31,3 @@ FINAL_VALIDATE_SCHEMA = validate_logger_baud_rate
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add_library("esphome/Improv", "1.0.0")

View File

@@ -98,13 +98,13 @@ std::vector<uint8_t> ImprovSerialComponent::build_rpc_settings_response_(improv:
std::string webserver_url = "http://" + ip.str() + ":" + to_string(WEBSERVER_PORT);
urls.push_back(webserver_url);
#endif
std::vector<uint8_t> data = improv::build_rpc_response(command, urls, false);
std::vector<uint8_t> data = improv::build_rpc_response(command, urls);
return data;
}
std::vector<uint8_t> ImprovSerialComponent::build_version_info_() {
std::vector<std::string> infos = {"ESPHome", ESPHOME_VERSION, ESPHOME_VARIANT, App.get_name()};
std::vector<uint8_t> data = improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false);
std::vector<uint8_t> data = improv::build_rpc_response(improv::GET_DEVICE_INFO, infos);
return data;
};
@@ -140,33 +140,22 @@ bool ImprovSerialComponent::parse_improv_serial_byte_(uint8_t byte) {
if (at < 8 + data_len)
return true;
if (at == 8 + data_len)
return true;
if (at == 8 + data_len + 1) {
uint8_t checksum = 0x00;
for (size_t i = 0; i < at; i++)
checksum += raw[i];
if (checksum != byte) {
ESP_LOGW(TAG, "Error decoding Improv payload");
this->set_error_(improv::ERROR_INVALID_RPC);
return false;
}
if (at == 8 + data_len) {
if (type == TYPE_RPC) {
this->set_error_(improv::ERROR_NONE);
auto command = improv::parse_improv_data(&raw[9], data_len, false);
auto command = improv::parse_improv_data(&raw[9], data_len);
return this->parse_improv_payload_(command);
}
}
// If we got here then the command coming is is improv, but not an RPC command
return false;
return true;
}
bool ImprovSerialComponent::parse_improv_payload_(improv::ImprovCommand &command) {
switch (command.command) {
case improv::BAD_CHECKSUM:
ESP_LOGW(TAG, "Error decoding Improv payload");
this->set_error_(improv::ERROR_INVALID_RPC);
return false;
case improv::WIFI_SETTINGS: {
wifi::WiFiAP sta{};
sta.set_ssid(command.ssid);
@@ -243,12 +232,6 @@ void ImprovSerialComponent::send_response_(std::vector<uint8_t> &response) {
data[7] = TYPE_RPC_RESPONSE;
data[8] = response.size();
data.insert(data.end(), response.begin(), response.end());
uint8_t checksum = 0x00;
for (uint8_t d : data)
checksum += d;
data.push_back(checksum);
this->write_data_(data);
}

View File

@@ -1,12 +1,11 @@
#pragma once
#include "esphome/components/improv/improv.h"
#include "esphome/components/wifi/wifi_component.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include <improv.h>
#ifdef USE_ARDUINO
#include <HardwareSerial.h>
#endif

View File

@@ -1,128 +0,0 @@
#include "ina260.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace ina260 {
static const char *const TAG = "ina260";
// | A0 | A1 | Address |
// | GND | GND | 0x40 |
// | GND | V_S+ | 0x41 |
// | GND | SDA | 0x42 |
// | GND | SCL | 0x43 |
// | V_S+ | GND | 0x44 |
// | V_S+ | V_S+ | 0x45 |
// | V_S+ | SDA | 0x46 |
// | V_S+ | SCL | 0x47 |
// | SDA | GND | 0x48 |
// | SDA | V_S+ | 0x49 |
// | SDA | SDA | 0x4A |
// | SDA | SCL | 0x4B |
// | SCL | GND | 0x4C |
// | SCL | V_S+ | 0x4D |
// | SCL | SDA | 0x4E |
// | SCL | SCL | 0x4F |
static const uint8_t INA260_REGISTER_CONFIG = 0x00;
static const uint8_t INA260_REGISTER_CURRENT = 0x01;
static const uint8_t INA260_REGISTER_BUS_VOLTAGE = 0x02;
static const uint8_t INA260_REGISTER_POWER = 0x03;
static const uint8_t INA260_REGISTER_MASK_ENABLE = 0x06;
static const uint8_t INA260_REGISTER_ALERT_LIMIT = 0x07;
static const uint8_t INA260_REGISTER_MANUFACTURE_ID = 0xFE;
static const uint8_t INA260_REGISTER_DEVICE_ID = 0xFF;
void INA260Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up INA260...");
// Reset device on setup
if (!this->write_byte_16(INA260_REGISTER_CONFIG, 0x8000)) {
this->error_code_ = DEVICE_RESET_FAILED;
this->mark_failed();
return;
}
delay(2);
this->read_byte_16(INA260_REGISTER_MANUFACTURE_ID, &this->manufacture_id_);
this->read_byte_16(INA260_REGISTER_DEVICE_ID, &this->device_id_);
if (this->manufacture_id_ != (uint16_t) 0x5449 || this->device_id_ != (uint16_t) 0x2270) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (!this->write_byte_16(INA260_REGISTER_CONFIG, (uint16_t) 0b0000001100000111)) {
this->error_code_ = FAILED_TO_UPDATE_CONFIGURATION;
this->mark_failed();
return;
}
}
void INA260Component::dump_config() {
ESP_LOGCONFIG(TAG, "INA260:");
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG, " Manufacture ID: 0x%x", this->manufacture_id_);
ESP_LOGCONFIG(TAG, " Device ID: 0x%x", this->device_id_);
LOG_SENSOR(" ", "Bus Voltage", this->bus_voltage_sensor_);
LOG_SENSOR(" ", "Current", this->current_sensor_);
LOG_SENSOR(" ", "Power", this->power_sensor_);
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Connected device does not match a known INA260 sensor");
break;
case DEVICE_RESET_FAILED:
ESP_LOGE(TAG, "Device reset failed - Is the device connected?");
break;
case FAILED_TO_UPDATE_CONFIGURATION:
ESP_LOGE(TAG, "Failed to update device configuration");
break;
case NONE:
default:
break;
}
}
void INA260Component::update() {
if (this->bus_voltage_sensor_ != nullptr) {
uint16_t raw_bus_voltage;
if (!this->read_byte_16(INA260_REGISTER_BUS_VOLTAGE, &raw_bus_voltage)) {
this->status_set_warning();
return;
}
float bus_voltage_v = int16_t(raw_bus_voltage) * 0.00125f;
this->bus_voltage_sensor_->publish_state(bus_voltage_v);
}
if (this->current_sensor_ != nullptr) {
uint16_t raw_current;
if (!this->read_byte_16(INA260_REGISTER_CURRENT, &raw_current)) {
this->status_set_warning();
return;
}
float current_a = int16_t(raw_current) * 0.00125f;
this->current_sensor_->publish_state(current_a);
}
if (this->power_sensor_ != nullptr) {
uint16_t raw_power;
if (!this->read_byte_16(INA260_REGISTER_POWER, &raw_power)) {
this->status_set_warning();
return;
}
float power_w = ((int16_t(raw_power) * 10.0f) / 1000.0f);
this->power_sensor_->publish_state(power_w);
}
this->status_clear_warning();
}
} // namespace ina260
} // namespace esphome

View File

@@ -1,39 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace ina260 {
class INA260Component : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
void update() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_bus_voltage_sensor(sensor::Sensor *bus_voltage_sensor) { this->bus_voltage_sensor_ = bus_voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { this->current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; }
protected:
uint16_t manufacture_id_{0};
uint16_t device_id_{0};
sensor::Sensor *bus_voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
enum ErrorCode {
NONE,
COMMUNICATION_FAILED,
DEVICE_RESET_FAILED,
FAILED_TO_UPDATE_CONFIGURATION,
} error_code_{NONE};
};
} // namespace ina260
} // namespace esphome

View File

@@ -1,71 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
CONF_BUS_VOLTAGE,
CONF_CURRENT,
CONF_POWER,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_POWER,
STATE_CLASS_MEASUREMENT,
UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
)
DEPENDENCIES = ["i2c"]
CODEOWNERS = ["@MrEditor97"]
ina260_ns = cg.esphome_ns.namespace("ina260")
INA260Component = ina260_ns.class_(
"INA260Component", cg.PollingComponent, i2c.I2CDevice
)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(INA260Component),
cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=3,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x40))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
if CONF_BUS_VOLTAGE in config:
sens = await sensor.new_sensor(config[CONF_BUS_VOLTAGE])
cg.add(var.set_bus_voltage_sensor(sens))
if CONF_CURRENT in config:
sens = await sensor.new_sensor(config[CONF_CURRENT])
cg.add(var.set_current_sensor(sens))
if CONF_POWER in config:
sens = await sensor.new_sensor(config[CONF_POWER])
cg.add(var.set_power_sensor(sens))

View File

@@ -6,13 +6,11 @@ from esphome.const import (
CONF_FULL_UPDATE_EVERY,
CONF_ID,
CONF_LAMBDA,
CONF_MODEL,
CONF_PAGES,
CONF_WAKEUP_PIN,
)
DEPENDENCIES = ["i2c", "esp32"]
AUTO_LOAD = ["psram"]
CONF_DISPLAY_DATA_0_PIN = "display_data_0_pin"
CONF_DISPLAY_DATA_1_PIN = "display_data_1_pin"
@@ -42,13 +40,6 @@ Inkplate6 = inkplate6_ns.class_(
"Inkplate6", cg.PollingComponent, i2c.I2CDevice, display.DisplayBuffer
)
InkplateModel = inkplate6_ns.enum("InkplateModel")
MODELS = {
"inkplate_6": InkplateModel.INKPLATE_6,
"inkplate_10": InkplateModel.INKPLATE_10,
}
CONFIG_SCHEMA = cv.All(
display.FULL_DISPLAY_SCHEMA.extend(
{
@@ -56,9 +47,6 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_GREYSCALE, default=False): cv.boolean,
cv.Optional(CONF_PARTIAL_UPDATING, default=True): cv.boolean,
cv.Optional(CONF_FULL_UPDATE_EVERY, default=10): cv.uint32_t,
cv.Optional(CONF_MODEL, default="inkplate_6"): cv.enum(
MODELS, lower=True, space="_"
),
# Control pins
cv.Required(CONF_CKV_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_GMOD_PIN): pins.gpio_output_pin_schema,
@@ -122,8 +110,6 @@ async def to_code(config):
cg.add(var.set_partial_updating(config[CONF_PARTIAL_UPDATING]))
cg.add(var.set_full_update_every(config[CONF_FULL_UPDATE_EVERY]))
cg.add(var.set_model(config[CONF_MODEL]))
ckv = await cg.gpio_pin_expression(config[CONF_CKV_PIN])
cg.add(var.set_ckv_pin(ckv))
@@ -180,3 +166,5 @@ async def to_code(config):
display_data_7 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_7_PIN])
cg.add(var.set_display_data_7_pin(display_data_7))
cg.add_build_flag("-DBOARD_HAS_PSRAM")

View File

@@ -42,32 +42,32 @@ void Inkplate6::setup() {
this->display();
}
void Inkplate6::initialize_() {
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
uint32_t buffer_size = this->get_buffer_length_();
if (buffer_size == 0)
return;
if (this->partial_buffer_ != nullptr)
allocator.deallocate(this->partial_buffer_, buffer_size);
if (this->partial_buffer_2_ != nullptr)
allocator.deallocate(this->partial_buffer_2_, buffer_size * 2);
if (this->buffer_ != nullptr)
allocator.deallocate(this->buffer_, buffer_size);
if (this->partial_buffer_ != nullptr) {
free(this->partial_buffer_); // NOLINT
}
if (this->partial_buffer_2_ != nullptr) {
free(this->partial_buffer_2_); // NOLINT
}
if (this->buffer_ != nullptr) {
free(this->buffer_); // NOLINT
}
this->buffer_ = allocator.allocate(buffer_size);
this->buffer_ = (uint8_t *) ps_malloc(buffer_size);
if (this->buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate buffer for display!");
this->mark_failed();
return;
}
if (!this->greyscale_) {
this->partial_buffer_ = allocator.allocate(buffer_size);
this->partial_buffer_ = (uint8_t *) ps_malloc(buffer_size);
if (this->partial_buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate partial buffer for display!");
this->mark_failed();
return;
}
this->partial_buffer_2_ = allocator.allocate(buffer_size * 2);
this->partial_buffer_2_ = (uint8_t *) ps_malloc(buffer_size * 2);
if (this->partial_buffer_2_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate partial buffer 2 for display!");
this->mark_failed();

View File

@@ -10,11 +10,6 @@
namespace esphome {
namespace inkplate6 {
enum InkplateModel : uint8_t {
INKPLATE_6 = 0,
INKPLATE_10 = 1,
};
class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public i2c::I2CDevice {
public:
const uint8_t LUT2[16] = {0b10101010, 0b10101001, 0b10100110, 0b10100101, 0b10011010, 0b10011001,
@@ -48,8 +43,6 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
void set_partial_updating(bool partial_updating) { this->partial_updating_ = partial_updating; }
void set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
void set_model(InkplateModel model) { this->model_ = model; }
void set_display_data_0_pin(InternalGPIOPin *data) { this->display_data_0_pin_ = data; }
void set_display_data_1_pin(InternalGPIOPin *data) { this->display_data_1_pin_ = data; }
void set_display_data_2_pin(InternalGPIOPin *data) { this->display_data_2_pin_ = data; }
@@ -108,21 +101,9 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
void pins_z_state_();
void pins_as_outputs_();
int get_width_internal() override {
if (this->model_ == INKPLATE_6)
return 800;
else if (this->model_ == INKPLATE_10)
return 1200;
return 0;
}
int get_width_internal() override { return 800; }
int get_height_internal() override {
if (this->model_ == INKPLATE_6)
return 600;
else if (this->model_ == INKPLATE_10)
return 825;
return 0;
}
int get_height_internal() override { return 600; }
size_t get_buffer_length_();
@@ -152,8 +133,6 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
bool greyscale_;
bool partial_updating_;
InkplateModel model_;
InternalGPIOPin *display_data_0_pin_;
InternalGPIOPin *display_data_1_pin_;
InternalGPIOPin *display_data_2_pin_;

View File

@@ -23,6 +23,31 @@ void IntegrationSensor::setup() {
this->sensor_->add_on_state_callback([this](float state) { this->process_sensor_value_(state); });
}
void IntegrationSensor::dump_config() { LOG_SENSOR("", "Integration Sensor", this); }
std::string IntegrationSensor::unit_of_measurement() {
std::string suffix;
switch (this->time_) {
case INTEGRATION_SENSOR_TIME_MILLISECOND:
suffix = "ms";
break;
case INTEGRATION_SENSOR_TIME_SECOND:
suffix = "s";
break;
case INTEGRATION_SENSOR_TIME_MINUTE:
suffix = "min";
break;
case INTEGRATION_SENSOR_TIME_HOUR:
suffix = "h";
break;
case INTEGRATION_SENSOR_TIME_DAY:
suffix = "d";
break;
}
std::string base = this->sensor_->get_unit_of_measurement();
if (str_endswith(base, "/" + suffix)) {
return base.substr(0, base.size() - suffix.size() - 1);
}
return base + suffix;
}
void IntegrationSensor::process_sensor_value_(float value) {
const uint32_t now = millis();
const double old_value = this->last_value_;

View File

@@ -63,6 +63,8 @@ class IntegrationSensor : public sensor::Sensor, public Component {
this->last_save_ = now;
this->rtc_.save(&result_f);
}
std::string unit_of_measurement() override;
int8_t accuracy_decimals() override { return this->sensor_->get_accuracy_decimals() + 2; }
sensor::Sensor *sensor_;
IntegrationSensorTime time_;

View File

@@ -2,14 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.components import sensor
from esphome.const import (
CONF_ICON,
CONF_ID,
CONF_SENSOR,
CONF_RESTORE,
CONF_UNIT_OF_MEASUREMENT,
CONF_ACCURACY_DECIMALS,
)
from esphome.const import CONF_ICON, CONF_ID, CONF_SENSOR, CONF_RESTORE
from esphome.core.entity_helpers import inherit_property_from
integration_ns = cg.esphome_ns.namespace("integration")
@@ -37,18 +30,6 @@ CONF_TIME_UNIT = "time_unit"
CONF_INTEGRATION_METHOD = "integration_method"
CONF_MIN_SAVE_INTERVAL = "min_save_interval"
def inherit_unit_of_measurement(uom, config):
suffix = config[CONF_TIME_UNIT]
if uom.endswith("/" + suffix):
return uom[0 : -len("/" + suffix)]
return uom + suffix
def inherit_accuracy_decimals(decimals, config):
return decimals + 2
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(IntegrationSensor),
@@ -70,19 +51,11 @@ FINAL_VALIDATE_SCHEMA = cv.All(
{
cv.Required(CONF_ID): cv.use_id(IntegrationSensor),
cv.Optional(CONF_ICON): cv.icon,
cv.Optional(CONF_UNIT_OF_MEASUREMENT): sensor.validate_unit_of_measurement,
cv.Optional(CONF_ACCURACY_DECIMALS): sensor.validate_accuracy_decimals,
cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
},
extra=cv.ALLOW_EXTRA,
),
inherit_property_from(CONF_ICON, CONF_SENSOR),
inherit_property_from(
CONF_UNIT_OF_MEASUREMENT, CONF_SENSOR, transform=inherit_unit_of_measurement
),
inherit_property_from(
CONF_ACCURACY_DECIMALS, CONF_SENSOR, transform=inherit_accuracy_decimals
),
)

View File

@@ -7,11 +7,12 @@ json_ns = cg.esphome_ns.namespace("json")
CONFIG_SCHEMA = cv.All(
cv.Schema({}),
cv.only_with_arduino,
)
@coroutine_with_priority(1.0)
async def to_code(config):
cg.add_library("bblanchon/ArduinoJson", "6.18.5")
cg.add_library("ottowinter/ArduinoJson-esphomelib", "5.13.3")
cg.add_define("USE_JSON")
cg.add_global(json_ns.using)

View File

@@ -1,13 +1,8 @@
#ifdef USE_ARDUINO
#include "json_util.h"
#include "esphome/core/log.h"
#ifdef USE_ESP8266
#include <Esp.h>
#endif
#ifdef USE_ESP32
#include <esp_heap_caps.h>
#endif
namespace esphome {
namespace json {
@@ -15,49 +10,110 @@ static const char *const TAG = "json";
static std::vector<char> global_json_build_buffer; // NOLINT
std::string build_json(const json_build_t &f) {
// Here we are allocating as much heap memory as available minus 2kb to be safe
// as we can not have a true dynamic sized document.
// The excess memory is freed below with `shrinkToFit()`
#ifdef USE_ESP8266
const size_t free_heap = ESP.getMaxFreeBlockSize() - 2048; // NOLINT(readability-static-accessed-through-instance)
#elif defined(USE_ESP32)
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT) - 2048;
#endif
const char *build_json(const json_build_t &f, size_t *length) {
global_json_buffer.clear();
JsonObject &root = global_json_buffer.createObject();
DynamicJsonDocument json_document(free_heap);
JsonObject root = json_document.to<JsonObject>();
f(root);
json_document.shrinkToFit();
std::string output;
serializeJson(json_document, output);
return output;
// The Json buffer size gives us a good estimate for the required size.
// Usually, it's a bit larger than the actual required string size
// | JSON Buffer Size | String Size |
// Discovery | 388 | 351 |
// Discovery | 372 | 356 |
// Discovery | 336 | 311 |
// Discovery | 408 | 393 |
global_json_build_buffer.reserve(global_json_buffer.size() + 1);
size_t bytes_written = root.printTo(global_json_build_buffer.data(), global_json_build_buffer.capacity());
if (bytes_written >= global_json_build_buffer.capacity() - 1) {
global_json_build_buffer.reserve(root.measureLength() + 1);
bytes_written = root.printTo(global_json_build_buffer.data(), global_json_build_buffer.capacity());
}
*length = bytes_written;
return global_json_build_buffer.data();
}
void parse_json(const std::string &data, const json_parse_t &f) {
// Here we are allocating as much heap memory as available minus 2kb to be safe
// as we can not have a true dynamic sized document.
// The excess memory is freed below with `shrinkToFit()`
#ifdef USE_ESP8266
const size_t free_heap = ESP.getMaxFreeBlockSize() - 2048; // NOLINT(readability-static-accessed-through-instance)
#elif defined(USE_ESP32)
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT) - 2048;
#endif
global_json_buffer.clear();
JsonObject &root = global_json_buffer.parseObject(data);
DynamicJsonDocument json_document(free_heap);
DeserializationError err = deserializeJson(json_document, data);
json_document.shrinkToFit();
JsonObject root = json_document.as<JsonObject>();
if (err) {
if (!root.success()) {
ESP_LOGW(TAG, "Parsing JSON failed.");
return;
}
f(root);
}
std::string build_json(const json_build_t &f) {
size_t len;
const char *c_str = build_json(f, &len);
return std::string(c_str, len);
}
VectorJsonBuffer::String::String(VectorJsonBuffer *parent) : parent_(parent), start_(parent->size_) {}
void VectorJsonBuffer::String::append(char c) const {
char *last = static_cast<char *>(this->parent_->do_alloc(1));
*last = c;
}
const char *VectorJsonBuffer::String::c_str() const {
this->append('\0');
return &this->parent_->buffer_[this->start_];
}
void VectorJsonBuffer::clear() {
for (char *block : this->free_blocks_)
free(block); // NOLINT
this->size_ = 0;
this->free_blocks_.clear();
}
VectorJsonBuffer::String VectorJsonBuffer::startString() { return {this}; } // NOLINT
void *VectorJsonBuffer::alloc(size_t bytes) {
// Make sure memory addresses are aligned
uint32_t new_size = round_size_up(this->size_);
this->resize(new_size);
return this->do_alloc(bytes);
}
void *VectorJsonBuffer::do_alloc(size_t bytes) { // NOLINT
const uint32_t begin = this->size_;
this->resize(begin + bytes);
return &this->buffer_[begin];
}
void VectorJsonBuffer::resize(size_t size) { // NOLINT
if (size <= this->size_) {
this->size_ = size;
return;
}
this->reserve(size);
this->size_ = size;
}
void VectorJsonBuffer::reserve(size_t size) { // NOLINT
if (size <= this->capacity_)
return;
uint32_t target_capacity = this->capacity_;
if (this->capacity_ == 0) {
// lazily initialize with a reasonable size
target_capacity = JSON_OBJECT_SIZE(16);
}
while (target_capacity < size)
target_capacity *= 2;
char *old_buffer = this->buffer_;
this->buffer_ = new char[target_capacity]; // NOLINT
if (old_buffer != nullptr && this->capacity_ != 0) {
this->free_blocks_.push_back(old_buffer);
memcpy(this->buffer_, old_buffer, this->capacity_);
}
this->capacity_ = target_capacity;
}
size_t VectorJsonBuffer::size() const { return this->size_; }
VectorJsonBuffer global_json_buffer; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace json
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,28 +1,68 @@
#pragma once
#ifdef USE_ARDUINO
#include <vector>
#include "esphome/core/helpers.h"
#undef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 1 // NOLINT
#include <ArduinoJson.h>
namespace esphome {
namespace json {
/// Callback function typedef for parsing JsonObjects.
using json_parse_t = std::function<void(JsonObject)>;
using json_parse_t = std::function<void(JsonObject &)>;
/// Callback function typedef for building JsonObjects.
using json_build_t = std::function<void(JsonObject)>;
using json_build_t = std::function<void(JsonObject &)>;
/// Build a JSON string with the provided json build function.
const char *build_json(const json_build_t &f, size_t *length);
std::string build_json(const json_build_t &f);
/// Parse a JSON string and run the provided json parse function if it's valid.
void parse_json(const std::string &data, const json_parse_t &f);
class VectorJsonBuffer : public ArduinoJson::Internals::JsonBufferBase<VectorJsonBuffer> {
public:
class String {
public:
String(VectorJsonBuffer *parent);
void append(char c) const;
const char *c_str() const;
protected:
VectorJsonBuffer *parent_;
uint32_t start_;
};
void *alloc(size_t bytes) override;
size_t size() const;
void clear();
String startString(); // NOLINT
protected:
void *do_alloc(size_t bytes); // NOLINT
void resize(size_t size); // NOLINT
void reserve(size_t size); // NOLINT
char *buffer_{nullptr};
size_t size_{0};
size_t capacity_{0};
std::vector<char *> free_blocks_;
};
extern VectorJsonBuffer global_json_buffer; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace json
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1 +0,0 @@
CODEOWNERS = ["@Cat-Ion"]

View File

@@ -1,82 +0,0 @@
#include "kalman_combinator.h"
#include "esphome/core/hal.h"
#include <cmath>
#include <functional>
namespace esphome {
namespace kalman_combinator {
void KalmanCombinatorComponent::dump_config() {
ESP_LOGCONFIG("kalman_combinator", "Kalman Combinator:");
ESP_LOGCONFIG("kalman_combinator", " Update variance: %f per ms", this->update_variance_value_);
ESP_LOGCONFIG("kalman_combinator", " Sensors:");
for (const auto &sensor : this->sensors_) {
auto &entity = *sensor.first;
ESP_LOGCONFIG("kalman_combinator", " - %s", entity.get_name().c_str());
}
}
void KalmanCombinatorComponent::setup() {
for (const auto &sensor : this->sensors_) {
const auto stddev = sensor.second;
sensor.first->add_on_state_callback([this, stddev](float x) -> void { this->correct_(x, stddev(x)); });
}
}
void KalmanCombinatorComponent::add_source(Sensor *sensor, std::function<float(float)> const &stddev) {
this->sensors_.emplace_back(sensor, stddev);
}
void KalmanCombinatorComponent::add_source(Sensor *sensor, float stddev) {
this->add_source(sensor, std::function<float(float)>{[stddev](float) -> float { return stddev; }});
}
void KalmanCombinatorComponent::update_variance_() {
uint32_t now = millis();
// Variance increases by update_variance_ each millisecond
auto dt = now - this->last_update_;
auto dv = this->update_variance_value_ * dt;
this->variance_ += dv;
this->last_update_ = now;
}
void KalmanCombinatorComponent::correct_(float value, float stddev) {
if (std::isnan(value) || std::isinf(stddev)) {
return;
}
if (std::isnan(this->state_) || std::isinf(this->variance_)) {
this->state_ = value;
this->variance_ = stddev * stddev;
if (this->std_dev_sensor_ != nullptr) {
this->std_dev_sensor_->publish_state(stddev);
}
return;
}
this->update_variance_();
// Combine two gaussian distributions mu1+-var1, mu2+-var2 to a new one around mu
// Use the value with the smaller variance as mu1 to prevent precision errors
const bool this_first = this->variance_ < (stddev * stddev);
const float mu1 = this_first ? this->state_ : value;
const float mu2 = this_first ? value : this->state_;
const float var1 = this_first ? this->variance_ : stddev * stddev;
const float var2 = this_first ? stddev * stddev : this->variance_;
const float mu = mu1 + var1 * (mu2 - mu1) / (var1 + var2);
const float var = var1 - (var1 * var1) / (var1 + var2);
// Update and publish state
this->state_ = mu;
this->variance_ = var;
this->publish_state(mu);
if (this->std_dev_sensor_ != nullptr) {
this->std_dev_sensor_->publish_state(std::sqrt(var));
}
}
} // namespace kalman_combinator
} // namespace esphome

View File

@@ -1,46 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include <cmath>
#include <vector>
namespace esphome {
namespace kalman_combinator {
class KalmanCombinatorComponent : public Component, public sensor::Sensor {
public:
KalmanCombinatorComponent() = default;
float get_setup_priority() const override { return esphome::setup_priority::DATA; }
void dump_config() override;
void setup() override;
void add_source(Sensor *sensor, std::function<float(float)> const &stddev);
void add_source(Sensor *sensor, float stddev);
void set_process_std_dev(float process_std_dev) {
this->update_variance_value_ = process_std_dev * process_std_dev * 0.001f;
}
void set_std_dev_sensor(Sensor *sensor) { this->std_dev_sensor_ = sensor; }
private:
void update_variance_();
void correct_(float value, float stddev);
// Source sensors and their error functions
std::vector<std::pair<Sensor *, std::function<float(float)>>> sensors_;
// Optional sensor for publishing the current error
sensor::Sensor *std_dev_sensor_{nullptr};
// Tick of the last update
uint32_t last_update_{0};
// Change of the variance, per ms
float update_variance_value_{0.f};
// Best guess for the state and its variance
float state_{NAN};
float variance_{INFINITY};
};
} // namespace kalman_combinator
} // namespace esphome

View File

@@ -1,87 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_ID,
CONF_SOURCE,
CONF_ACCURACY_DECIMALS,
CONF_DEVICE_CLASS,
CONF_ENTITY_CATEGORY,
CONF_ICON,
CONF_UNIT_OF_MEASUREMENT,
)
from esphome.core.entity_helpers import inherit_property_from
kalman_combinator_ns = cg.esphome_ns.namespace("kalman_combinator")
KalmanCombinatorComponent = kalman_combinator_ns.class_(
"KalmanCombinatorComponent", cg.Component, sensor.Sensor
)
CONF_ERROR = "error"
CONF_SOURCES = "sources"
CONF_PROCESS_STD_DEV = "process_std_dev"
CONF_STD_DEV = "std_dev"
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend(
{
cv.GenerateID(): cv.declare_id(KalmanCombinatorComponent),
cv.Required(CONF_PROCESS_STD_DEV): cv.positive_float,
cv.Required(CONF_SOURCES): cv.ensure_list(
cv.Schema(
{
cv.Required(CONF_SOURCE): cv.use_id(sensor.Sensor),
cv.Required(CONF_ERROR): cv.templatable(cv.positive_float),
}
),
),
cv.Optional(CONF_STD_DEV): sensor.SENSOR_SCHEMA,
}
)
# Inherit some sensor values from the first source, for both the state and the error value
properties_to_inherit = [
CONF_ACCURACY_DECIMALS,
CONF_DEVICE_CLASS,
CONF_ENTITY_CATEGORY,
CONF_ICON,
CONF_UNIT_OF_MEASUREMENT,
# CONF_STATE_CLASS could also be inherited, but might lead to unexpected behaviour with "total_increasing"
]
inherit_schema_for_state = [
inherit_property_from(property, [CONF_SOURCES, 0, CONF_SOURCE])
for property in properties_to_inherit
]
inherit_schema_for_std_dev = [
inherit_property_from([CONF_STD_DEV, property], [CONF_SOURCES, 0, CONF_SOURCE])
for property in properties_to_inherit
]
FINAL_VALIDATE_SCHEMA = cv.All(
CONFIG_SCHEMA.extend(
{cv.Required(CONF_ID): cv.use_id(KalmanCombinatorComponent)},
extra=cv.ALLOW_EXTRA,
),
*inherit_schema_for_state,
*inherit_schema_for_std_dev,
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await sensor.register_sensor(var, config)
cg.add(var.set_process_std_dev(config[CONF_PROCESS_STD_DEV]))
for source_conf in config[CONF_SOURCES]:
source = await cg.get_variable(source_conf[CONF_SOURCE])
error = await cg.templatable(
source_conf[CONF_ERROR],
[(float, "x")],
cg.float_,
)
cg.add(var.add_source(source, error))
if CONF_STD_DEV in config:
sens = await sensor.new_sensor(config[CONF_STD_DEV])
cg.add(var.set_std_dev_sensor(sens))

View File

@@ -17,7 +17,7 @@ void GPIOLCDDisplay::setup() {
this->enable_pin_->setup(); // OUTPUT
this->enable_pin_->digital_write(false);
for (uint8_t i = 0; i < (uint8_t)(this->is_four_bit_mode() ? 4u : 8u); i++) {
for (uint8_t i = 0; i < (this->is_four_bit_mode() ? 4 : 8); i++) {
this->data_pins_[i]->setup(); // OUTPUT
this->data_pins_[i]->digital_write(false);
}

View File

@@ -15,37 +15,17 @@ namespace ledc {
static const char *const TAG = "ledc.output";
#ifdef USE_ESP_IDF
static const int MAX_RES_BITS = LEDC_TIMER_BIT_MAX - 1;
#if SOC_LEDC_SUPPORT_HS_MODE
// Only ESP32 has LEDC_HIGH_SPEED_MODE
inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; }
#else
// S2, C3, S3 only support LEDC_LOW_SPEED_MODE
// See
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/ledc.html#functionality-overview
inline ledc_mode_t get_speed_mode(uint8_t) { return LEDC_LOW_SPEED_MODE; }
#endif
#else
static const int MAX_RES_BITS = 20;
#endif
float ledc_max_frequency_for_bit_depth(uint8_t bit_depth) { return 80e6f / float(1 << bit_depth); }
float ledc_min_frequency_for_bit_depth(uint8_t bit_depth, bool low_frequency) {
const float max_div_num = ((1 << MAX_RES_BITS) - 1) / (low_frequency ? 32.0f : 256.0f);
float ledc_min_frequency_for_bit_depth(uint8_t bit_depth) {
const float max_div_num = ((1 << 20) - 1) / 256.0f;
return 80e6f / (max_div_num * float(1 << bit_depth));
}
optional<uint8_t> ledc_bit_depth_for_frequency(float frequency) {
ESP_LOGD(TAG, "Calculating resolution bit-depth for frequency %f", frequency);
for (int i = MAX_RES_BITS; i >= 1; i--) {
const float min_frequency = ledc_min_frequency_for_bit_depth(i, (frequency < 100));
for (int i = 20; i >= 1; i--) {
const float min_frequency = ledc_min_frequency_for_bit_depth(i);
const float max_frequency = ledc_max_frequency_for_bit_depth(i);
if (min_frequency <= frequency && frequency <= max_frequency) {
ESP_LOGD(TAG, "Resolution calculated as %d", i);
if (min_frequency <= frequency && frequency <= max_frequency)
return i;
}
}
return {};
}
@@ -68,7 +48,7 @@ void LEDCOutput::write_state(float state) {
ledcWrite(this->channel_, duty);
#endif
#ifdef USE_ESP_IDF
auto speed_mode = get_speed_mode(channel_);
auto speed_mode = channel_ < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE;
auto chan_num = static_cast<ledc_channel_t>(channel_ % 8);
ledc_set_duty(speed_mode, chan_num, duty);
ledc_update_duty(speed_mode, chan_num);
@@ -83,15 +63,11 @@ void LEDCOutput::setup() {
ledcAttachPin(this->pin_->get_pin(), this->channel_);
#endif
#ifdef USE_ESP_IDF
auto speed_mode = get_speed_mode(channel_);
auto speed_mode = channel_ < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE;
auto timer_num = static_cast<ledc_timer_t>((channel_ % 8) / 2);
auto chan_num = static_cast<ledc_channel_t>(channel_ % 8);
bit_depth_ = *ledc_bit_depth_for_frequency(frequency_);
if (bit_depth_ < 1) {
ESP_LOGW(TAG, "Frequency %f can't be achieved with any bit depth", frequency_);
this->status_set_warning();
}
ledc_timer_config_t timer_conf{};
timer_conf.speed_mode = speed_mode;
@@ -138,7 +114,7 @@ void LEDCOutput::update_frequency(float frequency) {
ESP_LOGW(TAG, "LEDC output hasn't been initialized yet!");
return;
}
auto speed_mode = get_speed_mode(channel_);
auto speed_mode = channel_ < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE;
auto timer_num = static_cast<ledc_timer_t>((channel_ % 8) / 2);
ledc_timer_config_t timer_conf{};

View File

@@ -14,7 +14,6 @@ from esphome.const import (
CONF_RESTORE_MODE,
CONF_ON_TURN_OFF,
CONF_ON_TURN_ON,
CONF_ON_STATE,
CONF_TRIGGER_ID,
CONF_COLD_WHITE_COLOR_TEMPERATURE,
CONF_WARM_WHITE_COLOR_TEMPERATURE,
@@ -38,7 +37,6 @@ from .types import ( # noqa
AddressableLight,
LightTurnOnTrigger,
LightTurnOffTrigger,
LightStateTrigger,
)
CODEOWNERS = ["@esphome/core"]
@@ -71,11 +69,6 @@ LIGHT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ex
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightTurnOffTrigger),
}
),
cv.Optional(CONF_ON_STATE): auto.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightStateTrigger),
}
),
}
)
@@ -158,9 +151,6 @@ async def setup_light_core_(light_var, output_var, config):
for conf in config.get(CONF_ON_TURN_OFF, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], light_var)
await auto.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_STATE, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], light_var)
await auto.build_automation(trigger, [], conf)
if CONF_COLOR_CORRECT in config:
cg.add(output_var.set_correction(*config[CONF_COLOR_CORRECT]))

View File

@@ -167,7 +167,7 @@ class AddressableScanEffect : public AddressableLightEffect {
this->last_move_ = now;
it.all() = Color::BLACK;
for (uint32_t i = 0; i < this->scan_width_; i++) {
for (auto i = 0; i < this->scan_width_; i++) {
it[this->at_led_ + i] = current_color;
}
@@ -178,7 +178,7 @@ class AddressableScanEffect : public AddressableLightEffect {
uint32_t move_interval_{};
uint32_t scan_width_{1};
uint32_t last_move_{0};
uint32_t at_led_{0};
int at_led_{0};
bool direction_{true};
};
@@ -331,10 +331,9 @@ class AddressableFlickerEffect : public AddressableLightEffect {
return;
this->last_update_ = now;
uint32_t rng_state = random_uint32();
fast_random_set_seed(random_uint32());
for (auto var : it) {
rng_state = (rng_state * 0x9E3779B9) + 0x9E37;
const uint8_t flicker = (rng_state & 0xFF) % intensity;
const uint8_t flicker = fast_random_8() % intensity;
// scale down by random factor
var = var.get() * (255 - flicker);

View File

@@ -141,13 +141,6 @@ class LightTurnOffTrigger : public Trigger<> {
}
};
class LightStateTrigger : public Trigger<> {
public:
LightStateTrigger(LightState *a_light) {
a_light->add_new_remote_values_callback([this]() { this->trigger(); });
}
};
// This is slightly ugly, but we can't log in headers, and can't make this a static method on AddressableSet
// due to the template. It's just a temporary warning anyway.
void addressableset_warn_about_scale(const char *field);

View File

@@ -98,7 +98,7 @@ void LightCall::perform() {
// EFFECT
auto effect = this->effect_;
const char *effect_s;
if (effect == 0u)
if (effect == 0)
effect_s = "None";
else
effect_s = this->parent_->effects_[*this->effect_ - 1]->get_name().c_str();

View File

@@ -8,7 +8,7 @@ namespace light {
// See https://www.home-assistant.io/integrations/light.mqtt/#json-schema for documentation on the schema
void LightJSONSchema::dump_json(LightState &state, JsonObject root) {
void LightJSONSchema::dump_json(LightState &state, JsonObject &root) {
if (state.supports_effects())
root["effect"] = state.get_effect_name();
@@ -52,7 +52,7 @@ void LightJSONSchema::dump_json(LightState &state, JsonObject root) {
if (values.get_color_mode() & ColorCapability::BRIGHTNESS)
root["brightness"] = uint8_t(values.get_brightness() * 255);
JsonObject color = root.createNestedObject("color");
JsonObject &color = root.createNestedObject("color");
if (values.get_color_mode() & ColorCapability::RGB) {
color["r"] = uint8_t(values.get_color_brightness() * values.get_red() * 255);
color["g"] = uint8_t(values.get_color_brightness() * values.get_green() * 255);
@@ -72,7 +72,7 @@ void LightJSONSchema::dump_json(LightState &state, JsonObject root) {
}
}
void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonObject root) {
void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonObject &root) {
if (root.containsKey("state")) {
auto val = parse_on_off(root["state"]);
switch (val) {
@@ -95,7 +95,7 @@ void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonO
}
if (root.containsKey("color")) {
JsonObject color = root["color"];
JsonObject &color = root["color"];
// HA also encodes brightness information in the r, g, b values, so extract that and set it as color brightness.
float max_rgb = 0.0f;
if (color.containsKey("r")) {
@@ -140,7 +140,7 @@ void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonO
}
}
void LightJSONSchema::parse_json(LightState &state, LightCall &call, JsonObject root) {
void LightJSONSchema::parse_json(LightState &state, LightCall &call, JsonObject &root) {
LightJSONSchema::parse_color_json(state, call, root);
if (root.containsKey("flash")) {

View File

@@ -14,12 +14,12 @@ namespace light {
class LightJSONSchema {
public:
/// Dump the state of a light as JSON.
static void dump_json(LightState &state, JsonObject root);
static void dump_json(LightState &state, JsonObject &root);
/// Parse the JSON state of a light to a LightCall.
static void parse_json(LightState &state, LightCall &call, JsonObject root);
static void parse_json(LightState &state, LightCall &call, JsonObject &root);
protected:
static void parse_color_json(LightState &state, LightCall &call, JsonObject root);
static void parse_color_json(LightState &state, LightCall &call, JsonObject &root);
};
} // namespace light

View File

@@ -41,7 +41,6 @@ LightTurnOnTrigger = light_ns.class_(
LightTurnOffTrigger = light_ns.class_(
"LightTurnOffTrigger", automation.Trigger.template()
)
LightStateTrigger = light_ns.class_("LightStateTrigger", automation.Trigger.template())
# Effects
LightEffect = light_ns.class_("LightEffect")

View File

@@ -97,7 +97,7 @@ void LTR390Component::read_mode_(int mode_index) {
// If there are more modes to read then begin the next
// otherwise stop
if (mode_index + 1 < (int) this->mode_funcs_.size()) {
if (mode_index + 1 < this->mode_funcs_.size()) {
this->read_mode_(mode_index + 1);
} else {
this->reading_ = false;

View File

@@ -203,16 +203,16 @@ float MAX31865Sensor::calc_temperature_(float rtd_ratio) {
rtd_resistance *= 100;
}
float rpoly = rtd_resistance;
float neg_temp = -242.02f;
neg_temp += 2.2228f * rpoly;
float neg_temp = -242.02;
neg_temp += 2.2228 * rpoly;
rpoly *= rtd_resistance; // square
neg_temp += 2.5859e-3f * rpoly;
neg_temp += 2.5859e-3 * rpoly;
rpoly *= rtd_resistance; // ^3
neg_temp -= 4.8260e-6f * rpoly;
neg_temp -= 4.8260e-6 * rpoly;
rpoly *= rtd_resistance; // ^4
neg_temp -= 2.8183e-8f * rpoly;
neg_temp -= 2.8183e-8 * rpoly;
rpoly *= rtd_resistance; // ^5
neg_temp += 1.5243e-10f * rpoly;
neg_temp += 1.5243e-10 * rpoly;
return neg_temp;
}

View File

@@ -76,7 +76,7 @@ void MAX7219Component::loop() {
this->stepsleft_ = 0;
// Return if there is no need to scroll or scroll is off
if (!this->scroll_ || (this->max_displaybuffer_[0].size() <= (size_t) get_width_internal())) {
if (!this->scroll_ || (this->max_displaybuffer_[0].size() <= get_width_internal())) {
this->display();
return;
}
@@ -88,7 +88,7 @@ void MAX7219Component::loop() {
// Dwell time at end of string in case of stop at end
if (this->scroll_mode_ == ScrollMode::STOP) {
if (this->stepsleft_ >= this->max_displaybuffer_[0].size() - (size_t) get_width_internal() + 1) {
if (this->stepsleft_ >= this->max_displaybuffer_[0].size() - get_width_internal() + 1) {
if (now - this->last_scroll_ >= this->scroll_dwell_) {
this->stepsleft_ = 0;
this->last_scroll_ = now;
@@ -155,7 +155,7 @@ int MAX7219Component::get_height_internal() {
int MAX7219Component::get_width_internal() { return this->num_chips_ / this->num_chip_lines_ * 8; }
void HOT MAX7219Component::draw_absolute_pixel_internal(int x, int y, Color color) {
if (x + 1 > (int) this->max_displaybuffer_[0].size()) { // Extend the display buffer in case required
if (x + 1 > this->max_displaybuffer_[0].size()) { // Extend the display buffer in case required
for (int chip_line = 0; chip_line < this->num_chip_lines_; chip_line++) {
this->max_displaybuffer_[chip_line].resize(x + 1, this->bckgrnd_);
}

View File

@@ -35,6 +35,7 @@ void MCP23S08::dump_config() {
}
bool MCP23S08::read_reg(uint8_t reg, uint8_t *value) {
uint8_t data;
this->enable();
this->transfer_byte(this->device_opcode_ | 1);
this->transfer_byte(reg);

View File

@@ -24,7 +24,6 @@ void MCP23X17Base::pin_mode(uint8_t pin, gpio::Flags flags) {
uint8_t gppu = pin < 8 ? mcp23x17_base::MCP23X17_GPPUA : mcp23x17_base::MCP23X17_GPPUB;
if (flags == gpio::FLAG_INPUT) {
this->update_reg(pin, true, iodir);
this->update_reg(pin, false, gppu);
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
this->update_reg(pin, true, iodir);
this->update_reg(pin, true, gppu);

View File

@@ -127,6 +127,9 @@ canbus::Error MCP2515::set_mode_(const CanctrlReqopMode mode) {
}
canbus::Error MCP2515::set_clk_out_(const CanClkOut divisor) {
canbus::Error res;
uint8_t cfg3;
if (divisor == CLKOUT_DISABLE) {
/* Turn off CLKEN */
modify_register_(MCP_CANCTRL, CANCTRL_CLKEN, 0x00);

View File

@@ -1,27 +0,0 @@
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 = ["@rsumner"]
mcp3204_ns = cg.esphome_ns.namespace("mcp3204")
MCP3204 = mcp3204_ns.class_("MCP3204", cg.Component, spi.SPIDevice)
CONF_REFERENCE_VOLTAGE = "reference_voltage"
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(MCP3204),
cv.Optional(CONF_REFERENCE_VOLTAGE, default="3.3V"): cv.voltage,
}
).extend(spi.spi_device_schema(cs_pin_required=True))
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_reference_voltage(config[CONF_REFERENCE_VOLTAGE]))
await cg.register_component(var, config)
await spi.register_spi_device(var, config)

View File

@@ -1,35 +0,0 @@
#include "mcp3204.h"
#include "esphome/core/log.h"
namespace esphome {
namespace mcp3204 {
static const char *const TAG = "mcp3204";
float MCP3204::get_setup_priority() const { return setup_priority::HARDWARE; }
void MCP3204::setup() {
ESP_LOGCONFIG(TAG, "Setting up mcp3204");
this->spi_setup();
}
void MCP3204::dump_config() {
ESP_LOGCONFIG(TAG, "MCP3204:");
LOG_PIN(" CS Pin:", this->cs_);
ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_);
}
float MCP3204::read_data(uint8_t pin) {
uint8_t adc_primary_config = 0b00000110 & 0b00000111;
uint8_t adc_secondary_config = pin << 6;
this->enable();
this->transfer_byte(adc_primary_config);
uint8_t adc_primary_byte = this->transfer_byte(adc_secondary_config);
uint8_t adc_secondary_byte = this->transfer_byte(0x00);
this->disable();
uint16_t digital_value = (adc_primary_byte << 8 | adc_secondary_byte) & 0b111111111111;
return float(digital_value) / 4096.000 * this->reference_voltage_;
}
} // namespace mcp3204
} // namespace esphome

View File

@@ -1,28 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/spi/spi.h"
namespace esphome {
namespace mcp3204 {
class MCP3204 : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
spi::DATA_RATE_1MHZ> {
public:
MCP3204() = default;
void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
float read_data(uint8_t pin);
protected:
float reference_voltage_;
};
} // namespace mcp3204
} // namespace esphome

View File

@@ -1,32 +0,0 @@
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_NUMBER
from .. import mcp3204_ns, MCP3204
AUTO_LOAD = ["voltage_sampler"]
DEPENDENCIES = ["mcp3204"]
MCP3204Sensor = mcp3204_ns.class_(
"MCP3204Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
)
CONF_MCP3204_ID = "mcp3204_id"
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(MCP3204Sensor),
cv.GenerateID(CONF_MCP3204_ID): cv.use_id(MCP3204),
cv.Required(CONF_NUMBER): cv.int_range(min=0, max=3),
}
).extend(cv.polling_component_schema("60s"))
async def to_code(config):
var = cg.new_Pvariable(
config[CONF_ID],
config[CONF_NUMBER],
)
await cg.register_parented(var, config[CONF_MCP3204_ID])
await cg.register_component(var, config)
await sensor.register_sensor(var, config)

View File

@@ -1,23 +0,0 @@
#include "mcp3204_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace mcp3204 {
static const char *const TAG = "mcp3204.sensor";
MCP3204Sensor::MCP3204Sensor(uint8_t pin) : pin_(pin) {}
float MCP3204Sensor::get_setup_priority() const { return setup_priority::DATA; }
void MCP3204Sensor::dump_config() {
LOG_SENSOR("", "MCP3204 Sensor", this);
ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_);
LOG_UPDATE_INTERVAL(this);
}
float MCP3204Sensor::sample() { return this->parent_->read_data(this->pin_); }
void MCP3204Sensor::update() { this->publish_state(this->sample()); }
} // namespace mcp3204
} // namespace esphome

View File

@@ -1,30 +0,0 @@
#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 "../mcp3204.h"
namespace esphome {
namespace mcp3204 {
class MCP3204Sensor : public PollingComponent,
public Parented<MCP3204>,
public sensor::Sensor,
public voltage_sampler::VoltageSampler {
public:
MCP3204Sensor(uint8_t pin);
void update() override;
void dump_config() override;
float get_setup_priority() const override;
float sample() override;
protected:
uint8_t pin_;
};
} // namespace mcp3204
} // namespace esphome

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